-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdummy-spec.ts
99 lines (96 loc) · 3.31 KB
/
dummy-spec.ts
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
import NodePath from "node:path";
import { Glob, type GlobOptionsWithFileTypesUnset } from "glob";
import {
type AbsoluteLabel,
BazelLikeSpec,
type BazelTarget,
type ExactLabel,
type Spec,
build,
resolve,
} from "../label/exports";
import { getContext } from "./context";
import type { DummyBuildFileFn } from "./types";
export interface DummySpecOptions {
ignore?: string[];
buildFileName?: string | string[];
resolveRepoRoot?: (v: string) => string;
}
export class DummySpec extends BazelLikeSpec<BazelTarget> implements Spec<BazelTarget> {
readonly buildFileName: string[];
readonly resolveRepoRoot?: (repoName: string) => string;
readonly context: string;
readonly globOptions: GlobOptionsWithFileTypesUnset;
constructor(context: string, options: DummySpecOptions = {}) {
super();
this.context = context;
if (!NodePath.isAbsolute(this.context)) {
throw new Error(`Context must be absolute path`);
}
this.buildFileName = (
Array.isArray(options.buildFileName) ? options.buildFileName : [options.buildFileName]
).filter(Boolean as unknown as (v: any) => v is string);
if (this.buildFileName.length === 0) {
this.buildFileName.push("BUILD.{mjs,ts,js,mts,cts,cjs}");
}
this.resolveRepoRoot = options.resolveRepoRoot;
this.globOptions = {
ignore: options.ignore || [],
};
}
protected resolvePackage(label: AbsoluteLabel) {
if (label.scope === "") {
return NodePath.resolve(this.context, label.package);
} else if (this.resolveRepoRoot) {
return NodePath.resolve(this.resolveRepoRoot(label.scope), label.package);
} else {
throw new Error(
`Cannot resolve scope label "${build(label)}" without "resolveRepoRoot" provided`
);
}
}
async lookup(label: AbsoluteLabel) {
const base = this.resolvePackage(label);
const glob = new Glob(
this.buildFileName.map((v) => (label.includeSubPackages ? `**/${v}` : v)),
{
...this.globOptions,
cwd: base,
nodir: true,
absolute: false,
ignore: [
"**/node_modules/**",
"**/dist/**",
...((this.globOptions?.ignore as string[]) || []),
],
}
);
return Array.from(await glob.walk(), (v) => {
return resolve(
{ ...label, includeSubPackages: false },
{
package: NodePath.dirname(v),
includeSubPackages: false,
target: NodePath.basename(v),
}
) as ExactLabel;
});
}
async load(buildfile: AbsoluteLabel) {
const path = NodePath.resolve(this.resolvePackage(buildfile), buildfile.target);
const mod = (await import(path)) as
| { default: DummyBuildFileFn }
| { default: { default: DummyBuildFileFn } };
let fn = "default" in mod.default ? mod.default.default : mod.default;
fn = fn ?? (() => ({}));
const f = await fn(getContext({ workspace: this.context, pkg: buildfile.package }));
const { rules, files = [] } = ("rules" in f || "files" in f ? f : { rules: f, files: [] }) as {
rules: Record<string, unknown>;
files: string[];
};
return {
...Object.fromEntries(Object.entries(rules).map(([k, v]) => [k, { type: "rule", rule: v }])),
...Object.fromEntries(files.map((v: string) => [v, { type: "file", file: v }])),
} as Record<string, BazelTarget>;
}
}