@samva/markup 0.8.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 (172) hide show
  1. package/AGENTS.md +107 -46
  2. package/CHANGELOG.md +345 -0
  3. package/README.md +188 -52
  4. package/dist/{brand-DcoVkh_S.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/channel-specs-C2feJwuP.d.ts +13 -0
  9. package/dist/compiler.d.ts +88 -115
  10. package/dist/compiler.js +750 -171
  11. package/dist/components-BZCqegS8.js +1864 -0
  12. package/dist/diagnostic-model-DJtqbETd.js +38 -0
  13. package/dist/{diagnostics-OcQKQYSY.d.ts → diagnostic-model-DxthUZBT.d.ts} +3 -21
  14. package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
  15. package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +4 -3
  16. package/dist/diagnostics.d.ts +410 -2
  17. package/dist/diagnostics.js +402 -52
  18. package/dist/edit.d.ts +234 -0
  19. package/dist/edit.js +947 -0
  20. package/dist/email/jsx-dev-runtime.d.ts +2 -2
  21. package/dist/email/jsx-dev-runtime.js +1 -2
  22. package/dist/email/jsx-runtime.d.ts +1 -1
  23. package/dist/email/jsx-runtime.js +1 -85
  24. package/dist/{email/components.d.ts → email.d.ts} +22 -11
  25. package/dist/email.js +2 -0
  26. package/dist/fmt.d.ts +32 -0
  27. package/dist/fmt.js +174 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +2 -0
  30. package/dist/{render-vAv_4r9v.js → ir-CLhlklKV.js} +96 -279
  31. package/dist/jsx-runtime-CBlexoeR.js +98 -0
  32. package/dist/{elements-BzjjnoCS.d.ts → jsx-runtime-ylIOnaSf.d.ts} +76 -76
  33. package/dist/profile-pWGtWZXF.js +3803 -0
  34. package/dist/render-BPonDpCl.d.ts +539 -0
  35. package/dist/render-BQmfh94k.js +257 -0
  36. package/dist/render.d.ts +35 -0
  37. package/dist/render.js +49 -0
  38. package/dist/sms.d.ts +16 -0
  39. package/dist/sms.js +12 -0
  40. package/dist/source-locations-C8wCsiAy.d.ts +23 -0
  41. package/dist/template-DMPwxMSq.d.ts +65 -0
  42. package/dist/template-zLUjcwfF.js +42 -0
  43. package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
  44. package/dist/whatsapp.d.ts +57 -0
  45. package/dist/whatsapp.js +22 -0
  46. package/generated/contract.json +1788 -0
  47. package/generated/reference.md +360 -0
  48. package/package.json +46 -239
  49. package/samva-brand.d.ts +4 -4
  50. package/skills/sml/SKILL.md +123 -0
  51. package/dist/ast-BrDtApwS.d.ts +0 -107
  52. package/dist/ast.d.ts +0 -2
  53. package/dist/ast.js +0 -124
  54. package/dist/candidate.d.ts +0 -29
  55. package/dist/candidate.js +0 -88
  56. package/dist/catalog-CKuOooB8.d.ts +0 -354
  57. package/dist/checks-D73Xizbw.js +0 -59366
  58. package/dist/checks.d.ts +0 -33
  59. package/dist/checks.js +0 -2
  60. package/dist/classes.d.ts +0 -26
  61. package/dist/classes.js +0 -184
  62. package/dist/compile-sms.d.ts +0 -28
  63. package/dist/compile-sms.js +0 -44
  64. package/dist/compile-whatsapp.d.ts +0 -56
  65. package/dist/compile-whatsapp.js +0 -186
  66. package/dist/compile.d.ts +0 -18
  67. package/dist/compile.js +0 -29
  68. package/dist/components.d.ts +0 -289
  69. package/dist/components.js +0 -106
  70. package/dist/conditionals.d.ts +0 -10
  71. package/dist/conditionals.js +0 -74
  72. package/dist/corpus-CPPfgAHN.d.ts +0 -106
  73. package/dist/css-CS2jLID6.d.ts +0 -109
  74. package/dist/email/assets.d.ts +0 -40
  75. package/dist/email/assets.js +0 -63
  76. package/dist/email/brand-footer.d.ts +0 -34
  77. package/dist/email/brand-footer.js +0 -62
  78. package/dist/email/brand.d.ts +0 -2
  79. package/dist/email/components.js +0 -240
  80. package/dist/email/diagnostics.d.ts +0 -2
  81. package/dist/email/elements.d.ts +0 -2
  82. package/dist/email/elements.js +0 -299
  83. package/dist/email/html.d.ts +0 -2
  84. package/dist/email/html.js +0 -278
  85. package/dist/email/render.d.ts +0 -50
  86. package/dist/email/render.js +0 -3
  87. package/dist/email/selection.d.ts +0 -2
  88. package/dist/email/selection.js +0 -91
  89. package/dist/email/source-edit.d.ts +0 -67
  90. package/dist/email/source-edit.js +0 -185
  91. package/dist/email/stylesheets.d.ts +0 -15
  92. package/dist/email/stylesheets.js +0 -48
  93. package/dist/email/text.d.ts +0 -7
  94. package/dist/email/text.js +0 -100
  95. package/dist/emit.d.ts +0 -51
  96. package/dist/emit.js +0 -151
  97. package/dist/html-Bl9BAdqc.d.ts +0 -42
  98. package/dist/interpolate.d.ts +0 -24
  99. package/dist/interpolate.js +0 -43
  100. package/dist/jsx-dev-runtime.d.ts +0 -11
  101. package/dist/jsx-dev-runtime.js +0 -15
  102. package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
  103. package/dist/jsx-runtime.d.ts +0 -2
  104. package/dist/jsx-runtime.js +0 -121
  105. package/dist/lexer.d.ts +0 -60
  106. package/dist/lexer.js +0 -281
  107. package/dist/model.d.ts +0 -24
  108. package/dist/model.js +0 -77
  109. package/dist/ops-BvwqHl7V.js +0 -630
  110. package/dist/ops.d.ts +0 -114
  111. package/dist/ops.js +0 -2
  112. package/dist/parser-t29cHLVL.d.ts +0 -396
  113. package/dist/parser.d.ts +0 -2
  114. package/dist/parser.js +0 -859
  115. package/dist/predicate-BI6uRRM-.js +0 -549
  116. package/dist/predicate-M-05Nd7R.d.ts +0 -56
  117. package/dist/predicate.d.ts +0 -2
  118. package/dist/predicate.js +0 -2
  119. package/dist/printer.d.ts +0 -6
  120. package/dist/printer.js +0 -122
  121. package/dist/registry-Dcp6QEK_.d.ts +0 -73
  122. package/dist/registry.d.ts +0 -2
  123. package/dist/registry.js +0 -646
  124. package/dist/render-template.d.ts +0 -45
  125. package/dist/render-template.js +0 -76
  126. package/dist/selection-CCArx9lU.d.ts +0 -91
  127. package/dist/showcase-egkusQBf.d.ts +0 -415
  128. package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
  129. package/dist/sms-segments.d.ts +0 -2
  130. package/dist/sms-segments.js +0 -46
  131. package/dist/source-locations-DrCM82Ym.d.ts +0 -67
  132. package/dist/source-locations.d.ts +0 -2
  133. package/dist/source-locations.js +0 -102
  134. package/dist/starters/category-mapping.d.ts +0 -13
  135. package/dist/starters/category-mapping.js +0 -49
  136. package/dist/starters/corpus.d.ts +0 -2
  137. package/dist/starters/corpus.js +0 -194
  138. package/dist/starters/library.d.ts +0 -18
  139. package/dist/starters/library.js +0 -692
  140. package/dist/starters/public-gallery.d.ts +0 -266
  141. package/dist/starters/public-gallery.js +0 -916
  142. package/dist/starters/public-handoff.d.ts +0 -164
  143. package/dist/starters/public-handoff.js +0 -361
  144. package/dist/starters/public-preview-artifacts.d.ts +0 -43
  145. package/dist/starters/public-preview-artifacts.js +0 -104
  146. package/dist/starters/public-preview.d.ts +0 -61
  147. package/dist/starters/public-preview.js +0 -83
  148. package/dist/starters/showcase.d.ts +0 -2
  149. package/dist/starters/showcase.js +0 -335
  150. package/dist/starters/sources.d.ts +0 -45
  151. package/dist/starters/sources.js +0 -7762
  152. package/dist/starters/theme.d.ts +0 -45
  153. package/dist/starters/theme.js +0 -77
  154. package/dist/starters.d.ts +0 -2
  155. package/dist/starters.js +0 -874
  156. package/dist/tailwind-BYq7Lo6u.js +0 -727
  157. package/dist/template-DWftqh4x.d.ts +0 -60
  158. package/dist/template.d.ts +0 -2
  159. package/dist/template.js +0 -37
  160. package/dist/theme-css.js +0 -2
  161. package/dist/tsx-source-instrumentation.d.ts +0 -30
  162. package/dist/tsx-source-instrumentation.js +0 -115
  163. package/dist/tsx-tracer.d.ts +0 -112
  164. package/dist/tsx-tracer.js +0 -985
  165. package/dist/variables-J_L3qxRa.d.ts +0 -77
  166. package/dist/variables.d.ts +0 -2
  167. package/dist/variables.js +0 -141
  168. package/dist/version-BITr58kk.js +0 -96
  169. package/generated/sml-agent-contract.json +0 -709
  170. package/generated/sml-email-agent-contract.json +0 -615
  171. package/generated/sml-email-language-reference.md +0 -94
  172. package/generated/sml-language-reference.md +0 -195
@@ -1,10 +1,95 @@
1
1
  import { n as isObject } from "./guards-eV1qLbf2.js";
2
- import { EmailNode, drainEmailDiagnostics } from "./email/jsx-runtime.js";
3
- import { declarationValue, escapeAttribute, kebab, serializeEmailHtml } from "./email/html.js";
4
- import { PREHEADER_ATTRIBUTE, preheaderNode } from "./email/components.js";
5
- import { EmailCompileError, hasBlockingDiagnostic } from "./email/diagnostics.js";
6
- import { snapshotStylesheets } from "./email/stylesheets.js";
7
- import { deriveEmailText } from "./email/text.js";
2
+ import { _ as kebab, h as escapeAttribute, m as declarationValue } from "./components-BZCqegS8.js";
3
+ import { t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
4
+ //#region src/email/font-stacks.ts
5
+ /** Generic families every email client understands as the last resort in a stack. */
6
+ const GENERIC_FAMILIES = /* @__PURE__ */ new Set([
7
+ "serif",
8
+ "sans-serif",
9
+ "monospace",
10
+ "cursive",
11
+ "fantasy"
12
+ ]);
13
+ /** One family name as written, without its quotes and with runs of spaces collapsed. */
14
+ const unquote = (value) => {
15
+ const trimmed = value.trim();
16
+ const quote = trimmed[0];
17
+ return (quote === "\"" || quote === "'") && trimmed.endsWith(quote) && trimmed.length >= 2 ? trimmed.slice(1, -1) : trimmed.replace(/\s+/g, " ");
18
+ };
19
+ /** The families of a `font-family` value, unquoted, in stack order. */
20
+ const fontStackFamilies = (value) => {
21
+ const families = [];
22
+ let start = 0;
23
+ let quote;
24
+ for (let index = 0; index < value.length; index++) {
25
+ const character = value[index];
26
+ if (quote !== void 0) {
27
+ if (character === quote) quote = void 0;
28
+ } else if (character === "'" || character === "\"") quote = character;
29
+ else if (character === ",") {
30
+ families.push(unquote(value.slice(start, index)));
31
+ start = index + 1;
32
+ }
33
+ }
34
+ families.push(unquote(value.slice(start)));
35
+ return families.filter((family) => family !== "");
36
+ };
37
+ const FONT_SIZE = /^(?:xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|larger|smaller|[+-]?(?:\d+\.?\d*|\.\d+)(?:[a-z]+|%)|(?:calc|clamp|min|max|var)\(.*\))$/i;
38
+ /** Whitespace-separated tokens at the top level, keeping parentheses and quotes whole. */
39
+ const shorthandTokens = (value) => {
40
+ const tokens = [];
41
+ let current = "";
42
+ let depth = 0;
43
+ let quote;
44
+ for (const character of value.trim()) {
45
+ if (quote !== void 0) {
46
+ if (character === quote) quote = void 0;
47
+ } else if (character === "'" || character === "\"") quote = character;
48
+ else if (character === "(") depth++;
49
+ else if (character === ")") depth--;
50
+ else if (/\s/.test(character) && depth === 0) {
51
+ if (current !== "") tokens.push(current);
52
+ current = "";
53
+ continue;
54
+ }
55
+ current += character;
56
+ }
57
+ if (current !== "") tokens.push(current);
58
+ return tokens;
59
+ };
60
+ /**
61
+ * The family list of a `font` shorthand: everything after the size (and its
62
+ * optional line height), or `undefined` for a system-font keyword that names
63
+ * no family.
64
+ */
65
+ const fontShorthandFamilies = (value) => {
66
+ const tokens = shorthandTokens(value);
67
+ const size = tokens.findIndex((token) => FONT_SIZE.test(token.replace(/\/.*$/, "")));
68
+ if (size < 0) return void 0;
69
+ let next = size + 1;
70
+ const sizeToken = tokens[size];
71
+ if (sizeToken.endsWith("/")) next += 1;
72
+ else if (!sizeToken.includes("/") && tokens[next]?.startsWith("/")) next += tokens[next] === "/" ? 2 : 1;
73
+ const family = tokens.slice(next).join(" ");
74
+ return family === "" ? void 0 : family;
75
+ };
76
+ /**
77
+ * True when a stack names a declared project family without ending in a
78
+ * generic. `declared` holds lowercased family names. A quoted `"sans-serif"`
79
+ * names a font called sans-serif, not the generic, so it does not count.
80
+ */
81
+ const lacksGenericFallback = (value, declared) => {
82
+ const stack = value.replace(/\s*!important\s*$/i, "");
83
+ if (!fontStackFamilies(stack).some((family) => declared.has(family.toLowerCase()))) return false;
84
+ const last = stack.slice(stack.lastIndexOf(",") + 1).trim();
85
+ return !GENERIC_FAMILIES.has(last.toLowerCase());
86
+ };
87
+ const fontFallbackDiagnostic = (value) => ({
88
+ code: "email-font-fallback",
89
+ severity: "error",
90
+ message: `font-family ${JSON.stringify(value)} uses a project font without a generic fallback. Clients that drop webfonts (Gmail, classic Outlook) render this stack as written, so end it with sans-serif, serif or monospace.`
91
+ });
92
+ //#endregion
8
93
  //#region src/email/css-values.ts
9
94
  const MAX_RESOLVED_VALUE_LENGTH = 65536;
10
95
  const MAX_RESOLUTION_WORK = 262144;
@@ -192,95 +277,6 @@ const renderHeadCss = (rules, headAtRules, variables) => {
192
277
  return blocks.join("");
193
278
  };
194
279
  //#endregion
195
- //#region src/email/font-stacks.ts
196
- /** Generic families every email client understands as the last resort in a stack. */
197
- const GENERIC_FAMILIES = /* @__PURE__ */ new Set([
198
- "serif",
199
- "sans-serif",
200
- "monospace",
201
- "cursive",
202
- "fantasy"
203
- ]);
204
- /** One family name as written, without its quotes and with runs of spaces collapsed. */
205
- const unquote = (value) => {
206
- const trimmed = value.trim();
207
- const quote = trimmed[0];
208
- return (quote === "\"" || quote === "'") && trimmed.endsWith(quote) && trimmed.length >= 2 ? trimmed.slice(1, -1) : trimmed.replace(/\s+/g, " ");
209
- };
210
- /** The families of a `font-family` value, unquoted, in stack order. */
211
- const fontStackFamilies = (value) => {
212
- const families = [];
213
- let start = 0;
214
- let quote;
215
- for (let index = 0; index < value.length; index++) {
216
- const character = value[index];
217
- if (quote !== void 0) {
218
- if (character === quote) quote = void 0;
219
- } else if (character === "'" || character === "\"") quote = character;
220
- else if (character === ",") {
221
- families.push(unquote(value.slice(start, index)));
222
- start = index + 1;
223
- }
224
- }
225
- families.push(unquote(value.slice(start)));
226
- return families.filter((family) => family !== "");
227
- };
228
- const FONT_SIZE = /^(?:xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|larger|smaller|[+-]?(?:\d+\.?\d*|\.\d+)(?:[a-z]+|%)|(?:calc|clamp|min|max|var)\(.*\))$/i;
229
- /** Whitespace-separated tokens at the top level, keeping parentheses and quotes whole. */
230
- const shorthandTokens = (value) => {
231
- const tokens = [];
232
- let current = "";
233
- let depth = 0;
234
- let quote;
235
- for (const character of value.trim()) {
236
- if (quote !== void 0) {
237
- if (character === quote) quote = void 0;
238
- } else if (character === "'" || character === "\"") quote = character;
239
- else if (character === "(") depth++;
240
- else if (character === ")") depth--;
241
- else if (/\s/.test(character) && depth === 0) {
242
- if (current !== "") tokens.push(current);
243
- current = "";
244
- continue;
245
- }
246
- current += character;
247
- }
248
- if (current !== "") tokens.push(current);
249
- return tokens;
250
- };
251
- /**
252
- * The family list of a `font` shorthand: everything after the size (and its
253
- * optional line height), or `undefined` for a system-font keyword that names
254
- * no family.
255
- */
256
- const fontShorthandFamilies = (value) => {
257
- const tokens = shorthandTokens(value);
258
- const size = tokens.findIndex((token) => FONT_SIZE.test(token.replace(/\/.*$/, "")));
259
- if (size < 0) return void 0;
260
- let next = size + 1;
261
- const sizeToken = tokens[size];
262
- if (sizeToken.endsWith("/")) next += 1;
263
- else if (!sizeToken.includes("/") && tokens[next]?.startsWith("/")) next += tokens[next] === "/" ? 2 : 1;
264
- const family = tokens.slice(next).join(" ");
265
- return family === "" ? void 0 : family;
266
- };
267
- /**
268
- * True when a stack names a declared project family without ending in a
269
- * generic. `declared` holds lowercased family names. A quoted `"sans-serif"`
270
- * names a font called sans-serif, not the generic, so it does not count.
271
- */
272
- const lacksGenericFallback = (value, declared) => {
273
- const stack = value.replace(/\s*!important\s*$/i, "");
274
- if (!fontStackFamilies(stack).some((family) => declared.has(family.toLowerCase()))) return false;
275
- const last = stack.slice(stack.lastIndexOf(",") + 1).trim();
276
- return !GENERIC_FAMILIES.has(last.toLowerCase());
277
- };
278
- const fontFallbackDiagnostic = (value) => ({
279
- code: "email-font-fallback",
280
- severity: "error",
281
- message: `font-family ${JSON.stringify(value)} uses a project font without a generic fallback. Clients that drop webfonts (Gmail, classic Outlook) render this stack as written, so end it with sans-serif, serif or monospace.`
282
- });
283
- //#endregion
284
280
  //#region src/email/selectors.ts
285
281
  const classListOf = (element) => {
286
282
  const value = element.props.class ?? element.props.className;
@@ -578,189 +574,10 @@ const applyStylesheet = (root, sheet, options = {}) => {
578
574
  };
579
575
  };
580
576
  //#endregion
581
- //#region src/email/render.ts
582
- /** Classic Outlook lays a document out correctly only under a transitional doctype. */
583
- const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
584
- const settle = (diagnostics) => {
585
- if (hasBlockingDiagnostic(diagnostics)) throw new EmailCompileError({ diagnostics });
586
- return diagnostics;
587
- };
588
- /** Lower the derived tree to HTML and its plain-text alternative. */
589
- const compileEmail = (node, options = {}) => {
590
- const serialized = serializeEmailHtml(node, options);
591
- const diagnostics = settle([...drainEmailDiagnostics(), ...serialized.diagnostics]);
592
- return {
593
- html: serialized.html,
594
- text: deriveEmailText(node),
595
- diagnostics,
596
- positions: serialized.positions
597
- };
598
- };
599
- /** The preview text already present in the tree, from `<Email preheader>`. */
600
- const declaredPreheader = (node) => {
601
- switch (node.type) {
602
- case "Text":
603
- case "Raw": return;
604
- case "Fragment": return node.children.reduce((found, child) => found ?? declaredPreheader(child), void 0);
605
- case "Element": {
606
- const declared = node.props[PREHEADER_ATTRIBUTE];
607
- if (typeof declared === "string") return declared;
608
- return node.children.reduce((found, child) => found ?? declaredPreheader(child), void 0);
609
- }
610
- }
611
- };
612
- /** Put the hidden preview block first inside `<body>`, or first overall when there is no shell. */
613
- const withPreheader = (node, text) => {
614
- const insert = (current) => {
615
- if (current.type === "Fragment") {
616
- for (const [index, child] of current.children.entries()) {
617
- const replaced = insert(child);
618
- if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
619
- }
620
- return;
621
- }
622
- if (current.type !== "Element") return void 0;
623
- if (current.tag === "body") return EmailNode.Element({
624
- ...current,
625
- children: [preheaderNode(text), ...current.children]
626
- });
627
- for (const [index, child] of current.children.entries()) {
628
- const replaced = insert(child);
629
- if (replaced !== void 0) return EmailNode.Element({
630
- ...current,
631
- children: current.children.with(index, replaced)
632
- });
633
- }
634
- };
635
- return insert(node) ?? EmailNode.Fragment({ children: [preheaderNode(text), node] });
636
- };
637
- const headStyle = (css, origins) => EmailNode.Element({
638
- tag: "style",
639
- props: {},
640
- children: [EmailNode.Text({ value: css })],
641
- origins,
642
- authored: false
643
- });
644
- /**
645
- * Put the retained rules in a `<style>` at the end of `<head>`, and project
646
- * `@font-face` rules in a sibling classic Outlook cannot see. Outlook for
647
- * Windows registers a face it cannot load and then renders the family in Times
648
- * New Roman, ignoring the stack; hidden, the family is merely missing and the
649
- * stack's fallback applies.
650
- */
651
- const withHeadCss = (node, css, fontFaceCss) => {
652
- const insert = (current) => {
653
- if (current.type === "Fragment") {
654
- for (const [index, child] of current.children.entries()) {
655
- const replaced = insert(child);
656
- if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
657
- }
658
- return;
659
- }
660
- if (current.type !== "Element") return void 0;
661
- if (current.tag === "head") return EmailNode.Element({
662
- ...current,
663
- children: [
664
- ...current.children,
665
- ...css === "" ? [] : [headStyle(css, current.origins)],
666
- ...fontFaceCss === "" ? [] : [
667
- EmailNode.Raw({
668
- html: "<!--[if !mso]><!-->",
669
- text: "",
670
- origins: []
671
- }),
672
- headStyle(fontFaceCss, current.origins),
673
- EmailNode.Raw({
674
- html: "<!--<![endif]-->",
675
- text: "",
676
- origins: []
677
- })
678
- ]
679
- ]
680
- });
681
- for (const [index, child] of current.children.entries()) {
682
- const replaced = insert(child);
683
- if (replaced !== void 0) return EmailNode.Element({
684
- ...current,
685
- children: current.children.with(index, replaced)
686
- });
687
- }
688
- };
689
- return insert(node);
690
- };
691
- /** Render one validated input through the template's only content function. Host isolation is required for untrusted source. */
692
- const renderEmail = (template, data, options = {}) => renderEmailWith(snapshotStylesheets(), template, data, options);
693
- /**
694
- * A render bound to the sheets registered so far. A compiled project's wrapper
695
- * calls this once its own stylesheet imports have run, so a later project
696
- * loaded into the same process cannot restyle an entry that is rendered again.
697
- */
698
- const bindStylesheets = (stylesheet = snapshotStylesheets()) => (template, data, options = {}) => renderEmailWith(stylesheet, template, data, options);
699
- const renderEmailWith = (stylesheet, template, data, options) => {
700
- if (!template.schema.validate(data)) throw new TypeError(`Invalid template input: ${JSON.stringify(template.schema.validate.errors)}`);
701
- return renderEmailContent(stylesheet, () => template.render(data), options);
702
- };
703
- /**
704
- * Render authored content against a stylesheet: inline what a client honors,
705
- * keep the rest for `<head>`, and lower to HTML and text. `renderEmail` runs a
706
- * validated template through it; a host that composes content without a
707
- * template definition calls it directly.
708
- */
709
- const renderEmailContent = (stylesheet, render, options = {}) => {
710
- drainEmailDiagnostics();
711
- const content = render();
712
- const invalid = [];
713
- const fail = (code, message) => invalid.push({
714
- code,
715
- severity: "error",
716
- message,
717
- origins: []
718
- });
719
- if (typeof content.subject !== "string" || /[\r\n\u0000]/.test(content.subject)) fail("invalid-subject", "Invalid email subject: it must be one line of text.");
720
- if (content.preheader !== void 0 && typeof content.preheader !== "string") fail("invalid-preheader", "Invalid email preheader: it must be a string.");
721
- if (content.text !== void 0 && typeof content.text !== "string") fail("invalid-text", "Invalid plain text: it must be a string.");
722
- const declared = declaredPreheader(content.body);
723
- if (content.preheader !== void 0 && declared !== void 0) fail("duplicate-preheader", "Preheader is set on both the template content and <Email preheader>; keep one.");
724
- settle(invalid);
725
- const base = content.preheader === void 0 ? content.body : withPreheader(content.body, content.preheader);
726
- const styled = stylesheet === void 0 ? {
727
- tree: base,
728
- headCss: "",
729
- fontFaceCss: "",
730
- diagnostics: []
731
- } : applyStylesheet(base, stylesheet);
732
- const style = [...styled.diagnostics];
733
- let tree = styled.tree;
734
- if (styled.headCss !== "" || styled.fontFaceCss !== "") {
735
- const placed = withHeadCss(tree, styled.headCss, styled.fontFaceCss);
736
- if (placed === void 0) style.push({
737
- code: "missing-head",
738
- severity: "error",
739
- message: "Styles that cannot be inlined — media queries, dark-scheme rules and pseudo-selectors — need a <head> to live in. Wrap the message in <Email>, or write those declarations as inline styles.",
740
- origins: []
741
- });
742
- else tree = placed;
743
- }
744
- settle(style);
745
- const compiled = compileEmail(tree, options);
746
- const prefix = compiled.html.startsWith("<html") ? EMAIL_DOCTYPE : "";
747
- const html = `${prefix}${compiled.html}`;
748
- const positions = prefix === "" ? compiled.positions : compiled.positions.map((position) => ({
749
- ...position,
750
- start: position.start + prefix.length,
751
- end: position.end + prefix.length
752
- }));
753
- return {
754
- subject: content.subject,
755
- preheader: content.preheader ?? declared,
756
- html,
757
- text: content.text ?? compiled.text,
758
- tree,
759
- diagnostics: [...style, ...compiled.diagnostics],
760
- positions
761
- };
762
- };
577
+ //#region src/ir.ts
578
+ /** The IR version this package writes. A publication pins the version it was built with. */
579
+ const SML_IR_VERSION = 1;
763
580
  //#endregion
764
- export { renderEmailContent as a, matchesSelector as c, finalizeValue as d, foldCalc as f, renderEmail as i, unquote as l, resolveVariables as m, bindStylesheets as n, applyStylesheet as o, renderHeadCss as p, compileEmail as r, classListOf as s, EMAIL_DOCTYPE as t, downlevelMediaQuery as u };
581
+ export { downlevelMediaQuery as a, renderHeadCss as c, matchesSelector as i, resolveVariables as l, applyStylesheet as n, finalizeValue as o, classListOf as r, foldCalc as s, SML_IR_VERSION as t, unquote as u };
765
582
 
766
- //# sourceMappingURL=render-vAv_4r9v.js.map
583
+ //# sourceMappingURL=ir-CLhlklKV.js.map
@@ -0,0 +1,98 @@
1
+ import { t as hasProperty } from "./guards-eV1qLbf2.js";
2
+ //#region src/source-locations.ts
3
+ /** The JSX prop that carries a {@link JsxSource} to the email JSX runtime. */
4
+ const JSX_SOURCE_LOCATION_PROP = "__samva_source_location";
5
+ /** Normalize the optional payload a JSX transform attaches. */
6
+ const completeJsxSourceLocation = (source) => {
7
+ if (source?.fileName === void 0 || source.lineNumber === void 0 || source.columnNumber === void 0) return;
8
+ return Object.freeze({
9
+ fileName: source.fileName,
10
+ lineNumber: source.lineNumber,
11
+ columnNumber: source.columnNumber
12
+ });
13
+ };
14
+ //#endregion
15
+ //#region src/email/jsx-runtime.ts
16
+ /** Constructors for the authoring tree. The tree is data; nothing here validates it. */
17
+ const EmailNode = {
18
+ Text: (fields) => ({
19
+ type: "Text",
20
+ ...fields
21
+ }),
22
+ Element: (fields) => ({
23
+ type: "Element",
24
+ ...fields
25
+ }),
26
+ Fragment: (fields) => ({
27
+ type: "Fragment",
28
+ ...fields
29
+ }),
30
+ Raw: (fields) => ({
31
+ type: "Raw",
32
+ ...fields
33
+ })
34
+ };
35
+ const EMAIL_NODE_TYPES = /* @__PURE__ */ new Set([
36
+ "Text",
37
+ "Element",
38
+ "Fragment",
39
+ "Raw"
40
+ ]);
41
+ /** True for a node this runtime built; anything else is not a child it can place. */
42
+ const isEmailNode = (input) => hasProperty(input, "type") && typeof input.type === "string" && EMAIL_NODE_TYPES.has(input.type);
43
+ const Fragment = Symbol.for("@samva/markup/email/Fragment");
44
+ const callSites = [];
45
+ /** Call sites enclosing the element being built, innermost first. */
46
+ const currentEmailOrigins = () => [...callSites].reverse();
47
+ const reported = [];
48
+ /** Record a finding from inside a compiler primitive, located at the authoring call site. */
49
+ const reportEmailDiagnostic = (diagnostic) => {
50
+ reported.push({
51
+ ...diagnostic,
52
+ origins: currentEmailOrigins()
53
+ });
54
+ };
55
+ /** Take and clear the findings primitives reported during a render. */
56
+ const drainEmailDiagnostics = () => reported.splice(0);
57
+ /** Normalize actual values without interpolation or recording proxies. */
58
+ const normalizeChildren = (input) => {
59
+ if (input === null || input === void 0 || typeof input === "boolean") return [];
60
+ if (typeof input === "string") return [EmailNode.Text({ value: input })];
61
+ if (typeof input === "number" && Number.isFinite(input)) return [EmailNode.Text({ value: String(input) })];
62
+ if (Array.isArray(input)) return input.flatMap(normalizeChildren);
63
+ if (isEmailNode(input)) return [input];
64
+ throw new TypeError("Email children must be synchronous text, finite numbers, elements, or arrays");
65
+ };
66
+ /** Compatibility markup emitted by a compiler primitive, with the text it stands for. */
67
+ const rawMarkup = (html, text = "") => EmailNode.Raw({
68
+ html,
69
+ text,
70
+ origins: currentEmailOrigins()
71
+ });
72
+ /** Automatic JSX factory for ordinary HTML and synchronous imported components. */
73
+ const jsx = (type, props) => {
74
+ const { children, [JSX_SOURCE_LOCATION_PROP]: source, ...attributes } = props ?? {};
75
+ const origin = completeJsxSourceLocation(source);
76
+ if (type === Fragment) return EmailNode.Fragment({ children: normalizeChildren(children) });
77
+ if (typeof type === "string") return EmailNode.Element({
78
+ tag: type,
79
+ props: attributes,
80
+ children: normalizeChildren(children),
81
+ origins: origin === void 0 ? currentEmailOrigins() : [origin, ...currentEmailOrigins()],
82
+ authored: origin !== void 0
83
+ });
84
+ if (origin !== void 0) callSites.push(origin);
85
+ try {
86
+ return EmailNode.Fragment({ children: normalizeChildren(type({
87
+ ...attributes,
88
+ children
89
+ })) });
90
+ } finally {
91
+ if (origin !== void 0) callSites.pop();
92
+ }
93
+ };
94
+ const jsxs = jsx;
95
+ //#endregion
96
+ export { jsx as a, rawMarkup as c, completeJsxSourceLocation as d, drainEmailDiagnostics as i, reportEmailDiagnostic as l, Fragment as n, jsxs as o, currentEmailOrigins as r, normalizeChildren as s, EmailNode as t, JSX_SOURCE_LOCATION_PROP as u };
97
+
98
+ //# sourceMappingURL=jsx-runtime-CBlexoeR.js.map
@@ -1,77 +1,5 @@
1
- import { i as JsxSourceLocation } from "./source-locations-DrCM82Ym.js";
2
- import { r as EmailDiagnostic } from "./diagnostics-BMYtBCQk.js";
3
- //#region src/email/jsx-runtime.d.ts
4
- /** Derived authoring tree; source stays canonical. Origins run from inner element to component call sites. */
5
- type EmailNode = {
6
- readonly type: "Text";
7
- readonly value: string;
8
- } | {
9
- readonly type: "Element";
10
- readonly tag: string;
11
- readonly props: Readonly<Record<string, unknown>>;
12
- readonly children: readonly EmailNode[];
13
- readonly origins: readonly JsxSourceLocation[];
14
- /**
15
- * True when this element is written at `origins[0]`; false when a compiler
16
- * primitive generated it and `origins[0]` is the call site that asked for
17
- * it. Both point at the same authoring target, but only an authored element
18
- * can have its own props edited there.
19
- */
20
- readonly authored: boolean;
21
- } | {
22
- readonly type: "Fragment";
23
- readonly children: readonly EmailNode[];
24
- } |
25
- /**
26
- * Compatibility markup a compiler primitive emits verbatim — conditional
27
- * comments and VML. Only the primitives in `./components` construct it;
28
- * nothing an author passes as a string reaches this node.
29
- */
30
- {
31
- readonly type: "Raw";
32
- readonly html: string;
33
- readonly text: string;
34
- readonly origins: readonly JsxSourceLocation[];
35
- };
36
- type EmailNodeOf<Type extends EmailNode["type"]> = Extract<EmailNode, {
37
- readonly type: Type;
38
- }>;
39
- type EmailNodeFields<Type extends EmailNode["type"]> = Omit<EmailNodeOf<Type>, "type">;
40
- /** Constructors for the authoring tree. The tree is data; nothing here validates it. */
41
- declare const EmailNode: {
42
- readonly Text: (fields: EmailNodeFields<"Text">) => EmailNodeOf<"Text">;
43
- readonly Element: (fields: EmailNodeFields<"Element">) => EmailNodeOf<"Element">;
44
- readonly Fragment: (fields: EmailNodeFields<"Fragment">) => EmailNodeOf<"Fragment">;
45
- readonly Raw: (fields: EmailNodeFields<"Raw">) => EmailNodeOf<"Raw">;
46
- };
47
- type EmailChild = EmailNode | string | number | boolean | null | undefined | readonly EmailChild[];
48
- type EmailComponent<P = never> = (props: P) => EmailChild;
49
- declare const Fragment: unique symbol;
50
- /** Call sites enclosing the element being built, innermost first. */
51
- declare const currentEmailOrigins: () => readonly JsxSourceLocation[];
52
- /** Record a finding from inside a compiler primitive, located at the authoring call site. */
53
- declare const reportEmailDiagnostic: (diagnostic: Omit<EmailDiagnostic, "origins">) => void;
54
- /** Take and clear the findings primitives reported during a render. */
55
- declare const drainEmailDiagnostics: () => readonly EmailDiagnostic[];
56
- /** Normalize actual values without interpolation or recording proxies. */
57
- declare const normalizeChildren: (input: unknown) => EmailNode[];
58
- /** Compatibility markup emitted by a compiler primitive, with the text it stands for. */
59
- declare const rawMarkup: (html: string, text?: string) => EmailNode;
60
- /** Automatic JSX factory for ordinary HTML and synchronous imported components. */
61
- declare const jsx: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null) => EmailNode;
62
- declare const jsxs: typeof jsx;
63
- declare namespace JSX {
64
- type Element = EmailNode;
65
- type ElementType = string | EmailComponent | typeof Fragment;
66
- interface ElementChildrenAttribute {
67
- readonly children: object;
68
- }
69
- interface IntrinsicAttributes {
70
- readonly key?: string | number | undefined;
71
- }
72
- interface IntrinsicElements extends EmailIntrinsicElements {}
73
- }
74
- //#endregion
1
+ import { r as JsxSourceLocation } from "./source-locations-C8wCsiAy.js";
2
+ import { r as EmailDiagnostic } from "./diagnostics-B-Gym34R.js";
75
3
  //#region src/email/elements.d.ts
76
4
  /** How one attribute is spelled and what values it accepts. */
77
5
  interface EmailAttributeSpec {
@@ -695,5 +623,77 @@ type ChildrenProp<Content extends EmailElementSpec["content"]> = Content extends
695
623
  /** Props each supported tag accepts, derived from `EMAIL_ELEMENTS`. */
696
624
  type EmailIntrinsicElements = { readonly [Tag in EmailTag]: EmailGlobalProps & AttributeProps<typeof EMAIL_GLOBAL_ATTRIBUTES> & AttributeProps<(typeof EMAIL_ELEMENTS)[Tag]["attributes"]> & ChildrenProp<(typeof EMAIL_ELEMENTS)[Tag]["content"]>; };
697
625
  //#endregion
698
- export { reportEmailDiagnostic as C, rawMarkup as S, currentEmailOrigins as _, EmailGlobalProps as a, jsxs as b, EmailStyle as c, isUrlAttribute as d, EmailChild as f, JSX as g, Fragment as h, EmailElementSpec as i, EmailTag as l, EmailNode as m, EMAIL_GLOBAL_ATTRIBUTES as n, EmailIntrinsicElements as o, EmailComponent as p, EmailAttributeSpec as r, EmailLayout as s, EMAIL_ELEMENTS as t, emailElement as u, drainEmailDiagnostics as v, normalizeChildren as x, jsx as y };
699
- //# sourceMappingURL=elements-BzjjnoCS.d.ts.map
626
+ //#region src/email/jsx-runtime.d.ts
627
+ /** Derived authoring tree; source stays canonical. Origins run from inner element to component call sites. */
628
+ type EmailNode = {
629
+ readonly type: "Text";
630
+ readonly value: string;
631
+ } | {
632
+ readonly type: "Element";
633
+ readonly tag: string;
634
+ readonly props: Readonly<Record<string, unknown>>;
635
+ readonly children: readonly EmailNode[];
636
+ readonly origins: readonly JsxSourceLocation[];
637
+ /**
638
+ * True when this element is written at `origins[0]`; false when a compiler
639
+ * primitive generated it and `origins[0]` is the call site that asked for
640
+ * it. Both point at the same authoring target, but only an authored element
641
+ * can have its own props edited there.
642
+ */
643
+ readonly authored: boolean;
644
+ } | {
645
+ readonly type: "Fragment";
646
+ readonly children: readonly EmailNode[];
647
+ } |
648
+ /**
649
+ * Compatibility markup a compiler primitive emits verbatim — conditional
650
+ * comments and VML. Only the primitives in `./components` construct it;
651
+ * nothing an author passes as a string reaches this node.
652
+ */
653
+ {
654
+ readonly type: "Raw";
655
+ readonly html: string;
656
+ readonly text: string;
657
+ readonly origins: readonly JsxSourceLocation[];
658
+ };
659
+ type EmailNodeOf<Type extends EmailNode["type"]> = Extract<EmailNode, {
660
+ readonly type: Type;
661
+ }>;
662
+ type EmailNodeFields<Type extends EmailNode["type"]> = Omit<EmailNodeOf<Type>, "type">;
663
+ /** Constructors for the authoring tree. The tree is data; nothing here validates it. */
664
+ declare const EmailNode: {
665
+ readonly Text: (fields: EmailNodeFields<"Text">) => EmailNodeOf<"Text">;
666
+ readonly Element: (fields: EmailNodeFields<"Element">) => EmailNodeOf<"Element">;
667
+ readonly Fragment: (fields: EmailNodeFields<"Fragment">) => EmailNodeOf<"Fragment">;
668
+ readonly Raw: (fields: EmailNodeFields<"Raw">) => EmailNodeOf<"Raw">;
669
+ };
670
+ type EmailChild = EmailNode | string | number | boolean | null | undefined | readonly EmailChild[];
671
+ type EmailComponent<P = never> = (props: P) => EmailChild;
672
+ declare const Fragment: unique symbol;
673
+ /** Call sites enclosing the element being built, innermost first. */
674
+ declare const currentEmailOrigins: () => readonly JsxSourceLocation[];
675
+ /** Record a finding from inside a compiler primitive, located at the authoring call site. */
676
+ declare const reportEmailDiagnostic: (diagnostic: Omit<EmailDiagnostic, "origins">) => void;
677
+ /** Take and clear the findings primitives reported during a render. */
678
+ declare const drainEmailDiagnostics: () => readonly EmailDiagnostic[];
679
+ /** Normalize actual values without interpolation or recording proxies. */
680
+ declare const normalizeChildren: (input: unknown) => EmailNode[];
681
+ /** Compatibility markup emitted by a compiler primitive, with the text it stands for. */
682
+ declare const rawMarkup: (html: string, text?: string) => EmailNode;
683
+ /** Automatic JSX factory for ordinary HTML and synchronous imported components. */
684
+ declare const jsx: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null) => EmailNode;
685
+ declare const jsxs: typeof jsx;
686
+ declare namespace JSX {
687
+ type Element = EmailNode;
688
+ type ElementType = string | EmailComponent | typeof Fragment;
689
+ interface ElementChildrenAttribute {
690
+ readonly children: object;
691
+ }
692
+ interface IntrinsicAttributes {
693
+ readonly key?: string | number | undefined;
694
+ }
695
+ interface IntrinsicElements extends EmailIntrinsicElements {}
696
+ }
697
+ //#endregion
698
+ export { isUrlAttribute as C, emailElement as S, EmailGlobalProps as _, JSX as a, EmailStyle as b, jsx as c, rawMarkup as d, reportEmailDiagnostic as f, EmailElementSpec as g, EmailAttributeSpec as h, Fragment as i, jsxs as l, EMAIL_GLOBAL_ATTRIBUTES as m, EmailComponent as n, currentEmailOrigins as o, EMAIL_ELEMENTS as p, EmailNode as r, drainEmailDiagnostics as s, EmailChild as t, normalizeChildren as u, EmailIntrinsicElements as v, EmailTag as x, EmailLayout as y };
699
+ //# sourceMappingURL=jsx-runtime-ylIOnaSf.d.ts.map