@vmz/vmz 0.3.12 → 0.3.13

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.
Files changed (51) hide show
  1. package/delivery-runtime-files.json +1 -0
  2. package/dist/cli/cli.js +46 -23
  3. package/dist/cli/format-cmd.d.ts +9 -17
  4. package/dist/cli/format-cmd.js +37 -49
  5. package/dist/cli/format-config.d.ts +6 -9
  6. package/dist/cli/format-config.js +5 -29
  7. package/dist/delivery/delivery-profile.js +1 -1
  8. package/dist/dev/dev-session.js +16 -5
  9. package/dist/document/document-base-css.d.ts +15 -0
  10. package/dist/document/document-base-css.js +578 -0
  11. package/dist/document/document-build.d.ts +1 -0
  12. package/dist/document/document-build.js +94 -78
  13. package/dist/document/document-client.d.ts +13 -0
  14. package/dist/document/document-client.js +217 -0
  15. package/dist/document/document-cmd.js +3 -1
  16. package/dist/document/document-designs.d.ts +9 -3
  17. package/dist/document/document-designs.js +20 -34
  18. package/dist/document/document-enrich.d.ts +9 -0
  19. package/dist/document/document-enrich.js +55 -0
  20. package/dist/document/document-highlight.d.ts +26 -0
  21. package/dist/document/document-highlight.js +54 -0
  22. package/dist/document/document-integrate.d.ts +5 -0
  23. package/dist/document/document-integrate.js +1 -0
  24. package/dist/document/document-interactive.js +10 -2
  25. package/dist/document/document-layout-render.js +6 -2
  26. package/dist/document/document-schema.d.ts +5 -0
  27. package/dist/workspace/build-assemble.js +18 -6
  28. package/dist/workspace/content-addressed-assets.d.ts +6 -17
  29. package/dist/workspace/content-addressed-assets.js +10 -95
  30. package/dist/workspace/delivery-runtime-imports.js +3 -0
  31. package/dist/workspace/native-addon.d.ts +4 -0
  32. package/dist/workspace/pack-native.d.ts +139 -0
  33. package/dist/workspace/pack-native.js +273 -0
  34. package/dist/workspace/pack.d.ts +112 -32
  35. package/dist/workspace/pack.js +270 -65
  36. package/dist/workspace/plugin-host.d.ts +4 -4
  37. package/dist/workspace/plugin-host.js +6 -6
  38. package/dist/workspace/production-observability.d.ts +2 -0
  39. package/dist/workspace/production-observability.js +6 -2
  40. package/dist/workspace/project-build.js +26 -4
  41. package/dist/workspace/public-api.d.ts +7 -3
  42. package/dist/workspace/public-api.js +5 -3
  43. package/dist/workspace/static-emit.d.ts +30 -0
  44. package/dist/workspace/static-emit.js +211 -18
  45. package/dist/workspace/user-config.d.ts +112 -0
  46. package/dist/workspace/user-config.js +12 -0
  47. package/host-runtime-files.json +1 -0
  48. package/locales/en-US/cli.json +5 -4
  49. package/package.json +20 -20
  50. package/dist/workspace/pack-client-packages.d.ts +0 -34
  51. package/dist/workspace/pack-client-packages.js +0 -550
@@ -1,550 +0,0 @@
1
- /**
2
- * Browser-safe client package lowering (Pack stage thin slice).
3
- *
4
- * Bare npm/workspace imports are legal on the author surface (01/04).
5
- * Browser ESM cannot resolve them. Pack materializes reachable package
6
- * modules under `dist/vendor/<pkg>/…` and rewrites importers to relative paths
7
- * via a bounded rewrite of generated module syntax. Pack must not re-enter the
8
- * parser pipeline for every emitted JavaScript file.
9
- *
10
- * This stage is only that thin slice. Linking, dead-code elimination, chunk
11
- * splitting, and minification are NOT implemented here — the pack manifest
12
- * reports their absence rather than a placeholder backend.
13
- */
14
- import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from 'node:fs';
15
- import path from 'node:path';
16
- import { createRequire } from 'node:module';
17
- import { resolvePackageRoot } from './packages.js';
18
- import { requireNativeAddon } from './native-addon.js';
19
- const VENDOR_DIR = 'vendor';
20
- const SKIP_PREFIXES = ['node:', 'nodejs:', 'cloudflare:', 'data:', 'http:', 'https:', 'vmz:', '#'];
21
- const STYLE_EXT = /\.css$/i;
22
- /** `new URL('<file>', import.meta.url)` — runtime assets a vendored module loads itself. */
23
- const IMPORT_META_URL_RE = /\bnew\s+URL\s*\(\s*(['"])([^'"\n]+)\1\s*,\s*import\.meta\.url\s*\)/g;
24
- /** `url(<file>)` inside a vendored stylesheet. */
25
- const CSS_URL_RE = /\burl\s*\(\s*(['"]?)([^'")\n]+)\1\s*\)/g;
26
- export function packClientBareImports(outDir, opts = {}) {
27
- const projectRoot = opts.projectRoot ? path.resolve(opts.projectRoot) : path.dirname(path.resolve(outDir));
28
- /** @type {Map<string, string>} bareSpec → absolute vendored .js path */
29
- const bareToVendor = new Map();
30
- /** @type {Set<string>} absolute source files already materialized */
31
- const materializedSources = new Set();
32
- /** @type {string[]} */
33
- const bareQueue = [];
34
- /** @type {string[]} */
35
- const unresolved = [];
36
- /** @type {string[]} */
37
- const skippedVmz = [];
38
- for (const file of listClientJs(outDir)) {
39
- for (const spec of collectBareSpecs(readFileSync(file, 'utf8'))) {
40
- bareQueue.push({ spec: String(spec), from: file });
41
- }
42
- }
43
- while (bareQueue.length) {
44
- const item = bareQueue.shift();
45
- const { spec } = item;
46
- if (bareToVendor.has(spec))
47
- continue;
48
- const resolved = resolveBareToSource(projectRoot, spec, item.from);
49
- if (!resolved) {
50
- if (!unresolved.includes(spec))
51
- unresolved.push(spec);
52
- continue;
53
- }
54
- if (/\.vmz$/i.test(resolved.sourceFile)) {
55
- if (!skippedVmz.includes(spec))
56
- skippedVmz.push(spec);
57
- continue;
58
- }
59
- // Stylesheets are not browser modules: materialize the CSS (plus its
60
- // `url()` assets) and expose a loader module that links it once.
61
- if (STYLE_EXT.test(resolved.sourceFile)) {
62
- const styleDest = vendorPathForSource(outDir, resolved.pkgName, resolved.pkgRoot, resolved.sourceFile);
63
- materializeStyleFile(resolved.sourceFile, styleDest);
64
- const loaderDest = `${styleDest}.js`;
65
- writeFileSync(loaderDest, styleLoaderSource(path.basename(styleDest)), 'utf8');
66
- bareToVendor.set(spec, loaderDest);
67
- continue;
68
- }
69
- const destAbs = materializeSourceTree(outDir, resolved, materializedSources, bareQueue);
70
- if (destAbs)
71
- bareToVendor.set(spec, destAbs);
72
- else if (!unresolved.includes(spec))
73
- unresolved.push(spec);
74
- }
75
- /** @type {string[]} */
76
- const rewritten = [];
77
- for (const file of [...listClientJs(outDir), ...listVendorJs(outDir)]) {
78
- const before = readFileSync(file, 'utf8');
79
- let after = rewriteBareImports(before, file, bareToVendor);
80
- try {
81
- after = rewritePackModuleSpecifiers(after);
82
- }
83
- catch (error) {
84
- throw new Error(`pack module ${file}: ${error instanceof Error ? error.message : String(error)}`);
85
- }
86
- if (after !== before) {
87
- writeFileSync(file, after, 'utf8');
88
- rewritten.push(path.relative(outDir, file).replace(/\\/g, '/'));
89
- }
90
- }
91
- // Any bare that remains in client (non-vendor) JS after rewrite is still browser-broken.
92
- /** @type {string[]} */
93
- const remaining = [];
94
- for (const file of listClientJs(outDir)) {
95
- for (const spec of collectBareSpecs(readFileSync(file, 'utf8'))) {
96
- if (!remaining.includes(spec))
97
- remaining.push(spec);
98
- }
99
- }
100
- return {
101
- rewrittenFiles: rewritten.length,
102
- vendoredModules: [...bareToVendor.values()].map((abs) => path.relative(outDir, abs).replace(/\\/g, '/')),
103
- bareSpecs: [...bareToVendor.keys()],
104
- unresolvedBareSpecs: unresolved,
105
- skippedVmzExports: skippedVmz,
106
- remainingBareSpecs: remaining,
107
- };
108
- }
109
- /**
110
- * Materialize `resolved.sourceFile` and its relative import closure under vendor/.
111
- * @returns {string | null} vendor path for the entry source
112
- */
113
- function materializeSourceTree(outDir, resolved, materializedSources, bareQueue) {
114
- /** @type {string[]} */
115
- const sourceQueue = [resolved.sourceFile];
116
- // Subpath bare specs often land on a file already vendored via a relative
117
- // import from the package root — still map the bare name to that vendor path.
118
- /** @type {string | null} */
119
- let entryDest = vendorPathForSource(outDir, resolved.pkgName, resolved.pkgRoot, resolved.sourceFile);
120
- while (sourceQueue.length) {
121
- const sourceFile = sourceQueue.shift();
122
- if (materializedSources.has(sourceFile))
123
- continue;
124
- materializedSources.add(sourceFile);
125
- const destAbs = vendorPathForSource(outDir, resolved.pkgName, resolved.pkgRoot, sourceFile);
126
- mkdirSync(path.dirname(destAbs), { recursive: true });
127
- const js = materializeModule(sourceFile);
128
- writeFileSync(destAbs, js, 'utf8');
129
- materializeRuntimeAssets(sourceFile, destAbs, js);
130
- if (sourceFile === resolved.sourceFile)
131
- entryDest = destAbs;
132
- for (const bare of collectBareSpecs(js))
133
- bareQueue.push({ spec: String(bare), from: sourceFile });
134
- for (const rel of collectRelativeSpecs(js)) {
135
- const target = resolveRelativeSource(path.dirname(sourceFile), rel);
136
- if (target && !materializedSources.has(target))
137
- sourceQueue.push(target);
138
- }
139
- // Also follow relative imports as written in the *source* (before transpile),
140
- // so `./catalog.ts` is discovered even if transpile already rewrote to `.js`.
141
- const raw = readFileSync(sourceFile, 'utf8');
142
- for (const rel of collectRelativeSpecs(raw)) {
143
- const target = resolveRelativeSource(path.dirname(sourceFile), rel);
144
- if (target && !materializedSources.has(target))
145
- sourceQueue.push(target);
146
- }
147
- }
148
- return entryDest;
149
- }
150
- function listClientJs(outDir) {
151
- /** @type {string[]} */
152
- const out = [];
153
- walk(outDir, (file) => {
154
- const rel = path.relative(outDir, file).replace(/\\/g, '/');
155
- if (rel.startsWith('_vmz/') || rel.startsWith(`${VENDOR_DIR}/`) || rel.startsWith('#server/') || rel.startsWith('_vmz_server/')) {
156
- return;
157
- }
158
- if (rel.endsWith('.js') || rel.endsWith('.mjs'))
159
- out.push(file);
160
- });
161
- return out;
162
- }
163
- function listVendorJs(outDir) {
164
- const root = path.join(outDir, VENDOR_DIR);
165
- if (!existsSync(root))
166
- return [];
167
- /** @type {string[]} */
168
- const out = [];
169
- walk(root, (file) => {
170
- if (file.endsWith('.js') || file.endsWith('.mjs'))
171
- out.push(file);
172
- });
173
- return out;
174
- }
175
- function walk(dir, visit) {
176
- if (!existsSync(dir))
177
- return;
178
- for (const name of readdirSync(dir)) {
179
- if (name === 'node_modules')
180
- continue;
181
- const full = path.join(dir, name);
182
- let st;
183
- try {
184
- st = statSync(full);
185
- }
186
- catch {
187
- continue;
188
- }
189
- if (st.isDirectory())
190
- walk(full, visit);
191
- else
192
- visit(full);
193
- }
194
- }
195
- /** @param {string} js */
196
- export function collectBareSpecs(js) {
197
- /** @type {Set<string>} */
198
- const specs = new Set();
199
- const add = (spec) => {
200
- if (!spec || isRelativeOrAbsolute(spec) || shouldSkipBare(spec))
201
- return;
202
- specs.add(spec);
203
- };
204
- // `from 'x'` covers import/export … from
205
- let m;
206
- const fromRe = /\bfrom\s*['"]([^'"]+)['"]/g;
207
- while ((m = fromRe.exec(js)))
208
- add(m[1]);
209
- const dynRe = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
210
- while ((m = dynRe.exec(js)))
211
- add(m[1]);
212
- // side-effect: import 'x' (not import( and not import … from)
213
- const sideRe = /\bimport\s*['"]([^'"]+)['"]/g;
214
- while ((m = sideRe.exec(js)))
215
- add(m[1]);
216
- return [...specs];
217
- }
218
- function collectRelativeSpecs(js) {
219
- /** @type {Set<string>} */
220
- const specs = new Set();
221
- const re = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)['"](\.[^'"]+)['"]/g;
222
- let m;
223
- while ((m = re.exec(js)))
224
- specs.add(m[1]);
225
- return [...specs];
226
- }
227
- function isRelativeOrAbsolute(spec) {
228
- return spec.startsWith('.') || spec.startsWith('/') || spec.startsWith('\\');
229
- }
230
- function shouldSkipBare(spec) {
231
- return SKIP_PREFIXES.some((p) => spec.startsWith(p));
232
- }
233
- function resolveBareToSource(projectRoot, spec, fromFile) {
234
- const { pkgName, subpath } = splitPackageSpec(spec);
235
- let pkgRoot = null;
236
- if (fromFile && existsSync(fromFile)) {
237
- let cur = path.dirname(realpathSync(fromFile));
238
- for (let i = 0; i < 12; i++) {
239
- const nested = path.join(cur, 'node_modules', ...pkgName.split('/'));
240
- if (existsSync(path.join(nested, 'package.json'))) {
241
- pkgRoot = nested;
242
- break;
243
- }
244
- const parent = path.dirname(cur);
245
- if (parent === cur)
246
- break;
247
- cur = parent;
248
- }
249
- }
250
- if (!pkgRoot)
251
- pkgRoot = resolvePackageRoot(projectRoot, pkgName);
252
- if (!pkgRoot) {
253
- let cur = projectRoot;
254
- for (let i = 0; i < 8; i++) {
255
- pkgRoot = resolvePackageRoot(cur, pkgName);
256
- if (pkgRoot)
257
- break;
258
- const parent = path.dirname(cur);
259
- if (parent === cur)
260
- break;
261
- cur = parent;
262
- }
263
- }
264
- if (!pkgRoot)
265
- return null;
266
- const sourceFile = resolveExportFile(pkgRoot, subpath);
267
- if (!sourceFile)
268
- return null;
269
- return { pkgName, pkgRoot, subpath, sourceFile };
270
- }
271
- function splitPackageSpec(spec) {
272
- if (spec.startsWith('@')) {
273
- const parts = spec.split('/');
274
- if (parts.length < 2)
275
- return { pkgName: spec, subpath: '' };
276
- return { pkgName: `${parts[0]}/${parts[1]}`, subpath: parts.slice(2).join('/') };
277
- }
278
- const i = spec.indexOf('/');
279
- if (i < 0)
280
- return { pkgName: spec, subpath: '' };
281
- return { pkgName: spec.slice(0, i), subpath: spec.slice(i + 1) };
282
- }
283
- function resolveExportFile(pkgRoot, subpath) {
284
- const pkgPath = path.join(pkgRoot, 'package.json');
285
- if (!existsSync(pkgPath))
286
- return null;
287
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
288
- const key = subpath ? `./${subpath}` : '.';
289
- let target = null;
290
- if (pkg.exports && typeof pkg.exports === 'object' && !Array.isArray(pkg.exports)) {
291
- const entry = pkg.exports[key] ?? (!subpath ? pkg.exports['.'] : null);
292
- target = flattenExportTarget(entry);
293
- if (!target && subpath)
294
- target = matchWildcardExport(pkg.exports, key);
295
- }
296
- if (!target && !subpath)
297
- target = pkg.module || pkg.main || './index.js';
298
- if (!target && subpath) {
299
- for (const cand of [
300
- path.join(pkgRoot, 'src', `${subpath}.ts`),
301
- path.join(pkgRoot, 'src', `${subpath}.js`),
302
- path.join(pkgRoot, `${subpath}.ts`),
303
- path.join(pkgRoot, `${subpath}.js`),
304
- path.join(pkgRoot, 'src', subpath, 'index.ts'),
305
- path.join(pkgRoot, 'src', subpath, 'index.js'),
306
- ]) {
307
- if (existsSync(cand) && statSync(cand).isFile())
308
- return cand;
309
- }
310
- return null;
311
- }
312
- if (!target || typeof target !== 'string')
313
- return null;
314
- const abs = path.resolve(pkgRoot, target);
315
- if (existsSync(abs) && statSync(abs).isFile())
316
- return abs;
317
- for (const ext of ['.ts', '.tsx', '.js', '.mjs']) {
318
- const c = abs.endsWith(ext) ? abs : abs + ext;
319
- if (existsSync(c) && statSync(c).isFile())
320
- return c;
321
- }
322
- return null;
323
- }
324
- /** Longest-prefix `./*` / `./js/*` style export match for a subpath key. */
325
- function matchWildcardExport(exportsMap, key) {
326
- let best = null;
327
- let bestPrefix = -1;
328
- for (const [pattern, entry] of Object.entries(exportsMap)) {
329
- const star = pattern.indexOf('*');
330
- if (star < 0)
331
- continue;
332
- const prefix = pattern.slice(0, star);
333
- const suffix = pattern.slice(star + 1);
334
- if (!key.startsWith(prefix) || !key.endsWith(suffix))
335
- continue;
336
- const target = flattenExportTarget(entry);
337
- if (typeof target !== 'string')
338
- continue;
339
- const middle = key.slice(prefix.length, key.length - suffix.length);
340
- if (prefix.length > bestPrefix) {
341
- best = target.replace('*', middle);
342
- bestPrefix = prefix.length;
343
- }
344
- }
345
- return best;
346
- }
347
- function flattenExportTarget(entry) {
348
- if (typeof entry === 'string')
349
- return entry;
350
- if (!entry || typeof entry !== 'object')
351
- return null;
352
- // Package authors commonly put browser-first TypeScript sources behind a
353
- // conditional export. Resolve conditions before falling back to Node's
354
- // import/default branches so the pack stage can transpile the source into
355
- // the browser-safe vendor tree before static SSR imports it.
356
- const v = entry.browser || entry.import || entry.default || entry.require || entry.module || entry.node || null;
357
- if (typeof v === 'string')
358
- return v;
359
- if (v && typeof v === 'object')
360
- return flattenExportTarget(v);
361
- return null;
362
- }
363
- function vendorPathForSource(outDir, pkgName, pkgRoot, sourceFile) {
364
- const rel = path.relative(pkgRoot, sourceFile).replace(/\\/g, '/');
365
- return path.join(outDir, VENDOR_DIR, packageDirName(pkgName), rewriteTsExt(rel));
366
- }
367
- function packageDirName(pkgName) {
368
- return pkgName.replace(/^@/, '');
369
- }
370
- function materializeModule(sourceFile) {
371
- const ext = path.extname(sourceFile).toLowerCase();
372
- const raw = readFileSync(sourceFile, 'utf8');
373
- if (ext === '.json')
374
- return raw;
375
- if (ext === '.ts' || ext === '.tsx')
376
- return transpileTs(raw, sourceFile);
377
- try {
378
- return rewritePackModuleSpecifiers(raw);
379
- }
380
- catch (error) {
381
- throw new Error(`pack source ${sourceFile}: ${error instanceof Error ? error.message : String(error)}`);
382
- }
383
- }
384
- function isLocalAssetRef(ref) {
385
- const value = ref.trim();
386
- if (!value)
387
- return false;
388
- if (value.startsWith('/') || value.startsWith('\\') || value.startsWith('#'))
389
- return false;
390
- return !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value);
391
- }
392
- function copyVendoredAsset(fromDir, destDir, ref) {
393
- const cleaned = ref.replace(/[?#].*$/, '');
394
- if (!isLocalAssetRef(cleaned))
395
- return;
396
- const source = path.resolve(fromDir, cleaned);
397
- let stat;
398
- try {
399
- stat = statSync(source);
400
- }
401
- catch {
402
- return;
403
- }
404
- if (!stat.isFile())
405
- return;
406
- const dest = path.resolve(destDir, cleaned);
407
- mkdirSync(path.dirname(dest), { recursive: true });
408
- copyFileSync(source, dest);
409
- }
410
- /**
411
- * Copy files a vendored module loads by URL at runtime (`new URL(…, import.meta.url)`),
412
- * so `.wasm`, `.json` payloads, … stay reachable next to their module.
413
- */
414
- function materializeRuntimeAssets(sourceFile, destAbs, js) {
415
- IMPORT_META_URL_RE.lastIndex = 0;
416
- let match;
417
- while ((match = IMPORT_META_URL_RE.exec(js))) {
418
- copyVendoredAsset(path.dirname(sourceFile), path.dirname(destAbs), match[2]);
419
- }
420
- }
421
- /** Copy a stylesheet and everything its `url()` references. */
422
- function materializeStyleFile(sourceFile, destAbs) {
423
- const css = readFileSync(sourceFile, 'utf8');
424
- mkdirSync(path.dirname(destAbs), { recursive: true });
425
- writeFileSync(destAbs, css, 'utf8');
426
- CSS_URL_RE.lastIndex = 0;
427
- let match;
428
- while ((match = CSS_URL_RE.exec(css))) {
429
- copyVendoredAsset(path.dirname(sourceFile), path.dirname(destAbs), match[2]);
430
- }
431
- }
432
- /**
433
- * Loader module for a vendored stylesheet: links it once and exposes the load
434
- * promise as the default export.
435
- */
436
- function styleLoaderSource(fileName) {
437
- return `const href = new URL(${JSON.stringify(`./${fileName}`)}, import.meta.url).href;
438
- const ready =
439
- typeof document === 'undefined'
440
- ? Promise.resolve()
441
- : Array.from(document.querySelectorAll('link[rel="stylesheet"]')).some((el) => el.href === href)
442
- ? Promise.resolve()
443
- : new Promise((resolve, reject) => {
444
- const link = document.createElement('link');
445
- link.rel = 'stylesheet';
446
- link.href = href;
447
- link.onload = () => resolve();
448
- link.onerror = () => reject(new Error('VMZ stylesheet failed to load: ' + href));
449
- document.head.appendChild(link);
450
- });
451
- export default ready;
452
- `;
453
- }
454
- function transpileTs(source, filename) {
455
- try {
456
- const require = createRequire(import.meta.url);
457
- const ts = require('typescript');
458
- const out = ts.transpileModule(source, {
459
- fileName: filename,
460
- compilerOptions: {
461
- module: ts.ModuleKind.ESNext,
462
- target: ts.ScriptTarget.ES2022,
463
- moduleResolution: ts.ModuleResolutionKind.Bundler,
464
- esModuleInterop: true,
465
- skipLibCheck: true,
466
- },
467
- });
468
- return rewritePackModuleSpecifiers(out.outputText || '');
469
- }
470
- catch (err) {
471
- const msg = err instanceof Error ? err.message : String(err);
472
- return `/* vmz-pack: typescript transpile failed (${msg}) */\n${rewritePackModuleSpecifiers(source)}`;
473
- }
474
- }
475
- function rewriteTsExt(p) {
476
- // Path basename only (output layout) — not ESM source rewrite.
477
- return String(p)
478
- .replace(/\.tsx$/i, '.js')
479
- .replace(/\.ts$/i, '.js');
480
- }
481
- /** Native (N-API) module specifier rewrite (`.ts`→`.js` + optional exact map). */
482
- export function rewriteRelativeTsSpecs(js, exactMap = null) {
483
- const source = String(js ?? '');
484
- const hasModuleTsSpecifier = /(?:import\s*(?:[^'"()]*?\s*from\s*)?|export\s+[^'"()]*?\s*from\s*|import\s*\()(['"])[^'"\r\n]+\.tsx?\1/i.test(source);
485
- const exactKeys = Object.keys(exactMap ?? {});
486
- const hasExactSpecifier = exactKeys.some((spec) => source.includes(`'${spec}'`) || source.includes(`"${spec}"`));
487
- if (!hasModuleTsSpecifier && !hasExactSpecifier) {
488
- return source;
489
- }
490
- const native = requireNativeAddon();
491
- if (typeof native.rewriteModuleSpecifiers !== 'function') {
492
- throw new Error('native missing rewriteModuleSpecifiers — run `pnpm napi:build`');
493
- }
494
- const rules = {
495
- tsExtToJs: true,
496
- exact: exactMap && typeof exactMap === 'object' ? exactMap : {},
497
- };
498
- return native.rewriteModuleSpecifiers(String(js ?? ''), JSON.stringify(rules));
499
- }
500
- function resolveRelativeSource(fromDir, rel) {
501
- const cleaned = rel.replace(/\?.*$/, '').replace(/#.*$/, '');
502
- const base = path.resolve(fromDir, cleaned);
503
- for (const cand of [
504
- base,
505
- `${base}.ts`,
506
- `${base}.tsx`,
507
- `${base}.js`,
508
- `${base}.mjs`,
509
- path.join(base, 'index.ts'),
510
- path.join(base, 'index.js'),
511
- ]) {
512
- try {
513
- if (existsSync(cand) && statSync(cand).isFile())
514
- return cand;
515
- }
516
- catch {
517
- /* ignore */
518
- }
519
- }
520
- return null;
521
- }
522
- function rewriteBareImports(js, fromFile, bareToVendor) {
523
- /** @type {Record<string, string>} */
524
- const exact = {};
525
- for (const [spec, dest] of bareToVendor.entries()) {
526
- if (isRelativeOrAbsolute(spec) || shouldSkipBare(spec))
527
- continue;
528
- let rel = path.relative(path.dirname(fromFile), dest).replace(/\\/g, '/');
529
- if (!rel.startsWith('.'))
530
- rel = `./${rel}`;
531
- exact[spec] = rel;
532
- }
533
- return rewritePackModuleSpecifiers(js, exact);
534
- }
535
- function rewritePackModuleSpecifiers(source, exactMap = null) {
536
- const rewrite = (spec) => {
537
- const exact = exactMap && exactMap[spec];
538
- if (typeof exact === 'string')
539
- return exact;
540
- return /\.tsx?$/i.test(spec) ? spec.replace(/\.tsx?$/i, '.js') : spec;
541
- };
542
- const replace = (match, quote, spec) => {
543
- const next = rewrite(spec);
544
- return next === spec ? match : match.replace(`${quote}${spec}${quote}`, `${quote}${next}${quote}`);
545
- };
546
- let out = source.replace(/\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g, replace);
547
- out = out.replace(/\bimport\s+[^;\n]*?\sfrom\s+(['"])([^'"]+)\1/g, replace);
548
- out = out.replace(/\bimport\s*(['"])([^'"]+)\1/g, replace);
549
- return out.replace(/\bfrom\s*(['"])([^'"]+)\1/g, replace);
550
- }