feat(dev-infra): add bazel rule for extracting JavaScript module flavors from targets (#42809)

Introduces a rule that collects declared JavaScript module output files
from a list of dependencies based on a configurable JavaScript module
provider. The extracted outputs are exposed within the `DefaultInfo` provider.

Targets defined using this rule can be used as input for rules that
require JavaScript sources, or if there are multiple JavaScript output
variants defined for a target while for example only the `JSModuleInfo`
outputs are of interest.

As an example: This rule is helpful in combination with `ts_library` and
`ng_module` as those rule expose multiple output flavors (which are
distinguishable by the JavaScript module providers as imported from `providers.bzl`).
i.e. these rules expose flavors for named AMD modules and ECMAScript module output.
If we want to ship a NPM package only using ECMAScript modules for
example, we could extract all `JSEcmaScriptModuleInfo`-denoted output
and feed that into the `pkg_npm` rule, compared to bringing in all
output flavors.

For reference:
https://github.com/bazelbuild/rules_nodejs/blob/stable/packages/typescript/internal/build_defs.bzl#L334-L337

PR Close #42809
This commit is contained in:
Paul Gschwendtner 2021-07-09 20:22:50 +02:00 committed by Andrew Kushnir
parent ef15b979cf
commit 9af5abba86
2 changed files with 79 additions and 0 deletions

View File

@ -5,6 +5,7 @@ filegroup(
srcs = [
"BUILD.bazel",
"expand_template.bzl",
"extract_js_module_output.bzl",
"//dev-infra/bazel/api-golden:files",
"//dev-infra/bazel/browsers:files",
"//dev-infra/bazel/remote-execution:files",

View File

@ -0,0 +1,78 @@
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSModuleInfo", "JSNamedModuleInfo")
"""Converts a provider name to its actually Starlark provider instance."""
def _name_to_js_module_provider(name):
if name == "JSModuleInfo":
return JSModuleInfo
elif name == "JSNamedModuleInfo":
return JSNamedModuleInfo
elif name == "JSEcmaScriptModuleInfo":
return JSEcmaScriptModuleInfo
fail("Unexpected JavaScript module provider.")
"""Implementation of the extract_js_module_output rule."""
def _extract_js_module_output_impl(ctx):
js_module_provider = _name_to_js_module_provider(ctx.attr.provider)
depsets = []
for dep in ctx.attr.deps:
# Include JavaScript sources (including transitive outputs) based on the
# configured JavaScript module provider.
if js_module_provider in dep:
depsets.append(dep[js_module_provider].sources)
# Based on whether declarations should be collected, extract direct
# and transitive declaration files using the `DeclarationInfo` provider.
if ctx.attr.include_declarations and DeclarationInfo in dep:
depsets.append(dep[DeclarationInfo].transitive_declarations)
# Based on whether default files should be collected, extract direct
# files which are exposed using the `DefaultInfo` provider. Also include
# data runfiles which are needed for the current target.
# https://docs.bazel.build/versions/main/skylark/lib/DefaultInfo.html#data_runfiles
if ctx.attr.include_default_files and DefaultInfo in dep:
depsets.append(dep[DefaultInfo].files)
depsets.append(dep[DefaultInfo].data_runfiles.files)
sources = depset(transitive = depsets)
return [DefaultInfo(files = sources)]
"""
Rule that collects declared JavaScript module output files from a list of dependencies
based on a configurable JavaScript module provider. The extracted outputs are exposed
within the `DefaultInfo` provider. Targets defined using this rule can be used as input
for rules that require JavaScript sources, or if there are multiple JavaScript output
variants defined for a target while for example only the `JSModule` outputs are of interest.
As an example: This rule is helpful in combination with `ts_library` and `ng_module` as
those rule expose multiple output flavors (which are distinguishable by the JavaScript module
providers as imported from `providers.bzl`). i.e. these rules expose flavors for named AMD
modules and ECMAScript module output. For reference:
https://github.com/bazelbuild/rules_nodejs/blob/stable/packages/typescript/internal/build_defs.bzl#L334-L337
"""
extract_js_module_output = rule(
implementation = _extract_js_module_output_impl,
attrs = {
"deps": attr.label_list(
allow_files = True,
),
"provider": attr.string(
doc = "JavaScript module info provider that is used for collecting sources from the dependencies.",
mandatory = True,
values = ["JSModuleInfo", "JSNamedModuleInfo", "JSEcmaScriptModuleInfo"],
),
"include_declarations": attr.bool(
mandatory = True,
doc = "Whether declaration files should be collected from the dependencies.",
),
"include_default_files": attr.bool(
mandatory = True,
doc = """
Whether files from the `DefaultInfo` provider should be collected. Includes
data runfiles needed for the default outputs from dependencies.
""",
),
},
)