@vmz/vmz 0.0.1 → 0.0.3

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 (79) hide show
  1. package/README.md +52 -2
  2. package/bin/vmz.js +4 -0
  3. package/dist/application-cmd.d.ts +21 -0
  4. package/dist/application-cmd.js +347 -0
  5. package/dist/bundler-adapter.d.ts +63 -0
  6. package/dist/bundler-adapter.js +110 -0
  7. package/dist/cli.d.ts +23 -0
  8. package/dist/cli.js +474 -0
  9. package/dist/dev-session.d.ts +35 -0
  10. package/dist/dev-session.js +290 -0
  11. package/dist/document-build.d.ts +99 -0
  12. package/dist/document-build.js +273 -0
  13. package/dist/document-check.d.ts +44 -0
  14. package/dist/document-check.js +246 -0
  15. package/dist/document-cmd.d.ts +8 -0
  16. package/dist/document-cmd.js +146 -0
  17. package/dist/document-designs.d.ts +9 -0
  18. package/dist/document-designs.js +126 -0
  19. package/dist/document-enrich.d.ts +23 -0
  20. package/dist/document-enrich.js +233 -0
  21. package/dist/document-evidence.d.ts +49 -0
  22. package/dist/document-evidence.js +509 -0
  23. package/dist/document-integrate.d.ts +34 -0
  24. package/dist/document-integrate.js +88 -0
  25. package/dist/document-interactive.d.ts +69 -0
  26. package/dist/document-interactive.js +254 -0
  27. package/dist/document-locale.d.ts +31 -0
  28. package/dist/document-locale.js +59 -0
  29. package/dist/document-markdown.d.ts +12 -0
  30. package/dist/document-markdown.js +45 -0
  31. package/dist/document-scan.d.ts +21 -0
  32. package/dist/document-scan.js +151 -0
  33. package/dist/document-schema.d.ts +86 -0
  34. package/dist/document-schema.js +87 -0
  35. package/dist/explain-cmd.d.ts +5 -0
  36. package/dist/explain-cmd.js +123 -0
  37. package/dist/index.d.ts +359 -0
  38. package/dist/index.js +580 -0
  39. package/dist/invocation.d.ts +91 -0
  40. package/dist/invocation.js +190 -0
  41. package/dist/locale-check.d.ts +106 -0
  42. package/dist/locale-check.js +736 -0
  43. package/dist/locale-cmd.d.ts +5 -0
  44. package/dist/locale-cmd.js +442 -0
  45. package/dist/locale-delivery.d.ts +298 -0
  46. package/dist/locale-delivery.js +443 -0
  47. package/dist/locale-router.d.ts +206 -0
  48. package/dist/locale-router.js +507 -0
  49. package/dist/locale-runtime.d.ts +406 -0
  50. package/dist/locale-runtime.js +541 -0
  51. package/dist/locale-schema.d.ts +8 -0
  52. package/dist/locale-schema.js +9 -0
  53. package/dist/locale-tooling.d.ts +118 -0
  54. package/dist/locale-tooling.js +357 -0
  55. package/dist/log.d.ts +19 -0
  56. package/dist/log.js +42 -0
  57. package/dist/packages.d.ts +26 -0
  58. package/dist/packages.js +146 -0
  59. package/dist/plugin-host.d.ts +29 -0
  60. package/dist/plugin-host.js +369 -0
  61. package/dist/refactor-cmd.d.ts +8 -0
  62. package/dist/refactor-cmd.js +156 -0
  63. package/dist/resolve-native-cli.d.ts +14 -0
  64. package/dist/resolve-native-cli.js +84 -0
  65. package/dist/resolve.d.ts +24 -0
  66. package/dist/resolve.js +55 -0
  67. package/dist/test-cmd.d.ts +9 -0
  68. package/dist/test-cmd.js +363 -0
  69. package/dist/test-compile.d.ts +2 -0
  70. package/dist/test-compile.js +3 -0
  71. package/dist/test-discover.d.ts +2 -0
  72. package/dist/test-discover.js +3 -0
  73. package/dist/test-logic.d.ts +2 -0
  74. package/dist/test-logic.js +3 -0
  75. package/dist/test-protocol.d.ts +2 -0
  76. package/dist/test-protocol.js +3 -0
  77. package/dist/watch-diff.d.ts +17 -0
  78. package/dist/watch-diff.js +56 -0
  79. package/package.json +96 -3
@@ -0,0 +1,233 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * Document — enrich manifest with routes, anchors, nav; diagnose links.
4
+ */
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { DIAG } from './document-schema.js';
8
+ /**
9
+ * @param {string} routeBase e.g. /docs
10
+ * @param {string} locale
11
+ * @param {string} pageKey
12
+ */
13
+ export function pageRoute(routeBase, locale, pageKey) {
14
+ const base = String(routeBase || '/').replace(/\/$/, '') || '';
15
+ const key = pageKey === 'index' ? '' : pageKey.replace(/\\/g, '/');
16
+ const parts = [base.replace(/^\//, ''), locale, key].filter((p) => p !== '');
17
+ return '/' + parts.join('/');
18
+ }
19
+ /**
20
+ * Static file path relative to out dir (posix).
21
+ * @param {string} routeBase
22
+ * @param {string} locale
23
+ * @param {string} pageKey
24
+ */
25
+ export function pageHtmlRel(routeBase, locale, pageKey) {
26
+ const base = String(routeBase || '/')
27
+ .replace(/^\//, '')
28
+ .replace(/\/$/, '');
29
+ const file = pageKey === 'index' ? 'index.html' : `${pageKey.replace(/\\/g, '/')}.html`;
30
+ return [base, locale, file].filter(Boolean).join('/');
31
+ }
32
+ /**
33
+ * @param {import('./document-schema.js').DocumentManifest} manifest
34
+ * @param {{ analyzeMarkdown: Function, projectRoot: string, designsCssHref?: string | null }} ctx
35
+ */
36
+ export function enrichDocumentContent(manifest, ctx) {
37
+ const routeBase = manifest.mounts?.[0]?.routeBase || '/docs';
38
+ /** @type {Map<string, { html: string, headings: any[], links: any[], title: string, route: string, anchors: string[] }>} */
39
+ const byId = new Map();
40
+ /** @type {import('./document-schema.js').DocumentDiagnostic[]} */
41
+ const diagnostics = [...(manifest.diagnostics || [])];
42
+ /** @type {Map<string, string>} */
43
+ const routeOwners = new Map();
44
+ for (const page of manifest.pages) {
45
+ const abs = path.isAbsolute(page.sourcePath) ? page.sourcePath : path.join(manifest.root, page.sourcePath);
46
+ const source = fs.existsSync(abs) ? fs.readFileSync(abs, 'utf8') : '';
47
+ const analyzed = ctx.analyzeMarkdown(source);
48
+ const route = pageRoute(routeBase, page.identity.locale, page.identity.pageKey);
49
+ const anchors = analyzed.headings.map((h) => h.id);
50
+ const title = analyzed.headings.find((h) => h.level === 1)?.text || analyzed.headings[0]?.text || page.identity.pageKey;
51
+ // Duplicate anchors on page
52
+ const seen = new Set();
53
+ for (const id of anchors) {
54
+ if (seen.has(id)) {
55
+ diagnostics.push({
56
+ code: DIAG.ANCHOR_DUPLICATE,
57
+ severity: 'error',
58
+ message: `duplicate anchor #${id} on ${page.identity.locale}/${page.identity.pageKey}`,
59
+ path: page.sourcePath,
60
+ });
61
+ }
62
+ seen.add(id);
63
+ }
64
+ if (routeOwners.has(route)) {
65
+ diagnostics.push({
66
+ code: DIAG.ROUTE_DUPLICATE,
67
+ severity: 'error',
68
+ message: `duplicate route ${route} (also ${routeOwners.get(route)})`,
69
+ path: page.sourcePath,
70
+ });
71
+ }
72
+ else {
73
+ routeOwners.set(route, `${page.identity.locale}:${page.identity.pageKey}`);
74
+ }
75
+ page.route = route;
76
+ page.anchors = anchors;
77
+ page.title = title;
78
+ byId.set(`${page.identity.locale}:${page.identity.pageKey}`, {
79
+ html: analyzed.html,
80
+ headings: analyzed.headings,
81
+ links: analyzed.links,
82
+ title,
83
+ route,
84
+ anchors,
85
+ });
86
+ }
87
+ // Nav per locale (directory order: pageKey sorted)
88
+ /** @type {Record<string, Array<{ pageKey: string, title: string, href: string }>>} */
89
+ const navByLocale = {};
90
+ for (const loc of manifest.locales) {
91
+ const pages = manifest.pages
92
+ .filter((p) => p.identity.locale === loc)
93
+ .slice()
94
+ .sort((a, b) => a.identity.pageKey.localeCompare(b.identity.pageKey));
95
+ navByLocale[loc] = pages.map((p) => ({
96
+ pageKey: p.identity.pageKey,
97
+ title: p.title || p.identity.pageKey,
98
+ href: p.route,
99
+ }));
100
+ }
101
+ // Link checks
102
+ const pageKeySet = new Map(); // locale -> Set pageKey
103
+ for (const p of manifest.pages) {
104
+ const set = pageKeySet.get(p.identity.locale) || new Set();
105
+ set.add(p.identity.pageKey);
106
+ pageKeySet.set(p.identity.locale, set);
107
+ }
108
+ for (const page of manifest.pages) {
109
+ const info = byId.get(`${page.identity.locale}:${page.identity.pageKey}`);
110
+ if (!info)
111
+ continue;
112
+ for (const link of info.links) {
113
+ const href = String(link.href || '').trim();
114
+ if (!href || href.startsWith('mailto:') || href.startsWith('http://') || href.startsWith('https://')) {
115
+ continue;
116
+ }
117
+ // API refs are resolved by evidence, not as page links.
118
+ if (href.startsWith('vmz-api:') || href.startsWith('api:')) {
119
+ continue;
120
+ }
121
+ if (href.startsWith('#')) {
122
+ const id = href.slice(1);
123
+ if (!info.anchors.includes(id)) {
124
+ diagnostics.push({
125
+ code: DIAG.LINK_BROKEN,
126
+ severity: 'error',
127
+ message: `broken anchor ${href} on ${page.identity.locale}/${page.identity.pageKey}`,
128
+ path: page.sourcePath,
129
+ });
130
+ }
131
+ continue;
132
+ }
133
+ const resolved = resolveDocHref(href, page.identity.pageKey, page.identity.locale, routeBase, pageKeySet);
134
+ if (!resolved.ok) {
135
+ diagnostics.push({
136
+ code: DIAG.LINK_BROKEN,
137
+ severity: 'error',
138
+ message: `broken link ${JSON.stringify(href)}: ${resolved.reason}`,
139
+ path: page.sourcePath,
140
+ });
141
+ }
142
+ else if (resolved.anchor) {
143
+ const target = byId.get(`${resolved.locale}:${resolved.pageKey}`);
144
+ const anchors = target?.anchors || [];
145
+ if (!anchors.includes(resolved.anchor)) {
146
+ diagnostics.push({
147
+ code: DIAG.LINK_BROKEN,
148
+ severity: 'error',
149
+ message: `broken link ${JSON.stringify(href)}: missing anchor #${resolved.anchor}`,
150
+ path: page.sourcePath,
151
+ });
152
+ }
153
+ }
154
+ }
155
+ }
156
+ return { byId, navByLocale, diagnostics, routeBase };
157
+ }
158
+ /**
159
+ * @param {string} href
160
+ * @param {string} fromPageKey
161
+ * @param {string} locale
162
+ * @param {string} routeBase
163
+ * @param {Map<string, Set<string>>} pageKeySet
164
+ */
165
+ function resolveDocHref(href, fromPageKey, locale, routeBase, pageKeySet) {
166
+ let pathPart = href;
167
+ let anchor = null;
168
+ const hash = href.indexOf('#');
169
+ if (hash >= 0) {
170
+ pathPart = href.slice(0, hash);
171
+ anchor = href.slice(hash + 1);
172
+ }
173
+ pathPart = pathPart.replace(/\.md$/i, '').replace(/\\/g, '/');
174
+ if (pathPart.startsWith('/')) {
175
+ // Absolute site path under mount: /docs/zh-hans/guide/install
176
+ const want = pathPart.replace(/\/$/, '') || '/';
177
+ const prefix = pageRoute(routeBase, locale, 'index').replace(/\/$/, '');
178
+ // Accept full route or locale-relative
179
+ for (const [loc, keys] of pageKeySet) {
180
+ for (const pk of keys) {
181
+ const r = pageRoute(routeBase, loc, pk).replace(/\/$/, '');
182
+ if (r === want || want.endsWith(`/${loc}/${pk === 'index' ? '' : pk}`.replace(/\/$/, ''))) {
183
+ return { ok: true, locale: loc, pageKey: pk, anchor, anchors: [] };
184
+ }
185
+ }
186
+ }
187
+ // Still ok if matches any known route shape for this locale
188
+ const keys = pageKeySet.get(locale) || new Set();
189
+ const stripped = want.replace(new RegExp(`^${escapeRe(routeBase.replace(/\/$/, ''))}/${escapeRe(locale)}/?`), '');
190
+ const pk = stripped === '' ? 'index' : stripped;
191
+ if (keys.has(pk))
192
+ return { ok: true, locale, pageKey: pk, anchor, anchors: [] };
193
+ return { ok: false, reason: 'unknown route' };
194
+ }
195
+ // Relative to current page directory
196
+ const fromDir = pageKeyDir(fromPageKey);
197
+ const joined = path.posix.normalize(path.posix.join(fromDir || '.', pathPart));
198
+ let pk = joined === '.' || joined === '' ? 'index' : joined.replace(/^\.\//, '');
199
+ pk = normalizePageKey(pk);
200
+ const keys = pageKeySet.get(locale) || new Set();
201
+ if (!keys.has(pk)) {
202
+ return { ok: false, reason: `no PageKey ${pk} in ${locale}` };
203
+ }
204
+ return { ok: true, locale, pageKey: pk, anchor, anchors: [] };
205
+ }
206
+ /**
207
+ * Directory used for relative Markdown links.
208
+ * `index` → repo root; bare `guide` (from guide/index.md) → `guide`;
209
+ * `guide/install` → `guide`.
210
+ */
211
+ function pageKeyDir(pageKey) {
212
+ if (!pageKey || pageKey === 'index')
213
+ return '';
214
+ if (!pageKey.includes('/'))
215
+ return pageKey;
216
+ return pageKey.slice(0, pageKey.lastIndexOf('/'));
217
+ }
218
+ /** Strip trailing `/index` so guide/index.md links resolve to PageKey `guide`. */
219
+ function normalizePageKey(pageKey) {
220
+ let pk = String(pageKey || '')
221
+ .replace(/\\/g, '/')
222
+ .replace(/\/+$/, '');
223
+ if (pk.endsWith('/index')) {
224
+ pk = pk.slice(0, -'/index'.length);
225
+ }
226
+ else if (pk === 'index') {
227
+ return 'index';
228
+ }
229
+ return pk === '' || pk === '.' ? 'index' : pk;
230
+ }
231
+ function escapeRe(s) {
232
+ return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
233
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @param {string} info
3
+ * @returns {{ lang: string, run: string | null, source: string | null, playground: boolean }}
4
+ */
5
+ export declare function parseFenceInfo(info: any): {
6
+ lang: string;
7
+ run: any;
8
+ source: any;
9
+ playground: boolean;
10
+ };
11
+ /**
12
+ * @param {string} href
13
+ * @returns {string | null} symbol query (chunkId or name)
14
+ */
15
+ export declare function parseApiHref(href: any): string;
16
+ /**
17
+ * @param {string} projectRoot
18
+ * @returns {Array<{ chunkId: string, name: string, path: string, capabilities: string[], programPath: string }>}
19
+ */
20
+ export declare function loadProgramApiIndex(projectRoot: any): any[];
21
+ /**
22
+ * Resolve API symbol against Program Graph index.
23
+ * @param {ReturnType<typeof loadProgramApiIndex>} index
24
+ * @param {string} query
25
+ */
26
+ export declare function resolveApiSymbol(index: any, query: any): {
27
+ status: string;
28
+ matches: any;
29
+ };
30
+ /**
31
+ * @param {import('./document-schema.js').DocumentManifest} manifest
32
+ * @param {{
33
+ * analyzeMarkdown: Function,
34
+ * projectRoot: string,
35
+ * createWorkspace?: Function,
36
+ * ensureProgramGraph?: boolean,
37
+ * }} ctx
38
+ */
39
+ export declare function enrichDocumentEvidence(manifest: any, ctx: any): Promise<{
40
+ diagnostics: any[];
41
+ evidence: {
42
+ schema: string;
43
+ fences: any[];
44
+ apiRefs: any[];
45
+ testSelections: any[];
46
+ status: string;
47
+ };
48
+ }>;
49
+ /** Lazy note: callers pass `createWorkspace` from `./index.js` (see document-cmd / document-build). */