@proteus-vue/compiler-backend 0.1.0

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/index.js ADDED
@@ -0,0 +1,1061 @@
1
+ // src/conformance.ts
2
+ import { TAG_SEMANTIC_MAP } from "@proteus-vue/component-ir";
3
+ var DEFAULT_CONFORMANCE_SFC = `<template>
4
+ <p-stack :gap="12">
5
+ <p-grid :min-col-width="160" :max-cols="4">
6
+ <p-box />
7
+ <view class="compat"></view>
8
+ </p-grid>
9
+ <p-text>{{ title }}</p-text>
10
+ <p-button @click="onSave">\u4FDD\u5B58</p-button>
11
+ <p-input v-model="keyword" />
12
+ <p-scan-qr />
13
+ </p-stack>
14
+ </template>`;
15
+ function walkRender(node, fn) {
16
+ fn(node);
17
+ for (const c of node.children) walkRender(c, fn);
18
+ }
19
+ function countCIR(node) {
20
+ return 1 + node.children.reduce((acc, c) => acc + countCIR(c), 0);
21
+ }
22
+ function runCompilerConformance(backend, fixture = DEFAULT_CONFORMANCE_SFC) {
23
+ const checks = [];
24
+ function check(name, pass, detail) {
25
+ checks.push({ name, pass, detail });
26
+ }
27
+ check("id", typeof backend.id === "string" && backend.id.length > 0, `id=${String(backend.id)}`);
28
+ check("version", typeof backend.version === "string" && backend.version.length > 0, `version=${String(backend.version)}`);
29
+ check("minCompatVersion", backend.minCompatVersion === 1, `minCompatVersion=${String(backend.minCompatVersion)}\uFF08\u5951\u7EA6=1\uFF0CCMP004\uFF09`);
30
+ const caps = backend.capabilities;
31
+ if (!caps) {
32
+ check("capabilities", false, "\u7F3A\u5931 capabilities \u58F0\u660E");
33
+ } else {
34
+ check("capabilities.incremental", typeof caps.incremental === "boolean", `incremental=${String(caps.incremental)}`);
35
+ check("capabilities.sourceMap", typeof caps.sourceMap === "boolean", `sourceMap=${String(caps.sourceMap)}`);
36
+ check("capabilities.treeShaking", typeof caps.treeShaking === "boolean", `treeShaking=${String(caps.treeShaking)}`);
37
+ check("capabilities.wasmRuntime", typeof caps.wasmRuntime === "boolean", `wasmRuntime=${String(caps.wasmRuntime)}`);
38
+ check("capabilities.plugins", typeof caps.plugins === "boolean", `plugins=${String(caps.plugins)}`);
39
+ check("capabilities.maxFileSize", typeof caps.maxFileSize === "number" && caps.maxFileSize > 0, `maxFileSize=${String(caps.maxFileSize)}`);
40
+ }
41
+ let ir = null;
42
+ try {
43
+ ir = backend.compile({ filename: "conformance.vue", source: fixture });
44
+ } catch (e) {
45
+ check("compile", false, "compile \u629B\u9519: " + e.message);
46
+ }
47
+ if (ir) {
48
+ check("ir.version", ir.version === 1, `version=${String(ir.version)}\uFF08CMP004\uFF09`);
49
+ let semanticNodes = 0;
50
+ let compatElements = 0;
51
+ let linkBroken = [];
52
+ try {
53
+ walkRender(ir.render.root, (n) => {
54
+ check(`render.${n.type}`, typeof n.type === "string" && n.type.length > 0, `type=${n.type}`);
55
+ if (typeof n.type !== "string" || !Array.isArray(n.children)) {
56
+ return;
57
+ }
58
+ if (n.semantic) {
59
+ semanticNodes++;
60
+ const expected = n.type.startsWith("p-") ? TAG_SEMANTIC_MAP[n.type] : void 0;
61
+ if (n.type.startsWith("p-")) {
62
+ if (expected === void 0) {
63
+ linkBroken.push(`${n.type}\uFF08TAG_SEMANTIC_MAP \u672A\u767B\u8BB0\uFF09`);
64
+ } else if (expected !== n.semantic) {
65
+ linkBroken.push(`${n.type}: semantic=${n.semantic} \u2260 \u671F\u671B ${expected}`);
66
+ }
67
+ } else {
68
+ linkBroken.push(`${n.type}: \u975E p- \u5143\u7D20\u4E0D\u5E94\u643A\u5E26 semantic`);
69
+ }
70
+ } else if (n.type !== "#text" && n.type !== "#interpolation" && n.type !== "#comment") {
71
+ compatElements++;
72
+ }
73
+ });
74
+ } catch (e) {
75
+ check("render.tree", false, "render \u6811\u904D\u5386\u629B\u9519: " + e.message);
76
+ }
77
+ check("render.semanticLink", linkBroken.length === 0, linkBroken.length ? linkBroken.join("; ") : void 0);
78
+ const sem = ir.semantic;
79
+ if (!sem) {
80
+ check("ir.semantic", false, "\u7F3A\u5931 semantic IR");
81
+ } else {
82
+ check("ir.semantic.tree", sem.tree === null || typeof sem.tree.tag === "string" && typeof sem.tree.semantic === "string", sem.tree ? `root=${sem.tree.tag}\u2192${sem.tree.semantic}` : "tree=null");
83
+ const irCount = sem.tree ? countCIR(sem.tree) : 0;
84
+ check("ir.semantic.countMatch", irCount === sem.semanticCount, `C-IR \u6811 ${irCount} \u8282\u70B9 vs semanticCount=${sem.semanticCount}`);
85
+ check("ir.semantic.renderMatch", sem.semanticCount === semanticNodes, `semanticCount=${sem.semanticCount} vs \u6E32\u67D3\u6811\u8BED\u4E49\u8282\u70B9 ${semanticNodes}`);
86
+ check("ir.semantic.compatCount", sem.compatCount === compatElements, `compatCount=${sem.compatCount} vs \u6E32\u67D3\u6811\u517C\u5BB9\u5143\u7D20 ${compatElements}`);
87
+ }
88
+ const b = ir.bindings;
89
+ check("bindings.capabilities", Array.isArray(b?.capabilities), void 0);
90
+ check("bindings.models", Array.isArray(b?.models), void 0);
91
+ check("bindings.handlers", Array.isArray(b?.handlers), void 0);
92
+ }
93
+ try {
94
+ const ast = backend.parse("<p-grid />");
95
+ check("parse", typeof ast.root === "object" && ast.root !== null, `root.type=${String(ast?.root?.type)}`);
96
+ } catch (e) {
97
+ check("parse", false, "parse \u629B\u9519: " + e.message);
98
+ }
99
+ try {
100
+ if (ir) {
101
+ const gen = backend.generate(ir);
102
+ check("generate", typeof gen.code === "string" && Array.isArray(gen.warnings), void 0);
103
+ }
104
+ } catch {
105
+ check("generate", false, "generate \u629B\u9519");
106
+ }
107
+ if (backend.hotUpdate !== void 0 && typeof backend.hotUpdate !== "function") check("optional.hotUpdate", false, "hotUpdate \u975E\u51FD\u6570");
108
+ if (backend.generateSourceMap !== void 0 && typeof backend.generateSourceMap !== "function") check("optional.generateSourceMap", false, "generateSourceMap \u975E\u51FD\u6570");
109
+ return { ok: checks.every((c) => c.pass), checks };
110
+ }
111
+
112
+ // src/node.ts
113
+ import { parse as sfcParse } from "@vue/compiler-sfc";
114
+ import { parse as domParse, NodeTypes } from "@vue/compiler-dom";
115
+ import { toComponentIR, TAG_SEMANTIC_MAP as TAG_SEMANTIC_MAP2 } from "@proteus-vue/component-ir";
116
+ var NODE_CAPABILITIES = {
117
+ incremental: true,
118
+ // 官方 Node 后端支持增量(G-34 HMR 已有编译侧增量)
119
+ sourceMap: false,
120
+ // B4
121
+ treeShaking: false,
122
+ // B4
123
+ wasmRuntime: false,
124
+ plugins: true,
125
+ // 与 @proteus-vue/compiler 规则注册表同源
126
+ maxFileSize: 5 * 1024 * 1024
127
+ };
128
+ function camelize(s) {
129
+ return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
130
+ }
131
+ function flattenChildNodes(children) {
132
+ const out = [];
133
+ for (const c of children) {
134
+ if (c.type === NodeTypes.IF) {
135
+ const branches = c.branches ?? [];
136
+ for (const b of branches) out.push(...flattenChildNodes(b.children));
137
+ } else if (c.type === NodeTypes.FOR) {
138
+ out.push(...flattenChildNodes(c.children));
139
+ } else {
140
+ out.push(c);
141
+ }
142
+ }
143
+ return out;
144
+ }
145
+ function exprContent(exp) {
146
+ if (exp && typeof exp === "object" && "content" in exp && typeof exp.content === "string") {
147
+ return exp.content;
148
+ }
149
+ return null;
150
+ }
151
+ function elementToRenderNode(el, acc) {
152
+ const props = {};
153
+ for (const attr of el.props) {
154
+ if (attr.type === NodeTypes.ATTRIBUTE) {
155
+ const a = attr;
156
+ if (a.name === "class" || a.name === "style" || a.name === "id" || a.name === "key" || a.name === "ref") continue;
157
+ props[a.name] = a.value?.content ?? true;
158
+ continue;
159
+ }
160
+ const d = attr;
161
+ const arg = d.arg && "content" in d.arg ? d.arg.content : void 0;
162
+ const exp = exprContent(d.exp);
163
+ if (d.name === "bind") {
164
+ const key = camelize(arg ?? "");
165
+ props[key] = exp !== null ? { expr: exp } : true;
166
+ } else if (d.name === "on") {
167
+ acc.handlers.push({ name: arg ?? "tap", target: exp ?? "" });
168
+ } else if (d.name === "model") {
169
+ acc.models.push({ name: arg ?? "modelValue", expr: exp ?? "" });
170
+ } else {
171
+ props[`v-${d.name}`] = exp !== null ? exp : true;
172
+ }
173
+ }
174
+ return {
175
+ type: el.tag,
176
+ // ★G-31 语义链接:p-* 标签 → TAG_SEMANTIC_MAP 语义(渲染树 semantic 与 C-IR 树同源);非 p- → undefined(Layer 1 兼容层)
177
+ semantic: el.tag.startsWith("p-") ? TAG_SEMANTIC_MAP2[el.tag] : void 0,
178
+ props,
179
+ children: flattenChildNodes(el.children).filter((c) => c.type === NodeTypes.ELEMENT).map((c) => elementToRenderNode(c, acc)),
180
+ loc: { line: el.loc.start.line, column: el.loc.start.column }
181
+ };
182
+ }
183
+ function pickConstraintProps(props) {
184
+ const out = {};
185
+ for (const k of Object.keys(props)) {
186
+ if (k.startsWith("v-")) continue;
187
+ out[k] = props[k];
188
+ }
189
+ return out;
190
+ }
191
+ function renderToComponentIR(node) {
192
+ if (!node.type.startsWith("p-")) return null;
193
+ const children = node.children.map(renderToComponentIR).filter(Boolean);
194
+ return toComponentIR(node.type, pickConstraintProps(node.props), children);
195
+ }
196
+ function buildIR(template) {
197
+ const root = domParse(template, { onError: () => void 0 });
198
+ const rootEl = flattenChildNodes(root.children).find((c) => c.type === NodeTypes.ELEMENT);
199
+ if (!rootEl) {
200
+ return {
201
+ render: { type: "template", props: {}, children: [], loc: { line: 1, column: 1 } },
202
+ semantic: { tree: null, semanticCount: 0, compatCount: 0 },
203
+ bindings: { capabilities: [], models: [], handlers: [] }
204
+ };
205
+ }
206
+ const acc = { capabilities: [], models: [], handlers: [] };
207
+ const render = elementToRenderNode(rootEl, acc);
208
+ const tree = renderToComponentIR(render);
209
+ const semanticCount = tree ? countCIR2(tree) : 0;
210
+ const compatCount = countCompat(render);
211
+ if (tree) {
212
+ collectCapabilities(tree, acc);
213
+ }
214
+ return { render, semantic: { tree, semanticCount, compatCount }, bindings: acc };
215
+ }
216
+ function countCIR2(node) {
217
+ return 1 + node.children.reduce((acc, c) => acc + countCIR2(c), 0);
218
+ }
219
+ function countCompat(node) {
220
+ let n = 0;
221
+ if (node.type !== "#text" && node.type !== "#interpolation" && node.type !== "#comment" && !node.semantic) n++;
222
+ for (const c of node.children) n += countCompat(c);
223
+ return n;
224
+ }
225
+ function collectCapabilities(node, acc) {
226
+ if (node.semantic.startsWith("capability.")) {
227
+ acc.capabilities.push({ name: node.semantic.slice("capability.".length), semantic: node.semantic });
228
+ }
229
+ for (const c of node.children) collectCapabilities(c, acc);
230
+ }
231
+ function renderToTemplateNode(node) {
232
+ return {
233
+ type: node.type === "#text" ? "text" : node.type === "#interpolation" ? "interpolation" : node.type === "#comment" ? "comment" : "element",
234
+ tag: node.type,
235
+ props: { ...node.props },
236
+ children: node.children.map(renderToTemplateNode),
237
+ line: node.loc.line
238
+ };
239
+ }
240
+ function createNodeCompilerBackend() {
241
+ return {
242
+ id: "node",
243
+ version: "0.1.0",
244
+ minCompatVersion: 1,
245
+ capabilities: NODE_CAPABILITIES,
246
+ compile(sfc) {
247
+ const { descriptor } = sfcParse(sfc.source, { filename: sfc.filename ?? "anonymous.vue" });
248
+ const template = descriptor.template?.content ?? "";
249
+ const { render, semantic, bindings } = buildIR(template);
250
+ return { version: 1, render: { root: render }, semantic, bindings };
251
+ },
252
+ parse(template) {
253
+ const ir = buildIR(template);
254
+ return { root: renderToTemplateNode(ir.render) };
255
+ },
256
+ generate(ir) {
257
+ return { code: JSON.stringify(ir, null, 2), warnings: [] };
258
+ }
259
+ };
260
+ }
261
+
262
+ // src/dual-check.ts
263
+ import { execFileSync } from "node:child_process";
264
+ import fs from "node:fs";
265
+ import os from "node:os";
266
+ import path from "node:path";
267
+ import { createRequire } from "node:module";
268
+ var require2 = createRequire(import.meta.url);
269
+ function semanticSeq(node) {
270
+ const out = [];
271
+ const walk = (n) => {
272
+ out.push(n.semantic ?? n.type ?? "");
273
+ for (const c of n.children ?? []) walk(c);
274
+ };
275
+ walk(node);
276
+ return out;
277
+ }
278
+ function normHandlerName(name) {
279
+ return name.split(".")[0];
280
+ }
281
+ function verifyDualCompilerEquivalence(source, opts) {
282
+ if (!opts.rustBin) {
283
+ return {
284
+ status: "skipped",
285
+ details: [],
286
+ reason: "Rust \u540E\u7AEF\u4E8C\u8FDB\u5236\u672A\u627E\u5230\uFF08\u5B89\u88C5 @proteus-vue/compiler-backend-rust \u6216\u8BBE PROTEUS_CC_RUST\uFF09\u2014\u2014\u964D\u7EA7 Node \u6821\u9A8C"
287
+ };
288
+ }
289
+ const nodeIr = createNodeCompilerBackend().compile({ filename: opts.filename ?? "dual-check.vue", source });
290
+ let rustRaw;
291
+ try {
292
+ rustRaw = opts.runRust ? opts.runRust(opts.rustBin, source) : runRustCli(opts.rustBin, source);
293
+ } catch (e) {
294
+ return {
295
+ status: "mismatch",
296
+ details: [`Rust CLI \u6267\u884C\u5931\u8D25\uFF1A${e.message.slice(0, 160)}`],
297
+ reason: "rust-cli-error"
298
+ };
299
+ }
300
+ let rustIr;
301
+ try {
302
+ rustIr = JSON.parse(rustRaw);
303
+ } catch {
304
+ return { status: "mismatch", details: ["Rust CLI \u8F93\u51FA\u975E\u6CD5 JSON\uFF08\u975E CompilerIR\uFF09"], reason: "rust-invalid-json" };
305
+ }
306
+ const details = [];
307
+ const nodeRenderSeq = semanticSeq(nodeIr.render.root);
308
+ const rustRoot = rustIr.render?.root;
309
+ if (!rustRoot) {
310
+ details.push("Rust render.root \u7F3A\u5931");
311
+ } else if (JSON.stringify(semanticSeq(rustRoot)) !== JSON.stringify(nodeRenderSeq)) {
312
+ details.push("render \u6811\u8BED\u4E49\u5E8F\u5217\u4E0D\u4E00\u81F4\uFF08G-29.1\uFF09");
313
+ }
314
+ const rustSem = rustIr.semantic;
315
+ const nodeSem = nodeIr.semantic;
316
+ if (!rustSem || rustSem.semantic_count !== nodeSem.semanticCount) {
317
+ details.push(`semanticCount \u4E0D\u4E00\u81F4\uFF08Node ${nodeSem.semanticCount} vs Rust ${rustSem?.semantic_count ?? "?"}\uFF09`);
318
+ }
319
+ if (!rustSem || rustSem.compat_count !== nodeSem.compatCount) {
320
+ details.push(`compatCount \u4E0D\u4E00\u81F4\uFF08Node ${nodeSem.compatCount} vs Rust ${rustSem?.compat_count ?? "?"}\uFF09`);
321
+ }
322
+ const nodeTreeNull = nodeIr.semantic.tree == null;
323
+ const rustTreeNull = rustSem == null || rustSem.tree == null;
324
+ if (rustTreeNull !== nodeTreeNull) {
325
+ details.push(`C-IR tree null \u4E0E\u5426\u4E0D\u4E00\u81F4\uFF08Node ${nodeTreeNull} vs Rust ${rustTreeNull}\uFF09`);
326
+ }
327
+ const rb = rustIr.bindings;
328
+ const nb = nodeIr.bindings;
329
+ if (!rb || JSON.stringify(rb.handlers?.map((h) => ({ name: normHandlerName(h.name), target: h.target })) ?? []) !== JSON.stringify(nb.handlers.map((h) => ({ name: normHandlerName(h.name), target: h.target })))) {
330
+ details.push("bindings.handlers \u4E0D\u4E00\u81F4");
331
+ }
332
+ if (!rb || JSON.stringify(rb.models ?? []) !== JSON.stringify(nb.models)) {
333
+ details.push("bindings.models \u4E0D\u4E00\u81F4");
334
+ }
335
+ if (!rb || JSON.stringify(rb.capabilities ?? []) !== JSON.stringify(nb.capabilities)) {
336
+ details.push("bindings.capabilities \u4E0D\u4E00\u81F4");
337
+ }
338
+ return details.length ? { status: "mismatch", details, reason: "ir-drift" } : { status: "ok", details: [] };
339
+ }
340
+ function runRustCli(bin, source) {
341
+ const tmp = path.join(os.tmpdir(), `proteus-dual-${Math.random().toString(36).slice(2)}.vue`);
342
+ fs.writeFileSync(tmp, source, "utf-8");
343
+ try {
344
+ return execFileSync(process.execPath, [bin, "compile", tmp], { encoding: "utf-8", timeout: 3e4 });
345
+ } finally {
346
+ fs.rmSync(tmp, { force: true });
347
+ }
348
+ }
349
+ function resolveRustCliBin(projectRoot) {
350
+ const explicit = process.env.PROTEUS_CC_RUST;
351
+ if (explicit && fs.existsSync(explicit)) return explicit;
352
+ try {
353
+ const pkgJson = require2.resolve("@proteus-vue/compiler-backend-rust/package.json", {
354
+ paths: [projectRoot, process.cwd()]
355
+ });
356
+ const bin = path.join(path.dirname(pkgJson), "bin", "cli.js");
357
+ return fs.existsSync(bin) ? bin : null;
358
+ } catch {
359
+ return null;
360
+ }
361
+ }
362
+
363
+ // src/g38.ts
364
+ import { parse as sfcParse2 } from "@vue/compiler-sfc";
365
+ import { parse as domParse2, NodeTypes as NodeTypes2 } from "@vue/compiler-dom";
366
+ import { TAG_SEMANTIC_MAP as TAG_SEMANTIC_MAP3 } from "@proteus-vue/component-ir";
367
+
368
+ // src/g38-session.ts
369
+ function createG38IncrementalSession(backend, cacheDir, opts = {}) {
370
+ void cacheDir;
371
+ const sessionId = opts.id ?? "incr";
372
+ const tracked = /* @__PURE__ */ new Map();
373
+ const dependents = /* @__PURE__ */ new Map();
374
+ const invalidated = /* @__PURE__ */ new Set();
375
+ let committed = null;
376
+ let cacheHits = 0;
377
+ let recomputes = 0;
378
+ const regDeps = (file, deps) => {
379
+ for (const d of deps) {
380
+ if (!dependents.has(d)) dependents.set(d, /* @__PURE__ */ new Set());
381
+ dependents.get(d).add(file);
382
+ }
383
+ };
384
+ const trackFile = (file, content, deps = []) => {
385
+ const sig = g38Hash(`${content}|${backend.version}`);
386
+ const prev = tracked.get(file);
387
+ if (prev && prev.signature === sig) {
388
+ cacheHits++;
389
+ return;
390
+ }
391
+ recomputes++;
392
+ const ast = backend.parse({ content, path: file });
393
+ const moduleHash = ast.diagnostics?.length ? null : g38Hash(JSON.stringify(backend.transform(ast)));
394
+ if (prev) {
395
+ for (const d of prev.deps) {
396
+ const set = dependents.get(d);
397
+ if (set) {
398
+ set.delete(file);
399
+ if (!set.size) dependents.delete(d);
400
+ }
401
+ }
402
+ }
403
+ tracked.set(file, { signature: sig, content, deps, moduleHash });
404
+ regDeps(file, deps);
405
+ invalidated.delete(file);
406
+ };
407
+ const session = {
408
+ id: sessionId,
409
+ /** ★宿主驱动:注册文件内容 + 依赖(首次全量构建逐文件调用;同签名 → 缓存命中跳过重算) */
410
+ track: trackFile,
411
+ invalidate(file) {
412
+ invalidated.add(file);
413
+ },
414
+ invalidateAll() {
415
+ for (const f of tracked.keys()) invalidated.add(f);
416
+ },
417
+ /** ★局部重算:脏文件(+ 反向依赖闭包)re-track——无内容提供者时用已 track 内容比对签名 */
418
+ recompute() {
419
+ const changed = [];
420
+ const removed = [];
421
+ const added = [];
422
+ const affected = /* @__PURE__ */ new Set();
423
+ const dirty = invalidated.size ? [...invalidated] : [];
424
+ for (const file of dirty) {
425
+ let content = tracked.get(file)?.content ?? null;
426
+ if (opts.getContent) {
427
+ content = opts.getContent(file);
428
+ if (content == null) {
429
+ removed.push(file);
430
+ tracked.delete(file);
431
+ continue;
432
+ }
433
+ }
434
+ if (content == null) continue;
435
+ const sig = g38Hash(`${content}|${backend.version}`);
436
+ const prev = tracked.get(file);
437
+ if (prev && prev.signature === sig) {
438
+ cacheHits++;
439
+ invalidated.delete(file);
440
+ continue;
441
+ }
442
+ trackFile(file, content, prev?.deps ?? []);
443
+ changed.push(file);
444
+ affected.add(file);
445
+ const visitDependents = (f) => {
446
+ const set = dependents.get(f);
447
+ if (!set) return;
448
+ for (const dep of set) {
449
+ if (!affected.has(dep)) {
450
+ affected.add(dep);
451
+ changed.push(dep);
452
+ visitDependents(dep);
453
+ }
454
+ }
455
+ };
456
+ visitDependents(file);
457
+ }
458
+ invalidated.clear();
459
+ return { changed, removed, added, affectedFiles: [...affected] };
460
+ },
461
+ getDependencies(file) {
462
+ return [...tracked.get(file)?.deps ?? []];
463
+ },
464
+ getDependents(file) {
465
+ return [...dependents.get(file) ?? []];
466
+ },
467
+ commit() {
468
+ committed = {
469
+ tracked: new Map(tracked),
470
+ dependents: new Map([...dependents].map(([k, v]) => [k, new Set(v)]))
471
+ };
472
+ },
473
+ rollback() {
474
+ if (committed) {
475
+ tracked.clear();
476
+ dependents.clear();
477
+ for (const [f, t] of committed.tracked) tracked.set(f, { ...t, deps: [...t.deps] });
478
+ for (const [d, set] of committed.dependents) dependents.set(d, new Set(set));
479
+ } else {
480
+ tracked.clear();
481
+ dependents.clear();
482
+ }
483
+ invalidated.clear();
484
+ },
485
+ getStats() {
486
+ return { incremental: true, mode: "tracking", files: tracked.size, cacheHits, recomputes, hitRate: tracked.size ? Number((cacheHits / (cacheHits + recomputes) * 100).toFixed(1)) : 0 };
487
+ },
488
+ dispose() {
489
+ tracked.clear();
490
+ dependents.clear();
491
+ invalidated.clear();
492
+ }
493
+ };
494
+ return session;
495
+ }
496
+ function scanSfcImports(source) {
497
+ const script = source.includes("<script") ? source.match(/<script[^>]*>([\s\S]*?)<\/script>/i)?.[1] ?? "" : source;
498
+ const out = [];
499
+ for (const m of script.matchAll(/from\s+['"]([^'"]+)['"]/g)) {
500
+ if (m[1] && !m[1].startsWith("@proteus-vue/types")) out.push(m[1]);
501
+ }
502
+ return out;
503
+ }
504
+
505
+ // src/g38.ts
506
+ function g38Hash(s) {
507
+ let h = 5381;
508
+ for (let i = 0; i < s.length; i++) h = (h << 5) + h + s.charCodeAt(i) >>> 0;
509
+ return h.toString(16).padStart(8, "0");
510
+ }
511
+ function camelize2(s) {
512
+ return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
513
+ }
514
+ function exprContent2(exp) {
515
+ if (exp && typeof exp === "object" && "content" in exp && typeof exp.content === "string") {
516
+ return exp.content;
517
+ }
518
+ return null;
519
+ }
520
+ function flattenChildNodes2(children) {
521
+ const out = [];
522
+ for (const c of children) {
523
+ if (c.type === NodeTypes2.IF) {
524
+ const branches = c.branches ?? [];
525
+ for (const b of branches) out.push(...flattenChildNodes2(b.children));
526
+ } else if (c.type === NodeTypes2.FOR) {
527
+ out.push(...flattenChildNodes2(c.children));
528
+ } else {
529
+ out.push(c);
530
+ }
531
+ }
532
+ return out;
533
+ }
534
+ function elementToG38(el, diagnostics) {
535
+ const attributes = {};
536
+ for (const attr of el.props) {
537
+ if (attr.type === NodeTypes2.ATTRIBUTE) {
538
+ const a = attr;
539
+ if (a.name === "class" || a.name === "style" || a.name === "id" || a.name === "key" || a.name === "ref") continue;
540
+ attributes[a.name] = a.value?.content ?? true;
541
+ continue;
542
+ }
543
+ const d = attr;
544
+ const arg = d.arg && "content" in d.arg ? d.arg.content : void 0;
545
+ const exp = exprContent2(d.exp);
546
+ if (d.name === "bind") {
547
+ attributes[camelize2(arg ?? "")] = exp !== null ? { expr: exp } : true;
548
+ } else if (d.name === "model" || d.name === "on" || d.name === "slot") {
549
+ continue;
550
+ } else {
551
+ attributes[`v-${d.name}`] = exp !== null ? exp : true;
552
+ }
553
+ }
554
+ void diagnostics;
555
+ return {
556
+ kind: "element",
557
+ tag: el.tag,
558
+ attributes,
559
+ children: flattenChildNodes2(el.children).filter((c) => c.type === NodeTypes2.ELEMENT).map((c) => elementToG38(c, diagnostics)),
560
+ loc: { line: el.loc.start.line, column: el.loc.start.column }
561
+ };
562
+ }
563
+ function parseToProgram(source) {
564
+ const diagnostics = [];
565
+ let template = "";
566
+ const head = source.content.trimStart();
567
+ const looksLikeSfc = /^(?:<!--[\s\S]*?-->\s*)*<(?:template|script)\b/.test(head);
568
+ if (!looksLikeSfc) {
569
+ template = source.content;
570
+ } else {
571
+ try {
572
+ const { descriptor, errors } = sfcParse2(source.content, { filename: source.path ?? "anonymous.vue" });
573
+ for (const e of errors) {
574
+ diagnostics.push({ code: "sfc-parse", message: e.message, loc: { line: 0, column: 0 }, severity: "error" });
575
+ }
576
+ template = descriptor.template?.content ?? "";
577
+ if (!descriptor.template && (descriptor.script || descriptor.scriptSetup)) {
578
+ diagnostics.push({ code: "no-template", message: "SFC \u7F3A\u5C11 <template> \u5757", loc: { line: 0, column: 0 }, severity: "warning" });
579
+ }
580
+ } catch {
581
+ template = source.content;
582
+ }
583
+ }
584
+ const root = domParse2(template, {
585
+ onError: (e) => {
586
+ diagnostics.push({
587
+ code: `template-${e.code}`,
588
+ message: e.message,
589
+ loc: { line: e.loc?.start.line ?? 0, column: e.loc?.start.column ?? 0 },
590
+ severity: "error"
591
+ });
592
+ }
593
+ });
594
+ const nodes = flattenChildNodes2(root.children).filter((c) => c.type === NodeTypes2.ELEMENT).map((c) => elementToG38(c, diagnostics));
595
+ return { nodes, diagnostics };
596
+ }
597
+ function toComponentIRNode(el) {
598
+ if (!el.tag.startsWith("p-")) return null;
599
+ const semantic = TAG_SEMANTIC_MAP3[el.tag];
600
+ if (!semantic) return null;
601
+ const children = [];
602
+ for (const c of el.children) {
603
+ const ci = toComponentIRNode(c);
604
+ if (ci) children.push(ci);
605
+ }
606
+ const props = {};
607
+ for (const k of Object.keys(el.attributes)) {
608
+ if (k.startsWith("v-")) continue;
609
+ props[k] = el.attributes[k];
610
+ }
611
+ return { tag: el.tag, semantic, props, children };
612
+ }
613
+ function countComponentNodes(c) {
614
+ return 1 + c.children.reduce((n, ch) => n + countComponentNodes(ch), 0);
615
+ }
616
+ function createG38NodeBackend() {
617
+ let initialized = false;
618
+ const backend = {
619
+ id: "node",
620
+ version: "0.1.0",
621
+ capabilities: {
622
+ incremental: true,
623
+ // ★决策 #336:真增量会话(g38-session.ts——依赖图+签名缓存+局部重算)
624
+ aot: false,
625
+ sourceMap: false,
626
+ minify: false,
627
+ treeShake: false,
628
+ targetPlatforms: ["web"],
629
+ supportedLanguages: ["sfc", "vue"],
630
+ backend: "js",
631
+ deterministic: true
632
+ },
633
+ async initialize() {
634
+ initialized = true;
635
+ },
636
+ dispose() {
637
+ initialized = false;
638
+ },
639
+ parse(source, ctx) {
640
+ if (ctx?.filename?.endsWith(".tsx") || ctx?.filename?.endsWith(".jsx")) {
641
+ throw new Error(`G-38 parse\uFF1A\u4E0D\u652F\u6301\u8BED\u8A00 ${ctx.filename}\uFF08capabilities.supportedLanguages=['sfc','vue']\u2014\u2014TSX/JSX \u5C5E swc/oxc \u751F\u6001\u540E\u7AEF\uFF09`);
642
+ }
643
+ return parseToProgram(source);
644
+ },
645
+ transform(ast) {
646
+ const components = [];
647
+ const capabilities = [];
648
+ const collectCap = (c) => {
649
+ if (c.semantic.startsWith("capability.")) capabilities.push({ name: c.semantic.slice("capability.".length), semantic: c.semantic });
650
+ for (const ch of c.children) collectCap(ch);
651
+ };
652
+ const semanticOf = (tag) => tag.startsWith("p-") ? TAG_SEMANTIC_MAP3[tag] : void 0;
653
+ const collect = (el) => {
654
+ if (semanticOf(el.tag)) {
655
+ const ci = toComponentIRNode(el);
656
+ if (ci) {
657
+ components.push(ci);
658
+ collectCap(ci);
659
+ }
660
+ return;
661
+ }
662
+ for (const c of el.children) collect(c);
663
+ };
664
+ for (const el of ast.nodes) collect(el);
665
+ const countCompatOf = (el) => {
666
+ let n = semanticOf(el.tag) ? 0 : 1;
667
+ for (const c of el.children) n += countCompatOf(c);
668
+ return n;
669
+ };
670
+ const compatCount = ast.nodes.reduce((n, el) => n + countCompatOf(el), 0);
671
+ const semanticCount = components.reduce((n, c) => n + countComponentNodes(c), 0);
672
+ return {
673
+ id: `m-${ast.nodes.map((n) => n.tag).join("-") || "empty"}`,
674
+ imports: [],
675
+ components,
676
+ capabilities,
677
+ metadata: { semanticCount, compatCount, componentCount: components.length }
678
+ };
679
+ },
680
+ emit(module, ctx) {
681
+ const format = ctx?.format ?? "list";
682
+ let code;
683
+ if (format === "ir-json") {
684
+ code = JSON.stringify(module.components, null, 2);
685
+ } else if (format === "bundle") {
686
+ code = `/* proteus g38 bundle */
687
+ ${module.components.map((c) => `create('${c.semantic}')`).join("\n")}`;
688
+ } else {
689
+ code = module.components.map((c) => `\u251C\u2500 ${c.semantic}\uFF08${c.tag}\uFF09`).join("\n");
690
+ }
691
+ return { code, map: null, hash: g38Hash(code) };
692
+ },
693
+ createIncrementalSession(cacheDir, opts) {
694
+ return createG38IncrementalSession(backend, cacheDir, opts);
695
+ },
696
+ reportDiagnostics(module) {
697
+ void module;
698
+ return [];
699
+ },
700
+ getCacheKey(input) {
701
+ return g38Hash(`${input.content}|${backend.version}`);
702
+ },
703
+ getArtifactHash(artifact) {
704
+ return artifact.hash ?? g38Hash(artifact.code ?? "");
705
+ }
706
+ };
707
+ return backend;
708
+ }
709
+
710
+ // src/g38-fallback.ts
711
+ async function defaultLoader(id) {
712
+ if (id === "node") return createG38NodeBackend();
713
+ return null;
714
+ }
715
+ async function createG38FallbackBackend(opts) {
716
+ const load = opts.load ?? defaultLoader;
717
+ const fallbackTo = opts.fallback ?? "node";
718
+ try {
719
+ const preferred = await load(opts.preferred);
720
+ if (preferred) {
721
+ return { backend: preferred, fallback: null, isDegraded: false };
722
+ }
723
+ const log = { from: opts.preferred, to: fallbackTo, reason: `preferred backend '${opts.preferred}' \u4E0D\u53EF\u7528\uFF08\u672A\u5B89\u88C5/\u672A\u63A5\u5165\uFF09` };
724
+ opts.onFallback?.(log);
725
+ return { backend: await load(fallbackTo) ?? createG38NodeBackend(), fallback: log, isDegraded: true };
726
+ } catch (e) {
727
+ const log = { from: opts.preferred, to: fallbackTo, reason: `preferred backend '${opts.preferred}' \u52A0\u8F7D\u5931\u8D25\uFF1A${e.message.slice(0, 120)}` };
728
+ opts.onFallback?.(log);
729
+ return { backend: createG38NodeBackend(), fallback: log, isDegraded: true };
730
+ }
731
+ }
732
+
733
+ // src/g38-conformance.ts
734
+ function createG38TerminalBackend() {
735
+ const backend = {
736
+ id: "terminal",
737
+ version: "0.1.0",
738
+ capabilities: {
739
+ incremental: false,
740
+ aot: false,
741
+ sourceMap: false,
742
+ minify: false,
743
+ treeShake: false,
744
+ targetPlatforms: ["web"],
745
+ supportedLanguages: ["sfc"],
746
+ backend: "js",
747
+ deterministic: true
748
+ },
749
+ async initialize() {
750
+ backend._init = true;
751
+ },
752
+ dispose() {
753
+ backend._init = false;
754
+ },
755
+ parse(source) {
756
+ const nodes = [];
757
+ const re = /<(p-[a-z]+)([^>]*)>/g;
758
+ let m;
759
+ const content = source.content;
760
+ while ((m = re.exec(content)) !== null) {
761
+ nodes.push({ kind: "element", tag: m[1], loc: { line: 1, column: m.index } });
762
+ }
763
+ if (content.includes("<unclosed")) {
764
+ return { nodes: [], diagnostics: [{ code: "unclosed", message: "unclosed tag", loc: { line: 0, column: 0 }, severity: "error" }] };
765
+ }
766
+ return { nodes, diagnostics: [] };
767
+ },
768
+ transform(ast) {
769
+ if (ast.diagnostics?.length) return { id: "m-empty", imports: [], components: [], capabilities: [], metadata: { semanticCount: 0, compatCount: 0, componentCount: 0 } };
770
+ const map = { "p-grid": "layout.grid", "p-stack": "layout.stack", "p-scroll": "layout.scroll", "p-text": "ui.text", "p-button": "ui.button" };
771
+ const components = ast.nodes.map((n) => ({
772
+ tag: n.tag,
773
+ semantic: map[n.tag] ?? `unknown.${n.tag}`,
774
+ props: {},
775
+ children: []
776
+ }));
777
+ return { id: "m-term", imports: [], components, capabilities: [], metadata: { semanticCount: components.length, compatCount: 0, componentCount: components.length } };
778
+ },
779
+ emit(module) {
780
+ const code = module.components.map((c) => `\u251C\u2500 ${c.semantic}`).join("\n");
781
+ return { code, map: null, hash: g38Hash(code) };
782
+ },
783
+ createIncrementalSession() {
784
+ return {
785
+ id: "noop",
786
+ invalidate() {
787
+ },
788
+ invalidateAll() {
789
+ },
790
+ recompute() {
791
+ return { changed: [], removed: [], added: [], affectedFiles: [] };
792
+ },
793
+ getDependencies() {
794
+ return [];
795
+ },
796
+ getDependents() {
797
+ return [];
798
+ },
799
+ commit() {
800
+ },
801
+ rollback() {
802
+ },
803
+ getStats() {
804
+ return {};
805
+ },
806
+ dispose() {
807
+ }
808
+ };
809
+ },
810
+ reportDiagnostics() {
811
+ return [];
812
+ },
813
+ getCacheKey(source) {
814
+ return g38Hash(source.content);
815
+ },
816
+ getArtifactHash(artifact) {
817
+ return artifact.hash;
818
+ }
819
+ };
820
+ return backend;
821
+ }
822
+ var tests = [];
823
+ var register = (group) => (id, fn) => tests.push({ id: `${group}-${id}`, group, fn });
824
+ var C01 = register("C-01");
825
+ var C02 = register("C-02");
826
+ var C03 = register("C-03");
827
+ var C04 = register("C-04");
828
+ var C05 = register("C-05");
829
+ var C06 = register("C-06");
830
+ var C07 = register("C-07");
831
+ var C08 = register("C-08");
832
+ var C09 = register("C-09");
833
+ var C10 = register("C-10");
834
+ var REQUIRED = ["id", "version", "capabilities", "initialize", "dispose", "parse", "transform", "emit", "createIncrementalSession", "reportDiagnostics", "getCacheKey", "getArtifactHash"];
835
+ C01("01", (b) => {
836
+ for (const m of REQUIRED) {
837
+ if (typeof b[m] === "undefined" && m !== "version") throw new Error(`missing ${m}`);
838
+ }
839
+ });
840
+ C01("02", (b) => {
841
+ if (typeof b.id !== "string" || !b.id) throw new Error("id");
842
+ });
843
+ C01("03", (b) => {
844
+ if (!b.capabilities || typeof b.capabilities !== "object") throw new Error("capabilities");
845
+ });
846
+ C01("04", (b) => {
847
+ for (const m of ["parse", "transform", "emit"]) {
848
+ if (typeof b[m] !== "function") throw new Error(`not fn: ${m}`);
849
+ }
850
+ });
851
+ C01("05", (b) => {
852
+ if (typeof b.createIncrementalSession !== "function") throw new Error("no session");
853
+ });
854
+ C01("06", (b) => {
855
+ b.reportDiagnostics({});
856
+ b.getCacheKey?.({ content: "" });
857
+ b.getArtifactHash?.({});
858
+ });
859
+ C02("01", async (b) => {
860
+ await b.initialize();
861
+ if (!b._init && b.id !== "node") throw new Error("not init");
862
+ });
863
+ C02("02", (b) => {
864
+ b.dispose();
865
+ if (b._init) throw new Error("not disposed");
866
+ });
867
+ C02("03", async (b) => {
868
+ await b.initialize();
869
+ await b.initialize();
870
+ });
871
+ C02("04", (b) => {
872
+ b.dispose();
873
+ });
874
+ C02("05", async (b) => {
875
+ await Promise.all([b.initialize(), b.initialize()]);
876
+ });
877
+ C03("01", (b) => {
878
+ const ir = b.parse({ content: "<p-grid><p-text></p-text></p-grid>" });
879
+ if (!ir.nodes.find((n) => n.tag === "p-grid")) throw new Error("no grid");
880
+ });
881
+ C03("02", (b) => {
882
+ const ir = b.parse({ content: "<p-stack></p-stack>" });
883
+ if (!ir.nodes.find((n) => n.tag === "p-stack")) throw new Error("no stack");
884
+ });
885
+ C03("03", (b) => {
886
+ const ir = b.parse({ content: "<unclosed" });
887
+ if (!ir.diagnostics?.length) throw new Error("should diagnose, not throw");
888
+ });
889
+ C03("04", (b) => {
890
+ const ir = b.parse({ content: "<p-grid></p-grid>" });
891
+ if (!ir.nodes[0].loc) throw new Error("no loc info");
892
+ });
893
+ C03("05", (b) => {
894
+ try {
895
+ b.parse({ content: "<p-unsupported-xxx></p-unsupported-xxx>" });
896
+ } catch (e) {
897
+ throw new Error("must diagnose, not throw");
898
+ }
899
+ });
900
+ C04("01", (b) => {
901
+ const ir = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
902
+ if (ir.components[0]?.semantic !== "layout.grid") throw new Error("semantic");
903
+ });
904
+ C04("02", (b) => {
905
+ const ir = b.transform(b.parse({ content: '<p-stack snap="mandatory"></p-stack>' }));
906
+ if (ir.components[0]?.semantic !== "layout.stack") throw new Error("stack");
907
+ });
908
+ C04("03", (b) => {
909
+ const ir = b.transform(b.parse({ content: "<p-button></p-button>" }));
910
+ if (ir.components[0]?.semantic !== "ui.button") throw new Error("button");
911
+ });
912
+ C04("04", (b) => {
913
+ const ir = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
914
+ if (!Object.prototype.hasOwnProperty.call(ir.components[0], "semantic")) throw new Error("no semantic field");
915
+ });
916
+ C04("05", (b) => {
917
+ const a = b.transform(b.parse({ content: "<p-text></p-text>" }));
918
+ const c = b.transform(b.parse({ content: "<p-text></p-text>" }));
919
+ if (JSON.stringify(a) !== JSON.stringify(c)) throw new Error("not deterministic in transform");
920
+ });
921
+ C04("06", (b) => {
922
+ const ir = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
923
+ if (ir.components[0]?.semantic === "unknown.p-grid") throw new Error("should map");
924
+ });
925
+ C05("01", (b) => {
926
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
927
+ const a = b.emit(m);
928
+ if (!a.code) throw new Error("no code");
929
+ });
930
+ C05("02", (b) => {
931
+ if (!b.capabilities.sourceMap) return "SKIP";
932
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
933
+ const a = b.emit(m);
934
+ if (!a.map) throw new Error("no sourcemap");
935
+ });
936
+ C05("03", (b) => {
937
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
938
+ const a = b.emit(m);
939
+ if (!a.hash) throw new Error("no hash");
940
+ });
941
+ C05("04", (b) => {
942
+ if (!b.capabilities.treeShake) return "SKIP";
943
+ });
944
+ C05("05", (b) => {
945
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
946
+ const a1 = b.emit(m);
947
+ const a2 = b.emit(m);
948
+ if (a1.code !== a2.code) throw new Error("not deterministic emit");
949
+ });
950
+ C06("01", (b) => {
951
+ const s = b.createIncrementalSession("/tmp");
952
+ if (!s.id) throw new Error("no id");
953
+ });
954
+ C06("02", (b) => {
955
+ if (!b.capabilities.incremental) return "SKIP";
956
+ const s = b.createIncrementalSession("/tmp");
957
+ s.invalidate("a.sfc");
958
+ const diff = s.recompute();
959
+ if (!diff.affectedFiles) throw new Error("no diff");
960
+ });
961
+ C06("03", (b) => {
962
+ if (!b.capabilities.incremental) return "SKIP";
963
+ const s = b.createIncrementalSession("/tmp");
964
+ const k = s.getDependencies("a.sfc");
965
+ if (!Array.isArray(k)) throw new Error("no deps");
966
+ });
967
+ C06("04", (b) => {
968
+ if (!b.capabilities.incremental) return "SKIP";
969
+ const s = b.createIncrementalSession("/tmp");
970
+ s.invalidate("a.sfc");
971
+ s.recompute();
972
+ s.commit();
973
+ });
974
+ C06("05", (b) => {
975
+ if (!b.capabilities.incremental) return "SKIP";
976
+ const s = b.createIncrementalSession("/tmp");
977
+ s.rollback();
978
+ });
979
+ C07("01", (b) => {
980
+ if (b.id !== "node") return "SKIP";
981
+ });
982
+ C07("02", (b) => {
983
+ if (b.id !== "node") return "SKIP";
984
+ });
985
+ C07("03", (b) => {
986
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
987
+ const a = b.emit(m);
988
+ if (!a.code) throw new Error("no artifact");
989
+ });
990
+ C08("01", (b) => {
991
+ if (typeof b.benchmark !== "function") return "SKIP";
992
+ });
993
+ C08("02", (b) => {
994
+ if (b.id !== "rust") return "SKIP";
995
+ });
996
+ C08("03", (b) => {
997
+ if (b.id !== "wasm") return "SKIP";
998
+ });
999
+ C09("01", (b) => {
1000
+ const m = b.transform(b.parse({ content: "<p-grid></p-grid>" }));
1001
+ const h1 = b.getArtifactHash(b.emit(m));
1002
+ const h2 = b.getArtifactHash(b.emit(m));
1003
+ if (h1 !== h2) throw new Error(`not deterministic: ${h1} != ${h2}`);
1004
+ });
1005
+ C09("02", () => {
1006
+ return "SKIP";
1007
+ });
1008
+ C10("01", (b) => {
1009
+ const d = b.reportDiagnostics({});
1010
+ if (!Array.isArray(d)) throw new Error("not array");
1011
+ });
1012
+ C10("02", (b) => {
1013
+ const s = b.createIncrementalSession("/tmp");
1014
+ if (typeof s.getStats !== "function") throw new Error("no stats");
1015
+ });
1016
+ async function runG38Conformance(backend, opts) {
1017
+ const results = [];
1018
+ await backend.initialize();
1019
+ for (const t of tests) {
1020
+ if (opts?.only && !t.group.startsWith(opts.only)) continue;
1021
+ try {
1022
+ const ret = await t.fn(backend);
1023
+ results.push({ id: t.id, status: ret === "SKIP" ? "SKIP" : "PASS" });
1024
+ } catch (e) {
1025
+ results.push({ id: t.id, status: "FAIL", error: e.message });
1026
+ }
1027
+ }
1028
+ backend.dispose();
1029
+ return {
1030
+ total: results.length,
1031
+ pass: results.filter((r) => r.status === "PASS").length,
1032
+ fail: results.filter((r) => r.status === "FAIL").length,
1033
+ skip: results.filter((r) => r.status === "SKIP").length,
1034
+ results
1035
+ };
1036
+ }
1037
+ function formatG38Conformance(name, s) {
1038
+ const lines = [`[${name} \u540E\u7AEF]`];
1039
+ for (const r of s.results) {
1040
+ const icon = r.status === "PASS" ? "\u2705" : r.status === "SKIP" ? "\u23ED\uFE0F " : "\u274C";
1041
+ lines.push(` ${icon} ${r.id}${r.status === "FAIL" ? ` \u2014 ${r.error ?? ""}` : ""}`);
1042
+ }
1043
+ lines.push("\u2500".repeat(30));
1044
+ lines.push(`\u603B\u8BA1\uFF1APASS=${s.pass} FAIL=${s.fail} SKIP=${s.skip}\uFF08${s.total} \u9879 C-01~C-10\uFF09`);
1045
+ return lines.join("\n");
1046
+ }
1047
+ export {
1048
+ DEFAULT_CONFORMANCE_SFC,
1049
+ createG38FallbackBackend,
1050
+ createG38IncrementalSession,
1051
+ createG38NodeBackend,
1052
+ createG38TerminalBackend,
1053
+ createNodeCompilerBackend,
1054
+ formatG38Conformance,
1055
+ g38Hash,
1056
+ resolveRustCliBin,
1057
+ runCompilerConformance,
1058
+ runG38Conformance,
1059
+ scanSfcImports,
1060
+ verifyDualCompilerEquivalence
1061
+ };