diff --git a/BUILD.bazel b/BUILD.bazel index d91967171..c9f199d10 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,7 +11,7 @@ link_all_npm_packages(name = "node_modules") # Link the acorn package, which was fetched separately with npm_import from /WORKSPACE, to the # virtual store in bazel-bin/node_modules/.aspect_rules_js link_acorn( - name = "link_acorn", + name = "node_modules/acorn", # `direct` set to False as an example of *not* also linking this 3rd dependency as a # direct dependency in the package at bazel-bin/node_modules/@mycorp/mylib. Alternately, # you may specify link_packages in the npm_import of this package and direct is then @@ -21,7 +21,7 @@ link_acorn( # Linking a first-party dependency to the virtual store in bazel-bin/node_modules/.aspect_rules_js link_npm_package( - name = "link_mycorp_mylib", + name = "node_modules/@mycorp/mylib", src = "//examples/lib", # `direct` set to False as an example of *not* also linking this first-party dependency as a # direct dependency in the package at bazel-bin/node_modules/@mycorp/mylib. diff --git a/docs/link_npm_package.md b/docs/link_npm_package.md index 2b6ae9e17..f87f310d5 100644 --- a/docs/link_npm_package.md +++ b/docs/link_npm_package.md @@ -81,10 +81,10 @@ link_npm_package(name, 1: + package_scope = _import.package.split("/", 1)[0] + if package_scope not in package_scopes: + package_scopes.append(package_scope) + for fp_link in fp_links.values(): + fp_package = fp_link.get("package") + if len(fp_package.split("/", 1)) > 1: + package_scope = fp_package.split("/", 1)[0] + if package_scope not in package_scopes: + package_scopes.append(package_scope) + for package_scope in package_scopes: + defs_bzl_body.append(""" scoped_direct_targets["{}"] = []""".format(package_scope)) + + for (i, _import) in enumerate(npm_imports): maybe_deps = (""" deps = %s,""" % starlark_codegen_utils.to_dict_attr(_import.deps, 2)) if len(_import.deps) > 0 else "" maybe_transitive_closure = (""" @@ -443,33 +467,25 @@ def _impl(rctx): links_suffix = utils.links_suffix, ), ) - defs_bzl_body.append(""" direct_targets.append(link_{i}(name = "{direct_link_prefix}{bazel_name}", direct = None, fail_if_no_link = False))""".format( + defs_bzl_body.append(""" direct_targets.append(link_{i}(name = "{{}}/{name}".format(name), direct = None, fail_if_no_link = False))""".format( i = i, - direct_link_prefix = utils.direct_link_prefix, - bazel_name = utils.bazel_name(_import.package), + name = _import.package, )) + if len(_import.package.split("/", 1)) > 1: + package_scope = _import.package.split("/", 1)[0] + defs_bzl_body.append(""" scoped_direct_targets["{package_scope}"].append(direct_targets[-1])""".format( + package_scope = package_scope, + )) - # For direct dependencies create alias targets @repo_name//name, @repo_name//@scope/name, - # @repo_name//name:dir and @repo_name//@scope/name:dir for link_package in _import.link_packages: - build_file_path = paths.normalize(paths.join(link_package, _import.package, "BUILD.bazel")) - rctx.file(build_file_path, "\n".join(generated_by_lines + [ - _ALIAS_TMPL.format( - basename = paths.basename(_import.package), - bazel_name = utils.bazel_name(_import.package), - dir_suffix = utils.dir_suffix, - direct_link_prefix = utils.direct_link_prefix, - link_package = link_package, - link_workspace = rctx.attr.pnpm_lock.workspace_name, - ), - ])) - # Generate a package_json.bzl file for the bin entries (even if there are none) # Note, there's no has_bin attribute on npm_import so we can't get the boolean # value from the _import struct. # If this is a problem, we could lookup into the packages again like # if lockfile.get("packages").values()[i].get("hasBin"): if True: + build_file_path = paths.normalize(paths.join(link_package, _import.package, "BUILD.bazel")) + rctx.file(build_file_path, "\n".join(generated_by_lines)) package_json_bzl_file_path = paths.normalize(paths.join(link_package, _import.package, _PACKAGE_JSON_BZL_FILENAME)) repo_package_json_bzl = paths.normalize(paths.join(link_package, _PACKAGE_JSON_BZL_FILENAME)).rsplit("/", 1) if len(repo_package_json_bzl) == 1: @@ -483,64 +499,6 @@ def _impl(rctx): ), ])) - # Gather scoped packages - if len(_import.package.split("/", 1)) > 1: - package_scope = _import.package.split("/", 1)[0] - build_file_package = paths.normalize(paths.join(link_package, package_scope)) - if build_file_package not in scoped_packages: - scoped_packages[build_file_package] = [] - scoped_packages[build_file_package].append( - "@{link_workspace}//{link_package}:{direct_link_prefix}{bazel_name}".format( - bazel_name = utils.bazel_name(_import.package), - direct_link_prefix = utils.direct_link_prefix, - link_package = link_package, - link_workspace = rctx.attr.pnpm_lock.workspace_name, - ), - ) - - fp_links = {} - - # Look for first-party links - for import_path, importer in importers.items(): - dependencies = importer.get("dependencies") - if type(dependencies) != "dict": - fail("expected dict of dependencies in processed importer '%s'" % import_path) - link_package = _link_package(root_package, import_path) - for dep_package, dep_version in dependencies.items(): - if dep_version.startswith("link:"): - dep_importer = paths.normalize(paths.join(import_path, dep_version[len("link:"):])) - dep_path = _link_package(root_package, import_path, dep_version[len("link:"):]) - dep_key = "{}+{}".format(dep_package, dep_path) - if dep_key in fp_links.keys(): - fp_links[dep_key]["link_packages"].append(link_package) - else: - transitive_deps = [] - raw_deps = {} - if dep_importer in importers.keys(): - raw_deps = importers.get(dep_importer).get("dependencies") - for raw_package, raw_version in raw_deps.items(): - if raw_version.startswith("link:"): - raw_path = _link_package(root_package, dep_importer, raw_version[len("link:"):]) - raw_bazel_name = utils.bazel_name(raw_package, raw_path) - else: - raw_bazel_name = utils.bazel_name(raw_package, raw_version) - transitive_deps.append("//{root_package}:{store_link_prefix}{bazel_name}".format( - bazel_name = raw_bazel_name, - root_package = root_package, - store_link_prefix = utils.store_link_prefix, - )) - fp_links[dep_key] = { - "package": dep_package, - "path": dep_path, - "link_packages": [link_package], - "deps": transitive_deps, - } - - if fp_links: - defs_bzl_header.append("""load("@aspect_rules_js//npm/private:link_npm_package.bzl", - _link_npm_package_store = "link_npm_package_store", - _link_npm_package_direct = "link_npm_package_direct")""") - for fp_link in fp_links.values(): fp_package = fp_link.get("package") fp_path = fp_link.get("path") @@ -552,17 +510,15 @@ def _impl(rctx): defs_bzl_body.append(_FP_STORE_TMPL.format( bazel_name = fp_bazel_name, deps = starlark_codegen_utils.to_list_attr(fp_deps, 3), - direct_link_prefix = utils.direct_link_prefix, npm_package_target = fp_target, package = fp_package, store_link_prefix = utils.store_link_prefix, )) defs_bzl_body.append(_FP_DIRECT_TMPL.format( - alias = utils.bazel_name(fp_package), bazel_name = fp_bazel_name, + name = fp_package, dir_suffix = utils.dir_suffix, - direct_link_prefix = utils.direct_link_prefix, link_packages = fp_link_packages, package = fp_package, package_directory_output_group = utils.package_directory_output_group, @@ -570,38 +526,22 @@ def _impl(rctx): store_link_prefix = utils.store_link_prefix, )) - # Create alias targets @repo_name//name, @repo_name//@scope/name, - # @repo_name//name:dir and @repo_name//@scope/name:dir - for link_package in fp_link_packages: - build_file_path = paths.normalize(paths.join(link_package, fp_package, "BUILD.bazel")) - rctx.file(build_file_path, "\n".join(generated_by_lines + [ - _ALIAS_TMPL.format( - basename = paths.basename(fp_package), - bazel_name = utils.bazel_name(fp_package), - dir_suffix = utils.dir_suffix, - direct_link_prefix = utils.direct_link_prefix, - link_package = link_package, - link_workspace = rctx.attr.pnpm_lock.workspace_name, - ), - ])) - - # Gather scoped packages - if len(fp_package.split("/", 1)) > 1: - package_scope = fp_package.split("/", 1)[0] - build_file_package = paths.normalize(paths.join(link_package, package_scope)) - if build_file_package not in scoped_packages: - scoped_packages[build_file_package] = [] - scoped_packages[build_file_package].append( - "@{link_workspace}//{link_package}:{direct_link_prefix}{bazel_name}".format( - bazel_name = utils.bazel_name(fp_package), - direct_link_prefix = utils.direct_link_prefix, - link_package = link_package, - link_workspace = rctx.attr.pnpm_lock.workspace_name, - ), - ) + if len(fp_package.split("/", 1)) > 1: + package_scope = fp_package.split("/", 1)[0] + defs_bzl_body.append(""" scoped_direct_targets["{package_scope}"].append(direct_targets[-1])""".format( + package_scope = package_scope, + )) - # Generate linked_npm_packages target + # Generate catch all & scoped linked_npm_packages target defs_bzl_body.append(""" + for scope, scoped_targets in scoped_direct_targets.items(): + linked_npm_packages( + name = "{}/{}".format(name, scope), + srcs = [t for t in scoped_targets if t], + tags = ["manual"], + visibility = ["//visibility:public"], + ) + linked_npm_packages( name = name, srcs = [t for t in direct_targets if t], @@ -609,16 +549,6 @@ def _impl(rctx): visibility = ["//visibility:public"], )""") - # Generate scoped @npm//@scope targets - for build_file_package, scope_packages in scoped_packages.items(): - rctx.file(paths.join(build_file_package, "BUILD.bazel"), "\n".join(generated_by_lines + [ - _SCOPE_TMPL.format( - scope = paths.basename(build_file_package), - srcs = starlark_codegen_utils.to_list_attr(scope_packages, 1), - package_path = build_file_package, - ), - ])) - rctx.file(_DEFS_BZL_FILENAME, "\n".join(defs_bzl_header + [""] + defs_bzl_body + [""])) rctx.file(_REPOSITORIES_BZL_FILENAME, "\n".join(repositories_bzl)) rctx.file("BUILD.bazel", "\n".join(generated_by_lines + [ diff --git a/npm/private/utils.bzl b/npm/private/utils.bzl index b4472371c..4258b7422 100644 --- a/npm/private/utils.bzl +++ b/npm/private/utils.bzl @@ -93,11 +93,9 @@ utils = struct( strip_peer_dep_version = _strip_peer_dep_version, # Symlinked node_modules structure virtual store path under node_modules virtual_store_root = ".aspect_rules_js", - # Prefix for link_npm_package_direct links - direct_link_prefix = "direct_link__", # Prefix for link_npm_package_store links store_link_prefix = "store_link__", - # Suffix for package directory filegroup and alias targets + # Suffix for package directory filegroup dir_suffix = "__dir", # Suffix for npm_import links repository links_suffix = "__links",