@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,321 @@
1
+ export const DEFAULT_SITE_EDIT_RUNTIME_READY_TIMEOUT_MS = 1500;
2
+ export const SITE_EDIT_RUNTIME_READY_POLL_INTERVAL_MS = 16;
3
+ export const SITE_EDIT_RUNTIME_ATTRIBUTES = {
4
+ key: "data-vcp-edit-key",
5
+ parentKey: "data-vcp-edit-parent-key",
6
+ movable: "data-vcp-movable",
7
+ removable: "data-vcp-removable",
8
+ flags: "data-vcp-flags",
9
+ };
10
+ const CONTAINER_TAGS = new Set([
11
+ "article",
12
+ "aside",
13
+ "div",
14
+ "footer",
15
+ "form",
16
+ "header",
17
+ "li",
18
+ "main",
19
+ "nav",
20
+ "ol",
21
+ "section",
22
+ "ul",
23
+ ]);
24
+ const TEXT_TAGS = new Set([
25
+ "a",
26
+ "button",
27
+ "em",
28
+ "h1",
29
+ "h2",
30
+ "h3",
31
+ "h4",
32
+ "h5",
33
+ "h6",
34
+ "label",
35
+ "p",
36
+ "small",
37
+ "span",
38
+ "strong",
39
+ ]);
40
+ const STRONG_SYNC_OPERATION_KINDS = new Set([
41
+ "update-text",
42
+ "remove-node",
43
+ "insert-child",
44
+ "move-node",
45
+ "replace-rich-text-content",
46
+ "insert-rich-text-block",
47
+ "remove-rich-text-block",
48
+ "set-media-field",
49
+ "set-component-slot-content",
50
+ "set-object-field",
51
+ "insert-object-field",
52
+ "remove-object-field",
53
+ "update-array-item",
54
+ "insert-array-item",
55
+ "remove-array-item",
56
+ "move-array-item",
57
+ "replace-conditional-expression",
58
+ "set-conditional-branch-content",
59
+ "set-jsx-prop",
60
+ "remove-jsx-prop",
61
+ "set-class-name",
62
+ "add-class-token",
63
+ "remove-class-token",
64
+ "set-style-property",
65
+ "set-style-properties",
66
+ "set-css-module-class",
67
+ ]);
68
+ export function diffSiteEditRenderDocuments(previous_document, next_document) {
69
+ const previousEntries = new Map(previous_document.entries.map((entry) => [entry.key, entry]));
70
+ const nextEntries = new Map(next_document.entries.map((entry) => [entry.key, entry]));
71
+ const added_keys = next_document.entries
72
+ .map((entry) => entry.key)
73
+ .filter((key) => !previousEntries.has(key));
74
+ const removed_keys = previous_document.entries
75
+ .map((entry) => entry.key)
76
+ .filter((key) => !nextEntries.has(key));
77
+ const retained_keys = next_document.entries
78
+ .map((entry) => entry.key)
79
+ .filter((key) => previousEntries.has(key));
80
+ const changed_parentKeys = retained_keys.filter((key) => previousEntries.get(key)?.parentKey !== nextEntries.get(key)?.parentKey);
81
+ const changed_child_order_keys = retained_keys.filter((key) => {
82
+ const previousChildren = previousEntries.get(key)?.childKeys ?? [];
83
+ const nextChildren = nextEntries.get(key)?.childKeys ?? [];
84
+ return previousChildren.join("\u0000") !== nextChildren.join("\u0000");
85
+ });
86
+ return {
87
+ added_keys,
88
+ removed_keys,
89
+ retained_keys,
90
+ changed_parentKeys,
91
+ changed_child_order_keys,
92
+ };
93
+ }
94
+ export function isSiteEditRuntimeSyncedOperation(kind) {
95
+ return STRONG_SYNC_OPERATION_KINDS.has(kind);
96
+ }
97
+ export class SiteEditRuntimeDomAdapter {
98
+ constructor(documentLike, attributes = SITE_EDIT_RUNTIME_ATTRIBUTES) {
99
+ this.documentLike = documentLike;
100
+ this.attributes = attributes;
101
+ }
102
+ getKeyFromElement(element) {
103
+ return element.getAttribute(this.attributes.key);
104
+ }
105
+ findEditableElement(element) {
106
+ return element?.closest(`[${this.attributes.key}]`) ?? null;
107
+ }
108
+ findElementByKey(key) {
109
+ return (this.documentLike?.querySelector(`[${this.attributes.key}="${escapeAttributeValue(key)}"]`) ?? null);
110
+ }
111
+ findElementByRef(ref) {
112
+ if (typeof ref.instance_index !== "number" ||
113
+ typeof ref.instance_count !== "number" ||
114
+ ref.instance_count <= 1 ||
115
+ !this.documentLike?.querySelectorAll) {
116
+ return this.findElementByKey(ref.key);
117
+ }
118
+ const matches = Array.from(this.documentLike.querySelectorAll(`[${this.attributes.key}]`)).filter((item) => item.getAttribute(this.attributes.key) === ref.key);
119
+ return matches[ref.instance_index] ?? null;
120
+ }
121
+ snapshot(element) {
122
+ const attributes = Object.fromEntries(element
123
+ .getAttributeNames()
124
+ .map((name) => [name, element.getAttribute(name) ?? ""]));
125
+ const key = element.getAttribute(this.attributes.key) ?? "";
126
+ const tagName = element.tagName.toLowerCase();
127
+ const textPreview = element.textContent?.trim().slice(0, 80);
128
+ const snapshot = {
129
+ key,
130
+ tag_name: tagName,
131
+ attributes,
132
+ runtime_flags: {
133
+ editable: true,
134
+ movable: element.getAttribute(this.attributes.movable) !== "false",
135
+ removable: element.getAttribute(this.attributes.removable) !== "false",
136
+ text_editable: TEXT_TAGS.has(tagName),
137
+ container: CONTAINER_TAGS.has(tagName),
138
+ },
139
+ };
140
+ const instancePosition = this.resolveInstancePosition(element, key);
141
+ if (instancePosition) {
142
+ snapshot.instance_index = instancePosition.index;
143
+ snapshot.instance_count = instancePosition.count;
144
+ }
145
+ if (textPreview !== undefined) {
146
+ snapshot.text_preview = textPreview;
147
+ }
148
+ return snapshot;
149
+ }
150
+ resolveInstancePosition(element, key) {
151
+ if (!key || !this.documentLike?.querySelectorAll) {
152
+ return null;
153
+ }
154
+ const matches = Array.from(this.documentLike.querySelectorAll(`[${this.attributes.key}]`)).filter((item) => item.getAttribute(this.attributes.key) === key);
155
+ if (matches.length <= 1) {
156
+ return null;
157
+ }
158
+ const index = matches.indexOf(element);
159
+ if (index < 0) {
160
+ return null;
161
+ }
162
+ return {
163
+ count: matches.length,
164
+ index,
165
+ };
166
+ }
167
+ }
168
+ export class SiteEditRuntimeReadyProbe {
169
+ constructor(documentLike, attributes = SITE_EDIT_RUNTIME_ATTRIBUTES) {
170
+ this.dom = new SiteEditRuntimeDomAdapter(documentLike, attributes);
171
+ }
172
+ probe(input, diff = diffSiteEditRenderDocuments(input.previous_document, input.next_document)) {
173
+ const rootKeys = input.next_document.rootKeys.length > 0
174
+ ? input.next_document.rootKeys
175
+ : input.next_document.entries.slice(0, 1).map((entry) => entry.key);
176
+ const missingRoot = rootKeys.find((key) => !this.dom.findElementByKey(key));
177
+ if (missingRoot) {
178
+ return failure(input, "missing-root", "document-root", `preview root is missing: ${missingRoot}`);
179
+ }
180
+ if (input.selected_key &&
181
+ hasDocumentKey(input.next_document, input.selected_key) &&
182
+ !this.dom.findElementByKey(input.selected_key)) {
183
+ return failure(input, "missing-selected-key", "selected-node", `selected node is missing from preview DOM: ${input.selected_key}`);
184
+ }
185
+ const kind = input.request?.kind ?? input.result.kind;
186
+ if (!isSiteEditRuntimeSyncedOperation(kind)) {
187
+ return failure(input, "unsupported-operation", "operation-specific", `runtime ready check is not implemented for ${kind}`);
188
+ }
189
+ return this.checkOperationProjection(input, diff);
190
+ }
191
+ checkOperationProjection(input, diff) {
192
+ const kind = input.request?.kind ?? input.result.kind;
193
+ const targetKey = getNodeTargetKey(input.request) ?? getNodeTargetKey(input.result);
194
+ if (kind === "update-text" &&
195
+ input.request?.params.kind === "update-text") {
196
+ return this.checkTextProjection(input, targetKey);
197
+ }
198
+ if (kind === "remove-node" &&
199
+ targetKey &&
200
+ !hasDocumentKey(input.next_document, targetKey)) {
201
+ if (this.dom.findElementByKey(targetKey)) {
202
+ return failure(input, "removed-target-still-present", "removed-node", `removed node is still present in preview DOM: ${targetKey}`);
203
+ }
204
+ return this.checkGenericDiffProjection(input, diff, "removed-node");
205
+ }
206
+ if (kind === "insert-child") {
207
+ const addedResult = this.checkAddedKeys(input, diff, "inserted-node");
208
+ return addedResult.ok
209
+ ? this.checkGenericDiffProjection(input, diff, "inserted-node")
210
+ : addedResult;
211
+ }
212
+ if (kind === "move-node") {
213
+ return this.checkMovedNodeProjection(input, diff, targetKey);
214
+ }
215
+ return this.checkGenericDiffProjection(input, diff, "document-diff");
216
+ }
217
+ checkTextProjection(input, targetKey) {
218
+ if (!targetKey) {
219
+ return failure(input, "missing-target", "text-content", "update-text target key is missing");
220
+ }
221
+ const target = this.dom.findElementByKey(targetKey);
222
+ if (!target) {
223
+ return failure(input, "missing-target", "text-content", `update-text target is missing: ${targetKey}`);
224
+ }
225
+ const actualText = normalizeText(target.textContent ?? "");
226
+ const params = input.request?.params;
227
+ const expectedText = normalizeText(params?.kind === "update-text" ? params.value : "");
228
+ if (actualText !== expectedText) {
229
+ return failure(input, "text-mismatch", "text-content", `preview text has not updated for ${targetKey}`);
230
+ }
231
+ return success(input, "text-content", [targetKey]);
232
+ }
233
+ checkMovedNodeProjection(input, diff, targetKey) {
234
+ if (targetKey && !this.dom.findElementByKey(targetKey)) {
235
+ return failure(input, "missing-target", "moved-node", `moved node is missing: ${targetKey}`);
236
+ }
237
+ for (const parentKey of diff.changed_child_order_keys) {
238
+ const parent = input.next_document.entries.find((entry) => entry.key === parentKey);
239
+ if (!parent || !this.isChildOrderReady(parent.childKeys)) {
240
+ return failure(input, "order-mismatch", "child-order", `child order is not ready for ${parentKey}`);
241
+ }
242
+ }
243
+ return this.checkGenericDiffProjection(input, diff, "moved-node");
244
+ }
245
+ checkGenericDiffProjection(input, diff, check) {
246
+ const addedResult = this.checkAddedKeys(input, diff, check);
247
+ if (!addedResult.ok) {
248
+ return addedResult;
249
+ }
250
+ const presentRemovedKey = diff.removed_keys.find((key) => this.dom.findElementByKey(key));
251
+ if (presentRemovedKey) {
252
+ return failure(input, "removed-target-still-present", check, `removed node is still present in preview DOM: ${presentRemovedKey}`);
253
+ }
254
+ return success(input, check, [
255
+ ...input.next_document.rootKeys,
256
+ ...diff.added_keys,
257
+ ...diff.changed_parentKeys,
258
+ ...diff.changed_child_order_keys,
259
+ ]);
260
+ }
261
+ checkAddedKeys(input, diff, check) {
262
+ const missingAddedKey = diff.added_keys.find((key) => !this.dom.findElementByKey(key));
263
+ if (missingAddedKey) {
264
+ return failure(input, "missing-added-key", check, `added node is missing from preview DOM: ${missingAddedKey}`);
265
+ }
266
+ return success(input, check, diff.added_keys);
267
+ }
268
+ isChildOrderReady(childKeys) {
269
+ const elements = childKeys
270
+ .map((key) => this.dom.findElementByKey(key))
271
+ .filter((element) => Boolean(element));
272
+ if (elements.length < 2) {
273
+ return elements.length === childKeys.length;
274
+ }
275
+ for (let index = 1; index < elements.length; index += 1) {
276
+ const previous = elements[index - 1];
277
+ const current = elements[index];
278
+ if (previous &&
279
+ current &&
280
+ (previous.compareDocumentPosition(current) & 4) === 0) {
281
+ return false;
282
+ }
283
+ }
284
+ return elements.length === childKeys.length;
285
+ }
286
+ }
287
+ export function getSiteEditNodeTargetKey(input) {
288
+ return getNodeTargetKey(input);
289
+ }
290
+ export function hasSiteEditDocumentKey(document, key) {
291
+ return hasDocumentKey(document, key);
292
+ }
293
+ function getNodeTargetKey(input) {
294
+ return input?.target.kind === "node" ? input.target.key : null;
295
+ }
296
+ function hasDocumentKey(document, key) {
297
+ return document.entries.some((entry) => entry.key === key);
298
+ }
299
+ function normalizeText(value) {
300
+ return value.replace(/\s+/g, " ").trim();
301
+ }
302
+ function success(input, check, observed_keys) {
303
+ return {
304
+ ok: true,
305
+ version: input.next_document.version,
306
+ observed_keys: [...new Set(observed_keys.filter(Boolean))],
307
+ check,
308
+ };
309
+ }
310
+ function failure(input, reason, check, message) {
311
+ return {
312
+ ok: false,
313
+ version: input.next_document.version,
314
+ reason,
315
+ check,
316
+ message,
317
+ };
318
+ }
319
+ function escapeAttributeValue(value) {
320
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
321
+ }
@@ -0,0 +1,340 @@
1
+ import type { SiteEditEngineRuntime, SiteEditEngineRuntimeOptions, SiteEditPlanOperationResult } from "./types.js";
2
+ export declare class SnapshotSiteEditEngineRuntime implements SiteEditEngineRuntime {
3
+ private readonly options;
4
+ private readonly engine;
5
+ private readonly fileSystem;
6
+ constructor(options: SiteEditEngineRuntimeOptions);
7
+ get status(): SiteEditEngineRuntime["status"];
8
+ setActiveRoute(routeId: string): Promise<void>;
9
+ getDocument(routeId: string): {
10
+ siteId: string;
11
+ snapshotId: string;
12
+ routeId: string;
13
+ version: number;
14
+ rootKeys: string[];
15
+ entries: {
16
+ key: string;
17
+ tag: string;
18
+ label: string;
19
+ parentKey: string | null;
20
+ childKeys: string[];
21
+ operationSummary: {
22
+ canUpdateText: boolean;
23
+ canInsertChild: boolean;
24
+ canMove: boolean;
25
+ canRemove: boolean;
26
+ };
27
+ }[];
28
+ };
29
+ getObjectCapabilities(key: string, routeId?: string): {
30
+ key: string;
31
+ canUpdateText: boolean;
32
+ canInsertChild: boolean;
33
+ canMove: boolean;
34
+ canRemove: boolean;
35
+ boundaryKind: "component-boundary" | "repeat-region" | "conditional-region" | "fragment-region" | "opaque-region" | null;
36
+ isOpaque: boolean;
37
+ };
38
+ getObjectSummary(key: string, routeId?: string): {
39
+ key: string;
40
+ tag: string;
41
+ label: string;
42
+ capabilities: {
43
+ constraints: {
44
+ kind: "component-boundary" | "repeat-region" | "conditional-region" | "opaque-region" | "void-element" | "read-only" | "cross-file-required" | "import-required";
45
+ message: string;
46
+ }[];
47
+ };
48
+ isOpaque: boolean;
49
+ ancestors: {
50
+ key: string;
51
+ label: string;
52
+ tag: string;
53
+ }[];
54
+ provenanceChain?: {
55
+ editMode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
56
+ diagnostics: {
57
+ code: string;
58
+ message: string;
59
+ }[];
60
+ } | undefined;
61
+ };
62
+ getObjectEditContext(key: string, routeId?: string): {
63
+ key: string;
64
+ componentName: string;
65
+ sourceFile: string;
66
+ capabilities: {
67
+ key: string;
68
+ canUpdateText: boolean;
69
+ canInsertChild: boolean;
70
+ canMove: boolean;
71
+ canRemove: boolean;
72
+ constraints: {
73
+ kind: "component-boundary" | "repeat-region" | "conditional-region" | "opaque-region" | "void-element" | "read-only" | "cross-file-required" | "import-required";
74
+ message: string;
75
+ }[];
76
+ editModes?: {
77
+ updateText?: {
78
+ mode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
79
+ reasonCode?: string | undefined;
80
+ } | undefined;
81
+ insertChild?: {
82
+ mode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
83
+ reasonCode?: string | undefined;
84
+ } | undefined;
85
+ move?: {
86
+ mode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
87
+ reasonCode?: string | undefined;
88
+ } | undefined;
89
+ remove?: {
90
+ mode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
91
+ reasonCode?: string | undefined;
92
+ } | undefined;
93
+ } | undefined;
94
+ };
95
+ writeTarget: {
96
+ kind: "jsx-node" | "component-proxy" | "value-binding" | "route-export";
97
+ file: string;
98
+ componentName: string;
99
+ isProxy: boolean;
100
+ };
101
+ textSegments: {
102
+ index: number;
103
+ value: string;
104
+ editable: boolean;
105
+ source: {
106
+ kind: "literal" | "binding" | "imported-binding" | "repeat-template";
107
+ file: string;
108
+ expression: string;
109
+ bindingName?: string | undefined;
110
+ path?: (string | number)[] | undefined;
111
+ } | null;
112
+ }[];
113
+ boundaryKind: "component-boundary" | "repeat-region" | "conditional-region" | "fragment-region" | "opaque-region" | null;
114
+ children: {
115
+ key: string;
116
+ label: string;
117
+ tag: string;
118
+ }[];
119
+ siblings: {
120
+ key: string;
121
+ label: string;
122
+ tag: string;
123
+ }[];
124
+ effectiveWriteTarget?: {
125
+ kind: "jsx-node" | "route-export" | "value-path" | "external-entry";
126
+ isProxy: boolean;
127
+ file?: string | undefined;
128
+ displayPath?: string | undefined;
129
+ sourceType?: "api-field" | "cms-field" | "i18n-message" | "config-entry" | undefined;
130
+ sourceId?: string | undefined;
131
+ } | undefined;
132
+ provenanceChain?: {
133
+ finalSource: {
134
+ kind: "api-field" | "cms-field" | "i18n-message" | "config-entry" | "binding" | "imported-binding" | "repeat-template" | "jsx-literal" | "component-prop" | "object-field" | "array-item" | "conditional-branch";
135
+ file: string;
136
+ displayPath: string;
137
+ externalSource?: {
138
+ sourceType: "api-field" | "cms-field" | "i18n-message" | "config-entry";
139
+ sourceId: string;
140
+ adapterId?: string | undefined;
141
+ } | undefined;
142
+ } | null;
143
+ chain: {
144
+ kind: "api-field" | "cms-field" | "i18n-message" | "config-entry" | "binding" | "imported-binding" | "repeat-template" | "jsx-literal" | "component-prop" | "object-field" | "array-item" | "conditional-branch";
145
+ file: string;
146
+ displayName: string;
147
+ canEditHere: boolean;
148
+ }[];
149
+ confidence: "exact" | "safe-derived" | "partial" | "unknown";
150
+ editMode: "direct" | "proxy" | "upstream" | "readonly" | "unsupported";
151
+ diagnostics: {
152
+ code: string;
153
+ message: string;
154
+ }[];
155
+ } | undefined;
156
+ componentSemantic?: Record<string, unknown> | undefined;
157
+ };
158
+ getObjectStyleDetail(key: string, routeId?: string): {
159
+ key: string;
160
+ styleSource?: {
161
+ kind: "class-name-source";
162
+ className: string;
163
+ sourceKind: "missing" | "static-attribute" | "static-expression" | "dynamic-expression";
164
+ editable: boolean;
165
+ operationBoundary: ("update-text" | "remove-node" | "insert-child" | "move-node" | "replace-rich-text-content" | "insert-rich-text-block" | "remove-rich-text-block" | "set-media-field" | "set-component-slot-content" | "set-object-field" | "insert-object-field" | "remove-object-field" | "update-array-item" | "insert-array-item" | "remove-array-item" | "move-array-item" | "replace-conditional-expression" | "set-conditional-branch-content" | "set-jsx-prop" | "remove-jsx-prop" | "set-class-name" | "add-class-token" | "remove-class-token" | "set-style-property" | "set-style-properties" | "set-css-module-class" | "set-directive" | "remove-directive" | "set-route-export" | "set-metadata-field" | "set-generate-metadata")[];
166
+ sourcePath?: string | undefined;
167
+ diagnostics?: {
168
+ code: "missing-class-name" | "dynamic-binding" | "non-string-binding";
169
+ message: string;
170
+ }[] | undefined;
171
+ } | undefined;
172
+ styleModel?: Record<string, unknown> | {
173
+ kind: "css-style-model";
174
+ properties: {
175
+ property: "display" | "position" | "top" | "right" | "bottom" | "left" | "zIndex" | "flexDirection" | "flexWrap" | "flexGrow" | "flexShrink" | "flexBasis" | "order" | "gridTemplateColumns" | "gridTemplateRows" | "columns" | "gridColumn" | "gridRow" | "gap" | "gapX" | "gapY" | "spaceX" | "spaceY" | "alignItems" | "justifyContent" | "marginTop" | "marginRight" | "marginBottom" | "marginLeft" | "paddingTop" | "paddingRight" | "paddingBottom" | "paddingLeft" | "width" | "height" | "minWidth" | "minHeight" | "maxWidth" | "maxHeight" | "overflow" | "fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textAlign" | "textTransform" | "textDecoration" | "textOverflow" | "textIndent" | "writingMode" | "whiteSpace" | "wordBreak" | "lineClamp" | "fontVariantNumeric" | "screenReaderOnly" | "color" | "backgroundColor" | "backgroundImage" | "borderStyle" | "borderWidth" | "borderRadius" | "borderColor" | "objectFit" | "objectPosition" | "aspectRatio" | "opacity" | "boxShadow" | "transform" | "transformOrigin" | "transitionProperty" | "transitionDuration" | "transitionTimingFunction" | "animation" | "pointerEvents" | "cursor" | "userSelect" | "fontStyle" | "textUnderlineOffset" | "scrollMarginTop" | "alignSelf" | "flex" | "outlineStyle" | "resize" | "ringWidth" | "ringColor" | "backdropFilter" | "overscrollBehavior" | "divideWidth" | "divideColor";
176
+ value: string | number | boolean | null;
177
+ editable: boolean;
178
+ resolvedValue?: string | number | boolean | null | undefined;
179
+ breakpoint?: "sm" | "md" | "lg" | "xl" | "2xl" | undefined;
180
+ state?: "hover" | "active" | "focus" | "disabled" | undefined;
181
+ variants?: string[] | undefined;
182
+ options?: (string | number)[] | undefined;
183
+ diagnostics?: {
184
+ code: string;
185
+ message: string;
186
+ }[] | undefined;
187
+ operationBoundary?: ("update-text" | "remove-node" | "insert-child" | "move-node" | "replace-rich-text-content" | "insert-rich-text-block" | "remove-rich-text-block" | "set-media-field" | "set-component-slot-content" | "set-object-field" | "insert-object-field" | "remove-object-field" | "update-array-item" | "insert-array-item" | "remove-array-item" | "move-array-item" | "replace-conditional-expression" | "set-conditional-branch-content" | "set-jsx-prop" | "remove-jsx-prop" | "set-class-name" | "add-class-token" | "remove-class-token" | "set-style-property" | "set-style-properties" | "set-css-module-class" | "set-directive" | "remove-directive" | "set-route-export" | "set-metadata-field" | "set-generate-metadata")[] | undefined;
188
+ }[];
189
+ } | undefined;
190
+ };
191
+ getObjectContentDetail(key: string, routeId?: string): {
192
+ key: string;
193
+ contentModel?: Record<string, unknown> | undefined;
194
+ };
195
+ getObjectMediaDetail(key: string, routeId?: string): {
196
+ key: string;
197
+ mediaModel?: Record<string, unknown> | undefined;
198
+ };
199
+ getClassNameSource(key: string, routeId?: string): {
200
+ key: string;
201
+ routeId: string;
202
+ filePath: string;
203
+ componentName: string;
204
+ sourceKind: "missing" | "expression" | "stringLiteral";
205
+ attrRaw: string | null;
206
+ valueRaw: string | null;
207
+ attrRange: {
208
+ start: number;
209
+ end: number;
210
+ startLine?: number | undefined;
211
+ startColumn?: number | undefined;
212
+ endLine?: number | undefined;
213
+ endColumn?: number | undefined;
214
+ } | null;
215
+ valueRange: {
216
+ start: number;
217
+ end: number;
218
+ startLine?: number | undefined;
219
+ startColumn?: number | undefined;
220
+ endLine?: number | undefined;
221
+ endColumn?: number | undefined;
222
+ } | null;
223
+ openingElementRange: {
224
+ start: number;
225
+ end: number;
226
+ startLine?: number | undefined;
227
+ startColumn?: number | undefined;
228
+ endLine?: number | undefined;
229
+ endColumn?: number | undefined;
230
+ };
231
+ version: {
232
+ documentVersion: number;
233
+ contentHash: string;
234
+ parserVersion: string;
235
+ };
236
+ diagnostics: {
237
+ code: "missing-class-name" | "unsupported-attribute-name" | "source-locator-warning" | "invalid-new-attr" | "version-conflict" | "write-failed";
238
+ message: string;
239
+ }[];
240
+ };
241
+ setClassNameSource(request: Parameters<SiteEditEngineRuntime["setClassNameSource"]>[0]): Promise<{
242
+ ok: true;
243
+ source: {
244
+ key: string;
245
+ routeId: string;
246
+ filePath: string;
247
+ componentName: string;
248
+ sourceKind: "missing" | "expression" | "stringLiteral";
249
+ attrRaw: string | null;
250
+ valueRaw: string | null;
251
+ attrRange: {
252
+ start: number;
253
+ end: number;
254
+ startLine?: number | undefined;
255
+ startColumn?: number | undefined;
256
+ endLine?: number | undefined;
257
+ endColumn?: number | undefined;
258
+ } | null;
259
+ valueRange: {
260
+ start: number;
261
+ end: number;
262
+ startLine?: number | undefined;
263
+ startColumn?: number | undefined;
264
+ endLine?: number | undefined;
265
+ endColumn?: number | undefined;
266
+ } | null;
267
+ openingElementRange: {
268
+ start: number;
269
+ end: number;
270
+ startLine?: number | undefined;
271
+ startColumn?: number | undefined;
272
+ endLine?: number | undefined;
273
+ endColumn?: number | undefined;
274
+ };
275
+ version: {
276
+ documentVersion: number;
277
+ contentHash: string;
278
+ parserVersion: string;
279
+ };
280
+ diagnostics: {
281
+ code: "missing-class-name" | "unsupported-attribute-name" | "source-locator-warning" | "invalid-new-attr" | "version-conflict" | "write-failed";
282
+ message: string;
283
+ }[];
284
+ };
285
+ } | {
286
+ ok: false;
287
+ reason: "node_not_found" | "document_version_stale" | "file_hash_mismatch" | "range_mismatch" | "old_attr_mismatch" | "invalid_new_attr" | "unsupported_target" | "write_failed";
288
+ diagnostics: {
289
+ code: "missing-class-name" | "unsupported-attribute-name" | "source-locator-warning" | "invalid-new-attr" | "version-conflict" | "write-failed";
290
+ message: string;
291
+ }[];
292
+ current?: {
293
+ key: string;
294
+ routeId: string;
295
+ filePath: string;
296
+ componentName: string;
297
+ sourceKind: "missing" | "expression" | "stringLiteral";
298
+ attrRaw: string | null;
299
+ valueRaw: string | null;
300
+ attrRange: {
301
+ start: number;
302
+ end: number;
303
+ startLine?: number | undefined;
304
+ startColumn?: number | undefined;
305
+ endLine?: number | undefined;
306
+ endColumn?: number | undefined;
307
+ } | null;
308
+ valueRange: {
309
+ start: number;
310
+ end: number;
311
+ startLine?: number | undefined;
312
+ startColumn?: number | undefined;
313
+ endLine?: number | undefined;
314
+ endColumn?: number | undefined;
315
+ } | null;
316
+ openingElementRange: {
317
+ start: number;
318
+ end: number;
319
+ startLine?: number | undefined;
320
+ startColumn?: number | undefined;
321
+ endLine?: number | undefined;
322
+ endColumn?: number | undefined;
323
+ };
324
+ version: {
325
+ documentVersion: number;
326
+ contentHash: string;
327
+ parserVersion: string;
328
+ };
329
+ diagnostics: {
330
+ code: "missing-class-name" | "unsupported-attribute-name" | "source-locator-warning" | "invalid-new-attr" | "version-conflict" | "write-failed";
331
+ message: string;
332
+ }[];
333
+ } | undefined;
334
+ }>;
335
+ planOperation(request: Parameters<SiteEditEngineRuntime["planOperation"]>[0]): Promise<SiteEditPlanOperationResult>;
336
+ dispose(): void;
337
+ private createEngine;
338
+ private getChangedRouteIds;
339
+ }
340
+ export declare function createSiteEditEngineRuntime(options: SiteEditEngineRuntimeOptions): SiteEditEngineRuntime;