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: support ts_project with transpiler and no declarations for type-checking #698

Merged
merged 1 commit into from
Sep 21, 2024
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
44 changes: 38 additions & 6 deletions examples/no_emit/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@bazel_skylib//rules:write_file.bzl", "write_file")

write_file(
Expand All @@ -9,12 +10,43 @@ write_file(
],
)

# Shows how to run `tsc` producing no outputs at all.
# It will use a validation action to type-check the file:
# https://bazel.build/extending/rules#validation_actions
# Run bazel with --norun_validations to skip type-checking.
write_file(
name = "gen_js",
out = "b.js",
content = [
"export const b = 43",
],
)

# Shows how to run `tsc` producing no outputs at all via noEmit.
ts_project(
name = "typecheck_only",
name = "typecheck_only_noemit",
srcs = ["a.ts"],
no_emit = True,
tsconfig = {
"compilerOptions": {
"noEmit": True,
},
},
)

# Shows how to run `tsc` with .js producing no outputs at all via noEmit
ts_project(
name = "typecheck_nodeclarations_js",
srcs = ["b.js"],
out_dir = "typecheck_nodeclarations_js",
tsconfig = {
"compilerOptions": {
"allowJs": True,
"noEmit": True,
},
},
)

build_test(
name = "targets_test",
targets = [
# Ensure the _typecheck targets are declared despite no outputs.
":typecheck_only_noemit_typecheck",
":typecheck_nodeclarations_js_typecheck",
],
)
51 changes: 48 additions & 3 deletions examples/transpiler/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@bazel_skylib//rules:build_test.bzl", "build_test")

# Note, Bazel 6 starlark has lambda so maybe we can stop using partial
load("@bazel_skylib//rules:write_file.bzl", "write_file")
Expand All @@ -19,6 +20,14 @@ write_file(
],
)

write_file(
name = "gen_a",
out = "a.ts",
content = [
"export const b: number = 43",
],
)

# Runs babel to transpile ts -> js
# and tsc to type-check
ts_project(
Expand All @@ -31,9 +40,8 @@ ts_project(
)

# Runs babel to transpile ts -> js
# and does not produce any declaration outputs.
# `tsc` is used for type-check only, as a validation action
# (run bazel with --norun_validations to skip typechecking)
# and does not produce any declaration outputs due to noEmit=True.
# Type-checking will be a separate action and target.
ts_project(
name = "no-emit",
srcs = ["big.ts"],
Expand All @@ -45,3 +53,40 @@ ts_project(
},
},
)

# Runs babel to transpile ts -> js
# and does not produce any declaration outputs due to declaration=False.
# Type-checking will be a separate action and target.
ts_project(
name = "no-declarations",
srcs = ["a.ts"],
out_dir = "build-nodecls",
transpiler = babel,
tsconfig = {
"compilerOptions": {
"declaration": False,
},
},
)

build_test(
name = "targets_test",
targets = [
# babel ts_project
":babel",
":babel_typecheck",
# babel outputted js
"big.js", # NOTE: does not implement out_dir in this test
# tsc outputted dts
"build-babel/big.d.ts",

# no-emit for type-checking
":no-emit",
":no-emit_typecheck",

# babel outputted .js with no declarations
":no-declarations",
":no-declarations_typecheck",
"a.js", # NOTE: does not implement out_dir in this test
],
)
37 changes: 3 additions & 34 deletions ts/private/ts_project.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -177,43 +177,12 @@ See https://github.com/aspect-build/rules_ts/issues/361 for more details.

typings_srcs = [s for s in srcs_inputs if _lib.is_typings_src(s.path)]

if len(js_outs) + len(typings_outs) < 1 and not ctx.attr.no_emit:
label = "//{}:{}".format(ctx.label.package, ctx.label.name)
if len(typings_srcs) > 0:
no_outs_msg = """ts_project target {target} only has typings in srcs.
Since there is no `tsc` action to perform, there are no generated outputs.
For "typecheck-only" the TypeScript 'noEmit' feature can be used.
For grouping typings this should be changed to js_library, which can be done by running:
buildozer 'new_load @aspect_rules_js//js:defs.bzl js_library' //{pkg}:__pkg__
buildozer 'set kind js_library' {target}
buildozer 'remove declaration' {target}
""".format(
target = label,
pkg = ctx.label.package,
)
elif ctx.attr.transpile != 0:
no_outs_msg = """ts_project target %s is configured to produce no outputs.
This might be because
- you configured it with `noEmit`
- the `srcs` are empty
- `srcs` has elements producing non-ts outputs
""" % label
else:
no_outs_msg = "ts_project target %s with custom transpiler needs 'declaration = True'." % label
fail(no_outs_msg + """
This is an error because Bazel does not run actions unless their outputs are needed for the requested targets to build.
""")

# Make sure the user has acknowledged that transpiling is slow
if len(outputs) > 0 and ctx.attr.transpile == -1 and not ctx.attr.emit_declaration_only and not options.default_to_tsc_transpiler:
fail(transpiler_selection_required)

output_types = typings_outs + typing_maps_outs + typings_srcs
use_tsc_noemit = ctx.attr.no_emit or (ctx.attr.transpile == 0 and not ctx.attr.declaration)

# Default outputs (DefaultInfo files) is what you see on the command-line for a built
# library, and determines what files are used by a simple non-provider-aware downstream
Expand All @@ -225,7 +194,7 @@ This is an error because Bazel does not run actions unless their outputs are nee
else:
# We must avoid tsc writing any JS files in this case, as tsc was only run for typings, and some other
# action will try to write the JS files. We must avoid collisions where two actions write the same file.
if not ctx.attr.no_emit:
if not use_tsc_noemit:
arguments.add("--emitDeclarationOnly")

# We don't produce any DefaultInfo outputs in this case, because we avoid running the tsc action
Expand All @@ -236,7 +205,7 @@ This is an error because Bazel does not run actions unless their outputs are nee

stdout_file = ""

if ctx.attr.no_emit:
if use_tsc_noemit:
# The type-checking action still need to produce some output, so we output the stdout
# to a .typecheck file that ends up in the typecheck output group.
typecheck_output = ctx.actions.declare_file(ctx.attr.name + ".typecheck")
Expand Down
Loading