@vmz/vmz 0.3.6 → 0.3.7

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.
@@ -14,13 +14,20 @@ import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
14
14
  import path from 'node:path';
15
15
  import { buildIntegratedDocuments, projectHasDocuments } from '../document/document-integrate.js';
16
16
  import { createWorkspace, resolveNativePath } from '../workspace/public-api.js';
17
+ import { materializeWechatPackaging } from '../workspace/wechat-packaging.js';
17
18
  import { emitLocaleRuntimeModules, localeHasErrors } from '../locale/locale-check.js';
18
19
  import { log } from '../workspace/log.js';
19
- import { coalesceRootBurst, collectDevWatchRoots, classifyWatchRoot, isDependencyPath, mergeDirtySets, collectDevConfigPaths, configFingerprintMap, } from './dev-watch-roots.js';
20
+ import { coalesceRootBurst, collectDevWatchRoots, classifyWatchRoot, isDependencyPath, mergeDirtySets, collectConfigDependencies, configCandidatePaths, configFingerprintMap, } from './dev-watch-roots.js';
21
+ import { createConfigCycle } from './config-cycle.js';
20
22
  import { buildReloadPayload, filterGenerationIgnore, parseHmrPlan, registerWrittenOutputsIgnore, shouldSoftReload, staticRevisionFromArtifact, } from './dev-incremental.js';
21
23
  import { diffFingerprints, fileFingerprintMap } from '../workspace/watch-diff.js';
22
24
  /** Track serve-host so a failed/killed launcher cannot leave an orphan port. */
23
25
  const DEV_HOST_PID = '.vmz-dev-host.pid';
26
+ function cycleFailure(report) {
27
+ const detail = report.error?.args?.detail ?? 'config build process failed';
28
+ const error = new Error(detail);
29
+ return report.error ? Object.assign(error, { diagnostic: report.error }) : error;
30
+ }
24
31
  export function createDevSession(options) {
25
32
  const project = options.project;
26
33
  const outDir = options.outDir;
@@ -28,9 +35,13 @@ export function createDevSession(options) {
28
35
  const port = options.port ?? 5173;
29
36
  const pollMs = Math.max(50, options.pollMs ?? 300);
30
37
  const wechatPreview = options.target === 'mini-program-wechat';
38
+ let delivery = options.delivery ?? null;
31
39
  const createWs = options.createWorkspaceFn ?? createWorkspace;
32
40
  const spawnHost = options.spawnHostFn ?? defaultSpawnHost;
33
41
  const softReload = options.softReloadFn ?? defaultSoftReload;
42
+ const makeConfigCycle = options.configCycleFn ?? createConfigCycle;
43
+ const configCandidates = configCandidatePaths(project);
44
+ let configCycle = null;
34
45
  const ws = createWs({ root: project, outDir });
35
46
  let child = null;
36
47
  let stopped = false;
@@ -119,6 +130,8 @@ export function createDevSession(options) {
119
130
  }
120
131
  let report;
121
132
  try {
133
+ // Same prepared snapshot for this build cycle; native pack never reads config.
134
+ materializeWechatPackaging(project, delivery);
122
135
  const raw = ws.lowerMiniprogramWechatPackaging();
123
136
  report = typeof raw === 'string' ? JSON.parse(raw) : raw;
124
137
  }
@@ -191,15 +204,15 @@ export function createDevSession(options) {
191
204
  if (!existsSync(src)) {
192
205
  throw new Error(`vmz dev: missing src/ under ${project}`);
193
206
  }
194
- // Same as `vmz build`: materialize plugin sources (e.g. `<Shiki>`) before compile.
195
- // Soft rebuilds reuse the workspace; config/plugin changes still need a process restart
196
- // until `vmz.config.*` is watched.
197
- {
198
- const { loadVmzConfig, applyPlugins } = await import('../workspace/plugin-host.js');
199
- const { plugins, engines } = await loadVmzConfig(project);
200
- if (plugins.length) {
201
- await applyPlugins(ws, plugins, { project, outDir, engines });
202
- }
207
+ // Config evaluation + plugin contributions run in a detached build process.
208
+ // Functions/plugin objects never cross the boundary; only the data report does.
209
+ if (configCandidates.some((p) => existsSync(p))) {
210
+ configCycle = makeConfigCycle({ project, outDir, ...(options.configCycleWorkerPath ? { workerPath: options.configCycleWorkerPath } : {}) });
211
+ const report = await configCycle.start();
212
+ if (!report.ok)
213
+ throw cycleFailure(report);
214
+ delivery = report.delivery ?? delivery;
215
+ log.info(`config build process ready${report.plugins.length ? ` (${report.plugins.map((p) => p.name).join(', ')})` : ''}`);
203
216
  }
204
217
  log.info('initial build (N-API workspace, full)…');
205
218
  const initialPair = planAndRebuild();
@@ -238,7 +251,14 @@ export function createDevSession(options) {
238
251
  const designsRoot = path.join(project, 'designs');
239
252
  const watched = collectDevWatchRoots({ project, outDir });
240
253
  const publicRoot = watched.publicRoot;
241
- const configPaths = watched.configPaths.length ? watched.configPaths : collectDevConfigPaths(project);
254
+ /** Candidate config files plus their local reachable deps; refreshed after each cycle. */
255
+ const refreshConfigPaths = () => {
256
+ const deps = configCandidates
257
+ .filter((p) => existsSync(p))
258
+ .flatMap((p) => collectConfigDependencies(p, project));
259
+ return [...new Set([...configCandidates, ...deps])];
260
+ };
261
+ let configPaths = refreshConfigPaths();
242
262
  /** @type {string[]} */
243
263
  const watchRoots = [...watched.roots];
244
264
  /** @type {string[]} */
@@ -359,14 +379,66 @@ export function createDevSession(options) {
359
379
  continue;
360
380
  }
361
381
  if (batch.configDirty) {
362
- log.info('vmz.config change detected — respawn required (devControl)');
363
- configFingerprints = configFingerprintMap(configPaths);
364
- commitFingerprints();
365
- await respawnHost('config-changed');
382
+ log.info('vmz.config change detected — restarting the config build process…');
383
+ let cycleReport = null;
384
+ if (configCandidates.some((p) => existsSync(p))) {
385
+ let failure = null;
386
+ try {
387
+ if (!configCycle) {
388
+ configCycle = makeConfigCycle({
389
+ project,
390
+ outDir,
391
+ ...(options.configCycleWorkerPath ? { workerPath: options.configCycleWorkerPath } : {}),
392
+ });
393
+ cycleReport = await configCycle.start();
394
+ }
395
+ else {
396
+ // Old process is cancelled and awaited before the new one writes artifacts.
397
+ cycleReport = await configCycle.restart();
398
+ }
399
+ }
400
+ catch (err) {
401
+ failure = err instanceof Error ? err : new Error(String(err));
402
+ }
403
+ configPaths = refreshConfigPaths();
404
+ configFingerprints = configFingerprintMap(configPaths);
405
+ commitFingerprints();
406
+ if (failure) {
407
+ log.warn(`config build process restart failed: ${failure.message}`);
408
+ continue;
409
+ }
410
+ if (cycleReport && !cycleReport.ok) {
411
+ if (cycleReport.error)
412
+ log.diagnostic(cycleReport.error);
413
+ else
414
+ log.error('config build process failed');
415
+ continue;
416
+ }
417
+ if (cycleReport)
418
+ delivery = cycleReport.delivery ?? delivery;
419
+ }
420
+ else if (configCycle) {
421
+ await configCycle.cancel();
422
+ configCycle = null;
423
+ configPaths = refreshConfigPaths();
424
+ configFingerprints = configFingerprintMap(configPaths);
425
+ commitFingerprints();
426
+ log.warn('vmz.config removed — config build process stopped, last artifacts kept');
427
+ continue;
428
+ }
429
+ else {
430
+ configFingerprints = configFingerprintMap(configPaths);
431
+ commitFingerprints();
432
+ continue;
433
+ }
366
434
  const report = rebuild();
367
435
  if (printReport(report, 'rebuild')) {
368
436
  lastOutputRevision = report.outputRevision ?? report.output_revision ?? null;
369
437
  await emitPublicAndTrack();
438
+ if (wechatPreview)
439
+ packWechatPreview();
440
+ else
441
+ await respawnHost('config-changed');
370
442
  }
371
443
  continue;
372
444
  }
@@ -605,6 +677,8 @@ export function createDevSession(options) {
605
677
  stopped = true;
606
678
  killChild(child);
607
679
  child = null;
680
+ await configCycle?.cancel().catch(() => { });
681
+ configCycle = null;
608
682
  clearDevHostPid(outDir, null);
609
683
  try {
610
684
  ws.dispose();
@@ -7,8 +7,15 @@
7
7
  */
8
8
  /** Author-facing vs generated dev input bucket. */
9
9
  export type DevInputKind = 'author' | 'dependency' | 'public' | 'devControl' | 'locales' | 'docs' | 'designs' | 'other';
10
+ /** All supported `vmz.config.*` candidate paths, existing or not (so creation is detected). */
11
+ export declare function configCandidatePaths(project: string): string[];
10
12
  /** `vmz.config.*` at project root (devControl). */
11
13
  export declare function collectDevConfigPaths(project: string): string[];
14
+ /**
15
+ * Reachable local ESM dependencies of a config file (bounded, project-root only).
16
+ * These changes restart the dev config build process.
17
+ */
18
+ export declare function collectConfigDependencies(configPath: string, project: string): string[];
12
19
  /** Fingerprint map for explicit config files (not directory walks). */
13
20
  export declare function configFingerprintMap(configPaths: string[]): Map<string, string>;
14
21
  export interface DirtySet {
@@ -8,11 +8,74 @@
8
8
  import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
9
9
  import path from 'node:path';
10
10
  import { diffFingerprints, fileFingerprintMap } from '../workspace/watch-diff.js';
11
- const CONFIG_BASENAMES = ['vmz.config.ts', 'vmz.config.js', 'vmz.config.mjs', 'vmz.config.cjs'];
11
+ const CONFIG_BASENAMES = ['vmz.config.ts', 'vmz.config.mts', 'vmz.config.js', 'vmz.config.mjs', 'vmz.config.cjs'];
12
+ const LOCAL_MODULE_EXTENSIONS = ['.ts', '.mts', '.js', '.mjs', '.cts', '.cjs'];
13
+ /** All supported `vmz.config.*` candidate paths, existing or not (so creation is detected). */
14
+ export function configCandidatePaths(project) {
15
+ const root = path.resolve(project);
16
+ return CONFIG_BASENAMES.map((name) => path.join(root, name));
17
+ }
12
18
  /** `vmz.config.*` at project root (devControl). */
13
19
  export function collectDevConfigPaths(project) {
20
+ return configCandidatePaths(project).filter((p) => existsSync(p));
21
+ }
22
+ /**
23
+ * Reachable local ESM dependencies of a config file (bounded, project-root only).
24
+ * These changes restart the dev config build process.
25
+ */
26
+ export function collectConfigDependencies(configPath, project) {
14
27
  const root = path.resolve(project);
15
- return CONFIG_BASENAMES.map((name) => path.join(root, name)).filter((p) => existsSync(p));
28
+ const underRoot = (file) => file === root || file.startsWith(root + path.sep);
29
+ const seen = new Set();
30
+ const out = [];
31
+ const visit = (file, depth) => {
32
+ if (depth > 24 || seen.size > 200 || !existsSync(file) || !underRoot(file))
33
+ return;
34
+ if (seen.has(file))
35
+ return;
36
+ seen.add(file);
37
+ let text;
38
+ try {
39
+ text = readFileSync(file, 'utf8');
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ const specs = new Set();
45
+ for (const match of text.matchAll(/\b(?:import|export)\s+(?:[^'";]*?\s+from\s+)?['"]([^'"]+)['"]/g)) {
46
+ if (match[1])
47
+ specs.add(match[1]);
48
+ }
49
+ for (const match of text.matchAll(/\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g)) {
50
+ if (match[1])
51
+ specs.add(match[1]);
52
+ }
53
+ for (const spec of specs) {
54
+ if (!spec.startsWith('.'))
55
+ continue;
56
+ const base = path.resolve(path.dirname(file), spec);
57
+ const candidates = [
58
+ base,
59
+ ...LOCAL_MODULE_EXTENSIONS.map((ext) => base + ext),
60
+ ...LOCAL_MODULE_EXTENSIONS.map((ext) => path.join(base, `index${ext}`)),
61
+ ];
62
+ for (const candidate of candidates) {
63
+ try {
64
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
65
+ if (!seen.has(candidate))
66
+ out.push(candidate);
67
+ visit(candidate, depth + 1);
68
+ break;
69
+ }
70
+ }
71
+ catch {
72
+ /* keep looking */
73
+ }
74
+ }
75
+ }
76
+ };
77
+ visit(path.resolve(configPath), 0);
78
+ return out;
16
79
  }
17
80
  /** Fingerprint map for explicit config files (not directory walks). */
18
81
  export function configFingerprintMap(configPaths) {
@@ -195,20 +195,20 @@ function buildDocumentSlotHtml({ nav, bodyHtml, headings, htmlRel, route, routin
195
195
  .map((h) => ` <li class="h${h.level}"><a href="#${esc(h.id)}">${esc(h.text)}</a></li>`)
196
196
  .join('\n')}\n </ol>\n </nav>\n`
197
197
  : '';
198
- const docsNav = ` <nav aria-label="Documents" class="doc-subnav">
199
- <ul>
200
- ${navItems}
201
- </ul>
198
+ const docsNav = ` <nav aria-label="Documents" class="doc-subnav">
199
+ <ul>
200
+ ${navItems}
201
+ </ul>
202
202
  </nav>`;
203
- return ` <aside class="doc-sidebar">
204
- ${docsNav}
205
- ${searchShellHtml}
206
- </aside>
207
- <div class="doc-content">
208
- ${toc}<main id="main">
209
- ${bodyHtml}
210
- ${playgroundShellHtml}
211
- </main>
203
+ return ` <aside class="doc-sidebar">
204
+ ${docsNav}
205
+ ${searchShellHtml}
206
+ </aside>
207
+ <div class="doc-content">
208
+ ${toc}<main id="main">
209
+ ${bodyHtml}
210
+ ${playgroundShellHtml}
211
+ </main>
212
212
  </div>`;
213
213
  }
214
214
  /**
@@ -242,17 +242,17 @@ function renderStaticHtml({ title, locale, route, nav, bodyHtml, headings, desig
242
242
  .map((h) => ` <li class="h${h.level}"><a href="#${esc(h.id)}">${esc(h.text)}</a></li>`)
243
243
  .join('\n')}\n </ol>\n </nav>\n`
244
244
  : '';
245
- bodyInner = ` <a class="skip-link" href="#main">Skip to content</a>
246
- <nav aria-label="Documents" class="doc-subnav">
247
- <ul>
248
- ${navItems}
249
- </ul>
250
- </nav>
251
- ${searchShellHtml}
252
- ${toc}<main id="main">
253
- ${bodyHtml}
254
- ${playgroundShellHtml}
255
- </main>
245
+ bodyInner = ` <a class="skip-link" href="#main">Skip to content</a>
246
+ <nav aria-label="Documents" class="doc-subnav">
247
+ <ul>
248
+ ${navItems}
249
+ </ul>
250
+ </nav>
251
+ ${searchShellHtml}
252
+ ${toc}<main id="main">
253
+ ${bodyHtml}
254
+ ${playgroundShellHtml}
255
+ </main>
256
256
  `;
257
257
  }
258
258
  const native = requireNativeAddon();
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Document — resolve engines.markdown via the official plugin runtime.
2
+ * Document — resolve engines.markdown via the official plugin runtime export.
3
3
  */
4
4
  export interface ResolveMarkdownEngineOpts {
5
5
  engines?: {
@@ -1,36 +1,22 @@
1
1
  /**
2
- * Document — resolve engines.markdown via the official plugin runtime.
2
+ * Document — resolve engines.markdown via the official plugin runtime export.
3
3
  */
4
- import { createRequire } from 'node:module';
5
- import { existsSync } from 'node:fs';
6
- import path from 'node:path';
7
- import { fileURLToPath } from 'node:url';
8
- import { importMaybeTs } from '../workspace/plugin-host.js';
9
- const require = createRequire(import.meta.url);
10
4
  export async function resolveMarkdownEngine(opts = {}) {
11
5
  const id = opts.engines?.markdown || 'markdown-it';
12
6
  if (id !== 'markdown-it') {
13
7
  throw new Error(`unsupported engines.markdown ${JSON.stringify(id)} (markdown-it only)`);
14
8
  }
15
- let runtimeFile = null;
9
+ let mod;
16
10
  try {
17
- const pkg = require.resolve('@vmz/plugin-markdown-it/package.json');
18
- runtimeFile = path.join(path.dirname(pkg), 'runtime.ts');
11
+ // Public JS runtime export of the plugin package; never read the package directory.
12
+ mod = await import('@vmz/plugin-markdown-it/runtime');
19
13
  }
20
- catch {
21
- // Developer mode: monorepo source checkout.
22
- const here = path.dirname(fileURLToPath(import.meta.url));
23
- const fallback = path.resolve(here, '../../../plugins/vmz-plugin-markdown-it/runtime.ts');
24
- if (existsSync(fallback))
25
- runtimeFile = fallback;
26
- }
27
- if (!runtimeFile || !existsSync(runtimeFile)) {
14
+ catch (err) {
28
15
  throw new Error('markdown engine needs `@vmz/plugin-markdown-it` (optional peer of `@vmz/vmz`).\n' +
29
- ' Install: pnpm add -D @vmz/plugin-markdown-it');
16
+ ' Install: pnpm add -D @vmz/plugin-markdown-it', { cause: err });
30
17
  }
31
- const mod = await importMaybeTs(runtimeFile);
32
18
  if (typeof mod.analyzeMarkdown !== 'function') {
33
- throw new Error(`cannot load markdown engine markdown-it from ${runtimeFile}`);
19
+ throw new Error('cannot load markdown engine markdown-it: runtime export is missing analyzeMarkdown');
34
20
  }
35
21
  return {
36
22
  engine: id,
@@ -4,11 +4,9 @@
4
4
  import { contentHash, defineConfig, definePlugin } from '@vmz/plugin';
5
5
  export { contentHash, defineConfig, definePlugin };
6
6
  export declare const PLUGIN_PROTOCOL = "0.1.0";
7
- /**
8
- * @param {string} full
9
- * @returns {Promise<any>}
10
- */
11
- export declare function importMaybeTs(full: any): Promise<any>;
7
+ export declare const CONFIG_NAMES: string[];
8
+ export declare const CONFIG_LOAD_FAILED = "vmz::config::load_failed";
9
+ export declare const PLUGIN_ENTRY_INVALID = "vmz::plugin::invalid_entry";
12
10
  /**
13
11
  * Load `vmz.config.*` from project root (+ optional root `vmz.plugin.*`).
14
12
  * @param {string} project
@@ -4,30 +4,57 @@
4
4
  import { existsSync } from 'node:fs';
5
5
  import path from 'node:path';
6
6
  import { pathToFileURL } from 'node:url';
7
- import { createJiti } from 'jiti';
8
7
  import { PLUGIN_PROTOCOL as PLUGIN_PROTOCOL_PKG, contentHash, defineConfig, definePlugin } from '@vmz/plugin';
9
8
  import { log } from './log.js';
10
9
  import { resolveWorkspacePackages } from './packages.js';
11
10
  export { contentHash, defineConfig, definePlugin };
12
11
  export const PLUGIN_PROTOCOL = PLUGIN_PROTOCOL_PKG;
13
- const CONFIG_NAMES = ['vmz.config.ts', 'vmz.config.mts', 'vmz.config.mjs', 'vmz.config.js'];
12
+ export const CONFIG_NAMES = ['vmz.config.ts', 'vmz.config.mts', 'vmz.config.mjs', 'vmz.config.js'];
14
13
  const ROOT_PLUGIN_NAMES = ['vmz.plugin.ts', 'vmz.plugin.mts', 'vmz.plugin.mjs', 'vmz.plugin.js'];
14
+ export const CONFIG_LOAD_FAILED = 'vmz::config::load_failed';
15
+ export const PLUGIN_ENTRY_INVALID = 'vmz::plugin::invalid_entry';
15
16
  /**
17
+ * Load an ES module through the Node host (native `import()`).
18
+ * Project config and plugin entries must be erasable TS or JS: the host never
19
+ * runs a runtime TypeScript transpiler.
16
20
  * @param {string} full
17
21
  * @returns {Promise<any>}
18
22
  */
19
- export async function importMaybeTs(full) {
20
- const ext = path.extname(full).toLowerCase();
21
- if (ext === '.ts' || ext === '.mts') {
22
- const jiti = createJiti(import.meta.url, {
23
- interopDefault: true,
24
- moduleCache: false,
25
- });
26
- return jiti(full);
27
- }
23
+ async function importHostModule(full) {
28
24
  const mod = await import(pathToFileURL(full).href);
29
25
  return mod.default ?? mod;
30
26
  }
27
+ function errorDetail(err) {
28
+ const parts = [];
29
+ let cur = err;
30
+ for (let i = 0; cur && i < 4; i += 1) {
31
+ const message = cur instanceof Error ? cur.message : String(cur);
32
+ if (message && !parts.includes(message))
33
+ parts.push(message);
34
+ cur = cur && typeof cur === 'object' && 'cause' in cur ? cur.cause : null;
35
+ }
36
+ return parts.join(' ← ') || 'unknown error';
37
+ }
38
+ /**
39
+ * Build a host error carrying a product diagnostic (one print at the CLI boundary).
40
+ * @param {string} code
41
+ * @param {string} sourcePath
42
+ * @param {unknown} err
43
+ */
44
+ function configDiagnosticError(code, sourcePath, err) {
45
+ const detail = errorDetail(err);
46
+ const error = new Error(detail);
47
+ if (err instanceof Error)
48
+ error.cause = err;
49
+ return Object.assign(error, {
50
+ diagnostic: {
51
+ code,
52
+ severity: 'error',
53
+ path: sourcePath,
54
+ args: { detail },
55
+ },
56
+ });
57
+ }
31
58
  /**
32
59
  * Load `vmz.config.*` from project root (+ optional root `vmz.plugin.*`).
33
60
  * @param {string} project
@@ -61,7 +88,13 @@ export async function loadVmzConfig(project) {
61
88
  if (!existsSync(full))
62
89
  continue;
63
90
  configPath = full;
64
- const cfg = await importMaybeTs(full);
91
+ let cfg;
92
+ try {
93
+ cfg = await importHostModule(full);
94
+ }
95
+ catch (err) {
96
+ throw configDiagnosticError(CONFIG_LOAD_FAILED, full, err);
97
+ }
65
98
  const raw = cfg?.plugins ?? [];
66
99
  engines = cfg?.engines && typeof cfg.engines === 'object' ? { ...cfg.engines } : {};
67
100
  if (cfg?.delivery && typeof cfg.delivery === 'object') {
@@ -96,9 +129,11 @@ async function resolvePluginEntry(project, entry) {
96
129
  let value = entry;
97
130
  if (typeof value === 'string') {
98
131
  const resolved = path.isAbsolute(value) ? value : path.join(project, value);
99
- value = await importMaybeTs(resolved);
100
- if (value && typeof value === 'object' && 'default' in value && value.default) {
101
- value = value.default;
132
+ try {
133
+ value = await importHostModule(resolved);
134
+ }
135
+ catch (err) {
136
+ throw configDiagnosticError(PLUGIN_ENTRY_INVALID, resolved, err);
102
137
  }
103
138
  }
104
139
  value = await value;
@@ -106,7 +141,8 @@ async function resolvePluginEntry(project, entry) {
106
141
  return value;
107
142
  if (value?.name && value?.stages)
108
143
  return definePlugin(value);
109
- throw new Error(`invalid vmz plugin entry: ${String(entry)}`);
144
+ const sourcePath = typeof entry === 'string' ? (path.isAbsolute(entry) ? entry : path.join(project, entry)) : '';
145
+ throw configDiagnosticError(PLUGIN_ENTRY_INVALID, sourcePath, new Error(`invalid vmz plugin entry: ${String(entry)}`));
110
146
  }
111
147
  /**
112
148
  * Collect + apply contribution batches for the given stages onto a Workspace.
@@ -289,17 +325,17 @@ function buildMathFacade(defaultEngine, engines) {
289
325
  return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :tex="tex" :display="display" />`;
290
326
  })
291
327
  .join('\n');
292
- return `<template>
293
- ${branches}
294
- </template>
295
-
296
- <script client>
297
- export default class Math {
298
- public tex: string = '';
299
- public display: boolean = false;
300
- public engine: string | null = null;
301
- }
302
- </script>
328
+ return `<template>
329
+ ${branches}
330
+ </template>
331
+
332
+ <script client>
333
+ export default class Math {
334
+ public tex: string = '';
335
+ public display: boolean = false;
336
+ public engine: string | null = null;
337
+ }
338
+ </script>
303
339
  `;
304
340
  }
305
341
  /**
@@ -316,18 +352,18 @@ function buildCodeFacade(defaultEngine, engines) {
316
352
  return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :code="code" :lang="lang" :theme="theme" />`;
317
353
  })
318
354
  .join('\n');
319
- return `<template>
320
- ${branches}
321
- </template>
322
-
323
- <script client>
324
- export default class Code {
325
- public code: string = '';
326
- public lang: string = 'text';
327
- public theme: string | null = null;
328
- public engine: string | null = null;
329
- }
330
- </script>
355
+ return `<template>
356
+ ${branches}
357
+ </template>
358
+
359
+ <script client>
360
+ export default class Code {
361
+ public code: string = '';
362
+ public lang: string = 'text';
363
+ public theme: string | null = null;
364
+ public engine: string | null = null;
365
+ }
366
+ </script>
331
367
  `;
332
368
  }
333
369
  /**
@@ -344,16 +380,16 @@ function buildMarkdownFacade(defaultEngine, engines) {
344
380
  return ` <${tag} ${kw}="(engine || ${defaultLit}) === ${engLit}" :source="source" />`;
345
381
  })
346
382
  .join('\n');
347
- return `<template>
348
- ${branches}
349
- </template>
350
-
351
- <script client>
352
- export default class Markdown {
353
- public source: string = '';
354
- public engine: string | null = null;
355
- }
356
- </script>
383
+ return `<template>
384
+ ${branches}
385
+ </template>
386
+
387
+ <script client>
388
+ export default class Markdown {
389
+ public source: string = '';
390
+ public engine: string | null = null;
391
+ }
392
+ </script>
357
393
  `;
358
394
  }
359
395
  /** Embed a JS string literal inside a double-quoted Vue attribute. */
@@ -46,6 +46,10 @@ export declare function lowerMiniprogramBindingEventJson(rootPath: string): stri
46
46
  export declare function lowerMiniprogramStructureJson(rootPath: string): string;
47
47
  export declare function lowerMiniprogramRouteServerStyleJson(rootPath: string): string;
48
48
  export declare function lowerMiniprogramToolingDeployJson(rootPath: string): string;
49
+ /**
50
+ * Consume the prepared `dist/_vmz/wechat-packaging.json` snapshot.
51
+ * Callers that start from a config must `await prepareWechatPackaging(rootPath)` first.
52
+ */
49
53
  export declare function lowerMiniprogramWechatPackagingJson(rootPath: string): string;
50
54
  export declare function lowerMiniprogramMultiAdapterJson(rootPath: string): string;
51
55
  import { createMiniHost } from './mini-host.js';
@@ -99,7 +103,7 @@ export { CDN_POLICY_MANIFEST_SCHEMA, CDN_ADAPTER_PROJECTION_SCHEMA, CACHE_HTML,
99
103
  export { SITE_DELIVERY_CONTRACT_SCHEMA, SITE_DELIVERY_RESOLUTION_SCHEMA, defineSite, normalizeSiteDelivery, normalizeSourceProbe, resolveSiteRelease, probeReleaseDirectory, emitSiteDelivery, } from './site-delivery.js';
100
104
  export { EMBEDDED_RESOURCE_INDEX_SCHEMA, emitEmbeddedPackaging } from './embedded-packaging.js';
101
105
  export { SERVER_LANG_IDS, SERVER_LANG_ALIASES, SERVER_LANGUAGE_BACKENDS, resolveServerLanguage, assertLangRuntimePair, } from './server-language-backend.js';
102
- export { WECHAT_PACKAGING_SCHEMA, WECHAT_PACKAGING_REL, wechatPackagingFromDelivery, materializeWechatPackaging } from './wechat-packaging.js';
106
+ export { WECHAT_PACKAGING_SCHEMA, WECHAT_PACKAGING_REL, wechatPackagingFromDelivery, materializeWechatPackaging, prepareWechatPackaging, } from './wechat-packaging.js';
103
107
  export { DELIVERY_PROFILE_AUTHORING_SCHEMA, BUILD_PROFILE_SELECTION_SCHEMA, ASSEMBLIES, SERVER_RUNTIMES, BUILTIN_PROFILES, pickSiteAuthoring, pickDeliveryPackaging, normalizeProfileArtifactName, resolveProfileArtifactDir, normalizeDeliveryAuthoring, selectBuildProfile, semanticIdsForAssembly, } from '../delivery/delivery-profile.js';
104
108
  export { PACK_MANIFEST_SCHEMA, packFromDeploymentIr, ensureRuntimeCompanions } from './pack.js';
105
109
  export { SERVER_ARTIFACT_SCHEMA, HTTP_CONTRACT_SCHEMA, SERVER_RUNTIME_ADAPTER_SCHEMA, emitServerArtifact, projectServerRuntimeAdapter, } from './server-artifact.js';