@samva/markup 0.7.0 → 0.9.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 (176) hide show
  1. package/AGENTS.md +104 -37
  2. package/README.md +188 -52
  3. package/dist/assets-C5duwTya.d.ts +40 -0
  4. package/dist/brand-B-0bN_Ir.d.ts +88 -0
  5. package/dist/{render-aaJBnsXK.js → cascade-t6kxlgEI.js} +130 -160
  6. package/dist/channel-edit.d.ts +121 -0
  7. package/dist/channel-edit.js +609 -0
  8. package/dist/channel-specs-B6M_HlaV.js +29 -0
  9. package/dist/channel-specs-C2feJwuP.d.ts +13 -0
  10. package/dist/compatibility-DbISoFIq.js +589 -0
  11. package/dist/compiler.d.ts +19 -249
  12. package/dist/compiler.js +10 -1408
  13. package/dist/{css-COcFOT1y.d.ts → css-BVQKICKC.d.ts} +30 -4
  14. package/dist/diagnostic-codes.d.ts +403 -0
  15. package/dist/diagnostic-codes.js +399 -0
  16. package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
  17. package/dist/diagnostics.d.ts +31 -2
  18. package/dist/diagnostics.js +1 -19
  19. package/dist/{elements-BzjjnoCS.d.ts → elements-cqldpaJt.d.ts} +3 -3
  20. package/dist/email/assets.d.ts +2 -0
  21. package/dist/email/assets.js +63 -0
  22. package/dist/email/brand-footer.d.ts +34 -0
  23. package/dist/email/brand-footer.js +63 -0
  24. package/dist/email/brand.d.ts +2 -0
  25. package/dist/email/brand.js +148 -0
  26. package/dist/email/components.d.ts +21 -10
  27. package/dist/email/components.js +46 -11
  28. package/dist/email/diagnostics.d.ts +2 -2
  29. package/dist/email/diagnostics.js +2 -1
  30. package/dist/email/elements.d.ts +1 -1
  31. package/dist/email/html.d.ts +2 -42
  32. package/dist/email/html.js +56 -2
  33. package/dist/email/jsx-dev-runtime.d.ts +2 -2
  34. package/dist/email/jsx-runtime.d.ts +1 -1
  35. package/dist/email/render.d.ts +10 -13
  36. package/dist/email/render.js +163 -6
  37. package/dist/email/text.d.ts +1 -1
  38. package/dist/fmt.d.ts +32 -0
  39. package/dist/fmt.js +174 -0
  40. package/dist/html-BJepOwZ4.d.ts +56 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +2 -0
  43. package/dist/ir-aaqNE987.d.ts +252 -0
  44. package/dist/ir.d.ts +2 -0
  45. package/dist/ir.js +7 -0
  46. package/dist/preview-Ekdg1dXG.d.ts +100 -0
  47. package/dist/preview.d.ts +2 -0
  48. package/dist/preview.js +160 -0
  49. package/dist/profile-BH-OtdDA.js +3670 -0
  50. package/dist/render-ir.d.ts +19 -0
  51. package/dist/render-ir.js +826 -0
  52. package/dist/sms-segments.d.ts +13 -2
  53. package/dist/sms.d.ts +16 -0
  54. package/dist/sms.js +12 -0
  55. package/dist/{email/source-edit.d.ts → source-edit.d.ts} +55 -6
  56. package/dist/source-edit.js +343 -0
  57. package/dist/source-locations-C8wCsiAy.d.ts +23 -0
  58. package/dist/source-locations.d.ts +2 -2
  59. package/dist/source-locations.js +3 -89
  60. package/dist/static.d.ts +57 -0
  61. package/dist/static.js +69 -0
  62. package/dist/tailwind-CMYpZf1v.js +614 -0
  63. package/dist/template-_QE_rQND.d.ts +65 -0
  64. package/dist/template.d.ts +2 -2
  65. package/dist/template.js +15 -10
  66. package/dist/theme-css-hFqcPSar.js +587 -0
  67. package/dist/theme-css.d.ts +57 -16
  68. package/dist/theme-css.js +2 -509
  69. package/dist/theme-imports-lvBw3AD1.js +109 -0
  70. package/dist/transform-Ct2OMkFN.d.ts +153 -0
  71. package/dist/unsubscribe-link-CoesnQDU.js +26 -0
  72. package/dist/whatsapp.d.ts +57 -0
  73. package/dist/whatsapp.js +22 -0
  74. package/generated/contract.json +1782 -0
  75. package/generated/reference.md +353 -0
  76. package/package.json +56 -154
  77. package/samva-brand.d.ts +14 -0
  78. package/skills/sml/SKILL.md +123 -0
  79. package/dist/ast-BrDtApwS.d.ts +0 -107
  80. package/dist/ast.d.ts +0 -2
  81. package/dist/ast.js +0 -124
  82. package/dist/candidate.d.ts +0 -29
  83. package/dist/candidate.js +0 -88
  84. package/dist/catalog-60eaYC7b.d.ts +0 -356
  85. package/dist/checks-DBweSIPN.js +0 -58954
  86. package/dist/checks.d.ts +0 -33
  87. package/dist/checks.js +0 -2
  88. package/dist/classes.d.ts +0 -27
  89. package/dist/classes.js +0 -184
  90. package/dist/compile-sms.d.ts +0 -28
  91. package/dist/compile-sms.js +0 -44
  92. package/dist/compile-whatsapp.d.ts +0 -56
  93. package/dist/compile-whatsapp.js +0 -186
  94. package/dist/compile.d.ts +0 -18
  95. package/dist/compile.js +0 -29
  96. package/dist/components.d.ts +0 -289
  97. package/dist/components.js +0 -106
  98. package/dist/conditionals.d.ts +0 -10
  99. package/dist/conditionals.js +0 -74
  100. package/dist/corpus-BjYMqOoY.d.ts +0 -106
  101. package/dist/diagnostics-OcQKQYSY.d.ts +0 -49
  102. package/dist/email/selection.d.ts +0 -91
  103. package/dist/email/selection.js +0 -91
  104. package/dist/email/source-edit.js +0 -185
  105. package/dist/email/stylesheets.d.ts +0 -15
  106. package/dist/email/stylesheets.js +0 -45
  107. package/dist/emit.d.ts +0 -51
  108. package/dist/emit.js +0 -151
  109. package/dist/footer.d.ts +0 -66
  110. package/dist/footer.js +0 -93
  111. package/dist/interpolate.d.ts +0 -24
  112. package/dist/interpolate.js +0 -43
  113. package/dist/jsx-dev-runtime.d.ts +0 -11
  114. package/dist/jsx-dev-runtime.js +0 -15
  115. package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
  116. package/dist/jsx-runtime.d.ts +0 -2
  117. package/dist/jsx-runtime.js +0 -121
  118. package/dist/lexer.d.ts +0 -60
  119. package/dist/lexer.js +0 -281
  120. package/dist/model.d.ts +0 -24
  121. package/dist/model.js +0 -77
  122. package/dist/ops-2aiiYO7m.js +0 -630
  123. package/dist/ops.d.ts +0 -114
  124. package/dist/ops.js +0 -2
  125. package/dist/parser-t29cHLVL.d.ts +0 -396
  126. package/dist/parser.d.ts +0 -2
  127. package/dist/parser.js +0 -859
  128. package/dist/predicate-BI6uRRM-.js +0 -549
  129. package/dist/predicate-M-05Nd7R.d.ts +0 -56
  130. package/dist/predicate.d.ts +0 -2
  131. package/dist/predicate.js +0 -2
  132. package/dist/presets/category-mapping.d.ts +0 -13
  133. package/dist/presets/category-mapping.js +0 -49
  134. package/dist/presets/corpus.d.ts +0 -2
  135. package/dist/presets/corpus.js +0 -194
  136. package/dist/presets/public-gallery.d.ts +0 -266
  137. package/dist/presets/public-gallery.js +0 -916
  138. package/dist/presets/public-handoff.d.ts +0 -164
  139. package/dist/presets/public-handoff.js +0 -361
  140. package/dist/presets/public-preview-artifacts.d.ts +0 -43
  141. package/dist/presets/public-preview-artifacts.js +0 -104
  142. package/dist/presets/public-preview.d.ts +0 -61
  143. package/dist/presets/public-preview.js +0 -83
  144. package/dist/presets/showcase.d.ts +0 -2
  145. package/dist/presets/showcase.js +0 -627
  146. package/dist/presets/sources.d.ts +0 -38
  147. package/dist/presets/sources.js +0 -6083
  148. package/dist/presets.d.ts +0 -2
  149. package/dist/presets.js +0 -881
  150. package/dist/printer.d.ts +0 -6
  151. package/dist/printer.js +0 -122
  152. package/dist/registry.d.ts +0 -42
  153. package/dist/registry.js +0 -646
  154. package/dist/render-template.d.ts +0 -45
  155. package/dist/render-template.js +0 -76
  156. package/dist/showcase-DGZAWn4Z.d.ts +0 -456
  157. package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
  158. package/dist/source-locations-DrCM82Ym.d.ts +0 -67
  159. package/dist/template-DWftqh4x.d.ts +0 -60
  160. package/dist/theme-6ApjjiBo.d.ts +0 -116
  161. package/dist/theme.d.ts +0 -2
  162. package/dist/theme.js +0 -118
  163. package/dist/tokens.d.ts +0 -6
  164. package/dist/tokens.js +0 -417
  165. package/dist/tsx-source-instrumentation.d.ts +0 -30
  166. package/dist/tsx-source-instrumentation.js +0 -115
  167. package/dist/tsx-tracer.d.ts +0 -112
  168. package/dist/tsx-tracer.js +0 -985
  169. package/dist/variables-J_L3qxRa.d.ts +0 -77
  170. package/dist/variables.d.ts +0 -2
  171. package/dist/variables.js +0 -141
  172. package/dist/version-BITr58kk.js +0 -96
  173. package/generated/sml-agent-contract.json +0 -709
  174. package/generated/sml-email-agent-contract.json +0 -615
  175. package/generated/sml-email-language-reference.md +0 -94
  176. package/generated/sml-language-reference.md +0 -195
@@ -1,549 +0,0 @@
1
- import { Result } from "better-result";
2
- //#region src/limits.ts
3
- /** Hard ceilings shared by SML documents and standalone predicate parsing. */
4
- const SML_PARSER_LIMITS = {
5
- maxCharacters: 5e5,
6
- maxUtf8Bytes: 1048576,
7
- maxDepth: 64,
8
- maxNodes: 25e3
9
- };
10
- //#endregion
11
- //#region src/predicate.ts
12
- /** Standalone predicates inherit the same source, nesting, and node ceilings as SML. */
13
- const PREDICATE_PARSER_LIMITS = SML_PARSER_LIMITS;
14
- const CHAR_TAB = 9;
15
- const CHAR_LINE_FEED = 10;
16
- const CHAR_CARRIAGE_RETURN = 13;
17
- const CHAR_SPACE = 32;
18
- const CHAR_BANG = 33;
19
- const CHAR_SINGLE_QUOTE = 39;
20
- const CHAR_OPEN_PAREN = 40;
21
- const CHAR_CLOSE_PAREN = 41;
22
- const CHAR_MINUS = 45;
23
- const CHAR_DOT = 46;
24
- const CHAR_LESS_THAN = 60;
25
- const CHAR_EQUALS = 61;
26
- const CHAR_GREATER_THAN = 62;
27
- const CHAR_UNDERSCORE = 95;
28
- const CHAR_0 = 48;
29
- const CHAR_9 = 57;
30
- const CHAR_UPPER_A = 65;
31
- const CHAR_UPPER_Z = 90;
32
- const CHAR_LOWER_A = 97;
33
- const CHAR_LOWER_Z = 122;
34
- const isWhitespace = (code) => code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LINE_FEED || code === CHAR_CARRIAGE_RETURN;
35
- const isDigit = (code) => code >= CHAR_0 && code <= CHAR_9;
36
- const isLetter = (code) => code >= CHAR_UPPER_A && code <= CHAR_UPPER_Z || code >= CHAR_LOWER_A && code <= CHAR_LOWER_Z;
37
- const isNameStart = (code) => isLetter(code) || code === CHAR_UNDERSCORE;
38
- const isNameChar = (code) => isNameStart(code) || isDigit(code);
39
- const KEYWORDS = [
40
- "and",
41
- "or",
42
- "not"
43
- ];
44
- const isKeyword = (text) => KEYWORDS.includes(text);
45
- const tokenize = (source, baseOffset) => {
46
- const tokens = [];
47
- let index = 0;
48
- const length = source.length;
49
- const failAt = (code, message, start, end) => Result.err({ diagnostic: {
50
- code,
51
- message,
52
- span: {
53
- start: baseOffset + start,
54
- end: baseOffset + end
55
- }
56
- } });
57
- while (index < length) {
58
- const code = source.charCodeAt(index);
59
- if (isWhitespace(code)) {
60
- index++;
61
- continue;
62
- }
63
- const start = index;
64
- if (code === CHAR_OPEN_PAREN) {
65
- index++;
66
- tokens.push({
67
- kind: "lparen",
68
- text: "(",
69
- span: {
70
- start: baseOffset + start,
71
- end: baseOffset + index
72
- }
73
- });
74
- continue;
75
- }
76
- if (code === CHAR_CLOSE_PAREN) {
77
- index++;
78
- tokens.push({
79
- kind: "rparen",
80
- text: ")",
81
- span: {
82
- start: baseOffset + start,
83
- end: baseOffset + index
84
- }
85
- });
86
- continue;
87
- }
88
- if (code === CHAR_EQUALS || code === CHAR_BANG) {
89
- if (source.charCodeAt(index + 1) === CHAR_EQUALS) {
90
- index += 2;
91
- tokens.push({
92
- kind: "op",
93
- text: code === CHAR_EQUALS ? "==" : "!=",
94
- span: {
95
- start: baseOffset + start,
96
- end: baseOffset + index
97
- }
98
- });
99
- continue;
100
- }
101
- return failAt("predicate-invalid-operator", `unexpected ${String.fromCharCode(code)} — ${code === CHAR_EQUALS ? "write == to compare" : "write != to compare"}`, start, start + 1);
102
- }
103
- if (code === CHAR_GREATER_THAN || code === CHAR_LESS_THAN) {
104
- index++;
105
- if (source.charCodeAt(index) === CHAR_EQUALS) index++;
106
- tokens.push({
107
- kind: "op",
108
- text: source.slice(start, index),
109
- span: {
110
- start: baseOffset + start,
111
- end: baseOffset + index
112
- }
113
- });
114
- continue;
115
- }
116
- if (code === CHAR_SINGLE_QUOTE) {
117
- index++;
118
- const contentStart = index;
119
- while (index < length && source.charCodeAt(index) !== CHAR_SINGLE_QUOTE) index++;
120
- if (index >= length) return failAt("predicate-unterminated-string", "unterminated string — add a closing '", start, length);
121
- const value = source.slice(contentStart, index);
122
- index++;
123
- if (value.includes("--")) return failAt("predicate-string-double-dash", "string literals cannot contain -- (predicates are embedded in HTML comment markers)", start, index);
124
- tokens.push({
125
- kind: "string",
126
- text: source.slice(start, index),
127
- string: value,
128
- span: {
129
- start: baseOffset + start,
130
- end: baseOffset + index
131
- }
132
- });
133
- continue;
134
- }
135
- if (isDigit(code) || code === CHAR_MINUS && isDigit(source.charCodeAt(index + 1))) {
136
- index++;
137
- while (index < length && isDigit(source.charCodeAt(index))) index++;
138
- if (source.charCodeAt(index) === CHAR_DOT && isDigit(source.charCodeAt(index + 1))) {
139
- index++;
140
- while (index < length && isDigit(source.charCodeAt(index))) index++;
141
- }
142
- const raw = source.slice(start, index);
143
- const value = Number.parseFloat(raw);
144
- if (!Number.isFinite(value)) return failAt("predicate-number-out-of-range", "number literal is outside the finite numeric range", start, index);
145
- tokens.push({
146
- kind: "number",
147
- text: raw,
148
- number: value,
149
- span: {
150
- start: baseOffset + start,
151
- end: baseOffset + index
152
- }
153
- });
154
- continue;
155
- }
156
- if (isNameStart(code)) {
157
- index++;
158
- while (index < length && isNameChar(source.charCodeAt(index))) index++;
159
- if (source.charCodeAt(index) === CHAR_DOT) return failAt("predicate-path-not-supported", `unexpected . after "${source.slice(start, index)}" — predicates use flat variable names, not paths`, start, index + 1);
160
- tokens.push({
161
- kind: "name",
162
- text: source.slice(start, index),
163
- span: {
164
- start: baseOffset + start,
165
- end: baseOffset + index
166
- }
167
- });
168
- continue;
169
- }
170
- if (code === CHAR_DOT) return failAt("predicate-path-not-supported", "unexpected . — predicates use flat variable names, not paths", start, start + 1);
171
- return failAt("predicate-unexpected-character", `unexpected character ${JSON.stringify(String.fromCharCode(code))} in predicate`, start, start + 1);
172
- }
173
- tokens.push({
174
- kind: "eof",
175
- text: "",
176
- span: {
177
- start: baseOffset + length,
178
- end: baseOffset + length
179
- }
180
- });
181
- return Result.ok(tokens);
182
- };
183
- const COMPARISON_OPS = [
184
- "==",
185
- "!=",
186
- ">",
187
- ">=",
188
- "<",
189
- "<="
190
- ];
191
- /**
192
- * Parses a predicate. `baseOffset` is the absolute source offset of the
193
- * predicate's first character (an <If> test attribute passes valueSpan.start),
194
- * so diagnostic and node spans point into the containing document.
195
- */
196
- const parsePredicate = (source, baseOffset = 0) => {
197
- if (source.length > SML_PARSER_LIMITS.maxCharacters) return Result.err([{
198
- code: "predicate-character-limit",
199
- message: `predicate exceeds the ${SML_PARSER_LIMITS.maxCharacters} character limit`,
200
- span: {
201
- start: baseOffset,
202
- end: baseOffset + source.length
203
- }
204
- }]);
205
- if (new TextEncoder().encode(source).byteLength > SML_PARSER_LIMITS.maxUtf8Bytes) return Result.err([{
206
- code: "predicate-byte-limit",
207
- message: `predicate exceeds the ${SML_PARSER_LIMITS.maxUtf8Bytes} byte UTF-8 limit`,
208
- span: {
209
- start: baseOffset,
210
- end: baseOffset + source.length
211
- }
212
- }]);
213
- const lexed = tokenize(source, baseOffset);
214
- if (Result.isError(lexed)) return Result.err([lexed.error.diagnostic]);
215
- const tokens = lexed.value;
216
- let index = 0;
217
- let diagnostic;
218
- let nodeCount = 0;
219
- const fail = (code, message, span) => {
220
- diagnostic ??= {
221
- code,
222
- message,
223
- span
224
- };
225
- return null;
226
- };
227
- const peek = () => tokens[index];
228
- const advance = () => tokens[index++];
229
- const isKeywordToken = (token, keyword) => token.kind === "name" && token.text === keyword;
230
- const countNode = (node) => {
231
- nodeCount += 1;
232
- return nodeCount > SML_PARSER_LIMITS.maxNodes ? fail("predicate-node-limit", `predicate exceeds the ${SML_PARSER_LIMITS.maxNodes} node limit`, node.span) : node;
233
- };
234
- const parsePrimary = (depth) => {
235
- const token = advance();
236
- if (token.kind === "lparen") {
237
- if (depth >= SML_PARSER_LIMITS.maxDepth) return fail("predicate-depth-limit", `predicate nesting exceeds the maximum depth of ${SML_PARSER_LIMITS.maxDepth}`, token.span);
238
- const inner = parseOr(depth + 1);
239
- if (inner === null) return null;
240
- const close = advance();
241
- if (close.kind !== "rparen") return fail("predicate-missing-paren", "missing ) — close the group", close.span);
242
- return inner;
243
- }
244
- if (token.kind === "name") {
245
- if (isKeyword(token.text)) return fail("predicate-unexpected-token", `unexpected "${token.text}" — expected a variable name, comparison, or ( group )`, token.span);
246
- const opToken = peek();
247
- if (opToken.kind !== "op") return countNode({
248
- kind: "name",
249
- name: token.text,
250
- span: token.span
251
- });
252
- advance();
253
- const op = COMPARISON_OPS.find((candidate) => candidate === opToken.text);
254
- if (op === void 0) return fail("predicate-invalid-operator", `unknown operator ${opToken.text} — use ==, !=, >, >=, <, or <=`, opToken.span);
255
- const literalToken = advance();
256
- if (literalToken.kind === "string") return countNode({
257
- kind: "comparison",
258
- name: token.text,
259
- op,
260
- literal: {
261
- kind: "string",
262
- value: literalToken.string
263
- },
264
- span: {
265
- start: token.span.start,
266
- end: literalToken.span.end
267
- }
268
- });
269
- if (literalToken.kind === "number") return countNode({
270
- kind: "comparison",
271
- name: token.text,
272
- op,
273
- literal: {
274
- kind: "number",
275
- value: literalToken.number
276
- },
277
- span: {
278
- start: token.span.start,
279
- end: literalToken.span.end
280
- }
281
- });
282
- return fail("predicate-expected-literal", `expected a literal after ${op} — write ${token.text} ${op} 'value' or ${token.text} ${op} 5`, literalToken.span);
283
- }
284
- if (token.kind === "eof") return fail("predicate-unexpected-end", "unexpected end of predicate — expected a variable name, comparison, or ( group )", token.span);
285
- return fail("predicate-unexpected-token", `unexpected ${token.text} — comparisons put the variable first: name == 'value'`, token.span);
286
- };
287
- const parseUnary = (depth) => {
288
- const token = peek();
289
- if (isKeywordToken(token, "not")) {
290
- advance();
291
- const operand = parsePrimary(depth);
292
- if (operand === null) return null;
293
- return countNode({
294
- kind: "not",
295
- operand,
296
- span: {
297
- start: token.span.start,
298
- end: operand.span.end
299
- }
300
- });
301
- }
302
- return parsePrimary(depth);
303
- };
304
- const parseAnd = (depth) => {
305
- let left = parseUnary(depth);
306
- while (left !== null && isKeywordToken(peek(), "and")) {
307
- advance();
308
- const right = parseUnary(depth);
309
- if (right === null) return null;
310
- left = countNode({
311
- kind: "and",
312
- left,
313
- right,
314
- span: {
315
- start: left.span.start,
316
- end: right.span.end
317
- }
318
- });
319
- }
320
- return left;
321
- };
322
- const parseOr = (depth) => {
323
- let left = parseAnd(depth);
324
- while (left !== null && isKeywordToken(peek(), "or")) {
325
- advance();
326
- const right = parseAnd(depth);
327
- if (right === null) return null;
328
- left = countNode({
329
- kind: "or",
330
- left,
331
- right,
332
- span: {
333
- start: left.span.start,
334
- end: right.span.end
335
- }
336
- });
337
- }
338
- return left;
339
- };
340
- if (source.trim().length === 0) return Result.err([{
341
- code: "predicate-empty",
342
- message: "empty predicate — write e.g. plan == 'pro'",
343
- span: {
344
- start: baseOffset,
345
- end: baseOffset + source.length
346
- }
347
- }]);
348
- const ast = parseOr(0);
349
- if (ast !== null && diagnostic === void 0) {
350
- const trailing = peek();
351
- if (trailing.kind !== "eof") fail("predicate-trailing-input", `unexpected ${JSON.stringify(trailing.text)} after the predicate — join clauses with "and" or "or"`, trailing.span);
352
- }
353
- if (ast === null || diagnostic !== void 0) return Result.err([diagnostic ?? {
354
- code: "predicate-parse-failed",
355
- message: "predicate parse failed",
356
- span: {
357
- start: baseOffset,
358
- end: baseOffset + source.length
359
- }
360
- }]);
361
- return Result.ok(ast);
362
- };
363
- const toNumber = (value) => {
364
- if (typeof value === "number") return value;
365
- if (typeof value === "string" && value.trim() !== "") return Number(value);
366
- return NaN;
367
- };
368
- const compareNumbers = (op, left, right) => {
369
- switch (op) {
370
- case "==": return left === right;
371
- case "!=": return left !== right;
372
- case ">": return left > right;
373
- case ">=": return left >= right;
374
- case "<": return left < right;
375
- case "<=": return left <= right;
376
- }
377
- };
378
- const evaluateComparison = (node, variables) => {
379
- const value = variables[node.name];
380
- if (value === void 0 || value === null) return false;
381
- if (node.literal.kind === "number") {
382
- const left = toNumber(value);
383
- if (Number.isNaN(left)) return false;
384
- return compareNumbers(node.op, left, node.literal.value);
385
- }
386
- if (node.op === "==" || node.op === "!=") {
387
- if (typeof value !== "string") return false;
388
- return node.op === "==" ? value === node.literal.value : value !== node.literal.value;
389
- }
390
- const left = toNumber(value);
391
- const right = toNumber(node.literal.value);
392
- if (Number.isNaN(left) || Number.isNaN(right)) return false;
393
- return compareNumbers(node.op, left, right);
394
- };
395
- const evaluatePredicate = (ast, variables) => {
396
- const tasks = [{
397
- kind: "node",
398
- node: ast
399
- }];
400
- const values = [];
401
- while (tasks.length > 0) {
402
- const task = tasks.pop();
403
- if (task.kind === "not") {
404
- values.push(!values.pop());
405
- continue;
406
- }
407
- if (task.kind === "and" || task.kind === "or") {
408
- const left = values.pop();
409
- if (task.kind === "and" && !left || task.kind === "or" && left) values.push(left);
410
- else tasks.push({
411
- kind: "node",
412
- node: task.right
413
- });
414
- continue;
415
- }
416
- const node = task.node;
417
- switch (node.kind) {
418
- case "or":
419
- case "and":
420
- tasks.push({
421
- kind: node.kind,
422
- right: node.right
423
- }, {
424
- kind: "node",
425
- node: node.left
426
- });
427
- break;
428
- case "not":
429
- tasks.push({ kind: "not" }, {
430
- kind: "node",
431
- node: node.operand
432
- });
433
- break;
434
- case "comparison":
435
- values.push(evaluateComparison(node, variables));
436
- break;
437
- case "name": {
438
- const value = variables[node.name];
439
- values.push(value !== void 0 && value !== null && value !== "");
440
- break;
441
- }
442
- }
443
- }
444
- return values[0];
445
- };
446
- const precedence = (node) => {
447
- switch (node.kind) {
448
- case "or": return 1;
449
- case "and": return 2;
450
- case "not": return 3;
451
- case "comparison":
452
- case "name": return 4;
453
- }
454
- };
455
- const printLiteral = (literal) => {
456
- if (literal.kind === "number") {
457
- if (Number.isFinite(literal.value)) return String(literal.value);
458
- throw new TypeError(`Number ${String(literal.value)} cannot be represented in a predicate: number literals must be finite`);
459
- }
460
- if (literal.value.includes("'") || literal.value.includes("--")) throw new TypeError(`String ${JSON.stringify(literal.value)} cannot be represented in a predicate: string literals cannot contain ' or --`);
461
- return `'${literal.value}'`;
462
- };
463
- /** Canonical form: single space around operators/keywords, minimal parens. */
464
- const printPredicate = (ast) => {
465
- const frames = [{
466
- kind: "node",
467
- node: ast,
468
- minPrecedence: 0
469
- }];
470
- const output = [];
471
- while (frames.length > 0) {
472
- const frame = frames.pop();
473
- if (frame.kind === "text") {
474
- output.push(frame.value);
475
- continue;
476
- }
477
- const { node, minPrecedence } = frame;
478
- const wrapped = precedence(node) < minPrecedence;
479
- if (wrapped) frames.push({
480
- kind: "text",
481
- value: ")"
482
- });
483
- switch (node.kind) {
484
- case "or":
485
- case "and": {
486
- const operator = node.kind === "or" ? " or " : " and ";
487
- const childPrecedence = node.kind === "or" ? 1 : 2;
488
- frames.push({
489
- kind: "node",
490
- node: node.right,
491
- minPrecedence: childPrecedence
492
- }, {
493
- kind: "text",
494
- value: operator
495
- }, {
496
- kind: "node",
497
- node: node.left,
498
- minPrecedence: childPrecedence
499
- });
500
- break;
501
- }
502
- case "not":
503
- frames.push({
504
- kind: "node",
505
- node: node.operand,
506
- minPrecedence: 4
507
- }, {
508
- kind: "text",
509
- value: "not "
510
- });
511
- break;
512
- case "comparison":
513
- frames.push({
514
- kind: "text",
515
- value: `${node.name} ${node.op} ${printLiteral(node.literal)}`
516
- });
517
- break;
518
- case "name": frames.push({
519
- kind: "text",
520
- value: node.name
521
- });
522
- }
523
- if (wrapped) output.push("(");
524
- }
525
- return output.join("");
526
- };
527
- const collectPredicateVariables = (ast) => {
528
- const names = /* @__PURE__ */ new Set();
529
- const pending = [ast];
530
- while (pending.length > 0) {
531
- const node = pending.pop();
532
- switch (node.kind) {
533
- case "or":
534
- case "and":
535
- pending.push(node.right, node.left);
536
- break;
537
- case "not":
538
- pending.push(node.operand);
539
- break;
540
- case "comparison":
541
- case "name": names.add(node.name);
542
- }
543
- }
544
- return names;
545
- };
546
- //#endregion
547
- export { printPredicate as a, parsePredicate as i, collectPredicateVariables as n, SML_PARSER_LIMITS as o, evaluatePredicate as r, PREDICATE_PARSER_LIMITS as t };
548
-
549
- //# sourceMappingURL=predicate-BI6uRRM-.js.map
@@ -1,56 +0,0 @@
1
- import { a as Span, t as Diagnostic } from "./diagnostics-OcQKQYSY.js";
2
- import { Result } from "better-result";
3
- //#region src/predicate.d.ts
4
- /** Standalone predicates inherit the same source, nesting, and node ceilings as SML. */
5
- declare const PREDICATE_PARSER_LIMITS: {
6
- readonly maxCharacters: 500000;
7
- readonly maxUtf8Bytes: number;
8
- readonly maxDepth: 64;
9
- readonly maxNodes: 25000;
10
- };
11
- type ComparisonOp = "==" | "!=" | ">" | ">=" | "<" | "<=";
12
- type PredicateLiteral = {
13
- readonly kind: "string";
14
- readonly value: string;
15
- } | {
16
- readonly kind: "number";
17
- readonly value: number;
18
- };
19
- type PredicateAst = {
20
- readonly kind: "or";
21
- readonly left: PredicateAst;
22
- readonly right: PredicateAst;
23
- readonly span: Span;
24
- } | {
25
- readonly kind: "and";
26
- readonly left: PredicateAst;
27
- readonly right: PredicateAst;
28
- readonly span: Span;
29
- } | {
30
- readonly kind: "not";
31
- readonly operand: PredicateAst;
32
- readonly span: Span;
33
- } | {
34
- readonly kind: "comparison";
35
- readonly name: string;
36
- readonly op: ComparisonOp;
37
- readonly literal: PredicateLiteral;
38
- readonly span: Span;
39
- } | {
40
- readonly kind: "name";
41
- readonly name: string;
42
- readonly span: Span;
43
- };
44
- /**
45
- * Parses a predicate. `baseOffset` is the absolute source offset of the
46
- * predicate's first character (an <If> test attribute passes valueSpan.start),
47
- * so diagnostic and node spans point into the containing document.
48
- */
49
- declare const parsePredicate: (source: string, baseOffset?: number) => Result<PredicateAst, ReadonlyArray<Diagnostic>>;
50
- declare const evaluatePredicate: (ast: PredicateAst, variables: Record<string, unknown>) => boolean;
51
- /** Canonical form: single space around operators/keywords, minimal parens. */
52
- declare const printPredicate: (ast: PredicateAst) => string;
53
- declare const collectPredicateVariables: (ast: PredicateAst) => Set<string>;
54
- //#endregion
55
- export { collectPredicateVariables as a, printPredicate as c, PredicateLiteral as i, PREDICATE_PARSER_LIMITS as n, evaluatePredicate as o, PredicateAst as r, parsePredicate as s, ComparisonOp as t };
56
- //# sourceMappingURL=predicate-M-05Nd7R.d.ts.map
@@ -1,2 +0,0 @@
1
- import { a as collectPredicateVariables, c as printPredicate, i as PredicateLiteral, n as PREDICATE_PARSER_LIMITS, o as evaluatePredicate, r as PredicateAst, s as parsePredicate, t as ComparisonOp } from "./predicate-M-05Nd7R.js";
2
- export { ComparisonOp, PREDICATE_PARSER_LIMITS, PredicateAst, PredicateLiteral, collectPredicateVariables, evaluatePredicate, parsePredicate, printPredicate };
package/dist/predicate.js DELETED
@@ -1,2 +0,0 @@
1
- import { a as printPredicate, i as parsePredicate, n as collectPredicateVariables, r as evaluatePredicate, t as PREDICATE_PARSER_LIMITS } from "./predicate-BI6uRRM-.js";
2
- export { PREDICATE_PARSER_LIMITS, collectPredicateVariables, evaluatePredicate, parsePredicate, printPredicate };
@@ -1,13 +0,0 @@
1
- import { r as PresetCategory } from "../catalog-60eaYC7b.js";
2
- import { TemplateCollectionId } from "./public-gallery.js";
3
- //#region presets/category-mapping.d.ts
4
- declare const LAB_DIMENSIONS: readonly ["newsletter", "receipt", "security", "product-update", "onboarding", "promotion", "shipping", "social-notification"];
5
- type LabDimension = (typeof LAB_DIMENSIONS)[number];
6
- declare const LAB_KINDS: readonly ["newsletter", "receipt", "security", "product-update", "onboarding", "promotion", "shipping", "social-notification", "digest", "invoice", "account", "event", "statement", "developer-notification", "unknown"];
7
- type LabKind = (typeof LAB_KINDS)[number];
8
- declare const labKindToPresetCategory: Record<LabKind, PresetCategory>;
9
- declare const presetCategoryToCollection: Record<PresetCategory, TemplateCollectionId>;
10
- declare const labKindToCollection: (kind: LabKind) => TemplateCollectionId;
11
- //#endregion
12
- export { LAB_DIMENSIONS, LAB_KINDS, LabDimension, LabKind, labKindToCollection, labKindToPresetCategory, presetCategoryToCollection };
13
- //# sourceMappingURL=category-mapping.d.ts.map
@@ -1,49 +0,0 @@
1
- //#region presets/category-mapping.ts
2
- const LAB_DIMENSIONS = [
3
- "newsletter",
4
- "receipt",
5
- "security",
6
- "product-update",
7
- "onboarding",
8
- "promotion",
9
- "shipping",
10
- "social-notification"
11
- ];
12
- const LAB_KINDS = [
13
- ...LAB_DIMENSIONS,
14
- "digest",
15
- "invoice",
16
- "account",
17
- "event",
18
- "statement",
19
- "developer-notification",
20
- "unknown"
21
- ];
22
- const labKindToPresetCategory = {
23
- newsletter: "digest",
24
- receipt: "transactional",
25
- security: "transactional",
26
- "product-update": "marketing",
27
- onboarding: "lifecycle",
28
- promotion: "marketing",
29
- shipping: "transactional",
30
- "social-notification": "transactional",
31
- digest: "digest",
32
- invoice: "transactional",
33
- account: "transactional",
34
- event: "marketing",
35
- statement: "transactional",
36
- "developer-notification": "transactional",
37
- unknown: "transactional"
38
- };
39
- const presetCategoryToCollection = {
40
- transactional: "category:transactional",
41
- digest: "category:digest-editorial",
42
- marketing: "category:marketing",
43
- lifecycle: "category:lifecycle"
44
- };
45
- const labKindToCollection = (kind) => presetCategoryToCollection[labKindToPresetCategory[kind]];
46
- //#endregion
47
- export { LAB_DIMENSIONS, LAB_KINDS, labKindToCollection, labKindToPresetCategory, presetCategoryToCollection };
48
-
49
- //# sourceMappingURL=category-mapping.js.map
@@ -1,2 +0,0 @@
1
- import { a as PublicCorpusRegistrationIssue, c as TemplateFacetQuery, d as matchesTemplateFacets, f as ownedPresetSourcePath, h as templateFacetOptions, i as PublicCorpusRegistration, l as TemplateFacetSet, m as registerPublicCorpusEntry, n as InspirationReference, o as TemplateCorpusKind, p as ownedShowcasePresetSources, r as OwnedEditablePreset, s as TemplateCorpusRecord, t as BrandRecreationPreset, u as brandRecreationProvenance } from "../corpus-BjYMqOoY.js";
2
- export { BrandRecreationPreset, InspirationReference, OwnedEditablePreset, PublicCorpusRegistration, PublicCorpusRegistrationIssue, TemplateCorpusKind, TemplateCorpusRecord, TemplateFacetQuery, TemplateFacetSet, brandRecreationProvenance, matchesTemplateFacets, ownedPresetSourcePath, ownedShowcasePresetSources, registerPublicCorpusEntry, templateFacetOptions };