Skip to content

Commit 981e7c1

Browse files
authored
feat(typescript): support for declarationdir on ts_project (#2048)
* feat(typescript): support for declarationdir on ts_project * refactor: rename ts_library attributes to the snake_case version of their TypeScript names --outDir == out_dir --declarationDir == declaration_dir --rootDir == root_dir Note this is non-breaking since none of these attributes are on the 1.x branch
1 parent 8a8e512 commit 981e7c1

12 files changed

Lines changed: 154 additions & 24 deletions

File tree

packages/typescript/internal/ts_project.bzl

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ _DEFAULT_TSC = (
1111

1212
_ATTRS = {
1313
"args": attr.string_list(),
14+
"declaration_dir": attr.string(),
1415
"deps": attr.label_list(providers = [DeclarationInfo]),
1516
"extends": attr.label_list(allow_files = [".json"]),
16-
"outdir": attr.string(),
17-
"rootdir": attr.string(),
17+
"out_dir": attr.string(),
18+
"root_dir": attr.string(),
1819
# NB: no restriction on extensions here, because tsc sometimes adds type-check support
1920
# for more file kinds (like require('some.json')) and also
2021
# if you swap out the `compiler` attribute (like with ngtsc)
@@ -56,14 +57,15 @@ def _ts_project_impl(ctx):
5657
"--project",
5758
ctx.file.tsconfig.path,
5859
"--outDir",
59-
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.outdir),
60+
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.out_dir),
6061
"--rootDir",
61-
_join(ctx.label.package, ctx.attr.rootdir) if ctx.label.package else ".",
62+
_join(ctx.label.package, ctx.attr.root_dir) if ctx.label.package else ".",
6263
])
6364
if len(ctx.outputs.typings_outs) > 0:
65+
declaration_dir = ctx.attr.declaration_dir if ctx.attr.declaration_dir else ctx.attr.out_dir
6466
arguments.add_all([
6567
"--declarationDir",
66-
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.outdir),
68+
_join(ctx.bin_dir.path, ctx.label.package, declaration_dir),
6769
])
6870

6971
# When users report problems, we can ask them to re-build with
@@ -98,13 +100,13 @@ def _ts_project_impl(ctx):
98100
inputs.extend(ctx.files.extends)
99101

100102
# We do not try to predeclare json_outs, because their output locations generally conflict with their path in the source tree.
101-
# (The exception is when outdir is used, then the .json output is a different path than the input.)
103+
# (The exception is when out_dir is used, then the .json output is a different path than the input.)
102104
# However tsc will copy .json srcs to the output tree so we want to declare these outputs to include along with .js Default outs
103105
# NB: We don't have emit_declaration_only setting here, so use presence of any JS outputs as an equivalent.
104106
# tsc will only produce .json if it also produces .js
105107
if len(ctx.outputs.js_outs):
106108
json_outs = [
107-
ctx.actions.declare_file(_join(ctx.attr.outdir, src.short_path[len(ctx.label.package) + 1:]))
109+
ctx.actions.declare_file(_join(ctx.attr.out_dir, src.short_path[len(ctx.label.package) + 1:]))
108110
for src in ctx.files.srcs
109111
if src.basename.endswith(".json")
110112
]
@@ -115,7 +117,7 @@ def _ts_project_impl(ctx):
115117
if ctx.outputs.buildinfo_out:
116118
outputs.append(ctx.outputs.buildinfo_out)
117119
runtime_outputs = depset(json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs)
118-
typings_outputs = ctx.outputs.typings_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")]
120+
typings_outputs = ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")]
119121

120122
if len(outputs) > 0:
121123
run_node(
@@ -230,8 +232,9 @@ def ts_project_macro(
230232
emit_declaration_only = False,
231233
tsc = None,
232234
validate = True,
233-
outdir = None,
234-
rootdir = None,
235+
declaration_dir = None,
236+
out_dir = None,
237+
root_dir = None,
235238
**kwargs):
236239
"""Compiles one TypeScript project using `tsc --project`
237240
@@ -357,13 +360,21 @@ def ts_project_macro(
357360
358361
validate: boolean; whether to check that the tsconfig settings match the attributes.
359362
360-
outdir: a string specifying a subdirectory under the bazel-out folder where outputs are written.
363+
root_dir: a string specifying a subdirectory under the input package which should be consider the
364+
root directory of all the input files.
365+
Equivalent to the TypeScript --rootDir option.
366+
By default it is '.', meaning the source directory where the BUILD file lives.
367+
368+
out_dir: a string specifying a subdirectory under the bazel-out folder where outputs are written.
369+
Equivalent to the TypeScript --outDir option.
361370
Note that Bazel always requires outputs be written under a subdirectory matching the input package,
362-
so if your rule appears in path/to/my/package/BUILD.bazel and outdir = "foo" then the .js files
363-
will appear in bazel-out/[arch]/bin/path/to/my/package/foo/*.js
371+
so if your rule appears in path/to/my/package/BUILD.bazel and out_dir = "foo" then the .js files
372+
will appear in bazel-out/[arch]/bin/path/to/my/package/foo/*.js.
373+
By default the out_dir is '.', meaning the packages folder in bazel-out.
364374
365-
rootdir: a string specifying a subdirectory under the input package which should be consider the
366-
root directory of all the input files.
375+
declaration_dir: a string specifying a subdirectory under the bazel-out folder where generated declaration
376+
outputs are written. Equivalent to the TypeScript --declarationDir option.
377+
By default declarations are written to the out_dir.
367378
368379
declaration: if the `declaration` bit is set in the tsconfig.
369380
Instructs Bazel to expect a `.d.ts` output for each `.ts` source.
@@ -377,6 +388,8 @@ def ts_project_macro(
377388
Instructs Bazel to expect a `.tsbuildinfo` output.
378389
emit_declaration_only: if the `emitDeclarationOnly` bit is set in the tsconfig.
379390
Instructs Bazel *not* to expect `.js` or `.js.map` outputs for `.ts` sources.
391+
392+
**kwargs: passed through to underlying rule, allows eg. visibility, tags
380393
"""
381394

382395
if srcs == None:
@@ -402,19 +415,22 @@ def ts_project_macro(
402415
)
403416
extra_deps.append("_validate_%s_options" % name)
404417

418+
typings_out_dir = declaration_dir if declaration_dir else out_dir
419+
405420
ts_project(
406421
name = name,
407422
srcs = srcs,
408423
args = args,
409424
deps = deps + extra_deps,
410425
tsconfig = tsconfig,
411426
extends = extends,
412-
outdir = outdir,
413-
rootdir = rootdir,
414-
js_outs = _out_paths(srcs, outdir, rootdir, ".js") if not emit_declaration_only else [],
415-
map_outs = _out_paths(srcs, outdir, rootdir, ".js.map") if source_map and not emit_declaration_only else [],
416-
typings_outs = _out_paths(srcs, outdir, rootdir, ".d.ts") if declaration or composite else [],
417-
typing_maps_outs = _out_paths(srcs, outdir, rootdir, ".d.ts.map") if declaration_map else [],
427+
declaration_dir = declaration_dir,
428+
out_dir = out_dir,
429+
root_dir = root_dir,
430+
js_outs = _out_paths(srcs, out_dir, root_dir, ".js") if not emit_declaration_only else [],
431+
map_outs = _out_paths(srcs, out_dir, root_dir, ".js.map") if source_map and not emit_declaration_only else [],
432+
typings_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts") if declaration or composite else [],
433+
typing_maps_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts.map") if declaration_map else [],
418434
buildinfo_out = tsconfig[:-5] + ".tsbuildinfo" if composite or incremental else None,
419435
tsc = tsc,
420436
**kwargs
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
2+
load("//packages/typescript:index.bzl", "ts_project")
3+
4+
# Ensure that subdir/a.ts produces outDir/a.js and outDir/a.d.ts
5+
SRCS = [
6+
"subdir/a.ts",
7+
]
8+
9+
ts_project(
10+
name = "tsconfig",
11+
srcs = SRCS,
12+
declaration = True,
13+
declaration_map = True,
14+
out_dir = "out",
15+
root_dir = "subdir",
16+
source_map = True,
17+
)
18+
19+
filegroup(
20+
name = "types",
21+
srcs = [":tsconfig"],
22+
output_group = "types",
23+
)
24+
25+
nodejs_test(
26+
name = "test",
27+
data = [
28+
":tsconfig",
29+
":types",
30+
],
31+
entry_point = "verify.js",
32+
templated_args = [
33+
"$(locations :types)",
34+
"$(locations :tsconfig)",
35+
],
36+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const a: string = 'hello';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"sourceMap": true,
4+
"declaration": true,
5+
"declarationMap": true,
6+
"types": []
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const assert = require('assert');
2+
3+
const types_files = process.argv.slice(2, 4);
4+
const code_files = process.argv.slice(4, 6);
5+
assert.ok(types_files.some(f => f.endsWith('declarationdir/out/a.d.ts')), 'Missing a.d.ts');
6+
assert.ok(types_files.some(f => f.endsWith('declarationdir/out/a.d.ts.map')), 'Missing a.d.ts.map');
7+
assert.ok(code_files.some(f => f.endsWith('declarationdir/out/a.js')), 'Missing a.js');
8+
assert.ok(code_files.some(f => f.endsWith('declarationdir/out/a.js.map')), 'Missing a.js.map');
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
2+
load("//packages/typescript:index.bzl", "ts_project")
3+
4+
# Ensure that subdir/a.ts produces outDir/a.js and declarationDir/a.d.ts
5+
SRCS = [
6+
"subdir/a.ts",
7+
]
8+
9+
ts_project(
10+
name = "tsconfig",
11+
srcs = SRCS,
12+
declaration = True,
13+
declaration_dir = "out/types",
14+
declaration_map = True,
15+
out_dir = "out/code",
16+
root_dir = "subdir",
17+
source_map = True,
18+
)
19+
20+
filegroup(
21+
name = "types",
22+
srcs = [":tsconfig"],
23+
output_group = "types",
24+
)
25+
26+
nodejs_test(
27+
name = "test",
28+
data = [
29+
":tsconfig",
30+
":types",
31+
],
32+
entry_point = "verify.js",
33+
templated_args = [
34+
"$(locations :types)",
35+
"$(locations :tsconfig)",
36+
],
37+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const a: string = 'hello';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"sourceMap": true,
4+
"declaration": true,
5+
"declarationMap": true,
6+
"types": []
7+
}
8+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const assert = require('assert');
2+
3+
const types_files = process.argv.slice(2, 4);
4+
const code_files = process.argv.slice(4, 6);
5+
assert.ok(
6+
types_files.some(f => f.endsWith('declarationdir_with_value/out/types/a.d.ts')),
7+
'Missing a.d.ts');
8+
assert.ok(
9+
types_files.some(f => f.endsWith('declarationdir_with_value/out/types/a.d.ts.map')),
10+
'Missing a.d.ts.map');
11+
assert.ok(
12+
code_files.some(f => f.endsWith('declarationdir_with_value/out/code/a.js')), 'Missing a.js');
13+
assert.ok(
14+
code_files.some(f => f.endsWith('declarationdir_with_value/out/code/a.js.map')),
15+
'Missing a.js.map');

packages/typescript/test/ts_project/json/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SRCS = [
1010
ts_project(
1111
name = "tsconfig",
1212
srcs = SRCS,
13-
outdir = "foobar",
13+
out_dir = "foobar",
1414
)
1515

1616
ts_project(

0 commit comments

Comments
 (0)