@vmz/vmz 0.3.10 → 0.3.12

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.
@@ -396,6 +396,18 @@ function contentType(file) {
396
396
  return 'text/javascript; charset=utf-8';
397
397
  if (file.endsWith('.css'))
398
398
  return 'text/css; charset=utf-8';
399
+ if (file.endsWith('.wasm'))
400
+ return 'application/wasm';
401
+ if (file.endsWith('.woff2'))
402
+ return 'font/woff2';
403
+ if (file.endsWith('.woff'))
404
+ return 'font/woff';
405
+ if (file.endsWith('.otf'))
406
+ return 'font/otf';
407
+ if (file.endsWith('.ttf'))
408
+ return 'font/ttf';
409
+ if (file.endsWith('.svg'))
410
+ return 'image/svg+xml';
399
411
  if (file.endsWith('.xml'))
400
412
  return 'application/xml';
401
413
  if (file.endsWith('.txt'))
@@ -7,7 +7,9 @@
7
7
  * via a bounded rewrite of generated module syntax. Pack must not re-enter the
8
8
  * parser pipeline for every emitted JavaScript file.
9
9
  *
10
- * Not full oxc chunk-split/minify (`oxc-pending` remains for release minify).
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.
11
13
  */
12
14
  /**
13
15
  * @param {string} outDir
@@ -27,6 +29,6 @@ export declare function packClientBareImports(outDir: string, opts?: PackClientB
27
29
  };
28
30
  /** @param {string} js */
29
31
  export declare function collectBareSpecs(js: any): unknown[];
30
- /** oxc AST module specifier rewrite (`.ts`→`.js` + optional exact map). */
32
+ /** Native (N-API) module specifier rewrite (`.ts`→`.js` + optional exact map). */
31
33
  export declare function rewriteRelativeTsSpecs(js: any, exactMap?: any): any;
32
34
  export {};
@@ -7,15 +7,22 @@
7
7
  * via a bounded rewrite of generated module syntax. Pack must not re-enter the
8
8
  * parser pipeline for every emitted JavaScript file.
9
9
  *
10
- * Not full oxc chunk-split/minify (`oxc-pending` remains for release minify).
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.
11
13
  */
12
- import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from 'node:fs';
14
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from 'node:fs';
13
15
  import path from 'node:path';
14
16
  import { createRequire } from 'node:module';
15
17
  import { resolvePackageRoot } from './packages.js';
16
18
  import { requireNativeAddon } from './native-addon.js';
17
19
  const VENDOR_DIR = 'vendor';
18
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;
19
26
  export function packClientBareImports(outDir, opts = {}) {
20
27
  const projectRoot = opts.projectRoot ? path.resolve(opts.projectRoot) : path.dirname(path.resolve(outDir));
21
28
  /** @type {Map<string, string>} bareSpec → absolute vendored .js path */
@@ -49,6 +56,16 @@ export function packClientBareImports(outDir, opts = {}) {
49
56
  skippedVmz.push(spec);
50
57
  continue;
51
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
+ }
52
69
  const destAbs = materializeSourceTree(outDir, resolved, materializedSources, bareQueue);
53
70
  if (destAbs)
54
71
  bareToVendor.set(spec, destAbs);
@@ -109,6 +126,7 @@ function materializeSourceTree(outDir, resolved, materializedSources, bareQueue)
109
126
  mkdirSync(path.dirname(destAbs), { recursive: true });
110
127
  const js = materializeModule(sourceFile);
111
128
  writeFileSync(destAbs, js, 'utf8');
129
+ materializeRuntimeAssets(sourceFile, destAbs, js);
112
130
  if (sourceFile === resolved.sourceFile)
113
131
  entryDest = destAbs;
114
132
  for (const bare of collectBareSpecs(js))
@@ -272,6 +290,8 @@ function resolveExportFile(pkgRoot, subpath) {
272
290
  if (pkg.exports && typeof pkg.exports === 'object' && !Array.isArray(pkg.exports)) {
273
291
  const entry = pkg.exports[key] ?? (!subpath ? pkg.exports['.'] : null);
274
292
  target = flattenExportTarget(entry);
293
+ if (!target && subpath)
294
+ target = matchWildcardExport(pkg.exports, key);
275
295
  }
276
296
  if (!target && !subpath)
277
297
  target = pkg.module || pkg.main || './index.js';
@@ -301,6 +321,29 @@ function resolveExportFile(pkgRoot, subpath) {
301
321
  }
302
322
  return null;
303
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
+ }
304
347
  function flattenExportTarget(entry) {
305
348
  if (typeof entry === 'string')
306
349
  return entry;
@@ -338,6 +381,76 @@ function materializeModule(sourceFile) {
338
381
  throw new Error(`pack source ${sourceFile}: ${error instanceof Error ? error.message : String(error)}`);
339
382
  }
340
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
+ }
341
454
  function transpileTs(source, filename) {
342
455
  try {
343
456
  const require = createRequire(import.meta.url);
@@ -365,7 +478,7 @@ function rewriteTsExt(p) {
365
478
  .replace(/\.tsx$/i, '.js')
366
479
  .replace(/\.ts$/i, '.js');
367
480
  }
368
- /** oxc AST module specifier rewrite (`.ts`→`.js` + optional exact map). */
481
+ /** Native (N-API) module specifier rewrite (`.ts`→`.js` + optional exact map). */
369
482
  export function rewriteRelativeTsSpecs(js, exactMap = null) {
370
483
  const source = String(js ?? '');
371
484
  const hasModuleTsSpecifier = /(?:import\s*(?:[^'"()]*?\s*from\s*)?|export\s+[^'"()]*?\s*from\s*|import\s*\()(['"])[^'"\r\n]+\.tsx?\1/i.test(source);
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * Pack stage: consume Deployment IR (VPG-owned units), emit pack manifest,
3
3
  * and lower browser-unreachable bare package imports to `dist/vendor/**`.
4
- * Full oxc minify/chunk-split lands progressively (`oxc-pending` on release minify).
4
+ *
5
+ * Current status: a thin module-moving slice — reachable module closure
6
+ * materialization, specifier rewriting, and TypeScript `transpileModule` type
7
+ * erasure. Linking, dead-code elimination, chunk splitting, and minification
8
+ * are NOT implemented in this stage; the manifest reports that honestly.
9
+ * (Any compaction of compile-emitted modules happens upstream in the compiler,
10
+ * not here — pack never rewrites bytes beyond specifier lowering.)
5
11
  */
6
12
  export declare const PACK_MANIFEST_SCHEMA = "vmz.pack.manifest.v0";
7
13
  /**
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * Pack stage: consume Deployment IR (VPG-owned units), emit pack manifest,
3
3
  * and lower browser-unreachable bare package imports to `dist/vendor/**`.
4
- * Full oxc minify/chunk-split lands progressively (`oxc-pending` on release minify).
4
+ *
5
+ * Current status: a thin module-moving slice — reachable module closure
6
+ * materialization, specifier rewriting, and TypeScript `transpileModule` type
7
+ * erasure. Linking, dead-code elimination, chunk splitting, and minification
8
+ * are NOT implemented in this stage; the manifest reports that honestly.
9
+ * (Any compaction of compile-emitted modules happens upstream in the compiler,
10
+ * not here — pack never rewrites bytes beyond specifier lowering.)
5
11
  */
6
12
  import crypto from 'node:crypto';
7
13
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
@@ -75,7 +81,13 @@ export function packFromDeploymentIr(outDir, opts = {}) {
75
81
  deploymentSchema: ir.schema,
76
82
  unitCount: units.length,
77
83
  units,
78
- minify: opts.release ? 'oxc-pending' : 'dev-identity',
84
+ // Pack runs no compressor in either mode: it reports the bytes it was
85
+ // given (dev output written verbatim). Release artifacts may already be
86
+ // compacted by the compiler's release print path upstream — pack does not
87
+ // claim, add, or verify that compaction.
88
+ minify: opts.release ? 'none' : 'dev-identity',
89
+ // Names how VPG deployment units are selected for this manifest. It does
90
+ // NOT mean JavaScript dead-code elimination ran — that is not implemented.
79
91
  treeShakeBasis: 'vpg-deployment-ir',
80
92
  bundler: 'vmz-pack',
81
93
  clientPackageLowering: {
@@ -322,13 +322,12 @@ function buildMathFacade(defaultEngine, engines) {
322
322
  const tag = engineToTag(eng);
323
323
  const kw = i === 0 ? 'v-if' : 'v-else-if';
324
324
  const engLit = jsSingleQuoted(eng);
325
- return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :tex="tex" :display="display" />`;
325
+ return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :tex="tex" :display="display" />`;
326
326
  })
327
327
  .join('\n');
328
328
  return `<template>
329
329
  ${branches}
330
330
  </template>
331
-
332
331
  <script client>
333
332
  export default class Math {
334
333
  public tex: string = '';
@@ -349,13 +348,12 @@ function buildCodeFacade(defaultEngine, engines) {
349
348
  const tag = engineToTag(eng);
350
349
  const kw = i === 0 ? 'v-if' : 'v-else-if';
351
350
  const engLit = jsSingleQuoted(eng);
352
- return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :code="code" :lang="lang" :theme="theme" />`;
351
+ return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :code="code" :lang="lang" :theme="theme" />`;
353
352
  })
354
353
  .join('\n');
355
354
  return `<template>
356
355
  ${branches}
357
356
  </template>
358
-
359
357
  <script client>
360
358
  export default class Code {
361
359
  public code: string = '';
@@ -377,13 +375,12 @@ function buildMarkdownFacade(defaultEngine, engines) {
377
375
  const tag = engineToTag(eng);
378
376
  const kw = i === 0 ? 'v-if' : 'v-else-if';
379
377
  const engLit = jsSingleQuoted(eng);
380
- return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :source="source" />`;
378
+ return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :source="source" />`;
381
379
  })
382
380
  .join('\n');
383
381
  return `<template>
384
382
  ${branches}
385
383
  </template>
386
-
387
384
  <script client>
388
385
  export default class Markdown {
389
386
  public source: string = '';
package/package.json CHANGED
@@ -3,23 +3,23 @@
3
3
  "vmz": "./bin/vmz.js"
4
4
  },
5
5
  "dependencies": {
6
- "@vmz/commander": "0.3.10",
7
- "@vmz/core": "0.3.10",
8
- "@vmz/diagnostic": "0.3.10",
9
- "@vmz/plugin": "0.3.10",
10
- "@vmz/protocol": "0.3.10"
6
+ "@vmz/commander": "0.3.12",
7
+ "@vmz/core": "0.3.12",
8
+ "@vmz/diagnostic": "0.3.12",
9
+ "@vmz/plugin": "0.3.12",
10
+ "@vmz/protocol": "0.3.12"
11
11
  },
12
12
  "description": "VMZ Node toolchain — N-API workspace session + CLI (publish name @vmz/vmz)",
13
13
  "devDependencies": {
14
14
  "@types/node": "^22.15.0",
15
- "@vmz/plugin": "0.3.10",
16
- "@vmz/plugin-katex": "0.3.10",
17
- "@vmz/plugin-markdown-it": "0.3.10",
18
- "@vmz/plugin-shiki": "0.3.10",
19
- "@vmz/test": "0.3.10",
15
+ "@vmz/plugin": "0.3.12",
16
+ "@vmz/plugin-katex": "0.3.12",
17
+ "@vmz/plugin-markdown-it": "0.3.12",
18
+ "@vmz/plugin-shiki": "0.3.12",
19
+ "@vmz/test": "0.3.12",
20
20
  "linkedom": "^0.18.13",
21
21
  "typescript": "^5.8.3",
22
- "vmz-plugin-conformance": "0.3.10"
22
+ "vmz-plugin-conformance": "0.3.12"
23
23
  },
24
24
  "engines": {
25
25
  "node": ">=24.12.0"
@@ -80,16 +80,16 @@
80
80
  "main": "./dist/index.js",
81
81
  "name": "@vmz/vmz",
82
82
  "optionalDependencies": {
83
- "@vmz/vmz-darwin-arm64": "0.3.10",
84
- "@vmz/vmz-darwin-x64": "0.3.10",
85
- "@vmz/vmz-linux-arm64": "0.3.10",
86
- "@vmz/vmz-linux-x64": "0.3.10",
87
- "@vmz/vmz-win32-arm64": "0.3.10",
88
- "@vmz/vmz-win32-x64": "0.3.10"
83
+ "@vmz/vmz-darwin-arm64": "0.3.12",
84
+ "@vmz/vmz-darwin-x64": "0.3.12",
85
+ "@vmz/vmz-linux-arm64": "0.3.12",
86
+ "@vmz/vmz-linux-x64": "0.3.12",
87
+ "@vmz/vmz-win32-arm64": "0.3.12",
88
+ "@vmz/vmz-win32-x64": "0.3.12"
89
89
  },
90
90
  "peerDependencies": {
91
- "@vmz/plugin-markdown-it": "0.3.10",
92
- "@vmz/test": "0.3.10",
91
+ "@vmz/plugin-markdown-it": "0.3.12",
92
+ "@vmz/test": "0.3.12",
93
93
  "typescript": "^5.8.3"
94
94
  },
95
95
  "peerDependenciesMeta": {
@@ -122,5 +122,5 @@
122
122
  },
123
123
  "type": "module",
124
124
  "types": "./dist/index.d.ts",
125
- "version": "0.3.10"
125
+ "version": "0.3.12"
126
126
  }