@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/node.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { ProteusCompilerBackend } from './spi';
2
+ /** NodeBackend:官方 Node 编译器后端(参考实现——conformance 基线) */
3
+ export declare function createNodeCompilerBackend(): ProteusCompilerBackend;
package/dist/node.js ADDED
@@ -0,0 +1,152 @@
1
+ // src/node.ts
2
+ import { parse as sfcParse } from "@vue/compiler-sfc";
3
+ import { parse as domParse, NodeTypes } from "@vue/compiler-dom";
4
+ import { toComponentIR, TAG_SEMANTIC_MAP } from "@proteus-vue/component-ir";
5
+ var NODE_CAPABILITIES = {
6
+ incremental: true,
7
+ // 官方 Node 后端支持增量(G-34 HMR 已有编译侧增量)
8
+ sourceMap: false,
9
+ // B4
10
+ treeShaking: false,
11
+ // B4
12
+ wasmRuntime: false,
13
+ plugins: true,
14
+ // 与 @proteus-vue/compiler 规则注册表同源
15
+ maxFileSize: 5 * 1024 * 1024
16
+ };
17
+ function camelize(s) {
18
+ return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
19
+ }
20
+ function flattenChildNodes(children) {
21
+ const out = [];
22
+ for (const c of children) {
23
+ if (c.type === NodeTypes.IF) {
24
+ const branches = c.branches ?? [];
25
+ for (const b of branches) out.push(...flattenChildNodes(b.children));
26
+ } else if (c.type === NodeTypes.FOR) {
27
+ out.push(...flattenChildNodes(c.children));
28
+ } else {
29
+ out.push(c);
30
+ }
31
+ }
32
+ return out;
33
+ }
34
+ function exprContent(exp) {
35
+ if (exp && typeof exp === "object" && "content" in exp && typeof exp.content === "string") {
36
+ return exp.content;
37
+ }
38
+ return null;
39
+ }
40
+ function elementToRenderNode(el, acc) {
41
+ const props = {};
42
+ for (const attr of el.props) {
43
+ if (attr.type === NodeTypes.ATTRIBUTE) {
44
+ const a = attr;
45
+ if (a.name === "class" || a.name === "style" || a.name === "id" || a.name === "key" || a.name === "ref") continue;
46
+ props[a.name] = a.value?.content ?? true;
47
+ continue;
48
+ }
49
+ const d = attr;
50
+ const arg = d.arg && "content" in d.arg ? d.arg.content : void 0;
51
+ const exp = exprContent(d.exp);
52
+ if (d.name === "bind") {
53
+ const key = camelize(arg ?? "");
54
+ props[key] = exp !== null ? { expr: exp } : true;
55
+ } else if (d.name === "on") {
56
+ acc.handlers.push({ name: arg ?? "tap", target: exp ?? "" });
57
+ } else if (d.name === "model") {
58
+ acc.models.push({ name: arg ?? "modelValue", expr: exp ?? "" });
59
+ } else {
60
+ props[`v-${d.name}`] = exp !== null ? exp : true;
61
+ }
62
+ }
63
+ return {
64
+ type: el.tag,
65
+ // ★G-31 语义链接:p-* 标签 → TAG_SEMANTIC_MAP 语义(渲染树 semantic 与 C-IR 树同源);非 p- → undefined(Layer 1 兼容层)
66
+ semantic: el.tag.startsWith("p-") ? TAG_SEMANTIC_MAP[el.tag] : void 0,
67
+ props,
68
+ children: flattenChildNodes(el.children).filter((c) => c.type === NodeTypes.ELEMENT).map((c) => elementToRenderNode(c, acc)),
69
+ loc: { line: el.loc.start.line, column: el.loc.start.column }
70
+ };
71
+ }
72
+ function pickConstraintProps(props) {
73
+ const out = {};
74
+ for (const k of Object.keys(props)) {
75
+ if (k.startsWith("v-")) continue;
76
+ out[k] = props[k];
77
+ }
78
+ return out;
79
+ }
80
+ function renderToComponentIR(node) {
81
+ if (!node.type.startsWith("p-")) return null;
82
+ const children = node.children.map(renderToComponentIR).filter(Boolean);
83
+ return toComponentIR(node.type, pickConstraintProps(node.props), children);
84
+ }
85
+ function buildIR(template) {
86
+ const root = domParse(template, { onError: () => void 0 });
87
+ const rootEl = flattenChildNodes(root.children).find((c) => c.type === NodeTypes.ELEMENT);
88
+ if (!rootEl) {
89
+ return {
90
+ render: { type: "template", props: {}, children: [], loc: { line: 1, column: 1 } },
91
+ semantic: { tree: null, semanticCount: 0, compatCount: 0 },
92
+ bindings: { capabilities: [], models: [], handlers: [] }
93
+ };
94
+ }
95
+ const acc = { capabilities: [], models: [], handlers: [] };
96
+ const render = elementToRenderNode(rootEl, acc);
97
+ const tree = renderToComponentIR(render);
98
+ const semanticCount = tree ? countCIR(tree) : 0;
99
+ const compatCount = countCompat(render);
100
+ if (tree) {
101
+ collectCapabilities(tree, acc);
102
+ }
103
+ return { render, semantic: { tree, semanticCount, compatCount }, bindings: acc };
104
+ }
105
+ function countCIR(node) {
106
+ return 1 + node.children.reduce((acc, c) => acc + countCIR(c), 0);
107
+ }
108
+ function countCompat(node) {
109
+ let n = 0;
110
+ if (node.type !== "#text" && node.type !== "#interpolation" && node.type !== "#comment" && !node.semantic) n++;
111
+ for (const c of node.children) n += countCompat(c);
112
+ return n;
113
+ }
114
+ function collectCapabilities(node, acc) {
115
+ if (node.semantic.startsWith("capability.")) {
116
+ acc.capabilities.push({ name: node.semantic.slice("capability.".length), semantic: node.semantic });
117
+ }
118
+ for (const c of node.children) collectCapabilities(c, acc);
119
+ }
120
+ function renderToTemplateNode(node) {
121
+ return {
122
+ type: node.type === "#text" ? "text" : node.type === "#interpolation" ? "interpolation" : node.type === "#comment" ? "comment" : "element",
123
+ tag: node.type,
124
+ props: { ...node.props },
125
+ children: node.children.map(renderToTemplateNode),
126
+ line: node.loc.line
127
+ };
128
+ }
129
+ function createNodeCompilerBackend() {
130
+ return {
131
+ id: "node",
132
+ version: "0.1.0",
133
+ minCompatVersion: 1,
134
+ capabilities: NODE_CAPABILITIES,
135
+ compile(sfc) {
136
+ const { descriptor } = sfcParse(sfc.source, { filename: sfc.filename ?? "anonymous.vue" });
137
+ const template = descriptor.template?.content ?? "";
138
+ const { render, semantic, bindings } = buildIR(template);
139
+ return { version: 1, render: { root: render }, semantic, bindings };
140
+ },
141
+ parse(template) {
142
+ const ir = buildIR(template);
143
+ return { root: renderToTemplateNode(ir.render) };
144
+ },
145
+ generate(ir) {
146
+ return { code: JSON.stringify(ir, null, 2), warnings: [] };
147
+ }
148
+ };
149
+ }
150
+ export {
151
+ createNodeCompilerBackend
152
+ };
package/dist/spi.d.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { ComponentIR } from '@proteus-vue/component-ir';
2
+ export interface SFCSource {
3
+ filename?: string;
4
+ source: string;
5
+ }
6
+ export interface SourceLoc {
7
+ line: number;
8
+ column: number;
9
+ }
10
+ export type TemplateNodeType = 'element' | 'text' | 'interpolation' | 'comment';
11
+ export interface TemplateNode {
12
+ type: TemplateNodeType;
13
+ /** element 时的标签名(p-grid/view/...) */
14
+ tag: string;
15
+ /** element 时的规范化属性(静态属性 camelCase→字符串;动态绑定 → { expr }) */
16
+ props: Record<string, unknown>;
17
+ children: TemplateNode[];
18
+ line: number;
19
+ }
20
+ export interface TemplateAST {
21
+ root: TemplateNode;
22
+ }
23
+ /** 渲染 IR 节点(G-27 nodeOps 消费:有 semantic 走语义映射;无 semantic 属 Layer 1 兼容层按 type 原样) */
24
+ export interface RenderNode {
25
+ type: string;
26
+ semantic?: string;
27
+ props: Record<string, unknown>;
28
+ children: RenderNode[];
29
+ loc: SourceLoc;
30
+ }
31
+ export interface RenderIR {
32
+ root: RenderNode;
33
+ }
34
+ /** 语义 IR(G-31 C-IR 树——真实模板编译 → toComponentIR;非 p- 标签不产生 Layer 0 C-IR) */
35
+ export interface SemanticIR {
36
+ tree: ComponentIR | null;
37
+ /** C-IR 树节点数(= 渲染树中带 semantic 的元素数——conformance 交叉核对) */
38
+ semanticCount: number;
39
+ /** 兼容层元素数(渲染树中无 semantic 的元素——view/text/scroll-view 等) */
40
+ compatCount: number;
41
+ }
42
+ /** 布局约束(G-22——B1 占位,v1 可选) */
43
+ export interface LayoutConstraintIR {
44
+ }
45
+ export interface BindingIR {
46
+ /** 能力入口(p-scan-qr 等 capability.* 语义组件——G-28 消费) */
47
+ capabilities: Array<{
48
+ name: string;
49
+ semantic: string;
50
+ }>;
51
+ /** v-model 绑定(name → 表达式) */
52
+ models: Array<{
53
+ name: string;
54
+ expr: string;
55
+ }>;
56
+ /** 事件处理器(@click → target 方法名) */
57
+ handlers: Array<{
58
+ name: string;
59
+ target: string;
60
+ }>;
61
+ }
62
+ export interface CompilerIR {
63
+ /** IR 契约版本(版本协商:backend.minCompatVersion ≤ 1) */
64
+ version: 1;
65
+ render: RenderIR;
66
+ semantic: SemanticIR;
67
+ bindings: BindingIR;
68
+ layout?: LayoutConstraintIR;
69
+ }
70
+ export interface CompilerCapabilities {
71
+ /** HMR 增量编译 */
72
+ incremental: boolean;
73
+ sourceMap: boolean;
74
+ treeShaking: boolean;
75
+ /** 能否在浏览器跑(WASM) */
76
+ wasmRuntime: boolean;
77
+ /** 是否支持 G-21 Plugin */
78
+ plugins: boolean;
79
+ maxFileSize: number;
80
+ }
81
+ export interface FileChange {
82
+ file: string;
83
+ type: 'create' | 'update' | 'delete';
84
+ }
85
+ export interface UpdatePayload {
86
+ file: string;
87
+ action: 'update' | 'reload';
88
+ code?: string;
89
+ }
90
+ export interface SourceMap {
91
+ version: 3;
92
+ sources: string[];
93
+ mappings: string;
94
+ }
95
+ export interface ProteusCompilerBackend {
96
+ readonly id: string;
97
+ readonly version: string;
98
+ /** 产出 IR 的最低兼容版本(当前契约 = 1;不匹配 → CMP004 版本不兼容) */
99
+ readonly minCompatVersion: number;
100
+ readonly capabilities: CompilerCapabilities;
101
+ /** SFC 源码 → CompilerIR(B1 核心:真实模板编译 → 语义 IR) */
102
+ compile(sfc: SFCSource): CompilerIR;
103
+ /** 模板字符串 → 结构化元素树(中间产物,后端无关) */
104
+ parse(template: string): TemplateAST;
105
+ /** IR → 代码生成(B1 最小实现:序列化;产物代码生成后续批次) */
106
+ generate(ir: CompilerIR): {
107
+ code: string;
108
+ warnings: string[];
109
+ };
110
+ hotUpdate?(changes: FileChange[]): UpdatePayload;
111
+ generateSourceMap?(): SourceMap;
112
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@proteus-vue/compiler-backend",
3
+ "version": "0.1.0",
4
+ "description": "G-29 编译器可插拔后端:CompilerIR 契约 + conformance(CMP002/CMP004 + G-31.1 语义链接)+ NodeBackend 参考实现(真实模板编译 → C-IR 语义树)——编译、逻辑、UI、能力四维可插拔(原则 #10 终极形态)",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./package.json": "./package.json",
16
+ "./node": {
17
+ "types": "./dist/node.d.ts",
18
+ "import": "./dist/node.js",
19
+ "default": "./dist/node.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.build.json --emitDeclarationOnly && esbuild src/index.ts --bundle --format=esm --platform=node --outfile=dist/index.js --external:@vue/compiler-sfc --external:@vue/compiler-dom --external:@proteus-vue/component-ir && esbuild src/node.ts --bundle --format=esm --platform=neutral --outfile=dist/node.js --external:@vue/compiler-sfc --external:@vue/compiler-dom --external:@proteus-vue/component-ir"
28
+ },
29
+ "dependencies": {
30
+ "@proteus-vue/component-ir": "0.1.0"
31
+ },
32
+ "peerDependencies": {
33
+ "@vue/compiler-dom": "^3.4",
34
+ "@vue/compiler-sfc": "^3.4"
35
+ },
36
+ "devDependencies": {
37
+ "@vue/compiler-dom": "^3.5.42",
38
+ "@vue/compiler-sfc": "^3.5.42",
39
+ "@proteus-vue/types": "workspace:*"
40
+ }
41
+ }