@samva/markup 0.9.0 → 0.10.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 (88) hide show
  1. package/AGENTS.md +48 -40
  2. package/CHANGELOG.md +345 -0
  3. package/README.md +6 -6
  4. package/dist/{brand-B-0bN_Ir.d.ts → assets-BIsyMQ92.d.ts} +41 -11
  5. package/dist/{email/brand.js → brand-C0MKTwmX.js} +64 -4
  6. package/dist/{theme-css.d.ts → brand.d.ts} +12 -3
  7. package/dist/brand.js +4 -0
  8. package/dist/compiler.d.ts +231 -11
  9. package/dist/compiler.js +1312 -13
  10. package/dist/components-BZCqegS8.js +1864 -0
  11. package/dist/diagnostic-model-DJtqbETd.js +38 -0
  12. package/dist/diagnostic-model-DxthUZBT.d.ts +31 -0
  13. package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +2 -2
  14. package/dist/diagnostics.d.ts +406 -27
  15. package/dist/diagnostics.js +402 -34
  16. package/dist/edit.d.ts +234 -0
  17. package/dist/{channel-edit.js → edit.js} +341 -3
  18. package/dist/email/jsx-dev-runtime.d.ts +1 -1
  19. package/dist/email/jsx-dev-runtime.js +1 -2
  20. package/dist/email/jsx-runtime.d.ts +1 -1
  21. package/dist/email/jsx-runtime.js +1 -85
  22. package/dist/{email/components.d.ts → email.d.ts} +2 -2
  23. package/dist/email.js +2 -0
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/{cascade-t6kxlgEI.js → ir-CLhlklKV.js} +8 -4
  27. package/dist/jsx-runtime-CBlexoeR.js +98 -0
  28. package/dist/{elements-cqldpaJt.d.ts → jsx-runtime-ylIOnaSf.d.ts} +74 -74
  29. package/dist/{profile-BH-OtdDA.js → profile-pWGtWZXF.js} +153 -20
  30. package/dist/render-BPonDpCl.d.ts +539 -0
  31. package/dist/{email/render.js → render-BQmfh94k.js} +102 -8
  32. package/dist/render.d.ts +35 -0
  33. package/dist/render.js +49 -0
  34. package/dist/sms.d.ts +1 -1
  35. package/dist/sms.js +1 -1
  36. package/dist/{template-_QE_rQND.d.ts → template-DMPwxMSq.d.ts} +2 -2
  37. package/dist/{template.js → template-zLUjcwfF.js} +2 -2
  38. package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
  39. package/dist/whatsapp.d.ts +1 -1
  40. package/dist/whatsapp.js +1 -1
  41. package/generated/contract.json +16 -10
  42. package/generated/reference.md +17 -10
  43. package/package.json +36 -119
  44. package/samva-brand.d.ts +4 -4
  45. package/skills/sml/SKILL.md +2 -2
  46. package/dist/assets-C5duwTya.d.ts +0 -40
  47. package/dist/channel-edit.d.ts +0 -121
  48. package/dist/channel-specs-B6M_HlaV.js +0 -29
  49. package/dist/compatibility-DbISoFIq.js +0 -589
  50. package/dist/css-BVQKICKC.d.ts +0 -109
  51. package/dist/diagnostic-codes.d.ts +0 -403
  52. package/dist/diagnostic-codes.js +0 -399
  53. package/dist/email/assets.d.ts +0 -2
  54. package/dist/email/assets.js +0 -63
  55. package/dist/email/brand-footer.d.ts +0 -34
  56. package/dist/email/brand-footer.js +0 -63
  57. package/dist/email/brand.d.ts +0 -2
  58. package/dist/email/components.js +0 -275
  59. package/dist/email/diagnostics.d.ts +0 -2
  60. package/dist/email/elements.d.ts +0 -2
  61. package/dist/email/elements.js +0 -299
  62. package/dist/email/html.d.ts +0 -2
  63. package/dist/email/html.js +0 -321
  64. package/dist/email/render.d.ts +0 -40
  65. package/dist/email/text.d.ts +0 -7
  66. package/dist/email/text.js +0 -100
  67. package/dist/html-BJepOwZ4.d.ts +0 -56
  68. package/dist/ir-aaqNE987.d.ts +0 -252
  69. package/dist/ir.d.ts +0 -2
  70. package/dist/ir.js +0 -7
  71. package/dist/preview-Ekdg1dXG.d.ts +0 -100
  72. package/dist/preview.d.ts +0 -2
  73. package/dist/preview.js +0 -160
  74. package/dist/render-ir.d.ts +0 -19
  75. package/dist/render-ir.js +0 -826
  76. package/dist/sms-segments.d.ts +0 -13
  77. package/dist/sms-segments.js +0 -46
  78. package/dist/source-edit.d.ts +0 -116
  79. package/dist/source-edit.js +0 -343
  80. package/dist/source-locations.d.ts +0 -2
  81. package/dist/source-locations.js +0 -16
  82. package/dist/static.d.ts +0 -57
  83. package/dist/static.js +0 -69
  84. package/dist/tailwind-CMYpZf1v.js +0 -614
  85. package/dist/template.d.ts +0 -2
  86. package/dist/theme-css.js +0 -2
  87. package/dist/theme-imports-lvBw3AD1.js +0 -109
  88. package/dist/transform-Ct2OMkFN.d.ts +0 -153
@@ -1,252 +0,0 @@
1
- //#region src/ir.d.ts
2
- /** The IR version this package writes. A publication pins the version it was built with. */
3
- declare const SML_IR_VERSION = 1;
4
- /**
5
- * Where a node came from: `[line, column]` in the entry file, or `[line, column, file]` with an
6
- * index into `TemplateIr.sources` when the node came from an imported project file. Published
7
- * sends strip these.
8
- */
9
- type IrSource = readonly [line: number, column: number, file?: number];
10
- /**
11
- * A value read at render time.
12
- *
13
- * - a string, number, boolean or `null` is a literal;
14
- * - `bind` reads the input: `"order.id"` is a path from the input root, `"$item.title"` a path
15
- * from the enclosing `each` variable named `item` (the `$` prefix keeps loop variables from
16
- * colliding with input fields);
17
- * - `lit` is a literal object or array, for formatter options;
18
- * - `concat` joins the text of its parts (a template string);
19
- * - `format` calls one formatter from `@samva/markup/fmt`;
20
- * - `if` selects between two values (a conditional attribute or class);
21
- * - `op` is arithmetic, allowed inside formatter arguments and conditions;
22
- * - `length` is `.length` of a bound array or string;
23
- * - `count` is `.filter(...).length`: the items of an array that satisfy a condition.
24
- */
25
- type IrValue = string | number | boolean | null | {
26
- readonly bind: string;
27
- } | {
28
- readonly lit: unknown;
29
- } | {
30
- readonly concat: readonly IrValue[];
31
- } | {
32
- readonly format: IrFormatter;
33
- readonly args: readonly IrValue[];
34
- } | {
35
- readonly if: IrPredicate;
36
- readonly then: IrValue;
37
- readonly else: IrValue;
38
- } | {
39
- readonly op: IrArithmetic;
40
- readonly args: readonly [IrValue, IrValue];
41
- } | {
42
- readonly length: IrValue;
43
- } |
44
- /** How many items of a bound array satisfy `where`, with each item bound as `$as` while it runs. */
45
- {
46
- readonly count: IrValue;
47
- readonly as: string;
48
- readonly where: IrPredicate;
49
- };
50
- type IrFormatter = "money" | "number" | "date" | "time" | "plural" | "list";
51
- type IrArithmetic = "+" | "-" | "*" | "/" | "%";
52
- type IrComparison = "eq" | "ne" | "lt" | "gt" | "le" | "ge";
53
- /** A condition over the input. Truthiness follows JavaScript: `""`, `0`, `null` and absent are false. */
54
- type IrPredicate =
55
- /** The bound value at this path is truthy. */
56
- {
57
- readonly present: string;
58
- } |
59
- /** Any value is truthy. */
60
- {
61
- readonly truthy: IrValue;
62
- } | {
63
- readonly not: IrPredicate;
64
- } | {
65
- readonly and: readonly IrPredicate[];
66
- } | {
67
- readonly or: readonly IrPredicate[];
68
- } | {
69
- readonly cmp: IrComparison;
70
- readonly args: readonly [IrValue, IrValue];
71
- };
72
- /**
73
- * An element's inline style. A string is fully static and was checked at compile time; a list
74
- * carries declarations whose values are read at render time; `if` selects between two styles.
75
- */
76
- type IrStyle = string | readonly (readonly [property: string, value: IrValue])[] | {
77
- readonly if: IrPredicate;
78
- readonly then: IrStyle;
79
- readonly else: IrStyle;
80
- };
81
- /** A part of compatibility markup the primitives emit verbatim. */
82
- type IrRawPart = string | {
83
- readonly attr: IrValue;
84
- } | {
85
- readonly text: IrValue;
86
- };
87
- interface IrElement {
88
- readonly el: string;
89
- readonly attrs?: Readonly<Record<string, IrValue>>;
90
- readonly style?: IrStyle;
91
- readonly children?: readonly IrNode[];
92
- /**
93
- * Set by the compiler on the elements `BrandFooter` writes: only they may carry the reserved
94
- * footer markers, so an element the author wrote cannot claim a footer the send path would
95
- * then not append.
96
- */
97
- readonly reserved?: true;
98
- readonly src?: IrSource;
99
- }
100
- /** Content that appears when the predicate holds, or else `else`. */
101
- interface IrIf {
102
- readonly if: IrPredicate;
103
- readonly then: readonly IrNode[];
104
- readonly else?: readonly IrNode[];
105
- readonly src?: IrSource;
106
- }
107
- /**
108
- * Repeat `children` for each item of a bound array.
109
- *
110
- * `where` skips the items that fail a condition (`.filter(...)`), with the item bound as `$as`.
111
- * `chunk` groups the items into consecutive slices of that size instead: the loop variable `$as`
112
- * then holds one slice, an array, and the last slice may be shorter. Filtering applies first.
113
- */
114
- interface IrEach {
115
- readonly each: IrValue;
116
- /** The loop variable, referenced as `$as.field`. */
117
- readonly as: string;
118
- /** The zero-based index variable, referenced as `$index`. */
119
- readonly index?: string;
120
- readonly where?: IrPredicate;
121
- readonly chunk?: number;
122
- readonly children: readonly IrNode[];
123
- readonly src?: IrSource;
124
- }
125
- /**
126
- * Compatibility markup the email primitives emit verbatim (conditional comments, VML). Bound
127
- * parts are escaped for the context they sit in. `text` is what the plain-text part reads.
128
- */
129
- interface IrRaw {
130
- readonly raw: readonly IrRawPart[];
131
- readonly text?: IrValue;
132
- readonly src?: IrSource;
133
- }
134
- /** Where the hidden inbox-preview block goes; it renders the channel's `preheader`. */
135
- interface IrPreheader {
136
- readonly preheader: true;
137
- }
138
- /** A node in an email body. A bare value in child position is rendered as escaped text. */
139
- type IrNode = IrValue | IrElement | IrIf | IrEach | IrRaw | IrPreheader;
140
- interface IrEmail {
141
- readonly subject: IrValue;
142
- readonly preheader?: IrValue;
143
- readonly body: IrNode;
144
- }
145
- /** A plain-text channel body: text pieces, conditionals and loops. */
146
- interface IrSms {
147
- readonly category?: string;
148
- readonly body: readonly IrNode[];
149
- }
150
- type IrWhatsAppButton = {
151
- readonly type: "quick-reply";
152
- readonly text: IrValue;
153
- } | {
154
- readonly type: "url";
155
- readonly text: IrValue;
156
- readonly url: IrValue;
157
- } | {
158
- readonly type: "phone";
159
- readonly text: IrValue;
160
- readonly phone: IrValue;
161
- } | {
162
- readonly type: "copy-code";
163
- readonly code: IrValue;
164
- };
165
- /** A button, or buttons that appear when a condition over the input holds. */
166
- type IrWhatsAppButtonNode = IrWhatsAppButton | {
167
- readonly if: IrPredicate;
168
- readonly then: readonly IrWhatsAppButtonNode[];
169
- readonly else?: readonly IrWhatsAppButtonNode[];
170
- readonly src?: IrSource;
171
- };
172
- interface IrWhatsApp {
173
- readonly name?: string;
174
- readonly category: string;
175
- readonly language: string;
176
- /** For a media header, `content` is the media URL. */
177
- readonly header?: {
178
- readonly type: "text" | "image" | "video" | "document";
179
- readonly content: readonly IrNode[];
180
- };
181
- readonly body: readonly IrNode[];
182
- readonly footer?: readonly IrNode[];
183
- readonly buttons?: readonly IrWhatsAppButtonNode[];
184
- }
185
- interface TemplateIr {
186
- readonly sml: typeof SML_IR_VERSION;
187
- readonly template: string;
188
- readonly locale?: string;
189
- /** Project paths that `IrSource` file indexes name; index 0 is the entry. */
190
- readonly sources?: readonly string[];
191
- readonly email?: IrEmail;
192
- readonly sms?: IrSms;
193
- readonly whatsapp?: IrWhatsApp;
194
- /** The portable JSON Schema every send's input is validated against. */
195
- readonly schema: Readonly<Record<string, unknown>>;
196
- }
197
- /** How the renderer resolves formatters that take no explicit locale or time zone. */
198
- interface RenderOptions {
199
- /** Overrides the template's `locale`. */
200
- readonly locale?: string;
201
- /** IANA time zone; defaults to UTC. */
202
- readonly timeZone?: string;
203
- /** Also return where each element landed in the HTML, for mapping findings back to source. */
204
- readonly positions?: boolean;
205
- }
206
- /** One rendered element's offset range in the HTML, and the source it was lowered from. */
207
- interface RenderedPosition {
208
- readonly start: number;
209
- readonly end: number;
210
- readonly tag: string;
211
- readonly src?: IrSource;
212
- }
213
- interface RenderedIrEmail {
214
- readonly subject: string;
215
- readonly preheader: string | undefined;
216
- readonly html: string;
217
- readonly text: string;
218
- /** Present when the render asked for `positions`. */
219
- readonly positions?: readonly RenderedPosition[];
220
- }
221
- type RenderedWhatsAppButton = {
222
- readonly type: "quick-reply";
223
- readonly text: string;
224
- } | {
225
- readonly type: "url";
226
- readonly text: string;
227
- readonly url: string;
228
- } | {
229
- readonly type: "phone";
230
- readonly text: string;
231
- readonly phone: string;
232
- } | {
233
- readonly type: "copy-code";
234
- readonly code: string;
235
- };
236
- /** A WhatsApp message with every text rendered and every conditional button resolved. */
237
- interface RenderedIrWhatsApp {
238
- readonly name?: string;
239
- readonly language: string;
240
- readonly category: string;
241
- /** For a media header, `text` is the media URL. */
242
- readonly header?: {
243
- readonly type: "text" | "image" | "video" | "document";
244
- readonly text: string;
245
- };
246
- readonly body: string;
247
- readonly footer?: string;
248
- readonly buttons: readonly RenderedWhatsAppButton[];
249
- }
250
- //#endregion
251
- export { RenderedPosition as C, TemplateIr as E, RenderedIrWhatsApp as S, SML_IR_VERSION as T, IrWhatsApp as _, IrEmail as a, RenderOptions as b, IrNode as c, IrRaw as d, IrRawPart as f, IrValue as g, IrStyle as h, IrElement as i, IrPredicate as l, IrSource as m, IrComparison as n, IrFormatter as o, IrSms as p, IrEach as r, IrIf as s, IrArithmetic as t, IrPreheader as u, IrWhatsAppButton as v, RenderedWhatsAppButton as w, RenderedIrEmail as x, IrWhatsAppButtonNode as y };
252
- //# sourceMappingURL=ir-aaqNE987.d.ts.map
package/dist/ir.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { C as RenderedPosition, E as TemplateIr, S as RenderedIrWhatsApp, T as SML_IR_VERSION, _ as IrWhatsApp, a as IrEmail, b as RenderOptions, c as IrNode, d as IrRaw, f as IrRawPart, g as IrValue, h as IrStyle, i as IrElement, l as IrPredicate, m as IrSource, n as IrComparison, o as IrFormatter, p as IrSms, r as IrEach, s as IrIf, t as IrArithmetic, u as IrPreheader, v as IrWhatsAppButton, w as RenderedWhatsAppButton, x as RenderedIrEmail, y as IrWhatsAppButtonNode } from "./ir-aaqNE987.js";
2
- export { IrArithmetic, IrComparison, IrEach, IrElement, IrEmail, IrFormatter, IrIf, IrNode, IrPredicate, IrPreheader, IrRaw, IrRawPart, IrSms, IrSource, IrStyle, IrValue, IrWhatsApp, IrWhatsAppButton, IrWhatsAppButtonNode, RenderOptions, RenderedIrEmail, RenderedIrWhatsApp, RenderedPosition, RenderedWhatsAppButton, SML_IR_VERSION, TemplateIr };
package/dist/ir.js DELETED
@@ -1,7 +0,0 @@
1
- //#region src/ir.ts
2
- /** The IR version this package writes. A publication pins the version it was built with. */
3
- const SML_IR_VERSION = 1;
4
- //#endregion
5
- export { SML_IR_VERSION };
6
-
7
- //# sourceMappingURL=ir.js.map
@@ -1,100 +0,0 @@
1
- import { r as JsxSourceLocation } from "./source-locations-C8wCsiAy.js";
2
- import { E as TemplateIr, b as RenderOptions } from "./ir-aaqNE987.js";
3
- //#region src/preview.d.ts
4
- /**
5
- * The attribute a preview stamps so a click in a rendered document resolves to exactly one
6
- * rendered element. A delivered message never carries it.
7
- */
8
- declare const INSTANCE_PATH_ATTRIBUTE = "data-samva-instance";
9
- /** Where one element sits in the emitted document, with the authoring that produced it. */
10
- interface EmittedPosition {
11
- readonly start: number;
12
- readonly end: number;
13
- readonly origins: ReadonlyArray<JsxSourceLocation>;
14
- /**
15
- * Dot-separated element indices from the document root, assigned in document order. It is the
16
- * identity of one rendered instance.
17
- */
18
- readonly instancePath: string;
19
- readonly tag: string;
20
- /** False when a compiler primitive generated this element. */
21
- readonly authored: boolean;
22
- }
23
- /** One rendered element, and the authoring it came from. */
24
- interface EmailElementSelection {
25
- /**
26
- * Dot-separated element indices from the document root. It is the identity of one rendered
27
- * instance, which is what tells two iterations of the same authored element apart: their
28
- * origins are identical.
29
- */
30
- readonly instancePath: string;
31
- readonly tag: string;
32
- /**
33
- * The authored JSX element. Empty when the compiler generated this element with no authoring
34
- * behind it, the hidden preheader block for instance.
35
- */
36
- readonly origins: ReadonlyArray<JsxSourceLocation>;
37
- /**
38
- * False when a compiler primitive generated this element. `origins[0]` is then the authoring
39
- * element that asked for it rather than this element itself, so the wrapper selects the
40
- * primitive the author wrote.
41
- */
42
- readonly authored: boolean;
43
- /** 1-based position among the rendered elements sharing this origin and tag. */
44
- readonly occurrence: number;
45
- /**
46
- * How many rendered elements share that origin and tag. Above one, one piece of authoring
47
- * produced several rendered elements (a loop, or a primitive that generates a repeated cell),
48
- * so an edit there changes all of them.
49
- */
50
- readonly occurrences: number;
51
- /** Absent for the document root. */
52
- readonly parentPath?: string;
53
- /** Offset range in the rendered HTML this selection was taken from. */
54
- readonly start: number;
55
- readonly end: number;
56
- }
57
- /** A render of one fixture for an editor: the delivered content plus the identity of every element. */
58
- interface IrPreview {
59
- readonly subject: string;
60
- readonly preheader: string | undefined;
61
- /** Carries `INSTANCE_PATH_ATTRIBUTE` on every element. Preview-only. */
62
- readonly html: string;
63
- readonly text: string;
64
- /** Every rendered element in document order. */
65
- readonly selections: readonly EmailElementSelection[];
66
- }
67
- /**
68
- * Turn one render's positions into selections, in document order. `occurrence` and `occurrences`
69
- * count the rendered elements that share an authored origin and tag.
70
- */
71
- declare const emailSelections: (positions: readonly EmittedPosition[]) => readonly EmailElementSelection[];
72
- /**
73
- * Render one fixture with an instance path stamped on every element, and the selection each path
74
- * resolves to. The selections come from the spans the compiler recorded, so a click on the canvas
75
- * lands on the exact node of the source that produced it.
76
- */
77
- declare const renderIrPreview: (ir: TemplateIr, input: unknown, options?: Omit<RenderOptions, "positions">) => IrPreview;
78
- /** Look selections up by the instance path a rendered document carries. */
79
- declare const emailSelectionIndex: (selections: readonly EmailElementSelection[]) => ReadonlyMap<string, EmailElementSelection>;
80
- /**
81
- * The authoring element a selection edits. For an authored element that is the element itself; for
82
- * a generated wrapper it is the primitive that asked for it. Undefined only where the compiler
83
- * generated markup with no authoring behind it, which nothing can edit in place.
84
- */
85
- declare const emailAuthoringTarget: (selection: EmailElementSelection) => JsxSourceLocation | undefined;
86
- /** Root-first ancestry of a selection, itself last. */
87
- declare const emailSelectionAncestry: (index: ReadonlyMap<string, EmailElementSelection>, instancePath: string) => readonly EmailElementSelection[];
88
- /**
89
- * Every rendered instance produced by the same authored element, in document order. One entry
90
- * means it rendered once; several mean it repeated.
91
- */
92
- declare const emailSelectionSiblings: (selections: readonly EmailElementSelection[], selection: EmailElementSelection) => readonly EmailElementSelection[];
93
- /**
94
- * Every rendered instance of the same authored element. A partial edited at its definition changes
95
- * all of these, which is the scope a control has to name before it applies.
96
- */
97
- declare const emailDefinitionInstances: (selections: readonly EmailElementSelection[], selection: EmailElementSelection) => readonly EmailElementSelection[];
98
- //#endregion
99
- export { emailAuthoringTarget as a, emailSelectionIndex as c, renderIrPreview as d, IrPreview as i, emailSelectionSiblings as l, EmittedPosition as n, emailDefinitionInstances as o, INSTANCE_PATH_ATTRIBUTE as r, emailSelectionAncestry as s, EmailElementSelection as t, emailSelections as u };
100
- //# sourceMappingURL=preview-Ekdg1dXG.d.ts.map
package/dist/preview.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { a as emailAuthoringTarget, c as emailSelectionIndex, d as renderIrPreview, i as IrPreview, l as emailSelectionSiblings, n as EmittedPosition, o as emailDefinitionInstances, r as INSTANCE_PATH_ATTRIBUTE, s as emailSelectionAncestry, t as EmailElementSelection, u as emailSelections } from "./preview-Ekdg1dXG.js";
2
- export { EmailElementSelection, EmittedPosition, INSTANCE_PATH_ATTRIBUTE, IrPreview, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, renderIrPreview };
package/dist/preview.js DELETED
@@ -1,160 +0,0 @@
1
- import { renderIr } from "./render-ir.js";
2
- //#region src/preview.ts
3
- /**
4
- * The attribute a preview stamps so a click in a rendered document resolves to exactly one
5
- * rendered element. A delivered message never carries it.
6
- */
7
- const INSTANCE_PATH_ATTRIBUTE = "data-samva-instance";
8
- const locationKey = (origin) => `${origin.fileName}:${origin.lineNumber}:${origin.columnNumber}`;
9
- const originKey = (selection) => `${selection.tag}\u0000${selection.origins.map(locationKey).join("\0")}`;
10
- const parentOf = (instancePath) => {
11
- const cut = instancePath.lastIndexOf(".");
12
- return cut === -1 ? void 0 : instancePath.slice(0, cut);
13
- };
14
- /**
15
- * Turn one render's positions into selections, in document order. `occurrence` and `occurrences`
16
- * count the rendered elements that share an authored origin and tag.
17
- */
18
- const emailSelections = (positions) => {
19
- const counts = /* @__PURE__ */ new Map();
20
- for (const position of positions) {
21
- const key = originKey(position);
22
- counts.set(key, (counts.get(key) ?? 0) + 1);
23
- }
24
- const seen = /* @__PURE__ */ new Map();
25
- return [...positions].toSorted((left, right) => left.start === right.start ? right.end - left.end : left.start - right.start).map((position) => {
26
- const key = originKey(position);
27
- const occurrence = (seen.get(key) ?? 0) + 1;
28
- seen.set(key, occurrence);
29
- const parentPath = parentOf(position.instancePath);
30
- return {
31
- instancePath: position.instancePath,
32
- tag: position.tag,
33
- origins: position.origins,
34
- authored: position.authored,
35
- occurrence,
36
- occurrences: counts.get(key) ?? 1,
37
- ...parentPath === void 0 ? {} : { parentPath },
38
- start: position.start,
39
- end: position.end
40
- };
41
- });
42
- };
43
- /**
44
- * Render one fixture with an instance path stamped on every element, and the selection each path
45
- * resolves to. The selections come from the spans the compiler recorded, so a click on the canvas
46
- * lands on the exact node of the source that produced it.
47
- */
48
- const renderIrPreview = (ir, input, options = {}) => {
49
- const rendered = renderIr(ir, input, {
50
- ...options,
51
- positions: true
52
- });
53
- const sources = ir.sources ?? [];
54
- const ordered = (rendered.positions ?? []).map((position) => {
55
- const src = position.src;
56
- const origins = src === void 0 ? [] : [{
57
- fileName: sources[src[2] ?? 0] ?? "",
58
- lineNumber: src[0],
59
- columnNumber: src[1]
60
- }];
61
- return {
62
- start: position.start,
63
- end: position.end,
64
- tag: position.tag,
65
- src: src === void 0 ? void 0 : src.join(":"),
66
- origins,
67
- path: "",
68
- parent: void 0
69
- };
70
- }).toSorted((left, right) => left.start === right.start ? right.end - left.end : left.start - right.start);
71
- const open = [];
72
- const childCount = /* @__PURE__ */ new Map();
73
- for (const element of ordered) {
74
- while (open.length > 0 && open[open.length - 1].end <= element.start) open.pop();
75
- const parent = open[open.length - 1];
76
- const index = childCount.get(parent) ?? 0;
77
- childCount.set(parent, index + 1);
78
- element.parent = parent;
79
- element.path = parent === void 0 ? String(index) : `${parent.path}.${index}`;
80
- open.push(element);
81
- }
82
- const inserts = ordered.map((element) => ({
83
- at: element.start + 1 + element.tag.length,
84
- text: ` ${INSTANCE_PATH_ATTRIBUTE}="${element.path}"`
85
- }));
86
- inserts.sort((left, right) => left.at - right.at);
87
- let html = "";
88
- let cursor = 0;
89
- for (const insert of inserts) {
90
- html += rendered.html.slice(cursor, insert.at) + insert.text;
91
- cursor = insert.at;
92
- }
93
- html += rendered.html.slice(cursor);
94
- const shift = (offset) => {
95
- let moved = 0;
96
- for (const insert of inserts) {
97
- if (insert.at > offset) break;
98
- moved += insert.text.length;
99
- }
100
- return offset + moved;
101
- };
102
- const positions = ordered.map((element) => ({
103
- start: shift(element.start),
104
- end: shift(element.end),
105
- origins: element.origins,
106
- instancePath: element.path,
107
- tag: element.tag,
108
- authored: element.src !== void 0 && (element.parent === void 0 || element.parent.src !== element.src)
109
- }));
110
- const selections = emailSelections(positions);
111
- return {
112
- subject: rendered.subject,
113
- preheader: rendered.preheader,
114
- html,
115
- text: rendered.text,
116
- selections
117
- };
118
- };
119
- /** Look selections up by the instance path a rendered document carries. */
120
- const emailSelectionIndex = (selections) => new Map(selections.map((selection) => [selection.instancePath, selection]));
121
- /**
122
- * The authoring element a selection edits. For an authored element that is the element itself; for
123
- * a generated wrapper it is the primitive that asked for it. Undefined only where the compiler
124
- * generated markup with no authoring behind it, which nothing can edit in place.
125
- */
126
- const emailAuthoringTarget = (selection) => selection.origins[0];
127
- /** Root-first ancestry of a selection, itself last. */
128
- const emailSelectionAncestry = (index, instancePath) => {
129
- const chain = [];
130
- let current = index.get(instancePath);
131
- while (current !== void 0) {
132
- chain.unshift(current);
133
- current = current.parentPath === void 0 ? void 0 : index.get(current.parentPath);
134
- }
135
- return chain;
136
- };
137
- /**
138
- * Every rendered instance produced by the same authored element, in document order. One entry
139
- * means it rendered once; several mean it repeated.
140
- */
141
- const emailSelectionSiblings = (selections, selection) => {
142
- const key = originKey(selection);
143
- return selections.filter((candidate) => originKey(candidate) === key);
144
- };
145
- /**
146
- * Every rendered instance of the same authored element. A partial edited at its definition changes
147
- * all of these, which is the scope a control has to name before it applies.
148
- */
149
- const emailDefinitionInstances = (selections, selection) => {
150
- const authoring = selection.origins[0];
151
- const key = `${selection.tag}\u0000${authoring === void 0 ? "" : locationKey(authoring)}`;
152
- return selections.filter((candidate) => {
153
- const origin = candidate.origins[0];
154
- return `${candidate.tag}\u0000${origin === void 0 ? "" : locationKey(origin)}` === key;
155
- });
156
- };
157
- //#endregion
158
- export { INSTANCE_PATH_ATTRIBUTE, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, renderIrPreview };
159
-
160
- //# sourceMappingURL=preview.js.map
@@ -1,19 +0,0 @@
1
- import { E as TemplateIr, S as RenderedIrWhatsApp, b as RenderOptions, x as RenderedIrEmail } from "./ir-aaqNE987.js";
2
- //#region src/render-ir.d.ts
3
- interface IrRenderDiagnostic {
4
- readonly code: string;
5
- readonly message: string;
6
- }
7
- declare class IrRenderError extends Error {
8
- readonly diagnostics: readonly IrRenderDiagnostic[];
9
- constructor(diagnostics: readonly IrRenderDiagnostic[]);
10
- }
11
- /** Render the email channel of a compiled template against one validated input. */
12
- declare const renderIr: (ir: TemplateIr, input: unknown, options?: RenderOptions) => RenderedIrEmail;
13
- /** Render the SMS channel of a compiled template to plain text. */
14
- declare const renderIrSms: (ir: TemplateIr, input: unknown, options?: RenderOptions) => string;
15
- /** Render the WhatsApp channel of a compiled template: every text rendered, conditional buttons resolved. */
16
- declare const renderIrWhatsApp: (ir: TemplateIr, input: unknown, options?: RenderOptions) => RenderedIrWhatsApp;
17
- //#endregion
18
- export { IrRenderDiagnostic, IrRenderError, renderIr, renderIrSms, renderIrWhatsApp };
19
- //# sourceMappingURL=render-ir.d.ts.map