| # 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. |
| "Protocol Buffers" |
| |
| def _run_pbjs(actions, executable, output_name, proto_files, suffix = ".js", wrap = "amd", amd_name = ""): |
| js_file = actions.declare_file(output_name + suffix) |
| |
| # Create an intermediate file so that we can do some manipulation of the |
| # generated .js output that makes it compatible with our named AMD loading. |
| js_tmpl_file = actions.declare_file(output_name + suffix + ".tmpl") |
| |
| # Reference of arguments: |
| # https://github.com/dcodeIO/ProtoBuf.js/#pbjs-for-javascript |
| args = actions.args() |
| args.add_all(["--target", "static-module"]) |
| args.add_all(["--wrap", wrap]) |
| args.add("--strict-long") # Force usage of Long type with int64 fields |
| args.add_all(["--out", js_file.path + ".tmpl"]) |
| args.add_all(proto_files) |
| |
| actions.run( |
| executable = executable._pbjs, |
| inputs = proto_files, |
| outputs = [js_tmpl_file], |
| arguments = [args], |
| ) |
| |
| actions.expand_template( |
| template = js_tmpl_file, |
| output = js_file, |
| substitutions = { |
| # convert anonymous AMD module |
| # define(["protobufjs/minimal"], function($protobuf) { |
| # to named |
| # define("wksp/path/to/module", ["protobufjs/minimal"], ... |
| "define([": "define('%s/%s', [" % (amd_name, output_name), |
| }, |
| ) |
| return js_file |
| |
| def _run_pbts(actions, executable, js_file): |
| ts_file = actions.declare_file(js_file.basename[:-len(".closure.js")] + ".d.ts") |
| |
| # Reference of arguments: |
| # https://github.com/dcodeIO/ProtoBuf.js/#pbts-for-typescript |
| args = actions.args() |
| args.add_all(["--out", ts_file.path]) |
| args.add(js_file.path) |
| |
| actions.run( |
| executable = executable._pbts, |
| progress_message = "Generating typings from %s" % js_file.short_path, |
| inputs = [js_file], |
| outputs = [ts_file], |
| arguments = [args], |
| ) |
| return ts_file |
| |
| def _ts_proto_library(ctx): |
| sources = depset() |
| for dep in ctx.attr.deps: |
| if not hasattr(dep, "proto"): |
| fail("ts_proto_library dep %s must be a proto_library rule" % dep.label) |
| |
| # TODO(alexeagle): go/new-proto-library suggests |
| # > should not parse .proto files. Instead, they should use the descriptor |
| # > set output from proto_library |
| # but protobuf.js doesn't seem to accept that bin format |
| sources = depset(transitive = [sources, dep.proto.transitive_sources]) |
| |
| output_name = ctx.attr.output_name or ctx.label.name |
| |
| js_es5 = _run_pbjs( |
| ctx.actions, |
| ctx.executable, |
| output_name, |
| sources, |
| amd_name = "/".join([p for p in [ |
| ctx.workspace_name, |
| ctx.label.package, |
| ] if p]), |
| ) |
| js_es6 = _run_pbjs( |
| ctx.actions, |
| ctx.executable, |
| output_name, |
| sources, |
| suffix = ".closure.js", |
| wrap = "es6", |
| ) |
| dts = _run_pbts(ctx.actions, ctx.executable, js_es6) |
| |
| # Return a structure that is compatible with the deps[] of a ts_library. |
| return struct( |
| files = depset([dts]), |
| typescript = struct( |
| declarations = depset([dts]), |
| transitive_declarations = depset([dts]), |
| type_blacklisted_declarations = depset(), |
| es5_sources = depset([js_es5]), |
| es6_sources = depset([js_es6]), |
| transitive_es5_sources = depset(), |
| transitive_es6_sources = depset([js_es6]), |
| ), |
| ) |
| |
| ts_proto_library = rule( |
| implementation = _ts_proto_library, |
| attrs = { |
| "output_name": attr.string( |
| doc = """Name of the resulting module, which you will import from. |
| If not specified, the name will match the target's name.""", |
| ), |
| "deps": attr.label_list(doc = "proto_library targets"), |
| "_pbjs": attr.label( |
| default = Label("//internal/protobufjs:pbjs"), |
| executable = True, |
| cfg = "host", |
| ), |
| "_pbts": attr.label( |
| default = Label("//internal/protobufjs:pbts"), |
| executable = True, |
| cfg = "host", |
| ), |
| }, |
| ) |
| """ |
| Wraps https://github.com/dcodeIO/protobuf.js for use in Bazel. |
| |
| `ts_proto_library` has identical outputs to `ts_library`, so it can be used anywhere |
| a `ts_library` can appear, such as in the `deps[]` of another `ts_library`. |
| |
| Example: |
| |
| ``` |
| load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_proto_library") |
| |
| proto_library( |
| name = "car_proto", |
| srcs = ["car.proto"], |
| ) |
| |
| ts_proto_library( |
| name = "car", |
| deps = [":car_proto"], |
| ) |
| |
| ts_library( |
| name = "test_lib", |
| testonly = True, |
| srcs = ["car.spec.ts"], |
| deps = [":car"], |
| ) |
| ``` |
| |
| Note in this example we named the `ts_proto_library` rule `car` so that the |
| result will be `car.d.ts`. This means our TypeScript code can just |
| `import {symbols} from './car'`. Use the `output_name` attribute if you want to |
| name the rule differently from the output file. |
| |
| The JavaScript produced by protobuf.js has a runtime dependency on a support library. |
| Under devmode (e.g. `ts_devserver`, `ts_web_test_suite`) you'll need to include these scripts |
| in the `bootstrap` phase (before Require.js loads). You can use the label |
| `@build_bazel_rules_typescript//:protobufjs_bootstrap_scripts` to reference these scripts |
| in the `bootstrap` attribute of `ts_web_test_suite` or `ts_devserver`. |
| |
| To complete the example above, you could write a `ts_web_test_suite`: |
| |
| ``` |
| load("@build_bazel_rules_karma//:defs.bzl", "ts_web_test_suite") |
| |
| ts_web_test_suite( |
| name = "test", |
| deps = ["test_lib"], |
| bootstrap = ["@build_bazel_rules_typescript//:protobufjs_bootstrap_scripts"], |
| browsers = [ |
| "@io_bazel_rules_webtesting//browsers:chromium-local", |
| "@io_bazel_rules_webtesting//browsers:firefox-local", |
| ], |
| ) |
| ``` |
| """ |