I'm trying to build a bazel rule for codegen'ing GraphQL types, using the graphql-codegen
library.
The implementation of the gqlgen
rule is straightforward:
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
_SCHEMA = """
{types}:
schema: {schema}
plugins:
- "typescript"
{meta}:
schema: {schema}
plugins:
- "introspection"
"""
_CONFIG = """
overwrite: true
generates:
{instructions}
"""
def _gqlgen_impl(ctx):
config_file = ctx.actions.declare_file(ctx.label.name + ".yml")
out_files = []
instructions = []
for s in ctx.files.srcs:
name = paths.basename(s.path)[:-len(".graphql")]
types = ctx.actions.declare_file("types/{}.ts".format(name))
meta = ctx.actions.declare_file("meta/{}.json".format(name))
out_files.append(types)
out_files.append(meta)
instructions.append(_SCHEMA.format(schema = s.path, types = types.path, meta = meta.path))
instructions = "\n".join(instructions)
ctx.actions.write(
content = _CONFIG.format(instructions = instructions),
output = config_file,
)
ctx.actions.run_shell(
tools = [ctx.executable._codegen],
inputs = depset(ctx.files.srcs + [config_file]),
outputs = out_files,
command = "{gqlgen} --config {cfg}".format(
gqlgen = ctx.executable._codegen.path,
cfg = config_file.path,
),
)
The input is a set of *.graphql
files and the output is a corresponding set of *.json
and *.ts
files.
I'm using the nodejs rules, and since graphql-codegen
is a node module, I'm declaring a rule for it in the gqlgen
rule:
def gqlgen(name, **kwargs):
nodejs_binary(
name = "gqlgen",
data = ["@npm//:node_modules"],
entry_point = "@npm//:node_modules/@graphql-codegen/cli/bin.js",
install_source_map_support = False,
visibility = ["//visibility:public"],
)
_gqlgen(
name = name,
**kwargs
)
My issue lies in tying these two things together. I have the following:
_gqlgen = rule(
implementation = _gqlgen_impl,
attrs = {
"srcs": attr.label_list(
allow_files = [".graphql"],
),
"_codegen": attr.label(
cfg = "host",
default = "//schemas:gqlgen",
executable = True,
),
},
)
Note, however, that for the _codegen
attribute I'm specifying the executable as //schemas:gqlgen
, which is wrong, since I should be able to use the gqlgen
rule from any package.
Is there a way to refer to the nodejs_binary
from the call to rule()
?
To answer my question, I can simply do the following:
_gqlgen = rule(
implementation = _gqlgen_impl,
attrs = {
"srcs": attr.label_list(
allow_files = [".graphql"],
),
"_codegen": attr.label(
cfg = "host",
executable = True,
),
},
)
def gqlgen(name, **kwargs):
nodejs_binary(
name = "gqlgen",
data = ["@npm//:node_modules"],
entry_point = "@npm//:node_modules/@graphql-codegen/cli/bin.js",
install_source_map_support = False,
visibility = ["//visibility:public"],
)
_gqlgen(
name = name,
_codegen = "gqlgen",
**kwargs
)