Skip to content

Commit 16def64

Browse files
authored
fix(typescript): add the tsBuildInfoFile option to ts_project (#2138)
Like other options that affect tsc outputs, Bazel needs to know the value from the tsconfig if its set. Add it to our validator so there's a buildozer command to sync the option value into the BUILD file. Fixes #2137
1 parent 660b456 commit 16def64

5 files changed

Lines changed: 57 additions & 5 deletions

File tree

packages/typescript/internal/ts_project.bzl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ def _ts_project_impl(ctx):
116116

117117
outputs = json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs + ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs
118118
if ctx.outputs.buildinfo_out:
119+
arguments.add_all([
120+
"--tsBuildInfoFile",
121+
ctx.outputs.buildinfo_out.path,
122+
])
119123
outputs.append(ctx.outputs.buildinfo_out)
120124
runtime_outputs = json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs
121125
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):
184188
emit_declaration_only = ctx.attr.emit_declaration_only,
185189
source_map = ctx.attr.source_map,
186190
incremental = ctx.attr.incremental,
191+
ts_build_info_file = ctx.attr.ts_build_info_file,
187192
).to_json()])
188193

189194
run_node(
@@ -210,6 +215,7 @@ validate_options = rule(
210215
"incremental": attr.bool(),
211216
"source_map": attr.bool(),
212217
"target": attr.string(),
218+
"ts_build_info_file": attr.string(),
213219
"tsconfig": attr.label(mandatory = True, allow_single_file = [".json"]),
214220
"validator": attr.label(default = Label("//packages/typescript/bin:ts_project_options_validator"), executable = True, cfg = "host"),
215221
},
@@ -236,6 +242,7 @@ def ts_project_macro(
236242
composite = False,
237243
incremental = False,
238244
emit_declaration_only = False,
245+
ts_build_info_file = None,
239246
tsc = None,
240247
validate = True,
241248
declaration_dir = None,
@@ -394,6 +401,8 @@ def ts_project_macro(
394401
Instructs Bazel to expect a `.tsbuildinfo` output.
395402
emit_declaration_only: if the `emitDeclarationOnly` bit is set in the tsconfig.
396403
Instructs Bazel *not* to expect `.js` or `.js.map` outputs for `.ts` sources.
404+
ts_build_info_file: the user-specified value of `tsBuildInfoFile` from the tsconfig.
405+
Helps Bazel to predict the path where the .tsbuildinfo output is written.
397406
398407
**kwargs: passed through to underlying rule, allows eg. visibility, tags
399408
"""
@@ -416,12 +425,14 @@ def ts_project_macro(
416425
composite = composite,
417426
incremental = incremental,
418427
emit_declaration_only = emit_declaration_only,
428+
ts_build_info_file = ts_build_info_file,
419429
tsconfig = tsconfig,
420430
extends = extends,
421431
)
422432
extra_deps.append("_validate_%s_options" % name)
423433

424434
typings_out_dir = declaration_dir if declaration_dir else out_dir
435+
tsbuildinfo_path = ts_build_info_file if ts_build_info_file else tsconfig[:-5] + ".tsbuildinfo"
425436

426437
ts_project(
427438
name = name,
@@ -437,7 +448,7 @@ def ts_project_macro(
437448
map_outs = _out_paths(srcs, out_dir, root_dir, ".js.map") if source_map and not emit_declaration_only else [],
438449
typings_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts") if declaration or composite else [],
439450
typing_maps_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts.map") if declaration_map else [],
440-
buildinfo_out = tsconfig[:-5] + ".tsbuildinfo" if composite or incremental else None,
451+
buildinfo_out = tsbuildinfo_path if composite or incremental else None,
441452
tsc = tsc,
442453
**kwargs
443454
)

packages/typescript/internal/ts_project_options_validator.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {relative} from 'path';
12
import * as ts from 'typescript';
23

34
const diagnosticsHost: ts.FormatDiagnosticsHost = {
@@ -29,14 +30,37 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 {
2930

3031
const failures: string[] = [];
3132
const buildozerCmds: string[] = [];
33+
34+
function getTsOption(option) {
35+
if (typeof (options[option]) === 'string') {
36+
// Currently the only string-typed options are filepaths.
37+
// TypeScript will resolve these to a project path
38+
// so when echoing that back to the user, we need to reverse that resolution.
39+
// First turn //path/to/pkg:tsconfig into path/to/pkg
40+
const packageDir = target.substr(2, target.indexOf(':') - 2);
41+
return relative(packageDir, options[option] as string);
42+
}
43+
return options[option];
44+
}
45+
3246
function check(option: string, attr?: string) {
3347
attr = attr || option;
3448
// treat compilerOptions undefined as false
35-
const optionVal = options[option] === undefined ? false : options[option];
36-
if (optionVal !== attrs[attr]) {
49+
const optionVal = getTsOption(option);
50+
const match = optionVal === attrs[attr] ||
51+
(optionVal === undefined && (attrs[attr] === false || attrs[attr] === ''));
52+
if (!match) {
3753
failures.push(
3854
`attribute ${attr}=${attrs[attr]} does not match compilerOptions.${option}=${optionVal}`);
39-
buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`);
55+
if (typeof (optionVal) === 'boolean') {
56+
buildozerCmds.push(`set ${attr} ${optionVal ? 'True' : 'False'}`);
57+
} else if (typeof (optionVal) === 'string') {
58+
buildozerCmds.push(`set ${attr} \"${optionVal}\"`);
59+
} else if (optionVal === undefined) {
60+
// nothing to sync
61+
} else {
62+
throw new Error(`cannot check option ${option} of type ${typeof (option)}`);
63+
}
4064
}
4165
}
4266

@@ -46,6 +70,7 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 {
4670
check('composite');
4771
check('declaration');
4872
check('incremental');
73+
check('tsBuildInfoFile', 'ts_build_info_file');
4974

5075
if (failures.length > 0) {
5176
console.error(`ERROR: ts_project rule ${
@@ -70,6 +95,7 @@ function main([tsconfigPath, output, target, attrsStr]: string[]): 0|1 {
7095
// incremental: ${attrs.incremental}
7196
// source_map: ${attrs.source_map}
7297
// emit_declaration_only: ${attrs.emit_declaration_only}
98+
// ts_build_info_file: ${attrs.ts_build_info_file}
7399
`,
74100
'utf-8');
75101
return 0;
@@ -81,4 +107,4 @@ if (require.main === module) {
81107
} catch (e) {
82108
console.error(process.argv[1], e);
83109
}
84-
}
110+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
load("//packages/typescript:index.bzl", "ts_project")
2+
3+
ts_project(
4+
name = "tsconfig",
5+
composite = True,
6+
ts_build_info_file = "my.tsbuildinfo",
7+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const a: string = '';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"composite": true,
4+
"tsBuildInfoFile": "my.tsbuildinfo",
5+
"types": []
6+
}
7+
}

0 commit comments

Comments
 (0)