@statewalker/webrun-bundler 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +178 -2
- package/dist/index.d.mts +225 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +571 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -3
- package/src/bundle.test.ts +388 -0
- package/src/bundle.ts +245 -0
- package/src/index.ts +17 -0
- package/src/input-maps.ts +79 -0
- package/src/packages.ts +126 -0
- package/src/paths.ts +62 -0
- package/src/resolve.ts +116 -0
- package/src/types.ts +154 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
import { normalizePath, readText, tryReadText } from "@statewalker/webrun-files";
|
|
2
|
+
import { exports, imports } from "resolve.exports";
|
|
3
|
+
//#region src/paths.ts
|
|
4
|
+
/** `path` joined to `dir`, with `.` and `..` resolved; `undefined` when it leaves `root`. */
|
|
5
|
+
function joinWithin(root, dir, path) {
|
|
6
|
+
const parts = (path.startsWith("/") ? path : `${dir}/${path}`).split("/");
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const p of parts) {
|
|
9
|
+
if (!p || p === ".") continue;
|
|
10
|
+
if (p === "..") {
|
|
11
|
+
if (!out.length) return void 0;
|
|
12
|
+
out.pop();
|
|
13
|
+
} else out.push(p);
|
|
14
|
+
}
|
|
15
|
+
const joined = `/${out.join("/")}`;
|
|
16
|
+
const r = normalizePath(root);
|
|
17
|
+
return r === "/" || joined === r || joined.startsWith(`${r}/`) ? joined : void 0;
|
|
18
|
+
}
|
|
19
|
+
const dirOf = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
20
|
+
/** The id of a mount's file: `<prefix>/<path below root>`. */
|
|
21
|
+
function idOf(mount, path) {
|
|
22
|
+
const r = normalizePath(mount.root);
|
|
23
|
+
const rel = r === "/" ? path : path.slice(r.length);
|
|
24
|
+
return `${mount.prefix}${rel || "/"}`;
|
|
25
|
+
}
|
|
26
|
+
/** A mount's file from its id; `undefined` when the id is not the mount's. */
|
|
27
|
+
function pathOf(mount, id) {
|
|
28
|
+
if (!id.startsWith(`${mount.prefix}/`)) return void 0;
|
|
29
|
+
const r = normalizePath(mount.root);
|
|
30
|
+
const rel = id.slice(mount.prefix.length);
|
|
31
|
+
return r === "/" ? rel : `${r}${rel}`;
|
|
32
|
+
}
|
|
33
|
+
async function isFile(mount, path) {
|
|
34
|
+
return (await mount.files.stats(path))?.kind === "file";
|
|
35
|
+
}
|
|
36
|
+
async function readManifest(files, dir) {
|
|
37
|
+
const text = await tryReadText(files, `${dir === "/" ? "" : dir}/package.json`);
|
|
38
|
+
if (text === void 0) return void 0;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(text);
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** `react` → `{ name: "react" }`; `@a/b/c.js` → `{ name: "@a/b", subpath: "c.js" }`. */
|
|
46
|
+
function parsePackageSpecifier(spec) {
|
|
47
|
+
const parts = spec.split("/");
|
|
48
|
+
const n = spec.startsWith("@") ? 2 : 1;
|
|
49
|
+
const name = parts.slice(0, n).join("/");
|
|
50
|
+
const subpath = parts.slice(n).join("/");
|
|
51
|
+
return subpath ? {
|
|
52
|
+
name,
|
|
53
|
+
subpath
|
|
54
|
+
} : { name };
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/input-maps.ts
|
|
58
|
+
const MAP_COMMENT = /\/\/[#@]\s*sourceMappingURL=(\S+)\s*$/;
|
|
59
|
+
const toBase64$1 = (text) => {
|
|
60
|
+
const bytes = new TextEncoder().encode(text);
|
|
61
|
+
let bin = "";
|
|
62
|
+
for (let i = 0; i < bytes.length; i += 32768) bin += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
63
|
+
return btoa(bin);
|
|
64
|
+
};
|
|
65
|
+
const fromBase64 = (b64) => new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));
|
|
66
|
+
/**
|
|
67
|
+
* A file's own source map, made usable by esbuild, which reads only maps inlined in
|
|
68
|
+
* the file it loads (it cannot follow a linked `.map` through a FilesApi):
|
|
69
|
+
*
|
|
70
|
+
* - a linked map (`//# sourceMappingURL=index.js.map`) is read from the same tree and
|
|
71
|
+
* inlined; an inline `data:` map is kept;
|
|
72
|
+
* - its sources become ids of the same tree (`npm:pkg@1.0.0/src/index.ts`), so the
|
|
73
|
+
* bundle's map names the package's original files, not the published JavaScript;
|
|
74
|
+
* - missing `sourcesContent` is filled from the tree when the original file ships
|
|
75
|
+
* with the package.
|
|
76
|
+
*
|
|
77
|
+
* esbuild then composes it with its own: a bundled line traces to the original source.
|
|
78
|
+
* A map that is missing or unreadable is dropped (the file maps to itself).
|
|
79
|
+
*/
|
|
80
|
+
async function inlineInputMap(mount, path, code) {
|
|
81
|
+
const lines = code.trimEnd().split("\n");
|
|
82
|
+
const last = lines[lines.length - 1] ?? "";
|
|
83
|
+
const match = MAP_COMMENT.exec(last);
|
|
84
|
+
if (!match) return code;
|
|
85
|
+
const url = match[1];
|
|
86
|
+
const body = lines.slice(0, -1).join("\n");
|
|
87
|
+
let text;
|
|
88
|
+
let mapDir = dirOf(path);
|
|
89
|
+
if (url.startsWith("data:")) {
|
|
90
|
+
const comma = url.indexOf(",");
|
|
91
|
+
const meta = url.slice(5, comma);
|
|
92
|
+
const payload = url.slice(comma + 1);
|
|
93
|
+
try {
|
|
94
|
+
text = meta.endsWith(";base64") ? fromBase64(payload) : decodeURIComponent(payload);
|
|
95
|
+
} catch {
|
|
96
|
+
text = void 0;
|
|
97
|
+
}
|
|
98
|
+
} else if (!/^[a-z][a-z0-9+.-]*:/i.test(url)) {
|
|
99
|
+
const mapPath = joinWithin(mount.root, dirOf(path), decodeURIComponent(url));
|
|
100
|
+
if (mapPath) {
|
|
101
|
+
text = await tryReadText(mount.files, mapPath);
|
|
102
|
+
mapDir = dirOf(mapPath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let map;
|
|
106
|
+
try {
|
|
107
|
+
map = JSON.parse(text ?? "");
|
|
108
|
+
} catch {
|
|
109
|
+
return body;
|
|
110
|
+
}
|
|
111
|
+
const sourceDir = map.sourceRoot ? joinWithin("/", mapDir, map.sourceRoot.replace(/\/$/, "")) ?? mapDir : mapDir;
|
|
112
|
+
const contents = map.sourcesContent ? [...map.sourcesContent] : [];
|
|
113
|
+
const sources = [];
|
|
114
|
+
for (let i = 0; i < map.sources.length; i++) {
|
|
115
|
+
const src = map.sources[i];
|
|
116
|
+
const local = /^[a-z][a-z0-9+.-]*:/i.test(src) ? void 0 : joinWithin(mount.root, sourceDir, src);
|
|
117
|
+
sources.push(local ? idOf(mount, local) : src);
|
|
118
|
+
if (contents[i] == null && local) contents[i] = await tryReadText(mount.files, local) ?? null;
|
|
119
|
+
}
|
|
120
|
+
const fixed = {
|
|
121
|
+
...map,
|
|
122
|
+
sources,
|
|
123
|
+
sourcesContent: contents
|
|
124
|
+
};
|
|
125
|
+
delete fixed.sourceRoot;
|
|
126
|
+
return `${body}\n//# sourceMappingURL=data:application/json;base64,${toBase64$1(JSON.stringify(fixed))}\n`;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/packages.ts
|
|
130
|
+
const mountPrefix = (name, version) => `npm:${name}@${version ?? "0.0.0"}`;
|
|
131
|
+
/**
|
|
132
|
+
* Packages from `node_modules` folders, found as Node finds them: in the importing
|
|
133
|
+
* file's directory and each parent, inside the importer's own FilesApi. A package
|
|
134
|
+
* installed in the project (or in another package's `node_modules`) is read where it is.
|
|
135
|
+
*
|
|
136
|
+
* pnpm layouts: a package's own dependencies sit next to its real directory in
|
|
137
|
+
* `node_modules/.pnpm`, which Node reaches through the symlink's real path and a FilesApi
|
|
138
|
+
* cannot see. When the walk finds nothing, each ancestor's `node_modules/.pnpm/node_modules`
|
|
139
|
+
* (pnpm's hoisted links to every installed package) is tried too.
|
|
140
|
+
*/
|
|
141
|
+
function nodeModulesPackages() {
|
|
142
|
+
const mounts = /* @__PURE__ */ new Map();
|
|
143
|
+
const at = async (files, root, name) => {
|
|
144
|
+
const known = mounts.get(root);
|
|
145
|
+
if (known && known.files === files) return known;
|
|
146
|
+
const manifest = await readManifest(files, root);
|
|
147
|
+
if (!manifest) return void 0;
|
|
148
|
+
const mount = {
|
|
149
|
+
prefix: mountPrefix(name, manifest.version),
|
|
150
|
+
files,
|
|
151
|
+
root,
|
|
152
|
+
manifest
|
|
153
|
+
};
|
|
154
|
+
mounts.set(root, mount);
|
|
155
|
+
return mount;
|
|
156
|
+
};
|
|
157
|
+
const ancestors = (path) => {
|
|
158
|
+
const dirs = [];
|
|
159
|
+
for (let dir = dirOf(path);; dir = dirOf(dir)) {
|
|
160
|
+
dirs.push(dir === "/" ? "" : dir);
|
|
161
|
+
if (dir === "/") return dirs;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
return { async get(name, importer) {
|
|
165
|
+
const files = importer.mount.files;
|
|
166
|
+
const dirs = ancestors(importer.path);
|
|
167
|
+
for (const dir of dirs) {
|
|
168
|
+
const m = await at(files, `${dir}/node_modules/${name}`, name);
|
|
169
|
+
if (m) return m;
|
|
170
|
+
}
|
|
171
|
+
for (const dir of dirs) {
|
|
172
|
+
const m = await at(files, `${dir}/node_modules/.pnpm/node_modules/${name}`, name);
|
|
173
|
+
if (m) return m;
|
|
174
|
+
}
|
|
175
|
+
} };
|
|
176
|
+
}
|
|
177
|
+
const DEPENDENCY_FIELDS = [
|
|
178
|
+
"dependencies",
|
|
179
|
+
"peerDependencies",
|
|
180
|
+
"optionalDependencies",
|
|
181
|
+
"devDependencies"
|
|
182
|
+
];
|
|
183
|
+
/** The version range `importer`'s `package.json` gives `name`, if any. */
|
|
184
|
+
function rangeFor(name, importer) {
|
|
185
|
+
const m = importer.mount.manifest;
|
|
186
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
187
|
+
const range = m?.[field]?.[name];
|
|
188
|
+
if (range) return range;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Packages fetched on demand (default: the npm registry, through webrun-modules'
|
|
193
|
+
* `npmRegistrySource`) and kept in memory: each one is its own FilesApi tree. The
|
|
194
|
+
* version is the range the importer's `package.json` declares (the project's for the
|
|
195
|
+
* project's files), else the latest; one range loads once.
|
|
196
|
+
*/
|
|
197
|
+
function npmPackages(opts = {}) {
|
|
198
|
+
let registry;
|
|
199
|
+
const source = opts.source ?? {
|
|
200
|
+
matches: (ref) => "pkg" in ref,
|
|
201
|
+
load: async (ref) => {
|
|
202
|
+
registry ??= import("@statewalker/webrun-modules").then((m) => m.npmRegistrySource());
|
|
203
|
+
return (await registry).load(ref);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const byRange = /* @__PURE__ */ new Map();
|
|
207
|
+
const byVersion = /* @__PURE__ */ new Map();
|
|
208
|
+
return { get(name, importer) {
|
|
209
|
+
const range = rangeFor(name, importer);
|
|
210
|
+
const key = `${name}@${range ?? "latest"}`;
|
|
211
|
+
let mount = byRange.get(key);
|
|
212
|
+
if (!mount) {
|
|
213
|
+
mount = source.load({
|
|
214
|
+
pkg: name,
|
|
215
|
+
version: range
|
|
216
|
+
}).then((p) => {
|
|
217
|
+
const prefix = mountPrefix(p.name, p.version);
|
|
218
|
+
const seen = byVersion.get(prefix);
|
|
219
|
+
if (seen) return seen;
|
|
220
|
+
const m = {
|
|
221
|
+
prefix,
|
|
222
|
+
files: p.files,
|
|
223
|
+
root: "/",
|
|
224
|
+
manifest: p.manifest
|
|
225
|
+
};
|
|
226
|
+
byVersion.set(prefix, m);
|
|
227
|
+
return m;
|
|
228
|
+
});
|
|
229
|
+
byRange.set(key, mount);
|
|
230
|
+
}
|
|
231
|
+
return mount;
|
|
232
|
+
} };
|
|
233
|
+
}
|
|
234
|
+
/** The first store that has the package wins (`node_modules` first, then the registry). */
|
|
235
|
+
function chainPackages(...stores) {
|
|
236
|
+
return { async get(name, importer) {
|
|
237
|
+
let failure;
|
|
238
|
+
for (const s of stores) try {
|
|
239
|
+
const m = await s.get(name, importer);
|
|
240
|
+
if (m) return m;
|
|
241
|
+
} catch (e) {
|
|
242
|
+
failure ??= e;
|
|
243
|
+
}
|
|
244
|
+
if (failure) throw failure;
|
|
245
|
+
} };
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/resolve.ts
|
|
249
|
+
/** Extensions tried, in order, for a path written without one (or with `.js` for a `.ts` file). */
|
|
250
|
+
const EXTENSIONS = [
|
|
251
|
+
".ts",
|
|
252
|
+
".tsx",
|
|
253
|
+
".mts",
|
|
254
|
+
".cts",
|
|
255
|
+
".js",
|
|
256
|
+
".jsx",
|
|
257
|
+
".mjs",
|
|
258
|
+
".cjs",
|
|
259
|
+
".json"
|
|
260
|
+
];
|
|
261
|
+
/** `path` as written, else with an extension, else its `index` file. */
|
|
262
|
+
async function resolveFile(mount, path) {
|
|
263
|
+
if (await isFile(mount, path)) return path;
|
|
264
|
+
const js = /\.(m|c)?jsx?$/.exec(path);
|
|
265
|
+
if (js) {
|
|
266
|
+
const base = path.slice(0, -js[0].length);
|
|
267
|
+
for (const ext of [`.${js[1] ?? ""}ts`, ".tsx"]) if (await isFile(mount, base + ext)) return base + ext;
|
|
268
|
+
}
|
|
269
|
+
for (const ext of EXTENSIONS) if (await isFile(mount, path + ext)) return path + ext;
|
|
270
|
+
const dir = path.endsWith("/") ? path.slice(0, -1) : path;
|
|
271
|
+
for (const ext of EXTENSIONS) if (await isFile(mount, `${dir}/index${ext}`)) return `${dir}/index${ext}`;
|
|
272
|
+
}
|
|
273
|
+
function exportsTarget(manifest, entry, c) {
|
|
274
|
+
try {
|
|
275
|
+
return exports(manifest, entry, {
|
|
276
|
+
conditions: c.conditions,
|
|
277
|
+
require: c.require,
|
|
278
|
+
browser: c.browser
|
|
279
|
+
})?.[0];
|
|
280
|
+
} catch {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/** A package's file for `subpath`: `exports` first, then `module`/`main` (and `browser` when it is a string). */
|
|
285
|
+
async function resolvePackageEntry(mount, subpath, c) {
|
|
286
|
+
const manifest = mount.manifest ?? {};
|
|
287
|
+
const entry = subpath ? `./${subpath}` : ".";
|
|
288
|
+
if (manifest.exports !== void 0) {
|
|
289
|
+
const target = exportsTarget(manifest, entry, c);
|
|
290
|
+
if (!target) return void 0;
|
|
291
|
+
return joinWithin(mount.root, mount.root, target);
|
|
292
|
+
}
|
|
293
|
+
if (subpath) return resolveFile(mount, joinWithin(mount.root, mount.root, subpath) ?? "");
|
|
294
|
+
const fields = [
|
|
295
|
+
...c.browser && typeof manifest.browser === "string" ? [manifest.browser] : [],
|
|
296
|
+
...c.require ? [] : [manifest.module],
|
|
297
|
+
manifest.main,
|
|
298
|
+
"index.js"
|
|
299
|
+
].filter((f) => typeof f === "string");
|
|
300
|
+
for (const f of fields) {
|
|
301
|
+
const p = joinWithin(mount.root, mount.root, f);
|
|
302
|
+
const file = p && await resolveFile(mount, p);
|
|
303
|
+
if (file) return file;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Resolves `spec` as written in `importer`: a path of the same tree (`./x`, `../y.js`,
|
|
308
|
+
* `/z`), a `#imports` alias of the importer's package, or a package found by `packages`
|
|
309
|
+
* (with its `exports`, `module` and `main`).
|
|
310
|
+
*/
|
|
311
|
+
async function resolveSpecifier(spec, importer, packages, c) {
|
|
312
|
+
const { mount } = importer;
|
|
313
|
+
if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/") || spec === ".") {
|
|
314
|
+
const base = spec.startsWith("/") ? mount.root : dirOf(importer.path);
|
|
315
|
+
const target = joinWithin(mount.root, base, spec.startsWith("/") ? spec.slice(1) : spec);
|
|
316
|
+
const path = target && await resolveFile(mount, target);
|
|
317
|
+
return path ? {
|
|
318
|
+
mount,
|
|
319
|
+
path
|
|
320
|
+
} : void 0;
|
|
321
|
+
}
|
|
322
|
+
if (spec.startsWith("#")) try {
|
|
323
|
+
const target = imports(mount.manifest ?? {}, spec, {
|
|
324
|
+
conditions: c.conditions,
|
|
325
|
+
require: c.require,
|
|
326
|
+
browser: c.browser
|
|
327
|
+
})?.[0];
|
|
328
|
+
if (!target) return void 0;
|
|
329
|
+
if (!target.startsWith(".")) return resolveSpecifier(target, importer, packages, c);
|
|
330
|
+
const path = joinWithin(mount.root, mount.root, target);
|
|
331
|
+
return path && await isFile(mount, path) ? {
|
|
332
|
+
mount,
|
|
333
|
+
path
|
|
334
|
+
} : void 0;
|
|
335
|
+
} catch {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const { name, subpath } = parsePackageSpecifier(spec);
|
|
339
|
+
const pkg = await packages.get(name, importer);
|
|
340
|
+
if (!pkg) return void 0;
|
|
341
|
+
const path = await resolvePackageEntry(pkg, subpath, c);
|
|
342
|
+
return path && await isFile(pkg, path) ? {
|
|
343
|
+
mount: pkg,
|
|
344
|
+
path
|
|
345
|
+
} : void 0;
|
|
346
|
+
}
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region src/bundle.ts
|
|
349
|
+
/** esbuild's namespace for the files the bundler serves; its source-map names drop it. */
|
|
350
|
+
const NS = "webrun";
|
|
351
|
+
/** esbuild's namespace for the host's modules (`modules`): `virtual:<specifier>` in maps. */
|
|
352
|
+
const VNS = "webrun-virtual";
|
|
353
|
+
/** Marks an `inject` entry, so that it resolves like an import, not like the entry point. */
|
|
354
|
+
const INJECT = "webrun-inject:";
|
|
355
|
+
/** esbuild `supported` flags that lower `await` to generators. */
|
|
356
|
+
const LOWER_AWAIT = {
|
|
357
|
+
"async-await": false,
|
|
358
|
+
"async-generator": false,
|
|
359
|
+
"for-await": false
|
|
360
|
+
};
|
|
361
|
+
const LOADERS = {
|
|
362
|
+
ts: "ts",
|
|
363
|
+
mts: "ts",
|
|
364
|
+
cts: "ts",
|
|
365
|
+
tsx: "tsx",
|
|
366
|
+
jsx: "jsx",
|
|
367
|
+
js: "js",
|
|
368
|
+
mjs: "js",
|
|
369
|
+
cjs: "js",
|
|
370
|
+
json: "json",
|
|
371
|
+
css: "css",
|
|
372
|
+
txt: "text",
|
|
373
|
+
wasm: "binary"
|
|
374
|
+
};
|
|
375
|
+
const loaderFor = (path) => LOADERS[/\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? ""] ?? "js";
|
|
376
|
+
const isExternal = (spec, patterns) => /^(https?:|data:)/.test(spec) || patterns.some((p) => typeof p === "string" ? p.endsWith("*") ? spec.startsWith(p.slice(0, -1)) : spec === p : p.test(spec));
|
|
377
|
+
/** A source name of esbuild's map → the file id it stands for. */
|
|
378
|
+
const sourceId = (s) => s.replace(/^(\.\.\/)*/, "").replace(new RegExp(`^${VNS}:`), "virtual:").replace(new RegExp(`^${NS}:`), "");
|
|
379
|
+
const toBase64 = (text) => {
|
|
380
|
+
const bytes = new TextEncoder().encode(text);
|
|
381
|
+
let bin = "";
|
|
382
|
+
for (let i = 0; i < bytes.length; i += 32768) bin += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
383
|
+
return btoa(bin);
|
|
384
|
+
};
|
|
385
|
+
/** `code` with its trailing map link replaced: by `map` inlined, or by a link to `name`. */
|
|
386
|
+
function linkMap(code, map, how, name) {
|
|
387
|
+
return `${code.replace(/\n?\/\/# sourceMappingURL=\S+\s*$/, "")}\n//# sourceMappingURL=${how === "inline" ? `data:application/json;base64,${toBase64(JSON.stringify(map))}` : `${name.split("/").pop()}.map`}\n`;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Bundles `entry` of a project into one module with esbuild (esbuild-wasm in browsers).
|
|
391
|
+
* Every file is read through FilesApi (the project's, or a package's from `packages`):
|
|
392
|
+
* esbuild resolves and loads nothing itself. esbuild transpiles TypeScript and JSX,
|
|
393
|
+
* converts CommonJS, lowers `await` when asked, and bundles, all in one pass, and its
|
|
394
|
+
* source map goes back through each step to the files it read; where a package ships
|
|
395
|
+
* its own map (TypeScript compiled to `.js`), to the package's original source. The
|
|
396
|
+
* map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.
|
|
397
|
+
*/
|
|
398
|
+
async function bundle(opts) {
|
|
399
|
+
const root = opts.root ?? "/";
|
|
400
|
+
const project = {
|
|
401
|
+
prefix: "~",
|
|
402
|
+
files: opts.files,
|
|
403
|
+
root,
|
|
404
|
+
manifest: await readManifest(opts.files, root)
|
|
405
|
+
};
|
|
406
|
+
const packages = opts.packages ?? nodeModulesPackages();
|
|
407
|
+
const external = opts.external ?? [];
|
|
408
|
+
const browser = (opts.platform ?? "browser") === "browser";
|
|
409
|
+
const conditions = opts.conditions ?? ["browser"];
|
|
410
|
+
const outfile = opts.outfile ?? "bundle.js";
|
|
411
|
+
const mounts = /* @__PURE__ */ new Map([[project.prefix, project]]);
|
|
412
|
+
const supplied = opts.modules;
|
|
413
|
+
const virtualSource = (spec) => typeof supplied === "function" ? supplied(spec) : supplied?.[spec];
|
|
414
|
+
/** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */
|
|
415
|
+
const locate = (id) => {
|
|
416
|
+
let best;
|
|
417
|
+
for (const m of mounts.values()) if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length)) best = m;
|
|
418
|
+
const path = best && pathOf(best, id);
|
|
419
|
+
if (!best || !path) throw new Error(`webrun-bundler: no file ${id}`);
|
|
420
|
+
return {
|
|
421
|
+
mount: best,
|
|
422
|
+
path
|
|
423
|
+
};
|
|
424
|
+
};
|
|
425
|
+
const plugin = {
|
|
426
|
+
name: "webrun-files",
|
|
427
|
+
setup(b) {
|
|
428
|
+
b.onResolve({ filter: /.*/ }, async (args) => {
|
|
429
|
+
const injected = args.path.startsWith(INJECT);
|
|
430
|
+
const spec = injected ? args.path.slice(14) : args.path;
|
|
431
|
+
if (args.kind === "entry-point" && !injected) {
|
|
432
|
+
const path = joinWithin(root, root, args.path.replace(/^\/+/, ""));
|
|
433
|
+
if (!path) return { errors: [{ text: `entry ${args.path} is outside the project` }] };
|
|
434
|
+
return {
|
|
435
|
+
path: idOf(project, path),
|
|
436
|
+
namespace: NS
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
if (virtualSource(spec) !== void 0) return {
|
|
440
|
+
path: spec,
|
|
441
|
+
namespace: VNS
|
|
442
|
+
};
|
|
443
|
+
if (isExternal(spec, external)) return {
|
|
444
|
+
path: spec,
|
|
445
|
+
external: true
|
|
446
|
+
};
|
|
447
|
+
const importer = injected || args.namespace === VNS ? {
|
|
448
|
+
mount: project,
|
|
449
|
+
path: `${root === "/" ? "" : root}/`
|
|
450
|
+
} : locate(args.importer);
|
|
451
|
+
const require = args.kind === "require-call" || args.kind === "require-resolve";
|
|
452
|
+
const failed = (why) => ({ errors: [{ text: `Could not resolve "${spec}" (imported by ${args.importer || "inject"})${why ? `: ${why}` : ""}` }] });
|
|
453
|
+
let r;
|
|
454
|
+
try {
|
|
455
|
+
r = await resolveSpecifier(spec, importer, packages, {
|
|
456
|
+
conditions,
|
|
457
|
+
require,
|
|
458
|
+
browser
|
|
459
|
+
});
|
|
460
|
+
} catch (e) {
|
|
461
|
+
return failed(e?.message ?? String(e));
|
|
462
|
+
}
|
|
463
|
+
if (!r) return failed();
|
|
464
|
+
mounts.set(r.mount.prefix, r.mount);
|
|
465
|
+
return {
|
|
466
|
+
path: idOf(r.mount, r.path),
|
|
467
|
+
namespace: NS
|
|
468
|
+
};
|
|
469
|
+
});
|
|
470
|
+
b.onLoad({
|
|
471
|
+
filter: /.*/,
|
|
472
|
+
namespace: VNS
|
|
473
|
+
}, (args) => ({
|
|
474
|
+
contents: virtualSource(args.path) ?? "",
|
|
475
|
+
loader: "js"
|
|
476
|
+
}));
|
|
477
|
+
b.onLoad({
|
|
478
|
+
filter: /.*/,
|
|
479
|
+
namespace: NS
|
|
480
|
+
}, async (args) => {
|
|
481
|
+
const { mount, path } = locate(args.path);
|
|
482
|
+
const loader = loaderFor(path);
|
|
483
|
+
if (loader === "binary") {
|
|
484
|
+
const chunks = [];
|
|
485
|
+
for await (const c of mount.files.read(path)) chunks.push(c);
|
|
486
|
+
const bytes = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
|
|
487
|
+
let at = 0;
|
|
488
|
+
for (const c of chunks) {
|
|
489
|
+
bytes.set(c, at);
|
|
490
|
+
at += c.length;
|
|
491
|
+
}
|
|
492
|
+
return {
|
|
493
|
+
contents: bytes,
|
|
494
|
+
loader
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
const text = await readText(mount.files, path);
|
|
498
|
+
return {
|
|
499
|
+
contents: loader === "js" || loader === "ts" || loader === "jsx" || loader === "tsx" ? await inlineInputMap(mount, path, text) : text,
|
|
500
|
+
loader
|
|
501
|
+
};
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
const { plugins: extraPlugins = [], ...rest } = opts.esbuildOptions ?? {};
|
|
506
|
+
const result = await opts.esbuild.build({
|
|
507
|
+
entryPoints: [opts.entry],
|
|
508
|
+
bundle: true,
|
|
509
|
+
write: false,
|
|
510
|
+
format: opts.format ?? "esm",
|
|
511
|
+
platform: opts.platform ?? "browser",
|
|
512
|
+
target: opts.target ?? "es2022",
|
|
513
|
+
outfile,
|
|
514
|
+
absWorkingDir: "/",
|
|
515
|
+
metafile: true,
|
|
516
|
+
logLevel: "silent",
|
|
517
|
+
minify: opts.minify,
|
|
518
|
+
define: opts.define,
|
|
519
|
+
...opts.lowerAwait ? { supported: LOWER_AWAIT } : {},
|
|
520
|
+
...rest,
|
|
521
|
+
...opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {},
|
|
522
|
+
sourcemap: "external",
|
|
523
|
+
sourcesContent: true,
|
|
524
|
+
plugins: [...extraPlugins, plugin]
|
|
525
|
+
});
|
|
526
|
+
const out = result.outputFiles ?? [];
|
|
527
|
+
const jsFile = out.find((f) => !f.path.endsWith(".map"));
|
|
528
|
+
const mapFile = out.find((f) => f.path.endsWith(".map"));
|
|
529
|
+
if (!jsFile || !mapFile) throw new Error("webrun-bundler: esbuild produced no output");
|
|
530
|
+
const raw = JSON.parse(mapFile.text);
|
|
531
|
+
const map = {
|
|
532
|
+
...raw,
|
|
533
|
+
file: outfile.split("/").pop(),
|
|
534
|
+
sources: raw.sources.map(sourceId)
|
|
535
|
+
};
|
|
536
|
+
delete map.sourceRoot;
|
|
537
|
+
return {
|
|
538
|
+
code: linkMap(jsFile.text, map, opts.sourcemap ?? "external", outfile),
|
|
539
|
+
map,
|
|
540
|
+
metafile: result.metafile,
|
|
541
|
+
warnings: result.warnings
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Transpiles one file (TypeScript, JSX, modern syntax down to `target`; `await` lowered
|
|
546
|
+
* when asked) with a source map back to it. A map the code carries (`sourceMappingURL`,
|
|
547
|
+
* inline) is composed in, so the result still traces to the original.
|
|
548
|
+
*/
|
|
549
|
+
async function transpile(code, opts) {
|
|
550
|
+
const r = await opts.esbuild.transform(code, {
|
|
551
|
+
loader: loaderFor(opts.path),
|
|
552
|
+
sourcefile: opts.path,
|
|
553
|
+
sourcemap: "external",
|
|
554
|
+
sourcesContent: true,
|
|
555
|
+
format: opts.format,
|
|
556
|
+
target: opts.target ?? "es2022",
|
|
557
|
+
minify: opts.minify,
|
|
558
|
+
define: opts.define,
|
|
559
|
+
...opts.lowerAwait ? { supported: LOWER_AWAIT } : {}
|
|
560
|
+
});
|
|
561
|
+
const map = JSON.parse(r.map);
|
|
562
|
+
return {
|
|
563
|
+
code: linkMap(r.code, map, opts.sourcemap ?? "external", opts.path.replace(/\.[^./]+$/, ".js")),
|
|
564
|
+
map,
|
|
565
|
+
warnings: r.warnings
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
//#endregion
|
|
569
|
+
export { bundle, chainPackages, inlineInputMap, loaderFor, nodeModulesPackages, npmPackages, resolveSpecifier, transpile };
|
|
570
|
+
|
|
571
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["toBase64","resolvePackageExports","resolveImports"],"sources":["../src/paths.ts","../src/input-maps.ts","../src/packages.ts","../src/resolve.ts","../src/bundle.ts"],"sourcesContent":["import { normalizePath, tryReadText } from \"@statewalker/webrun-files\";\nimport type { Mount, PackageManifest } from \"./types.js\";\n\n/** `path` joined to `dir`, with `.` and `..` resolved; `undefined` when it leaves `root`. */\nexport function joinWithin(root: string, dir: string, path: string): string | undefined {\n const parts = (path.startsWith(\"/\") ? path : `${dir}/${path}`).split(\"/\");\n const out: string[] = [];\n for (const p of parts) {\n if (!p || p === \".\") continue;\n if (p === \"..\") {\n if (!out.length) return undefined;\n out.pop();\n } else out.push(p);\n }\n const joined = `/${out.join(\"/\")}`;\n const r = normalizePath(root);\n return r === \"/\" || joined === r || joined.startsWith(`${r}/`) ? joined : undefined;\n}\n\nexport const dirOf = (path: string) => path.slice(0, path.lastIndexOf(\"/\")) || \"/\";\n\n/** The id of a mount's file: `<prefix>/<path below root>`. */\nexport function idOf(mount: Mount, path: string): string {\n const r = normalizePath(mount.root);\n const rel = r === \"/\" ? path : path.slice(r.length);\n return `${mount.prefix}${rel || \"/\"}`;\n}\n\n/** A mount's file from its id; `undefined` when the id is not the mount's. */\nexport function pathOf(mount: Mount, id: string): string | undefined {\n if (!id.startsWith(`${mount.prefix}/`)) return undefined;\n const r = normalizePath(mount.root);\n const rel = id.slice(mount.prefix.length);\n return r === \"/\" ? rel : `${r}${rel}`;\n}\n\nexport async function isFile(mount: Mount, path: string): Promise<boolean> {\n const s = await mount.files.stats(path);\n return s?.kind === \"file\";\n}\n\nexport async function readManifest(\n files: Mount[\"files\"],\n dir: string,\n): Promise<PackageManifest | undefined> {\n const text = await tryReadText(files, `${dir === \"/\" ? \"\" : dir}/package.json`);\n if (text === undefined) return undefined;\n try {\n return JSON.parse(text) as PackageManifest;\n } catch {\n return undefined;\n }\n}\n\n/** `react` → `{ name: \"react\" }`; `@a/b/c.js` → `{ name: \"@a/b\", subpath: \"c.js\" }`. */\nexport function parsePackageSpecifier(spec: string): { name: string; subpath?: string } {\n const parts = spec.split(\"/\");\n const n = spec.startsWith(\"@\") ? 2 : 1;\n const name = parts.slice(0, n).join(\"/\");\n const subpath = parts.slice(n).join(\"/\");\n return subpath ? { name, subpath } : { name };\n}\n","import { tryReadText } from \"@statewalker/webrun-files\";\nimport { dirOf, idOf, joinWithin } from \"./paths.js\";\nimport type { Mount, SourceMap } from \"./types.js\";\n\n// The last `//# sourceMappingURL=…` (or `//@`) comment of a JS file.\nconst MAP_COMMENT = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\nconst fromBase64 = (b64: string) =>\n new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));\n\n/**\n * A file's own source map, made usable by esbuild, which reads only maps inlined in\n * the file it loads (it cannot follow a linked `.map` through a FilesApi):\n *\n * - a linked map (`//# sourceMappingURL=index.js.map`) is read from the same tree and\n * inlined; an inline `data:` map is kept;\n * - its sources become ids of the same tree (`npm:pkg@1.0.0/src/index.ts`), so the\n * bundle's map names the package's original files, not the published JavaScript;\n * - missing `sourcesContent` is filled from the tree when the original file ships\n * with the package.\n *\n * esbuild then composes it with its own: a bundled line traces to the original source.\n * A map that is missing or unreadable is dropped (the file maps to itself).\n */\nexport async function inlineInputMap(mount: Mount, path: string, code: string): Promise<string> {\n const lines = code.trimEnd().split(\"\\n\");\n const last = lines[lines.length - 1] ?? \"\";\n const match = MAP_COMMENT.exec(last);\n if (!match) return code;\n const url = match[1] as string;\n const body = lines.slice(0, -1).join(\"\\n\");\n let text: string | undefined;\n let mapDir = dirOf(path);\n if (url.startsWith(\"data:\")) {\n const comma = url.indexOf(\",\");\n const meta = url.slice(5, comma);\n const payload = url.slice(comma + 1);\n try {\n text = meta.endsWith(\";base64\") ? fromBase64(payload) : decodeURIComponent(payload);\n } catch {\n text = undefined;\n }\n } else if (!/^[a-z][a-z0-9+.-]*:/i.test(url)) {\n const mapPath = joinWithin(mount.root, dirOf(path), decodeURIComponent(url));\n if (mapPath) {\n text = await tryReadText(mount.files, mapPath);\n mapDir = dirOf(mapPath);\n }\n }\n let map: SourceMap;\n try {\n map = JSON.parse(text ?? \"\") as SourceMap;\n } catch {\n return body; // no usable map: the file is its own source\n }\n const sourceDir = map.sourceRoot\n ? (joinWithin(\"/\", mapDir, map.sourceRoot.replace(/\\/$/, \"\")) ?? mapDir)\n : mapDir;\n const contents: (string | null)[] = map.sourcesContent ? [...map.sourcesContent] : [];\n const sources: string[] = [];\n for (let i = 0; i < map.sources.length; i++) {\n const src = map.sources[i] as string;\n const local = /^[a-z][a-z0-9+.-]*:/i.test(src)\n ? undefined\n : joinWithin(mount.root, sourceDir, src);\n sources.push(local ? idOf(mount, local) : src);\n if (contents[i] == null && local) contents[i] = (await tryReadText(mount.files, local)) ?? null;\n }\n const fixed: SourceMap = { ...map, sources, sourcesContent: contents };\n delete fixed.sourceRoot;\n return `${body}\\n//# sourceMappingURL=data:application/json;base64,${toBase64(JSON.stringify(fixed))}\\n`;\n}\n","import type { Source } from \"@statewalker/webrun-modules\";\nimport { dirOf, readManifest } from \"./paths.js\";\nimport type { Importer, Mount, PackageStore } from \"./types.js\";\n\nconst mountPrefix = (name: string, version: string | undefined) =>\n `npm:${name}@${version ?? \"0.0.0\"}`;\n\n/**\n * Packages from `node_modules` folders, found as Node finds them: in the importing\n * file's directory and each parent, inside the importer's own FilesApi. A package\n * installed in the project (or in another package's `node_modules`) is read where it is.\n *\n * pnpm layouts: a package's own dependencies sit next to its real directory in\n * `node_modules/.pnpm`, which Node reaches through the symlink's real path and a FilesApi\n * cannot see. When the walk finds nothing, each ancestor's `node_modules/.pnpm/node_modules`\n * (pnpm's hoisted links to every installed package) is tried too.\n */\nexport function nodeModulesPackages(): PackageStore {\n const mounts = new Map<string, Mount>();\n const at = async (files: Mount[\"files\"], root: string, name: string) => {\n const known = mounts.get(root);\n if (known && known.files === files) return known;\n const manifest = await readManifest(files, root);\n if (!manifest) return undefined;\n const mount: Mount = { prefix: mountPrefix(name, manifest.version), files, root, manifest };\n mounts.set(root, mount);\n return mount;\n };\n const ancestors = (path: string) => {\n const dirs: string[] = [];\n for (let dir = dirOf(path); ; dir = dirOf(dir)) {\n dirs.push(dir === \"/\" ? \"\" : dir);\n if (dir === \"/\") return dirs;\n }\n };\n return {\n async get(name, importer) {\n const files = importer.mount.files;\n const dirs = ancestors(importer.path);\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/${name}`, name);\n if (m) return m;\n }\n for (const dir of dirs) {\n const m = await at(files, `${dir}/node_modules/.pnpm/node_modules/${name}`, name);\n if (m) return m;\n }\n return undefined;\n },\n };\n}\n\nconst DEPENDENCY_FIELDS = [\n \"dependencies\",\n \"peerDependencies\",\n \"optionalDependencies\",\n \"devDependencies\",\n] as const;\n\n/** The version range `importer`'s `package.json` gives `name`, if any. */\nfunction rangeFor(name: string, importer: Importer): string | undefined {\n const m = importer.mount.manifest;\n for (const field of DEPENDENCY_FIELDS) {\n const range = m?.[field]?.[name];\n if (range) return range;\n }\n return undefined;\n}\n\n/**\n * Packages fetched on demand (default: the npm registry, through webrun-modules'\n * `npmRegistrySource`) and kept in memory: each one is its own FilesApi tree. The\n * version is the range the importer's `package.json` declares (the project's for the\n * project's files), else the latest; one range loads once.\n */\nexport function npmPackages(opts: { source?: Source } = {}): PackageStore {\n // Loaded only when used: a bundle of the bundler that brings its own source stays small.\n let registry: Promise<Source> | undefined;\n const source: Source = opts.source ?? {\n matches: (ref) => \"pkg\" in ref,\n load: async (ref) => {\n registry ??= import(\"@statewalker/webrun-modules\").then((m) => m.npmRegistrySource());\n return (await registry).load(ref);\n },\n };\n const byRange = new Map<string, Promise<Mount>>();\n const byVersion = new Map<string, Mount>();\n return {\n get(name, importer) {\n const range = rangeFor(name, importer);\n const key = `${name}@${range ?? \"latest\"}`;\n let mount = byRange.get(key);\n if (!mount) {\n mount = source.load({ pkg: name, version: range }).then((p) => {\n const prefix = mountPrefix(p.name, p.version);\n const seen = byVersion.get(prefix);\n if (seen) return seen; // two ranges, one version: one copy of the package\n const m: Mount = { prefix, files: p.files, root: \"/\", manifest: p.manifest };\n byVersion.set(prefix, m);\n return m;\n });\n byRange.set(key, mount);\n }\n return mount;\n },\n };\n}\n\n/** The first store that has the package wins (`node_modules` first, then the registry). */\nexport function chainPackages(...stores: PackageStore[]): PackageStore {\n return {\n async get(name, importer) {\n let failure: unknown;\n for (const s of stores) {\n try {\n const m = await s.get(name, importer);\n if (m) return m;\n } catch (e) {\n failure ??= e; // the next store may still have it\n }\n }\n if (failure) throw failure;\n return undefined;\n },\n };\n}\n","import { imports as resolveImports, exports as resolvePackageExports } from \"resolve.exports\";\nimport { dirOf, isFile, joinWithin, parsePackageSpecifier } from \"./paths.js\";\nimport type { Importer, Mount, PackageManifest, PackageStore } from \"./types.js\";\n\n/** Extensions tried, in order, for a path written without one (or with `.js` for a `.ts` file). */\nconst EXTENSIONS = [\".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".json\"];\n\nexport interface Resolved {\n mount: Mount;\n path: string;\n}\n\n/** `path` as written, else with an extension, else its `index` file. */\nasync function resolveFile(mount: Mount, path: string): Promise<string | undefined> {\n if (await isFile(mount, path)) return path;\n // TypeScript sources import `./x.js` for `./x.ts`.\n const js = /\\.(m|c)?jsx?$/.exec(path);\n if (js) {\n const base = path.slice(0, -js[0].length);\n for (const ext of [`.${js[1] ?? \"\"}ts`, \".tsx\"])\n if (await isFile(mount, base + ext)) return base + ext;\n }\n for (const ext of EXTENSIONS) if (await isFile(mount, path + ext)) return path + ext;\n const dir = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n for (const ext of EXTENSIONS)\n if (await isFile(mount, `${dir}/index${ext}`)) return `${dir}/index${ext}`;\n return undefined;\n}\n\ntype Conditions = { conditions: string[]; require: boolean; browser: boolean };\n\nfunction exportsTarget(\n manifest: PackageManifest,\n entry: string,\n c: Conditions,\n): string | undefined {\n try {\n const out = resolvePackageExports(manifest, entry, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n return out?.[0];\n } catch {\n return undefined;\n }\n}\n\n/** A package's file for `subpath`: `exports` first, then `module`/`main` (and `browser` when it is a string). */\nasync function resolvePackageEntry(\n mount: Mount,\n subpath: string | undefined,\n c: Conditions,\n): Promise<string | undefined> {\n const manifest = mount.manifest ?? {};\n const entry = subpath ? `./${subpath}` : \".\";\n if (manifest.exports !== undefined) {\n const target = exportsTarget(manifest, entry, c);\n if (!target) return undefined; // not exported: Node refuses it as well\n return joinWithin(mount.root, mount.root, target);\n }\n if (subpath) return resolveFile(mount, joinWithin(mount.root, mount.root, subpath) ?? \"\");\n const fields = [\n ...(c.browser && typeof manifest.browser === \"string\" ? [manifest.browser] : []),\n ...(c.require ? [] : [manifest.module]),\n manifest.main,\n \"index.js\",\n ].filter((f): f is string => typeof f === \"string\");\n for (const f of fields) {\n const p = joinWithin(mount.root, mount.root, f);\n const file = p && (await resolveFile(mount, p));\n if (file) return file;\n }\n return undefined;\n}\n\n/**\n * Resolves `spec` as written in `importer`: a path of the same tree (`./x`, `../y.js`,\n * `/z`), a `#imports` alias of the importer's package, or a package found by `packages`\n * (with its `exports`, `module` and `main`).\n */\nexport async function resolveSpecifier(\n spec: string,\n importer: Importer,\n packages: PackageStore,\n c: Conditions,\n): Promise<Resolved | undefined> {\n const { mount } = importer;\n if (spec.startsWith(\"./\") || spec.startsWith(\"../\") || spec.startsWith(\"/\") || spec === \".\") {\n const base = spec.startsWith(\"/\") ? mount.root : dirOf(importer.path);\n const target = joinWithin(mount.root, base, spec.startsWith(\"/\") ? spec.slice(1) : spec);\n const path = target && (await resolveFile(mount, target));\n return path ? { mount, path } : undefined;\n }\n if (spec.startsWith(\"#\")) {\n try {\n const out = resolveImports(mount.manifest ?? {}, spec, {\n conditions: c.conditions,\n require: c.require,\n browser: c.browser,\n }) as string[] | undefined;\n const target = out?.[0];\n if (!target) return undefined;\n if (!target.startsWith(\".\")) return resolveSpecifier(target, importer, packages, c);\n const path = joinWithin(mount.root, mount.root, target);\n return path && (await isFile(mount, path)) ? { mount, path } : undefined;\n } catch {\n return undefined;\n }\n }\n const { name, subpath } = parsePackageSpecifier(spec);\n const pkg = await packages.get(name, importer);\n if (!pkg) return undefined;\n const path = await resolvePackageEntry(pkg, subpath, c);\n return path && (await isFile(pkg, path)) ? { mount: pkg, path } : undefined;\n}\n","import { readText } from \"@statewalker/webrun-files\";\nimport type { Loader, Plugin } from \"esbuild-wasm\";\nimport { inlineInputMap } from \"./input-maps.js\";\nimport { nodeModulesPackages } from \"./packages.js\";\nimport { idOf, joinWithin, pathOf, readManifest } from \"./paths.js\";\nimport { resolveSpecifier } from \"./resolve.js\";\nimport type {\n BundleOptions,\n BundleResult,\n ExternalPattern,\n Mount,\n SourceMap,\n TranspileOptions,\n TranspileResult,\n} from \"./types.js\";\n\n/** esbuild's namespace for the files the bundler serves; its source-map names drop it. */\nconst NS = \"webrun\";\n/** esbuild's namespace for the host's modules (`modules`): `virtual:<specifier>` in maps. */\nconst VNS = \"webrun-virtual\";\n/** Marks an `inject` entry, so that it resolves like an import, not like the entry point. */\nconst INJECT = \"webrun-inject:\";\n\n/** esbuild `supported` flags that lower `await` to generators. */\nconst LOWER_AWAIT = { \"async-await\": false, \"async-generator\": false, \"for-await\": false };\n\nconst LOADERS: Record<string, Loader> = {\n ts: \"ts\",\n mts: \"ts\",\n cts: \"ts\",\n tsx: \"tsx\",\n jsx: \"jsx\",\n js: \"js\",\n mjs: \"js\",\n cjs: \"js\",\n json: \"json\",\n css: \"css\",\n txt: \"text\",\n wasm: \"binary\",\n};\nexport const loaderFor = (path: string): Loader =>\n LOADERS[/\\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? \"\"] ?? \"js\";\n\nconst isExternal = (spec: string, patterns: ExternalPattern[]) =>\n /^(https?:|data:)/.test(spec) ||\n patterns.some((p) =>\n typeof p === \"string\"\n ? p.endsWith(\"*\")\n ? spec.startsWith(p.slice(0, -1))\n : spec === p\n : p.test(spec),\n );\n\n/** A source name of esbuild's map → the file id it stands for. */\nconst sourceId = (s: string) =>\n s\n .replace(/^(\\.\\.\\/)*/, \"\")\n .replace(new RegExp(`^${VNS}:`), \"virtual:\")\n .replace(new RegExp(`^${NS}:`), \"\");\n\nconst toBase64 = (text: string) => {\n const bytes = new TextEncoder().encode(text);\n let bin = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000)\n bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return btoa(bin);\n};\n\n/** `code` with its trailing map link replaced: by `map` inlined, or by a link to `name`. */\nfunction linkMap(code: string, map: SourceMap, how: \"external\" | \"inline\", name: string) {\n const body = code.replace(/\\n?\\/\\/# sourceMappingURL=\\S+\\s*$/, \"\");\n const url =\n how === \"inline\"\n ? `data:application/json;base64,${toBase64(JSON.stringify(map))}`\n : `${name.split(\"/\").pop()}.map`;\n return `${body}\\n//# sourceMappingURL=${url}\\n`;\n}\n\n/**\n * Bundles `entry` of a project into one module with esbuild (esbuild-wasm in browsers).\n * Every file is read through FilesApi (the project's, or a package's from `packages`):\n * esbuild resolves and loads nothing itself. esbuild transpiles TypeScript and JSX,\n * converts CommonJS, lowers `await` when asked, and bundles, all in one pass, and its\n * source map goes back through each step to the files it read; where a package ships\n * its own map (TypeScript compiled to `.js`), to the package's original source. The\n * map's sources are file ids: `~/src/app.ts`, `npm:pkg@1.2.3/src/index.ts`.\n */\nexport async function bundle(opts: BundleOptions): Promise<BundleResult> {\n const root = opts.root ?? \"/\";\n const project: Mount = {\n prefix: \"~\",\n files: opts.files,\n root,\n manifest: await readManifest(opts.files, root),\n };\n const packages = opts.packages ?? nodeModulesPackages();\n const external = opts.external ?? [];\n const browser = (opts.platform ?? \"browser\") === \"browser\";\n const conditions = opts.conditions ?? [\"browser\"];\n const outfile = opts.outfile ?? \"bundle.js\";\n const mounts = new Map<string, Mount>([[project.prefix, project]]);\n const supplied = opts.modules;\n const virtualSource = (spec: string) =>\n typeof supplied === \"function\" ? supplied(spec) : supplied?.[spec];\n\n /** The mount and path of a file id; the longest prefix wins (`npm:@a/b@1.0.0/…`). */\n const locate = (id: string) => {\n let best: Mount | undefined;\n for (const m of mounts.values())\n if (id.startsWith(`${m.prefix}/`) && (!best || m.prefix.length > best.prefix.length))\n best = m;\n const path = best && pathOf(best, id);\n if (!best || !path) throw new Error(`webrun-bundler: no file ${id}`);\n return { mount: best, path };\n };\n\n const plugin: Plugin = {\n name: \"webrun-files\",\n setup(b) {\n b.onResolve({ filter: /.*/ }, async (args) => {\n const injected = args.path.startsWith(INJECT);\n const spec = injected ? args.path.slice(INJECT.length) : args.path;\n if (args.kind === \"entry-point\" && !injected) {\n const path = joinWithin(root, root, args.path.replace(/^\\/+/, \"\"));\n if (!path) return { errors: [{ text: `entry ${args.path} is outside the project` }] };\n return { path: idOf(project, path), namespace: NS };\n }\n if (virtualSource(spec) !== undefined) return { path: spec, namespace: VNS };\n if (isExternal(spec, external)) return { path: spec, external: true };\n // The host's modules and `inject` entries import from the project's root.\n const importer =\n injected || args.namespace === VNS\n ? { mount: project, path: `${root === \"/\" ? \"\" : root}/` }\n : locate(args.importer);\n const require = args.kind === \"require-call\" || args.kind === \"require-resolve\";\n const failed = (why?: string) => ({\n errors: [\n {\n text: `Could not resolve \"${spec}\" (imported by ${args.importer || \"inject\"})${why ? `: ${why}` : \"\"}`,\n },\n ],\n });\n let r: Awaited<ReturnType<typeof resolveSpecifier>>;\n try {\n r = await resolveSpecifier(spec, importer, packages, {\n conditions,\n require,\n browser,\n });\n } catch (e) {\n return failed((e as Error)?.message ?? String(e));\n }\n if (!r) return failed();\n mounts.set(r.mount.prefix, r.mount);\n return { path: idOf(r.mount, r.path), namespace: NS };\n });\n b.onLoad({ filter: /.*/, namespace: VNS }, (args) => ({\n contents: virtualSource(args.path) ?? \"\",\n loader: \"js\",\n }));\n b.onLoad({ filter: /.*/, namespace: NS }, async (args) => {\n const { mount, path } = locate(args.path);\n const loader = loaderFor(path);\n if (loader === \"binary\") {\n const chunks: Uint8Array[] = [];\n for await (const c of mount.files.read(path)) chunks.push(c);\n const bytes = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let at = 0;\n for (const c of chunks) {\n bytes.set(c, at);\n at += c.length;\n }\n return { contents: bytes, loader };\n }\n const text = await readText(mount.files, path);\n const js = loader === \"js\" || loader === \"ts\" || loader === \"jsx\" || loader === \"tsx\";\n return { contents: js ? await inlineInputMap(mount, path, text) : text, loader };\n });\n },\n };\n\n const { plugins: extraPlugins = [], ...rest } = opts.esbuildOptions ?? {};\n const result = await opts.esbuild.build({\n entryPoints: [opts.entry],\n bundle: true,\n write: false,\n format: opts.format ?? \"esm\",\n platform: opts.platform ?? \"browser\",\n target: opts.target ?? \"es2022\",\n outfile,\n absWorkingDir: \"/\",\n metafile: true,\n logLevel: \"silent\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n ...rest,\n ...(opts.inject?.length ? { inject: opts.inject.map((s) => INJECT + s) } : {}),\n sourcemap: \"external\",\n sourcesContent: true,\n plugins: [...extraPlugins, plugin],\n });\n const out = result.outputFiles ?? [];\n const jsFile = out.find((f) => !f.path.endsWith(\".map\"));\n const mapFile = out.find((f) => f.path.endsWith(\".map\"));\n if (!jsFile || !mapFile) throw new Error(\"webrun-bundler: esbuild produced no output\");\n const raw = JSON.parse(mapFile.text) as SourceMap;\n const map: SourceMap = {\n ...raw,\n file: outfile.split(\"/\").pop(),\n sources: raw.sources.map(sourceId),\n };\n delete map.sourceRoot;\n return {\n code: linkMap(jsFile.text, map, opts.sourcemap ?? \"external\", outfile),\n map,\n metafile: result.metafile as BundleResult[\"metafile\"],\n warnings: result.warnings,\n };\n}\n\n/**\n * Transpiles one file (TypeScript, JSX, modern syntax down to `target`; `await` lowered\n * when asked) with a source map back to it. A map the code carries (`sourceMappingURL`,\n * inline) is composed in, so the result still traces to the original.\n */\nexport async function transpile(code: string, opts: TranspileOptions): Promise<TranspileResult> {\n const r = await opts.esbuild.transform(code, {\n loader: loaderFor(opts.path),\n sourcefile: opts.path,\n sourcemap: \"external\",\n sourcesContent: true,\n format: opts.format,\n target: opts.target ?? \"es2022\",\n minify: opts.minify,\n define: opts.define,\n ...(opts.lowerAwait ? { supported: LOWER_AWAIT } : {}),\n });\n const map = JSON.parse(r.map) as SourceMap;\n return {\n code: linkMap(r.code, map, opts.sourcemap ?? \"external\", opts.path.replace(/\\.[^./]+$/, \".js\")),\n map,\n warnings: r.warnings,\n };\n}\n"],"mappings":"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"}
|