diff --git a/packages/typescript/internal/ts_project.bzl b/packages/typescript/internal/ts_project.bzl index fcd0f2d13c..26f5ed10e5 100644 --- a/packages/typescript/internal/ts_project.bzl +++ b/packages/typescript/internal/ts_project.bzl @@ -116,6 +116,10 @@ def _ts_project_impl(ctx): outputs = json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs + ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs if ctx.outputs.buildinfo_out: + arguments.add_all([ + "--tsBuildInfoFile", + ctx.outputs.buildinfo_out.path, + ]) outputs.append(ctx.outputs.buildinfo_out) runtime_outputs = json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs typings_outputs = ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")] @@ -184,6 +188,7 @@ def _validate_options_impl(ctx): emit_declaration_only = ctx.attr.emit_declaration_only, source_map = ctx.attr.source_map, incremental = ctx.attr.incremental, + ts_build_info_file = ctx.attr.ts_build_info_file, ).to_json()]) run_node( @@ -210,6 +215,7 @@ validate_options = rule( "incremental": attr.bool(), "source_map": attr.bool(), "target": attr.string(), + "ts_build_info_file": attr.string(), "tsconfig": attr.label(mandatory = True, allow_single_file = [".json"]), "validator": attr.label(default = Label("//packages/typescript/bin:ts_project_options_validator"), executable = True, cfg = "host"), }, @@ -236,6 +242,7 @@ def ts_project_macro( composite = False, incremental = False, emit_declaration_only = False, + ts_build_info_file = None, tsc = None, validate = True, declaration_dir = None, @@ -394,6 +401,8 @@ def ts_project_macro( Instructs Bazel to expect a `.tsbuildinfo` output. emit_declaration_only: if the `emitDeclarationOnly` bit is set in the tsconfig. Instructs Bazel *not* to expect `.js` or `.js.map` outputs for `.ts` sources. + ts_build_info_file: the user-specified value of `tsBuildInfoFile` from the tsconfig. + Helps Bazel to predict the path where the .tsbuildinfo output is written. **kwargs: passed through to underlying rule, allows eg. visibility, tags """ @@ -416,12 +425,14 @@ def ts_project_macro( composite = composite, incremental = incremental, emit_declaration_only = emit_declaration_only, + ts_build_info_file = ts_build_info_file, tsconfig = tsconfig, extends = extends, ) extra_deps.append("_validate_%s_options" % name) typings_out_dir = declaration_dir if declaration_dir else out_dir + tsbuildinfo_path = ts_build_info_file if ts_build_info_file else tsconfig[:-5] + ".tsbuildinfo" ts_project( name = name, @@ -437,7 +448,7 @@ def ts_project_macro( map_outs = _out_paths(srcs, out_dir, root_dir, ".js.map") if source_map and not emit_declaration_only else [], typings_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts") if declaration or composite else [], typing_maps_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts.map") if declaration_map else [], - buildinfo_out = tsconfig[:-5] + ".tsbuildinfo" if composite or incremental else None, + buildinfo_out = tsbuildinfo_path if composite or incremental else None, tsc = tsc, **kwargs ) diff --git a/packages/typescript/internal/ts_project_options_validator.ts b/packages/typescript/internal/ts_project_options_validator.ts index e33f51f662..a8468446d9 100644 --- a/packages/typescript/internal/ts_project_options_validator.ts +++ b/packages/typescript/internal/ts_project_options_validator.ts @@ -1,3 +1,4 @@ +import {relative} from 'path'; import * as ts from 'typescript'; const diagnosticsHost: ts.FormatDiagnosticsHost = { @@ -29,14 +30,37 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 { const failures: string[] = []; const buildozerCmds: string[] = []; + + function getTsOption(option) { + if (typeof (options[option]) === 'string') { + // Currently the only string-typed options are filepaths. + // TypeScript will resolve these to a project path + // so when echoing that back to the user, we need to reverse that resolution. + // First turn //path/to/pkg:tsconfig into path/to/pkg + const packageDir = target.substr(2, target.indexOf(':') - 2); + return relative(packageDir, options[option] as string); + } + return options[option]; + } + function check(option: string, attr?: string) { attr = attr || option; // treat compilerOptions undefined as false - const optionVal = options[option] === undefined ? false : options[option]; - if (optionVal !== attrs[attr]) { + const optionVal = getTsOption(option); + const match = optionVal === attrs[attr] || + (optionVal === undefined && (attrs[attr] === false || attrs[attr] === '')); + if (!match) { failures.push( `attribute ${attr}=${attrs[attr]} does not match compilerOptions.${option}=${optionVal}`); - buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`); + if (typeof (optionVal) === 'boolean') { + buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`); + } else if (typeof (optionVal) === 'string') { + buildozerCmds.push(`set ${attr} \"${optionVal}\"`); + } else if (optionVal === undefined) { + // nothing to sync + } else { + throw new Error(`cannot check option ${option} of type ${typeof (option)}`); + } } } @@ -46,6 +70,7 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 { check('composite'); check('declaration'); check('incremental'); + check('tsBuildInfoFile', 'ts_build_info_file'); if (failures.length > 0) { console.error(`ERROR: ts_project rule ${ @@ -70,6 +95,7 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 { // incremental: ${attrs.incremental} // source_map: ${attrs.source_map} // emit_declaration_only: ${attrs.emit_declaration_only} +// ts_build_info_file: ${attrs.ts_build_info_file} `, 'utf-8'); return 0; @@ -81,4 +107,4 @@ if (require.main === module) { } catch (e) { console.error(process.argv[1], e); } -} \ No newline at end of file +} diff --git a/packages/typescript/test/ts_project/tsbuildinfofile/BUILD.bazel b/packages/typescript/test/ts_project/tsbuildinfofile/BUILD.bazel new file mode 100644 index 0000000000..0b8d3a94a6 --- /dev/null +++ b/packages/typescript/test/ts_project/tsbuildinfofile/BUILD.bazel @@ -0,0 +1,7 @@ +load("//packages/typescript:index.bzl", "ts_project") + +ts_project( + name = "tsconfig", + composite = True, + ts_build_info_file = "my.tsbuildinfo", +) diff --git a/packages/typescript/test/ts_project/tsbuildinfofile/a.ts b/packages/typescript/test/ts_project/tsbuildinfofile/a.ts new file mode 100644 index 0000000000..db233fb40c --- /dev/null +++ b/packages/typescript/test/ts_project/tsbuildinfofile/a.ts @@ -0,0 +1 @@ +export const a: string = ''; diff --git a/packages/typescript/test/ts_project/tsbuildinfofile/tsconfig.json b/packages/typescript/test/ts_project/tsbuildinfofile/tsconfig.json new file mode 100644 index 0000000000..4f34f64477 --- /dev/null +++ b/packages/typescript/test/ts_project/tsbuildinfofile/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "my.tsbuildinfo", + "types": [] + } +}