File
Blob: build/js_file.bzl
| 1 | """ |
| 2 | Give a collection of js files a JsInfo provider so it can be used as a dependency for aspect_rules. |
| 3 | """ |
| 4 | |
| 5 | load("@aspect_rules_js//js:providers.bzl", "JsInfo", "js_info") |
| 6 | load("@bazel_lib//lib:copy_to_bin.bzl", "COPY_FILE_TO_BIN_TOOLCHAINS", "copy_file_to_bin_action") |
| 7 | |
| 8 | _ATTRS = { |
| 9 | "srcs": attr.label_list( |
| 10 | allow_files = True, |
| 11 | ), |
| 12 | "deps": attr.label_list(), |
| 13 | } |
| 14 | |
| 15 | def _gather_sources_and_types(ctx, targets, files): |
| 16 | """Gathers sources and types from a list of targets |
| 17 | |
| 18 | Args: |
| 19 | ctx: the rule context |
| 20 | |
| 21 | targets: List of targets to gather sources and types from their JsInfo providers. |
| 22 | |
| 23 | These typically come from the `srcs` and/or `data` attributes of a rule |
| 24 | |
| 25 | files: List of files to gather as sources and types. |
| 26 | |
| 27 | These typically come from the `srcs` and/or `data` attributes of a rule |
| 28 | |
| 29 | Returns: |
| 30 | Sources & declaration files depsets in the sequence (sources, types) |
| 31 | """ |
| 32 | sources = [] |
| 33 | types = [] |
| 34 | |
| 35 | for file in files: |
| 36 | if file.is_source: |
| 37 | file = copy_file_to_bin_action(ctx, file) |
| 38 | |
| 39 | if file.is_directory: |
| 40 | # assume a directory contains types since we can't know that it doesn't |
| 41 | types.append(file) |
| 42 | sources.append(file) |
| 43 | elif ( |
| 44 | file.path.endswith((".d.ts", ".d.ts.map", ".d.mts", ".d.mts.map", ".d.cts", ".d.cts.map")) |
| 45 | ): |
| 46 | types.append(file) |
| 47 | elif file.path.endswith(".json"): |
| 48 | # Any .json can produce types: https://www.typescriptlang.org/tsconfig/#resolveJsonModule |
| 49 | # package.json may be required to resolve types with the "typings" key |
| 50 | types.append(file) |
| 51 | sources.append(file) |
| 52 | else: |
| 53 | sources.append(file) |
| 54 | |
| 55 | # sources as depset |
| 56 | sources = depset(sources, transitive = [ |
| 57 | target[JsInfo].sources |
| 58 | for target in targets |
| 59 | if JsInfo in target |
| 60 | ]) |
| 61 | |
| 62 | # types as depset |
| 63 | types = depset(types, transitive = [ |
| 64 | target[JsInfo].types |
| 65 | for target in targets |
| 66 | if JsInfo in target |
| 67 | ]) |
| 68 | |
| 69 | return (sources, types) |
| 70 | |
| 71 | def _js_file_impl(ctx): |
| 72 | sources, types = _gather_sources_and_types( |
| 73 | ctx = ctx, |
| 74 | targets = ctx.attr.srcs, |
| 75 | files = ctx.files.srcs, |
| 76 | ) |
| 77 | |
| 78 | return [ |
| 79 | js_info( |
| 80 | target = ctx.label, |
| 81 | sources = sources, |
| 82 | types = types, |
| 83 | ), |
| 84 | DefaultInfo( |
| 85 | files = sources, |
| 86 | ), |
| 87 | OutputGroupInfo( |
| 88 | types = types, |
| 89 | ), |
| 90 | ] |
| 91 | |
| 92 | js_file_lib = struct( |
| 93 | attrs = _ATTRS, |
| 94 | implementation = _js_file_impl, |
| 95 | provides = [DefaultInfo, JsInfo, OutputGroupInfo], |
| 96 | ) |
| 97 | |
| 98 | js_file = rule( |
| 99 | implementation = js_file_lib.implementation, |
| 100 | attrs = js_file_lib.attrs, |
| 101 | provides = js_file_lib.provides, |
| 102 | toolchains = COPY_FILE_TO_BIN_TOOLCHAINS, |
| 103 | ) |