Skip to content

Commit

Permalink
feat(typescript): support for declarationdir on ts_project (#2048)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mistic authored Jul 17, 2020
1 parent 8a8e512 commit 981e7c1
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 24 deletions.
58 changes: 37 additions & 21 deletions packages/typescript/internal/ts_project.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ _DEFAULT_TSC = (

_ATTRS = {
"args": attr.string_list(),
"declaration_dir": attr.string(),
"deps": attr.label_list(providers = [DeclarationInfo]),
"extends": attr.label_list(allow_files = [".json"]),
"outdir": attr.string(),
"rootdir": attr.string(),
"out_dir": attr.string(),
"root_dir": attr.string(),
# NB: no restriction on extensions here, because tsc sometimes adds type-check support
# for more file kinds (like require('some.json')) and also
# if you swap out the `compiler` attribute (like with ngtsc)
Expand Down Expand Up @@ -56,14 +57,15 @@ def _ts_project_impl(ctx):
"--project",
ctx.file.tsconfig.path,
"--outDir",
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.outdir),
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.out_dir),
"--rootDir",
_join(ctx.label.package, ctx.attr.rootdir) if ctx.label.package else ".",
_join(ctx.label.package, ctx.attr.root_dir) if ctx.label.package else ".",
])
if len(ctx.outputs.typings_outs) > 0:
declaration_dir = ctx.attr.declaration_dir if ctx.attr.declaration_dir else ctx.attr.out_dir
arguments.add_all([
"--declarationDir",
_join(ctx.bin_dir.path, ctx.label.package, ctx.attr.outdir),
_join(ctx.bin_dir.path, ctx.label.package, declaration_dir),
])

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

# 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 outdir is used, then the .json output is a different path than the input.)
# (The exception is when out_dir is used, then the .json output is a different path than the input.)
# However tsc will copy .json srcs to the output tree so we want to declare these outputs to include along with .js Default outs
# NB: We don't have emit_declaration_only setting here, so use presence of any JS outputs as an equivalent.
# tsc will only produce .json if it also produces .js
if len(ctx.outputs.js_outs):
json_outs = [
ctx.actions.declare_file(_join(ctx.attr.outdir, src.short_path[len(ctx.label.package) + 1:]))
ctx.actions.declare_file(_join(ctx.attr.out_dir, src.short_path[len(ctx.label.package) + 1:]))
for src in ctx.files.srcs
if src.basename.endswith(".json")
]
Expand All @@ -115,7 +117,7 @@ def _ts_project_impl(ctx):
if ctx.outputs.buildinfo_out:
outputs.append(ctx.outputs.buildinfo_out)
runtime_outputs = depset(json_outs + ctx.outputs.js_outs + ctx.outputs.map_outs)
typings_outputs = ctx.outputs.typings_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")]
typings_outputs = ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")]

if len(outputs) > 0:
run_node(
Expand Down Expand Up @@ -230,8 +232,9 @@ def ts_project_macro(
emit_declaration_only = False,
tsc = None,
validate = True,
outdir = None,
rootdir = None,
declaration_dir = None,
out_dir = None,
root_dir = None,
**kwargs):
"""Compiles one TypeScript project using `tsc --project`
Expand Down Expand Up @@ -357,13 +360,21 @@ def ts_project_macro(
validate: boolean; whether to check that the tsconfig settings match the attributes.
outdir: a string specifying a subdirectory under the bazel-out folder where outputs are written.
root_dir: a string specifying a subdirectory under the input package which should be consider the
root directory of all the input files.
Equivalent to the TypeScript --rootDir option.
By default it is '.', meaning the source directory where the BUILD file lives.
out_dir: a string specifying a subdirectory under the bazel-out folder where outputs are written.
Equivalent to the TypeScript --outDir option.
Note that Bazel always requires outputs be written under a subdirectory matching the input package,
so if your rule appears in path/to/my/package/BUILD.bazel and outdir = "foo" then the .js files
will appear in bazel-out/[arch]/bin/path/to/my/package/foo/*.js
so if your rule appears in path/to/my/package/BUILD.bazel and out_dir = "foo" then the .js files
will appear in bazel-out/[arch]/bin/path/to/my/package/foo/*.js.
By default the out_dir is '.', meaning the packages folder in bazel-out.
rootdir: a string specifying a subdirectory under the input package which should be consider the
root directory of all the input files.
declaration_dir: a string specifying a subdirectory under the bazel-out folder where generated declaration
outputs are written. Equivalent to the TypeScript --declarationDir option.
By default declarations are written to the out_dir.
declaration: if the `declaration` bit is set in the tsconfig.
Instructs Bazel to expect a `.d.ts` output for each `.ts` source.
Expand All @@ -377,6 +388,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.
**kwargs: passed through to underlying rule, allows eg. visibility, tags
"""

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

typings_out_dir = declaration_dir if declaration_dir else out_dir

ts_project(
name = name,
srcs = srcs,
args = args,
deps = deps + extra_deps,
tsconfig = tsconfig,
extends = extends,
outdir = outdir,
rootdir = rootdir,
js_outs = _out_paths(srcs, outdir, rootdir, ".js") if not emit_declaration_only else [],
map_outs = _out_paths(srcs, outdir, rootdir, ".js.map") if source_map and not emit_declaration_only else [],
typings_outs = _out_paths(srcs, outdir, rootdir, ".d.ts") if declaration or composite else [],
typing_maps_outs = _out_paths(srcs, outdir, rootdir, ".d.ts.map") if declaration_map else [],
declaration_dir = declaration_dir,
out_dir = out_dir,
root_dir = root_dir,
js_outs = _out_paths(srcs, out_dir, root_dir, ".js") if not emit_declaration_only else [],
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,
tsc = tsc,
**kwargs
Expand Down
36 changes: 36 additions & 0 deletions packages/typescript/test/ts_project/declarationdir/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
load("//packages/typescript:index.bzl", "ts_project")

# Ensure that subdir/a.ts produces outDir/a.js and outDir/a.d.ts
SRCS = [
"subdir/a.ts",
]

ts_project(
name = "tsconfig",
srcs = SRCS,
declaration = True,
declaration_map = True,
out_dir = "out",
root_dir = "subdir",
source_map = True,
)

filegroup(
name = "types",
srcs = [":tsconfig"],
output_group = "types",
)

nodejs_test(
name = "test",
data = [
":tsconfig",
":types",
],
entry_point = "verify.js",
templated_args = [
"$(locations :types)",
"$(locations :tsconfig)",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const a: string = 'hello';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"types": []
}
}
8 changes: 8 additions & 0 deletions packages/typescript/test/ts_project/declarationdir/verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const assert = require('assert');

const types_files = process.argv.slice(2, 4);
const code_files = process.argv.slice(4, 6);
assert.ok(types_files.some(f => f.endsWith('declarationdir/out/a.d.ts')), 'Missing a.d.ts');
assert.ok(types_files.some(f => f.endsWith('declarationdir/out/a.d.ts.map')), 'Missing a.d.ts.map');
assert.ok(code_files.some(f => f.endsWith('declarationdir/out/a.js')), 'Missing a.js');
assert.ok(code_files.some(f => f.endsWith('declarationdir/out/a.js.map')), 'Missing a.js.map');
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
load("//packages/typescript:index.bzl", "ts_project")

# Ensure that subdir/a.ts produces outDir/a.js and declarationDir/a.d.ts
SRCS = [
"subdir/a.ts",
]

ts_project(
name = "tsconfig",
srcs = SRCS,
declaration = True,
declaration_dir = "out/types",
declaration_map = True,
out_dir = "out/code",
root_dir = "subdir",
source_map = True,
)

filegroup(
name = "types",
srcs = [":tsconfig"],
output_group = "types",
)

nodejs_test(
name = "test",
data = [
":tsconfig",
":types",
],
entry_point = "verify.js",
templated_args = [
"$(locations :types)",
"$(locations :tsconfig)",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const a: string = 'hello';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"types": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const assert = require('assert');

const types_files = process.argv.slice(2, 4);
const code_files = process.argv.slice(4, 6);
assert.ok(
types_files.some(f => f.endsWith('declarationdir_with_value/out/types/a.d.ts')),
'Missing a.d.ts');
assert.ok(
types_files.some(f => f.endsWith('declarationdir_with_value/out/types/a.d.ts.map')),
'Missing a.d.ts.map');
assert.ok(
code_files.some(f => f.endsWith('declarationdir_with_value/out/code/a.js')), 'Missing a.js');
assert.ok(
code_files.some(f => f.endsWith('declarationdir_with_value/out/code/a.js.map')),
'Missing a.js.map');
2 changes: 1 addition & 1 deletion packages/typescript/test/ts_project/json/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SRCS = [
ts_project(
name = "tsconfig",
srcs = SRCS,
outdir = "foobar",
out_dir = "foobar",
)

ts_project(
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/test/ts_project/outdir/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ load("//packages/typescript:index.bzl", "ts_project")
format,
],
# Write the output files to an extra nested directory
outdir = format,
out_dir = format,
tsconfig = "tsconfig.json",
)
for format in [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ SRCS = [
ts_project(
name = "tsconfig",
srcs = SRCS,
rootdir = "subdir",
root_dir = "subdir",
)

nodejs_test(
Expand Down

0 comments on commit 981e7c1

Please sign in to comment.