Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ npm/private/test/vendored/lodash-4.17.21.tgz=-1206623349
npm/private/test/vendored/semver-max/package.json=578664053
package.json=564790136
pnpm-lock.yaml=322824775
pnpm-workspace.yaml=1888889068
pnpm-workspace.yaml=-1219461713
5 changes: 4 additions & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ use_repo(

# The default + public version of pnpm used by default.
pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm")
pnpm.pnpm(name = "pnpm")
pnpm.pnpm(
name = "pnpm",
include_npm = True,
)
use_repo(pnpm, "pnpm", "pnpm__links")

bazel_lib_toolchains = use_extension("@bazel_lib//lib:extensions.bzl", "toolchains")
Expand Down
2 changes: 2 additions & 0 deletions npm/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ bzl_library(
"//npm/private:npm_package",
"//npm/private:npm_package_info",
"//npm/private:npm_package_store_info",
"//npm/private:pnpm_extract_catalogs",
"//npm/private:pnpm_package",
],
)

Expand Down
11 changes: 10 additions & 1 deletion npm/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ load(
_npm_package = "npm_package",
_stamped_package_json = "stamped_package_json",
)

load(
"//npm/private:pnpm_extract_catalogs.bzl",
_pnpm_extract_catalogs = "pnpm_extract_catalogs",
)
load(
"//npm/private:pnpm_package.bzl",
_pnpm_package = "pnpm_package",
)
npm_package = _npm_package
npm_link_package = _npm_link_package
pnpm_extract_catalogs = _pnpm_extract_catalogs
pnpm_package = _pnpm_package
stamped_package_json = _stamped_package_json
29 changes: 28 additions & 1 deletion npm/private/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Internal implementation details"

load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_library")
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

package(default_visibility = ["//npm:__subpackages__"])
Expand All @@ -11,6 +11,33 @@ js_library(
visibility = ["//visibility:public"],
)

js_binary(
name = "pnpm_package_json_transform_bin",
entry_point = "pnpm_package_json_transform.mjs",
visibility = ["//visibility:public"],
)


bzl_library(
name = "pnpm_extract_catalogs",
srcs = ["pnpm_extract_catalogs.bzl"],
deps = ["@yq.bzl//yq:yq"],
)

bzl_library(
name = "pnpm_package",
srcs = ["pnpm_package.bzl"],
deps = [
":npm_package",
":pnpm_package_json_transform",
],
)

bzl_library(
name = "pnpm_package_json_transform",
srcs = ["pnpm_package_json_transform.bzl"],
)

bzl_library(
name = "npm_package",
srcs = ["npm_package.bzl"],
Expand Down
10 changes: 9 additions & 1 deletion npm/private/npm_translate_lock_generate.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ def generate_repository_files(attr, state, npm_imports):
packages = state.packages()
root_package = state.root_package()

final_rctx_files = {}
workspace_package_versions = state.workspace_package_versions()
pnpm_catalogs = state.pnpm_catalogs()

final_rctx_files = {
"workspace_versions.json": json.encode(workspace_package_versions),
"catalogs.json": json.encode(pnpm_catalogs),
}

rctx_files = {
"BUILD.bazel": [
Expand All @@ -75,6 +81,8 @@ js_binary(name = "sync", entry_point = "noop.js")
"",
"exports_files({})".format(starlark_codegen_utils.to_list_attr([
_DEFS_BZL_FILENAME,
"workspace_versions.json",
"catalogs.json",
])),
],
}
Expand Down
26 changes: 25 additions & 1 deletion npm/private/npm_translate_lock_state.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ def _init_workspace(priv, rctx, is_windows):
priv["pnpm_settings"] = priv["pnpm_settings"] | pnpm_workspace_settings
priv["only_built_dependencies"] = _only_built_dependencies(priv)

workspace_data = json.decode(pnpm_workspace_json)
catalogs = {}
default_catalog = workspace_data.get("catalog")
if default_catalog:
catalogs["default"] = default_catalog
named_catalogs = workspace_data.get("catalogs", {})
catalogs.update(named_catalogs)
priv["pnpm_catalogs"] = catalogs

if workspace_parse_err != None:
should_update = _should_update_pnpm_lock(priv)
msg = """
Expand Down Expand Up @@ -227,7 +236,8 @@ ERROR: Implicitly using pnpm-workspace.yaml file `{pnpm_workspace}` since the `{
pnpm_lock_dir = str(rctx.path(pnpm_lock_label).dirname) if pnpm_lock_label else priv["src_root"]
rel_dir = _rel_path(priv, pnpm_lock_dir)

# package.json files
# package.json files — read each workspace package's name and version
workspace_package_versions = {}
for package_json in priv["importers"].keys():
rel_path = paths.normalize(paths.join(rel_dir, package_json, "package.json"))
workspace_path = paths.join(priv["src_root"], rel_path)
Expand All @@ -241,6 +251,16 @@ ERROR: Implicitly using pnpm-workspace.yaml file `{pnpm_workspace}` since the `{
fail(msg)
_copy_input_file(priv, rctx, attr, workspace_path, str(rctx.path(rel_path)))

pkg_json_path = rctx.path(rel_path)
if pkg_json_path.exists:
pkg_json = json.decode(rctx.read(pkg_json_path))
pkg_name = pkg_json.get("name")
pkg_version = pkg_json.get("version")
if pkg_name and pkg_version:
workspace_package_versions[pkg_name] = pkg_version

priv["workspace_package_versions"] = workspace_package_versions

# Read patches from pnpm-lock.yaml `patchedDependencies`
for name in priv["pnpm_patched_dependencies"]:
patch_path = _patch_path_for(priv, name)
Expand Down Expand Up @@ -517,6 +537,8 @@ def _new(rctx, mod, attr):
"pnpm_settings": {},
"pnpm_patched_dependencies": {},
"should_update_pnpm_lock": should_update_pnpm_lock,
"workspace_package_versions": {},
"pnpm_catalogs": {},
}

_init(priv, rctx, attr)
Expand All @@ -538,6 +560,8 @@ def _new(rctx, mod, attr):
root_package = lambda: priv["root_package"],
set_input_hash = lambda label, value: _set_input_hash(priv, label, value),
action_cache_miss = lambda: _action_cache_miss(priv, rctx),
workspace_package_versions = lambda: priv["workspace_package_versions"],
pnpm_catalogs = lambda: priv["pnpm_catalogs"],
write_action_cache = lambda: _write_action_cache(priv, rctx),
)

Expand Down
29 changes: 29 additions & 0 deletions npm/private/pnpm_extract_catalogs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Macro for extracting pnpm catalog definitions from pnpm-workspace.yaml.

Uses yq to select the catalog/catalogs sections and emit a JSON file
mapping catalog names to {package: version} dicts. The unnamed catalog:
section is keyed as "default".
"""

load("@yq.bzl//yq:yq.bzl", "yq")

def pnpm_extract_catalogs(
name,
workspace_manifest = "//:pnpm-workspace.yaml",
**kwargs):
"""Extracts catalog/catalogs sections from pnpm-workspace.yaml into a JSON file.

Args:
name: Target name. Output will be catalogs.json.
workspace_manifest: The pnpm-workspace.yaml file to extract catalogs from.
Defaults to //:pnpm-workspace.yaml.
**kwargs: Additional arguments passed to the underlying yq rule.
"""
yq(
name = name,
srcs = [workspace_manifest],
expression = '{"default": .catalog} * (.catalogs // {}) | with_entries(select(.value != null))',
args = ["-o=json"],
outs = ["catalogs.json"],
**kwargs
)
63 changes: 63 additions & 0 deletions npm/private/pnpm_git_tag_version.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Rule for extracting package versions from git tags.

Example usage:

```starlark
load("@aspect_rules_js//npm:defs.bzl", "pnpm_package")
load("@aspect_rules_js//npm/private:pnpm_git_tag_version.bzl", "pnpm_git_tag_version")

pnpm_git_tag_version(
name = "version",
prefix = "@internal/my-package",
fallback = "0.0.0-development",
)

pnpm_package(
name = "pkg",
srcs = [":lib"],
version = ":version",
)
```

Given git tags like `@internal/my-package@1.2.3`, this extracts `1.2.3` as the version.
The latest matching tag (by semver sort) is used.
"""

def _pnpm_git_tag_version_impl(ctx):
output = ctx.actions.declare_file(ctx.label.name + ".version")

ctx.actions.run_shell(
outputs = [output],
command = """\
prefix="$1"
fallback="$2"
output="$3"
version=$(git tag -l "${prefix}@*" --sort=-v:refname | head -1 | sed 's/.*@//')
if [ -z "$version" ]; then
version="${fallback}"
fi
printf '%s' "$version" > "${output}"
""",
arguments = [ctx.attr.prefix, ctx.attr.fallback, output.path],
execution_requirements = {
"local": "1",
"no-sandbox": "1",
},
)

return [DefaultInfo(files = depset([output]))]

pnpm_git_tag_version = rule(
implementation = _pnpm_git_tag_version_impl,
attrs = {
"prefix": attr.string(
mandatory = True,
doc = "Git tag prefix to match, e.g. '@internal/my-package'. Tags should be in the format '<prefix>@<version>'.",
),
"fallback": attr.string(
default = "0.0.0-development",
doc = "Version to use when no matching git tag is found",
),
},
doc = "Extracts a package version from git tags matching the given prefix.",
)
Loading
Loading