From 18f0f1c7e6eb5a95c1ac046ea9596a0b48ff36df Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Thu, 27 Aug 2020 10:21:53 -0700 Subject: [PATCH] feat(typescript): accept TsConfigInfo in extends --- packages/typescript/internal/ts_config.bzl | 15 ++----- packages/typescript/internal/ts_project.bzl | 35 +++++++++++++---- .../generated_tsconfig/extends/BUILD.bazel | 39 +++++++++++++++++-- .../extends/tsconfig-extended.json | 6 +++ .../ts_project/ts_config_info/BUILD.bazel | 5 +-- 5 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 packages/typescript/test/ts_project/generated_tsconfig/extends/tsconfig-extended.json diff --git a/packages/typescript/internal/ts_config.bzl b/packages/typescript/internal/ts_config.bzl index 06896d5b4f..88841534ba 100644 --- a/packages/typescript/internal/ts_config.bzl +++ b/packages/typescript/internal/ts_config.bzl @@ -99,29 +99,22 @@ write_tsconfig_rule = rule( ) # Syntax sugar around skylib's write_file -def write_tsconfig(name, config, files, extends, out): +def write_tsconfig(name, config, files, out, extends = None): """Wrapper around bazel_skylib's write_file which understands tsconfig paths Args: name: name of the resulting write_file rule config: tsconfig dictionary files: list of input .ts files to put in the files[] array - extends: a tsconfig.json file to extend from out: the file to write + extends: a label for a tsconfig.json file to extend from, if any """ - # Allow extends to be a list of labels, as this is what ts_project accepts - if type(extends) == type([]): - if len(extends): - extends = extends[0] - else: - extends = None if extends: - extends = Label(extends) - config["extends"] = "__extends__" #_join(workspace_root, extends.package, extends.name) + config["extends"] = "__extends__" amended_config = struct( - files = "__files__", #[_join(workspace_root, native.package_name(), f) for f in files], + files = "__files__", **config ) write_tsconfig_rule( diff --git a/packages/typescript/internal/ts_project.bzl b/packages/typescript/internal/ts_project.bzl index e7ce6b9e4f..7768d13417 100644 --- a/packages/typescript/internal/ts_project.bzl +++ b/packages/typescript/internal/ts_project.bzl @@ -105,12 +105,17 @@ def _ts_project_impl(ctx): deps_depsets.append(dep[DeclarationInfo].transitive_declarations) inputs = ctx.files.srcs + depset(transitive = deps_depsets).to_list() + + # Gather TsConfig info from both the direct (tsconfig) and indirect (extends) attribute if TsConfigInfo in ctx.attr.tsconfig: inputs.extend(ctx.attr.tsconfig[TsConfigInfo].deps) else: inputs.append(ctx.file.tsconfig) - if ctx.attr.extends: - inputs.extend(ctx.files.extends) + for extend in ctx.attr.extends: + if TsConfigInfo in extend: + inputs.extend(extend[TsConfigInfo].deps) + else: + inputs.extend(extend.files.to_list()) # We do not try to predeclare json_outs, because their output locations generally conflict with their path in the source tree. # (The exception is when out_dir is used, then the .json output is a different path than the input.) @@ -374,7 +379,10 @@ def ts_project_macro( deps: List of labels of other rules that produce TypeScript typings (.d.ts files) - tsconfig: Label of the tsconfig.json file to use for the compilation, or a target that provides TsConfigInfo. + tsconfig: Label of the tsconfig.json file to use for the compilation + + To support "chaining" of more than one extended config, this label could be a target that + provdes `TsConfigInfo` such as `ts_config`. By default, we assume the tsconfig file is named by adding `.json` to the `name` attribute. @@ -407,10 +415,15 @@ def ts_project_macro( ) ``` - extends: List of labels of tsconfig file(s) referenced in `extends` section of tsconfig. + extends: Label of the tsconfig file referenced in the `extends` section of tsconfig - Any tsconfig files "chained" by extends clauses must either be transitive deps of the TsConfigInfo - provided to the `tsconfig` attribute, or must be explicitly listed here. + To support "chaining" of more than one extended config, this label could be a target that + provdes `TsConfigInfo` such as `ts_config`. + + _DEPRECATED, to be removed in 3.0_: + For backwards compatibility, this accepts a list of Labels of the "chained" + tsconfig files. You should instead use a single Label of a `ts_config` target. + Follow this deprecation: https://github.com/bazelbuild/rules_nodejs/issues/2140 args: List of strings of additional command-line arguments to pass to tsc. @@ -460,6 +473,10 @@ def ts_project_macro( extra_deps = [] if type(tsconfig) == type(dict()): + # Opt-in to #2140 breaking change at the same time you opt-in to experimental tsconfig dict + if type(extends) == type([]): + fail("when tsconfig is a dict, extends should have a single value") + # Copy attributes <-> tsconfig properties # TODO: fail if compilerOptions includes a conflict with an attribute? compiler_options = tsconfig.setdefault("compilerOptions", {}) @@ -482,7 +499,7 @@ def ts_project_macro( name = "_gen_tsconfig_%s" % name, config = tsconfig, files = srcs, - extends = extends, + extends = Label("//%s:%s" % (native.package_name(), name)).relative(extends) if extends else None, out = "tsconfig_%s.json" % name, ) @@ -513,6 +530,10 @@ def ts_project_macro( typings_out_dir = declaration_dir if declaration_dir else out_dir tsbuildinfo_path = ts_build_info_file if ts_build_info_file else name + ".tsbuildinfo" + # Backcompat for extends as a list, to cleanup in #2140 + if (type(extends) == type("")): + extends = [extends] + ts_project( name = name, srcs = srcs, diff --git a/packages/typescript/test/ts_project/generated_tsconfig/extends/BUILD.bazel b/packages/typescript/test/ts_project/generated_tsconfig/extends/BUILD.bazel index 7694eb5545..dd553d98d7 100644 --- a/packages/typescript/test/ts_project/generated_tsconfig/extends/BUILD.bazel +++ b/packages/typescript/test/ts_project/generated_tsconfig/extends/BUILD.bazel @@ -1,19 +1,50 @@ load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test") -load("//packages/typescript:index.bzl", "ts_project") +load("//packages/typescript:index.bzl", "ts_config", "ts_project") +# Case one: extend from a single tsconfig ts_project( - extends = ["//packages/typescript/test/ts_project:tsconfig-base.json"], + name = "case_one", + extends = "//packages/typescript/test/ts_project:tsconfig-base.json", tsconfig = { "compilerOptions": { "declaration": True, + "outDir": "case_one", "types": [], }, }, ) +ts_config( + name = "tsconfig_chain", + src = "tsconfig-extended.json", + deps = [ + "//packages/typescript/test/ts_project:tsconfig", + ], +) + +# Case two: extend from a chain of tsconfig +ts_project( + name = "case_two", + extends = ":tsconfig_chain", + tsconfig = { + "compilerOptions": { + "declaration": True, + "outDir": "case_two", + "types": [], + }, + }, +) + +generated_file_test( + name = "test_one", + # test the default output of the ts_project + src = "expected.js_", + generated = "case_one/a.js", +) + generated_file_test( - name = "test", + name = "test_two", # test the default output of the ts_project src = "expected.js_", - generated = "a.js", + generated = "case_two/a.js", ) diff --git a/packages/typescript/test/ts_project/generated_tsconfig/extends/tsconfig-extended.json b/packages/typescript/test/ts_project/generated_tsconfig/extends/tsconfig-extended.json new file mode 100644 index 0000000000..ae65966f72 --- /dev/null +++ b/packages/typescript/test/ts_project/generated_tsconfig/extends/tsconfig-extended.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig-base", + "compilerOptions": { + "declaration": true + }, +} diff --git a/packages/typescript/test/ts_project/ts_config_info/BUILD.bazel b/packages/typescript/test/ts_project/ts_config_info/BUILD.bazel index c04a583f4e..e16b566eaf 100644 --- a/packages/typescript/test/ts_project/ts_config_info/BUILD.bazel +++ b/packages/typescript/test/ts_project/ts_config_info/BUILD.bazel @@ -5,7 +5,7 @@ Test a tree of tsconfig.json files load("//packages/typescript:index.bzl", "ts_config", "ts_project") ts_config( - name = "tsconfig.abcd", + name = "tsconfig", src = "tsconfig.json", deps = [ "tsconfig-extended.json", @@ -17,6 +17,5 @@ ts_project( name = "compile_ts", composite = True, declaration = True, - # We'll name the tsbuildinfo output after tsconfig[:-5] so fool it for now - tsconfig = "tsconfig.abcd", + tsconfig = "tsconfig", )