diff --git a/packages/typescript/checked_in_ts_project.bzl b/packages/typescript/checked_in_ts_project.bzl index b904ce3319..a2db49399c 100644 --- a/packages/typescript/checked_in_ts_project.bzl +++ b/packages/typescript/checked_in_ts_project.bzl @@ -1,7 +1,6 @@ "checked_in_ts_project rule" load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test") -load("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel-skylib:rules/write_file.bzl", "write_file") load("//packages/typescript:index.bzl", "ts_project") def checked_in_ts_project(name, src, checked_in_js = None, **kwargs): @@ -15,16 +14,13 @@ def checked_in_ts_project(name, src, checked_in_js = None, **kwargs): if not checked_in_js: checked_in_js = src[:-3] + ".js" - tsconfig = "tsconfig_%s.json" % name - - # workspace is up three dirs (bazel-out/arch/bin) plus number of segments in the package - workspace_root = "/".join([".."] * (3 + len(native.package_name().split("/")))) - - # Generate a tsconfig, this is partly an example of how it can be done, per jbedard and toxicable request - write_file( - name = "_gen_tsconfig_%s" % name, - content = [struct( - compilerOptions = struct( + ts_project( + name = name, + srcs = [src], + declaration = True, + # using config means a tsconfig.json file will be generated + config = { + "compilerOptions": struct( lib = ["es2017", "dom"], strict = True, target = "es2015", @@ -33,16 +29,7 @@ def checked_in_ts_project(name, src, checked_in_js = None, **kwargs): declaration = True, skipLibCheck = True, ), - files = ["/".join([workspace_root, native.package_name(), src])], - ).to_json()], - out = tsconfig, - ) - - ts_project( - name = name, - srcs = [src], - declaration = True, - tsconfig = tsconfig, + }, **kwargs ) diff --git a/packages/typescript/internal/ts_config.bzl b/packages/typescript/internal/ts_config.bzl index 2fc4f8e690..d83cd694ed 100644 --- a/packages/typescript/internal/ts_config.bzl +++ b/packages/typescript/internal/ts_config.bzl @@ -14,6 +14,8 @@ "tsconfig.json files using extends" +load("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel-skylib:rules/write_file.bzl", "write_file") + TsConfigInfo = provider() def _ts_config_impl(ctx): @@ -46,3 +48,21 @@ feature from TypeScript, then the Bazel implementation needs to know about that extended configuration file as well, to pass them both to the TypeScript compiler. """, ) + +def _join(*elements): + return "/".join([f for f in elements if f]) + +# Syntax sugar around skylib's write_file +def write_tsconfig(name, config, files, out): + # workspace is up three dirs (bazel-out/arch/bin) plus number of segments in the package + workspace_root = "/".join([".."] * (3 + len(native.package_name().split("/")))) + + amended_config = struct( + files = [_join(workspace_root, native.package_name(), f) for f in files], + **config + ) + write_file( + name = name, + content = [amended_config.to_json()], + out = out, + ) diff --git a/packages/typescript/internal/ts_project.bzl b/packages/typescript/internal/ts_project.bzl index fcd0f2d13c..3b71c199b8 100644 --- a/packages/typescript/internal/ts_project.bzl +++ b/packages/typescript/internal/ts_project.bzl @@ -2,6 +2,7 @@ load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "NpmPackageInfo", "declaration_info", "js_module_info", "run_node") load("@build_bazel_rules_nodejs//internal/linker:link_node_modules.bzl", "module_mappings_aspect") +load(":ts_config.bzl", "write_tsconfig") _DEFAULT_TSC = ( # BEGIN-INTERNAL @@ -226,6 +227,7 @@ def _out_paths(srcs, outdir, rootdir, ext): def ts_project_macro( name = "tsconfig", tsconfig = None, + config = None, srcs = None, args = [], deps = [], @@ -349,6 +351,13 @@ def ts_project_macro( deps: List of labels of other rules that produce TypeScript typings (.d.ts files) + config: EXPERIMENTAL a dictionary of tsconfig keys. + + If specified, a tsconfig.json file will be generated for this compilation. + You may use only one of config or tsconfig + + Each file in srcs will be converted to a relative path in the `files` section. + tsconfig: Label of the tsconfig.json file to use for the compilation. By default, we add `.json` to the `name` attribute. @@ -400,26 +409,40 @@ def ts_project_macro( if srcs == None: srcs = native.glob(["**/*.ts", "**/*.tsx"]) - - if tsconfig == None: - tsconfig = name + ".json" - extra_deps = [] - if validate: - validate_options( - name = "_validate_%s_options" % name, - target = "//%s:%s" % (native.package_name(), name), - declaration = declaration, - source_map = source_map, - declaration_map = declaration_map, - composite = composite, - incremental = incremental, - emit_declaration_only = emit_declaration_only, - tsconfig = tsconfig, - extends = extends, + if config != None: + # Usage with a config attribute that generates a tsconfig.json + if tsconfig != None: + fail("only one of config or tsconfig may be set") + + tsconfig = "tsconfig_%s.json" % name + write_tsconfig( + name = "_gen_tsconfig_%s" % name, + config = config, + files = srcs, + out = tsconfig, ) - extra_deps.append("_validate_%s_options" % name) + + else: + # Usage with a user-defined tsconfig.json file + if tsconfig == None: + tsconfig = name + ".json" + + if validate: + validate_options( + name = "_validate_%s_options" % name, + target = "//%s:%s" % (native.package_name(), name), + declaration = declaration, + source_map = source_map, + declaration_map = declaration_map, + composite = composite, + incremental = incremental, + emit_declaration_only = emit_declaration_only, + tsconfig = tsconfig, + extends = extends, + ) + extra_deps.append("_validate_%s_options" % name) typings_out_dir = declaration_dir if declaration_dir else out_dir diff --git a/packages/typescript/test/ts_project/generated_tsconfig/BUILD.bazel b/packages/typescript/test/ts_project/generated_tsconfig/BUILD.bazel new file mode 100644 index 0000000000..e541902e3b --- /dev/null +++ b/packages/typescript/test/ts_project/generated_tsconfig/BUILD.bazel @@ -0,0 +1,32 @@ +load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test") +load("//packages/typescript:index.bzl", "ts_project") + +ts_project( + name = "compile1", + srcs = glob(["*.ts*"]), + config = {}, + out_dir = "1", +) + +generated_file_test( + name = "test1", + src = "empty_config.js_", + generated = ":1/a.js", +) + +ts_project( + name = "compile2", + srcs = glob(["*.ts*"]), + config = { + "compilerOptions": { + "module": "esnext", + }, + }, + out_dir = "2", +) + +generated_file_test( + name = "test2", + src = "esnext.js_", + generated = ":2/a.js", +) diff --git a/packages/typescript/test/ts_project/generated_tsconfig/a.ts b/packages/typescript/test/ts_project/generated_tsconfig/a.ts new file mode 100644 index 0000000000..f32045c3a2 --- /dev/null +++ b/packages/typescript/test/ts_project/generated_tsconfig/a.ts @@ -0,0 +1 @@ +export const a: string = 'hello world'; diff --git a/packages/typescript/test/ts_project/generated_tsconfig/empty_config.js_ b/packages/typescript/test/ts_project/generated_tsconfig/empty_config.js_ new file mode 100644 index 0000000000..3b0b11cce7 --- /dev/null +++ b/packages/typescript/test/ts_project/generated_tsconfig/empty_config.js_ @@ -0,0 +1,3 @@ +"use strict"; +exports.__esModule = true; +exports.a = 'hello world'; diff --git a/packages/typescript/test/ts_project/generated_tsconfig/esnext.js_ b/packages/typescript/test/ts_project/generated_tsconfig/esnext.js_ new file mode 100644 index 0000000000..7dc7ad7c64 --- /dev/null +++ b/packages/typescript/test/ts_project/generated_tsconfig/esnext.js_ @@ -0,0 +1 @@ +export var a = 'hello world';