-
Notifications
You must be signed in to change notification settings - Fork 12k
/
Copy pathinterop.bzl
157 lines (141 loc) · 5.47 KB
/
interop.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
load("@aspect_rules_js//js:providers.bzl", "JsInfo", "js_info")
load("@aspect_rules_ts//ts:defs.bzl", _ts_project = "ts_project")
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSModuleInfo", "LinkablePackageInfo")
load("@devinfra//bazel/ts_project:index.bzl", "strict_deps_test")
def _ts_deps_interop_impl(ctx):
types = []
sources = []
runfiles = ctx.runfiles(files = [])
for dep in ctx.attr.deps:
if not DeclarationInfo in dep:
fail("Expected target with DeclarationInfo: %s", dep)
types.append(dep[DeclarationInfo].transitive_declarations)
if not JSModuleInfo in dep:
fail("Expected target with JSModuleInfo: %s", dep)
sources.append(dep[JSModuleInfo].sources)
if not DefaultInfo in dep:
fail("Expected target with DefaultInfo: %s", dep)
runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
return [
DefaultInfo(runfiles = runfiles),
## NOTE: We don't need to propagate module mappings FORTUNATELY!
# because rules_nodejs supports tsconfig path mapping, given that
# everything is nicely compiled from `bazel-bin/`!
js_info(
target = ctx.label,
transitive_types = depset(transitive = types),
transitive_sources = depset(transitive = sources),
),
]
ts_deps_interop = rule(
implementation = _ts_deps_interop_impl,
attrs = {
"deps": attr.label_list(providers = [DeclarationInfo], mandatory = True),
},
toolchains = ["@devinfra//bazel/git-toolchain:toolchain_type"],
)
def _ts_project_module_impl(ctx):
# Forward runfiles. e.g. JSON files on `ts_project#data`. The jasmine
# consuming rules may rely on this, or the linker due to its symlinks then.
runfiles = ctx.attr.dep[DefaultInfo].default_runfiles
info = ctx.attr.dep[JsInfo]
# Filter runfiles to not include `node_modules` from Aspect as this interop
# target is supposed to be used downstream by `rules_nodejs` consumers,
# and mixing pnpm-style node modules with linker node modules is incompatible.
filtered_runfiles = []
for f in runfiles.files.to_list():
if f.short_path.startswith("node_modules/"):
continue
filtered_runfiles.append(f)
runfiles = ctx.runfiles(files = filtered_runfiles)
providers = [
DefaultInfo(
runfiles = runfiles,
),
JSModuleInfo(
direct_sources = info.sources,
sources = depset(transitive = [info.transitive_sources]),
),
JSEcmaScriptModuleInfo(
direct_sources = info.sources,
sources = depset(transitive = [info.transitive_sources]),
),
DeclarationInfo(
declarations = _filter_types_depset(info.types),
transitive_declarations = _filter_types_depset(info.transitive_types),
type_blocklisted_declarations = depset(),
),
]
if ctx.attr.module_name:
providers.append(
LinkablePackageInfo(
package_name = ctx.attr.module_name,
package_path = "",
path = "%s/%s/%s" % (ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package),
files = info.sources,
),
)
return providers
ts_project_module = rule(
implementation = _ts_project_module_impl,
attrs = {
"dep": attr.label(providers = [JsInfo], mandatory = True),
# Noop attribute for aspect propagation of the linker interop deps; so
# that transitive linker dependencies are discovered.
"deps": attr.label_list(),
# Note: The module aspect from consuming `ts_library` targets will
# consume the module mappings automatically.
"module_name": attr.string(),
"module_root": attr.string(),
},
)
def ts_project(
name,
module_name = None,
deps = [],
tsconfig = None,
testonly = False,
visibility = None,
ignore_strict_deps = False,
**kwargs):
if tsconfig == None:
tsconfig = "//:test-tsconfig" if testonly else "//:build-tsconfig"
_ts_project(
name = name,
testonly = testonly,
declaration = True,
tsconfig = tsconfig,
visibility = visibility,
# Use the worker from our own Angular rules, as the default worker
# from `rules_ts` is incompatible with TS5+ and abandoned. We need
# worker for efficient, fast DX and avoiding Windows no-sandbox issues.
supports_workers = 1,
tsc_worker = "//tools:vanilla_ts_worker",
deps = deps,
**kwargs
)
if not ignore_strict_deps:
strict_deps_test(
name = "%s_strict_deps_test" % name,
srcs = kwargs.get("srcs", []),
deps = deps,
)
ts_project_module(
name = "%s_legacy" % name,
testonly = testonly,
visibility = visibility,
dep = name,
deps = deps,
module_name = module_name,
)
# Filter type provider to not include `.json` files. `ts_config`
# targets are included in `ts_project` and their tsconfig json file
# is included as type. See:
# https://github.com/aspect-build/rules_ts/blob/main/ts/private/ts_config.bzl#L55C63-L55C68.
def _filter_types_depset(types_depset):
types = []
for t in types_depset.to_list():
if t.short_path.endswith(".json"):
continue
types.append(t)
return depset(types)