@vmz/vmz 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ import { registerDocumentCommands } from '../document/document-cmd.js';
|
|
|
13
13
|
import { buildIntegratedDocuments, projectHasDocuments } from '../document/document-integrate.js';
|
|
14
14
|
import { registerExplainCommand } from './explain-cmd.js';
|
|
15
15
|
import { registerGithubActionsCommand } from './github-actions-cmd.js';
|
|
16
|
+
import { registerInitCommands } from './init-cmd.js';
|
|
16
17
|
import { createWorkspace, getProtocolVersions, HOST_PROTOCOL, materializeServeHostRuntime, materializeWechatPackaging, resolveCoreRuntimeDist, resolveNativePath, } from '../workspace/public-api.js';
|
|
17
18
|
import { gateGlobalProjectCommand, getInvocationContext, isGlobalAllowedCommand } from '../workspace/invocation.js';
|
|
18
19
|
import { emitLocaleRuntimeModules, localeHasErrors } from '../locale/locale-check.js';
|
|
@@ -92,6 +93,7 @@ function buildProductCli(opts = {}) {
|
|
|
92
93
|
registerRefactorCommands(cli.command('refactor', 'cli.cmd.refactor'));
|
|
93
94
|
registerExplainCommand(cli);
|
|
94
95
|
registerGithubActionsCommand(cli);
|
|
96
|
+
registerInitCommands(cli.command('init', 'cli.cmd.init'));
|
|
95
97
|
cli.command('version', 'cli.cmd.version').action(() => cmdVersion());
|
|
96
98
|
return cli;
|
|
97
99
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vmz init` — materialize official presets into the application workspace.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { log } from '../workspace/log.js';
|
|
8
|
+
import { resolveWorkspaceDirs } from '../workspace/resolve.js';
|
|
9
|
+
export function registerInitCommands(parent) {
|
|
10
|
+
parent
|
|
11
|
+
.command('design', 'cli.cmd.init.design')
|
|
12
|
+
.option('--preset <name>', 'cli.opt.init-preset')
|
|
13
|
+
.option('--designs-dir <dir>', 'cli.opt.init-designs-dir')
|
|
14
|
+
.option('--force', 'cli.opt.init-force')
|
|
15
|
+
.option('--dry-run', 'cli.opt.init-dry-run')
|
|
16
|
+
.action((options) => cmdInitDesign(options));
|
|
17
|
+
}
|
|
18
|
+
/** Resolve `@vmz/ui/presets/<id>` from the project and read its `files` manifest. */
|
|
19
|
+
function resolvePreset(project, id) {
|
|
20
|
+
const require = createRequire(path.join(project, 'package.json'));
|
|
21
|
+
const manifestPath = require.resolve(`@vmz/ui/presets/${id}`);
|
|
22
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
23
|
+
const files = [
|
|
24
|
+
manifest.files?.theme,
|
|
25
|
+
...(manifest.files?.tokens ?? []),
|
|
26
|
+
...(manifest.files?.themes ?? []),
|
|
27
|
+
].filter((rel) => typeof rel === 'string' && rel.length > 0);
|
|
28
|
+
if (!files.length) {
|
|
29
|
+
throw new Error(`@vmz/ui/presets/${id} has no materialize files`);
|
|
30
|
+
}
|
|
31
|
+
// `presets/<id>.v0.json` sits next to the `presets/<id>/` directory.
|
|
32
|
+
return { id: manifest.id ?? id, root: path.join(path.dirname(manifestPath), id), files };
|
|
33
|
+
}
|
|
34
|
+
function cmdInitDesign(args) {
|
|
35
|
+
const { project } = resolveWorkspaceDirs({ path: args._[0] ?? '.' });
|
|
36
|
+
const presetId = typeof args.preset === 'string' && args.preset ? args.preset : 'web-surface';
|
|
37
|
+
const force = args.force === true;
|
|
38
|
+
const dryRun = args['dry-run'] === true;
|
|
39
|
+
let preset;
|
|
40
|
+
try {
|
|
41
|
+
preset = resolvePreset(project, presetId);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
log.errorId('cli.err.init.preset', {
|
|
45
|
+
preset: presetId,
|
|
46
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
47
|
+
});
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
const designsDir = typeof args['designs-dir'] === 'string' && args['designs-dir']
|
|
51
|
+
? path.resolve(project, args['designs-dir'])
|
|
52
|
+
: path.join(project, 'designs');
|
|
53
|
+
const created = [];
|
|
54
|
+
const overwritten = [];
|
|
55
|
+
const skipped = [];
|
|
56
|
+
for (const rel of preset.files) {
|
|
57
|
+
const source = path.join(preset.root, rel);
|
|
58
|
+
const destination = path.join(designsDir, rel);
|
|
59
|
+
const existed = existsSync(destination);
|
|
60
|
+
if (existed && !force) {
|
|
61
|
+
skipped.push(rel);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!dryRun) {
|
|
65
|
+
mkdirSync(path.dirname(destination), { recursive: true });
|
|
66
|
+
writeFileSync(destination, readFileSync(source));
|
|
67
|
+
}
|
|
68
|
+
(existed ? overwritten : created).push(rel);
|
|
69
|
+
}
|
|
70
|
+
const prefix = dryRun ? 'init design (dry-run)' : 'init design';
|
|
71
|
+
console.log(`${prefix}: preset=${preset.id} designs=${designsDir}`);
|
|
72
|
+
for (const rel of created)
|
|
73
|
+
console.log(` create ${rel}`);
|
|
74
|
+
for (const rel of overwritten)
|
|
75
|
+
console.log(` overwrite ${rel}`);
|
|
76
|
+
for (const rel of skipped)
|
|
77
|
+
console.log(` skip ${rel}`);
|
|
78
|
+
console.log(`${prefix}: created=${created.length} overwritten=${overwritten.length} skipped=${skipped.length}`);
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
@@ -125,7 +125,7 @@ export function enrichDocumentContent(manifest, ctx) {
|
|
|
125
125
|
if (resolved.ok === false) {
|
|
126
126
|
diagnostics.push({
|
|
127
127
|
code: DIAG.LINK_BROKEN,
|
|
128
|
-
severity: 'error',
|
|
128
|
+
severity: resolved.severity ?? 'error',
|
|
129
129
|
message: `broken link ${JSON.stringify(href)}: ${resolved.reason}`,
|
|
130
130
|
path: page.sourcePath,
|
|
131
131
|
});
|
|
@@ -173,6 +173,14 @@ function resolveDocHref(href, fromPageKey, locale, routeBase, pageKeySet) {
|
|
|
173
173
|
const pk = stripped === '' ? 'index' : stripped;
|
|
174
174
|
if (keys.has(pk))
|
|
175
175
|
return { ok: true, locale, pageKey: pk, anchor, anchors: [] };
|
|
176
|
+
const docBase = routeBase === '/' ? '' : routeBase.replace(/\/$/, '');
|
|
177
|
+
if (docBase !== '' && !want.startsWith(`${docBase}/`) && want !== docBase) {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
reason: 'not a document route (application routes are not validated here)',
|
|
181
|
+
severity: 'warning',
|
|
182
|
+
};
|
|
183
|
+
}
|
|
176
184
|
return { ok: false, reason: 'unknown route' };
|
|
177
185
|
}
|
|
178
186
|
// Relative to current page directory
|
|
@@ -27,18 +27,23 @@ export function assertIntegratedDistReady(distDir) {
|
|
|
27
27
|
export function assertCompiledShellHtml(html) {
|
|
28
28
|
const header = html.match(/<header[^>]*data-vmz-fixture="site-header"[\s\S]*?<\/header>/i)?.[0] ?? '';
|
|
29
29
|
const footer = html.match(/<footer[^>]*data-vmz-fixture="site-footer"[\s\S]*?<\/footer>/i)?.[0] ?? '';
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const parts = [
|
|
31
|
+
{ label: 'header', tag: 'header', fixture: 'site-header', html: header },
|
|
32
|
+
{ label: 'footer', tag: 'footer', fixture: 'site-footer', html: footer },
|
|
33
|
+
];
|
|
34
|
+
for (const part of parts) {
|
|
35
|
+
if (!part.html) {
|
|
36
|
+
throw new Error(`document layout SSR missing compiled <${part.tag} data-vmz-fixture="${part.fixture}"> in chrome`);
|
|
37
|
+
}
|
|
38
|
+
const leak = part.html.match(/\{[A-Za-z][A-Za-z0-9]*\}/);
|
|
32
39
|
if (leak) {
|
|
33
|
-
throw new Error(`document layout SSR leaked binding placeholder ${leak[0]}`);
|
|
40
|
+
throw new Error(`document layout SSR leaked binding placeholder ${leak[0]} in ${part.label}`);
|
|
34
41
|
}
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
const leakedTag = part.html.match(/<(Link|Button|Icon)\b/)?.[1];
|
|
43
|
+
if (leakedTag) {
|
|
44
|
+
throw new Error(`document layout SSR leaked uncompiled <${leakedTag}> in ${part.label} (compile it or use plain HTML)`);
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
|
-
if (!header || !footer) {
|
|
40
|
-
throw new Error('document layout SSR missing compiled SiteHeader/SiteFooter fixtures');
|
|
41
|
-
}
|
|
42
47
|
}
|
|
43
48
|
async function loadCtor(distDir, chunkId) {
|
|
44
49
|
const href = pathToFileURL(path.join(distDir, `${chunkId}.client.js`)).href;
|
package/locales/en-US/cli.json
CHANGED
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
"cli.cmd.plan": "Dump frozen Rust plans via N-API",
|
|
51
51
|
"cli.cmd.plan.locale": "LocalePlan from locales/",
|
|
52
52
|
"cli.cmd.plan.document-route": "DocumentRoutePlan from documents/",
|
|
53
|
+
"cli.cmd.init": "Materialize project scaffolding from official presets",
|
|
54
|
+
"cli.cmd.init.design": "Copy the application Style Theme preset into designs/ (skip existing files)",
|
|
53
55
|
"cli.cmd.version": "Show host + native protocol versions",
|
|
54
56
|
"cli.opt.out-dir": "Workspace output root (default: dist)",
|
|
55
57
|
"cli.opt.release": "Release build (omit serve-host; pack minify; proof)",
|
|
@@ -101,7 +103,12 @@
|
|
|
101
103
|
"cli.opt.gha.timeout-minutes": "Max wait minutes for mode=wait",
|
|
102
104
|
"cli.opt.gha.interval-seconds": "Poll interval seconds for mode=wait",
|
|
103
105
|
"cli.opt.gha.required-conclusion": "Required conclusion when mode=wait (default success)",
|
|
106
|
+
"cli.opt.init-preset": "Official preset id (default web-surface)",
|
|
107
|
+
"cli.opt.init-designs-dir": "Target designs directory (default <project>/designs)",
|
|
108
|
+
"cli.opt.init-force": "Overwrite existing design files",
|
|
109
|
+
"cli.opt.init-dry-run": "Print the materialize plan without writing files",
|
|
104
110
|
"cli.err.unknown_plan_kind": "unknown plan kind `{kind}` (locale | document-route)",
|
|
111
|
+
"cli.err.init.preset": "cannot materialize preset `{preset}`: {detail} (install `@vmz/ui` in the app first)",
|
|
105
112
|
"cli.err.gha.mode": "unknown --mode {mode} (status | wait)",
|
|
106
113
|
"cli.err.gha.repo": "set --owner/--repo or GITHUB_REPOSITORY (owner/repo)",
|
|
107
114
|
"cli.err.invalid_level": "unknown --level `{level}` (error | warn | info)",
|
package/package.json
CHANGED
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
"vmz": "./bin/vmz.js"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@vmz/commander": "0.3.
|
|
7
|
-
"@vmz/core": "0.3.
|
|
8
|
-
"@vmz/diagnostic": "0.3.
|
|
9
|
-
"@vmz/plugin": "0.3.
|
|
10
|
-
"@vmz/protocol": "0.3.
|
|
6
|
+
"@vmz/commander": "0.3.11",
|
|
7
|
+
"@vmz/core": "0.3.11",
|
|
8
|
+
"@vmz/diagnostic": "0.3.11",
|
|
9
|
+
"@vmz/plugin": "0.3.11",
|
|
10
|
+
"@vmz/protocol": "0.3.11"
|
|
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.
|
|
16
|
-
"@vmz/plugin-katex": "0.3.
|
|
17
|
-
"@vmz/plugin-markdown-it": "0.3.
|
|
18
|
-
"@vmz/plugin-shiki": "0.3.
|
|
19
|
-
"@vmz/test": "0.3.
|
|
15
|
+
"@vmz/plugin": "0.3.11",
|
|
16
|
+
"@vmz/plugin-katex": "0.3.11",
|
|
17
|
+
"@vmz/plugin-markdown-it": "0.3.11",
|
|
18
|
+
"@vmz/plugin-shiki": "0.3.11",
|
|
19
|
+
"@vmz/test": "0.3.11",
|
|
20
20
|
"linkedom": "^0.18.13",
|
|
21
21
|
"typescript": "^5.8.3",
|
|
22
|
-
"vmz-plugin-conformance": "0.3.
|
|
22
|
+
"vmz-plugin-conformance": "0.3.11"
|
|
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.
|
|
84
|
-
"@vmz/vmz-darwin-x64": "0.3.
|
|
85
|
-
"@vmz/vmz-linux-arm64": "0.3.
|
|
86
|
-
"@vmz/vmz-linux-x64": "0.3.
|
|
87
|
-
"@vmz/vmz-win32-arm64": "0.3.
|
|
88
|
-
"@vmz/vmz-win32-x64": "0.3.
|
|
83
|
+
"@vmz/vmz-darwin-arm64": "0.3.11",
|
|
84
|
+
"@vmz/vmz-darwin-x64": "0.3.11",
|
|
85
|
+
"@vmz/vmz-linux-arm64": "0.3.11",
|
|
86
|
+
"@vmz/vmz-linux-x64": "0.3.11",
|
|
87
|
+
"@vmz/vmz-win32-arm64": "0.3.11",
|
|
88
|
+
"@vmz/vmz-win32-x64": "0.3.11"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
|
-
"@vmz/plugin-markdown-it": "0.3.
|
|
92
|
-
"@vmz/test": "0.3.
|
|
91
|
+
"@vmz/plugin-markdown-it": "0.3.11",
|
|
92
|
+
"@vmz/test": "0.3.11",
|
|
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.
|
|
125
|
+
"version": "0.3.11"
|
|
126
126
|
}
|