Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.
Closed
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
14 changes: 14 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ node_repositories(
package_json = ["//:package.json"],
preserve_symlinks = True)

# Closure compiler.
# This is is needed for the closure templates example, users should not need to add it unless they want to use it.
# Using a fork to get support for typescript and clutz.
http_archive(
name = "io_bazel_rules_closure",
sha256 = "cbdeac3e610982e60c1af5695191d46e4f432cdbb30ac8535820aaf1e285abcc",
strip_prefix = "rules_closure-2a78960a3c64df0bf1311e07269ea28be476e848",
url = "http://github.com/ribrdb/rules_closure/archive/2a78960a3c64df0bf1311e07269ea28be476e848.tar.gz",
)

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")

closure_repositories()

http_archive(
name = "io_bazel_rules_go",
urls = [
Expand Down
3 changes: 2 additions & 1 deletion defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Users should not load files under "/internal"
"""
load("//internal:ts_repositories.bzl", _ts_setup_workspace = "ts_setup_workspace")
load("//internal:build_defs.bzl", _ts_library = "ts_library")
load("//internal:build_defs.bzl", _ts_library = "ts_library", _ts_declaration="ts_declaration")
load("//internal:ts_config.bzl", _ts_config = "ts_config")
load("//internal/devserver:ts_devserver.bzl", _ts_devserver = "ts_devserver_macro")
load("//internal/karma:ts_web_test.bzl",
Expand All @@ -27,6 +27,7 @@ load("//internal/protobufjs:ts_proto_library.bzl", _ts_proto_library = "ts_proto

ts_setup_workspace = _ts_setup_workspace
ts_library = _ts_library
ts_declaration = _ts_declaration
ts_config = _ts_config
ts_devserver = _ts_devserver
# TODO(alexeagle): make ts_web_test && ts_web_test_suite work in google3
Expand Down
1 change: 1 addition & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ts_library(
name = "bar_ts_library",
srcs = ["bar.ts"],
tsconfig = ":tsconfig.json",
tsickle_typed = False,
deps = [
":foo_ts_library",
"//examples/some_library:lib",
Expand Down
1 change: 1 addition & 0 deletions examples/some_library/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ ts_library(
module_name = "some-lib",
# The imported path should be the library.d.ts file
module_root = "library",
tsickle_typed = False,
)
95 changes: 95 additions & 0 deletions examples/some_soy/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

package(default_visibility = ["//visibility:public"])

load(
"@io_bazel_rules_closure//closure:defs.bzl",
"closure_js_template_library",
"closure_js_binary",
"closure_js_library",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("//:defs.bzl", "ts_library", "ts_declaration")

closure_js_template_library(
name = "template",
srcs = ["some.soy"],
)

genrule(
name="template_clutz",
outs=["template.d.ts"],
srcs=["some.soy.js",
"@io_angular_clutz//:src/resources/partial_goog_base.js",
"@io_bazel_rules_closure//third_party/clutz:externs.js"
],
tools=["@io_angular_clutz//:clutz"],
cmd="""
BASE=$(location @io_angular_clutz//:src/resources/partial_goog_base.js);
CLUTZ=$(location @io_angular_clutz//:clutz);
$$CLUTZ --partialInput -o $@ --skipEmitRegExp $$BASE $(SRCS)
"""
)

ts_declaration(
name="template_ts",
srcs=["template.d.ts"],
generate_externs=False,
runtime_deps=[":template"],
)

ts_library(
name = "main",
srcs = ["main.ts"],
deps = [
":mini_closure",
":template_ts",
],
)

closure_js_library(
name = "main_js",
ts_lib = ":main",
suppress=["unusedLocalVariables"],
)

closure_js_binary(
name = "render_soy_bin",
entry_points = ["goog:build_bazel_rules_typescript.examples.some_soy.main"],
deps = [":main_js"],
)

nodejs_binary(
name = "some_soy",
data = [
":render_soy_bin",
],
entry_point = "build_bazel_rules_typescript/examples/some_soy/render_soy_bin.js",
)

sh_test(
name = "soy_render_test",
srcs = ["soy_render_test.sh"],
data = [":some_soy"],
)

ts_library(
name="mini_closure",
srcs=[":closure.d.ts"],
runtime_deps = [
"@io_bazel_rules_closure//closure/library",
],
generate_externs = False,
)
3 changes: 3 additions & 0 deletions examples/some_soy/closure.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare namespace goog {
function isString(x:any): x is string;
}
6 changes: 6 additions & 0 deletions examples/some_soy/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {Template} from 'goog:some.templates';

const msg = Template({name:"World"}).getContent();
if (goog.isString(msg)){
console.log(msg);
}
5 changes: 5 additions & 0 deletions examples/some_soy/some.soy
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{namespace some.templates}
{template .Template}
{@param name: string}
<h1>Hello, {$name}</h1>
{/template}
8 changes: 8 additions & 0 deletions examples/some_soy/soy_render_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
set -e

readonly OUT=$($TEST_SRCDIR/build_bazel_rules_typescript/examples/some_soy/some_soy)
if [ "$OUT" != "<h1>Hello, World</h1>" ]; then
echo "Expected output '<h1>Hello, World</h1>' but was $OUT"
exit 1
fi
74 changes: 67 additions & 7 deletions internal/build_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,11 @@ def _compile_action(ctx, inputs, outputs, tsconfig_file, node_opts, description
externs_files = []
action_outputs = []
for output in outputs:
if output.basename.endswith(".externs.js"):
externs_files.append(output)
elif output.basename.endswith(".es5.MF"):
if output.basename.endswith(".es5.MF"):
ctx.file_action(output, content="")
else:
action_outputs.append(output)

# TODO(plf): For now we mock creation of files other than {name}.js.
for externs_file in externs_files:
ctx.file_action(output=externs_file, content="")

# A ts_library that has only .d.ts inputs will have no outputs,
# therefore there are no actions to execute
if not action_outputs:
Expand Down Expand Up @@ -196,3 +190,69 @@ ts_library = rule(
It produces declarations files (`.d.ts`) which are used for compiling downstream
TypeScript targets and JavaScript for the browser and Closure compiler.
"""

def _ts_declaration_impl(ctx):
"""Implementation of ts_declaration.

Args:
ctx: the context.

Returns:
the struct returned by the call to compile_ts.
"""
ts_providers = compile_ts(ctx, is_library=False,
compile_action=_compile_action,
devmode_compile_action=_devmode_compile_action,
tsc_wrapped_tsconfig=tsc_wrapped_tsconfig)
return ts_providers_dict_to_struct(ts_providers)

ts_declaration = rule(
_ts_declaration_impl,
attrs = dict(COMMON_ATTRIBUTES, **{
"srcs": attr.label_list(
allow_files = FileType([
".ts",
".tsx",
]),
mandatory = True,
),

# TODO(alexeagle): reconcile with google3: ts_library rules should
# be portable across internal/external, so we need this attribute
# internally as well.
"tsconfig": attr.label(
doc = """A tsconfig.json file containing settings for TypeScript compilation.
Note that some properties in the tsconfig are governed by Bazel and will be
overridden, such as `target` and `module`.""",
allow_files = True,
single_file = True,
),
"compiler": attr.label(
doc = """Intended for internal use only.
Sets a different TypeScript compiler binary to use for this library.
For example, we use the vanilla TypeScript tsc.js for bootstrapping,
and Angular compilations can replace this with `ngc`.""",
default = Label("//internal:tsc_wrapped_bin"),
single_file = False,
allow_files = True,
executable = True,
cfg = "host",
),
"supports_workers": attr.bool(
doc = """Intended for internal use only.
Allows you to disable the Bazel Worker strategy for this library.
Typically used together with the "compiler" setting when using a
non-worker aware compiler binary.""",
default = True,
),
"tsickle_typed": attr.bool(default = True),
"_tsc_wrapped_deps": attr.label(default = Label("@build_bazel_rules_typescript_tsc_wrapped_deps//:node_modules")),
# @// is special syntax for the "main" repository
# The default assumes the user specified a target "node_modules" in their
# root BUILD file.
"node_modules": attr.label(default = Label("@//:node_modules")),
}),
outputs = {
"tsconfig": "%{name}_tsconfig.json",
},
)
15 changes: 11 additions & 4 deletions internal/common/compilation.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ COMMON_ATTRIBUTES = dict(BASE_ATTRIBUTES, **{
# any closure JS code.
"runtime_deps": attr.label_list(
default = [],
providers = ["js"],
providers = [["js"], ["closure_js_library"]],
),
"_additional_d_ts": attr.label_list(
allow_files = True,
Expand Down Expand Up @@ -188,9 +188,11 @@ def compile_ts(ctx,
transpiled_devmode_js = outs.devmode_js
gen_declarations = outs.declarations

if has_sources and ctx.attr.runtime != "nodejs":
# Note: setting this variable controls whether tsickle is run at all.
tsickle_externs = [ctx.new_file(ctx.label.name + ".externs.js")]
if hasattr(ctx.attr,'tsickle_typed') and ctx.attr.tsickle_typed:
if has_sources and ctx.attr.runtime != "nodejs":
if is_library or ctx.attr.generate_externs:
# Note: setting this variable controls whether tsickle is run at all.
tsickle_externs = [ctx.new_file(ctx.label.name + ".externs.js")]

dep_declarations = _collect_dep_declarations(ctx)
input_declarations = dep_declarations.transitive + src_declarations
Expand Down Expand Up @@ -344,6 +346,10 @@ def compile_ts(ctx,
transitive_es5_sources = depset(transitive = [transitive_es5_sources, es5_sources])
transitive_es6_sources = depset(transitive = [transitive_es6_sources, es6_sources])

transitive_runtime_deps = depset(
ctx.attr.runtime_deps,
transitive=[dep.typescript.runtime_deps for dep in ctx.attr.deps] )

return {
"files": files,
"output_groups": {
Expand All @@ -369,6 +375,7 @@ def compile_ts(ctx,
"type_blacklisted_declarations": type_blacklisted_declarations,
"tsickle_externs": tsickle_externs,
"replay_params": replay_params,
"runtime_deps": transitive_runtime_deps,
},
# Expose the tags so that a Skylark aspect can access them.
"tags": ctx.attr.tags,
Expand Down
4 changes: 4 additions & 0 deletions internal/common/tsconfig.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def create_tsconfig(ctx, files, srcs,
"target": str(ctx.label),
"package": ctx.label.package,
"tsickle": tsickle_externs != None,
"googmodule": tsickle_externs != None,
"tsickleGenerateExterns": getattr(ctx.attr, "generate_externs", True),
"tsickleExternsPath": tsickle_externs.path if tsickle_externs else "",
"untyped": not getattr(ctx.attr, "tsickle_typed", False),
Expand Down Expand Up @@ -244,6 +245,9 @@ def create_tsconfig(ctx, files, srcs,
"sourceMap": False,
}

if tsickle_externs != None:
compiler_options["module"] = "commonjs"

if hasattr(ctx.attr, "node_modules"):
compiler_options["typeRoots"] = ["/".join([p for p in [
workspace_path,
Expand Down
1 change: 1 addition & 0 deletions internal/protobufjs/ts_proto_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def _ts_proto_library(ctx):
es6_sources = depset([js_es6]),
transitive_es5_sources = depset(),
transitive_es6_sources = depset([js_es6]),
runtime_deps = depset(),
),
)

Expand Down
2 changes: 1 addition & 1 deletion internal/tsc_wrapped/compiler_host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export class CompilerHost implements ts.CompilerHost, tsickle.TsickleHost {

/** Allows suppressing warnings for specific known libraries */
shouldIgnoreWarningsForPath(filePath: string): boolean {
return this.bazelOpts.ignoreWarningPaths.some(
return this.bazelOpts.ignoreWarningPaths && this.bazelOpts.ignoreWarningPaths.some(
p => !!filePath.match(new RegExp(p)));
}

Expand Down
40 changes: 32 additions & 8 deletions internal/tsc_wrapped/tsc_wrapped.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';

import {PLUGIN as tsetsePlugin} from '../tsetse/runner';
Expand Down Expand Up @@ -141,15 +142,38 @@ function runOneBuild(
return false;
}

for (const sf of program.getSourceFiles().filter(isCompilationTarget)) {
const emitResult = program.emit(
sf, /*writeFile*/ undefined,
/*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, {
after: [fixUmdModuleDeclarations(
(sf: ts.SourceFile) => compilerHost.amdModuleName(sf))]
});
diags.push(...emitResult.diagnostics);
const emitResults = [];

if (bazelOpts.tsickle) {
const emitResults: tsickle.EmitResult[] =
program.getSourceFiles()
.filter(isCompilationTarget)
.map(
file => tsickle.emitWithTsickle(
program, compilerHost, (compilerHost as ts.CompilerHost),
options, file));

const emitResult = tsickle.mergeEmitResults(emitResults);

if (bazelOpts.tsickleExternsPath) {
const externs = bazelOpts.tsickleGenerateExterns ? tsickle.getGeneratedExterns(emitResult.externs) : '';
fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
}
} else {
for (const sf of program.getSourceFiles().filter(isCompilationTarget)) {
const emitResult = program.emit(
sf, /*writeFile*/ undefined,
/*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, {
after: [fixUmdModuleDeclarations(
(sf: ts.SourceFile) => compilerHost.amdModuleName(sf))]
});
diags.push(...emitResult.diagnostics);
}
if (bazelOpts.tsickleExternsPath) {
fs.writeFileSync(bazelOpts.tsickleExternsPath, '');
}
}

if (diags.length > 0) {
console.error(diagnostics.format(bazelOpts.target, diags));
return false;
Expand Down
Loading