diff --git a/WORKSPACE b/WORKSPACE
index 01388e13..60d09397 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -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 = [
diff --git a/defs.bzl b/defs.bzl
index e7caea17..c3aeb83f 100644
--- a/defs.bzl
+++ b/defs.bzl
@@ -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",
@@ -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
diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel
index 3d1bcbca..e44a3278 100644
--- a/examples/BUILD.bazel
+++ b/examples/BUILD.bazel
@@ -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",
diff --git a/examples/some_library/BUILD.bazel b/examples/some_library/BUILD.bazel
index 43dbc2c6..a34e8608 100644
--- a/examples/some_library/BUILD.bazel
+++ b/examples/some_library/BUILD.bazel
@@ -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,
)
diff --git a/examples/some_soy/BUILD.bazel b/examples/some_soy/BUILD.bazel
new file mode 100644
index 00000000..0d2a8a78
--- /dev/null
+++ b/examples/some_soy/BUILD.bazel
@@ -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,
+)
diff --git a/examples/some_soy/closure.d.ts b/examples/some_soy/closure.d.ts
new file mode 100644
index 00000000..cde28f1d
--- /dev/null
+++ b/examples/some_soy/closure.d.ts
@@ -0,0 +1,3 @@
+declare namespace goog {
+ function isString(x:any): x is string;
+}
\ No newline at end of file
diff --git a/examples/some_soy/main.ts b/examples/some_soy/main.ts
new file mode 100644
index 00000000..c03c3d3a
--- /dev/null
+++ b/examples/some_soy/main.ts
@@ -0,0 +1,6 @@
+import {Template} from 'goog:some.templates';
+
+const msg = Template({name:"World"}).getContent();
+if (goog.isString(msg)){
+ console.log(msg);
+}
diff --git a/examples/some_soy/some.soy b/examples/some_soy/some.soy
new file mode 100644
index 00000000..fdd911bb
--- /dev/null
+++ b/examples/some_soy/some.soy
@@ -0,0 +1,5 @@
+{namespace some.templates}
+{template .Template}
+{@param name: string}
+
Hello, {$name}
+{/template}
\ No newline at end of file
diff --git a/examples/some_soy/soy_render_test.sh b/examples/some_soy/soy_render_test.sh
new file mode 100755
index 00000000..9b60bc96
--- /dev/null
+++ b/examples/some_soy/soy_render_test.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+readonly OUT=$($TEST_SRCDIR/build_bazel_rules_typescript/examples/some_soy/some_soy)
+if [ "$OUT" != "Hello, World
" ]; then
+ echo "Expected output 'Hello, World
' but was $OUT"
+ exit 1
+fi
diff --git a/internal/build_defs.bzl b/internal/build_defs.bzl
index b41d367f..9b3b0956 100644
--- a/internal/build_defs.bzl
+++ b/internal/build_defs.bzl
@@ -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:
@@ -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",
+ },
+)
diff --git a/internal/common/compilation.bzl b/internal/common/compilation.bzl
index 68624272..7278dc9b 100644
--- a/internal/common/compilation.bzl
+++ b/internal/common/compilation.bzl
@@ -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,
@@ -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
@@ -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": {
@@ -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,
diff --git a/internal/common/tsconfig.bzl b/internal/common/tsconfig.bzl
index 525b6647..ac779ff9 100644
--- a/internal/common/tsconfig.bzl
+++ b/internal/common/tsconfig.bzl
@@ -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),
@@ -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,
diff --git a/internal/protobufjs/ts_proto_library.bzl b/internal/protobufjs/ts_proto_library.bzl
index 19957f79..f65dd75d 100644
--- a/internal/protobufjs/ts_proto_library.bzl
+++ b/internal/protobufjs/ts_proto_library.bzl
@@ -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(),
),
)
diff --git a/internal/tsc_wrapped/compiler_host.ts b/internal/tsc_wrapped/compiler_host.ts
index 2649be4a..1fc2cc01 100644
--- a/internal/tsc_wrapped/compiler_host.ts
+++ b/internal/tsc_wrapped/compiler_host.ts
@@ -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)));
}
diff --git a/internal/tsc_wrapped/tsc_wrapped.ts b/internal/tsc_wrapped/tsc_wrapped.ts
index 286e6f8b..ac5e20da 100644
--- a/internal/tsc_wrapped/tsc_wrapped.ts
+++ b/internal/tsc_wrapped/tsc_wrapped.ts
@@ -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';
@@ -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;
diff --git a/package.json b/package.json
index ffe5684e..ee31006d 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"homepage": "https://github.com/bazelbuild/rules_typescript",
"license": "Apache-2.0",
"peerDependencies": {
- "typescript": ">=2.4.2"
+ "typescript": "2.6.2"
},
"devDependencies": {
"@bazel/ibazel": "^0.2.0",
@@ -23,7 +23,7 @@
"http-server": "^0.11.1",
"protobufjs": "5.0.0",
"protractor": "^5.2.0",
- "tsickle": "0.25.x",
+ "tsickle": "0.27.2",
"tsutils": "2.20.0",
"typescript": "2.7.x"
},
@@ -38,4 +38,4 @@
"skylint": "find . -type f -name \"*.bzl\" ! -path \"*/node_modules/*\" | xargs $(bazel info bazel-bin)/external/io_bazel/src/tools/skylark/java/com/google/devtools/skylark/skylint/Skylint",
"skydoc": "bazel build //:docs && unzip -o -d docs/api bazel-bin/docs-skydoc.zip"
}
-}
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 9c52425b..3a1f1d97 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -912,7 +912,13 @@ sntp@2.x.x:
dependencies:
hoek "4.x.x"
-source-map-support@^0.4.2, source-map-support@~0.4.0:
+source-map-support@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.3.tgz#2b3d5fff298cfa4d1afd7d4352d569e9a0158e76"
+ dependencies:
+ source-map "^0.6.0"
+
+source-map-support@~0.4.0:
version "0.4.18"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
dependencies:
@@ -922,6 +928,10 @@ source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+source-map@^0.6.0:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+
spawn-command@^0.0.2-1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
@@ -1002,14 +1012,14 @@ tree-kill@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
-tsickle@0.25.x:
- version "0.25.0"
- resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.25.0.tgz#4ba51e79e9333ab7baec6f374c789b0bc1dba36c"
+tsickle@0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.27.2.tgz#f33d46d046f73dd5c155a37922e422816e878736"
dependencies:
minimist "^1.2.0"
mkdirp "^0.5.1"
- source-map "^0.5.6"
- source-map-support "^0.4.2"
+ source-map "^0.6.0"
+ source-map-support "^0.5.0"
tslib@^1.8.1:
version "1.9.0"