@trojanbox-vcp-test/site-edit-engine 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.
Files changed (174) hide show
  1. package/README.md +85 -0
  2. package/dist/execute-integration/execute-fixture-harness.d.ts +25 -0
  3. package/dist/execute-integration/execute-fixture-harness.js +37 -0
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.js +2 -0
  6. package/dist/internal/ast/diagnostics/index.d.ts +5 -0
  7. package/dist/internal/ast/diagnostics/index.js +25 -0
  8. package/dist/internal/ast/history/index.d.ts +15 -0
  9. package/dist/internal/ast/history/index.js +62 -0
  10. package/dist/internal/ast/index.d.ts +8 -0
  11. package/dist/internal/ast/index.js +5 -0
  12. package/dist/internal/ast/locators/index.d.ts +1 -0
  13. package/dist/internal/ast/locators/index.js +1 -0
  14. package/dist/internal/ast/locators/resolve-locator.d.ts +16 -0
  15. package/dist/internal/ast/locators/resolve-locator.js +920 -0
  16. package/dist/internal/ast/parser/SourceParser.d.ts +30 -0
  17. package/dist/internal/ast/parser/SourceParser.js +49 -0
  18. package/dist/internal/ast/parser/index.d.ts +21 -0
  19. package/dist/internal/ast/parser/index.js +64 -0
  20. package/dist/internal/ast/primitives/conditional/conditional-primitives.d.ts +18 -0
  21. package/dist/internal/ast/primitives/conditional/conditional-primitives.js +237 -0
  22. package/dist/internal/ast/primitives/conditional/index.d.ts +1 -0
  23. package/dist/internal/ast/primitives/conditional/index.js +1 -0
  24. package/dist/internal/ast/primitives/imports/add-import.d.ts +18 -0
  25. package/dist/internal/ast/primitives/imports/add-import.js +111 -0
  26. package/dist/internal/ast/primitives/imports/index.d.ts +2 -0
  27. package/dist/internal/ast/primitives/imports/index.js +2 -0
  28. package/dist/internal/ast/primitives/imports/remove-import.d.ts +15 -0
  29. package/dist/internal/ast/primitives/imports/remove-import.js +72 -0
  30. package/dist/internal/ast/primitives/index.d.ts +10 -0
  31. package/dist/internal/ast/primitives/index.js +10 -0
  32. package/dist/internal/ast/primitives/jsx/index.d.ts +4 -0
  33. package/dist/internal/ast/primitives/jsx/index.js +4 -0
  34. package/dist/internal/ast/primitives/jsx/insert-child.d.ts +11 -0
  35. package/dist/internal/ast/primitives/jsx/insert-child.js +69 -0
  36. package/dist/internal/ast/primitives/jsx/move-node.d.ts +9 -0
  37. package/dist/internal/ast/primitives/jsx/move-node.js +76 -0
  38. package/dist/internal/ast/primitives/jsx/remove-node.d.ts +7 -0
  39. package/dist/internal/ast/primitives/jsx/remove-node.js +36 -0
  40. package/dist/internal/ast/primitives/jsx/update-text.d.ts +8 -0
  41. package/dist/internal/ast/primitives/jsx/update-text.js +81 -0
  42. package/dist/internal/ast/primitives/next/index.d.ts +1 -0
  43. package/dist/internal/ast/primitives/next/index.js +1 -0
  44. package/dist/internal/ast/primitives/next/next-primitives.d.ts +43 -0
  45. package/dist/internal/ast/primitives/next/next-primitives.js +211 -0
  46. package/dist/internal/ast/primitives/shared.d.ts +60 -0
  47. package/dist/internal/ast/primitives/shared.js +176 -0
  48. package/dist/internal/ast/primitives/style/class-expression.d.ts +23 -0
  49. package/dist/internal/ast/primitives/style/class-expression.js +174 -0
  50. package/dist/internal/ast/primitives/style/index.d.ts +1 -0
  51. package/dist/internal/ast/primitives/style/index.js +1 -0
  52. package/dist/internal/ast/primitives/style/style-primitives.d.ts +49 -0
  53. package/dist/internal/ast/primitives/style/style-primitives.js +555 -0
  54. package/dist/internal/ast/primitives/values/index.d.ts +1 -0
  55. package/dist/internal/ast/primitives/values/index.js +1 -0
  56. package/dist/internal/ast/primitives/values/value-primitives.d.ts +42 -0
  57. package/dist/internal/ast/primitives/values/value-primitives.js +158 -0
  58. package/dist/internal/ast/printer/SourcePrinter.d.ts +21 -0
  59. package/dist/internal/ast/printer/SourcePrinter.js +76 -0
  60. package/dist/internal/ast/printer/index.d.ts +6 -0
  61. package/dist/internal/ast/printer/index.js +126 -0
  62. package/dist/internal/ast/types.d.ts +190 -0
  63. package/dist/internal/ast/types.js +1 -0
  64. package/dist/internal/capability/capability-resolver.d.ts +16 -0
  65. package/dist/internal/capability/capability-resolver.js +127 -0
  66. package/dist/internal/classname-source.d.ts +24 -0
  67. package/dist/internal/classname-source.js +220 -0
  68. package/dist/internal/contracts/IEditEngineRuntime.d.ts +18 -0
  69. package/dist/internal/contracts/IEditEngineRuntime.js +1 -0
  70. package/dist/internal/domain/EditDiagnostic.d.ts +38 -0
  71. package/dist/internal/domain/EditDiagnostic.js +43 -0
  72. package/dist/internal/events/event-bus.d.ts +14 -0
  73. package/dist/internal/events/event-bus.js +21 -0
  74. package/dist/internal/graph/graph-builder.d.ts +12 -0
  75. package/dist/internal/graph/graph-builder.js +1371 -0
  76. package/dist/internal/graph/import-resolver.d.ts +31 -0
  77. package/dist/internal/graph/import-resolver.js +109 -0
  78. package/dist/internal/graph/project-graph-builder.d.ts +32 -0
  79. package/dist/internal/graph/project-graph-builder.js +133 -0
  80. package/dist/internal/graph/types.d.ts +114 -0
  81. package/dist/internal/graph/types.js +6 -0
  82. package/dist/internal/history/undo-redo.d.ts +28 -0
  83. package/dist/internal/history/undo-redo.js +42 -0
  84. package/dist/internal/index.d.ts +2 -0
  85. package/dist/internal/index.js +1 -0
  86. package/dist/internal/planner/planner.d.ts +104 -0
  87. package/dist/internal/planner/planner.js +2533 -0
  88. package/dist/internal/planner/types.d.ts +275 -0
  89. package/dist/internal/planner/types.js +6 -0
  90. package/dist/internal/protocol/boundary.d.ts +10 -0
  91. package/dist/internal/protocol/boundary.js +3 -0
  92. package/dist/internal/protocol/capability.d.ts +47 -0
  93. package/dist/internal/protocol/capability.js +8 -0
  94. package/dist/internal/protocol/error.d.ts +43 -0
  95. package/dist/internal/protocol/error.js +38 -0
  96. package/dist/internal/protocol/event.d.ts +39 -0
  97. package/dist/internal/protocol/event.js +3 -0
  98. package/dist/internal/protocol/identity.d.ts +26 -0
  99. package/dist/internal/protocol/identity.js +30 -0
  100. package/dist/internal/protocol/operation.d.ts +224 -0
  101. package/dist/internal/protocol/operation.js +8 -0
  102. package/dist/internal/protocol/render.d.ts +212 -0
  103. package/dist/internal/protocol/render.js +3 -0
  104. package/dist/internal/protocol.d.ts +9 -0
  105. package/dist/internal/protocol.js +2 -0
  106. package/dist/internal/provenance/binding-graph.d.ts +39 -0
  107. package/dist/internal/provenance/binding-graph.js +184 -0
  108. package/dist/internal/provenance/capability-policy.d.ts +15 -0
  109. package/dist/internal/provenance/capability-policy.js +96 -0
  110. package/dist/internal/provenance/data-source-classifier.d.ts +14 -0
  111. package/dist/internal/provenance/data-source-classifier.js +281 -0
  112. package/dist/internal/provenance/resolve-text-provenance.d.ts +45 -0
  113. package/dist/internal/provenance/resolve-text-provenance.js +3090 -0
  114. package/dist/internal/provenance/types.d.ts +89 -0
  115. package/dist/internal/provenance/types.js +1 -0
  116. package/dist/internal/render/component-semantic.d.ts +11 -0
  117. package/dist/internal/render/component-semantic.js +141 -0
  118. package/dist/internal/render/content-model.d.ts +3 -0
  119. package/dist/internal/render/content-model.js +89 -0
  120. package/dist/internal/render/media-model.d.ts +3 -0
  121. package/dist/internal/render/media-model.js +45 -0
  122. package/dist/internal/render/provenance-types.d.ts +33 -0
  123. package/dist/internal/render/provenance-types.js +1 -0
  124. package/dist/internal/render/render-projection.d.ts +24 -0
  125. package/dist/internal/render/render-projection.js +281 -0
  126. package/dist/internal/render/tailwind-style-model.d.ts +19 -0
  127. package/dist/internal/render/tailwind-style-model.js +1187 -0
  128. package/dist/internal/runtime/EditEngineRuntime.d.ts +25 -0
  129. package/dist/internal/runtime/EditEngineRuntime.js +89 -0
  130. package/dist/internal/runtime/EditEngineRuntimeSnapshot.d.ts +31 -0
  131. package/dist/internal/runtime/EditEngineRuntimeSnapshot.js +15 -0
  132. package/dist/internal/runtime/InternalEditEngine.d.ts +44 -0
  133. package/dist/internal/runtime/InternalEditEngine.js +1391 -0
  134. package/dist/internal/runtime.d.ts +3 -0
  135. package/dist/internal/runtime.js +1 -0
  136. package/dist/internal/topology/topology.d.ts +6 -0
  137. package/dist/internal/topology/topology.js +98 -0
  138. package/dist/internal/topology/types.d.ts +35 -0
  139. package/dist/internal/topology/types.js +5 -0
  140. package/dist/internal/types.d.ts +1 -0
  141. package/dist/internal/types.js +1 -0
  142. package/dist/internal/writeback/in-memory-fs.d.ts +7 -0
  143. package/dist/internal/writeback/in-memory-fs.js +44 -0
  144. package/dist/internal/writeback/types.d.ts +45 -0
  145. package/dist/internal/writeback/types.js +7 -0
  146. package/dist/internal/writeback/writeback-service.d.ts +7 -0
  147. package/dist/internal/writeback/writeback-service.js +568 -0
  148. package/dist/internal-adapter.d.ts +18 -0
  149. package/dist/internal-adapter.js +350 -0
  150. package/dist/next-app-router-fs.d.ts +2 -0
  151. package/dist/next-app-router-fs.js +64 -0
  152. package/dist/next-app-router.d.ts +11 -0
  153. package/dist/next-app-router.js +140 -0
  154. package/dist/preview-runtime.d.ts +394 -0
  155. package/dist/preview-runtime.js +102 -0
  156. package/dist/public-file-system.d.ts +7 -0
  157. package/dist/public-file-system.js +1 -0
  158. package/dist/runtime-sync.d.ts +95 -0
  159. package/dist/runtime-sync.js +321 -0
  160. package/dist/runtime.d.ts +340 -0
  161. package/dist/runtime.js +134 -0
  162. package/dist/site-edit-instrumentation.d.ts +19 -0
  163. package/dist/site-edit-instrumentation.js +322 -0
  164. package/dist/snapshot-file-system.d.ts +19 -0
  165. package/dist/snapshot-file-system.js +49 -0
  166. package/dist/source-watcher.d.ts +20 -0
  167. package/dist/source-watcher.js +150 -0
  168. package/dist/source-writeback-test-harness.d.ts +244 -0
  169. package/dist/source-writeback-test-harness.js +119 -0
  170. package/dist/types.d.ts +68 -0
  171. package/dist/types.js +1 -0
  172. package/dist/webpack-loader.cjs +592 -0
  173. package/dist/webpack-loader.d.ts +27 -0
  174. package/package.json +66 -0
@@ -0,0 +1,158 @@
1
+ import { objectProperty } from "@babel/types";
2
+ import { primitiveFailure } from "../../diagnostics/index.js";
3
+ import { resolveLocatorPath } from "../../locators/index.js";
4
+ import { objectPropertyKey, parseMutationSource, printMutationWithOperation, valueToExpression, } from "../shared.js";
5
+ export function updateValue(params) {
6
+ const { source, locator, next } = params;
7
+ const resolved = resolveValuePathForMutation(source, locator);
8
+ if (!resolved.ok) {
9
+ return resolved.result;
10
+ }
11
+ resolved.path.replaceWith(valueToExpression(next));
12
+ return printMutationWithOperation(resolved.ast, source, {
13
+ kind: "update-value",
14
+ target: "value",
15
+ inverse: "restore-value",
16
+ });
17
+ }
18
+ export function insertArrayElement(params) {
19
+ const { source, locator, index, value } = params;
20
+ const resolved = resolveValuePathForMutation(source, locator);
21
+ if (!resolved.ok) {
22
+ return resolved.result;
23
+ }
24
+ if (!resolved.path.isArrayExpression()) {
25
+ return primitiveFailure(source, "unsupported-syntax", "Array operations require array expression target", "value");
26
+ }
27
+ if (resolved.path.node.elements.some((element) => element?.type === "SpreadElement")) {
28
+ /* node:coverage ignore next */
29
+ return primitiveFailure(source, "unsupported-syntax", "Spread array elements are not supported", "value");
30
+ }
31
+ if (index < 0 || index > resolved.path.node.elements.length) {
32
+ return primitiveFailure(source, "array-index-out-of-range", `Array index ${index} is out of range`, "value");
33
+ }
34
+ resolved.path.node.elements.splice(index, 0, valueToExpression(value));
35
+ return printMutationWithOperation(resolved.ast, source, {
36
+ kind: "insert-array-element",
37
+ target: "value",
38
+ inverse: "remove-array-element",
39
+ });
40
+ }
41
+ export function removeArrayElement(params) {
42
+ const { source, locator, index } = params;
43
+ const resolved = resolveValuePathForMutation(source, locator);
44
+ if (!resolved.ok) {
45
+ return resolved.result;
46
+ }
47
+ if (!resolved.path.isArrayExpression()) {
48
+ return primitiveFailure(source, "unsupported-syntax", "Array operations require array expression target", "value");
49
+ }
50
+ if (resolved.path.node.elements.some((element) => element?.type === "SpreadElement")) {
51
+ return primitiveFailure(source, "unsupported-syntax", "Spread array elements are not supported", "value");
52
+ }
53
+ if (index < 0 || index >= resolved.path.node.elements.length) {
54
+ return primitiveFailure(source, "array-index-out-of-range", `Array index ${index} is out of range`, "value");
55
+ }
56
+ resolved.path.node.elements.splice(index, 1);
57
+ return printMutationWithOperation(resolved.ast, source, {
58
+ kind: "remove-array-element",
59
+ target: "value",
60
+ inverse: "insert-array-element",
61
+ });
62
+ }
63
+ export function moveArrayElement(params) {
64
+ const { source, locator, fromIndex, toIndex } = params;
65
+ const resolved = resolveValuePathForMutation(source, locator);
66
+ if (!resolved.ok) {
67
+ return resolved.result;
68
+ }
69
+ if (!resolved.path.isArrayExpression()) {
70
+ return primitiveFailure(source, "unsupported-syntax", "Array operations require array expression target", "value");
71
+ }
72
+ if (resolved.path.node.elements.some((element) => element?.type === "SpreadElement")) {
73
+ return primitiveFailure(source, "unsupported-syntax", "Spread array elements are not supported", "value");
74
+ }
75
+ if (fromIndex < 0 ||
76
+ fromIndex >= resolved.path.node.elements.length ||
77
+ toIndex < 0 ||
78
+ toIndex > resolved.path.node.elements.length) {
79
+ return primitiveFailure(source, "array-index-out-of-range", "Array move indices are out of range", "value");
80
+ }
81
+ const [moved] = resolved.path.node.elements.splice(fromIndex, 1);
82
+ const insertionIndex = Math.min(toIndex, resolved.path.node.elements.length);
83
+ resolved.path.node.elements.splice(insertionIndex, 0, moved);
84
+ return printMutationWithOperation(resolved.ast, source, {
85
+ kind: "move-array-element",
86
+ target: "value",
87
+ inverse: "move-array-element-back",
88
+ });
89
+ }
90
+ export function insertObjectProperty(params) {
91
+ const { source, locator, property } = params;
92
+ const resolved = resolveValuePathForMutation(source, locator);
93
+ if (!resolved.ok) {
94
+ return resolved.result;
95
+ }
96
+ if (!resolved.path.isObjectExpression()) {
97
+ return primitiveFailure(source, "unsupported-syntax", "Object operations require object expression target", "value");
98
+ }
99
+ if (resolved.path.node.properties.some((item) => item.type !== "ObjectProperty")) {
100
+ return primitiveFailure(source, "unsupported-syntax", "Spread properties are not supported", "value");
101
+ }
102
+ resolved.path.node.properties.push(objectProperty(objectPropertyKey(property.key), valueToExpression(property.value)));
103
+ return printMutationWithOperation(resolved.ast, source, {
104
+ kind: "insert-object-property",
105
+ target: "value",
106
+ inverse: "remove-object-property",
107
+ });
108
+ }
109
+ export function removeObjectProperty(params) {
110
+ const { source, locator, key } = params;
111
+ const resolved = resolveValuePathForMutation(source, locator);
112
+ if (!resolved.ok) {
113
+ return resolved.result;
114
+ }
115
+ if (!resolved.path.isObjectExpression()) {
116
+ return primitiveFailure(source, "unsupported-syntax", "Object operations require object expression target", "value");
117
+ }
118
+ if (resolved.path.node.properties.some((item) => item.type !== "ObjectProperty")) {
119
+ return primitiveFailure(source, "unsupported-syntax", "Spread properties are not supported", "value");
120
+ }
121
+ const nextProperties = resolved.path.node.properties.filter((item) => item.type !== "ObjectProperty" ||
122
+ (item.key.type === "Identifier"
123
+ ? item.key.name
124
+ : item.key.type === "StringLiteral"
125
+ ? item.key.value
126
+ : null) !== key);
127
+ if (nextProperties.length === resolved.path.node.properties.length) {
128
+ return primitiveFailure(source, "property-not-found", `Property '${key}' not found`, "value");
129
+ }
130
+ resolved.path.node.properties = nextProperties;
131
+ return printMutationWithOperation(resolved.ast, source, {
132
+ kind: "remove-object-property",
133
+ target: "value",
134
+ inverse: "insert-object-property",
135
+ });
136
+ }
137
+ function resolveValuePathForMutation(source, locator) {
138
+ const parsed = parseMutationSource(source, "value");
139
+ if (!parsed.ok) {
140
+ return { ok: false, result: parsed.result };
141
+ }
142
+ const resolved = resolveLocatorPath(parsed.ast, locator);
143
+ if (!resolved.ok) {
144
+ return {
145
+ ok: false,
146
+ result: {
147
+ ok: false,
148
+ source,
149
+ diagnostic: resolved.diagnostic,
150
+ },
151
+ };
152
+ }
153
+ return {
154
+ ok: true,
155
+ ast: parsed.ast,
156
+ path: resolved.match.path,
157
+ };
158
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * SourcePrinter - AST 打印器。
3
+ *
4
+ * 使用 Babel generator 将 AST 转换回源码字符串。
5
+ * 支持检测并保留原始缩进风格。
6
+ */
7
+ import type * as t from "@babel/types";
8
+ /**
9
+ * 打印 AST 为源码字符串。
10
+ */
11
+ export declare function printAst(params: {
12
+ ast: t.File;
13
+ source: string;
14
+ }): {
15
+ ok: true;
16
+ source: string;
17
+ } | {
18
+ ok: false;
19
+ source: string;
20
+ diagnostic: import("../../domain/EditDiagnostic.js").EditDiagnostic;
21
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * SourcePrinter - AST 打印器。
3
+ *
4
+ * 使用 Babel generator 将 AST 转换回源码字符串。
5
+ * 支持检测并保留原始缩进风格。
6
+ */
7
+ import generateModule from "@babel/generator";
8
+ import { primitiveFailure } from "../../domain/EditDiagnostic.js";
9
+ /* node:coverage ignore next */
10
+ const generate = typeof generateModule === "function"
11
+ ? generateModule
12
+ : generateModule.default;
13
+ /**
14
+ * 检测源码的主导缩进风格。
15
+ * 返回 '2'、'4' 或 'tab'。
16
+ */
17
+ function detectIndent(source) {
18
+ const lines = source.split("\n");
19
+ const spaceCounts = [];
20
+ let hasTab = false;
21
+ for (const line of lines) {
22
+ const match = line.match(/^(\s+)/);
23
+ if (match) {
24
+ const indent = match[1];
25
+ if (indent.includes("\t")) {
26
+ hasTab = true;
27
+ }
28
+ else if (indent.length > 0) {
29
+ spaceCounts.push(indent.length);
30
+ }
31
+ }
32
+ }
33
+ if (hasTab) {
34
+ const allHaveTab = lines.every((l) => {
35
+ const m = l.match(/^(\s+)/);
36
+ return !m || m[1].includes("\t");
37
+ });
38
+ if (allHaveTab)
39
+ return "tab";
40
+ }
41
+ if (spaceCounts.length === 0)
42
+ return "2";
43
+ function gcd(a, b) {
44
+ return b === 0 ? a : gcd(b, a % b);
45
+ }
46
+ let baseUnit = spaceCounts[0];
47
+ for (let i = 1; i < spaceCounts.length; i++) {
48
+ baseUnit = gcd(baseUnit, spaceCounts[i]);
49
+ }
50
+ if (baseUnit >= 4)
51
+ return "4";
52
+ return "2";
53
+ }
54
+ /**
55
+ * 打印 AST 为源码字符串。
56
+ */
57
+ export function printAst(params) {
58
+ const { ast, source } = params;
59
+ try {
60
+ const indent = detectIndent(source);
61
+ const result = generate(ast, {
62
+ comments: true,
63
+ jsescOption: {
64
+ minimal: true,
65
+ quotes: "single",
66
+ },
67
+ }, source);
68
+ return {
69
+ ok: true,
70
+ source: result.code,
71
+ };
72
+ }
73
+ catch (error) {
74
+ return primitiveFailure(source, "printer-failed", `AST print failed: ${error instanceof Error ? error.message : String(error)}`);
75
+ }
76
+ }
@@ -0,0 +1,6 @@
1
+ import type * as t from "@babel/types";
2
+ import type { AstPrimitiveResult } from "../types.js";
3
+ export declare function printAst(params: {
4
+ ast: t.File;
5
+ source: string;
6
+ }): AstPrimitiveResult;
@@ -0,0 +1,126 @@
1
+ import generateModule from "@babel/generator";
2
+ import { primitiveFailure } from "../diagnostics/index.js";
3
+ /* node:coverage ignore next */
4
+ const generate = typeof generateModule === "function"
5
+ ? generateModule
6
+ : generateModule.default;
7
+ /**
8
+ * Detect the dominant indentation style from source code.
9
+ * Returns the indent style as '2', '4', or 'tab'.
10
+ * Uses GCD of all indent lengths to determine the base unit.
11
+ */
12
+ function detectIndent(source) {
13
+ const lines = source.split("\n");
14
+ const spaceCounts = [];
15
+ let hasTab = false;
16
+ for (const line of lines) {
17
+ const match = line.match(/^(\s+)/);
18
+ if (match) {
19
+ const indent = match[1];
20
+ if (indent.includes("\t")) {
21
+ hasTab = true;
22
+ }
23
+ else if (indent.length > 0) {
24
+ spaceCounts.push(indent.length);
25
+ }
26
+ }
27
+ }
28
+ if (hasTab) {
29
+ // Check if all indented lines have tabs
30
+ const allHaveTab = lines.every((l) => {
31
+ const m = l.match(/^(\s+)/);
32
+ return !m || m[1].includes("\t");
33
+ });
34
+ if (allHaveTab)
35
+ return "tab";
36
+ }
37
+ if (spaceCounts.length === 0)
38
+ return "2";
39
+ // Find GCD of all space counts to determine base unit
40
+ function gcd(a, b) {
41
+ return b === 0 ? a : gcd(b, a % b);
42
+ }
43
+ let baseUnit = spaceCounts[0];
44
+ for (let i = 1; i < spaceCounts.length; i++) {
45
+ baseUnit = gcd(baseUnit, spaceCounts[i]);
46
+ }
47
+ if (baseUnit >= 4)
48
+ return "4";
49
+ return "2";
50
+ }
51
+ /**
52
+ * Normalize a single line's indentation to the target style.
53
+ * Uses the minimum non-zero indent in the output as the base unit.
54
+ */
55
+ function normalizeLineIndent(line, target) {
56
+ const match = line.match(/^(\s+)(.*)/s);
57
+ if (!match)
58
+ return line;
59
+ const rawIndent = match[1];
60
+ const content = match[2];
61
+ if (rawIndent.length === 0)
62
+ return line;
63
+ let levels = 0;
64
+ if (rawIndent.includes("\t")) {
65
+ levels = rawIndent.split("\t").length - 1;
66
+ }
67
+ else {
68
+ // Use the raw space count directly, scaled to target
69
+ const spaceCount = rawIndent.length;
70
+ if (target === "4") {
71
+ // Convert to 4-space: each 2 spaces becomes 1 level → 4 spaces
72
+ levels = Math.max(1, Math.round(spaceCount / 2));
73
+ }
74
+ else if (target === "tab") {
75
+ // Convert to tab: each 2 spaces becomes 1 tab
76
+ levels = Math.max(1, Math.round(spaceCount / 2));
77
+ }
78
+ else {
79
+ // Target is 2-space: keep as-is (each 2 spaces = 1 level)
80
+ levels = Math.max(1, Math.round(spaceCount / 2));
81
+ }
82
+ }
83
+ // Clamp levels to reasonable range
84
+ levels = Math.min(Math.max(levels, 0), 20);
85
+ if (target === "tab") {
86
+ return "\t".repeat(levels) + content;
87
+ }
88
+ else if (target === "4") {
89
+ return " ".repeat(levels) + content;
90
+ }
91
+ else {
92
+ return " ".repeat(levels) + content;
93
+ }
94
+ }
95
+ /**
96
+ * Post-process: normalize indentation to match source style.
97
+ */
98
+ function normalizeSourceIndent(source, target) {
99
+ const lines = source.split("\n");
100
+ return lines.map((line) => normalizeLineIndent(line, target)).join("\n");
101
+ }
102
+ export function printAst(params) {
103
+ const { ast, source } = params;
104
+ try {
105
+ const indent = detectIndent(source);
106
+ const result = generate(ast, {
107
+ comments: true,
108
+ jsescOption: {
109
+ minimal: true,
110
+ quotes: "single",
111
+ },
112
+ }, source);
113
+ // Post-process: normalize indentation to match source style
114
+ let output = result.code;
115
+ if (indent !== "2") {
116
+ output = normalizeSourceIndent(output, indent);
117
+ }
118
+ return {
119
+ ok: true,
120
+ source: output,
121
+ };
122
+ }
123
+ catch (error) {
124
+ return primitiveFailure(source, "printer-failed", `AST print failed: ${error instanceof Error ? error.message : String(error)}`);
125
+ }
126
+ }
@@ -0,0 +1,190 @@
1
+ import type * as t from "@babel/types";
2
+ export interface SourceRange {
3
+ startLine: number;
4
+ startColumn: number;
5
+ endLine: number;
6
+ endColumn: number;
7
+ }
8
+ export type Placement = "prepend" | "append" | "before" | "after";
9
+ export type ValuePathSegment = {
10
+ kind: "property";
11
+ name: string;
12
+ } | {
13
+ kind: "index";
14
+ index: number;
15
+ };
16
+ export type ValueRootSelector = {
17
+ kind: "binding";
18
+ name: string;
19
+ } | {
20
+ kind: "hook-state";
21
+ name: string;
22
+ hook: "useState" | "useReducer";
23
+ } | {
24
+ kind: "named-export";
25
+ name: string;
26
+ } | {
27
+ kind: "default-export";
28
+ } | {
29
+ kind: "expression";
30
+ sourceRange: SourceRange;
31
+ };
32
+ export type JsxNodeLocator = {
33
+ kind: "jsx-node";
34
+ strategy: "source-range";
35
+ sourceRange: SourceRange;
36
+ expectedIdentity?: {
37
+ file: string;
38
+ component: string;
39
+ structuralPath: string;
40
+ };
41
+ } | {
42
+ kind: "jsx-node";
43
+ strategy: "structural-path";
44
+ file: string;
45
+ component: string;
46
+ structuralPath: string;
47
+ expectedRange?: SourceRange;
48
+ };
49
+ export interface JsxAttributeLocator {
50
+ kind: "jsx-attribute";
51
+ element: JsxNodeLocator;
52
+ name: string;
53
+ }
54
+ export interface ValueLocator {
55
+ kind: "value";
56
+ root: ValueRootSelector;
57
+ path?: ValuePathSegment[];
58
+ expectedRange?: SourceRange;
59
+ }
60
+ export interface ExpressionLocator {
61
+ kind: "expression";
62
+ base: string;
63
+ path?: ValuePathSegment[];
64
+ expectedRange?: SourceRange;
65
+ }
66
+ export interface DirectiveLocator {
67
+ kind: "directive";
68
+ value: string;
69
+ expectedRange?: SourceRange;
70
+ }
71
+ export type ExportLocator = {
72
+ kind: "export";
73
+ exportKind: "named";
74
+ name: string;
75
+ expectedRange?: SourceRange;
76
+ } | {
77
+ kind: "export";
78
+ exportKind: "metadata";
79
+ expectedRange?: SourceRange;
80
+ } | {
81
+ kind: "export";
82
+ exportKind: "generate-metadata";
83
+ expectedRange?: SourceRange;
84
+ } | {
85
+ kind: "export";
86
+ exportKind: "default";
87
+ expectedRange?: SourceRange;
88
+ };
89
+ export type AstLocator = JsxNodeLocator | JsxAttributeLocator | ValueLocator | ExpressionLocator | DirectiveLocator | ExportLocator;
90
+ export type AstLocatorKind = AstLocator["kind"];
91
+ export type AstDiagnosticCode = "parse-failed" | "locator-miss" | "unsupported-syntax" | "binding-not-found" | "export-not-found" | "property-not-found" | "array-index-out-of-range" | "directive-conflict" | "metadata-shape-unsupported" | "printer-failed" | "invalid-parent-child-relation" | "self-closing-element";
92
+ export interface AstDiagnostic {
93
+ code: AstDiagnosticCode;
94
+ message: string;
95
+ locatorKind?: AstLocatorKind;
96
+ details?: Record<string, unknown>;
97
+ }
98
+ export interface LocatorMatch {
99
+ locatorKind: AstLocatorKind;
100
+ node: t.Node;
101
+ start: number;
102
+ end: number;
103
+ }
104
+ export type ResolveLocatorResult = {
105
+ ok: true;
106
+ match: LocatorMatch;
107
+ } | {
108
+ ok: false;
109
+ source: string;
110
+ diagnostic: AstDiagnostic;
111
+ };
112
+ export interface OperationDescription {
113
+ type: string;
114
+ nodeId: string;
115
+ kind?: string;
116
+ target?: string;
117
+ timestamp?: number;
118
+ beforeSourceHash?: string;
119
+ afterSourceHash?: string;
120
+ inverse?: string;
121
+ meta?: Record<string, unknown>;
122
+ }
123
+ export interface HistoryEntry {
124
+ operation: OperationDescription;
125
+ timestamp: number;
126
+ }
127
+ export type AstPrimitiveResult = {
128
+ ok: true;
129
+ source: string;
130
+ operation?: OperationDescription;
131
+ } | {
132
+ ok: false;
133
+ source: string;
134
+ diagnostic: AstDiagnostic;
135
+ };
136
+ export type PrimitiveValue = string | number | boolean | null | PrimitiveValue[] | {
137
+ [key: string]: PrimitiveValue;
138
+ };
139
+ /**
140
+ * 将 locator kind 映射到对应的 primitive 操作参数类型。
141
+ * 用于编译期验证 locator/primitive 组合的正确性。
142
+ */
143
+ export type LocatorToPrimitiveMap = {
144
+ "jsx-node": {
145
+ updateText: "JsxNodeLocator";
146
+ removeNode: "JsxNodeLocator";
147
+ insertChild: "JsxNodeLocator";
148
+ moveNode: "JsxNodeLocator";
149
+ };
150
+ "jsx-attribute": {
151
+ setJsxAttribute: "JsxAttributeLocator";
152
+ removeJsxAttribute: "JsxAttributeLocator";
153
+ updateStyleProperty: "JsxAttributeLocator";
154
+ updateClassName: "JsxAttributeLocator";
155
+ addTailwindClass: "JsxAttributeLocator";
156
+ removeTailwindClass: "JsxAttributeLocator";
157
+ updateCssModuleClassReference: "JsxAttributeLocator";
158
+ };
159
+ value: {
160
+ updateValue: "ValueLocator";
161
+ insertArrayElement: "ValueLocator";
162
+ removeArrayElement: "ValueLocator";
163
+ moveArrayElement: "ValueLocator";
164
+ insertObjectProperty: "ValueLocator";
165
+ removeObjectProperty: "ValueLocator";
166
+ };
167
+ expression: {
168
+ updateValue: "ExpressionLocator";
169
+ };
170
+ directive: {
171
+ addDirective: "DirectiveLocator";
172
+ removeDirective: "DirectiveLocator";
173
+ updateDirective: "DirectiveLocator";
174
+ };
175
+ export: {
176
+ updateNamedExport: "ExportLocator";
177
+ updateMetadataField: "ExportLocator";
178
+ updateGenerateMetadata: "ExportLocator";
179
+ };
180
+ };
181
+ /**
182
+ * 根据 locator kind 推断对应的 primitive 操作类型。
183
+ * 用于编译期类型推断。
184
+ */
185
+ export type PrimitiveOperationForLocator<K extends AstLocatorKind> = K extends keyof LocatorToPrimitiveMap ? keyof LocatorToPrimitiveMap[K] : never;
186
+ /**
187
+ * 验证 locator/primitive 组合的编译期断言工具。
188
+ * 正确组合返回 true,错误组合返回 never。
189
+ */
190
+ export type ValidatePrimitiveContract<K extends AstLocatorKind, Op extends string> = K extends keyof LocatorToPrimitiveMap ? Op extends keyof LocatorToPrimitiveMap[K] ? true : never : never;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { NodeCapabilitySnapshot } from "../protocol.js";
2
+ import type { EditableTopology } from "../topology/types.js";
3
+ import type { RenderSourceGraph } from "../graph/types.js";
4
+ /**
5
+ * 为指定节点计算能力快照。
6
+ *
7
+ * 规则:
8
+ * - canMove = true 意味着支持全部 MoveTarget 位置(含跨文件)
9
+ * - canInsertChild = true 意味着支持 native-tag + component-call
10
+ * - 限制通过 constraints 显式返回
11
+ */
12
+ export declare function resolveCapability(key: string, topology: EditableTopology, graph: RenderSourceGraph): NodeCapabilitySnapshot;
13
+ /**
14
+ * 批量计算所有节点的能力快照。
15
+ */
16
+ export declare function resolveAllCapabilities(topology: EditableTopology, graph: RenderSourceGraph): Map<string, NodeCapabilitySnapshot>;