anki/ts/protobuf.bzl
Damien Elmes 829b99e5b2 force number in protobuf generation
Anki's object IDs and millisecond timestamps fit within MAX_SAFE_INTEGER.
2021-04-12 14:33:20 +10:00

127 lines
4.3 KiB
Python

# taken from example on
# https://github.com/bazelbuild/rules_nodejs/commit/078243a217afe85a8c8f449838bb66ca87608aba
# tweaked to use json-module instead of static-module, and force number
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
# TODO switch to protobufjs-cli when its published
# https://github.com/protobufjs/protobuf.js/commit/da34f43ccd51ad97017e139f137521782f5ef119
load("@npm//protobufjs:index.bzl", "pbjs", "pbts")
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
# protobuf.js relies on these packages, but does not list them as dependencies
# in its package.json.
# Instead they are listed under "cliDependencies"
# (see https://unpkg.com/protobufjs@6.10.2/package.json)
# When run, the CLI attempts to run `npm install` at runtime to get them.
# This fails under Bazel as it tries to access the npm cache outside of the sandbox.
# Per Bazel semantics, all dependencies should be pre-declared.
# Note, you'll also need to install all of these in your package.json!
# (This should be fixed when we switch to protobufjs-cli)
_PROTOBUFJS_CLI_DEPS = ["@npm//%s" % s for s in [
"chalk",
"escodegen",
"espree",
"estraverse",
"glob",
"jsdoc",
"minimist",
"semver",
"tmp",
"uglify-js",
]]
def _proto_sources_impl(ctx):
return DefaultInfo(files = ctx.attr.proto[ProtoInfo].transitive_sources)
_proto_sources = rule(
doc = """Provider Adapter from ProtoInfo to DefaultInfo.
Extracts the transitive_sources from the ProtoInfo provided by the proto attr.
This allows a macro to access the complete set of .proto files needed during compilation.
""",
implementation = _proto_sources_impl,
attrs = {"proto": attr.label(providers = [ProtoInfo])},
)
def protobufjs_library(name, proto, **kwargs):
"""Minimal wrapper macro around pbjs/pbts tooling
Args:
name: name of generated js_library target, also used to name the .js/.d.ts outputs
proto: label of a single proto_library target to generate for
**kwargs: passed through to the js_library
"""
js_static_out = name + "_static.js"
js_out = name + ".js"
ts_out = js_out.replace(".js", ".d.ts")
# Generate some target names, based on the provided name
# (so that they are unique if the macro is called several times in one package)
proto_target = "_%s_protos" % name
js_target = "_%s_pbjs" % name
js_static_target = js_target + "_static"
ts_target = "_%s_pbts" % name
# grab the transitive .proto files needed to compile the given one
_proto_sources(
name = proto_target,
proto = proto,
)
# Build static module, which we need for pbts
pbjs(
name = js_static_target,
data = [proto_target] + _PROTOBUFJS_CLI_DEPS,
# Arguments documented at
# https://github.com/protobufjs/protobuf.js/tree/6.8.8#pbjs-for-javascript
args = [
"--target=static-module",
"--wrap=default",
#"--strict-long", # Force usage of Long type with int64 fields
"--force-number",
"--out=$@",
"$(execpaths %s)" % proto_target,
],
outs = [js_static_out],
)
# Build json module, which we'll use in our code.
pbjs(
name = js_target,
data = [proto_target] + _PROTOBUFJS_CLI_DEPS,
# Arguments documented at
# https://github.com/protobufjs/protobuf.js/tree/6.8.8#pbjs-for-javascript
args = [
"--target=json-module",
"--wrap=default",
#"--strict-long", # Force usage of Long type with int64 fields
"--force-number",
"--out=$@",
"$(execpaths %s)" % proto_target,
],
outs = [js_out],
)
# Transform the _pb.js file to a .d.ts file with TypeScript types
pbts(
name = ts_target,
data = [js_static_target] + _PROTOBUFJS_CLI_DEPS,
# Arguments documented at
# https://github.com/protobufjs/protobuf.js/tree/6.8.8#pbts-for-typescript
args = [
"--out=$@",
"$(execpath %s)" % js_static_target,
],
outs = [ts_out],
)
# Expose the results as js_library which provides DeclarationInfo for interop with other rules
js_library(
name = name,
srcs = [
js_target,
ts_target,
],
**kwargs
)