From 00b890be25c9e53d8146142eb36185be2135de62 Mon Sep 17 00:00:00 2001 From: Greg Magolan Date: Fri, 3 Jun 2022 01:38:47 -0700 Subject: [PATCH] feat: add js_library rule --- docs/BUILD.bazel | 5 ++ docs/js_library.md | 51 ++++++++++++ examples/js_library/BUILD.bazel | 0 examples/js_library/one/BUILD.bazel | 13 +++ examples/js_library/one/one.d.ts | 1 + examples/js_library/one/one.js | 4 + examples/js_library/one/one.ts | 1 + examples/js_library/one/package.json | 5 ++ examples/js_library/two/BUILD.bazel | 26 ++++++ examples/js_library/two/tsconfig.json | 8 ++ examples/js_library/two/two.ts | 3 + js/BUILD.bazel | 1 + js/defs.bzl | 11 ++- js/private/BUILD.bazel | 13 +++ js/private/js_library.bzl | 110 ++++++++++++++++++++++++++ npm/private/test/defs_checked.bzl | 1 + 16 files changed, 251 insertions(+), 2 deletions(-) create mode 100755 docs/js_library.md create mode 100644 examples/js_library/BUILD.bazel create mode 100644 examples/js_library/one/BUILD.bazel create mode 100644 examples/js_library/one/one.d.ts create mode 100644 examples/js_library/one/one.js create mode 100644 examples/js_library/one/one.ts create mode 100644 examples/js_library/one/package.json create mode 100644 examples/js_library/two/BUILD.bazel create mode 100644 examples/js_library/two/tsconfig.json create mode 100644 examples/js_library/two/two.ts create mode 100644 js/private/js_library.bzl diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 02eb42d05..210b1d3ae 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -5,6 +5,11 @@ stardoc_with_diff_test( bzl_library_target = "//js/private:js_binary", ) +stardoc_with_diff_test( + name = "js_library", + bzl_library_target = "//js/private:js_library", +) + stardoc_with_diff_test( name = "run_js_binary", bzl_library_target = "//js/private:run_js_binary", diff --git a/docs/js_library.md b/docs/js_library.md new file mode 100755 index 000000000..79a8673b6 --- /dev/null +++ b/docs/js_library.md @@ -0,0 +1,51 @@ + + +Expose some files with DeclarationInfo, like filegroup but can be a dep of ts_project. + +Load this with, + +```starlark +load("@aspect_rules_js//js:defs.bzl", "js_library") +``` + + + + +## js_library + +
+js_library(name, deps, srcs)
+
+ +Copies all sources to the output tree and expose some files with DeclarationInfo. + +Can be used as a dep for rules that expect a DeclarationInfo such as ts_project. + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| deps | - | List of labels | optional | [] | +| srcs | - | List of labels | optional | [] | + + + + +## js_library_lib.implementation + +
+js_library_lib.implementation(ctx)
+
+ + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| ctx |

-

| none | + + diff --git a/examples/js_library/BUILD.bazel b/examples/js_library/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/examples/js_library/one/BUILD.bazel b/examples/js_library/one/BUILD.bazel new file mode 100644 index 000000000..b86b2abe8 --- /dev/null +++ b/examples/js_library/one/BUILD.bazel @@ -0,0 +1,13 @@ +load("@aspect_rules_js//js:defs.bzl", "js_library") + +js_library( + name = "one", + srcs = [ + "one.d.ts", + "one.js", + # package.json needed here so that the "typings" field appears in the + # downstream typecheck and so "main" field is seen at runtime + "package.json", + ], + visibility = ["//examples/js_library:__subpackages__"], +) diff --git a/examples/js_library/one/one.d.ts b/examples/js_library/one/one.d.ts new file mode 100644 index 000000000..b9dc8dd63 --- /dev/null +++ b/examples/js_library/one/one.d.ts @@ -0,0 +1 @@ +export declare const one = 1 diff --git a/examples/js_library/one/one.js b/examples/js_library/one/one.js new file mode 100644 index 000000000..e4d42eea3 --- /dev/null +++ b/examples/js_library/one/one.js @@ -0,0 +1,4 @@ +'use strict' +exports.__esModule = true +exports.one = void 0 +exports.one = 1 diff --git a/examples/js_library/one/one.ts b/examples/js_library/one/one.ts new file mode 100644 index 000000000..c30aa0c47 --- /dev/null +++ b/examples/js_library/one/one.ts @@ -0,0 +1 @@ +export const one = 1 diff --git a/examples/js_library/one/package.json b/examples/js_library/one/package.json new file mode 100644 index 000000000..c3fb36009 --- /dev/null +++ b/examples/js_library/one/package.json @@ -0,0 +1,5 @@ +{ + "private": true, + "main": "one.js", + "typings": "one.d.ts" +} diff --git a/examples/js_library/two/BUILD.bazel b/examples/js_library/two/BUILD.bazel new file mode 100644 index 000000000..cf4cc1fe7 --- /dev/null +++ b/examples/js_library/two/BUILD.bazel @@ -0,0 +1,26 @@ +load("@npm//typescript:package_json.bzl", typescript_bin = "bin") +load("@aspect_rules_js//js:defs.bzl", "js_test") + +typescript_bin.tsc( + name = "two", + srcs = [ + "tsconfig.json", + "two.ts", + "//:node_modules/@types/node", + "//examples/js_library/one", + ], + outs = [ + "two.js", + ], + chdir = package_name(), + args = [ + "-p", + "tsconfig.json", + ], +) + +js_test( + name = "two_test", + data = ["//examples/js_library/one"], + entry_point = "two.js", +) diff --git a/examples/js_library/two/tsconfig.json b/examples/js_library/two/tsconfig.json new file mode 100644 index 000000000..ec6b5c211 --- /dev/null +++ b/examples/js_library/two/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2017", + "noImplicitAny": true + }, + "include": ["*.ts"] +} diff --git a/examples/js_library/two/two.ts b/examples/js_library/two/two.ts new file mode 100644 index 000000000..1d0943ca0 --- /dev/null +++ b/examples/js_library/two/two.ts @@ -0,0 +1,3 @@ +import { one } from '../one' +export const two = one + one +console.log(two) diff --git a/js/BUILD.bazel b/js/BUILD.bazel index 7741765ec..cbddbc711 100644 --- a/js/BUILD.bazel +++ b/js/BUILD.bazel @@ -13,6 +13,7 @@ bzl_library( visibility = ["//visibility:public"], deps = [ "//js/private:js_binary", + "//js/private:js_library", "//js/private:run_js_binary", ], ) diff --git a/js/defs.bzl b/js/defs.bzl index 3f3d8d3e8..00abd447b 100644 --- a/js/defs.bzl +++ b/js/defs.bzl @@ -6,6 +6,11 @@ load( _js_binary_lib = "js_binary_lib", _js_test = "js_test", ) +load( + "//js/private:js_library.bzl", + _js_library = "js_library", + _js_library_lib = "js_library_lib", +) load( "//js/private:run_js_binary.bzl", _run_js_binary = "run_js_binary", @@ -29,7 +34,9 @@ def js_test(**kwargs): **kwargs ) +js_library = _js_library +run_js_binary = _run_js_binary + # export the starlark libraries as a public API js_binary_lib = _js_binary_lib - -run_js_binary = _run_js_binary +js_library_lib = _js_library_lib diff --git a/js/private/BUILD.bazel b/js/private/BUILD.bazel index a4a82a55e..21be4f87e 100644 --- a/js/private/BUILD.bazel +++ b/js/private/BUILD.bazel @@ -31,6 +31,19 @@ bzl_library( ], ) +bzl_library( + name = "js_library", + srcs = ["js_library.bzl"], + visibility = [ + "//docs:__subpackages__", + "//js:__subpackages__", + ], + deps = [ + "@aspect_bazel_lib//lib:copy_to_bin", + "@rules_nodejs//nodejs:bzl", + ], +) + bzl_library( name = "run_js_binary", srcs = ["run_js_binary.bzl"], diff --git a/js/private/js_library.bzl b/js/private/js_library.bzl new file mode 100644 index 000000000..7ca7d867e --- /dev/null +++ b/js/private/js_library.bzl @@ -0,0 +1,110 @@ +"""Expose some files with DeclarationInfo, like filegroup but can be a dep of ts_project. + +Load this with, + +```starlark +load("@aspect_rules_js//js:defs.bzl", "js_library") +``` +""" + +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_files_to_bin_actions") +load("@rules_nodejs//nodejs:providers.bzl", "DeclarationInfo", "declaration_info") + +_DOC = """Copies all sources to the output tree and expose some files with DeclarationInfo. + +Can be used as a dep for rules that expect a DeclarationInfo such as ts_project.""" + +_ATTRS = { + "srcs": attr.label_list(allow_files = True), + "deps": attr.label_list(allow_files = True), + "_windows_constraint": attr.label(default = "@platforms//os:windows"), +} + +def _js_library_impl(ctx): + is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]) + + typings = [] + + for file in ctx.files.srcs: + if ctx.label.package != file.owner.package: + msg = """ + +Expected to find file {file_basename} in {this_package}, but instead it is in {file_package}. + +All srcs in a js_library must be in the same package as the js_library target. + +Either move {file_basename} to {this_package}, or create a js_library +target in {file_basename}'s package and add that target to the deps of {this_target}: + + buildozer 'new_load @aspect_rules_js//js:defs.bzl js_library' {file_package}:__pkg__ + buildozer 'new js_library {new_target_name}' {file_package}:__pkg__ + buildozer 'add srcs {file_basename}' {file_package}:{new_target_name} + buildozer 'add visibility {this_package}:__pkg__' {file_package}:{new_target_name} + buildozer 'remove srcs {file_package}:{file_basename}' {this_target} + buildozer 'add deps {file_package}:{new_target_name}' {this_target} + +""".format( + file_basename = file.basename, + file_package = "%s//%s" % (file.owner.workspace_name, file.owner.package), + new_target_name = file.basename.replace(".", "_"), + this_package = "%s//%s" % (ctx.label.workspace_name, ctx.label.package), + this_target = ctx.label, + ) + fail(msg) + + output_srcs = copy_files_to_bin_actions(ctx, ctx.files.srcs, is_windows = is_windows) + + for src in output_srcs: + if src.is_directory: + # assume a directory contains typings since we can't know that it doesn't + typings.append(src) + elif ( + src.path.endswith(".d.ts") or + src.path.endswith(".d.ts.map") or + # package.json may be required to resolve "typings" key + src.path.endswith("/package.json") + ): + typings.append(src) + + typings_depsets = [depset(typings)] + files_depsets = [depset(output_srcs)] + + for dep in ctx.attr.deps: + if DeclarationInfo in dep: + typings_depsets.append(dep[DeclarationInfo].declarations) + if DefaultInfo in dep: + files_depsets.append(dep[DefaultInfo].files) + + runfiles = ctx.runfiles( + files = output_srcs, + # We do not include typings_depsets in the runfiles because that would cause type-check actions to occur + # in every development workflow. + transitive_files = depset(transitive = files_depsets), + ) + deps_runfiles = [d[DefaultInfo].default_runfiles for d in ctx.attr.deps] + decls = depset(transitive = typings_depsets) + + return [ + DefaultInfo( + files = depset(transitive = files_depsets), + runfiles = runfiles.merge_all(deps_runfiles), + ), + declaration_info( + declarations = decls, + deps = ctx.attr.deps, + ), + OutputGroupInfo(types = decls), + ] + +js_library_lib = struct( + attrs = _ATTRS, + implementation = _js_library_impl, + provides = [DefaultInfo, DeclarationInfo], +) + +js_library = rule( + doc = _DOC, + implementation = js_library_lib.implementation, + attrs = js_library_lib.attrs, + provides = js_library_lib.provides, +) diff --git a/npm/private/test/defs_checked.bzl b/npm/private/test/defs_checked.bzl index a974c4f1e..e598b07e4 100755 --- a/npm/private/test/defs_checked.bzl +++ b/npm/private/test/defs_checked.bzl @@ -1,5 +1,6 @@ "@generated by @aspect_rules_js//npm/private:translate_pnpm_lock.bzl from pnpm lock file @//:pnpm-lock.yaml" +# buildifier: disable=bzl-visibility load("@aspect_rules_js//npm/private:linked_npm_packages.bzl", "linked_npm_packages") load("@npm__at_aspect-test_a__5.0.0__links//:defs.bzl", link_0 = "link_npm_package") load("@npm__at_aspect-test_b__5.0.0__links//:defs.bzl", link_1 = "link_npm_package")