Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(typescript): support for declarationdir on ts_project #2048

Merged
merged 5 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why make this change? I don't think .map files belong in DeclarationInfo, they are meant to be consumed by editors not by other tsc actions that need to type-check

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checked with @gregmagolan - you are correct we transport .map files along with the thing they map (it's like that for .js.map files for example)


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