diff --git a/internal/common/module_mappings.bzl b/internal/common/module_mappings.bzl index c344ed3065..9f14b95f18 100644 --- a/internal/common/module_mappings.bzl +++ b/internal/common/module_mappings.bzl @@ -74,6 +74,8 @@ def _get_module_mappings(target, ctx): # the runfiles directory. This requires the workspace_name to be prefixed on # each module root. mr = "/".join([p for p in [workspace_name, target.label.package] if p]) + if hasattr(ctx.rule.attr, "strip_prefix") and ctx.rule.attr.strip_prefix: + mr += "/" + ctx.rule.attr.strip_prefix if hasattr(ctx.rule.attr, "module_root") and ctx.rule.attr.module_root and ctx.rule.attr.module_root != ".": if ctx.rule.attr.module_root.endswith(".ts"): # Validate that sources are underneath the module root. diff --git a/internal/js_library/js_library.bzl b/internal/js_library/js_library.bzl index 5fcce1486a..ba37c7b8a6 100644 --- a/internal/js_library/js_library.bzl +++ b/internal/js_library/js_library.bzl @@ -98,6 +98,10 @@ _ATTRS = { ), "package_name": attr.string(), "srcs": attr.label_list(allow_files = True), + "strip_prefix": attr.string( + doc = "Path components to strip from the start of the package import path", + default = "", + ), } AmdNamesInfo = provider( @@ -223,7 +227,27 @@ def _impl(ctx): ] if ctx.attr.package_name: - path = "/".join([p for p in [ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package] if p]) + path = "/".join([ + p + for p in [ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package] + if p + ]) + + # Strip a prefix from the package require path + if ctx.attr.strip_prefix: + path += "/" + ctx.attr.strip_prefix + + # Check that strip_prefix contains at least one src path + check_prefix = "/".join([p for p in [ctx.label.package, ctx.attr.strip_prefix] if p]) + prefix_contains_src = False + for file in all_files: + if file.short_path.startswith(check_prefix): + prefix_contains_src = True + break + + if not prefix_contains_src: + fail("js_library %s strip_prefix path does not contain any of the provided sources" % ctx.label) + providers.append(LinkablePackageInfo( package_name = ctx.attr.package_name, path = path, @@ -339,6 +363,7 @@ def js_library( srcs: the list of files that comprise the package package_name: the name it will be imported by. Should match the "name" field in the package.json file. deps: other targets that provide JavaScript code + strip_prefix: path components to strip from the start of the package import path **kwargs: used for undocumented legacy features """ diff --git a/internal/js_library/test/strip_prefix/BUILD.bazel b/internal/js_library/test/strip_prefix/BUILD.bazel new file mode 100644 index 0000000000..400b7f7856 --- /dev/null +++ b/internal/js_library/test/strip_prefix/BUILD.bazel @@ -0,0 +1,17 @@ +load("//:index.bzl", "js_library", "nodejs_test") + +js_library( + name = "stripped_library", + package_name = "stripped_library", + srcs = ["library/file.js"], + strip_prefix = "library", +) + +nodejs_test( + name = "test", + data = [ + "test.js", + ":stripped_library", + ], + entry_point = "test.js", +) diff --git a/internal/js_library/test/strip_prefix/library/file.js b/internal/js_library/test/strip_prefix/library/file.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/js_library/test/strip_prefix/test.js b/internal/js_library/test/strip_prefix/test.js new file mode 100644 index 0000000000..0eb4118c05 --- /dev/null +++ b/internal/js_library/test/strip_prefix/test.js @@ -0,0 +1,9 @@ +// Try to load on unstripped path, this should fail +try { + require("stripped_library/library/file"); +} catch (exc) { + if (exc.code !== 'MODULE_NOT_FOUND') throw exc; +} + +// Load with the stripped path, this should succeed +require("stripped_library/file");