| """Hacky way of allowing rules_nodejs targets to depend on rules_closure targets. |
| |
| We don't have a way of producing TypeScript code directly from .proto schemas. |
| Nor do we have a way of managing their dependencies using ts_library. So what |
| we do is use closure_rules to generate code for the protos and to package up |
| all that code and its dependencies into a single .js file, add the required |
| ES exports and suppressions to that file, and feed it into the TypeScript |
| compiler. |
| """ |
| |
| load("@bazel_skylib//rules:write_file.bzl", "write_file") |
| load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary", "closure_js_library") |
| load("@npm//@bazel/typescript:index.bzl", "ts_library") |
| |
| def ts_library_from_closure(name, namespace_aliases, deps): |
| """Returns a ts_library that wraps the given Closure libraries. |
| |
| Args: |
| name: The name to give to the ts_library and its ES module. |
| namespace_aliases: A dictionary whose keys are the names that this |
| TypeScript ES module should export, and the values are the Closure |
| namespaces whose values should be exported under those names. |
| deps: The Closure libraries providing the above namespaces. |
| """ |
| write_file( |
| name = name + "_entry_point_js", |
| out = name + "_entry_point.js", |
| content = ["goog.module('epm${name}');".format(name = name)] + [ |
| "const epr${alias} = goog.require('{namespace}');".format( |
| alias = alias, |
| namespace = namespace, |
| ) |
| for alias, namespace in namespace_aliases.items() |
| ] + [ |
| "{alias} = epr${alias};".format(alias = alias) |
| for alias in namespace_aliases |
| ], |
| ) |
| write_file( |
| name = name + "_externs_js", |
| out = name + "_externs.js", |
| content = ["/** @externs */"] + [ |
| "let {alias};".format(alias = alias) |
| for alias in namespace_aliases |
| ], |
| ) |
| closure_js_library( |
| name = name + "_lib", |
| srcs = [ |
| name + "_entry_point.js", |
| name + "_externs.js", |
| ], |
| deps = deps, |
| ) |
| closure_js_binary( |
| name = name + "_bin", |
| deps = [name + "_lib"], |
| # According to https://kangax.github.io/compat-table/es2016plus/, |
| # ES2017 is the latest standard fully supported by Chrome, Firefox, |
| # and Safari as of 2020-08-20. It is also used in tsconfig.json. |
| language = "ECMASCRIPT_2017", |
| entry_points = ["epm${name}".format(name = name)], |
| # Advanced optimizations remove dead code, which is a problem here |
| # because we have no way to straightforwardly tell Closure Compiler |
| # that the publicly-exposed properties of classes that are part of our |
| # public API aren't dead code. |
| compilation_level = "SIMPLE", |
| # For easier debugging. Terser will remove this whitespace from |
| # production builds. |
| formatting = "PRETTY_PRINT", |
| ) |
| write_file( |
| name = name + "_preamble_js", |
| out = name + "_preamble.js", |
| content = ["// @ts-nocheck"] + [ |
| "export let {alias};".format(alias = alias) |
| for alias in namespace_aliases |
| ] + [ |
| "export type {alias} = any;".format(alias = alias) |
| for alias in namespace_aliases |
| ], |
| ) |
| native.genrule( |
| name = name + "_ts", |
| srcs = [ |
| name + "_preamble.js", |
| name + "_bin.js", |
| ], |
| outs = [name + ".ts"], |
| cmd = "cat $(SRCS) >$@", |
| ) |
| ts_library( |
| name = name, |
| srcs = [name + ".ts"], |
| ) |