@stll/template-conditions 0.6.2 → 0.6.3
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/index.d.ts +4 -1
- package/dist/index.js +28 -14
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { CompareNode, CompareOp, Condition, ConditionNode, ConditionNode as Cond
|
|
|
4
4
|
export declare const resolvePath: (path: string, data: Record<string, unknown>) => unknown;
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region src/parse.d.ts
|
|
7
|
+
/** Maximum combined nesting of parentheses and unary negation. */
|
|
8
|
+
export declare const MAX_CONDITION_NESTING = 256;
|
|
7
9
|
/** Bare words the tokenizer reads as operators or literals; a data path can
|
|
8
10
|
* never be one of them. */
|
|
9
11
|
export declare const CONDITION_RESERVED_WORDS: readonly ["and", "or", "not", "in", "is", "defined", "true", "false"];
|
|
@@ -349,7 +351,8 @@ type InvalidMarker = {
|
|
|
349
351
|
*/
|
|
350
352
|
export declare const scanInvalidMarkers: (text: string) => InvalidMarker[];
|
|
351
353
|
/** The loop alias the codemod (and the legacy-marker message) generates for a
|
|
352
|
-
* `{{#each path}}`: the singular of the last plain-word segment, else `item`.
|
|
354
|
+
* `{{#each path}}`: the singular of the last plain-word segment, else `item`.
|
|
355
|
+
* A fresh `{% for %}` inserted by the Studio names its item by the same rule. */
|
|
353
356
|
export declare const legacyLoopAlias: (path: string) => string;
|
|
354
357
|
/** Translate an old-dialect condition expression to the Jinja surface:
|
|
355
358
|
* `!a` becomes `not a`, `a contains "x"` becomes `"x" in a`. */
|
package/dist/index.js
CHANGED
|
@@ -191,6 +191,8 @@ const evaluateNumericExpression = (expression, data) => {
|
|
|
191
191
|
};
|
|
192
192
|
//#endregion
|
|
193
193
|
//#region src/parse.ts
|
|
194
|
+
/** Maximum combined nesting of parentheses and unary negation. */
|
|
195
|
+
const MAX_CONDITION_NESTING = 256;
|
|
194
196
|
const COMPARE_SYMBOL_TO_OP = {
|
|
195
197
|
"==": "eq",
|
|
196
198
|
"!=": "neq",
|
|
@@ -325,13 +327,16 @@ const parseCondition = (expression) => {
|
|
|
325
327
|
if (tokens.length === 0) return null;
|
|
326
328
|
let pos = 0;
|
|
327
329
|
const peek = () => tokens[pos];
|
|
328
|
-
const parseOr = () => {
|
|
329
|
-
const first = parseAnd();
|
|
330
|
+
const parseOr = (depth) => {
|
|
331
|
+
const first = parseAnd(depth);
|
|
332
|
+
if (first === null) return null;
|
|
330
333
|
if (peek()?.type !== "or") return first;
|
|
331
334
|
const children = [first];
|
|
332
335
|
while (peek()?.type === "or") {
|
|
333
336
|
pos += 1;
|
|
334
|
-
|
|
337
|
+
const child = parseAnd(depth);
|
|
338
|
+
if (child === null) return null;
|
|
339
|
+
children.push(child);
|
|
335
340
|
}
|
|
336
341
|
return {
|
|
337
342
|
type: "group",
|
|
@@ -339,13 +344,16 @@ const parseCondition = (expression) => {
|
|
|
339
344
|
children
|
|
340
345
|
};
|
|
341
346
|
};
|
|
342
|
-
const parseAnd = () => {
|
|
343
|
-
const first = parseNot();
|
|
347
|
+
const parseAnd = (depth) => {
|
|
348
|
+
const first = parseNot(depth);
|
|
349
|
+
if (first === null) return null;
|
|
344
350
|
if (peek()?.type !== "and") return first;
|
|
345
351
|
const children = [first];
|
|
346
352
|
while (peek()?.type === "and") {
|
|
347
353
|
pos += 1;
|
|
348
|
-
|
|
354
|
+
const child = parseNot(depth);
|
|
355
|
+
if (child === null) return null;
|
|
356
|
+
children.push(child);
|
|
349
357
|
}
|
|
350
358
|
return {
|
|
351
359
|
type: "group",
|
|
@@ -353,22 +361,27 @@ const parseCondition = (expression) => {
|
|
|
353
361
|
children
|
|
354
362
|
};
|
|
355
363
|
};
|
|
356
|
-
const parseNot = () => {
|
|
364
|
+
const parseNot = (depth) => {
|
|
357
365
|
if (peek()?.type === "not") {
|
|
366
|
+
if (depth >= 256) return null;
|
|
358
367
|
pos += 1;
|
|
368
|
+
const child = parseNot(depth + 1);
|
|
369
|
+
if (child === null) return null;
|
|
359
370
|
return {
|
|
360
371
|
type: "group",
|
|
361
372
|
combinator: "and",
|
|
362
373
|
negated: true,
|
|
363
|
-
children: [
|
|
374
|
+
children: [child]
|
|
364
375
|
};
|
|
365
376
|
}
|
|
366
|
-
return parseComparison();
|
|
377
|
+
return parseComparison(depth);
|
|
367
378
|
};
|
|
368
|
-
const parseComparison = () => {
|
|
379
|
+
const parseComparison = (depth) => {
|
|
369
380
|
if (peek()?.type === "lparen") {
|
|
381
|
+
if (depth >= 256) return null;
|
|
370
382
|
pos += 1;
|
|
371
|
-
const inner = parseOr();
|
|
383
|
+
const inner = parseOr(depth + 1);
|
|
384
|
+
if (inner === null) return null;
|
|
372
385
|
if (peek()?.type === "rparen") pos += 1;
|
|
373
386
|
return inner;
|
|
374
387
|
}
|
|
@@ -437,7 +450,7 @@ const parseCondition = (expression) => {
|
|
|
437
450
|
right: operandFromToken(rightTok)
|
|
438
451
|
};
|
|
439
452
|
};
|
|
440
|
-
return parseOr();
|
|
453
|
+
return parseOr(0);
|
|
441
454
|
};
|
|
442
455
|
//#endregion
|
|
443
456
|
//#region src/referenced-paths.ts
|
|
@@ -1183,7 +1196,8 @@ const singularize = (segment) => {
|
|
|
1183
1196
|
return segment;
|
|
1184
1197
|
};
|
|
1185
1198
|
/** The loop alias the codemod (and the legacy-marker message) generates for a
|
|
1186
|
-
* `{{#each path}}`: the singular of the last plain-word segment, else `item`.
|
|
1199
|
+
* `{{#each path}}`: the singular of the last plain-word segment, else `item`.
|
|
1200
|
+
* A fresh `{% for %}` inserted by the Studio names its item by the same rule. */
|
|
1187
1201
|
const legacyLoopAlias = (path) => {
|
|
1188
1202
|
const segment = path.split(".").at(-1) ?? "";
|
|
1189
1203
|
if (!IDENTIFIER_RE.test(segment)) return "item";
|
|
@@ -1713,4 +1727,4 @@ const evaluateCondition = (expression, data, namedConditions, _resolved = /* @__
|
|
|
1713
1727
|
return evaluateCondition$1(node, makeResolver(data, namedConditions, _resolved, _depth));
|
|
1714
1728
|
};
|
|
1715
1729
|
//#endregion
|
|
1716
|
-
export { ARRAY_FILTER_NAMES, BLOCK_DIRECTIVE_KINDS, CONDITION_RESERVED_WORDS, DATE_FORMAT_EXAMPLE_ISO, DATE_FORMAT_STYLES, DIRECTIVE_KINDS, FILTER_NAMES, LOOP_PROPERTIES, MARKER_DEFECT_KINDS, MARKER_OUTPUT_BODY, MARKER_STATEMENT_BODY, MAX_CONDITION_DEPTH, NUMERIC_FUNCTION_NAMES, arrayFiltersFromFieldConfig, assertNever, blockDirectiveLinePattern, classifyMarker, classifyMarkerDefect, clauseSlotKey, clauseSlotPattern, conditionHasFormula, conditionNodeSchema, conditionSchema, detectRowBlockPair, emptyCondition, evaluateCondition, evaluateNumericExpression, filtersFromFieldConfig, formatDate, hasBlockDirectivePattern, hasNumberingPattern, isArrayFilterName, isBlockDirectiveKind, isClauseSlotName, isFieldPath, isSafeFieldPath, legacyLoopAlias, legacyMarkerReplacement, loopPattern, markerPattern, normalizeMarkerInner, numPattern, parseCondition, placeholderPattern, qualifyLoopPath, qualifyRowScopedPath, qualifyRowScopedPlaceholder, refPattern, referencedConditionPaths, renderConditionTag, renderDeterministicFieldValue, renderFilterChain, renderForOpener, renderValueMarker, replaceOutputMarkers, resolvePath, rowScopePaths, scanInvalidMarkers, scanMarkers, serializeCondition, substitutionKey, translateLegacyExpression, unwritableFilterValues, unwritableMarkerLiteral };
|
|
1730
|
+
export { ARRAY_FILTER_NAMES, BLOCK_DIRECTIVE_KINDS, CONDITION_RESERVED_WORDS, DATE_FORMAT_EXAMPLE_ISO, DATE_FORMAT_STYLES, DIRECTIVE_KINDS, FILTER_NAMES, LOOP_PROPERTIES, MARKER_DEFECT_KINDS, MARKER_OUTPUT_BODY, MARKER_STATEMENT_BODY, MAX_CONDITION_DEPTH, MAX_CONDITION_NESTING, NUMERIC_FUNCTION_NAMES, arrayFiltersFromFieldConfig, assertNever, blockDirectiveLinePattern, classifyMarker, classifyMarkerDefect, clauseSlotKey, clauseSlotPattern, conditionHasFormula, conditionNodeSchema, conditionSchema, detectRowBlockPair, emptyCondition, evaluateCondition, evaluateNumericExpression, filtersFromFieldConfig, formatDate, hasBlockDirectivePattern, hasNumberingPattern, isArrayFilterName, isBlockDirectiveKind, isClauseSlotName, isFieldPath, isSafeFieldPath, legacyLoopAlias, legacyMarkerReplacement, loopPattern, markerPattern, normalizeMarkerInner, numPattern, parseCondition, placeholderPattern, qualifyLoopPath, qualifyRowScopedPath, qualifyRowScopedPlaceholder, refPattern, referencedConditionPaths, renderConditionTag, renderDeterministicFieldValue, renderFilterChain, renderForOpener, renderValueMarker, replaceOutputMarkers, resolvePath, rowScopePaths, scanInvalidMarkers, scanMarkers, serializeCondition, substitutionKey, translateLegacyExpression, unwritableFilterValues, unwritableMarkerLiteral };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/template-conditions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "A document-template marker and condition engine: {{...}} marker grammar, parse, compute, serialize, field values.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"condition",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test": "bun test",
|
|
44
44
|
"test:property": "bun test --preload @stll/property-testing/preload $(grep -rlF 'fc.assert' src --include='*.test.ts')",
|
|
45
45
|
"typecheck": "bun ../../packages/scripts/src/tsc-native.ts --noEmit",
|
|
46
|
-
"lint": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --report-unused-disable-directives-severity=error --type-aware packages/template-conditions",
|
|
46
|
+
"lint": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --report-unused-disable-directives-severity=error --type-aware --type-check packages/template-conditions",
|
|
47
47
|
"lint:fix": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --type-aware --fix packages/template-conditions",
|
|
48
48
|
"format": "bun ../../scripts/run-oxfmt.ts .",
|
|
49
49
|
"prepack": "bun run build"
|