@samva/markup 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 (124) hide show
  1. package/AGENTS.md +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +41 -0
  4. package/dist/ast-DAhnAvQN.d.ts +120 -0
  5. package/dist/ast.d.ts +2 -0
  6. package/dist/ast.js +159 -0
  7. package/dist/ast.js.map +1 -0
  8. package/dist/candidate.d.ts +29 -0
  9. package/dist/candidate.js +88 -0
  10. package/dist/candidate.js.map +1 -0
  11. package/dist/checks-CW0nFj5n.js +58922 -0
  12. package/dist/checks-CW0nFj5n.js.map +1 -0
  13. package/dist/checks.d.ts +26 -0
  14. package/dist/checks.js +2 -0
  15. package/dist/classes.d.ts +27 -0
  16. package/dist/classes.js +184 -0
  17. package/dist/classes.js.map +1 -0
  18. package/dist/compile-sms.d.ts +28 -0
  19. package/dist/compile-sms.js +44 -0
  20. package/dist/compile-sms.js.map +1 -0
  21. package/dist/compile-whatsapp.d.ts +56 -0
  22. package/dist/compile-whatsapp.js +186 -0
  23. package/dist/compile-whatsapp.js.map +1 -0
  24. package/dist/compile.d.ts +93 -0
  25. package/dist/compile.js +938 -0
  26. package/dist/compile.js.map +1 -0
  27. package/dist/components.d.ts +289 -0
  28. package/dist/components.js +106 -0
  29. package/dist/components.js.map +1 -0
  30. package/dist/conditionals.d.ts +10 -0
  31. package/dist/conditionals.js +42 -0
  32. package/dist/conditionals.js.map +1 -0
  33. package/dist/diagnostics-oveE-laV.d.ts +79 -0
  34. package/dist/diagnostics.d.ts +2 -0
  35. package/dist/diagnostics.js +62 -0
  36. package/dist/diagnostics.js.map +1 -0
  37. package/dist/emit.d.ts +50 -0
  38. package/dist/emit.js +151 -0
  39. package/dist/emit.js.map +1 -0
  40. package/dist/footer.d.ts +66 -0
  41. package/dist/footer.js +90 -0
  42. package/dist/footer.js.map +1 -0
  43. package/dist/interpolate.d.ts +27 -0
  44. package/dist/interpolate.js +61 -0
  45. package/dist/interpolate.js.map +1 -0
  46. package/dist/jsx-dev-runtime.d.ts +10 -0
  47. package/dist/jsx-dev-runtime.js +7 -0
  48. package/dist/jsx-dev-runtime.js.map +1 -0
  49. package/dist/jsx-runtime-fSxcvlx4.d.ts +57 -0
  50. package/dist/jsx-runtime.d.ts +2 -0
  51. package/dist/jsx-runtime.js +102 -0
  52. package/dist/jsx-runtime.js.map +1 -0
  53. package/dist/lexer.d.ts +60 -0
  54. package/dist/lexer.js +269 -0
  55. package/dist/lexer.js.map +1 -0
  56. package/dist/model.d.ts +39 -0
  57. package/dist/model.js +90 -0
  58. package/dist/model.js.map +1 -0
  59. package/dist/ops.d.ts +208 -0
  60. package/dist/ops.js +546 -0
  61. package/dist/ops.js.map +1 -0
  62. package/dist/parser-yzjUOGhc.d.ts +387 -0
  63. package/dist/parser.d.ts +2 -0
  64. package/dist/parser.js +821 -0
  65. package/dist/parser.js.map +1 -0
  66. package/dist/predicate-DTtVtLK7.d.ts +49 -0
  67. package/dist/predicate.d.ts +2 -0
  68. package/dist/predicate.js +417 -0
  69. package/dist/predicate.js.map +1 -0
  70. package/dist/presets/category-mapping.d.ts +13 -0
  71. package/dist/presets/category-mapping.js +49 -0
  72. package/dist/presets/category-mapping.js.map +1 -0
  73. package/dist/presets/public-gallery.d.ts +490 -0
  74. package/dist/presets/public-gallery.js +563 -0
  75. package/dist/presets/public-gallery.js.map +1 -0
  76. package/dist/presets/public-handoff.d.ts +68 -0
  77. package/dist/presets/public-handoff.js +105 -0
  78. package/dist/presets/public-handoff.js.map +1 -0
  79. package/dist/presets/public-preview-artifacts.d.ts +41 -0
  80. package/dist/presets/public-preview-artifacts.js +109 -0
  81. package/dist/presets/public-preview-artifacts.js.map +1 -0
  82. package/dist/presets/public-preview.d.ts +1168 -0
  83. package/dist/presets/public-preview.js +1158 -0
  84. package/dist/presets/public-preview.js.map +1 -0
  85. package/dist/presets/sources.d.ts +7 -0
  86. package/dist/presets/sources.js +54 -0
  87. package/dist/presets/sources.js.map +1 -0
  88. package/dist/presets.d.ts +350 -0
  89. package/dist/presets.js +1251 -0
  90. package/dist/presets.js.map +1 -0
  91. package/dist/printer.d.ts +6 -0
  92. package/dist/printer.js +122 -0
  93. package/dist/printer.js.map +1 -0
  94. package/dist/registry.d.ts +42 -0
  95. package/dist/registry.js +646 -0
  96. package/dist/registry.js.map +1 -0
  97. package/dist/render-template.d.ts +42 -0
  98. package/dist/render-template.js +74 -0
  99. package/dist/render-template.js.map +1 -0
  100. package/dist/sms-segments-y4FpPilJ.d.ts +13 -0
  101. package/dist/sms-segments.d.ts +2 -0
  102. package/dist/sms-segments.js +46 -0
  103. package/dist/sms-segments.js.map +1 -0
  104. package/dist/theme-6ApjjiBo.d.ts +116 -0
  105. package/dist/theme-css.d.ts +24 -0
  106. package/dist/theme-css.js +509 -0
  107. package/dist/theme-css.js.map +1 -0
  108. package/dist/theme.d.ts +2 -0
  109. package/dist/theme.js +95 -0
  110. package/dist/theme.js.map +1 -0
  111. package/dist/tokens.d.ts +6 -0
  112. package/dist/tokens.js +417 -0
  113. package/dist/tokens.js.map +1 -0
  114. package/dist/variables-3NGLpNTB.d.ts +77 -0
  115. package/dist/variables.d.ts +2 -0
  116. package/dist/variables.js +141 -0
  117. package/dist/variables.js.map +1 -0
  118. package/dist/version-BITr58kk.js +96 -0
  119. package/dist/version-BITr58kk.js.map +1 -0
  120. package/generated/sml-agent-contract.json +917 -0
  121. package/generated/sml-email-agent-contract.json +790 -0
  122. package/generated/sml-email-language-reference.md +160 -0
  123. package/generated/sml-language-reference.md +220 -0
  124. package/package.json +203 -0
package/dist/ops.js ADDED
@@ -0,0 +1,546 @@
1
+ import { DiagnosticSchema } from "./diagnostics.js";
2
+ import { AttributeValueSchema, SML_TAGS, SmlNodeSchema, documentChannel } from "./ast.js";
3
+ import { CHANNEL_TAG_SPECS, allowedChildren, parseSml } from "./parser.js";
4
+ import { compileSml } from "./compile.js";
5
+ import { i as isBreakingCompatibilityCheck, n as checkSmlCompatibility } from "./checks-CW0nFj5n.js";
6
+ import { printSml } from "./printer.js";
7
+ import { Result, Schema } from "effect";
8
+ //#region src/ops.ts
9
+ const InsertPositionSchema = Schema.Literals([
10
+ "before",
11
+ "after",
12
+ "inside"
13
+ ]);
14
+ const SetPropOpSchema = Schema.TaggedStruct("setProp", {
15
+ nodeId: Schema.String,
16
+ name: Schema.String,
17
+ value: Schema.NullOr(AttributeValueSchema)
18
+ });
19
+ /**
20
+ * Replace a node's complete child list. The normal print → parse → compile
21
+ * preflight remains the authority on whether the replacement satisfies the
22
+ * target's content model.
23
+ */
24
+ const SetChildrenOpSchema = Schema.TaggedStruct("setChildren", {
25
+ nodeId: Schema.String,
26
+ children: Schema.Array(SmlNodeSchema)
27
+ });
28
+ const InsertBlockOpSchema = Schema.TaggedStruct("insertBlock", {
29
+ tag: Schema.Literals(SML_TAGS),
30
+ referenceId: Schema.NullOr(Schema.String),
31
+ position: InsertPositionSchema
32
+ });
33
+ const InsertSnippetOpSchema = Schema.TaggedStruct("insertSnippet", {
34
+ snippet: Schema.String,
35
+ referenceId: Schema.NullOr(Schema.String),
36
+ position: InsertPositionSchema
37
+ });
38
+ /**
39
+ * `insertionIndex` is an element-child index into `targetParentId` evaluated
40
+ * AFTER the moved node has left its old position — the lifted-out model, so a
41
+ * same-parent caller must compute the index against the sibling list without
42
+ * the node. Indexes past the end append.
43
+ */
44
+ const MoveNodeOpSchema = Schema.TaggedStruct("moveNode", {
45
+ nodeId: Schema.String,
46
+ targetParentId: Schema.String,
47
+ insertionIndex: Schema.Finite
48
+ });
49
+ const DuplicateNodeOpSchema = Schema.TaggedStruct("duplicateNode", { nodeId: Schema.String });
50
+ const RemoveNodeOpSchema = Schema.TaggedStruct("removeNode", { nodeId: Schema.String });
51
+ /**
52
+ * A single edit against SML source. `nodeId` (and `referenceId` /
53
+ * `targetParentId`) are positional ids from the source the caller last read;
54
+ * within a batch they always resolve against that snapshot — see {@link applyOps}.
55
+ */
56
+ const SmlOpSchema = Schema.Union([
57
+ SetPropOpSchema,
58
+ SetChildrenOpSchema,
59
+ InsertBlockOpSchema,
60
+ InsertSnippetOpSchema,
61
+ MoveNodeOpSchema,
62
+ DuplicateNodeOpSchema,
63
+ RemoveNodeOpSchema
64
+ ]);
65
+ const SmlOpResultSchema = Schema.Struct({
66
+ index: Schema.Finite,
67
+ status: Schema.Literals(["applied", "failed"]),
68
+ op: SmlOpSchema,
69
+ diagnostics: Schema.Array(DiagnosticSchema)
70
+ });
71
+ const ApplyOpsResultSchema = Schema.Struct({
72
+ source: Schema.String,
73
+ revision: Schema.String,
74
+ diagnostics: Schema.Array(DiagnosticSchema),
75
+ results: Schema.Array(SmlOpResultSchema)
76
+ });
77
+ var SmlOpError = class extends Schema.TaggedErrorClass()("SmlOpError", { diagnostics: Schema.Array(DiagnosticSchema) }) {
78
+ get message() {
79
+ return this.diagnostics.map((diagnostic) => diagnostic.message).join("\n");
80
+ }
81
+ };
82
+ const zeroSpan = {
83
+ start: 0,
84
+ end: 0
85
+ };
86
+ const diagnostic = (code, message, span = zeroSpan) => ({
87
+ code,
88
+ message,
89
+ span
90
+ });
91
+ const cloneAttribute = (attribute) => ({ ...attribute });
92
+ /**
93
+ * Deep-copy a subtree, blanking every id to "". A duplicated node must not
94
+ * alias the original's object graph or share its ids: batch ids resolve
95
+ * against the pre-batch snapshot, and mapElement transforms every node whose
96
+ * id matches — so two live copies sharing an id would both be rewritten by a
97
+ * later op. Blank ids make the clone unaddressable (like any freshly created
98
+ * node) until the next reprint reassigns positional ids.
99
+ */
100
+ const cloneSubtree = (node) => {
101
+ if (node.kind === "element") return {
102
+ ...node,
103
+ id: "",
104
+ attributes: node.attributes.map(cloneAttribute),
105
+ children: node.children.map(cloneSubtree)
106
+ };
107
+ return {
108
+ ...node,
109
+ id: ""
110
+ };
111
+ };
112
+ const makeAttribute = (name, value) => ({
113
+ name,
114
+ value,
115
+ span: zeroSpan,
116
+ valueSpan: zeroSpan
117
+ });
118
+ const classAttr = (value) => makeAttribute("class", {
119
+ kind: "string",
120
+ value
121
+ });
122
+ const sourceRevision = (source) => {
123
+ let hash = 2166136261;
124
+ for (let index = 0; index < source.length; index++) {
125
+ hash ^= source.charCodeAt(index);
126
+ hash = Math.imul(hash, 16777619);
127
+ }
128
+ return `sml:${(hash >>> 0).toString(16).padStart(8, "0")}`;
129
+ };
130
+ const normalizeSml = (source) => {
131
+ const parsed = parseSml(source);
132
+ if (Result.isFailure(parsed)) return Result.fail(parsed.failure);
133
+ return Result.succeed(printSml(parsed.success));
134
+ };
135
+ const findElement = (node, nodeId) => {
136
+ if (node.kind !== "element") return null;
137
+ if (node.id === nodeId) return node;
138
+ for (const child of node.children) {
139
+ const found = findElement(child, nodeId);
140
+ if (found !== null) return found;
141
+ }
142
+ return null;
143
+ };
144
+ const mapElement = (node, targetId, transform) => {
145
+ if (node.kind !== "element") return node;
146
+ if (node.id === targetId) return transform(node);
147
+ return {
148
+ ...node,
149
+ children: node.children.map((child) => mapElement(child, targetId, transform))
150
+ };
151
+ };
152
+ const transformElement = (document, targetId, transform) => {
153
+ if (findElement(document.root, targetId) === null) return Result.fail([diagnostic("op-target-not-found", `node "${targetId}" was not found in the current source`)]);
154
+ return Result.succeed({
155
+ ...document,
156
+ root: mapElement(document.root, targetId, transform)
157
+ });
158
+ };
159
+ const setElementAttribute = (element, name, value) => {
160
+ const rest = element.attributes.filter((attribute) => attribute.name !== name);
161
+ if (value === null || value.kind === "string" && value.value === "") return {
162
+ ...element,
163
+ attributes: rest
164
+ };
165
+ const next = makeAttribute(name, value);
166
+ const attributes = element.attributes.some((attribute) => attribute.name === name) ? element.attributes.map((attribute) => attribute.name === name ? next : cloneAttribute(attribute)) : [...element.attributes, next];
167
+ return {
168
+ ...element,
169
+ attributes
170
+ };
171
+ };
172
+ const setImageSchemeSource = (document, nodeId, scheme, value) => transformElement(document, nodeId, (element) => {
173
+ if (element.tag !== "Image") return element;
174
+ const src = value?.kind === "string" ? value.value : "";
175
+ const children = element.children.filter((child) => !(child.kind === "element" && child.tag === "Source" && child.attributes.some((attribute) => attribute.name === "scheme" && attribute.value.kind === "string" && attribute.value.value === scheme)));
176
+ if (src === "") return {
177
+ ...element,
178
+ children
179
+ };
180
+ const sourceNode = {
181
+ kind: "element",
182
+ id: "",
183
+ tag: "Source",
184
+ attributes: [makeAttribute("scheme", {
185
+ kind: "string",
186
+ value: scheme
187
+ }), makeAttribute("src", {
188
+ kind: "string",
189
+ value: src
190
+ })],
191
+ children: [],
192
+ span: zeroSpan
193
+ };
194
+ return {
195
+ ...element,
196
+ children: [...children, sourceNode]
197
+ };
198
+ });
199
+ const setProp = (document, op) => {
200
+ if (op.name === "src:dark") return setImageSchemeSource(document, op.nodeId, "dark", op.value);
201
+ return transformElement(document, op.nodeId, (element) => {
202
+ const value = op.name === "class" && op.value?.kind === "string" ? {
203
+ kind: "string",
204
+ value: op.value.value.trim().replace(/\s+/g, " ")
205
+ } : op.value;
206
+ return setElementAttribute(element, op.name, value);
207
+ });
208
+ };
209
+ const setChildren = (document, op) => transformElement(document, op.nodeId, (element) => ({
210
+ ...element,
211
+ children: [...op.children]
212
+ }));
213
+ const makeColumn = () => ({
214
+ kind: "element",
215
+ id: "",
216
+ tag: "Column",
217
+ attributes: [classAttr("px-8")],
218
+ children: [{
219
+ kind: "element",
220
+ id: "",
221
+ tag: "Text",
222
+ attributes: [classAttr("text-base text-gray-700")],
223
+ children: [{
224
+ kind: "text",
225
+ id: "",
226
+ value: "Column",
227
+ span: zeroSpan
228
+ }],
229
+ span: zeroSpan
230
+ }],
231
+ span: zeroSpan
232
+ });
233
+ const makeBlock = (tag) => {
234
+ const base = (attributes, children) => ({
235
+ kind: "element",
236
+ id: "",
237
+ tag,
238
+ attributes,
239
+ children,
240
+ span: zeroSpan
241
+ });
242
+ const text = (value) => ({
243
+ kind: "text",
244
+ id: "",
245
+ value,
246
+ span: zeroSpan
247
+ });
248
+ switch (tag) {
249
+ case "Heading": return base([makeAttribute("level", {
250
+ kind: "number",
251
+ value: 2
252
+ }), classAttr("text-xl text-gray-900")], [text("Heading")]);
253
+ case "Text": return base([classAttr("text-base text-gray-700")], [text("Add your text here.")]);
254
+ case "Button": return base([makeAttribute("href", {
255
+ kind: "string",
256
+ value: "https://example.com"
257
+ }), classAttr("bg-blue-600 text-white px-20 py-12 rounded-md")], [text("Button")]);
258
+ case "Image": return base([
259
+ makeAttribute("src", {
260
+ kind: "string",
261
+ value: "https://placehold.co/600x200"
262
+ }),
263
+ makeAttribute("alt", {
264
+ kind: "string",
265
+ value: ""
266
+ }),
267
+ makeAttribute("width", {
268
+ kind: "number",
269
+ value: 600
270
+ })
271
+ ], []);
272
+ case "Divider": return base([classAttr("border-gray-200")], []);
273
+ case "Spacer": return base([makeAttribute("height", {
274
+ kind: "number",
275
+ value: 24
276
+ })], []);
277
+ case "Section": return base([classAttr("py-16")], [makeBlock("Text")]);
278
+ case "Container": return base([classAttr("bg-white p-24")], [makeBlock("Text")]);
279
+ case "Row": return base([], [makeColumn(), makeColumn()]);
280
+ default: return base([], []);
281
+ }
282
+ };
283
+ const elementChildIndexToNodeIndex = (children, insertionIndex) => {
284
+ if (insertionIndex <= 0) {
285
+ const firstElement = children.findIndex((child) => child.kind === "element");
286
+ return firstElement === -1 ? children.length : firstElement;
287
+ }
288
+ let elementIndex = 0;
289
+ for (let index = 0; index < children.length; index++) {
290
+ if (children[index]?.kind !== "element") continue;
291
+ if (elementIndex === insertionIndex) return index;
292
+ elementIndex++;
293
+ }
294
+ return children.length;
295
+ };
296
+ const insertChildren = (document, childrenToInsert, referenceId, position) => {
297
+ if (childrenToInsert.length === 0) return Result.fail([diagnostic("op-empty-insert", "insert operation produced no element nodes")]);
298
+ if (referenceId === null || referenceId === document.root.id) {
299
+ const children = position === "before" ? [...childrenToInsert, ...document.root.children] : [...document.root.children, ...childrenToInsert];
300
+ return Result.succeed({
301
+ ...document,
302
+ root: {
303
+ ...document.root,
304
+ children
305
+ }
306
+ });
307
+ }
308
+ if (findElement(document.root, referenceId) === null) return Result.fail([diagnostic("op-target-not-found", `node "${referenceId}" was not found in the current source`)]);
309
+ if (position === "inside") return transformElement(document, referenceId, (element) => ({
310
+ ...element,
311
+ children: [...element.children, ...childrenToInsert]
312
+ }));
313
+ const insertInParent = (node) => {
314
+ if (node.kind !== "element") return node;
315
+ const index = node.children.findIndex((child) => child.kind === "element" && child.id === referenceId);
316
+ if (index >= 0) {
317
+ const at = position === "after" ? index + 1 : index;
318
+ return {
319
+ ...node,
320
+ children: [
321
+ ...node.children.slice(0, at),
322
+ ...childrenToInsert,
323
+ ...node.children.slice(at)
324
+ ]
325
+ };
326
+ }
327
+ return {
328
+ ...node,
329
+ children: node.children.map(insertInParent)
330
+ };
331
+ };
332
+ return Result.succeed({
333
+ ...document,
334
+ root: insertInParent(document.root)
335
+ });
336
+ };
337
+ const insertBlock = (document, op) => insertChildren(document, [makeBlock(op.tag)], op.referenceId, op.position);
338
+ const insertSnippet = (document, op) => {
339
+ const rootTag = document.root.tag;
340
+ const parsed = parseSml(`<${rootTag}>${op.snippet}</${rootTag}>`);
341
+ if (Result.isFailure(parsed)) return Result.fail(parsed.failure.diagnostics);
342
+ const children = parsed.success.root.children.filter((child) => child.kind === "element");
343
+ return insertChildren(document, children, op.referenceId, op.position);
344
+ };
345
+ const removeNodeById = (document, nodeId) => {
346
+ if (document.root.id === nodeId) return Result.fail([diagnostic("op-root-target", "the document root cannot be removed")]);
347
+ if (findElement(document.root, nodeId) === null) return Result.fail([diagnostic("op-target-not-found", `node "${nodeId}" was not found in the current source`)]);
348
+ const prune = (node) => {
349
+ if (node.kind !== "element") return node;
350
+ return {
351
+ ...node,
352
+ children: node.children.filter((child) => !(child.kind === "element" && child.id === nodeId)).map(prune)
353
+ };
354
+ };
355
+ return Result.succeed({
356
+ ...document,
357
+ root: prune(document.root)
358
+ });
359
+ };
360
+ const isDescendant = (ancestor, nodeId) => ancestor.children.some((child) => {
361
+ if (child.kind !== "element") return false;
362
+ return child.id === nodeId || isDescendant(child, nodeId);
363
+ });
364
+ const removeElement = (node, nodeId) => {
365
+ let removed = null;
366
+ const children = [];
367
+ for (const child of node.children) {
368
+ if (child.kind === "element" && child.id === nodeId) {
369
+ removed = child;
370
+ continue;
371
+ }
372
+ if (child.kind === "element") {
373
+ const result = removeElement(child, nodeId);
374
+ if (result.removed !== null) removed = result.removed;
375
+ children.push(result.node);
376
+ } else children.push(child);
377
+ }
378
+ return {
379
+ node: {
380
+ ...node,
381
+ children
382
+ },
383
+ removed
384
+ };
385
+ };
386
+ const insertIntoParent = (node, targetParentId, insertionIndex, moved) => {
387
+ if (node.id === targetParentId) {
388
+ const at = elementChildIndexToNodeIndex(node.children, insertionIndex);
389
+ return {
390
+ ...node,
391
+ children: [
392
+ ...node.children.slice(0, at),
393
+ moved,
394
+ ...node.children.slice(at)
395
+ ]
396
+ };
397
+ }
398
+ return {
399
+ ...node,
400
+ children: node.children.map((child) => child.kind === "element" ? insertIntoParent(child, targetParentId, insertionIndex, moved) : child)
401
+ };
402
+ };
403
+ const moveNode = (document, op) => {
404
+ if (document.root.id === op.nodeId) return Result.fail([diagnostic("op-root-target", "the document root cannot be moved")]);
405
+ const moved = findElement(document.root, op.nodeId);
406
+ if (moved === null) return Result.fail([diagnostic("op-target-not-found", `node "${op.nodeId}" was not found in the current source`)]);
407
+ const parent = findElement(document.root, op.targetParentId);
408
+ if (parent === null) return Result.fail([diagnostic("op-target-not-found", `target parent "${op.targetParentId}" was not found in the current source`)]);
409
+ if (moved.id === parent.id || isDescendant(moved, parent.id)) return Result.fail([diagnostic("op-invalid-reparent", "a node cannot be moved into itself or its descendants")]);
410
+ const channel = documentChannel(document);
411
+ const childModel = CHANNEL_TAG_SPECS[channel][parent.tag]?.content;
412
+ if (!(childModel === void 0 ? [] : allowedChildren(childModel)).includes(moved.tag)) return Result.fail([diagnostic("op-invalid-reparent", `<${moved.tag}> is not allowed directly inside <${parent.tag}>`, parent.span)]);
413
+ const { node: rootWithoutMoved, removed } = removeElement(document.root, op.nodeId);
414
+ if (removed === null) return Result.fail([diagnostic("op-target-not-found", `node "${op.nodeId}" was not found in the current source`)]);
415
+ return Result.succeed({
416
+ ...document,
417
+ root: insertIntoParent(rootWithoutMoved, op.targetParentId, op.insertionIndex, removed)
418
+ });
419
+ };
420
+ const duplicateNode = (document, nodeId) => {
421
+ if (document.root.id === nodeId) return Result.fail([diagnostic("op-root-target", "the document root cannot be duplicated")]);
422
+ if (findElement(document.root, nodeId) === null) return Result.fail([diagnostic("op-target-not-found", `node "${nodeId}" was not found in the current source`)]);
423
+ const insertClone = (node) => {
424
+ if (node.kind !== "element") return node;
425
+ const index = node.children.findIndex((child) => child.kind === "element" && child.id === nodeId);
426
+ if (index >= 0) {
427
+ const clone = cloneSubtree(node.children[index]);
428
+ return {
429
+ ...node,
430
+ children: [
431
+ ...node.children.slice(0, index + 1),
432
+ clone,
433
+ ...node.children.slice(index + 1)
434
+ ]
435
+ };
436
+ }
437
+ return {
438
+ ...node,
439
+ children: node.children.map(insertClone)
440
+ };
441
+ };
442
+ return Result.succeed({
443
+ ...document,
444
+ root: insertClone(document.root)
445
+ });
446
+ };
447
+ const mutate = (document, op) => {
448
+ switch (op._tag) {
449
+ case "setProp": return setProp(document, op);
450
+ case "setChildren": return setChildren(document, op);
451
+ case "insertBlock": return insertBlock(document, op);
452
+ case "insertSnippet": return insertSnippet(document, op);
453
+ case "moveNode": return moveNode(document, op);
454
+ case "duplicateNode": return duplicateNode(document, op.nodeId);
455
+ case "removeNode": return removeNodeById(document, op.nodeId);
456
+ }
457
+ };
458
+ const preflight = (source) => {
459
+ const reparsed = parseSml(source);
460
+ if (Result.isFailure(reparsed)) return Result.fail(reparsed.failure.diagnostics);
461
+ const compiled = compileSml(reparsed.success);
462
+ if (Result.isFailure(compiled)) return Result.fail(compiled.failure.diagnostics);
463
+ const compatibilityErrors = checkSmlCompatibility({ source }).filter(isBreakingCompatibilityCheck).map((message) => diagnostic("compatibility-error", message));
464
+ if (compatibilityErrors.length > 0) return Result.fail(compatibilityErrors);
465
+ return Result.succeed(reparsed.success);
466
+ };
467
+ const failedResult = (index, op, diagnostics) => ({
468
+ index,
469
+ status: "failed",
470
+ op,
471
+ diagnostics: [...diagnostics]
472
+ });
473
+ /**
474
+ * Apply a batch of ops to SML source, returning the rewritten source, its new
475
+ * revision, and a per-op result.
476
+ *
477
+ * Id contract: every id in the batch resolves against the id-space of the
478
+ * source the caller read (the `expectedRevision` snapshot). Ids are positional
479
+ * (`n0..nN` in document order) and are NOT rewritten between ops, so:
480
+ *
481
+ * - An op cannot target a node created earlier in the same batch — freshly
482
+ * inserted/duplicated nodes carry a blank id until the next reprint reassigns
483
+ * positional ids, and are unaddressable within the batch (fails with
484
+ * `op-target-not-found`).
485
+ * - After `duplicateNode`, the duplicated id still addresses the ORIGINAL (the
486
+ * first match in document order); the clone is a blank-id copy.
487
+ * - Structural ops (insert/remove/move) do not shift the ids of the nodes that
488
+ * survive, so a later op targeting a surviving sibling lands on the intended
489
+ * node regardless of what earlier ops did.
490
+ *
491
+ * Each op is still preflighted (reprint, reparse, compile, compatibility check)
492
+ * as an independent validity gate; a failing op is recorded as `failed` and
493
+ * does not advance the working document.
494
+ */
495
+ const applyOps = (source, ops, options) => {
496
+ const parsed = parseSml(source);
497
+ if (Result.isFailure(parsed)) return Result.fail(new SmlOpError({ diagnostics: parsed.failure.diagnostics }));
498
+ const currentRevision = String(options?.currentRevision ?? sourceRevision(source));
499
+ if (options?.expectedRevision !== void 0 && String(options.expectedRevision) !== currentRevision) {
500
+ const stale = diagnostic("stale-revision", `source revision changed from ${String(options.expectedRevision)} to ${currentRevision}`);
501
+ return Result.succeed({
502
+ source,
503
+ revision: currentRevision,
504
+ diagnostics: [stale],
505
+ results: ops.map((op, index) => failedResult(index, op, [stale]))
506
+ });
507
+ }
508
+ let currentSource = source;
509
+ let currentDocument = parsed.success;
510
+ const results = [];
511
+ const diagnostics = [];
512
+ ops.forEach((op, index) => {
513
+ const mutated = mutate(currentDocument, op);
514
+ if (Result.isFailure(mutated)) {
515
+ results.push(failedResult(index, op, mutated.failure));
516
+ diagnostics.push(...mutated.failure);
517
+ return;
518
+ }
519
+ const candidateSource = printSml(mutated.success);
520
+ const checked = preflight(candidateSource);
521
+ if (Result.isFailure(checked)) {
522
+ results.push(failedResult(index, op, checked.failure));
523
+ diagnostics.push(...checked.failure);
524
+ return;
525
+ }
526
+ currentSource = candidateSource;
527
+ currentDocument = mutated.success;
528
+ results.push({
529
+ index,
530
+ status: "applied",
531
+ op,
532
+ diagnostics: []
533
+ });
534
+ });
535
+ return Result.succeed({
536
+ source: currentSource,
537
+ revision: sourceRevision(currentSource),
538
+ diagnostics,
539
+ results
540
+ });
541
+ };
542
+ const applyOp = (source, op, options) => applyOps(source, [op], options);
543
+ //#endregion
544
+ export { ApplyOpsResultSchema, SmlOpError, SmlOpResultSchema, SmlOpSchema, applyOp, applyOps, normalizeSml, sourceRevision };
545
+
546
+ //# sourceMappingURL=ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops.js","names":[],"sources":["../src/ops.ts"],"sourcesContent":["import { Result, Schema } from \"effect\";\n\nimport type { Attribute, AttributeValue, ElementNode, SmlDocument, SmlNode, SmlTag } from \"./ast\";\nimport { AttributeValueSchema, SML_TAGS, SmlNodeSchema, documentChannel } from \"./ast\";\nimport { checkSmlCompatibility, isBreakingCompatibilityCheck } from \"./checks\";\nimport { compileSml } from \"./compile\";\nimport type { Diagnostic, Span } from \"./diagnostics\";\nimport { DiagnosticSchema, SmlParseError } from \"./diagnostics\";\nimport { allowedChildren, CHANNEL_TAG_SPECS } from \"./parser\";\nimport { parseSml } from \"./parser\";\nimport { printSml } from \"./printer\";\n\nconst InsertPositionSchema = Schema.Literals([\"before\", \"after\", \"inside\"]);\n\nconst SetPropOpSchema = Schema.TaggedStruct(\"setProp\", {\n nodeId: Schema.String,\n name: Schema.String,\n value: Schema.NullOr(AttributeValueSchema),\n});\n\n/**\n * Replace a node's complete child list. The normal print → parse → compile\n * preflight remains the authority on whether the replacement satisfies the\n * target's content model.\n */\nconst SetChildrenOpSchema = Schema.TaggedStruct(\"setChildren\", {\n nodeId: Schema.String,\n children: Schema.Array(SmlNodeSchema),\n});\n\nconst InsertBlockOpSchema = Schema.TaggedStruct(\"insertBlock\", {\n tag: Schema.Literals(SML_TAGS),\n referenceId: Schema.NullOr(Schema.String),\n position: InsertPositionSchema,\n});\n\nconst InsertSnippetOpSchema = Schema.TaggedStruct(\"insertSnippet\", {\n snippet: Schema.String,\n referenceId: Schema.NullOr(Schema.String),\n position: InsertPositionSchema,\n});\n\n/**\n * `insertionIndex` is an element-child index into `targetParentId` evaluated\n * AFTER the moved node has left its old position — the lifted-out model, so a\n * same-parent caller must compute the index against the sibling list without\n * the node. Indexes past the end append.\n */\nconst MoveNodeOpSchema = Schema.TaggedStruct(\"moveNode\", {\n nodeId: Schema.String,\n targetParentId: Schema.String,\n insertionIndex: Schema.Finite,\n});\n\nconst DuplicateNodeOpSchema = Schema.TaggedStruct(\"duplicateNode\", {\n nodeId: Schema.String,\n});\n\nconst RemoveNodeOpSchema = Schema.TaggedStruct(\"removeNode\", {\n nodeId: Schema.String,\n});\n\n/**\n * A single edit against SML source. `nodeId` (and `referenceId` /\n * `targetParentId`) are positional ids from the source the caller last read;\n * within a batch they always resolve against that snapshot — see {@link applyOps}.\n */\nexport const SmlOpSchema = Schema.Union([\n SetPropOpSchema,\n SetChildrenOpSchema,\n InsertBlockOpSchema,\n InsertSnippetOpSchema,\n MoveNodeOpSchema,\n DuplicateNodeOpSchema,\n RemoveNodeOpSchema,\n]);\n\nexport type SmlOp = typeof SmlOpSchema.Type;\n\nexport const SmlOpResultSchema = Schema.Struct({\n index: Schema.Finite,\n status: Schema.Literals([\"applied\", \"failed\"]),\n op: SmlOpSchema,\n diagnostics: Schema.Array(DiagnosticSchema),\n});\n\nexport interface SmlOpResult extends Schema.Schema.Type<typeof SmlOpResultSchema> {}\n\nexport const ApplyOpsResultSchema = Schema.Struct({\n source: Schema.String,\n revision: Schema.String,\n diagnostics: Schema.Array(DiagnosticSchema),\n results: Schema.Array(SmlOpResultSchema),\n});\n\nexport interface ApplyOpsResult extends Schema.Schema.Type<typeof ApplyOpsResultSchema> {}\n\nexport interface ApplyOpsOptions {\n readonly expectedRevision?: string | number | undefined;\n readonly currentRevision?: string | number | undefined;\n}\n\nexport class SmlOpError extends Schema.TaggedErrorClass<SmlOpError>()(\"SmlOpError\", {\n diagnostics: Schema.Array(DiagnosticSchema),\n}) {\n override get message() {\n return this.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\");\n }\n}\n\nconst zeroSpan: Span = { start: 0, end: 0 };\n\nconst diagnostic = (code: string, message: string, span: Span = zeroSpan): Diagnostic => ({\n code,\n message,\n span,\n});\n\nconst cloneAttribute = (attribute: Attribute): Attribute => ({ ...attribute });\n\n/**\n * Deep-copy a subtree, blanking every id to \"\". A duplicated node must not\n * alias the original's object graph or share its ids: batch ids resolve\n * against the pre-batch snapshot, and mapElement transforms every node whose\n * id matches — so two live copies sharing an id would both be rewritten by a\n * later op. Blank ids make the clone unaddressable (like any freshly created\n * node) until the next reprint reassigns positional ids.\n */\nconst cloneSubtree = (node: SmlNode): SmlNode => {\n if (node.kind === \"element\") {\n return {\n ...node,\n id: \"\",\n attributes: node.attributes.map(cloneAttribute),\n children: node.children.map(cloneSubtree),\n };\n }\n return { ...node, id: \"\" };\n};\n\nconst makeAttribute = (name: string, value: AttributeValue): Attribute => ({\n name,\n value,\n span: zeroSpan,\n valueSpan: zeroSpan,\n});\n\nconst classAttr = (value: string): Attribute => makeAttribute(\"class\", { kind: \"string\", value });\n\nexport const sourceRevision = (source: string): string => {\n let hash = 0x811c9dc5;\n for (let index = 0; index < source.length; index++) {\n hash ^= source.charCodeAt(index);\n hash = Math.imul(hash, 0x01000193);\n }\n return `sml:${(hash >>> 0).toString(16).padStart(8, \"0\")}`;\n};\n\nexport const normalizeSml = (source: string): Result.Result<string, SmlParseError> => {\n const parsed = parseSml(source);\n if (Result.isFailure(parsed)) return Result.fail(parsed.failure);\n return Result.succeed(printSml(parsed.success));\n};\n\nconst findElement = (node: SmlNode, nodeId: string): ElementNode | null => {\n if (node.kind !== \"element\") return null;\n if (node.id === nodeId) return node;\n for (const child of node.children) {\n const found = findElement(child, nodeId);\n if (found !== null) return found;\n }\n return null;\n};\n\nconst mapElement = (\n node: SmlNode,\n targetId: string,\n transform: (element: ElementNode) => ElementNode,\n): SmlNode => {\n if (node.kind !== \"element\") return node;\n if (node.id === targetId) return transform(node);\n return {\n ...node,\n children: node.children.map((child) => mapElement(child, targetId, transform)),\n };\n};\n\nconst transformElement = (\n document: SmlDocument,\n targetId: string,\n transform: (element: ElementNode) => ElementNode,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n const target = findElement(document.root, targetId);\n if (target === null) {\n return Result.fail([\n diagnostic(\"op-target-not-found\", `node \"${targetId}\" was not found in the current source`),\n ]);\n }\n return Result.succeed({\n ...document,\n root: mapElement(document.root, targetId, transform) as ElementNode,\n });\n};\n\nconst setElementAttribute = (\n element: ElementNode,\n name: string,\n value: AttributeValue | null,\n): ElementNode => {\n const rest = element.attributes.filter((attribute) => attribute.name !== name);\n if (value === null || (value.kind === \"string\" && value.value === \"\")) {\n return { ...element, attributes: rest };\n }\n const next = makeAttribute(name, value);\n const existed = element.attributes.some((attribute) => attribute.name === name);\n const attributes = existed\n ? element.attributes.map((attribute) =>\n attribute.name === name ? next : cloneAttribute(attribute),\n )\n : [...element.attributes, next];\n return { ...element, attributes };\n};\n\nconst setImageSchemeSource = (\n document: SmlDocument,\n nodeId: string,\n scheme: \"dark\",\n value: AttributeValue | null,\n): Result.Result<SmlDocument, readonly Diagnostic[]> =>\n transformElement(document, nodeId, (element) => {\n if (element.tag !== \"Image\") return element;\n const src = value?.kind === \"string\" ? value.value : \"\";\n const children = element.children.filter(\n (child) =>\n !(\n child.kind === \"element\" &&\n child.tag === \"Source\" &&\n child.attributes.some(\n (attribute) =>\n attribute.name === \"scheme\" &&\n attribute.value.kind === \"string\" &&\n attribute.value.value === scheme,\n )\n ),\n );\n if (src === \"\") return { ...element, children };\n const sourceNode: ElementNode = {\n kind: \"element\",\n id: \"\",\n tag: \"Source\",\n attributes: [\n makeAttribute(\"scheme\", { kind: \"string\", value: scheme }),\n makeAttribute(\"src\", { kind: \"string\", value: src }),\n ],\n children: [],\n span: zeroSpan,\n };\n return { ...element, children: [...children, sourceNode] };\n });\n\nconst setProp = (\n document: SmlDocument,\n op: Extract<SmlOp, { _tag: \"setProp\" }>,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n if (op.name === \"src:dark\") return setImageSchemeSource(document, op.nodeId, \"dark\", op.value);\n return transformElement(document, op.nodeId, (element) => {\n const value =\n op.name === \"class\" && op.value?.kind === \"string\"\n ? { kind: \"string\" as const, value: op.value.value.trim().replace(/\\s+/g, \" \") }\n : op.value;\n return setElementAttribute(element, op.name, value);\n });\n};\n\nconst setChildren = (\n document: SmlDocument,\n op: Extract<SmlOp, { _tag: \"setChildren\" }>,\n): Result.Result<SmlDocument, readonly Diagnostic[]> =>\n transformElement(document, op.nodeId, (element) => ({ ...element, children: [...op.children] }));\n\nconst makeColumn = (): ElementNode => ({\n kind: \"element\",\n id: \"\",\n tag: \"Column\",\n attributes: [classAttr(\"px-8\")],\n children: [\n {\n kind: \"element\",\n id: \"\",\n tag: \"Text\",\n attributes: [classAttr(\"text-base text-gray-700\")],\n children: [{ kind: \"text\", id: \"\", value: \"Column\", span: zeroSpan }],\n span: zeroSpan,\n },\n ],\n span: zeroSpan,\n});\n\nconst makeBlock = (tag: SmlTag): ElementNode => {\n const base = (attributes: Attribute[], children: SmlNode[]): ElementNode => ({\n kind: \"element\",\n id: \"\",\n tag,\n attributes,\n children,\n span: zeroSpan,\n });\n const text = (value: string): SmlNode => ({\n kind: \"text\",\n id: \"\",\n value,\n span: zeroSpan,\n });\n switch (tag) {\n case \"Heading\":\n return base(\n [makeAttribute(\"level\", { kind: \"number\", value: 2 }), classAttr(\"text-xl text-gray-900\")],\n [text(\"Heading\")],\n );\n case \"Text\":\n return base([classAttr(\"text-base text-gray-700\")], [text(\"Add your text here.\")]);\n case \"Button\":\n return base(\n [\n makeAttribute(\"href\", { kind: \"string\", value: \"https://example.com\" }),\n classAttr(\"bg-blue-600 text-white px-20 py-12 rounded-md\"),\n ],\n [text(\"Button\")],\n );\n case \"Image\":\n return base(\n [\n makeAttribute(\"src\", { kind: \"string\", value: \"https://placehold.co/600x200\" }),\n makeAttribute(\"alt\", { kind: \"string\", value: \"\" }),\n makeAttribute(\"width\", { kind: \"number\", value: 600 }),\n ],\n [],\n );\n case \"Divider\":\n return base([classAttr(\"border-gray-200\")], []);\n case \"Spacer\":\n return base([makeAttribute(\"height\", { kind: \"number\", value: 24 })], []);\n case \"Section\":\n return base([classAttr(\"py-16\")], [makeBlock(\"Text\")]);\n case \"Container\":\n return base([classAttr(\"bg-white p-24\")], [makeBlock(\"Text\")]);\n case \"Row\":\n return base([], [makeColumn(), makeColumn()]);\n default:\n return base([], []);\n }\n};\n\nconst elementChildIndexToNodeIndex = (\n children: ReadonlyArray<SmlNode>,\n insertionIndex: number,\n): number => {\n if (insertionIndex <= 0) {\n const firstElement = children.findIndex((child) => child.kind === \"element\");\n return firstElement === -1 ? children.length : firstElement;\n }\n let elementIndex = 0;\n for (let index = 0; index < children.length; index++) {\n if (children[index]?.kind !== \"element\") continue;\n if (elementIndex === insertionIndex) return index;\n elementIndex++;\n }\n return children.length;\n};\n\nconst insertChildren = (\n document: SmlDocument,\n childrenToInsert: readonly ElementNode[],\n referenceId: string | null,\n position: typeof InsertPositionSchema.Type,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n if (childrenToInsert.length === 0) {\n return Result.fail([\n diagnostic(\"op-empty-insert\", \"insert operation produced no element nodes\"),\n ]);\n }\n if (referenceId === null || referenceId === document.root.id) {\n const children =\n position === \"before\"\n ? [...childrenToInsert, ...document.root.children]\n : [...document.root.children, ...childrenToInsert];\n return Result.succeed({ ...document, root: { ...document.root, children } });\n }\n const reference = findElement(document.root, referenceId);\n if (reference === null) {\n return Result.fail([\n diagnostic(\n \"op-target-not-found\",\n `node \"${referenceId}\" was not found in the current source`,\n ),\n ]);\n }\n if (position === \"inside\") {\n return transformElement(document, referenceId, (element) => ({\n ...element,\n children: [...element.children, ...childrenToInsert],\n }));\n }\n const insertInParent = (node: SmlNode): SmlNode => {\n if (node.kind !== \"element\") return node;\n const index = node.children.findIndex(\n (child) => child.kind === \"element\" && child.id === referenceId,\n );\n if (index >= 0) {\n const at = position === \"after\" ? index + 1 : index;\n return {\n ...node,\n children: [...node.children.slice(0, at), ...childrenToInsert, ...node.children.slice(at)],\n };\n }\n return { ...node, children: node.children.map(insertInParent) };\n };\n return Result.succeed({ ...document, root: insertInParent(document.root) as ElementNode });\n};\n\nconst insertBlock = (\n document: SmlDocument,\n op: Extract<SmlOp, { _tag: \"insertBlock\" }>,\n): Result.Result<SmlDocument, readonly Diagnostic[]> =>\n insertChildren(document, [makeBlock(op.tag)], op.referenceId, op.position);\n\nconst insertSnippet = (\n document: SmlDocument,\n op: Extract<SmlOp, { _tag: \"insertSnippet\" }>,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n const rootTag = document.root.tag;\n const parsed = parseSml(`<${rootTag}>${op.snippet}</${rootTag}>`);\n if (Result.isFailure(parsed)) return Result.fail(parsed.failure.diagnostics);\n const children = parsed.success.root.children.filter(\n (child): child is ElementNode => child.kind === \"element\",\n );\n return insertChildren(document, children, op.referenceId, op.position);\n};\n\nconst removeNodeById = (\n document: SmlDocument,\n nodeId: string,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n if (document.root.id === nodeId) {\n return Result.fail([diagnostic(\"op-root-target\", \"the document root cannot be removed\")]);\n }\n if (findElement(document.root, nodeId) === null) {\n return Result.fail([\n diagnostic(\"op-target-not-found\", `node \"${nodeId}\" was not found in the current source`),\n ]);\n }\n const prune = (node: SmlNode): SmlNode => {\n if (node.kind !== \"element\") return node;\n return {\n ...node,\n children: node.children\n .filter((child) => !(child.kind === \"element\" && child.id === nodeId))\n .map(prune),\n };\n };\n return Result.succeed({ ...document, root: prune(document.root) as ElementNode });\n};\n\nconst isDescendant = (ancestor: ElementNode, nodeId: string): boolean =>\n ancestor.children.some((child) => {\n if (child.kind !== \"element\") return false;\n return child.id === nodeId || isDescendant(child, nodeId);\n });\n\nconst removeElement = (\n node: ElementNode,\n nodeId: string,\n): { readonly node: ElementNode; readonly removed: ElementNode | null } => {\n let removed: ElementNode | null = null;\n const children: SmlNode[] = [];\n for (const child of node.children) {\n if (child.kind === \"element\" && child.id === nodeId) {\n removed = child;\n continue;\n }\n if (child.kind === \"element\") {\n const result = removeElement(child, nodeId);\n if (result.removed !== null) removed = result.removed;\n children.push(result.node);\n } else {\n children.push(child);\n }\n }\n return { node: { ...node, children }, removed };\n};\n\nconst insertIntoParent = (\n node: ElementNode,\n targetParentId: string,\n insertionIndex: number,\n moved: ElementNode,\n): ElementNode => {\n if (node.id === targetParentId) {\n const at = elementChildIndexToNodeIndex(node.children, insertionIndex);\n return {\n ...node,\n children: [...node.children.slice(0, at), moved, ...node.children.slice(at)],\n };\n }\n return {\n ...node,\n children: node.children.map((child) =>\n child.kind === \"element\"\n ? insertIntoParent(child, targetParentId, insertionIndex, moved)\n : child,\n ),\n };\n};\n\nconst moveNode = (\n document: SmlDocument,\n op: Extract<SmlOp, { _tag: \"moveNode\" }>,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n if (document.root.id === op.nodeId) {\n return Result.fail([diagnostic(\"op-root-target\", \"the document root cannot be moved\")]);\n }\n const moved = findElement(document.root, op.nodeId);\n if (moved === null) {\n return Result.fail([\n diagnostic(\"op-target-not-found\", `node \"${op.nodeId}\" was not found in the current source`),\n ]);\n }\n const parent = findElement(document.root, op.targetParentId);\n if (parent === null) {\n return Result.fail([\n diagnostic(\n \"op-target-not-found\",\n `target parent \"${op.targetParentId}\" was not found in the current source`,\n ),\n ]);\n }\n if (moved.id === parent.id || isDescendant(moved, parent.id)) {\n return Result.fail([\n diagnostic(\"op-invalid-reparent\", \"a node cannot be moved into itself or its descendants\"),\n ]);\n }\n const channel = documentChannel(document);\n const spec = CHANNEL_TAG_SPECS[channel][parent.tag];\n const childModel = spec?.content;\n const allowed = childModel === undefined ? [] : allowedChildren(childModel);\n if (!allowed.includes(moved.tag)) {\n return Result.fail([\n diagnostic(\n \"op-invalid-reparent\",\n `<${moved.tag}> is not allowed directly inside <${parent.tag}>`,\n parent.span,\n ),\n ]);\n }\n const { node: rootWithoutMoved, removed } = removeElement(document.root, op.nodeId);\n if (removed === null) {\n return Result.fail([\n diagnostic(\"op-target-not-found\", `node \"${op.nodeId}\" was not found in the current source`),\n ]);\n }\n return Result.succeed({\n ...document,\n root: insertIntoParent(rootWithoutMoved, op.targetParentId, op.insertionIndex, removed),\n });\n};\n\nconst duplicateNode = (\n document: SmlDocument,\n nodeId: string,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n if (document.root.id === nodeId) {\n return Result.fail([diagnostic(\"op-root-target\", \"the document root cannot be duplicated\")]);\n }\n if (findElement(document.root, nodeId) === null) {\n return Result.fail([\n diagnostic(\"op-target-not-found\", `node \"${nodeId}\" was not found in the current source`),\n ]);\n }\n const insertClone = (node: SmlNode): SmlNode => {\n if (node.kind !== \"element\") return node;\n const index = node.children.findIndex(\n (child) => child.kind === \"element\" && child.id === nodeId,\n );\n if (index >= 0) {\n const clone = cloneSubtree(node.children[index]!);\n return {\n ...node,\n children: [...node.children.slice(0, index + 1), clone, ...node.children.slice(index + 1)],\n };\n }\n return { ...node, children: node.children.map(insertClone) };\n };\n return Result.succeed({ ...document, root: insertClone(document.root) as ElementNode });\n};\n\nconst mutate = (\n document: SmlDocument,\n op: SmlOp,\n): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n switch (op._tag) {\n case \"setProp\":\n return setProp(document, op);\n case \"setChildren\":\n return setChildren(document, op);\n case \"insertBlock\":\n return insertBlock(document, op);\n case \"insertSnippet\":\n return insertSnippet(document, op);\n case \"moveNode\":\n return moveNode(document, op);\n case \"duplicateNode\":\n return duplicateNode(document, op.nodeId);\n case \"removeNode\":\n return removeNodeById(document, op.nodeId);\n }\n};\n\nconst preflight = (source: string): Result.Result<SmlDocument, readonly Diagnostic[]> => {\n const reparsed = parseSml(source);\n if (Result.isFailure(reparsed)) return Result.fail(reparsed.failure.diagnostics);\n const compiled = compileSml(reparsed.success);\n if (Result.isFailure(compiled)) return Result.fail(compiled.failure.diagnostics);\n const compatibilityErrors = checkSmlCompatibility({ source })\n .filter(isBreakingCompatibilityCheck)\n .map((message) => diagnostic(\"compatibility-error\", message));\n if (compatibilityErrors.length > 0) return Result.fail(compatibilityErrors);\n return Result.succeed(reparsed.success);\n};\n\nconst failedResult = (\n index: number,\n op: SmlOp,\n diagnostics: readonly Diagnostic[],\n): SmlOpResult => ({\n index,\n status: \"failed\",\n op,\n diagnostics: [...diagnostics],\n});\n\n/**\n * Apply a batch of ops to SML source, returning the rewritten source, its new\n * revision, and a per-op result.\n *\n * Id contract: every id in the batch resolves against the id-space of the\n * source the caller read (the `expectedRevision` snapshot). Ids are positional\n * (`n0..nN` in document order) and are NOT rewritten between ops, so:\n *\n * - An op cannot target a node created earlier in the same batch — freshly\n * inserted/duplicated nodes carry a blank id until the next reprint reassigns\n * positional ids, and are unaddressable within the batch (fails with\n * `op-target-not-found`).\n * - After `duplicateNode`, the duplicated id still addresses the ORIGINAL (the\n * first match in document order); the clone is a blank-id copy.\n * - Structural ops (insert/remove/move) do not shift the ids of the nodes that\n * survive, so a later op targeting a surviving sibling lands on the intended\n * node regardless of what earlier ops did.\n *\n * Each op is still preflighted (reprint, reparse, compile, compatibility check)\n * as an independent validity gate; a failing op is recorded as `failed` and\n * does not advance the working document.\n */\nexport const applyOps = (\n source: string,\n ops: readonly SmlOp[],\n options?: ApplyOpsOptions,\n): Result.Result<ApplyOpsResult, SmlOpError> => {\n const parsed = parseSml(source);\n if (Result.isFailure(parsed)) {\n return Result.fail(new SmlOpError({ diagnostics: parsed.failure.diagnostics }));\n }\n\n const currentRevision = String(options?.currentRevision ?? sourceRevision(source));\n if (\n options?.expectedRevision !== undefined &&\n String(options.expectedRevision) !== currentRevision\n ) {\n const stale = diagnostic(\n \"stale-revision\",\n `source revision changed from ${String(options.expectedRevision)} to ${currentRevision}`,\n );\n return Result.succeed({\n source,\n revision: currentRevision,\n diagnostics: [stale],\n results: ops.map((op, index) => failedResult(index, op, [stale])),\n });\n }\n\n let currentSource = source;\n let currentDocument = parsed.success;\n const results: SmlOpResult[] = [];\n const diagnostics: Diagnostic[] = [];\n\n ops.forEach((op, index) => {\n const mutated = mutate(currentDocument, op);\n if (Result.isFailure(mutated)) {\n results.push(failedResult(index, op, mutated.failure));\n diagnostics.push(...mutated.failure);\n return;\n }\n const candidateSource = printSml(mutated.success);\n const checked = preflight(candidateSource);\n if (Result.isFailure(checked)) {\n results.push(failedResult(index, op, checked.failure));\n diagnostics.push(...checked.failure);\n return;\n }\n // Thread the MUTATED document, not the reparsed one: reparsing reassigns\n // positional ids, which would move every id an op targets out from under\n // the caller's snapshot. The mutation helpers spread-copy and preserve the\n // `id` field, so ids from the initial parse stay stable across the batch.\n // Preflight above stays the per-op validity gate; only its result document\n // is discarded.\n currentSource = candidateSource;\n currentDocument = mutated.success;\n results.push({ index, status: \"applied\", op, diagnostics: [] });\n });\n\n return Result.succeed({\n source: currentSource,\n revision: sourceRevision(currentSource),\n diagnostics,\n results,\n });\n};\n\nexport const applyOp = (\n source: string,\n op: SmlOp,\n options?: ApplyOpsOptions,\n): Result.Result<ApplyOpsResult, SmlOpError> => applyOps(source, [op], options);\n"],"mappings":"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"}