@econ-v1/app-sdk 7.4.0 → 7.4.2
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/dist/burger-build/aliases.d.ts +19 -1
- package/dist/burger-build/cli.js +248 -137
- package/dist/burger-build/gate.d.ts +2 -0
- package/dist/burger-build/index.js +248 -137
- package/dist/burger-build/test-prepare.d.ts +8 -1
- package/dist/burger-types/globals.d.ts +45 -0
- package/dist/burger-types/modules.d.ts +99 -3
- package/package.json +1 -1
|
@@ -14,8 +14,26 @@ export declare const ALIASES: ReadonlyMap<string, BurgerModule>;
|
|
|
14
14
|
* (`ws`, `undici`) that apps legitimately depend on.
|
|
15
15
|
*/
|
|
16
16
|
export declare const NODE_BUILTINS: ReadonlySet<string>;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Named exports of each `burger:*` module (C4, C6). Used to bridge CommonJS
|
|
19
|
+
* `require()`.
|
|
20
|
+
*
|
|
21
|
+
* DATA-APP PACK: `realpathSync`, `copyFileSync`, `symlinkSync`, `openSync`,
|
|
22
|
+
* `writeSync`, `fsyncSync`, `fdatasyncSync`, `closeSync`, `Dirent` and
|
|
23
|
+
* `constants` on `burger:fs` ship with the data-app pack
|
|
24
|
+
* (econ-v1/node-app-burger#12), not Phase 1. They are listed here so the
|
|
25
|
+
* build-time gate accepts them ahead of a runtime that provides them; an app
|
|
26
|
+
* using them must depend on that node-app-burger release. `readSync`,
|
|
27
|
+
* `fstatSync` and `utimesSync` arrive with the second data-app pack (asked
|
|
28
|
+
* for by the node-app-memory flip, econ-v1/node-app-memory#40).
|
|
29
|
+
*/
|
|
18
30
|
export declare const BURGER_EXPORTS: Readonly<Record<BurgerModule, readonly string[]>>;
|
|
31
|
+
/**
|
|
32
|
+
* `burger:*` modules with a `default` export (C6): every module except
|
|
33
|
+
* `burger:host` and `burger:test` (verified against the runtime JS in
|
|
34
|
+
* node-app-burger). `import x from "burger:host"` fails to link.
|
|
35
|
+
*/
|
|
36
|
+
export declare const BURGER_DEFAULT_EXPORT: Readonly<Partial<Record<BurgerModule, true>>>;
|
|
19
37
|
export type SpecifierClass = {
|
|
20
38
|
kind: "burger";
|
|
21
39
|
target: BurgerModule;
|
package/dist/burger-build/cli.js
CHANGED
|
@@ -20,134 +20,6 @@ function assertSupportedBun(version = Bun.version) {
|
|
|
20
20
|
// ../burger-build/src/gate.ts
|
|
21
21
|
import { readFileSync } from "fs";
|
|
22
22
|
import { extname, isAbsolute, relative, resolve } from "path";
|
|
23
|
-
var FS_SPECIFIERS = new Set([
|
|
24
|
-
"fs",
|
|
25
|
-
"node:fs",
|
|
26
|
-
"fs/promises",
|
|
27
|
-
"node:fs/promises",
|
|
28
|
-
"burger:fs",
|
|
29
|
-
"burger:fs/promises"
|
|
30
|
-
]);
|
|
31
|
-
var BUN_GLOBAL = /(?<![\w$.'"`])Bun\s*\.\s*[A-Za-z_$]|\bglobalThis\s*\.\s*Bun\b/;
|
|
32
|
-
var IMPORT_META_PATH = /\bimport\.meta\.(?:url|dir|dirname|filename|path)\b/;
|
|
33
|
-
var NATIVE_LOADER_PACKAGE = /[\\/]node_modules[\\/](?:bindings|node-gyp-build)[\\/]/;
|
|
34
|
-
function metafileKeyToPath(key, cwd) {
|
|
35
|
-
if (isAbsolute(key))
|
|
36
|
-
return key;
|
|
37
|
-
const colon = key.indexOf(":");
|
|
38
|
-
const slash = key.indexOf("/");
|
|
39
|
-
if (colon > 0 && (slash === -1 || colon < slash))
|
|
40
|
-
return key;
|
|
41
|
-
return resolve(cwd, key);
|
|
42
|
-
}
|
|
43
|
-
function importerGraph(metafile, cwd) {
|
|
44
|
-
const parents = new Map;
|
|
45
|
-
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
46
|
-
const importer = metafileKeyToPath(key, cwd);
|
|
47
|
-
for (const record of input.imports) {
|
|
48
|
-
if (record.external)
|
|
49
|
-
continue;
|
|
50
|
-
const child = metafileKeyToPath(record.path, cwd);
|
|
51
|
-
if (child !== importer && !parents.has(child)) {
|
|
52
|
-
parents.set(child, importer);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return parents;
|
|
57
|
-
}
|
|
58
|
-
function importerChain(file, parents) {
|
|
59
|
-
const chain = [file];
|
|
60
|
-
const seen = new Set(chain);
|
|
61
|
-
let current = parents.get(file);
|
|
62
|
-
while (current !== undefined && !seen.has(current)) {
|
|
63
|
-
chain.unshift(current);
|
|
64
|
-
seen.add(current);
|
|
65
|
-
current = parents.get(current);
|
|
66
|
-
}
|
|
67
|
-
return chain;
|
|
68
|
-
}
|
|
69
|
-
function loaderFor(file) {
|
|
70
|
-
switch (extname(file)) {
|
|
71
|
-
case ".ts":
|
|
72
|
-
case ".mts":
|
|
73
|
-
case ".cts":
|
|
74
|
-
return "ts";
|
|
75
|
-
case ".tsx":
|
|
76
|
-
return "tsx";
|
|
77
|
-
case ".jsx":
|
|
78
|
-
return "jsx";
|
|
79
|
-
case ".js":
|
|
80
|
-
case ".mjs":
|
|
81
|
-
case ".cjs":
|
|
82
|
-
return "js";
|
|
83
|
-
default:
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function codeOf(file, source) {
|
|
88
|
-
const loader = loaderFor(file);
|
|
89
|
-
if (!loader)
|
|
90
|
-
return;
|
|
91
|
-
try {
|
|
92
|
-
return new Bun.Transpiler({ loader }).transformSync(source);
|
|
93
|
-
} catch {
|
|
94
|
-
return source;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function scanModule(file, code, importedSpecifiers) {
|
|
98
|
-
const messages = [];
|
|
99
|
-
if (BUN_GLOBAL.test(code)) {
|
|
100
|
-
messages.push("uses the Bun global (Bun.*), which does not exist in Burger");
|
|
101
|
-
}
|
|
102
|
-
if (IMPORT_META_PATH.test(code) && importedSpecifiers.some((specifier) => FS_SPECIFIERS.has(specifier))) {
|
|
103
|
-
messages.push("reads files relative to import.meta; bundling moves this module, so the files are not found at runtime \u2014 import the data statically instead");
|
|
104
|
-
}
|
|
105
|
-
if (NATIVE_LOADER_PACKAGE.test(file)) {
|
|
106
|
-
messages.push("loads a native addon (bindings/node-gyp-build), which Burger cannot run");
|
|
107
|
-
}
|
|
108
|
-
return messages;
|
|
109
|
-
}
|
|
110
|
-
function collectProblems(metafile, violations, cwd) {
|
|
111
|
-
const parents = importerGraph(metafile, cwd);
|
|
112
|
-
const problems = [];
|
|
113
|
-
for (const violation of violations) {
|
|
114
|
-
problems.push({
|
|
115
|
-
message: `import "${violation.specifier}": ${violation.reason}`,
|
|
116
|
-
chain: importerChain(violation.importer, parents)
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
120
|
-
const file = metafileKeyToPath(key, cwd);
|
|
121
|
-
if (!isAbsolute(file))
|
|
122
|
-
continue;
|
|
123
|
-
let source;
|
|
124
|
-
try {
|
|
125
|
-
source = readFileSync(file, "utf8");
|
|
126
|
-
} catch {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const code = codeOf(file, source);
|
|
130
|
-
if (code === undefined)
|
|
131
|
-
continue;
|
|
132
|
-
const specifiers = input.imports.flatMap((record) => record.original === undefined ? [record.path] : [record.path, record.original]);
|
|
133
|
-
for (const message of scanModule(file, code, specifiers)) {
|
|
134
|
-
problems.push({ message, chain: importerChain(file, parents) });
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return problems;
|
|
138
|
-
}
|
|
139
|
-
function formatProblems(problems, cwd) {
|
|
140
|
-
const lines = [`burger-build: ${problems.length} problem(s) \u2014 this code cannot run on Burger:`];
|
|
141
|
-
for (const problem of problems) {
|
|
142
|
-
lines.push(` \u2717 ${problem.message}`);
|
|
143
|
-
problem.chain.forEach((file, index) => {
|
|
144
|
-
const shown = isAbsolute(file) ? relative(cwd, file) : file;
|
|
145
|
-
lines.push(index === 0 ? ` ${shown}` : ` \u2192 ${shown}`);
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
return lines.join(`
|
|
149
|
-
`);
|
|
150
|
-
}
|
|
151
23
|
|
|
152
24
|
// ../burger-build/src/aliases.ts
|
|
153
25
|
var BURGER_MODULES = [
|
|
@@ -265,7 +137,20 @@ var BURGER_EXPORTS = {
|
|
|
265
137
|
"chmodSync",
|
|
266
138
|
"unlinkSync",
|
|
267
139
|
"mkdtempSync",
|
|
268
|
-
"promises"
|
|
140
|
+
"promises",
|
|
141
|
+
"realpathSync",
|
|
142
|
+
"copyFileSync",
|
|
143
|
+
"symlinkSync",
|
|
144
|
+
"openSync",
|
|
145
|
+
"writeSync",
|
|
146
|
+
"fsyncSync",
|
|
147
|
+
"fdatasyncSync",
|
|
148
|
+
"closeSync",
|
|
149
|
+
"Dirent",
|
|
150
|
+
"constants",
|
|
151
|
+
"readSync",
|
|
152
|
+
"fstatSync",
|
|
153
|
+
"utimesSync"
|
|
269
154
|
],
|
|
270
155
|
"burger:fs/promises": [
|
|
271
156
|
"exists",
|
|
@@ -313,6 +198,16 @@ var BURGER_EXPORTS = {
|
|
|
313
198
|
"setDefaultTimeout"
|
|
314
199
|
]
|
|
315
200
|
};
|
|
201
|
+
var BURGER_DEFAULT_EXPORT = {
|
|
202
|
+
"burger:fs": true,
|
|
203
|
+
"burger:fs/promises": true,
|
|
204
|
+
"burger:path": true,
|
|
205
|
+
"burger:os": true,
|
|
206
|
+
"burger:worker_threads": true,
|
|
207
|
+
"burger:crypto": true,
|
|
208
|
+
"burger:buffer": true,
|
|
209
|
+
"burger:sqlite": true
|
|
210
|
+
};
|
|
316
211
|
var BURGER_MODULE_SET = new Set(BURGER_MODULES);
|
|
317
212
|
function classifySpecifier(specifier) {
|
|
318
213
|
if (BURGER_MODULE_SET.has(specifier)) {
|
|
@@ -340,6 +235,191 @@ function classifySpecifier(specifier) {
|
|
|
340
235
|
return { kind: "other" };
|
|
341
236
|
}
|
|
342
237
|
|
|
238
|
+
// ../burger-build/src/gate.ts
|
|
239
|
+
var FS_SPECIFIERS = new Set([
|
|
240
|
+
"fs",
|
|
241
|
+
"node:fs",
|
|
242
|
+
"fs/promises",
|
|
243
|
+
"node:fs/promises",
|
|
244
|
+
"burger:fs",
|
|
245
|
+
"burger:fs/promises"
|
|
246
|
+
]);
|
|
247
|
+
var BUN_GLOBAL = /(?<![\w$.'"`])Bun\s*\.\s*[A-Za-z_$]|\bglobalThis\s*\.\s*Bun\b/;
|
|
248
|
+
var IMPORT_META_PATH = /\bimport\.meta\.(?:url|dir|dirname|filename|path)\b/;
|
|
249
|
+
var IMPORT_OR_REEXPORT = /\b(?:import|export)\s+([^;]+?)\s+from\s*["']([^"']+)["']/g;
|
|
250
|
+
function parseNamedList(braced, into) {
|
|
251
|
+
for (const rawItem of braced.replace(/^\{|\}$/g, "").split(",")) {
|
|
252
|
+
const item = rawItem.trim();
|
|
253
|
+
if (item === "" || item.startsWith("type "))
|
|
254
|
+
continue;
|
|
255
|
+
const asMatch = /^([\w$]+|default)\s+as\s+[\w$]+$/.exec(item);
|
|
256
|
+
if (asMatch)
|
|
257
|
+
into.push(asMatch[1]);
|
|
258
|
+
else if (/^[\w$]+$/.test(item) || item === "default")
|
|
259
|
+
into.push(item);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function parseClause(raw) {
|
|
263
|
+
const clause = raw.trim();
|
|
264
|
+
const result = { named: [] };
|
|
265
|
+
if (clause.startsWith("type ") || clause.startsWith("*"))
|
|
266
|
+
return result;
|
|
267
|
+
if (clause.startsWith("{")) {
|
|
268
|
+
parseNamedList(clause, result.named);
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
const match = /^([\w$]+)\s*(?:,\s*([\s\S]+))?$/.exec(clause);
|
|
272
|
+
if (!match)
|
|
273
|
+
return result;
|
|
274
|
+
result.named.push("default");
|
|
275
|
+
const trailing = match[2]?.trim();
|
|
276
|
+
if (trailing?.startsWith("{"))
|
|
277
|
+
parseNamedList(trailing, result.named);
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
function missingExportMessage(target, name, specifier) {
|
|
281
|
+
return `"${target}" has no export "${name}" (imported as "${specifier}"); Burger provides: ${BURGER_EXPORTS[target].join(", ")}`;
|
|
282
|
+
}
|
|
283
|
+
function scanBurgerImports(code) {
|
|
284
|
+
const messages = [];
|
|
285
|
+
const reported = new Set;
|
|
286
|
+
for (const match of code.matchAll(IMPORT_OR_REEXPORT)) {
|
|
287
|
+
const specifier = match[2];
|
|
288
|
+
const specifierClass = classifySpecifier(specifier);
|
|
289
|
+
if (specifierClass.kind !== "burger")
|
|
290
|
+
continue;
|
|
291
|
+
const target = specifierClass.target;
|
|
292
|
+
for (const name of parseClause(match[1]).named) {
|
|
293
|
+
const provided = name === "default" ? target in BURGER_DEFAULT_EXPORT : BURGER_EXPORTS[target].includes(name);
|
|
294
|
+
const key = `${target}\x00${name}\x00${specifier}`;
|
|
295
|
+
if (provided || reported.has(key))
|
|
296
|
+
continue;
|
|
297
|
+
reported.add(key);
|
|
298
|
+
messages.push(missingExportMessage(target, name, specifier));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return messages;
|
|
302
|
+
}
|
|
303
|
+
var NATIVE_LOADER_PACKAGE = /[\\/]node_modules[\\/](?:bindings|node-gyp-build)[\\/]/;
|
|
304
|
+
function metafileKeyToPath(key, cwd) {
|
|
305
|
+
if (isAbsolute(key))
|
|
306
|
+
return key;
|
|
307
|
+
const colon = key.indexOf(":");
|
|
308
|
+
const slash = key.indexOf("/");
|
|
309
|
+
if (colon > 0 && (slash === -1 || colon < slash))
|
|
310
|
+
return key;
|
|
311
|
+
return resolve(cwd, key);
|
|
312
|
+
}
|
|
313
|
+
function importerGraph(metafile, cwd) {
|
|
314
|
+
const parents = new Map;
|
|
315
|
+
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
316
|
+
const importer = metafileKeyToPath(key, cwd);
|
|
317
|
+
for (const record of input.imports) {
|
|
318
|
+
if (record.external)
|
|
319
|
+
continue;
|
|
320
|
+
const child = metafileKeyToPath(record.path, cwd);
|
|
321
|
+
if (child !== importer && !parents.has(child)) {
|
|
322
|
+
parents.set(child, importer);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return parents;
|
|
327
|
+
}
|
|
328
|
+
function importerChain(file, parents) {
|
|
329
|
+
const chain = [file];
|
|
330
|
+
const seen = new Set(chain);
|
|
331
|
+
let current = parents.get(file);
|
|
332
|
+
while (current !== undefined && !seen.has(current)) {
|
|
333
|
+
chain.unshift(current);
|
|
334
|
+
seen.add(current);
|
|
335
|
+
current = parents.get(current);
|
|
336
|
+
}
|
|
337
|
+
return chain;
|
|
338
|
+
}
|
|
339
|
+
function loaderFor(file) {
|
|
340
|
+
switch (extname(file)) {
|
|
341
|
+
case ".ts":
|
|
342
|
+
case ".mts":
|
|
343
|
+
case ".cts":
|
|
344
|
+
return "ts";
|
|
345
|
+
case ".tsx":
|
|
346
|
+
return "tsx";
|
|
347
|
+
case ".jsx":
|
|
348
|
+
return "jsx";
|
|
349
|
+
case ".js":
|
|
350
|
+
case ".mjs":
|
|
351
|
+
case ".cjs":
|
|
352
|
+
return "js";
|
|
353
|
+
default:
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function codeOf(file, source) {
|
|
358
|
+
const loader = loaderFor(file);
|
|
359
|
+
if (!loader)
|
|
360
|
+
return;
|
|
361
|
+
try {
|
|
362
|
+
return new Bun.Transpiler({ loader }).transformSync(source);
|
|
363
|
+
} catch {
|
|
364
|
+
return source;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function scanModule(file, code, importedSpecifiers) {
|
|
368
|
+
const messages = [];
|
|
369
|
+
if (BUN_GLOBAL.test(code)) {
|
|
370
|
+
messages.push("uses the Bun global (Bun.*), which does not exist in Burger");
|
|
371
|
+
}
|
|
372
|
+
if (IMPORT_META_PATH.test(code) && importedSpecifiers.some((specifier) => FS_SPECIFIERS.has(specifier))) {
|
|
373
|
+
messages.push("reads files relative to import.meta; bundling moves this module, so the files are not found at runtime \u2014 import the data statically instead");
|
|
374
|
+
}
|
|
375
|
+
if (NATIVE_LOADER_PACKAGE.test(file)) {
|
|
376
|
+
messages.push("loads a native addon (bindings/node-gyp-build), which Burger cannot run");
|
|
377
|
+
}
|
|
378
|
+
messages.push(...scanBurgerImports(code));
|
|
379
|
+
return messages;
|
|
380
|
+
}
|
|
381
|
+
function collectProblems(metafile, violations, cwd) {
|
|
382
|
+
const parents = importerGraph(metafile, cwd);
|
|
383
|
+
const problems = [];
|
|
384
|
+
for (const violation of violations) {
|
|
385
|
+
problems.push({
|
|
386
|
+
message: `import "${violation.specifier}": ${violation.reason}`,
|
|
387
|
+
chain: importerChain(violation.importer, parents)
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
391
|
+
const file = metafileKeyToPath(key, cwd);
|
|
392
|
+
if (!isAbsolute(file))
|
|
393
|
+
continue;
|
|
394
|
+
let source;
|
|
395
|
+
try {
|
|
396
|
+
source = readFileSync(file, "utf8");
|
|
397
|
+
} catch {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const code = codeOf(file, source);
|
|
401
|
+
if (code === undefined)
|
|
402
|
+
continue;
|
|
403
|
+
const specifiers = input.imports.flatMap((record) => record.original === undefined ? [record.path] : [record.path, record.original]);
|
|
404
|
+
for (const message of scanModule(file, code, specifiers)) {
|
|
405
|
+
problems.push({ message, chain: importerChain(file, parents) });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return problems;
|
|
409
|
+
}
|
|
410
|
+
function formatProblems(problems, cwd) {
|
|
411
|
+
const lines = [`burger-build: ${problems.length} problem(s) \u2014 this code cannot run on Burger:`];
|
|
412
|
+
for (const problem of problems) {
|
|
413
|
+
lines.push(` \u2717 ${problem.message}`);
|
|
414
|
+
problem.chain.forEach((file, index) => {
|
|
415
|
+
const shown = isAbsolute(file) ? relative(cwd, file) : file;
|
|
416
|
+
lines.push(index === 0 ? ` ${shown}` : ` \u2192 ${shown}`);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
return lines.join(`
|
|
420
|
+
`);
|
|
421
|
+
}
|
|
422
|
+
|
|
343
423
|
// ../burger-build/src/plugin.ts
|
|
344
424
|
var BRIDGE_NAMESPACE = "burger-require";
|
|
345
425
|
var BRIDGE_PREFIX = "cjs-bridge/";
|
|
@@ -515,22 +595,36 @@ function relativeSpecifier(fromDir, to) {
|
|
|
515
595
|
const rel = relative2(fromDir, to).split(sep).join("/");
|
|
516
596
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
517
597
|
}
|
|
598
|
+
var JS_TO_TS_SUFFIXES = {
|
|
599
|
+
".js": [".ts", ".tsx"],
|
|
600
|
+
".jsx": [".tsx"],
|
|
601
|
+
".mjs": [".mts"],
|
|
602
|
+
".cjs": []
|
|
603
|
+
};
|
|
518
604
|
function resolveRelativeFile(importerDir, specifier) {
|
|
519
605
|
const base = resolve2(importerDir, specifier);
|
|
606
|
+
const isFile = (candidate) => existsSync(candidate) && statSync(candidate).isFile();
|
|
607
|
+
if (isFile(base))
|
|
608
|
+
return base;
|
|
609
|
+
const mapped = JS_TO_TS_SUFFIXES[extname2(specifier)];
|
|
610
|
+
if (mapped !== undefined) {
|
|
611
|
+
const stem = base.slice(0, base.length - extname2(specifier).length);
|
|
612
|
+
return mapped.map((suffix) => stem + suffix).find(isFile);
|
|
613
|
+
}
|
|
520
614
|
const candidates = [
|
|
521
|
-
base,
|
|
522
615
|
...RESOLVE_SUFFIXES.map((suffix) => base + suffix),
|
|
523
616
|
...RESOLVE_SUFFIXES.map((suffix) => join2(base, `index${suffix}`))
|
|
524
617
|
];
|
|
525
|
-
return candidates.find(
|
|
618
|
+
return candidates.find(isFile);
|
|
526
619
|
}
|
|
527
620
|
function dependencyFileName(specifier) {
|
|
528
621
|
return specifier.replace(/^@/, "").replace(/[\\/]/g, "__") + ".js";
|
|
529
622
|
}
|
|
623
|
+
var TEXT_NAMESPACE = "burger-text";
|
|
530
624
|
function rewriteSpecifier(ws, importer, specifier) {
|
|
531
625
|
const specifierClass = classifySpecifier(specifier);
|
|
532
626
|
if (specifierClass.kind === "burger")
|
|
533
|
-
return specifierClass.target;
|
|
627
|
+
return { external: specifierClass.target };
|
|
534
628
|
if (specifierClass.kind === "forbidden") {
|
|
535
629
|
ws.problems.push({ message: `import "${specifier}": ${specifierClass.reason}`, chain: [importer] });
|
|
536
630
|
return;
|
|
@@ -547,7 +641,14 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
547
641
|
return;
|
|
548
642
|
}
|
|
549
643
|
ws.jsonFiles.add(target);
|
|
550
|
-
return `${relativeSpecifier(dirname(importer), target)}.js
|
|
644
|
+
return { external: `${relativeSpecifier(dirname(importer), target)}.js` };
|
|
645
|
+
}
|
|
646
|
+
if (!isCodeFile(target)) {
|
|
647
|
+
if (!isInside(target, ws.root)) {
|
|
648
|
+
ws.problems.push({ message: `"${specifier}" is outside ${ws.root}`, chain: [importer] });
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
return { inline: target };
|
|
551
652
|
}
|
|
552
653
|
if (!ws.sources.has(target)) {
|
|
553
654
|
ws.problems.push({
|
|
@@ -556,7 +657,7 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
556
657
|
});
|
|
557
658
|
return;
|
|
558
659
|
}
|
|
559
|
-
return preparedPath(relativeSpecifier(dirname(importer), target));
|
|
660
|
+
return { external: preparedPath(relativeSpecifier(dirname(importer), target)) };
|
|
560
661
|
}
|
|
561
662
|
if (specifier.startsWith("#")) {
|
|
562
663
|
ws.problems.push({
|
|
@@ -566,7 +667,7 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
566
667
|
return;
|
|
567
668
|
}
|
|
568
669
|
ws.dependencies.add(specifier);
|
|
569
|
-
return specifier;
|
|
670
|
+
return { external: specifier };
|
|
570
671
|
}
|
|
571
672
|
function moduleIdentity(importer, specifier) {
|
|
572
673
|
const specifierClass = classifySpecifier(specifier);
|
|
@@ -610,8 +711,17 @@ function sourcesPlugin(ws) {
|
|
|
610
711
|
});
|
|
611
712
|
return { path: args.path, external: true };
|
|
612
713
|
}
|
|
613
|
-
|
|
714
|
+
const resolved = rewriteSpecifier(ws, args.importer, args.path);
|
|
715
|
+
if (resolved === undefined)
|
|
716
|
+
return { path: args.path, external: true };
|
|
717
|
+
if ("inline" in resolved)
|
|
718
|
+
return { path: resolved.inline, namespace: TEXT_NAMESPACE, external: false };
|
|
719
|
+
return { path: resolved.external, external: true };
|
|
614
720
|
});
|
|
721
|
+
build.onLoad({ filter: /.*/, namespace: TEXT_NAMESPACE }, (args) => ({
|
|
722
|
+
contents: readFileSync2(args.path, "utf8"),
|
|
723
|
+
loader: "text"
|
|
724
|
+
}));
|
|
615
725
|
}
|
|
616
726
|
};
|
|
617
727
|
}
|
|
@@ -736,7 +846,8 @@ async function prepareTests(options) {
|
|
|
736
846
|
const output = join2(out, preparedPath(relative2(root, file)));
|
|
737
847
|
const prepared = readFileSync2(output, "utf8").replace(MOCK_MODULE_CALL, (call, quote, specifier) => {
|
|
738
848
|
const rewritten = rewriteSpecifier(ws, file, specifier);
|
|
739
|
-
|
|
849
|
+
const replacement = rewritten === undefined ? undefined : ("external" in rewritten) ? rewritten.external : undefined;
|
|
850
|
+
return replacement === undefined ? call : call.replace(`${quote}${specifier}${quote}`, JSON.stringify(replacement));
|
|
740
851
|
});
|
|
741
852
|
writeFileSync2(output, prepared);
|
|
742
853
|
const source = readFileSync2(file, "utf8");
|
|
@@ -15,6 +15,8 @@ export interface Problem {
|
|
|
15
15
|
/** Entry point first, offending module last; absolute paths. */
|
|
16
16
|
chain: string[];
|
|
17
17
|
}
|
|
18
|
+
/** Problems from importing a name a `burger:*` module does not export. */
|
|
19
|
+
export declare function scanBurgerImports(code: string): string[];
|
|
18
20
|
/** Metafile keys are relative to the process cwd; namespaced keys (`ns:path`) are left as-is. */
|
|
19
21
|
export declare function metafileKeyToPath(key: string, cwd: string): string;
|
|
20
22
|
/** child → first importer, over resolved (non-external) imports. */
|
|
@@ -15,134 +15,6 @@ function assertSupportedBun(version = Bun.version) {
|
|
|
15
15
|
// ../burger-build/src/gate.ts
|
|
16
16
|
import { readFileSync } from "fs";
|
|
17
17
|
import { extname, isAbsolute, relative, resolve } from "path";
|
|
18
|
-
var FS_SPECIFIERS = new Set([
|
|
19
|
-
"fs",
|
|
20
|
-
"node:fs",
|
|
21
|
-
"fs/promises",
|
|
22
|
-
"node:fs/promises",
|
|
23
|
-
"burger:fs",
|
|
24
|
-
"burger:fs/promises"
|
|
25
|
-
]);
|
|
26
|
-
var BUN_GLOBAL = /(?<![\w$.'"`])Bun\s*\.\s*[A-Za-z_$]|\bglobalThis\s*\.\s*Bun\b/;
|
|
27
|
-
var IMPORT_META_PATH = /\bimport\.meta\.(?:url|dir|dirname|filename|path)\b/;
|
|
28
|
-
var NATIVE_LOADER_PACKAGE = /[\\/]node_modules[\\/](?:bindings|node-gyp-build)[\\/]/;
|
|
29
|
-
function metafileKeyToPath(key, cwd) {
|
|
30
|
-
if (isAbsolute(key))
|
|
31
|
-
return key;
|
|
32
|
-
const colon = key.indexOf(":");
|
|
33
|
-
const slash = key.indexOf("/");
|
|
34
|
-
if (colon > 0 && (slash === -1 || colon < slash))
|
|
35
|
-
return key;
|
|
36
|
-
return resolve(cwd, key);
|
|
37
|
-
}
|
|
38
|
-
function importerGraph(metafile, cwd) {
|
|
39
|
-
const parents = new Map;
|
|
40
|
-
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
41
|
-
const importer = metafileKeyToPath(key, cwd);
|
|
42
|
-
for (const record of input.imports) {
|
|
43
|
-
if (record.external)
|
|
44
|
-
continue;
|
|
45
|
-
const child = metafileKeyToPath(record.path, cwd);
|
|
46
|
-
if (child !== importer && !parents.has(child)) {
|
|
47
|
-
parents.set(child, importer);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return parents;
|
|
52
|
-
}
|
|
53
|
-
function importerChain(file, parents) {
|
|
54
|
-
const chain = [file];
|
|
55
|
-
const seen = new Set(chain);
|
|
56
|
-
let current = parents.get(file);
|
|
57
|
-
while (current !== undefined && !seen.has(current)) {
|
|
58
|
-
chain.unshift(current);
|
|
59
|
-
seen.add(current);
|
|
60
|
-
current = parents.get(current);
|
|
61
|
-
}
|
|
62
|
-
return chain;
|
|
63
|
-
}
|
|
64
|
-
function loaderFor(file) {
|
|
65
|
-
switch (extname(file)) {
|
|
66
|
-
case ".ts":
|
|
67
|
-
case ".mts":
|
|
68
|
-
case ".cts":
|
|
69
|
-
return "ts";
|
|
70
|
-
case ".tsx":
|
|
71
|
-
return "tsx";
|
|
72
|
-
case ".jsx":
|
|
73
|
-
return "jsx";
|
|
74
|
-
case ".js":
|
|
75
|
-
case ".mjs":
|
|
76
|
-
case ".cjs":
|
|
77
|
-
return "js";
|
|
78
|
-
default:
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function codeOf(file, source) {
|
|
83
|
-
const loader = loaderFor(file);
|
|
84
|
-
if (!loader)
|
|
85
|
-
return;
|
|
86
|
-
try {
|
|
87
|
-
return new Bun.Transpiler({ loader }).transformSync(source);
|
|
88
|
-
} catch {
|
|
89
|
-
return source;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function scanModule(file, code, importedSpecifiers) {
|
|
93
|
-
const messages = [];
|
|
94
|
-
if (BUN_GLOBAL.test(code)) {
|
|
95
|
-
messages.push("uses the Bun global (Bun.*), which does not exist in Burger");
|
|
96
|
-
}
|
|
97
|
-
if (IMPORT_META_PATH.test(code) && importedSpecifiers.some((specifier) => FS_SPECIFIERS.has(specifier))) {
|
|
98
|
-
messages.push("reads files relative to import.meta; bundling moves this module, so the files are not found at runtime \u2014 import the data statically instead");
|
|
99
|
-
}
|
|
100
|
-
if (NATIVE_LOADER_PACKAGE.test(file)) {
|
|
101
|
-
messages.push("loads a native addon (bindings/node-gyp-build), which Burger cannot run");
|
|
102
|
-
}
|
|
103
|
-
return messages;
|
|
104
|
-
}
|
|
105
|
-
function collectProblems(metafile, violations, cwd) {
|
|
106
|
-
const parents = importerGraph(metafile, cwd);
|
|
107
|
-
const problems = [];
|
|
108
|
-
for (const violation of violations) {
|
|
109
|
-
problems.push({
|
|
110
|
-
message: `import "${violation.specifier}": ${violation.reason}`,
|
|
111
|
-
chain: importerChain(violation.importer, parents)
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
115
|
-
const file = metafileKeyToPath(key, cwd);
|
|
116
|
-
if (!isAbsolute(file))
|
|
117
|
-
continue;
|
|
118
|
-
let source;
|
|
119
|
-
try {
|
|
120
|
-
source = readFileSync(file, "utf8");
|
|
121
|
-
} catch {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
const code = codeOf(file, source);
|
|
125
|
-
if (code === undefined)
|
|
126
|
-
continue;
|
|
127
|
-
const specifiers = input.imports.flatMap((record) => record.original === undefined ? [record.path] : [record.path, record.original]);
|
|
128
|
-
for (const message of scanModule(file, code, specifiers)) {
|
|
129
|
-
problems.push({ message, chain: importerChain(file, parents) });
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return problems;
|
|
133
|
-
}
|
|
134
|
-
function formatProblems(problems, cwd) {
|
|
135
|
-
const lines = [`burger-build: ${problems.length} problem(s) \u2014 this code cannot run on Burger:`];
|
|
136
|
-
for (const problem of problems) {
|
|
137
|
-
lines.push(` \u2717 ${problem.message}`);
|
|
138
|
-
problem.chain.forEach((file, index) => {
|
|
139
|
-
const shown = isAbsolute(file) ? relative(cwd, file) : file;
|
|
140
|
-
lines.push(index === 0 ? ` ${shown}` : ` \u2192 ${shown}`);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return lines.join(`
|
|
144
|
-
`);
|
|
145
|
-
}
|
|
146
18
|
|
|
147
19
|
// ../burger-build/src/aliases.ts
|
|
148
20
|
var BURGER_MODULES = [
|
|
@@ -260,7 +132,20 @@ var BURGER_EXPORTS = {
|
|
|
260
132
|
"chmodSync",
|
|
261
133
|
"unlinkSync",
|
|
262
134
|
"mkdtempSync",
|
|
263
|
-
"promises"
|
|
135
|
+
"promises",
|
|
136
|
+
"realpathSync",
|
|
137
|
+
"copyFileSync",
|
|
138
|
+
"symlinkSync",
|
|
139
|
+
"openSync",
|
|
140
|
+
"writeSync",
|
|
141
|
+
"fsyncSync",
|
|
142
|
+
"fdatasyncSync",
|
|
143
|
+
"closeSync",
|
|
144
|
+
"Dirent",
|
|
145
|
+
"constants",
|
|
146
|
+
"readSync",
|
|
147
|
+
"fstatSync",
|
|
148
|
+
"utimesSync"
|
|
264
149
|
],
|
|
265
150
|
"burger:fs/promises": [
|
|
266
151
|
"exists",
|
|
@@ -308,6 +193,16 @@ var BURGER_EXPORTS = {
|
|
|
308
193
|
"setDefaultTimeout"
|
|
309
194
|
]
|
|
310
195
|
};
|
|
196
|
+
var BURGER_DEFAULT_EXPORT = {
|
|
197
|
+
"burger:fs": true,
|
|
198
|
+
"burger:fs/promises": true,
|
|
199
|
+
"burger:path": true,
|
|
200
|
+
"burger:os": true,
|
|
201
|
+
"burger:worker_threads": true,
|
|
202
|
+
"burger:crypto": true,
|
|
203
|
+
"burger:buffer": true,
|
|
204
|
+
"burger:sqlite": true
|
|
205
|
+
};
|
|
311
206
|
var BURGER_MODULE_SET = new Set(BURGER_MODULES);
|
|
312
207
|
function classifySpecifier(specifier) {
|
|
313
208
|
if (BURGER_MODULE_SET.has(specifier)) {
|
|
@@ -335,6 +230,191 @@ function classifySpecifier(specifier) {
|
|
|
335
230
|
return { kind: "other" };
|
|
336
231
|
}
|
|
337
232
|
|
|
233
|
+
// ../burger-build/src/gate.ts
|
|
234
|
+
var FS_SPECIFIERS = new Set([
|
|
235
|
+
"fs",
|
|
236
|
+
"node:fs",
|
|
237
|
+
"fs/promises",
|
|
238
|
+
"node:fs/promises",
|
|
239
|
+
"burger:fs",
|
|
240
|
+
"burger:fs/promises"
|
|
241
|
+
]);
|
|
242
|
+
var BUN_GLOBAL = /(?<![\w$.'"`])Bun\s*\.\s*[A-Za-z_$]|\bglobalThis\s*\.\s*Bun\b/;
|
|
243
|
+
var IMPORT_META_PATH = /\bimport\.meta\.(?:url|dir|dirname|filename|path)\b/;
|
|
244
|
+
var IMPORT_OR_REEXPORT = /\b(?:import|export)\s+([^;]+?)\s+from\s*["']([^"']+)["']/g;
|
|
245
|
+
function parseNamedList(braced, into) {
|
|
246
|
+
for (const rawItem of braced.replace(/^\{|\}$/g, "").split(",")) {
|
|
247
|
+
const item = rawItem.trim();
|
|
248
|
+
if (item === "" || item.startsWith("type "))
|
|
249
|
+
continue;
|
|
250
|
+
const asMatch = /^([\w$]+|default)\s+as\s+[\w$]+$/.exec(item);
|
|
251
|
+
if (asMatch)
|
|
252
|
+
into.push(asMatch[1]);
|
|
253
|
+
else if (/^[\w$]+$/.test(item) || item === "default")
|
|
254
|
+
into.push(item);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function parseClause(raw) {
|
|
258
|
+
const clause = raw.trim();
|
|
259
|
+
const result = { named: [] };
|
|
260
|
+
if (clause.startsWith("type ") || clause.startsWith("*"))
|
|
261
|
+
return result;
|
|
262
|
+
if (clause.startsWith("{")) {
|
|
263
|
+
parseNamedList(clause, result.named);
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
const match = /^([\w$]+)\s*(?:,\s*([\s\S]+))?$/.exec(clause);
|
|
267
|
+
if (!match)
|
|
268
|
+
return result;
|
|
269
|
+
result.named.push("default");
|
|
270
|
+
const trailing = match[2]?.trim();
|
|
271
|
+
if (trailing?.startsWith("{"))
|
|
272
|
+
parseNamedList(trailing, result.named);
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
function missingExportMessage(target, name, specifier) {
|
|
276
|
+
return `"${target}" has no export "${name}" (imported as "${specifier}"); Burger provides: ${BURGER_EXPORTS[target].join(", ")}`;
|
|
277
|
+
}
|
|
278
|
+
function scanBurgerImports(code) {
|
|
279
|
+
const messages = [];
|
|
280
|
+
const reported = new Set;
|
|
281
|
+
for (const match of code.matchAll(IMPORT_OR_REEXPORT)) {
|
|
282
|
+
const specifier = match[2];
|
|
283
|
+
const specifierClass = classifySpecifier(specifier);
|
|
284
|
+
if (specifierClass.kind !== "burger")
|
|
285
|
+
continue;
|
|
286
|
+
const target = specifierClass.target;
|
|
287
|
+
for (const name of parseClause(match[1]).named) {
|
|
288
|
+
const provided = name === "default" ? target in BURGER_DEFAULT_EXPORT : BURGER_EXPORTS[target].includes(name);
|
|
289
|
+
const key = `${target}\x00${name}\x00${specifier}`;
|
|
290
|
+
if (provided || reported.has(key))
|
|
291
|
+
continue;
|
|
292
|
+
reported.add(key);
|
|
293
|
+
messages.push(missingExportMessage(target, name, specifier));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return messages;
|
|
297
|
+
}
|
|
298
|
+
var NATIVE_LOADER_PACKAGE = /[\\/]node_modules[\\/](?:bindings|node-gyp-build)[\\/]/;
|
|
299
|
+
function metafileKeyToPath(key, cwd) {
|
|
300
|
+
if (isAbsolute(key))
|
|
301
|
+
return key;
|
|
302
|
+
const colon = key.indexOf(":");
|
|
303
|
+
const slash = key.indexOf("/");
|
|
304
|
+
if (colon > 0 && (slash === -1 || colon < slash))
|
|
305
|
+
return key;
|
|
306
|
+
return resolve(cwd, key);
|
|
307
|
+
}
|
|
308
|
+
function importerGraph(metafile, cwd) {
|
|
309
|
+
const parents = new Map;
|
|
310
|
+
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
311
|
+
const importer = metafileKeyToPath(key, cwd);
|
|
312
|
+
for (const record of input.imports) {
|
|
313
|
+
if (record.external)
|
|
314
|
+
continue;
|
|
315
|
+
const child = metafileKeyToPath(record.path, cwd);
|
|
316
|
+
if (child !== importer && !parents.has(child)) {
|
|
317
|
+
parents.set(child, importer);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return parents;
|
|
322
|
+
}
|
|
323
|
+
function importerChain(file, parents) {
|
|
324
|
+
const chain = [file];
|
|
325
|
+
const seen = new Set(chain);
|
|
326
|
+
let current = parents.get(file);
|
|
327
|
+
while (current !== undefined && !seen.has(current)) {
|
|
328
|
+
chain.unshift(current);
|
|
329
|
+
seen.add(current);
|
|
330
|
+
current = parents.get(current);
|
|
331
|
+
}
|
|
332
|
+
return chain;
|
|
333
|
+
}
|
|
334
|
+
function loaderFor(file) {
|
|
335
|
+
switch (extname(file)) {
|
|
336
|
+
case ".ts":
|
|
337
|
+
case ".mts":
|
|
338
|
+
case ".cts":
|
|
339
|
+
return "ts";
|
|
340
|
+
case ".tsx":
|
|
341
|
+
return "tsx";
|
|
342
|
+
case ".jsx":
|
|
343
|
+
return "jsx";
|
|
344
|
+
case ".js":
|
|
345
|
+
case ".mjs":
|
|
346
|
+
case ".cjs":
|
|
347
|
+
return "js";
|
|
348
|
+
default:
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function codeOf(file, source) {
|
|
353
|
+
const loader = loaderFor(file);
|
|
354
|
+
if (!loader)
|
|
355
|
+
return;
|
|
356
|
+
try {
|
|
357
|
+
return new Bun.Transpiler({ loader }).transformSync(source);
|
|
358
|
+
} catch {
|
|
359
|
+
return source;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function scanModule(file, code, importedSpecifiers) {
|
|
363
|
+
const messages = [];
|
|
364
|
+
if (BUN_GLOBAL.test(code)) {
|
|
365
|
+
messages.push("uses the Bun global (Bun.*), which does not exist in Burger");
|
|
366
|
+
}
|
|
367
|
+
if (IMPORT_META_PATH.test(code) && importedSpecifiers.some((specifier) => FS_SPECIFIERS.has(specifier))) {
|
|
368
|
+
messages.push("reads files relative to import.meta; bundling moves this module, so the files are not found at runtime \u2014 import the data statically instead");
|
|
369
|
+
}
|
|
370
|
+
if (NATIVE_LOADER_PACKAGE.test(file)) {
|
|
371
|
+
messages.push("loads a native addon (bindings/node-gyp-build), which Burger cannot run");
|
|
372
|
+
}
|
|
373
|
+
messages.push(...scanBurgerImports(code));
|
|
374
|
+
return messages;
|
|
375
|
+
}
|
|
376
|
+
function collectProblems(metafile, violations, cwd) {
|
|
377
|
+
const parents = importerGraph(metafile, cwd);
|
|
378
|
+
const problems = [];
|
|
379
|
+
for (const violation of violations) {
|
|
380
|
+
problems.push({
|
|
381
|
+
message: `import "${violation.specifier}": ${violation.reason}`,
|
|
382
|
+
chain: importerChain(violation.importer, parents)
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
386
|
+
const file = metafileKeyToPath(key, cwd);
|
|
387
|
+
if (!isAbsolute(file))
|
|
388
|
+
continue;
|
|
389
|
+
let source;
|
|
390
|
+
try {
|
|
391
|
+
source = readFileSync(file, "utf8");
|
|
392
|
+
} catch {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const code = codeOf(file, source);
|
|
396
|
+
if (code === undefined)
|
|
397
|
+
continue;
|
|
398
|
+
const specifiers = input.imports.flatMap((record) => record.original === undefined ? [record.path] : [record.path, record.original]);
|
|
399
|
+
for (const message of scanModule(file, code, specifiers)) {
|
|
400
|
+
problems.push({ message, chain: importerChain(file, parents) });
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return problems;
|
|
404
|
+
}
|
|
405
|
+
function formatProblems(problems, cwd) {
|
|
406
|
+
const lines = [`burger-build: ${problems.length} problem(s) \u2014 this code cannot run on Burger:`];
|
|
407
|
+
for (const problem of problems) {
|
|
408
|
+
lines.push(` \u2717 ${problem.message}`);
|
|
409
|
+
problem.chain.forEach((file, index) => {
|
|
410
|
+
const shown = isAbsolute(file) ? relative(cwd, file) : file;
|
|
411
|
+
lines.push(index === 0 ? ` ${shown}` : ` \u2192 ${shown}`);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return lines.join(`
|
|
415
|
+
`);
|
|
416
|
+
}
|
|
417
|
+
|
|
338
418
|
// ../burger-build/src/plugin.ts
|
|
339
419
|
var BRIDGE_NAMESPACE = "burger-require";
|
|
340
420
|
var BRIDGE_PREFIX = "cjs-bridge/";
|
|
@@ -509,22 +589,36 @@ function relativeSpecifier(fromDir, to) {
|
|
|
509
589
|
const rel = relative2(fromDir, to).split(sep).join("/");
|
|
510
590
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
511
591
|
}
|
|
592
|
+
var JS_TO_TS_SUFFIXES = {
|
|
593
|
+
".js": [".ts", ".tsx"],
|
|
594
|
+
".jsx": [".tsx"],
|
|
595
|
+
".mjs": [".mts"],
|
|
596
|
+
".cjs": []
|
|
597
|
+
};
|
|
512
598
|
function resolveRelativeFile(importerDir, specifier) {
|
|
513
599
|
const base = resolve2(importerDir, specifier);
|
|
600
|
+
const isFile = (candidate) => existsSync(candidate) && statSync(candidate).isFile();
|
|
601
|
+
if (isFile(base))
|
|
602
|
+
return base;
|
|
603
|
+
const mapped = JS_TO_TS_SUFFIXES[extname2(specifier)];
|
|
604
|
+
if (mapped !== undefined) {
|
|
605
|
+
const stem = base.slice(0, base.length - extname2(specifier).length);
|
|
606
|
+
return mapped.map((suffix) => stem + suffix).find(isFile);
|
|
607
|
+
}
|
|
514
608
|
const candidates = [
|
|
515
|
-
base,
|
|
516
609
|
...RESOLVE_SUFFIXES.map((suffix) => base + suffix),
|
|
517
610
|
...RESOLVE_SUFFIXES.map((suffix) => join2(base, `index${suffix}`))
|
|
518
611
|
];
|
|
519
|
-
return candidates.find(
|
|
612
|
+
return candidates.find(isFile);
|
|
520
613
|
}
|
|
521
614
|
function dependencyFileName(specifier) {
|
|
522
615
|
return specifier.replace(/^@/, "").replace(/[\\/]/g, "__") + ".js";
|
|
523
616
|
}
|
|
617
|
+
var TEXT_NAMESPACE = "burger-text";
|
|
524
618
|
function rewriteSpecifier(ws, importer, specifier) {
|
|
525
619
|
const specifierClass = classifySpecifier(specifier);
|
|
526
620
|
if (specifierClass.kind === "burger")
|
|
527
|
-
return specifierClass.target;
|
|
621
|
+
return { external: specifierClass.target };
|
|
528
622
|
if (specifierClass.kind === "forbidden") {
|
|
529
623
|
ws.problems.push({ message: `import "${specifier}": ${specifierClass.reason}`, chain: [importer] });
|
|
530
624
|
return;
|
|
@@ -541,7 +635,14 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
541
635
|
return;
|
|
542
636
|
}
|
|
543
637
|
ws.jsonFiles.add(target);
|
|
544
|
-
return `${relativeSpecifier(dirname(importer), target)}.js
|
|
638
|
+
return { external: `${relativeSpecifier(dirname(importer), target)}.js` };
|
|
639
|
+
}
|
|
640
|
+
if (!isCodeFile(target)) {
|
|
641
|
+
if (!isInside(target, ws.root)) {
|
|
642
|
+
ws.problems.push({ message: `"${specifier}" is outside ${ws.root}`, chain: [importer] });
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
return { inline: target };
|
|
545
646
|
}
|
|
546
647
|
if (!ws.sources.has(target)) {
|
|
547
648
|
ws.problems.push({
|
|
@@ -550,7 +651,7 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
550
651
|
});
|
|
551
652
|
return;
|
|
552
653
|
}
|
|
553
|
-
return preparedPath(relativeSpecifier(dirname(importer), target));
|
|
654
|
+
return { external: preparedPath(relativeSpecifier(dirname(importer), target)) };
|
|
554
655
|
}
|
|
555
656
|
if (specifier.startsWith("#")) {
|
|
556
657
|
ws.problems.push({
|
|
@@ -560,7 +661,7 @@ function rewriteSpecifier(ws, importer, specifier) {
|
|
|
560
661
|
return;
|
|
561
662
|
}
|
|
562
663
|
ws.dependencies.add(specifier);
|
|
563
|
-
return specifier;
|
|
664
|
+
return { external: specifier };
|
|
564
665
|
}
|
|
565
666
|
function moduleIdentity(importer, specifier) {
|
|
566
667
|
const specifierClass = classifySpecifier(specifier);
|
|
@@ -604,8 +705,17 @@ function sourcesPlugin(ws) {
|
|
|
604
705
|
});
|
|
605
706
|
return { path: args.path, external: true };
|
|
606
707
|
}
|
|
607
|
-
|
|
708
|
+
const resolved = rewriteSpecifier(ws, args.importer, args.path);
|
|
709
|
+
if (resolved === undefined)
|
|
710
|
+
return { path: args.path, external: true };
|
|
711
|
+
if ("inline" in resolved)
|
|
712
|
+
return { path: resolved.inline, namespace: TEXT_NAMESPACE, external: false };
|
|
713
|
+
return { path: resolved.external, external: true };
|
|
608
714
|
});
|
|
715
|
+
build.onLoad({ filter: /.*/, namespace: TEXT_NAMESPACE }, (args) => ({
|
|
716
|
+
contents: readFileSync2(args.path, "utf8"),
|
|
717
|
+
loader: "text"
|
|
718
|
+
}));
|
|
609
719
|
}
|
|
610
720
|
};
|
|
611
721
|
}
|
|
@@ -730,7 +840,8 @@ async function prepareTests(options) {
|
|
|
730
840
|
const output = join2(out, preparedPath(relative2(root, file)));
|
|
731
841
|
const prepared = readFileSync2(output, "utf8").replace(MOCK_MODULE_CALL, (call, quote, specifier) => {
|
|
732
842
|
const rewritten = rewriteSpecifier(ws, file, specifier);
|
|
733
|
-
|
|
843
|
+
const replacement = rewritten === undefined ? undefined : ("external" in rewritten) ? rewritten.external : undefined;
|
|
844
|
+
return replacement === undefined ? call : call.replace(`${quote}${specifier}${quote}`, JSON.stringify(replacement));
|
|
734
845
|
});
|
|
735
846
|
writeFileSync2(output, prepared);
|
|
736
847
|
const source = readFileSync2(file, "utf8");
|
|
@@ -42,12 +42,19 @@ interface Workspace {
|
|
|
42
42
|
dependencies: Set<string>;
|
|
43
43
|
problems: Problem[];
|
|
44
44
|
}
|
|
45
|
+
/** Namespace `sourcesPlugin` uses for a non-code, non-JSON file inlined as text (matching Bun's own `build`). */
|
|
46
|
+
export declare const TEXT_NAMESPACE = "burger-text";
|
|
47
|
+
export type ResolvedImport = {
|
|
48
|
+
external: string;
|
|
49
|
+
} | {
|
|
50
|
+
inline: string;
|
|
51
|
+
};
|
|
45
52
|
/**
|
|
46
53
|
* What a prepared module imports instead of `specifier` (written in
|
|
47
54
|
* `importer`). Returns undefined — with a recorded problem — when the import
|
|
48
55
|
* cannot work under Burger.
|
|
49
56
|
*/
|
|
50
|
-
export declare function rewriteSpecifier(ws: Workspace, importer: string, specifier: string):
|
|
57
|
+
export declare function rewriteSpecifier(ws: Workspace, importer: string, specifier: string): ResolvedImport | undefined;
|
|
51
58
|
/**
|
|
52
59
|
* Problems for a module that statically imports a module it also replaces
|
|
53
60
|
* with `mock.module`. Bun patches the already-linked bindings, so the test
|
|
@@ -64,3 +64,48 @@ interface BurgerProcess {
|
|
|
64
64
|
memoryUsage(): BurgerProcessMemoryUsage;
|
|
65
65
|
}
|
|
66
66
|
declare var process: BurgerProcess;
|
|
67
|
+
|
|
68
|
+
/** A message delivered to a `Worker` or to a worker's own scope. Data is copied as JSON. */
|
|
69
|
+
interface BurgerWorkerMessageEvent {
|
|
70
|
+
readonly type: "message";
|
|
71
|
+
readonly data: unknown;
|
|
72
|
+
readonly target: unknown;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** An error a worker's handler threw, reported to its parent. */
|
|
76
|
+
interface BurgerWorkerErrorEvent {
|
|
77
|
+
readonly type: "error";
|
|
78
|
+
readonly message: string;
|
|
79
|
+
readonly error: Error;
|
|
80
|
+
readonly target: unknown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The Worker-equivalent (data-app pack, econ-v1/node-app-burger#12): the Web
|
|
85
|
+
* `Worker` as Bun provides it, limited to running work an app can cancel.
|
|
86
|
+
* `specifier` is a path, a `file:` URL string, or an object with a `file:`
|
|
87
|
+
* `href`.
|
|
88
|
+
*/
|
|
89
|
+
declare class Worker {
|
|
90
|
+
constructor(specifier: string | { readonly href: string }, options?: { type?: "module" });
|
|
91
|
+
postMessage(message: unknown): void;
|
|
92
|
+
terminate(): void;
|
|
93
|
+
onmessage: ((event: BurgerWorkerMessageEvent) => void) | null;
|
|
94
|
+
onerror: ((event: BurgerWorkerErrorEvent) => void) | null;
|
|
95
|
+
addEventListener(type: "message", listener: (event: BurgerWorkerMessageEvent) => void): void;
|
|
96
|
+
addEventListener(type: "error", listener: (event: BurgerWorkerErrorEvent) => void): void;
|
|
97
|
+
removeEventListener(type: "message" | "error", listener: (...args: never[]) => void): void;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Inside a worker module (data-app pack): the worker's own scope, where
|
|
102
|
+
* `self` is `globalThis`. A handler that throws is reported to the parent's
|
|
103
|
+
* `onerror` and the worker keeps running.
|
|
104
|
+
*/
|
|
105
|
+
declare function postMessage(message: unknown): void;
|
|
106
|
+
/** Ends this worker from inside. */
|
|
107
|
+
declare function close(): void;
|
|
108
|
+
declare var onmessage: ((event: BurgerWorkerMessageEvent) => void) | null;
|
|
109
|
+
declare function addEventListener(type: "message", listener: (event: BurgerWorkerMessageEvent) => void): void;
|
|
110
|
+
declare function removeEventListener(type: "message", listener: (event: BurgerWorkerMessageEvent) => void): void;
|
|
111
|
+
declare var self: typeof globalThis;
|
|
@@ -47,13 +47,40 @@ declare module "burger:fs" {
|
|
|
47
47
|
readonly mtimeMs: number;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A `readdirSync(path, { withFileTypes: true })` entry, Node 22 shape (data-app
|
|
52
|
+
* pack). The type is the entry's own, symlinks not followed.
|
|
53
|
+
*/
|
|
54
|
+
export class Dirent {
|
|
55
|
+
private constructor();
|
|
56
|
+
readonly name: string;
|
|
57
|
+
/** The directory it was listed from, as the caller spelled it. */
|
|
58
|
+
readonly parentPath: string;
|
|
59
|
+
/** Same as `parentPath`; Node's older name for it, kept by the runtime for code that reads it. */
|
|
60
|
+
readonly path: string;
|
|
61
|
+
isFile(): boolean;
|
|
62
|
+
isDirectory(): boolean;
|
|
63
|
+
isSymbolicLink(): boolean;
|
|
64
|
+
isFIFO(): boolean;
|
|
65
|
+
isSocket(): boolean;
|
|
66
|
+
isBlockDevice(): boolean;
|
|
67
|
+
isCharacterDevice(): boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ReaddirOptions {
|
|
71
|
+
encoding?: Utf8Encoding;
|
|
72
|
+
/** Names (or Dirents) of every entry below, as paths relative to the listed directory. */
|
|
73
|
+
recursive?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
50
76
|
export function existsSync(path: PathLike): boolean;
|
|
51
77
|
export function readFileSync(path: PathLike): Uint8Array;
|
|
52
78
|
export function readFileSync(path: PathLike, encoding: Utf8Encoding | { encoding: Utf8Encoding }): string;
|
|
53
79
|
export function writeFileSync(path: PathLike, data: string | Uint8Array): void;
|
|
54
80
|
export function appendFileSync(path: PathLike, data: string | Uint8Array): void;
|
|
55
81
|
export function mkdirSync(path: PathLike, options?: { recursive?: boolean }): void;
|
|
56
|
-
export function readdirSync(path: PathLike): string[];
|
|
82
|
+
export function readdirSync(path: PathLike, options?: Utf8Encoding | (ReaddirOptions & { withFileTypes?: false })): string[];
|
|
83
|
+
export function readdirSync(path: PathLike, options: ReaddirOptions & { withFileTypes: true }): Dirent[];
|
|
57
84
|
export function statSync(path: PathLike): Stats;
|
|
58
85
|
export function rmSync(path: PathLike, options?: { recursive?: boolean; force?: boolean }): void;
|
|
59
86
|
export function renameSync(oldPath: PathLike, newPath: PathLike): void;
|
|
@@ -61,6 +88,39 @@ declare module "burger:fs" {
|
|
|
61
88
|
export function unlinkSync(path: PathLike): void;
|
|
62
89
|
/** Create a unique directory whose name starts with `prefix`; returns its path. */
|
|
63
90
|
export function mkdtempSync(prefix: string): string;
|
|
91
|
+
// data-app pack (econ-v1/node-app-burger#12):
|
|
92
|
+
export interface RealpathSync {
|
|
93
|
+
(path: PathLike, options?: Utf8Encoding | { encoding: Utf8Encoding }): string;
|
|
94
|
+
/** The same resolver (Node's name for it). */
|
|
95
|
+
native(path: PathLike, options?: Utf8Encoding | { encoding: Utf8Encoding }): string;
|
|
96
|
+
}
|
|
97
|
+
export const realpathSync: RealpathSync;
|
|
98
|
+
/** `copyFileSync` modes and `access`-style mode bits. `COPYFILE_FICLONE` falls back to a plain copy. */
|
|
99
|
+
export const constants: {
|
|
100
|
+
readonly COPYFILE_EXCL: 1;
|
|
101
|
+
readonly COPYFILE_FICLONE: 2;
|
|
102
|
+
readonly COPYFILE_FICLONE_FORCE: 4;
|
|
103
|
+
readonly F_OK: 0;
|
|
104
|
+
readonly R_OK: 4;
|
|
105
|
+
readonly W_OK: 2;
|
|
106
|
+
readonly X_OK: 1;
|
|
107
|
+
};
|
|
108
|
+
export function copyFileSync(src: PathLike, dest: PathLike, mode?: number): void;
|
|
109
|
+
/** `type` ("file"/"dir"/"junction") matters only on Windows and is ignored. */
|
|
110
|
+
export function symlinkSync(target: PathLike, path: PathLike, type?: "file" | "dir" | "junction"): void;
|
|
111
|
+
export type OpenFlags = "r" | "r+" | "rs+" | "w" | "wx" | "w+" | "wx+" | "a" | "ax" | "a+" | "ax+";
|
|
112
|
+
export function openSync(path: PathLike, flags?: OpenFlags, mode?: number | string): number;
|
|
113
|
+
export function writeSync(fd: number, buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number;
|
|
114
|
+
export function writeSync(fd: number, text: string, position?: number | null, encoding?: Utf8Encoding): number;
|
|
115
|
+
export function fsyncSync(fd: number): void;
|
|
116
|
+
export function fdatasyncSync(fd: number): void;
|
|
117
|
+
export function closeSync(fd: number): void;
|
|
118
|
+
// second data-app pack (econ-v1/node-app-memory#40):
|
|
119
|
+
/** Read into `buffer` at `offset`; `position` null reads from the current position. Returns bytes read. */
|
|
120
|
+
export function readSync(fd: number, buffer: Uint8Array, offset?: number, length?: number, position?: number | null): number;
|
|
121
|
+
export function fstatSync(fd: number): Stats;
|
|
122
|
+
/** Set access and modification times (seconds since the epoch, or Dates). */
|
|
123
|
+
export function utimesSync(path: PathLike, atime: number | Date, mtime: number | Date): void;
|
|
64
124
|
|
|
65
125
|
export interface FsPromises {
|
|
66
126
|
exists(path: PathLike): Promise<boolean>;
|
|
@@ -69,7 +129,8 @@ declare module "burger:fs" {
|
|
|
69
129
|
writeFile(path: PathLike, data: string | Uint8Array): Promise<void>;
|
|
70
130
|
appendFile(path: PathLike, data: string | Uint8Array): Promise<void>;
|
|
71
131
|
mkdir(path: PathLike, options?: { recursive?: boolean }): Promise<void>;
|
|
72
|
-
readdir(path: PathLike): Promise<string[]>;
|
|
132
|
+
readdir(path: PathLike, options?: Utf8Encoding | (ReaddirOptions & { withFileTypes?: false })): Promise<string[]>;
|
|
133
|
+
readdir(path: PathLike, options: ReaddirOptions & { withFileTypes: true }): Promise<Dirent[]>;
|
|
73
134
|
stat(path: PathLike): Promise<Stats>;
|
|
74
135
|
rm(path: PathLike, options?: { recursive?: boolean; force?: boolean }): Promise<void>;
|
|
75
136
|
rename(oldPath: PathLike, newPath: PathLike): Promise<void>;
|
|
@@ -93,6 +154,19 @@ declare module "burger:fs" {
|
|
|
93
154
|
chmodSync: typeof chmodSync;
|
|
94
155
|
unlinkSync: typeof unlinkSync;
|
|
95
156
|
mkdtempSync: typeof mkdtempSync;
|
|
157
|
+
realpathSync: typeof realpathSync;
|
|
158
|
+
constants: typeof constants;
|
|
159
|
+
copyFileSync: typeof copyFileSync;
|
|
160
|
+
symlinkSync: typeof symlinkSync;
|
|
161
|
+
openSync: typeof openSync;
|
|
162
|
+
writeSync: typeof writeSync;
|
|
163
|
+
fsyncSync: typeof fsyncSync;
|
|
164
|
+
fdatasyncSync: typeof fdatasyncSync;
|
|
165
|
+
closeSync: typeof closeSync;
|
|
166
|
+
readSync: typeof readSync;
|
|
167
|
+
fstatSync: typeof fstatSync;
|
|
168
|
+
utimesSync: typeof utimesSync;
|
|
169
|
+
Dirent: typeof Dirent;
|
|
96
170
|
promises: FsPromises;
|
|
97
171
|
};
|
|
98
172
|
export default fs;
|
|
@@ -222,7 +296,7 @@ declare module "burger:crypto" {
|
|
|
222
296
|
}
|
|
223
297
|
|
|
224
298
|
declare module "burger:buffer" {
|
|
225
|
-
export type BufferEncoding = "utf8" | "utf-8" | "hex" | "base64" | "base64url";
|
|
299
|
+
export type BufferEncoding = "utf8" | "utf-8" | "hex" | "base64" | "base64url" | "latin1" | "binary" | "ascii";
|
|
226
300
|
|
|
227
301
|
/** C5 subset of Node's Buffer. Instances are `Uint8Array`s. */
|
|
228
302
|
export interface Buffer extends Uint8Array<ArrayBuffer> {
|
|
@@ -265,21 +339,43 @@ declare module "burger:sqlite" {
|
|
|
265
339
|
get(...params: SQLParams): Row | null;
|
|
266
340
|
run(...params: SQLParams): Changes;
|
|
267
341
|
values(...params: SQLParams): SQLValue[][];
|
|
342
|
+
/** data-app pack: rows one at a time; the deadline bounds the whole iteration. */
|
|
343
|
+
iterate(...params: SQLParams): IterableIterator<Row>;
|
|
344
|
+
[Symbol.iterator](): IterableIterator<Row>;
|
|
345
|
+
/** data-app pack. */
|
|
346
|
+
readonly columnNames: string[];
|
|
347
|
+
/**
|
|
348
|
+
* data-app pack (Burger extension): wall-clock budget in ms for each
|
|
349
|
+
* execution of this statement. Past it the call throws an Error whose
|
|
350
|
+
* `code` is "SQLITE_INTERRUPT"; unlike the runtime watchdog it is not a
|
|
351
|
+
* strike. `undefined` inherits the Database's `deadlineMs`; 0 or `null`
|
|
352
|
+
* means none.
|
|
353
|
+
*/
|
|
354
|
+
deadlineMs: number | null | undefined;
|
|
268
355
|
}
|
|
269
356
|
|
|
270
357
|
export interface DatabaseOptions {
|
|
271
358
|
create?: boolean;
|
|
272
359
|
readonly?: boolean;
|
|
360
|
+
readwrite?: boolean;
|
|
361
|
+
/** data-app pack: the default `deadlineMs` of this database's statements. */
|
|
362
|
+
deadlineMs?: number;
|
|
273
363
|
}
|
|
274
364
|
|
|
275
365
|
export class Database {
|
|
276
366
|
constructor(filename?: string, options?: DatabaseOptions);
|
|
367
|
+
/** data-app pack: the default statement deadline in ms (`undefined`: none). */
|
|
368
|
+
deadlineMs: number | null | undefined;
|
|
277
369
|
query<Row = unknown>(sql: string): Statement<Row>;
|
|
278
370
|
prepare<Row = unknown>(sql: string): Statement<Row>;
|
|
279
371
|
exec(sql: string, ...params: SQLParams): Changes;
|
|
280
372
|
run(sql: string, ...params: SQLParams): Changes;
|
|
281
373
|
transaction<Args extends unknown[], Result>(fn: (...args: Args) => Result): (...args: Args) => Result;
|
|
282
374
|
close(): void;
|
|
375
|
+
/** data-app pack: the database image (`sqlite3_serialize`) of schema `name` (default "main"). */
|
|
376
|
+
serialize(name?: string): Uint8Array;
|
|
377
|
+
/** second data-app pack: open an in-memory database from `serialize()` bytes. */
|
|
378
|
+
static deserialize(serialized: Uint8Array, isReadOnly?: boolean): Database;
|
|
283
379
|
}
|
|
284
380
|
|
|
285
381
|
/** Default export is the Database class itself, which also carries `.Database` (C6). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@econ-v1/app-sdk",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.2",
|
|
4
4
|
"description": "TypeScript SDK for building Node mini-app plugins (Bun runtime) on the Lightning-powered marketplace daemon",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"author": "Node contributors",
|