feat: improve rules_js parity
This commit is contained in:
@@ -6,6 +6,13 @@ _DEFAULT_INSTALL_INPUTS = [
|
||||
"bunfig.toml",
|
||||
]
|
||||
|
||||
_MANIFEST_DEP_FIELDS = [
|
||||
"dependencies",
|
||||
"devDependencies",
|
||||
"optionalDependencies",
|
||||
"peerDependencies",
|
||||
]
|
||||
|
||||
def _normalize_path(path):
|
||||
normalized = path.replace("\\", "/")
|
||||
if normalized.endswith("/") and normalized != "/":
|
||||
@@ -115,6 +122,30 @@ def _validate_catalog_shape(field, value):
|
||||
def _copy_json_value(value):
|
||||
return json.decode(json.encode(value))
|
||||
|
||||
def _package_target_name(package_name):
|
||||
sanitized = package_name
|
||||
sanitized = sanitized.replace("@", "at_")
|
||||
sanitized = sanitized.replace("/", "_")
|
||||
sanitized = sanitized.replace("-", "_")
|
||||
sanitized = sanitized.replace(".", "_")
|
||||
sanitized = sanitized.replace("__", "_").replace("__", "_").replace("__", "_")
|
||||
sanitized = sanitized.strip("_")
|
||||
if not sanitized:
|
||||
sanitized = "package"
|
||||
return "npm__" + sanitized
|
||||
|
||||
def _manifest_dependency_names(manifest):
|
||||
names = {}
|
||||
for field in _MANIFEST_DEP_FIELDS:
|
||||
dependencies = manifest.get(field)
|
||||
if dependencies == None:
|
||||
continue
|
||||
if type(dependencies) != type({}):
|
||||
fail("bun_install: `{}` must be an object when present".format(field))
|
||||
for name in dependencies.keys():
|
||||
names[name] = True
|
||||
return names
|
||||
|
||||
def _normalized_root_manifest(repository_ctx, package_json):
|
||||
manifest = json.decode(repository_ctx.read(package_json))
|
||||
workspaces = manifest.get("workspaces")
|
||||
@@ -147,6 +178,7 @@ def _materialize_workspace_packages(repository_ctx, package_json):
|
||||
package_root = package_json.dirname
|
||||
package_root_str = str(package_root)
|
||||
written = {}
|
||||
workspace_packages = {}
|
||||
|
||||
for pattern in _workspace_patterns(repository_ctx, package_json):
|
||||
segments = pattern.split("/")
|
||||
@@ -168,6 +200,15 @@ def _materialize_workspace_packages(repository_ctx, package_json):
|
||||
repository_ctx.read(workspace_package_json),
|
||||
)
|
||||
written[relative_dir] = True
|
||||
manifest = json.decode(repository_ctx.read(workspace_package_json))
|
||||
package_name = manifest.get("name")
|
||||
workspace_packages[relative_dir] = package_name if type(package_name) == type("") else ""
|
||||
|
||||
package_dirs = sorted(workspace_packages.keys())
|
||||
return struct(
|
||||
package_dirs = package_dirs,
|
||||
package_names = [workspace_packages[package_dir] for package_dir in package_dirs if workspace_packages[package_dir]],
|
||||
)
|
||||
|
||||
def _materialize_install_inputs(repository_ctx, package_json):
|
||||
package_root = package_json.dirname
|
||||
@@ -218,6 +259,68 @@ def _select_bun_binary(repository_ctx):
|
||||
|
||||
fail("Unsupported host platform: os={}, arch={}".format(repository_ctx.os.name, repository_ctx.os.arch))
|
||||
|
||||
def _render_package_targets_file(package_names):
|
||||
lines = ["NPM_PACKAGE_TARGETS = {"]
|
||||
for package_name in package_names:
|
||||
lines.append(' "{}": "{}",'.format(package_name, _package_target_name(package_name)))
|
||||
lines.extend([
|
||||
"}",
|
||||
"",
|
||||
])
|
||||
return "\n".join(lines)
|
||||
|
||||
def _render_repo_defs_bzl(repo_name):
|
||||
return """load(":packages.bzl", "NPM_PACKAGE_TARGETS")
|
||||
|
||||
def package_target_name(package_name):
|
||||
return NPM_PACKAGE_TARGETS.get(package_name)
|
||||
|
||||
def npm_link_all_packages(name = "node_modules", imported_links = []):
|
||||
if not native.existing_rule(name):
|
||||
native.alias(
|
||||
name = name,
|
||||
actual = "@{repo_name}//:node_modules",
|
||||
)
|
||||
|
||||
requested = {{}}
|
||||
for package_name in imported_links:
|
||||
requested[package_name] = True
|
||||
|
||||
for package_name, target_name in NPM_PACKAGE_TARGETS.items():
|
||||
if imported_links and package_name not in requested:
|
||||
continue
|
||||
if native.existing_rule(target_name):
|
||||
continue
|
||||
native.alias(
|
||||
name = target_name,
|
||||
actual = "@{repo_name}//:%s" % target_name,
|
||||
)
|
||||
""".format(repo_name = repo_name)
|
||||
|
||||
def _render_repo_build(package_names):
|
||||
lines = [
|
||||
'exports_files(["defs.bzl", "packages.bzl"])',
|
||||
"",
|
||||
"filegroup(",
|
||||
' name = "node_modules",',
|
||||
' srcs = glob(["**/node_modules/**"], allow_empty = False),',
|
||||
' visibility = ["//visibility:public"],',
|
||||
")",
|
||||
"",
|
||||
]
|
||||
|
||||
for package_name in package_names:
|
||||
lines.extend([
|
||||
"filegroup(",
|
||||
' name = "{}",'.format(_package_target_name(package_name)),
|
||||
' srcs = glob(["node_modules/{}/**"], allow_empty = True),'.format(package_name),
|
||||
' visibility = ["//visibility:public"],',
|
||||
")",
|
||||
"",
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
def _bun_install_repository_impl(repository_ctx):
|
||||
package_json = repository_ctx.path(repository_ctx.attr.package_json)
|
||||
bun_lockfile = repository_ctx.path(repository_ctx.attr.bun_lockfile)
|
||||
@@ -230,6 +333,7 @@ def _bun_install_repository_impl(repository_ctx):
|
||||
|
||||
bun_bin = _select_bun_binary(repository_ctx)
|
||||
lockfile_name = bun_lockfile.basename
|
||||
root_manifest = json.decode(repository_ctx.read(package_json))
|
||||
|
||||
if lockfile_name not in ["bun.lock", "bun.lockb"]:
|
||||
lockfile_name = "bun.lock"
|
||||
@@ -237,7 +341,7 @@ def _bun_install_repository_impl(repository_ctx):
|
||||
repository_ctx.file("package.json", _normalized_root_manifest(repository_ctx, package_json))
|
||||
repository_ctx.symlink(bun_lockfile, lockfile_name)
|
||||
_materialize_install_inputs(repository_ctx, package_json)
|
||||
_materialize_workspace_packages(repository_ctx, package_json)
|
||||
workspace_packages = _materialize_workspace_packages(repository_ctx, package_json)
|
||||
|
||||
install_args = [str(bun_bin), "--bun", "install", "--frozen-lockfile", "--no-progress"]
|
||||
if repository_ctx.attr.isolated_home:
|
||||
@@ -263,15 +367,26 @@ stderr:
|
||||
""".format(result.stdout, result.stderr))
|
||||
|
||||
repository_ctx.file(
|
||||
"BUILD.bazel",
|
||||
"""filegroup(
|
||||
name = "node_modules",
|
||||
srcs = glob(["**/node_modules/**"], allow_empty = False),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
"node_modules/.rules_bun/install.json",
|
||||
json.encode({
|
||||
"bun_lockfile": lockfile_name,
|
||||
"package_json": "package.json",
|
||||
"workspace_package_dirs": workspace_packages.package_dirs,
|
||||
}) + "\n",
|
||||
)
|
||||
|
||||
package_names = {}
|
||||
for package_name in _manifest_dependency_names(root_manifest).keys():
|
||||
package_names[package_name] = True
|
||||
for package_name in workspace_packages.package_names:
|
||||
package_names[package_name] = True
|
||||
|
||||
sorted_package_names = sorted(package_names.keys())
|
||||
visible_repo_name = repository_ctx.attr.visible_repo_name or repository_ctx.name
|
||||
repository_ctx.file("packages.bzl", _render_package_targets_file(sorted_package_names))
|
||||
repository_ctx.file("defs.bzl", _render_repo_defs_bzl(visible_repo_name))
|
||||
repository_ctx.file("BUILD.bazel", _render_repo_build(sorted_package_names))
|
||||
|
||||
bun_install_repository = repository_rule(
|
||||
implementation = _bun_install_repository_impl,
|
||||
attrs = {
|
||||
@@ -279,6 +394,7 @@ bun_install_repository = repository_rule(
|
||||
"bun_lockfile": attr.label(mandatory = True, allow_single_file = True),
|
||||
"install_inputs": attr.label_list(allow_files = True),
|
||||
"isolated_home": attr.bool(default = True),
|
||||
"visible_repo_name": attr.string(),
|
||||
"bun_linux_x64": attr.label(default = "@bun_linux_x64//:bun-linux-x64/bun", allow_single_file = True),
|
||||
"bun_linux_aarch64": attr.label(default = "@bun_linux_aarch64//:bun-linux-aarch64/bun", allow_single_file = True),
|
||||
"bun_darwin_x64": attr.label(default = "@bun_darwin_x64//:bun-darwin-x64/bun", allow_single_file = True),
|
||||
@@ -313,4 +429,5 @@ def bun_install(name, package_json, bun_lockfile, install_inputs = [], isolated_
|
||||
bun_lockfile = bun_lockfile,
|
||||
install_inputs = install_inputs,
|
||||
isolated_home = isolated_home,
|
||||
visible_repo_name = name,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user