@samva/markup 0.1.0 → 0.1.2
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.
- package/dist/ast.js +1 -1
- package/dist/{checks-CW0nFj5n.js → checks-D-zFQt5R.js} +2 -2
- package/dist/checks.js +1 -1
- package/dist/compile-sms.d.ts +1 -1
- package/dist/compile-whatsapp.d.ts +1 -1
- package/dist/components.d.ts +3 -3
- package/dist/conditionals.js +1 -1
- package/dist/diagnostics.js +2 -2
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/{jsx-runtime-fSxcvlx4.d.ts → jsx-runtime-eNIMY87F.d.ts} +2 -2
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/ops.js +2 -2
- package/dist/{parser-yzjUOGhc.d.ts → parser-DkQKIjDa.d.ts} +11 -2
- package/dist/parser.d.ts +2 -2
- package/dist/parser.js +48 -9
- package/dist/predicate-CvkzT-a2.js +539 -0
- package/dist/{predicate-DTtVtLK7.d.ts → predicate-G2SeSvoN.d.ts} +9 -2
- package/dist/predicate.d.ts +2 -2
- package/dist/predicate.js +2 -417
- package/dist/presets/category-mapping.d.ts +1 -1
- package/dist/presets/public-gallery.d.ts +2 -490
- package/dist/presets/public-gallery.js +2 -1
- package/dist/presets/public-handoff.d.ts +2 -68
- package/dist/presets/public-handoff.js +110 -24
- package/dist/presets/public-preview-artifacts.d.ts +2 -2
- package/dist/presets/public-preview.d.ts +2 -1168
- package/dist/presets/public-preview.js +17 -17
- package/dist/presets/sources.js +17 -17
- package/dist/public-gallery-D0Zv0pZE.d.ts +611 -0
- package/dist/public-preview-u1Z9aaGq.d.ts +1168 -0
- package/dist/render-template.d.ts +2 -2
- package/dist/render-template.js +1 -1
- package/dist/{variables-3NGLpNTB.d.ts → variables-if1VrV34.d.ts} +2 -2
- package/dist/variables.d.ts +1 -1
- package/dist/variables.js +1 -1
- package/generated/sml-email-language-reference.md +1 -1
- package/generated/sml-language-reference.md +1 -1
- package/package.json +6 -3
- package/dist/ast.js.map +0 -1
- package/dist/candidate.js.map +0 -1
- package/dist/checks-CW0nFj5n.js.map +0 -1
- package/dist/classes.js.map +0 -1
- package/dist/compile-sms.js.map +0 -1
- package/dist/compile-whatsapp.js.map +0 -1
- package/dist/compile.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/conditionals.js.map +0 -1
- package/dist/diagnostics.js.map +0 -1
- package/dist/emit.js.map +0 -1
- package/dist/footer.js.map +0 -1
- package/dist/interpolate.js.map +0 -1
- package/dist/jsx-dev-runtime.js.map +0 -1
- package/dist/jsx-runtime.js.map +0 -1
- package/dist/lexer.js.map +0 -1
- package/dist/model.js.map +0 -1
- package/dist/ops.js.map +0 -1
- package/dist/parser.js.map +0 -1
- package/dist/predicate.js.map +0 -1
- package/dist/presets/category-mapping.js.map +0 -1
- package/dist/presets/public-gallery.js.map +0 -1
- package/dist/presets/public-handoff.js.map +0 -1
- package/dist/presets/public-preview-artifacts.js.map +0 -1
- package/dist/presets/public-preview.js.map +0 -1
- package/dist/presets/sources.js.map +0 -1
- package/dist/presets.js.map +0 -1
- package/dist/printer.js.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/render-template.js.map +0 -1
- package/dist/sms-segments.js.map +0 -1
- package/dist/theme-css.js.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/tokens.js.map +0 -1
- package/dist/variables.js.map +0 -1
- package/dist/version-BITr58kk.js.map +0 -1
package/dist/predicate.js
CHANGED
|
@@ -1,417 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const CHAR_TAB = 9;
|
|
4
|
-
const CHAR_LINE_FEED = 10;
|
|
5
|
-
const CHAR_CARRIAGE_RETURN = 13;
|
|
6
|
-
const CHAR_SPACE = 32;
|
|
7
|
-
const CHAR_BANG = 33;
|
|
8
|
-
const CHAR_SINGLE_QUOTE = 39;
|
|
9
|
-
const CHAR_OPEN_PAREN = 40;
|
|
10
|
-
const CHAR_CLOSE_PAREN = 41;
|
|
11
|
-
const CHAR_MINUS = 45;
|
|
12
|
-
const CHAR_DOT = 46;
|
|
13
|
-
const CHAR_LESS_THAN = 60;
|
|
14
|
-
const CHAR_EQUALS = 61;
|
|
15
|
-
const CHAR_GREATER_THAN = 62;
|
|
16
|
-
const CHAR_UNDERSCORE = 95;
|
|
17
|
-
const CHAR_0 = 48;
|
|
18
|
-
const CHAR_9 = 57;
|
|
19
|
-
const CHAR_UPPER_A = 65;
|
|
20
|
-
const CHAR_UPPER_Z = 90;
|
|
21
|
-
const CHAR_LOWER_A = 97;
|
|
22
|
-
const CHAR_LOWER_Z = 122;
|
|
23
|
-
const isWhitespace = (code) => code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LINE_FEED || code === CHAR_CARRIAGE_RETURN;
|
|
24
|
-
const isDigit = (code) => code >= CHAR_0 && code <= CHAR_9;
|
|
25
|
-
const isLetter = (code) => code >= CHAR_UPPER_A && code <= CHAR_UPPER_Z || code >= CHAR_LOWER_A && code <= CHAR_LOWER_Z;
|
|
26
|
-
const isNameStart = (code) => isLetter(code) || code === CHAR_UNDERSCORE;
|
|
27
|
-
const isNameChar = (code) => isNameStart(code) || isDigit(code);
|
|
28
|
-
const KEYWORDS = [
|
|
29
|
-
"and",
|
|
30
|
-
"or",
|
|
31
|
-
"not"
|
|
32
|
-
];
|
|
33
|
-
const isKeyword = (text) => KEYWORDS.includes(text);
|
|
34
|
-
const tokenize = (source, baseOffset) => {
|
|
35
|
-
const tokens = [];
|
|
36
|
-
let index = 0;
|
|
37
|
-
const length = source.length;
|
|
38
|
-
const failAt = (code, message, start, end) => Result.fail({ diagnostic: {
|
|
39
|
-
code,
|
|
40
|
-
message,
|
|
41
|
-
span: {
|
|
42
|
-
start: baseOffset + start,
|
|
43
|
-
end: baseOffset + end
|
|
44
|
-
}
|
|
45
|
-
} });
|
|
46
|
-
while (index < length) {
|
|
47
|
-
const code = source.charCodeAt(index);
|
|
48
|
-
if (isWhitespace(code)) {
|
|
49
|
-
index++;
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const start = index;
|
|
53
|
-
if (code === CHAR_OPEN_PAREN) {
|
|
54
|
-
index++;
|
|
55
|
-
tokens.push({
|
|
56
|
-
kind: "lparen",
|
|
57
|
-
text: "(",
|
|
58
|
-
span: {
|
|
59
|
-
start: baseOffset + start,
|
|
60
|
-
end: baseOffset + index
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (code === CHAR_CLOSE_PAREN) {
|
|
66
|
-
index++;
|
|
67
|
-
tokens.push({
|
|
68
|
-
kind: "rparen",
|
|
69
|
-
text: ")",
|
|
70
|
-
span: {
|
|
71
|
-
start: baseOffset + start,
|
|
72
|
-
end: baseOffset + index
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (code === CHAR_EQUALS || code === CHAR_BANG) {
|
|
78
|
-
if (source.charCodeAt(index + 1) === CHAR_EQUALS) {
|
|
79
|
-
index += 2;
|
|
80
|
-
tokens.push({
|
|
81
|
-
kind: "op",
|
|
82
|
-
text: code === CHAR_EQUALS ? "==" : "!=",
|
|
83
|
-
span: {
|
|
84
|
-
start: baseOffset + start,
|
|
85
|
-
end: baseOffset + index
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
return failAt("predicate-invalid-operator", `unexpected ${String.fromCharCode(code)} — ${code === CHAR_EQUALS ? "write == to compare" : "write != to compare"}`, start, start + 1);
|
|
91
|
-
}
|
|
92
|
-
if (code === CHAR_GREATER_THAN || code === CHAR_LESS_THAN) {
|
|
93
|
-
index++;
|
|
94
|
-
if (source.charCodeAt(index) === CHAR_EQUALS) index++;
|
|
95
|
-
tokens.push({
|
|
96
|
-
kind: "op",
|
|
97
|
-
text: source.slice(start, index),
|
|
98
|
-
span: {
|
|
99
|
-
start: baseOffset + start,
|
|
100
|
-
end: baseOffset + index
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (code === CHAR_SINGLE_QUOTE) {
|
|
106
|
-
index++;
|
|
107
|
-
const contentStart = index;
|
|
108
|
-
while (index < length && source.charCodeAt(index) !== CHAR_SINGLE_QUOTE) index++;
|
|
109
|
-
if (index >= length) return failAt("predicate-unterminated-string", "unterminated string — add a closing '", start, length);
|
|
110
|
-
const value = source.slice(contentStart, index);
|
|
111
|
-
index++;
|
|
112
|
-
if (value.includes("--")) return failAt("predicate-string-double-dash", "string literals cannot contain -- (predicates are embedded in HTML comment markers)", start, index);
|
|
113
|
-
tokens.push({
|
|
114
|
-
kind: "string",
|
|
115
|
-
text: source.slice(start, index),
|
|
116
|
-
string: value,
|
|
117
|
-
span: {
|
|
118
|
-
start: baseOffset + start,
|
|
119
|
-
end: baseOffset + index
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
if (isDigit(code) || code === CHAR_MINUS && isDigit(source.charCodeAt(index + 1))) {
|
|
125
|
-
index++;
|
|
126
|
-
while (index < length && isDigit(source.charCodeAt(index))) index++;
|
|
127
|
-
if (source.charCodeAt(index) === CHAR_DOT && isDigit(source.charCodeAt(index + 1))) {
|
|
128
|
-
index++;
|
|
129
|
-
while (index < length && isDigit(source.charCodeAt(index))) index++;
|
|
130
|
-
}
|
|
131
|
-
tokens.push({
|
|
132
|
-
kind: "number",
|
|
133
|
-
text: source.slice(start, index),
|
|
134
|
-
number: Number.parseFloat(source.slice(start, index)),
|
|
135
|
-
span: {
|
|
136
|
-
start: baseOffset + start,
|
|
137
|
-
end: baseOffset + index
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
if (isNameStart(code)) {
|
|
143
|
-
index++;
|
|
144
|
-
while (index < length && isNameChar(source.charCodeAt(index))) index++;
|
|
145
|
-
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);
|
|
146
|
-
tokens.push({
|
|
147
|
-
kind: "name",
|
|
148
|
-
text: source.slice(start, index),
|
|
149
|
-
span: {
|
|
150
|
-
start: baseOffset + start,
|
|
151
|
-
end: baseOffset + index
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
if (code === CHAR_DOT) return failAt("predicate-path-not-supported", "unexpected . — predicates use flat variable names, not paths", start, start + 1);
|
|
157
|
-
return failAt("predicate-unexpected-character", `unexpected character ${JSON.stringify(String.fromCharCode(code))} in predicate`, start, start + 1);
|
|
158
|
-
}
|
|
159
|
-
tokens.push({
|
|
160
|
-
kind: "eof",
|
|
161
|
-
text: "",
|
|
162
|
-
span: {
|
|
163
|
-
start: baseOffset + length,
|
|
164
|
-
end: baseOffset + length
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
return Result.succeed(tokens);
|
|
168
|
-
};
|
|
169
|
-
const COMPARISON_OPS = [
|
|
170
|
-
"==",
|
|
171
|
-
"!=",
|
|
172
|
-
">",
|
|
173
|
-
">=",
|
|
174
|
-
"<",
|
|
175
|
-
"<="
|
|
176
|
-
];
|
|
177
|
-
/**
|
|
178
|
-
* Parses a predicate. `baseOffset` is the absolute source offset of the
|
|
179
|
-
* predicate's first character (an <If> test attribute passes valueSpan.start),
|
|
180
|
-
* so diagnostic and node spans point into the containing document.
|
|
181
|
-
*/
|
|
182
|
-
const parsePredicate = (source, baseOffset = 0) => {
|
|
183
|
-
const lexed = tokenize(source, baseOffset);
|
|
184
|
-
if (Result.isFailure(lexed)) return Result.fail([lexed.failure.diagnostic]);
|
|
185
|
-
const tokens = lexed.success;
|
|
186
|
-
let index = 0;
|
|
187
|
-
let diagnostic;
|
|
188
|
-
const fail = (code, message, span) => {
|
|
189
|
-
diagnostic ??= {
|
|
190
|
-
code,
|
|
191
|
-
message,
|
|
192
|
-
span
|
|
193
|
-
};
|
|
194
|
-
return null;
|
|
195
|
-
};
|
|
196
|
-
const peek = () => tokens[index];
|
|
197
|
-
const advance = () => tokens[index++];
|
|
198
|
-
const isKeywordToken = (token, keyword) => token.kind === "name" && token.text === keyword;
|
|
199
|
-
const parsePrimary = () => {
|
|
200
|
-
const token = advance();
|
|
201
|
-
if (token.kind === "lparen") {
|
|
202
|
-
const inner = parseOr();
|
|
203
|
-
if (inner === null) return null;
|
|
204
|
-
const close = advance();
|
|
205
|
-
if (close.kind !== "rparen") return fail("predicate-missing-paren", "missing ) — close the group", close.span);
|
|
206
|
-
return inner;
|
|
207
|
-
}
|
|
208
|
-
if (token.kind === "name") {
|
|
209
|
-
if (isKeyword(token.text)) return fail("predicate-unexpected-token", `unexpected "${token.text}" — expected a variable name, comparison, or ( group )`, token.span);
|
|
210
|
-
const opToken = peek();
|
|
211
|
-
if (opToken.kind !== "op") return {
|
|
212
|
-
kind: "name",
|
|
213
|
-
name: token.text,
|
|
214
|
-
span: token.span
|
|
215
|
-
};
|
|
216
|
-
advance();
|
|
217
|
-
const op = COMPARISON_OPS.find((candidate) => candidate === opToken.text);
|
|
218
|
-
if (op === void 0) return fail("predicate-invalid-operator", `unknown operator ${opToken.text} — use ==, !=, >, >=, <, or <=`, opToken.span);
|
|
219
|
-
const literalToken = advance();
|
|
220
|
-
if (literalToken.kind === "string") return {
|
|
221
|
-
kind: "comparison",
|
|
222
|
-
name: token.text,
|
|
223
|
-
op,
|
|
224
|
-
literal: {
|
|
225
|
-
kind: "string",
|
|
226
|
-
value: literalToken.string
|
|
227
|
-
},
|
|
228
|
-
span: {
|
|
229
|
-
start: token.span.start,
|
|
230
|
-
end: literalToken.span.end
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
if (literalToken.kind === "number") return {
|
|
234
|
-
kind: "comparison",
|
|
235
|
-
name: token.text,
|
|
236
|
-
op,
|
|
237
|
-
literal: {
|
|
238
|
-
kind: "number",
|
|
239
|
-
value: literalToken.number
|
|
240
|
-
},
|
|
241
|
-
span: {
|
|
242
|
-
start: token.span.start,
|
|
243
|
-
end: literalToken.span.end
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
return fail("predicate-expected-literal", `expected a literal after ${op} — write ${token.text} ${op} 'value' or ${token.text} ${op} 5`, literalToken.span);
|
|
247
|
-
}
|
|
248
|
-
if (token.kind === "eof") return fail("predicate-unexpected-end", "unexpected end of predicate — expected a variable name, comparison, or ( group )", token.span);
|
|
249
|
-
return fail("predicate-unexpected-token", `unexpected ${token.text} — comparisons put the variable first: name == 'value'`, token.span);
|
|
250
|
-
};
|
|
251
|
-
const parseUnary = () => {
|
|
252
|
-
const token = peek();
|
|
253
|
-
if (isKeywordToken(token, "not")) {
|
|
254
|
-
advance();
|
|
255
|
-
const operand = parsePrimary();
|
|
256
|
-
if (operand === null) return null;
|
|
257
|
-
return {
|
|
258
|
-
kind: "not",
|
|
259
|
-
operand,
|
|
260
|
-
span: {
|
|
261
|
-
start: token.span.start,
|
|
262
|
-
end: operand.span.end
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return parsePrimary();
|
|
267
|
-
};
|
|
268
|
-
const parseAnd = () => {
|
|
269
|
-
let left = parseUnary();
|
|
270
|
-
while (left !== null && isKeywordToken(peek(), "and")) {
|
|
271
|
-
advance();
|
|
272
|
-
const right = parseUnary();
|
|
273
|
-
if (right === null) return null;
|
|
274
|
-
left = {
|
|
275
|
-
kind: "and",
|
|
276
|
-
left,
|
|
277
|
-
right,
|
|
278
|
-
span: {
|
|
279
|
-
start: left.span.start,
|
|
280
|
-
end: right.span.end
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
return left;
|
|
285
|
-
};
|
|
286
|
-
const parseOr = () => {
|
|
287
|
-
let left = parseAnd();
|
|
288
|
-
while (left !== null && isKeywordToken(peek(), "or")) {
|
|
289
|
-
advance();
|
|
290
|
-
const right = parseAnd();
|
|
291
|
-
if (right === null) return null;
|
|
292
|
-
left = {
|
|
293
|
-
kind: "or",
|
|
294
|
-
left,
|
|
295
|
-
right,
|
|
296
|
-
span: {
|
|
297
|
-
start: left.span.start,
|
|
298
|
-
end: right.span.end
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
return left;
|
|
303
|
-
};
|
|
304
|
-
if (source.trim().length === 0) return Result.fail([{
|
|
305
|
-
code: "predicate-empty",
|
|
306
|
-
message: "empty predicate — write e.g. plan == 'pro'",
|
|
307
|
-
span: {
|
|
308
|
-
start: baseOffset,
|
|
309
|
-
end: baseOffset + source.length
|
|
310
|
-
}
|
|
311
|
-
}]);
|
|
312
|
-
const ast = parseOr();
|
|
313
|
-
if (ast !== null && diagnostic === void 0) {
|
|
314
|
-
const trailing = peek();
|
|
315
|
-
if (trailing.kind !== "eof") fail("predicate-trailing-input", `unexpected ${JSON.stringify(trailing.text)} after the predicate — join clauses with "and" or "or"`, trailing.span);
|
|
316
|
-
}
|
|
317
|
-
if (ast === null || diagnostic !== void 0) return Result.fail([diagnostic ?? {
|
|
318
|
-
code: "predicate-parse-failed",
|
|
319
|
-
message: "predicate parse failed",
|
|
320
|
-
span: {
|
|
321
|
-
start: baseOffset,
|
|
322
|
-
end: baseOffset + source.length
|
|
323
|
-
}
|
|
324
|
-
}]);
|
|
325
|
-
return Result.succeed(ast);
|
|
326
|
-
};
|
|
327
|
-
const toNumber = (value) => {
|
|
328
|
-
if (typeof value === "number") return value;
|
|
329
|
-
if (typeof value === "string" && value.trim() !== "") return Number(value);
|
|
330
|
-
return NaN;
|
|
331
|
-
};
|
|
332
|
-
const compareNumbers = (op, left, right) => {
|
|
333
|
-
switch (op) {
|
|
334
|
-
case "==": return left === right;
|
|
335
|
-
case "!=": return left !== right;
|
|
336
|
-
case ">": return left > right;
|
|
337
|
-
case ">=": return left >= right;
|
|
338
|
-
case "<": return left < right;
|
|
339
|
-
case "<=": return left <= right;
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
const evaluateComparison = (node, variables) => {
|
|
343
|
-
const value = variables[node.name];
|
|
344
|
-
if (value === void 0 || value === null) return false;
|
|
345
|
-
if (node.literal.kind === "number") {
|
|
346
|
-
const left = toNumber(value);
|
|
347
|
-
if (Number.isNaN(left)) return false;
|
|
348
|
-
return compareNumbers(node.op, left, node.literal.value);
|
|
349
|
-
}
|
|
350
|
-
if (node.op === "==" || node.op === "!=") {
|
|
351
|
-
if (typeof value !== "string") return false;
|
|
352
|
-
return node.op === "==" ? value === node.literal.value : value !== node.literal.value;
|
|
353
|
-
}
|
|
354
|
-
const left = toNumber(value);
|
|
355
|
-
const right = toNumber(node.literal.value);
|
|
356
|
-
if (Number.isNaN(left) || Number.isNaN(right)) return false;
|
|
357
|
-
return compareNumbers(node.op, left, right);
|
|
358
|
-
};
|
|
359
|
-
const evaluatePredicate = (ast, variables) => {
|
|
360
|
-
switch (ast.kind) {
|
|
361
|
-
case "or": return evaluatePredicate(ast.left, variables) || evaluatePredicate(ast.right, variables);
|
|
362
|
-
case "and": return evaluatePredicate(ast.left, variables) && evaluatePredicate(ast.right, variables);
|
|
363
|
-
case "not": return !evaluatePredicate(ast.operand, variables);
|
|
364
|
-
case "comparison": return evaluateComparison(ast, variables);
|
|
365
|
-
case "name": {
|
|
366
|
-
const value = variables[ast.name];
|
|
367
|
-
return value !== void 0 && value !== null && value !== "";
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
const precedence = (node) => {
|
|
372
|
-
switch (node.kind) {
|
|
373
|
-
case "or": return 1;
|
|
374
|
-
case "and": return 2;
|
|
375
|
-
case "not": return 3;
|
|
376
|
-
case "comparison":
|
|
377
|
-
case "name": return 4;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
const printLiteral = (literal) => literal.kind === "string" ? `'${literal.value}'` : String(literal.value);
|
|
381
|
-
const printNode = (node, minPrecedence) => {
|
|
382
|
-
const wrap = (text) => precedence(node) < minPrecedence ? `(${text})` : text;
|
|
383
|
-
switch (node.kind) {
|
|
384
|
-
case "or": return wrap(`${printNode(node.left, 1)} or ${printNode(node.right, 1)}`);
|
|
385
|
-
case "and": return wrap(`${printNode(node.left, 2)} and ${printNode(node.right, 2)}`);
|
|
386
|
-
case "not": return wrap(`not ${printNode(node.operand, 4)}`);
|
|
387
|
-
case "comparison": return wrap(`${node.name} ${node.op} ${printLiteral(node.literal)}`);
|
|
388
|
-
case "name": return wrap(node.name);
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
/** Canonical form: single space around operators/keywords, minimal parens. */
|
|
392
|
-
const printPredicate = (ast) => printNode(ast, 0);
|
|
393
|
-
const collectPredicateVariables = (ast) => {
|
|
394
|
-
const names = /* @__PURE__ */ new Set();
|
|
395
|
-
const visit = (node) => {
|
|
396
|
-
switch (node.kind) {
|
|
397
|
-
case "or":
|
|
398
|
-
case "and":
|
|
399
|
-
visit(node.left);
|
|
400
|
-
visit(node.right);
|
|
401
|
-
return;
|
|
402
|
-
case "not":
|
|
403
|
-
visit(node.operand);
|
|
404
|
-
return;
|
|
405
|
-
case "comparison":
|
|
406
|
-
case "name":
|
|
407
|
-
names.add(node.name);
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
visit(ast);
|
|
412
|
-
return names;
|
|
413
|
-
};
|
|
414
|
-
//#endregion
|
|
415
|
-
export { collectPredicateVariables, evaluatePredicate, parsePredicate, printPredicate };
|
|
416
|
-
|
|
417
|
-
//# sourceMappingURL=predicate.js.map
|
|
1
|
+
import { a as printPredicate, i as parsePredicate, n as collectPredicateVariables, r as evaluatePredicate, t as PREDICATE_PARSER_LIMITS } from "./predicate-CvkzT-a2.js";
|
|
2
|
+
export { PREDICATE_PARSER_LIMITS, collectPredicateVariables, evaluatePredicate, parsePredicate, printPredicate };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PresetCategory } from "../presets.js";
|
|
2
|
-
import { TemplateCollectionId } from "
|
|
2
|
+
import { i as TemplateCollectionId } from "../public-gallery-D0Zv0pZE.js";
|
|
3
3
|
//#region presets/category-mapping.d.ts
|
|
4
4
|
declare const LAB_DIMENSIONS: readonly ["newsletter", "receipt", "security", "product-update", "onboarding", "promotion", "shipping", "social-notification"];
|
|
5
5
|
type LabDimension = (typeof LAB_DIMENSIONS)[number];
|