env-runner 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -2
- package/dist/_chunks/common-base-runner.d.mts +434 -1
- package/dist/_chunks/common-base-runner.mjs +596 -7
- package/dist/_chunks/common-worker-utils.mjs +19 -477
- package/dist/_chunks/deno-process-runner.d.mts +4 -1
- package/dist/_chunks/deno-process-runner.mjs +7 -0
- package/dist/_chunks/miniflare-runner.d.mts +5 -2
- package/dist/_chunks/miniflare-runner.mjs +169 -43
- package/dist/_chunks/netlify-runner.d.mts +3 -1
- package/dist/_chunks/node-worker-runner.d.mts +3 -1
- package/dist/_chunks/node-worker-runner.mjs +7 -2
- package/dist/_chunks/plugin-hooks.mjs +1656 -0
- package/dist/_chunks/server.mjs +1 -0
- package/dist/_chunks/types.d.mts +1 -1
- package/dist/_chunks/vercel-runner.d.mts +3 -1
- package/dist/cli.mjs +0 -0
- package/dist/index.d.mts +6 -2
- package/dist/runners/bun-process/runner.d.mts +4 -1
- package/dist/runners/bun-process/runner.mjs +8 -1
- package/dist/runners/bun-process/worker.mjs +5 -4
- package/dist/runners/deno-process/worker.mjs +5 -4
- package/dist/runners/node-process/runner.d.mts +3 -1
- package/dist/runners/node-process/worker.mjs +5 -4
- package/dist/runners/node-worker/worker.mjs +5 -4
- package/dist/runners/self/runner.d.mts +3 -1
- package/dist/runners/self/runner.mjs +4 -0
- package/package.json +18 -18
- package/dist/_chunks/virtual-loader.mjs +0 -345
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { encodeVirtualModules, normalizeVirtualModules, resolveVirtualModules, warnVirtualPathCollisions } from "./
|
|
1
|
+
import { PLUGINS_DATA_KEY, compileFilter, compileFilterExpressions, compilePrefilter, createPrefilter, encodeVirtualModules, moduleTypeOf, normalizeFilterId, normalizeVirtualModules, openTransformPort, openTransformSocket, queryOf, requiredMatch, resolveVirtualModules, satisfiesMatch, stripQuery, virtualModuleFormat, warnVirtualPathCollisions } from "./plugin-hooks.mjs";
|
|
2
|
+
import { isBuiltin } from "node:module";
|
|
2
3
|
import { rm } from "node:fs/promises";
|
|
3
4
|
import { proxyFetch, proxyUpgrade } from "httpxy";
|
|
5
|
+
import * as nodePath from "node:path";
|
|
6
|
+
import { isAbsolute, normalize } from "node:path";
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
import { resolveModulePath } from "exsolve";
|
|
4
9
|
function hostEnv(extra) {
|
|
5
10
|
const env = {
|
|
6
11
|
...process.env,
|
|
@@ -11,6 +16,559 @@ function hostEnv(extra) {
|
|
|
11
16
|
if (!("COLUMNS" in env) && stdout?.columns) env.COLUMNS = String(stdout.columns);
|
|
12
17
|
return env;
|
|
13
18
|
}
|
|
19
|
+
const SEP = String.raw`[\\/]`;
|
|
20
|
+
const SEGMENT_CHAR = String.raw`[^\\/]`;
|
|
21
|
+
function resolveGlob(pattern, cwd = process.cwd(), windows = process.platform === "win32") {
|
|
22
|
+
if (pattern.startsWith("**")) return pattern;
|
|
23
|
+
if ((windows ? nodePath.win32 : nodePath.posix).isAbsolute(pattern)) return windows && !pattern.includes("/") ? pattern.replaceAll("\\", "/") : pattern;
|
|
24
|
+
const base = cwd.replaceAll("\\", "/").replace(/[*?[\]{}()!+@,\\]/g, "\\$&");
|
|
25
|
+
return nodePath.posix.join(base, pattern);
|
|
26
|
+
}
|
|
27
|
+
function globToRegExp(glob) {
|
|
28
|
+
const closing = _braceMatches(glob);
|
|
29
|
+
let source = "";
|
|
30
|
+
let depth = 0;
|
|
31
|
+
for (let i = 0; i < glob.length; i++) {
|
|
32
|
+
const char = glob[i];
|
|
33
|
+
if (char === "\\" && i + 1 < glob.length) source += _escape(glob[++i]);
|
|
34
|
+
else if (char === "*") {
|
|
35
|
+
if (glob[i + 1] !== "*") {
|
|
36
|
+
source += `${SEGMENT_CHAR}*`;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!((i === 0 || glob[i - 1] === "/") && (i + 2 === glob.length || glob[i + 2] === "/"))) source += `${SEGMENT_CHAR}*`;
|
|
40
|
+
else if (i + 2 === glob.length) source += ".*";
|
|
41
|
+
else {
|
|
42
|
+
source += `(?:${SEGMENT_CHAR}*${SEP})*`;
|
|
43
|
+
i++;
|
|
44
|
+
}
|
|
45
|
+
i++;
|
|
46
|
+
} else if (char === "?") source += SEGMENT_CHAR;
|
|
47
|
+
else if (char === "[" && glob.indexOf("]", i + 2) !== -1) {
|
|
48
|
+
const end = glob.indexOf("]", i + 2);
|
|
49
|
+
let body = glob.slice(i + 1, end);
|
|
50
|
+
const negated = body[0] === "!" || body[0] === "^";
|
|
51
|
+
if (negated) body = body.slice(1);
|
|
52
|
+
source += `[${negated ? String.raw`^\\/` : ""}${body.replace(/[\\\]^]/g, "\\$&")}]`;
|
|
53
|
+
i = end;
|
|
54
|
+
} else if (char === "{" && closing.has(i)) {
|
|
55
|
+
depth++;
|
|
56
|
+
source += "(?:";
|
|
57
|
+
} else if (char === "}" && depth > 0) {
|
|
58
|
+
depth--;
|
|
59
|
+
source += ")";
|
|
60
|
+
} else if (char === "," && depth > 0) source += "|";
|
|
61
|
+
else source += char === "/" ? SEP : _escape(char);
|
|
62
|
+
}
|
|
63
|
+
return new RegExp(`^${source}$`);
|
|
64
|
+
}
|
|
65
|
+
function _braceMatches(glob) {
|
|
66
|
+
const open = [];
|
|
67
|
+
const matched = /* @__PURE__ */ new Set();
|
|
68
|
+
for (let i = 0; i < glob.length; i++) if (glob[i] === "\\") i++;
|
|
69
|
+
else if (glob[i] === "{") open.push(i);
|
|
70
|
+
else if (glob[i] === "}" && open.length > 0) matched.add(open.pop());
|
|
71
|
+
return matched;
|
|
72
|
+
}
|
|
73
|
+
function _escape(char) {
|
|
74
|
+
return char.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
75
|
+
}
|
|
76
|
+
const KNOWN_MODULE_TYPES = [
|
|
77
|
+
"js",
|
|
78
|
+
"jsx",
|
|
79
|
+
"ts",
|
|
80
|
+
"tsx",
|
|
81
|
+
"json"
|
|
82
|
+
];
|
|
83
|
+
function createPluginPipeline(plugins, options = {}) {
|
|
84
|
+
const { resolveConditions } = options;
|
|
85
|
+
if (plugins == null) return;
|
|
86
|
+
if (!Array.isArray(plugins)) throw new TypeError("[env-runner] `plugins` must be an array of plugin objects.");
|
|
87
|
+
const normalized = _flattenPlugins(plugins, "").map(([plugin, path]) => _normalizePlugin(plugin, path));
|
|
88
|
+
const rank = {
|
|
89
|
+
pre: 0,
|
|
90
|
+
normal: 1,
|
|
91
|
+
post: 2
|
|
92
|
+
};
|
|
93
|
+
const enforced = normalized.toSorted((a, b) => rank[a.enforce] - rank[b.enforce]);
|
|
94
|
+
const ordered = (kind) => {
|
|
95
|
+
const hooks = enforced.flatMap((plugin) => plugin[kind] ? [plugin[kind]] : []);
|
|
96
|
+
const byOrder = (order) => hooks.filter((hook) => hook.order === order);
|
|
97
|
+
return [
|
|
98
|
+
...byOrder("pre"),
|
|
99
|
+
...byOrder("normal"),
|
|
100
|
+
...byOrder("post")
|
|
101
|
+
];
|
|
102
|
+
};
|
|
103
|
+
const resolveHooks = ordered("resolveId");
|
|
104
|
+
const loadHooks = ordered("load");
|
|
105
|
+
const transformHooks = ordered("transform");
|
|
106
|
+
if (resolveHooks.length + loadHooks.length + transformHooks.length === 0) return;
|
|
107
|
+
const prefilters = normalized.flatMap((plugin) => [plugin.load, plugin.transform].flatMap((hook) => hook ? [hook.prefilter] : []));
|
|
108
|
+
const resolvePrefilters = resolveHooks.map((hook) => hook.prefilter);
|
|
109
|
+
const fallbackPrefilter = createPrefilter(resolvePrefilters.filter((prefilter) => prefilter.fallback));
|
|
110
|
+
const prefilter = createPrefilter(prefilters);
|
|
111
|
+
const resolvePrefilter = createPrefilter(resolvePrefilters.filter((prefilter) => !prefilter.fallback));
|
|
112
|
+
const filter = (id, moduleType, resolved) => {
|
|
113
|
+
const matchId = normalizeFilterId(id);
|
|
114
|
+
return prefilter(matchId, moduleType ?? moduleTypeOf(matchId), resolved || moduleType !== void 0);
|
|
115
|
+
};
|
|
116
|
+
const contextResolve = (caller, skip) => async (source, importer, options = {}) => {
|
|
117
|
+
if (typeof source !== "string") throw new TypeError(`[env-runner] \`this.resolve()\` needs a string (got ${_describe(source)}).`);
|
|
118
|
+
const skipping = caller && options.skipSelf !== false ? [...skip, {
|
|
119
|
+
hook: caller,
|
|
120
|
+
source,
|
|
121
|
+
importer
|
|
122
|
+
}] : skip;
|
|
123
|
+
const skipped = new Set(skipping.filter((entry) => entry.source === source && entry.importer === importer).map((entry) => entry.hook));
|
|
124
|
+
const { skipSelf: _, ...rest } = options;
|
|
125
|
+
return await _resolveId(source, importer, rest, skipped, skipping) ?? _resolveLikeRuntime(source, importer, resolveConditions?.()) ?? await _resolveId(source, importer, {
|
|
126
|
+
...rest,
|
|
127
|
+
fallback: true
|
|
128
|
+
}, skipped, skipping) ?? null;
|
|
129
|
+
};
|
|
130
|
+
const _resolveId = async (source, importer, options, skipped, skip) => {
|
|
131
|
+
const matchId = normalizeFilterId(source);
|
|
132
|
+
const extra = {
|
|
133
|
+
isEntry: options?.isEntry ?? false,
|
|
134
|
+
attributes: options?.attributes ?? {}
|
|
135
|
+
};
|
|
136
|
+
for (const hook of resolveHooks) {
|
|
137
|
+
if (Boolean(hook.fallback) !== Boolean(options?.fallback) || skipped.has(hook) || !hook.match(matchId, "js", void 0, true)) continue;
|
|
138
|
+
const context = _createContext(hook.name, source, "", contextResolve(hook, skip));
|
|
139
|
+
const result = await _callHook(hook.name, "failed to resolve", source, "", () => hook.handler.call(context, source, importer, extra));
|
|
140
|
+
if (result == null) continue;
|
|
141
|
+
if (result === false) return {
|
|
142
|
+
id: source,
|
|
143
|
+
external: true
|
|
144
|
+
};
|
|
145
|
+
const id = typeof result === "string" ? result : result.id;
|
|
146
|
+
if (typeof id !== "string" || id === "") throw new TypeError(`[env-runner] plugin "${hook.name}" resolved "${source}" to an invalid id (got ${_describe(id)}): return a string, \`{ id }\` or nullish.`);
|
|
147
|
+
return {
|
|
148
|
+
id,
|
|
149
|
+
external: typeof result === "object" && Boolean(result.external)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const resolveId = (source, importer, options) => _resolveId(source, importer, options, /* @__PURE__ */ new Set(), []);
|
|
154
|
+
const load = async (id, read, options) => {
|
|
155
|
+
const matchId = normalizeFilterId(id);
|
|
156
|
+
let moduleType = moduleTypeOf(id);
|
|
157
|
+
const required = read ? requiredMatch(moduleType) : void 0;
|
|
158
|
+
const resolved = !read || options?.resolved;
|
|
159
|
+
for (const hook of loadHooks) {
|
|
160
|
+
if (!satisfiesMatch(hook.match(matchId, moduleType, void 0, resolved), required)) continue;
|
|
161
|
+
const result = await _callHook(hook.name, "failed to load", id, "", () => hook.handler.call(_createContext(hook.name, id, "", contextResolve(void 0, [])), id));
|
|
162
|
+
if (result == null) continue;
|
|
163
|
+
const code = typeof result === "string" ? result : result.code;
|
|
164
|
+
if (typeof code !== "string") throw new TypeError(`[env-runner] plugin "${hook.name}" loaded non-string \`code\` for "${id}" (got ${_describe(code)}).`);
|
|
165
|
+
const map = typeof result === "object" ? _parseMap(result.map) : void 0;
|
|
166
|
+
if (typeof result === "object" && result.moduleType) moduleType = result.moduleType;
|
|
167
|
+
else if (!KNOWN_MODULE_TYPES.includes(moduleType)) moduleType = "js";
|
|
168
|
+
return _transform(id, code, moduleType, {
|
|
169
|
+
resolved,
|
|
170
|
+
changed: true,
|
|
171
|
+
map,
|
|
172
|
+
mappedBy: map ? hook.name : void 0
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (!read) throw new Error(`[env-runner] no plugin loaded "${id}": a \`resolveId\` hook resolved an import to it, so a \`load\` hook must return its code.`);
|
|
176
|
+
if (!filter(id, void 0, resolved)) return;
|
|
177
|
+
return _transform(id, read(), moduleType, {
|
|
178
|
+
resolved,
|
|
179
|
+
changed: false
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
const _transform = async (id, code, moduleType, state) => {
|
|
183
|
+
let { changed, map, mappedBy } = state;
|
|
184
|
+
const matchId = normalizeFilterId(id);
|
|
185
|
+
for (const hook of transformHooks) {
|
|
186
|
+
const match = hook.match(matchId, moduleType, code, state.resolved);
|
|
187
|
+
if (!satisfiesMatch(match, requiredMatch(moduleType))) continue;
|
|
188
|
+
const result = await _callHook(hook.name, "failed on", id, code, () => hook.handler.call(_createContext(hook.name, id, code, contextResolve(void 0, [])), code, id, { moduleType }));
|
|
189
|
+
const next = typeof result === "string" ? result : result?.code ?? code;
|
|
190
|
+
if (typeof next !== "string") throw new TypeError(`[env-runner] plugin "${hook.name}" returned non-string \`code\` for "${id}" (got ${_describe(next)}): convert it to a string (e.g. \`s.toString()\`, with \`map: s.generateMap()\`).`);
|
|
191
|
+
const resultType = result && typeof result === "object" ? result.moduleType : void 0;
|
|
192
|
+
if (resultType) moduleType = resultType;
|
|
193
|
+
if (next === code) continue;
|
|
194
|
+
code = next;
|
|
195
|
+
changed = true;
|
|
196
|
+
if (!resultType && !KNOWN_MODULE_TYPES.includes(moduleType)) moduleType = "js";
|
|
197
|
+
const nextMap = typeof result === "object" ? _parseMap(result?.map) : void 0;
|
|
198
|
+
if (nextMap) {
|
|
199
|
+
if (mappedBy === void 0) {
|
|
200
|
+
map = nextMap;
|
|
201
|
+
mappedBy = hook.name;
|
|
202
|
+
} else {
|
|
203
|
+
map = void 0;
|
|
204
|
+
_warnDroppedMap(mappedBy, hook.name);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (!changed) return;
|
|
209
|
+
if (moduleType === "json") try {
|
|
210
|
+
JSON.parse(code);
|
|
211
|
+
return {
|
|
212
|
+
code,
|
|
213
|
+
moduleType: "json"
|
|
214
|
+
};
|
|
215
|
+
} catch {
|
|
216
|
+
moduleType = "js";
|
|
217
|
+
}
|
|
218
|
+
if (moduleType !== "js" && moduleType !== "ts") throw new TypeError(`[env-runner] "${id}" is still ${moduleType} after its plugins: add one that compiles it to JavaScript (returning \`moduleType: "js"\`) or narrow the plugins' filters.`);
|
|
219
|
+
if (map) {
|
|
220
|
+
const file = stripQuery(id);
|
|
221
|
+
const source = isAbsolute(file) ? pathToFileURL(file).href : file;
|
|
222
|
+
const json = JSON.stringify({
|
|
223
|
+
...map,
|
|
224
|
+
sources: [source],
|
|
225
|
+
file: void 0
|
|
226
|
+
});
|
|
227
|
+
code += `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(json).toString("base64")}\n`;
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
code,
|
|
231
|
+
moduleType
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
const transform = (id, code, sourceType) => _transform(id, code, sourceType ?? moduleTypeOf(id), {
|
|
235
|
+
resolved: true,
|
|
236
|
+
changed: false
|
|
237
|
+
});
|
|
238
|
+
return {
|
|
239
|
+
names: normalized.map((plugin) => plugin.name),
|
|
240
|
+
prefilters,
|
|
241
|
+
resolvePrefilters,
|
|
242
|
+
filter,
|
|
243
|
+
resolveFilter: (source, fallback) => (fallback ? fallbackPrefilter : resolvePrefilter)(normalizeFilterId(source), "js", true),
|
|
244
|
+
resolveId,
|
|
245
|
+
load,
|
|
246
|
+
transform
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function _resolveLikeRuntime(source, importer, conditions) {
|
|
250
|
+
if (isBuiltin(source)) return {
|
|
251
|
+
id: source,
|
|
252
|
+
external: true
|
|
253
|
+
};
|
|
254
|
+
const from = importer && isAbsolute(stripQuery(importer)) ? stripQuery(importer) : pathToFileURL(`${process.cwd()}/`).href;
|
|
255
|
+
const path = resolveModulePath(stripQuery(source), {
|
|
256
|
+
from,
|
|
257
|
+
conditions,
|
|
258
|
+
try: true,
|
|
259
|
+
cache: false
|
|
260
|
+
});
|
|
261
|
+
return path ? {
|
|
262
|
+
id: normalize(path) + queryOf(source),
|
|
263
|
+
external: false
|
|
264
|
+
} : null;
|
|
265
|
+
}
|
|
266
|
+
async function _callHook(name, what, id, code, call) {
|
|
267
|
+
try {
|
|
268
|
+
return await call();
|
|
269
|
+
} catch (error) {
|
|
270
|
+
const message = error?.message || String(error);
|
|
271
|
+
if (message.startsWith("[env-runner]")) throw error;
|
|
272
|
+
const at = `${id}${_formatPosition(code, _logPosition(error, id, code))}`;
|
|
273
|
+
throw new Error(`[env-runner] plugin "${name}" ${what} "${at}": ${message}${_frame(error)}`, { cause: error });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function _logPosition(log, id, code) {
|
|
277
|
+
const { loc, pos } = log ?? {};
|
|
278
|
+
if (typeof loc?.line === "number" && typeof loc.column === "number") return typeof loc.file === "string" && loc.file !== stripQuery(id) && loc.file !== id ? void 0 : {
|
|
279
|
+
line: loc.line,
|
|
280
|
+
column: loc.column
|
|
281
|
+
};
|
|
282
|
+
return typeof pos === "number" && code ? pos : void 0;
|
|
283
|
+
}
|
|
284
|
+
function _frame(log) {
|
|
285
|
+
const frame = log?.frame;
|
|
286
|
+
return typeof frame === "string" && frame.trim() ? `\n\n${frame.replace(/\n+$/, "")}` : "";
|
|
287
|
+
}
|
|
288
|
+
const VIRTUAL_MODULE_TYPES = {
|
|
289
|
+
module: "js",
|
|
290
|
+
commonjs: "js",
|
|
291
|
+
"module-typescript": "ts",
|
|
292
|
+
"commonjs-typescript": "ts",
|
|
293
|
+
jsx: "jsx",
|
|
294
|
+
tsx: "tsx"
|
|
295
|
+
};
|
|
296
|
+
async function transformVirtualModules(pipeline, modules) {
|
|
297
|
+
const out = { ...modules };
|
|
298
|
+
for (const [key, module] of Object.entries(modules)) {
|
|
299
|
+
if (module === null) continue;
|
|
300
|
+
const format = virtualModuleFormat(key, module);
|
|
301
|
+
const moduleType = VIRTUAL_MODULE_TYPES[format];
|
|
302
|
+
if (!moduleType || !pipeline.filter(key, moduleType)) continue;
|
|
303
|
+
const source = typeof module === "string" ? module : module.source;
|
|
304
|
+
const result = await pipeline.transform(key, source, moduleType);
|
|
305
|
+
if (result) {
|
|
306
|
+
const system = format.startsWith("commonjs") ? "commonjs" : "module";
|
|
307
|
+
out[key] = {
|
|
308
|
+
source: result.code,
|
|
309
|
+
format: result.moduleType === "ts" ? `${system}-typescript` : system
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return out;
|
|
314
|
+
}
|
|
315
|
+
function _flattenPlugins(plugins, path) {
|
|
316
|
+
return plugins.flatMap((plugin, index) => {
|
|
317
|
+
const at = `${path}[${index}]`;
|
|
318
|
+
return Array.isArray(plugin) ? _flattenPlugins(plugin, at) : plugin ? [[plugin, at]] : [];
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
const HOOK_KINDS = [
|
|
322
|
+
"resolveId",
|
|
323
|
+
"load",
|
|
324
|
+
"transform"
|
|
325
|
+
];
|
|
326
|
+
function _normalizePlugin(plugin, path) {
|
|
327
|
+
const fail = (reason) => {
|
|
328
|
+
throw new TypeError(`[env-runner] \`plugins${path}\` ${reason}: expected a plugin object with \`resolveId\`, \`load\` or \`transform\` hooks, each a function or \`{ order?, filter?, handler }\`.`);
|
|
329
|
+
};
|
|
330
|
+
if (typeof plugin !== "object") return fail("is not a plugin object");
|
|
331
|
+
const { name: pluginName, enforce } = plugin;
|
|
332
|
+
const name = typeof pluginName === "string" ? pluginName : `plugins${path}`;
|
|
333
|
+
if (enforce != null && enforce !== "pre" && enforce !== "post") return fail(`has an invalid \`enforce\` (${JSON.stringify(enforce)})`);
|
|
334
|
+
const normalized = {
|
|
335
|
+
name,
|
|
336
|
+
enforce: enforce ?? "normal"
|
|
337
|
+
};
|
|
338
|
+
for (const kind of HOOK_KINDS) {
|
|
339
|
+
const hook = plugin[kind];
|
|
340
|
+
if (hook != null) normalized[kind] = _normalizeHook(kind, hook, name, path, fail);
|
|
341
|
+
}
|
|
342
|
+
return normalized;
|
|
343
|
+
}
|
|
344
|
+
function _normalizeHook(kind, hook, name, path, fail) {
|
|
345
|
+
const failFilter = (key, reason) => {
|
|
346
|
+
throw new TypeError(`[env-runner] \`plugins${path}\` has an invalid \`${kind}.filter${key}\` ${reason}.`);
|
|
347
|
+
};
|
|
348
|
+
let order = "normal";
|
|
349
|
+
let filter;
|
|
350
|
+
let fallback = false;
|
|
351
|
+
let handler;
|
|
352
|
+
if (typeof hook === "function") handler = hook;
|
|
353
|
+
else if (hook && typeof hook === "object" && typeof hook.handler === "function") {
|
|
354
|
+
const object = hook;
|
|
355
|
+
if (object.order != null && object.order !== "pre" && object.order !== "post") return fail(`has an invalid \`${kind}.order\` (${JSON.stringify(object.order)})`);
|
|
356
|
+
if (object.fallback != null && object.fallback !== false) {
|
|
357
|
+
if (kind !== "resolveId") return fail(`has a \`${kind}.fallback\` (only \`resolveId\` hooks take one)`);
|
|
358
|
+
if (object.fallback !== true) return fail(`has an invalid \`${kind}.fallback\` (${_describe(object.fallback)})`);
|
|
359
|
+
fallback = true;
|
|
360
|
+
}
|
|
361
|
+
order = object.order ?? "normal";
|
|
362
|
+
filter = object.filter;
|
|
363
|
+
handler = object.handler;
|
|
364
|
+
} else return fail(`has an invalid \`${kind}\` hook (got ${_describe(hook)})`);
|
|
365
|
+
const flags = {
|
|
366
|
+
...kind === "load" ? { load: true } : {},
|
|
367
|
+
...fallback && { fallback: true }
|
|
368
|
+
};
|
|
369
|
+
if (Array.isArray(filter)) {
|
|
370
|
+
const expr = _normalizeExpressions(filter, kind, failFilter);
|
|
371
|
+
const test = compileFilterExpressions(expr);
|
|
372
|
+
const prefilter = {
|
|
373
|
+
expr,
|
|
374
|
+
...flags
|
|
375
|
+
};
|
|
376
|
+
const level = compilePrefilter(prefilter);
|
|
377
|
+
return {
|
|
378
|
+
name,
|
|
379
|
+
order,
|
|
380
|
+
prefilter,
|
|
381
|
+
fallback,
|
|
382
|
+
match: (id, moduleType, code, resolved) => test(id, moduleType, code) !== false && level(id, moduleType, resolved, code),
|
|
383
|
+
handler
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const keys = kind === "transform" ? "`{ id?, code?, moduleType? }`" : "`{ id? }`";
|
|
387
|
+
if (filter != null && typeof filter !== "object") return failFilter("", `(got ${_describe(filter)}): expected ${keys} or an array of filter expressions`);
|
|
388
|
+
const { id: idValue, code: codeValue, moduleType: moduleTypeValue } = filter ?? {};
|
|
389
|
+
if (kind !== "transform") {
|
|
390
|
+
for (const [key, value] of [["code", codeValue], ["moduleType", moduleTypeValue]]) if (value) failFilter(`.${key}`, `(\`${kind}\` filters take \`id\` only)`);
|
|
391
|
+
}
|
|
392
|
+
const idPatterns = _stringFilter(idValue, ".id", failFilter);
|
|
393
|
+
const toPattern = (pattern) => _idPattern(pattern, kind !== "resolveId");
|
|
394
|
+
const id = idPatterns && {
|
|
395
|
+
include: idPatterns.include.map(toPattern),
|
|
396
|
+
exclude: idPatterns.exclude.map(toPattern)
|
|
397
|
+
};
|
|
398
|
+
const codePatterns = _stringFilter(codeValue, ".code", failFilter);
|
|
399
|
+
const code = codePatterns && compileFilter(codePatterns.include.map(_codePattern), codePatterns.exclude.map(_codePattern), _matchCode);
|
|
400
|
+
const prefilter = {
|
|
401
|
+
id,
|
|
402
|
+
moduleTypes: _moduleTypes(moduleTypeValue, failFilter),
|
|
403
|
+
...flags
|
|
404
|
+
};
|
|
405
|
+
const level = compilePrefilter(prefilter);
|
|
406
|
+
return {
|
|
407
|
+
name,
|
|
408
|
+
order,
|
|
409
|
+
prefilter,
|
|
410
|
+
fallback,
|
|
411
|
+
match: (idValue, moduleType, codeValue, resolved) => (codeValue === void 0 || !code || code.test(codeValue)) && level(idValue, moduleType, resolved),
|
|
412
|
+
handler
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
const _isPattern = (value) => typeof value === "string" || value instanceof RegExp;
|
|
416
|
+
function _stringFilter(filter, key, fail) {
|
|
417
|
+
if (!filter) return;
|
|
418
|
+
const toList = (value) => {
|
|
419
|
+
const list = value ? Array.isArray(value) ? value : [value] : [];
|
|
420
|
+
const invalid = list.find((pattern) => !_isPattern(pattern));
|
|
421
|
+
if (invalid !== void 0) fail(key, `(got ${_describe(invalid)}): expected strings or RegExps, as a value, an array or \`{ include, exclude }\``);
|
|
422
|
+
return list;
|
|
423
|
+
};
|
|
424
|
+
if (typeof filter === "object" && !Array.isArray(filter) && !(filter instanceof RegExp)) {
|
|
425
|
+
const { include, exclude } = filter;
|
|
426
|
+
return {
|
|
427
|
+
include: toList(include),
|
|
428
|
+
exclude: toList(exclude)
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
include: toList(filter),
|
|
433
|
+
exclude: []
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function _moduleTypes(filter, fail) {
|
|
437
|
+
if (!filter) return;
|
|
438
|
+
const list = Array.isArray(filter) ? filter : typeof filter === "object" ? filter.include ?? [] : void 0;
|
|
439
|
+
if (!Array.isArray(list) || list.some((type) => typeof type !== "string")) return fail(".moduleType", `(got ${_describe(filter)}): expected an array of module types or \`{ include: [...] }\``);
|
|
440
|
+
if (list.length === 0) return fail(".moduleType", "(no module types): list at least one, or leave it out");
|
|
441
|
+
return list;
|
|
442
|
+
}
|
|
443
|
+
function _idPattern(pattern, resolve = true) {
|
|
444
|
+
return typeof pattern === "string" ? {
|
|
445
|
+
source: globToRegExp(resolve ? resolveGlob(pattern) : pattern).source,
|
|
446
|
+
flags: "",
|
|
447
|
+
glob: true
|
|
448
|
+
} : {
|
|
449
|
+
source: pattern.source,
|
|
450
|
+
flags: _statelessFlags(pattern)
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function _codePattern(pattern) {
|
|
454
|
+
return typeof pattern === "string" ? pattern : new RegExp(pattern.source, _statelessFlags(pattern));
|
|
455
|
+
}
|
|
456
|
+
function _statelessFlags(pattern) {
|
|
457
|
+
return pattern.flags.replace(/[gy]/g, "");
|
|
458
|
+
}
|
|
459
|
+
function _normalizeExpressions(list, kind, fail) {
|
|
460
|
+
return list.map((value, index) => {
|
|
461
|
+
if (value?.kind !== "include" && value?.kind !== "exclude") return fail(`[${index}]`, `(got ${_describe(value?.kind ?? value)}): expected an \`include\` or \`exclude\` expression`);
|
|
462
|
+
return {
|
|
463
|
+
kind: value.kind,
|
|
464
|
+
expr: _normalizeNode(value.expr, `[${index}].expr`, kind, fail)
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function _normalizeNode(node, key, hook, fail) {
|
|
469
|
+
const pattern = (allowed, expected) => {
|
|
470
|
+
if (!allowed(node.pattern)) fail(`${key}.pattern`, `(got ${_describe(node.pattern)}): expected ${expected}`);
|
|
471
|
+
return node.pattern;
|
|
472
|
+
};
|
|
473
|
+
switch (node?.kind) {
|
|
474
|
+
case "and":
|
|
475
|
+
case "or":
|
|
476
|
+
if (!Array.isArray(node.args) || node.args.length === 0) return fail(key, `(\`${node.kind}\` needs at least one argument)`);
|
|
477
|
+
return {
|
|
478
|
+
kind: node.kind,
|
|
479
|
+
args: node.args.map((arg, index) => _normalizeNode(arg, `${key}.args[${index}]`, hook, fail))
|
|
480
|
+
};
|
|
481
|
+
case "not": return {
|
|
482
|
+
kind: "not",
|
|
483
|
+
expr: _normalizeNode(node.expr, `${key}.expr`, hook, fail)
|
|
484
|
+
};
|
|
485
|
+
case "id": return {
|
|
486
|
+
kind: "id",
|
|
487
|
+
pattern: _idPattern(pattern(_isPattern, "a string or RegExp"), hook !== "resolveId")
|
|
488
|
+
};
|
|
489
|
+
case "code": {
|
|
490
|
+
if (hook !== "transform") return fail(key, `(\`code\` doesn't apply to \`${hook}\`)`);
|
|
491
|
+
const value = _codePattern(pattern(_isPattern, "a string or RegExp"));
|
|
492
|
+
return {
|
|
493
|
+
kind: "code",
|
|
494
|
+
pattern: typeof value === "string" ? value : {
|
|
495
|
+
source: value.source,
|
|
496
|
+
flags: value.flags
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
case "moduleType":
|
|
501
|
+
if (hook !== "transform") return fail(key, `(\`moduleType\` doesn't apply to \`${hook}\`)`);
|
|
502
|
+
return {
|
|
503
|
+
kind: "moduleType",
|
|
504
|
+
pattern: pattern((value) => typeof value === "string", "a string")
|
|
505
|
+
};
|
|
506
|
+
case "query": {
|
|
507
|
+
if (typeof node.key !== "string") return fail(`${key}.key`, `(got ${_describe(node.key)}): expected a string`);
|
|
508
|
+
const value = pattern((value) => _isPattern(value) || typeof value === "boolean", "a string, RegExp or boolean");
|
|
509
|
+
return {
|
|
510
|
+
kind: "query",
|
|
511
|
+
key: node.key,
|
|
512
|
+
pattern: value instanceof RegExp ? {
|
|
513
|
+
source: value.source,
|
|
514
|
+
flags: _statelessFlags(value)
|
|
515
|
+
} : value
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
case "importerId": return fail(key, `(\`importerId\` isn't supported)`);
|
|
519
|
+
default: return fail(key, `(got ${_describe(node?.kind ?? node)}): unknown expression kind`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function _describe(value) {
|
|
523
|
+
if (value instanceof RegExp) return String(value);
|
|
524
|
+
if (Array.isArray(value)) return "an array";
|
|
525
|
+
if (value && typeof value === "object") {
|
|
526
|
+
const name = value.constructor?.name;
|
|
527
|
+
return name && name !== "Object" ? name : "an object";
|
|
528
|
+
}
|
|
529
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
530
|
+
}
|
|
531
|
+
function _createContext(name, id, code, resolve) {
|
|
532
|
+
const format = (log, pos) => typeof log === "string" ? `[env-runner] plugin "${name}" (${id}${_formatPosition(code, pos)}): ${log}` : `[env-runner] plugin "${name}" (${id}${_formatPosition(code, pos ?? _logPosition(log, id, code))}): ${log?.message}${_frame(log)}`;
|
|
533
|
+
return {
|
|
534
|
+
warn: (log, pos) => console.warn(format(log, pos)),
|
|
535
|
+
info: (log, pos) => console.info(format(log, pos)),
|
|
536
|
+
debug: () => {},
|
|
537
|
+
error: (log, pos) => {
|
|
538
|
+
throw new Error(format(log, pos), typeof log === "string" ? void 0 : { cause: log });
|
|
539
|
+
},
|
|
540
|
+
resolve,
|
|
541
|
+
addWatchFile: () => {},
|
|
542
|
+
getWatchFiles: () => [],
|
|
543
|
+
meta: { watchMode: false }
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function _formatPosition(code, pos) {
|
|
547
|
+
if (typeof pos === "number") {
|
|
548
|
+
const before = code.slice(0, pos);
|
|
549
|
+
return `:${before.split("\n").length}:${pos - before.lastIndexOf("\n") - 1}`;
|
|
550
|
+
}
|
|
551
|
+
return pos && typeof pos === "object" ? `:${pos.line}:${pos.column}` : "";
|
|
552
|
+
}
|
|
553
|
+
function _matchCode(pattern, code) {
|
|
554
|
+
return typeof pattern === "string" ? code.includes(pattern) : pattern.test(code);
|
|
555
|
+
}
|
|
556
|
+
function _parseMap(map) {
|
|
557
|
+
if (typeof map === "string") try {
|
|
558
|
+
return JSON.parse(map);
|
|
559
|
+
} catch {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
return map ?? void 0;
|
|
563
|
+
}
|
|
564
|
+
const _warnedMaps = /* @__PURE__ */ new Set();
|
|
565
|
+
function _warnDroppedMap(first, second) {
|
|
566
|
+
const key = `${first}\0${second}`;
|
|
567
|
+
if (!_warnedMaps.has(key)) {
|
|
568
|
+
_warnedMaps.add(key);
|
|
569
|
+
console.warn(`[env-runner] plugins "${first}" and "${second}" both returned a source map; maps are not combined, so modules both change have none.`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
14
572
|
var BaseEnvRunner = class {
|
|
15
573
|
closed = false;
|
|
16
574
|
_name;
|
|
@@ -26,10 +584,13 @@ var BaseEnvRunner = class {
|
|
|
26
584
|
_virtualUpdates = Promise.resolve();
|
|
27
585
|
#virtualUpdateId = 0;
|
|
28
586
|
_processData;
|
|
587
|
+
_plugins;
|
|
588
|
+
_transformChannel;
|
|
29
589
|
constructor(opts) {
|
|
30
590
|
this._name = opts.name;
|
|
31
591
|
this._workerEntry = opts.workerEntry;
|
|
32
592
|
this._data = opts.data;
|
|
593
|
+
this._plugins = createPluginPipeline(opts.plugins, { resolveConditions: () => this._resolveConditions() });
|
|
33
594
|
this._hooks = opts.hooks || {};
|
|
34
595
|
this._messageListeners = /* @__PURE__ */ new Set();
|
|
35
596
|
this._pendingRequests = /* @__PURE__ */ new Set();
|
|
@@ -129,6 +690,8 @@ var BaseEnvRunner = class {
|
|
|
129
690
|
const onError = (error) => console.error(error);
|
|
130
691
|
await this._closeRuntime().catch(onError);
|
|
131
692
|
await this._closeSocket().catch(onError);
|
|
693
|
+
this._transformChannel?.close();
|
|
694
|
+
this._transformChannel = void 0;
|
|
132
695
|
}
|
|
133
696
|
async [Symbol.asyncDispose]() {
|
|
134
697
|
await this.close();
|
|
@@ -153,18 +716,33 @@ var BaseEnvRunner = class {
|
|
|
153
716
|
for (const listener of this._messageListeners) listener(message);
|
|
154
717
|
}
|
|
155
718
|
_processEnv() {
|
|
156
|
-
|
|
719
|
+
let data = this._data || {};
|
|
157
720
|
const virtual = data.virtual;
|
|
721
|
+
if (virtual) data = {
|
|
722
|
+
...data,
|
|
723
|
+
virtual: encodeVirtualModules(virtual)
|
|
724
|
+
};
|
|
725
|
+
if (this._plugins) data = {
|
|
726
|
+
...data,
|
|
727
|
+
...this._pluginWorkerData("socket")
|
|
728
|
+
};
|
|
158
729
|
try {
|
|
159
|
-
this._processData = JSON.stringify(
|
|
160
|
-
...data,
|
|
161
|
-
virtual: encodeVirtualModules(virtual)
|
|
162
|
-
} : data);
|
|
730
|
+
this._processData = JSON.stringify(data);
|
|
163
731
|
} catch (error) {
|
|
164
732
|
throw new TypeError(`Runner data must be JSON-serializable: ${error?.message || error}`, { cause: error });
|
|
165
733
|
}
|
|
166
734
|
return hostEnv({ ENV_RUNNER_NAME: this._name });
|
|
167
735
|
}
|
|
736
|
+
_resolveConditions() {}
|
|
737
|
+
_pluginWorkerData(kind) {
|
|
738
|
+
if (!this._plugins) return {};
|
|
739
|
+
this._transformChannel ??= kind === "port" ? openTransformPort(this._plugins) : openTransformSocket(this._plugins);
|
|
740
|
+
return { [PLUGINS_DATA_KEY]: {
|
|
741
|
+
prefilters: this._plugins.prefilters,
|
|
742
|
+
resolvePrefilters: this._plugins.resolvePrefilters,
|
|
743
|
+
...this._transformChannel.channel
|
|
744
|
+
} };
|
|
745
|
+
}
|
|
168
746
|
_handleProcessMessage(message) {
|
|
169
747
|
if (message?.event !== "request-init-data") {
|
|
170
748
|
this._handleMessage(message);
|
|
@@ -221,6 +799,16 @@ var BaseEnvRunner = class {
|
|
|
221
799
|
this._data = { ...this._data };
|
|
222
800
|
warnVirtualPathCollisions(Object.keys(virtual ?? {}));
|
|
223
801
|
if (!virtual) return;
|
|
802
|
+
const plugins = this._plugins;
|
|
803
|
+
if (plugins) {
|
|
804
|
+
this._virtualResolved = resolveVirtualModules(virtual).then((resolved) => transformVirtualModules(plugins, resolved)).then((transformed) => {
|
|
805
|
+
this._data = {
|
|
806
|
+
...this._data,
|
|
807
|
+
virtual: transformed
|
|
808
|
+
};
|
|
809
|
+
});
|
|
810
|
+
return this._virtualResolved;
|
|
811
|
+
}
|
|
224
812
|
if (!Object.values(virtual).some((v) => typeof v === "function")) try {
|
|
225
813
|
this._data.virtual = normalizeVirtualModules(virtual);
|
|
226
814
|
return;
|
|
@@ -243,7 +831,8 @@ var BaseEnvRunner = class {
|
|
|
243
831
|
const entries = Object.entries(changes()).filter(([, source]) => source !== void 0);
|
|
244
832
|
if (entries.length === 0) return;
|
|
245
833
|
const sets = Object.fromEntries(entries.filter((entry) => entry[1] !== null));
|
|
246
|
-
|
|
834
|
+
let resolved = await resolveVirtualModules(sets);
|
|
835
|
+
if (this._plugins) resolved = await transformVirtualModules(this._plugins, resolved);
|
|
247
836
|
const sources = this._virtualSources ??= {};
|
|
248
837
|
const virtual = (this._data ??= {}).virtual ??= {};
|
|
249
838
|
let added = false;
|