From b53241a169ea7be18abc195ef7fe406919c9768b Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 16 Mar 2018 09:44:13 -0600 Subject: [PATCH 1/8] Interoperate with rules_closure. --- WORKSPACE | 14 ++++++++ examples/some_library/BUILD.bazel | 1 + examples/some_soy/BUILD.bazel | 54 ++++++++++++++++++++++++++++ examples/some_soy/main.ts | 4 +++ examples/some_soy/some.soy | 5 +++ examples/some_soy/soy_render_test.sh | 8 +++++ internal/build_defs.bzl | 17 +++++---- internal/common/closure.bzl | 40 +++++++++++++++++++++ internal/common/compilation.bzl | 11 +++--- internal/common/tsconfig.bzl | 4 +++ internal/tsc_wrapped/tsc_wrapped.ts | 41 ++++++++++++++++----- package.json | 6 ++-- yarn.lock | 22 ++++++++---- 13 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 examples/some_soy/BUILD.bazel create mode 100644 examples/some_soy/main.ts create mode 100644 examples/some_soy/some.soy create mode 100755 examples/some_soy/soy_render_test.sh create mode 100644 internal/common/closure.bzl diff --git a/WORKSPACE b/WORKSPACE index 01388e13..962abeef 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 interop example, users should not need to add it unless they want to use it. +# Using a fork to get support for clutz. +http_archive( + name = "io_bazel_rules_closure", + sha256 = "bf644d28e38678b32c3451b756dd10d573a92bbf389d8635d15f7a4f73c6732b", + strip_prefix = "rules_closure-ff38624368a4da08a23428659ae1a3232044a59e", + url = "http://github.com/ribrdb/rules_closure/archive/ff38624368a4da08a23428659ae1a3232044a59e.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/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..ec8af4b5 --- /dev/null +++ b/examples/some_soy/BUILD.bazel @@ -0,0 +1,54 @@ +# 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", +) +load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") +load("//:defs.bzl", "ts_library") + +closure_js_template_library( + name = "template", + srcs = ["some.soy"], +) + +ts_library( + name = "main", + srcs = ["main.ts"], + deps = [":template"], +) + +closure_js_binary( + name="bin", + deps=[":main"], + entry_points=["goog:build_bazel_rules_typescript.examples.some_soy.main"], +) + +nodejs_binary( + name = "some_soy", + data = [ + ":bin", + ], + entry_point = "build_bazel_rules_typescript/examples/some_soy/bin.js", +) + +sh_test( + name = "soy_render_test", + srcs = ["soy_render_test.sh"], + data = [":some_soy"], +) diff --git a/examples/some_soy/main.ts b/examples/some_soy/main.ts new file mode 100644 index 00000000..77b26f22 --- /dev/null +++ b/examples/some_soy/main.ts @@ -0,0 +1,4 @@ +import {Template} from 'goog:some.templates'; + +const msg = Template({name:"World"}).getContent(); +console.log(msg); \ No newline at end of file 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..2dafac52 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: @@ -112,6 +106,15 @@ def tsc_wrapped_tsconfig(ctx, "node_modules" ] if p]) + if config["compilerOptions"]["target"] == "es6": + if not(config["bazelOptions"]["tsickle"]): + config["compilerOptions"]["module"] = "es2015" + else: + # The "typescript.es5_sources" provider is expected to work + # in both nodejs and in browsers. + # NOTE: tsc-wrapped will always name the enclosed AMD modules + config["compilerOptions"]["module"] = "umd" + # If the user gives a tsconfig attribute, the generated file should extend # from the user's tsconfig. # See https://github.com/Microsoft/TypeScript/issues/9876 diff --git a/internal/common/closure.bzl b/internal/common/closure.bzl new file mode 100644 index 00000000..9882a77b --- /dev/null +++ b/internal/common/closure.bzl @@ -0,0 +1,40 @@ +def _closure_aspect_impl(target, ctx): + """Generate typescript providers for closure_js_libraries""" + if hasattr(target, 'typescript'): + return [] + if not(hasattr(target, 'closure_js_library')): + return [] + direct_typings = [target.clutz_dts] + srcs = ctx.rule.files.srcs + + deps = getattr(ctx.rule.attr, 'deps', []) + exports = getattr(ctx.rule.attr, 'exports', []) + decls = depset(direct_typings,transitive=[dep.typescript.declarations for dep in exports]) + transitive_deps = [dep.typescript.declarations for dep in deps] + transitive_decls = depset(direct_typings, transitive=transitive_deps) + # transitive_decls = depset(direct_typings+ctx.files._clutz_root_decls, transitive=transitive_deps) + transitive_es6_srcs = depset(srcs, transitive=[dep.typescript.transitive_es6_sources for dep in deps]) + transitive_es5_srcs = depset(srcs, transitive=[dep.typescript.transitive_es5_sources for dep in deps]) + return struct( + typescript=struct( + declarations=decls, + transitive_declarations=transitive_decls, + es6_srcs=depset(srcs), + transitive_es6_sources=transitive_es6_srcs, + es5_sources=depset(srcs), + transitive_es5_sources=transitive_es5_srcs, + type_blacklisted_declarations=depset(transitive=[dep.typescript.type_blacklisted_declarations for dep in deps]), + runtime_deps=depset(transitive=[d.typescript.runtime_deps for d in deps]), + tsickle_externs=[], + replay_params=None, + devmode_manifest=None, + ) + ) + +closure_aspect = aspect( + attr_aspects = [ + "deps", + "exports", + ], + implementation = _closure_aspect_impl, +) diff --git a/internal/common/compilation.bzl b/internal/common/compilation.bzl index 68624272..a4213b7c 100644 --- a/internal/common/compilation.bzl +++ b/internal/common/compilation.bzl @@ -15,6 +15,7 @@ """Used for compilation by the different implementations of build_defs.bzl. """ +load(":common/closure.bzl", "closure_aspect") load(":common/module_mappings.bzl", "module_mappings_aspect") load(":common/json_marshal.bzl", "json_marshal") @@ -22,6 +23,7 @@ BASE_ATTRIBUTES = dict() DEPS_ASPECTS = [ module_mappings_aspect, + closure_aspect, ] # Attributes shared by any typescript-compatible rule (ts_library, ng_module) @@ -41,7 +43,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 +190,10 @@ 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": + # 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 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/tsc_wrapped/tsc_wrapped.ts b/internal/tsc_wrapped/tsc_wrapped.ts index 286e6f8b..6bf8aa40 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,39 @@ 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.tsickleGenerateExterns && bazelOpts.tsickleExternsPath) { + fs.writeFileSync( + bazelOpts.tsickleExternsPath, + tsickle.getGeneratedExterns(emitResult.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.tsickleGenerateExterns && 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" From 34e03b7169296406f715a99274c03f833ffb2496 Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 16 Mar 2018 13:34:24 -0600 Subject: [PATCH 2/8] runtime_deps should require 'js' or 'closure_js_library', not both. --- internal/common/compilation.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/common/compilation.bzl b/internal/common/compilation.bzl index a4213b7c..2a545a6b 100644 --- a/internal/common/compilation.bzl +++ b/internal/common/compilation.bzl @@ -43,7 +43,7 @@ COMMON_ATTRIBUTES = dict(BASE_ATTRIBUTES, **{ # any closure JS code. "runtime_deps": attr.label_list( default = [], - providers = ["js", "closure_js_library"], + providers = [["js"], ["closure_js_library"]], ), "_additional_d_ts": attr.label_list( allow_files = True, From e2ea57b7150be94e3639722eb59fc5bbb81b3814 Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 16 Mar 2018 15:38:57 -0600 Subject: [PATCH 3/8] Bug fixes and more tests: - Fix calling functions from closure's goog/base.js. - Support generate_externs=False. --- WORKSPACE | 6 +-- examples/some_soy/BUILD.bazel | 53 +++++++++++++++++++++++--- examples/some_soy/closure.d.ts | 3 ++ examples/some_soy/main.ts | 4 +- examples/some_soy/runtime_deps_main.ts | 1 + examples/some_soy/runtime_deps_test.sh | 8 ++++ internal/common/closure.bzl | 2 +- internal/tsc_wrapped/tsc_wrapped.ts | 9 ++--- 8 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 examples/some_soy/closure.d.ts create mode 100644 examples/some_soy/runtime_deps_main.ts create mode 100755 examples/some_soy/runtime_deps_test.sh diff --git a/WORKSPACE b/WORKSPACE index 962abeef..1eb7e784 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -48,9 +48,9 @@ node_repositories( # Using a fork to get support for clutz. http_archive( name = "io_bazel_rules_closure", - sha256 = "bf644d28e38678b32c3451b756dd10d573a92bbf389d8635d15f7a4f73c6732b", - strip_prefix = "rules_closure-ff38624368a4da08a23428659ae1a3232044a59e", - url = "http://github.com/ribrdb/rules_closure/archive/ff38624368a4da08a23428659ae1a3232044a59e.tar.gz", + sha256 = "f8392913b8aa2ce1e477181fa6b5761ca5c1872775a4e6895ef874b0265d7912", + strip_prefix = "rules_closure-2447dc5fc4a94adbbe772c7e943fd31d91ffe21f", + url = "http://github.com/ribrdb/rules_closure/archive/2447dc5fc4a94adbbe772c7e943fd31d91ffe21f.tar.gz", ) load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories") diff --git a/examples/some_soy/BUILD.bazel b/examples/some_soy/BUILD.bazel index ec8af4b5..bc097291 100644 --- a/examples/some_soy/BUILD.bazel +++ b/examples/some_soy/BUILD.bazel @@ -18,6 +18,7 @@ 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") @@ -30,21 +31,24 @@ closure_js_template_library( ts_library( name = "main", srcs = ["main.ts"], - deps = [":template"], + deps = [ + "@io_bazel_rules_closure//closure/library", + ":template", + ], ) closure_js_binary( - name="bin", - deps=[":main"], - entry_points=["goog:build_bazel_rules_typescript.examples.some_soy.main"], + name = "render_soy_bin", + entry_points = ["goog:build_bazel_rules_typescript.examples.some_soy.main"], + deps = [":main"], ) nodejs_binary( name = "some_soy", data = [ - ":bin", + ":render_soy_bin", ], - entry_point = "build_bazel_rules_typescript/examples/some_soy/bin.js", + entry_point = "build_bazel_rules_typescript/examples/some_soy/render_soy_bin.js", ) sh_test( @@ -52,3 +56,40 @@ sh_test( srcs = ["soy_render_test.sh"], data = [":some_soy"], ) + +ts_library( + name="custom_closure", + srcs=[":closure.d.ts"], + runtime_deps = [ + "@io_bazel_rules_closure//closure/library", + ], + generate_externs = False, +) + +ts_library( + name = "runtime_deps_main", + srcs = ["runtime_deps_main.ts"], + deps = [ + ":custom_closure", + ], +) + +closure_js_binary( + name = "runtime_deps_jsbin", + entry_points = ["goog:build_bazel_rules_typescript.examples.some_soy.runtime_deps_main"], + deps = [":runtime_deps_main"], +) + +nodejs_binary( + name = "runtime_deps", + data = [ + ":runtime_deps_jsbin", + ], + entry_point = "build_bazel_rules_typescript/examples/some_soy/runtime_deps_jsbin.js", +) + +sh_test( + name = "runtime_deps_test", + srcs = ["runtime_deps_test.sh"], + data = [":runtime_deps"], +) \ No newline at end of file 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 index 77b26f22..c03c3d3a 100644 --- a/examples/some_soy/main.ts +++ b/examples/some_soy/main.ts @@ -1,4 +1,6 @@ import {Template} from 'goog:some.templates'; const msg = Template({name:"World"}).getContent(); -console.log(msg); \ No newline at end of file +if (goog.isString(msg)){ + console.log(msg); +} diff --git a/examples/some_soy/runtime_deps_main.ts b/examples/some_soy/runtime_deps_main.ts new file mode 100644 index 00000000..9dd1ff04 --- /dev/null +++ b/examples/some_soy/runtime_deps_main.ts @@ -0,0 +1 @@ +console.log(goog.isString("foobar")); \ No newline at end of file diff --git a/examples/some_soy/runtime_deps_test.sh b/examples/some_soy/runtime_deps_test.sh new file mode 100755 index 00000000..814227bb --- /dev/null +++ b/examples/some_soy/runtime_deps_test.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +readonly OUT=$($TEST_SRCDIR/build_bazel_rules_typescript/examples/some_soy/runtime_deps) +if [ "$OUT" != "true" ]; then + echo "Expected output 'true' but was $OUT" + exit 1 +fi diff --git a/internal/common/closure.bzl b/internal/common/closure.bzl index 9882a77b..0904254e 100644 --- a/internal/common/closure.bzl +++ b/internal/common/closure.bzl @@ -4,7 +4,7 @@ def _closure_aspect_impl(target, ctx): return [] if not(hasattr(target, 'closure_js_library')): return [] - direct_typings = [target.clutz_dts] + direct_typings = target.clutz_dts srcs = ctx.rule.files.srcs deps = getattr(ctx.rule.attr, 'deps', []) diff --git a/internal/tsc_wrapped/tsc_wrapped.ts b/internal/tsc_wrapped/tsc_wrapped.ts index 6bf8aa40..ac5e20da 100644 --- a/internal/tsc_wrapped/tsc_wrapped.ts +++ b/internal/tsc_wrapped/tsc_wrapped.ts @@ -155,10 +155,9 @@ function runOneBuild( const emitResult = tsickle.mergeEmitResults(emitResults); - if (bazelOpts.tsickleGenerateExterns && bazelOpts.tsickleExternsPath) { - fs.writeFileSync( - bazelOpts.tsickleExternsPath, - tsickle.getGeneratedExterns(emitResult.externs)); + 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)) { @@ -170,7 +169,7 @@ function runOneBuild( }); diags.push(...emitResult.diagnostics); } - if (bazelOpts.tsickleGenerateExterns && bazelOpts.tsickleExternsPath) { + if (bazelOpts.tsickleExternsPath) { fs.writeFileSync(bazelOpts.tsickleExternsPath, ''); } } From 090e4c34a0ecb9e31fc81f218fa0286a8b4c2dd3 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Fri, 16 Mar 2018 17:58:22 -0600 Subject: [PATCH 4/8] A couple more bugfixes. --- internal/common/closure.bzl | 1 - internal/tsc_wrapped/compiler_host.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/common/closure.bzl b/internal/common/closure.bzl index 0904254e..4d920b7c 100644 --- a/internal/common/closure.bzl +++ b/internal/common/closure.bzl @@ -24,7 +24,6 @@ def _closure_aspect_impl(target, ctx): es5_sources=depset(srcs), transitive_es5_sources=transitive_es5_srcs, type_blacklisted_declarations=depset(transitive=[dep.typescript.type_blacklisted_declarations for dep in deps]), - runtime_deps=depset(transitive=[d.typescript.runtime_deps for d in deps]), tsickle_externs=[], replay_params=None, devmode_manifest=None, 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))); } From f3bd83d2b44b61089e169ed1aedf394dfcb64746 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Thu, 22 Mar 2018 13:41:50 -0600 Subject: [PATCH 5/8] Add ts_declaration rule. --- defs.bzl | 3 +- internal/build_defs.bzl | 51 +++++++++++++++++++++++++++++++++ internal/common/compilation.bzl | 5 ++-- 3 files changed, 56 insertions(+), 3 deletions(-) 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/internal/build_defs.bzl b/internal/build_defs.bzl index 2dafac52..2fc91fd2 100644 --- a/internal/build_defs.bzl +++ b/internal/build_defs.bzl @@ -199,3 +199,54 @@ 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(allow_files = True, single_file = True), + "compiler": + attr.label( + default=get_tsc(), + single_file=False, + allow_files=True, + executable=True, + cfg="host"), + "supports_workers": attr.bool(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 2a545a6b..542c85ef 100644 --- a/internal/common/compilation.bzl +++ b/internal/common/compilation.bzl @@ -192,8 +192,9 @@ def compile_ts(ctx, if hasattr(ctx.attr,'tsickle_typed') and ctx.attr.tsickle_typed: 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 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 From 09bc88a0fd26135b4e718ba3c744fbb079cce63e Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 6 Jul 2018 12:13:02 -0600 Subject: [PATCH 6/8] Get rid of closure aspect and add runtime_deps to the provider output. --- internal/common/closure.bzl | 39 --------------------------------- internal/common/compilation.bzl | 7 ++++-- 2 files changed, 5 insertions(+), 41 deletions(-) delete mode 100644 internal/common/closure.bzl diff --git a/internal/common/closure.bzl b/internal/common/closure.bzl deleted file mode 100644 index 4d920b7c..00000000 --- a/internal/common/closure.bzl +++ /dev/null @@ -1,39 +0,0 @@ -def _closure_aspect_impl(target, ctx): - """Generate typescript providers for closure_js_libraries""" - if hasattr(target, 'typescript'): - return [] - if not(hasattr(target, 'closure_js_library')): - return [] - direct_typings = target.clutz_dts - srcs = ctx.rule.files.srcs - - deps = getattr(ctx.rule.attr, 'deps', []) - exports = getattr(ctx.rule.attr, 'exports', []) - decls = depset(direct_typings,transitive=[dep.typescript.declarations for dep in exports]) - transitive_deps = [dep.typescript.declarations for dep in deps] - transitive_decls = depset(direct_typings, transitive=transitive_deps) - # transitive_decls = depset(direct_typings+ctx.files._clutz_root_decls, transitive=transitive_deps) - transitive_es6_srcs = depset(srcs, transitive=[dep.typescript.transitive_es6_sources for dep in deps]) - transitive_es5_srcs = depset(srcs, transitive=[dep.typescript.transitive_es5_sources for dep in deps]) - return struct( - typescript=struct( - declarations=decls, - transitive_declarations=transitive_decls, - es6_srcs=depset(srcs), - transitive_es6_sources=transitive_es6_srcs, - es5_sources=depset(srcs), - transitive_es5_sources=transitive_es5_srcs, - type_blacklisted_declarations=depset(transitive=[dep.typescript.type_blacklisted_declarations for dep in deps]), - tsickle_externs=[], - replay_params=None, - devmode_manifest=None, - ) - ) - -closure_aspect = aspect( - attr_aspects = [ - "deps", - "exports", - ], - implementation = _closure_aspect_impl, -) diff --git a/internal/common/compilation.bzl b/internal/common/compilation.bzl index 542c85ef..7278dc9b 100644 --- a/internal/common/compilation.bzl +++ b/internal/common/compilation.bzl @@ -15,7 +15,6 @@ """Used for compilation by the different implementations of build_defs.bzl. """ -load(":common/closure.bzl", "closure_aspect") load(":common/module_mappings.bzl", "module_mappings_aspect") load(":common/json_marshal.bzl", "json_marshal") @@ -23,7 +22,6 @@ BASE_ATTRIBUTES = dict() DEPS_ASPECTS = [ module_mappings_aspect, - closure_aspect, ] # Attributes shared by any typescript-compatible rule (ts_library, ng_module) @@ -348,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": { @@ -373,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, From 2b7d50e5c09bd8313bb8e900ac2fd706319c7410 Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 6 Jul 2018 12:13:17 -0600 Subject: [PATCH 7/8] Fix merge. --- internal/build_defs.bzl | 53 ++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/internal/build_defs.bzl b/internal/build_defs.bzl index 2fc91fd2..e10ac4f7 100644 --- a/internal/build_defs.bzl +++ b/internal/build_defs.bzl @@ -218,27 +218,42 @@ def _ts_declaration_impl(ctx): ts_declaration = rule( _ts_declaration_impl, attrs = dict(COMMON_ATTRIBUTES, **{ - "srcs": - attr.label_list( - allow_files=FileType([ - ".ts", - ".tsx", - ]), - mandatory=True,), + "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(allow_files = True, single_file = True), - "compiler": - attr.label( - default=get_tsc(), - single_file=False, - allow_files=True, - executable=True, - cfg="host"), - "supports_workers": attr.bool(default = True), + "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 @@ -247,6 +262,6 @@ ts_declaration = rule( "node_modules": attr.label(default = Label("@//:node_modules")), }), outputs = { - "tsconfig": "%{name}_tsconfig.json" - } + "tsconfig": "%{name}_tsconfig.json", + }, ) From 55eb1a61fb5507f2d4414eb0745c17513dea5d32 Mon Sep 17 00:00:00 2001 From: Ryan D Brown Date: Fri, 6 Jul 2018 15:20:34 -0600 Subject: [PATCH 8/8] Update to latest rules_typescript. --- WORKSPACE | 10 ++-- examples/BUILD.bazel | 1 + examples/some_soy/BUILD.bazel | 66 ++++++++++++------------ examples/some_soy/runtime_deps_main.ts | 1 - examples/some_soy/runtime_deps_test.sh | 8 --- internal/build_defs.bzl | 9 ---- internal/protobufjs/ts_proto_library.bzl | 1 + 7 files changed, 40 insertions(+), 56 deletions(-) delete mode 100644 examples/some_soy/runtime_deps_main.ts delete mode 100755 examples/some_soy/runtime_deps_test.sh diff --git a/WORKSPACE b/WORKSPACE index 1eb7e784..60d09397 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -44,13 +44,13 @@ node_repositories( preserve_symlinks = True) # Closure compiler. -# This is is needed for the closure interop example, users should not need to add it unless they want to use it. -# Using a fork to get support for clutz. +# 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 = "f8392913b8aa2ce1e477181fa6b5761ca5c1872775a4e6895ef874b0265d7912", - strip_prefix = "rules_closure-2447dc5fc4a94adbbe772c7e943fd31d91ffe21f", - url = "http://github.com/ribrdb/rules_closure/archive/2447dc5fc4a94adbbe772c7e943fd31d91ffe21f.tar.gz", + 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") 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_soy/BUILD.bazel b/examples/some_soy/BUILD.bazel index bc097291..0d2a8a78 100644 --- a/examples/some_soy/BUILD.bazel +++ b/examples/some_soy/BUILD.bazel @@ -21,26 +21,54 @@ load( "closure_js_library", ) load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") -load("//:defs.bzl", "ts_library") +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 = [ - "@io_bazel_rules_closure//closure/library", - ":template", + ":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"], + deps = [":main_js"], ) nodejs_binary( @@ -58,38 +86,10 @@ sh_test( ) ts_library( - name="custom_closure", + name="mini_closure", srcs=[":closure.d.ts"], runtime_deps = [ "@io_bazel_rules_closure//closure/library", ], generate_externs = False, ) - -ts_library( - name = "runtime_deps_main", - srcs = ["runtime_deps_main.ts"], - deps = [ - ":custom_closure", - ], -) - -closure_js_binary( - name = "runtime_deps_jsbin", - entry_points = ["goog:build_bazel_rules_typescript.examples.some_soy.runtime_deps_main"], - deps = [":runtime_deps_main"], -) - -nodejs_binary( - name = "runtime_deps", - data = [ - ":runtime_deps_jsbin", - ], - entry_point = "build_bazel_rules_typescript/examples/some_soy/runtime_deps_jsbin.js", -) - -sh_test( - name = "runtime_deps_test", - srcs = ["runtime_deps_test.sh"], - data = [":runtime_deps"], -) \ No newline at end of file diff --git a/examples/some_soy/runtime_deps_main.ts b/examples/some_soy/runtime_deps_main.ts deleted file mode 100644 index 9dd1ff04..00000000 --- a/examples/some_soy/runtime_deps_main.ts +++ /dev/null @@ -1 +0,0 @@ -console.log(goog.isString("foobar")); \ No newline at end of file diff --git a/examples/some_soy/runtime_deps_test.sh b/examples/some_soy/runtime_deps_test.sh deleted file mode 100755 index 814227bb..00000000 --- a/examples/some_soy/runtime_deps_test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -e - -readonly OUT=$($TEST_SRCDIR/build_bazel_rules_typescript/examples/some_soy/runtime_deps) -if [ "$OUT" != "true" ]; then - echo "Expected output 'true' but was $OUT" - exit 1 -fi diff --git a/internal/build_defs.bzl b/internal/build_defs.bzl index e10ac4f7..9b3b0956 100644 --- a/internal/build_defs.bzl +++ b/internal/build_defs.bzl @@ -106,15 +106,6 @@ def tsc_wrapped_tsconfig(ctx, "node_modules" ] if p]) - if config["compilerOptions"]["target"] == "es6": - if not(config["bazelOptions"]["tsickle"]): - config["compilerOptions"]["module"] = "es2015" - else: - # The "typescript.es5_sources" provider is expected to work - # in both nodejs and in browsers. - # NOTE: tsc-wrapped will always name the enclosed AMD modules - config["compilerOptions"]["module"] = "umd" - # If the user gives a tsconfig attribute, the generated file should extend # from the user's tsconfig. # See https://github.com/Microsoft/TypeScript/issues/9876 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(), ), )