@samva/markup 0.4.0 → 0.6.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 (107) hide show
  1. package/AGENTS.md +19 -0
  2. package/dist/{ast-63I-VLQx.d.ts → ast-BrDtApwS.d.ts} +34 -60
  3. package/dist/ast.d.ts +2 -2
  4. package/dist/ast.js +4 -52
  5. package/dist/{catalog-Ck1tAGwO.d.ts → catalog-60eaYC7b.d.ts} +2 -2
  6. package/dist/{checks-DXuERO4B.js → checks-DBweSIPN.js} +18 -20
  7. package/dist/checks.d.ts +1 -1
  8. package/dist/checks.js +1 -1
  9. package/dist/classes.d.ts +1 -1
  10. package/dist/compile-sms.d.ts +3 -3
  11. package/dist/compile-whatsapp.d.ts +5 -5
  12. package/dist/compile-whatsapp.js +3 -3
  13. package/dist/compile.d.ts +5 -5
  14. package/dist/compile.js +5 -5
  15. package/dist/compiler.d.ts +8 -5
  16. package/dist/compiler.js +45 -45
  17. package/dist/components.d.ts +4 -4
  18. package/dist/conditionals.js +56 -24
  19. package/dist/corpus-BjYMqOoY.d.ts +106 -0
  20. package/dist/{css-ar2lU3NC.d.ts → css-COcFOT1y.d.ts} +4 -5
  21. package/dist/diagnostics-BMYtBCQk.d.ts +46 -0
  22. package/dist/diagnostics-OcQKQYSY.d.ts +49 -0
  23. package/dist/diagnostics.d.ts +2 -2
  24. package/dist/diagnostics.js +24 -33
  25. package/dist/{elements-DtwKlFVH.d.ts → elements-BzjjnoCS.d.ts} +40 -161
  26. package/dist/email/components.d.ts +1 -1
  27. package/dist/email/components.js +40 -10
  28. package/dist/email/diagnostics.d.ts +1 -1
  29. package/dist/email/diagnostics.js +8 -43
  30. package/dist/email/elements.d.ts +1 -1
  31. package/dist/email/html.d.ts +2 -2
  32. package/dist/email/html.js +11 -10
  33. package/dist/email/jsx-dev-runtime.d.ts +3 -21
  34. package/dist/email/jsx-runtime.d.ts +1 -1
  35. package/dist/email/jsx-runtime.js +29 -3
  36. package/dist/email/render.d.ts +4 -4
  37. package/dist/email/render.js +1 -1
  38. package/dist/email/selection.d.ts +20 -31
  39. package/dist/email/selection.js +1 -53
  40. package/dist/email/source-edit.d.ts +1 -1
  41. package/dist/email/source-edit.js +2 -2
  42. package/dist/email/stylesheets.d.ts +1 -1
  43. package/dist/email/text.d.ts +1 -1
  44. package/dist/email/text.js +3 -3
  45. package/dist/emit.d.ts +2 -2
  46. package/dist/emit.js +5 -5
  47. package/dist/footer.js +7 -4
  48. package/dist/guards-eV1qLbf2.js +9 -0
  49. package/dist/{input-schema-BIfzI63B.d.ts → input-schema-7dPFVvNE.d.ts} +2 -2
  50. package/dist/input-schema-zjkgrXn2.js +455 -0
  51. package/dist/input-schema.d.ts +1 -1
  52. package/dist/input-schema.js +1 -169
  53. package/dist/interpolate.d.ts +9 -12
  54. package/dist/interpolate.js +1 -19
  55. package/dist/jsx-dev-runtime.d.ts +2 -2
  56. package/dist/{jsx-runtime-C5k_Zq0A.d.ts → jsx-runtime-I-1nCtl2.d.ts} +3 -3
  57. package/dist/jsx-runtime.d.ts +1 -1
  58. package/dist/jsx-runtime.js +3 -3
  59. package/dist/lexer.js +17 -5
  60. package/dist/model.d.ts +18 -33
  61. package/dist/model.js +4 -17
  62. package/dist/ops-2aiiYO7m.js +630 -0
  63. package/dist/ops.d.ts +78 -172
  64. package/dist/ops.js +2 -546
  65. package/dist/{parser-CGBS73Gz.d.ts → parser-CQcASEyy.d.ts} +5 -5
  66. package/dist/parser.d.ts +1 -1
  67. package/dist/parser.js +8 -8
  68. package/dist/{predicate-CvkzT-a2.js → predicate-BI6uRRM-.js} +24 -14
  69. package/dist/{predicate-G2SeSvoN.d.ts → predicate-M-05Nd7R.d.ts} +4 -4
  70. package/dist/predicate.d.ts +1 -1
  71. package/dist/predicate.js +1 -1
  72. package/dist/presets/category-mapping.d.ts +1 -1
  73. package/dist/presets/corpus.d.ts +1 -1
  74. package/dist/presets/corpus.js +74 -117
  75. package/dist/presets/public-gallery.d.ts +2 -2
  76. package/dist/presets/public-gallery.js +17 -9
  77. package/dist/presets/public-handoff.d.ts +4 -4
  78. package/dist/presets/public-handoff.js +10 -9
  79. package/dist/presets/public-preview-artifacts.d.ts +7 -5
  80. package/dist/presets/public-preview-artifacts.js +10 -9
  81. package/dist/presets/showcase.d.ts +1 -1
  82. package/dist/presets.d.ts +1 -1
  83. package/dist/printer.d.ts +1 -1
  84. package/dist/{render-ykQhtMs_.js → render-aaJBnsXK.js} +44 -27
  85. package/dist/render-template.d.ts +7 -7
  86. package/dist/render-template.js +6 -6
  87. package/dist/{showcase-C_xgl6hz.d.ts → showcase-DGZAWn4Z.d.ts} +2 -2
  88. package/dist/{source-locations-BCJQnIfU.d.ts → source-locations-DrCM82Ym.d.ts} +4 -26
  89. package/dist/source-locations.d.ts +2 -2
  90. package/dist/source-locations.js +3 -26
  91. package/dist/{template-Dy5yOPyp.d.ts → template-DWftqh4x.d.ts} +4 -4
  92. package/dist/template.d.ts +1 -1
  93. package/dist/template.js +3 -3
  94. package/dist/theme-css.d.ts +3 -3
  95. package/dist/theme-css.js +3 -3
  96. package/dist/theme.js +25 -2
  97. package/dist/tsx-source-instrumentation.d.ts +1 -3
  98. package/dist/tsx-source-instrumentation.js +6 -6
  99. package/dist/tsx-tracer.d.ts +7 -11
  100. package/dist/tsx-tracer.js +165 -165
  101. package/dist/{variables-if1VrV34.d.ts → variables-J_L3qxRa.d.ts} +2 -2
  102. package/dist/variables.d.ts +1 -1
  103. package/dist/variables.js +4 -4
  104. package/package.json +4 -3
  105. package/dist/corpus-U2EeALvS.d.ts +0 -234
  106. package/dist/diagnostics-Djd9ckLg.d.ts +0 -90
  107. package/dist/diagnostics-oveE-laV.d.ts +0 -79
package/dist/ops.js CHANGED
@@ -1,546 +1,2 @@
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 { a as isBreakingCompatibilityCheck, r as checkSmlCompatibility } from "./checks-DXuERO4B.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.TaggedError()("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
1
+ import { a as sourceRevision, i as normalizeSml, n as applyOp, r as applyOps, t as SmlOpError } from "./ops-2aiiYO7m.js";
2
+ export { SmlOpError, applyOp, applyOps, normalizeSml, sourceRevision };
@@ -1,6 +1,6 @@
1
- import { o as SmlParseError } from "./diagnostics-oveE-laV.js";
2
- import { O as SmlTag, d as Channel, w as SmlDocument } from "./ast-63I-VLQx.js";
3
- import { Result } from "effect";
1
+ import { i as SmlParseError } from "./diagnostics-OcQKQYSY.js";
2
+ import { S as SmlTag, b as SmlDocument, l as Channel } from "./ast-BrDtApwS.js";
3
+ import { Result } from "better-result";
4
4
  //#region src/limits.d.ts
5
5
  /** Hard ceilings shared by SML documents and standalone predicate parsing. */
6
6
  declare const SML_PARSER_LIMITS: {
@@ -390,7 +390,7 @@ declare const UNIVERSAL_ATTRIBUTES: {
390
390
  declare const UNIVERSAL_ATTRIBUTE_TAGS: ReadonlySet<SmlTag>;
391
391
  /** Tags a content model admits as direct children (public alongside the spec tables). */
392
392
  declare const allowedChildren: (model: ContentModel) => ReadonlyArray<SmlTag>;
393
- declare const parseSml: (source: string) => Result.Result<SmlDocument, SmlParseError>;
393
+ declare const parseSml: (source: string) => Result<SmlDocument, SmlParseError>;
394
394
  //#endregion
395
395
  export { SMS_TAG_SPECS as a, UNIVERSAL_ATTRIBUTE_TAGS as c, parseSml as d, SML_PARSER_LIMITS as f, EMAIL_TAG_SPECS as i, WHATSAPP_TAG_SPECS as l, CHANNEL_TAG_SPECS as n, TagSpec as o, ContentModel as r, UNIVERSAL_ATTRIBUTES as s, AttributeSpec as t, allowedChildren as u };
396
- //# sourceMappingURL=parser-CGBS73Gz.d.ts.map
396
+ //# sourceMappingURL=parser-CQcASEyy.d.ts.map
package/dist/parser.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as SMS_TAG_SPECS, c as UNIVERSAL_ATTRIBUTE_TAGS, d as parseSml, f as SML_PARSER_LIMITS, i as EMAIL_TAG_SPECS, l as WHATSAPP_TAG_SPECS, n as CHANNEL_TAG_SPECS, o as TagSpec, r as ContentModel, s as UNIVERSAL_ATTRIBUTES, t as AttributeSpec, u as allowedChildren } from "./parser-CGBS73Gz.js";
1
+ import { a as SMS_TAG_SPECS, c as UNIVERSAL_ATTRIBUTE_TAGS, d as parseSml, f as SML_PARSER_LIMITS, i as EMAIL_TAG_SPECS, l as WHATSAPP_TAG_SPECS, n as CHANNEL_TAG_SPECS, o as TagSpec, r as ContentModel, s as UNIVERSAL_ATTRIBUTES, t as AttributeSpec, u as allowedChildren } from "./parser-CQcASEyy.js";
2
2
  export { AttributeSpec, CHANNEL_TAG_SPECS, ContentModel, EMAIL_TAG_SPECS, SML_PARSER_LIMITS, SMS_TAG_SPECS, TagSpec, UNIVERSAL_ATTRIBUTES, UNIVERSAL_ATTRIBUTE_TAGS, WHATSAPP_TAG_SPECS, allowedChildren, parseSml };
package/dist/parser.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { SmlParseError } from "./diagnostics.js";
2
- import { a as printPredicate, i as parsePredicate, o as SML_PARSER_LIMITS } from "./predicate-CvkzT-a2.js";
2
+ import { a as printPredicate, i as parsePredicate, o as SML_PARSER_LIMITS } from "./predicate-BI6uRRM-.js";
3
3
  import { CHANNEL_BY_ROOT_TAG, ROOT_TAGS, SML_TAGS, isRootTag } from "./ast.js";
4
4
  import { TokenKind, createLexer } from "./lexer.js";
5
- import { Result } from "effect";
5
+ import { Result } from "better-result";
6
6
  //#region src/parser.ts
7
- const parserLimitFailure = (code, message, sourceLength) => Result.fail(new SmlParseError({ diagnostics: [{
7
+ const parserLimitFailure = (code, message, sourceLength) => Result.err(new SmlParseError({ diagnostics: [{
8
8
  code,
9
9
  message,
10
10
  span: {
@@ -649,15 +649,15 @@ const parseSml = (source) => {
649
649
  const testAttribute = element.attributes[testIndex];
650
650
  if (testAttribute.value.kind === "string") {
651
651
  const parsed = parsePredicate(testAttribute.value.value, testAttribute.valueSpan.start);
652
- if (Result.isFailure(parsed)) {
653
- const first = parsed.failure[0];
652
+ if (Result.isError(parsed)) {
653
+ const first = parsed.error[0];
654
654
  return fail(first.code, first.message, first.span);
655
655
  }
656
656
  element.attributes[testIndex] = {
657
657
  ...testAttribute,
658
658
  value: {
659
659
  kind: "string",
660
- value: printPredicate(parsed.success)
660
+ value: printPredicate(parsed.value)
661
661
  }
662
662
  };
663
663
  }
@@ -815,7 +815,7 @@ const parseSml = (source) => {
815
815
  root = null;
816
816
  }
817
817
  }
818
- if (root === null || diagnostic !== void 0) return Result.fail(new SmlParseError({ diagnostics: [diagnostic ?? {
818
+ if (root === null || diagnostic !== void 0) return Result.err(new SmlParseError({ diagnostics: [diagnostic ?? {
819
819
  code: "parse-failed",
820
820
  message: "parse failed",
821
821
  span: {
@@ -824,7 +824,7 @@ const parseSml = (source) => {
824
824
  }
825
825
  }] }));
826
826
  assignNodeIds(root);
827
- return Result.succeed({
827
+ return Result.ok({
828
828
  kind: "document",
829
829
  root
830
830
  });