@stll/template-conditions 0.6.3 → 0.6.5

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 CHANGED
@@ -1,17 +1,11 @@
1
1
  import { CompareNode, CompareOp, Condition, ConditionNode, ConditionNode as ConditionNode$1, GroupNode, Operand, PredicateNode, PredicateOp, conditionHasFormula, conditionNodeSchema, conditionSchema, emptyCondition } from "@stll/conditions";
2
- //#region src/path.d.ts
3
- /** Resolve a dotted path like `company.name` against data. */
4
- export declare const resolvePath: (path: string, data: Record<string, unknown>) => unknown;
5
- //#endregion
6
- //#region src/parse.d.ts
2
+ import { resolvePath } from "./path.js";
7
3
  /** Maximum combined nesting of parentheses and unary negation. */
8
4
  export declare const MAX_CONDITION_NESTING = 256;
9
5
  /** Bare words the tokenizer reads as operators or literals; a data path can
10
6
  * never be one of them. */
11
7
  export declare const CONDITION_RESERVED_WORDS: readonly ["and", "or", "not", "in", "is", "defined", "true", "false"];
12
8
  export declare const parseCondition: (expression: string) => ConditionNode$1 | null;
13
- //#endregion
14
- //#region src/referenced-paths.d.ts
15
9
  /**
16
10
  * What a `{% if %}` expression reads. Structural, not evaluative: the paths a
17
11
  * condition depends on, for callers that decide something about the condition
@@ -26,8 +20,6 @@ export declare const parseCondition: (expression: string) => ConditionNode$1 | n
26
20
  * nothing".
27
21
  */
28
22
  export declare const referencedConditionPaths: (expression: string) => string[] | null;
29
- //#endregion
30
- //#region src/compute.d.ts
31
23
  /**
32
24
  * Arithmetic evaluator for computed template fields.
33
25
  *
@@ -48,8 +40,6 @@ export declare const referencedConditionPaths: (expression: string) => string[]
48
40
  export declare const NUMERIC_FUNCTION_NAMES: readonly ["min", "max", "round", "abs", "floor", "ceil"];
49
41
  type NumericFunctionName = (typeof NUMERIC_FUNCTION_NAMES)[number];
50
42
  export declare const evaluateNumericExpression: (expression: string, data: Record<string, unknown>) => number | undefined;
51
- //#endregion
52
- //#region src/field-values.d.ts
53
43
  /**
54
44
  * Single source of truth for the DETERMINISTIC field-value transforms a
55
45
  * template fill applies: formula (arithmetic over the other values) and
@@ -115,16 +105,12 @@ type DeterministicFieldConfig = {
115
105
  * value, so the caller leaves the field as-is.
116
106
  */
117
107
  export declare const renderDeterministicFieldValue: (field: DeterministicFieldConfig, values: Record<string, unknown>) => string | null;
118
- //#endregion
119
- //#region src/condition-builder.d.ts
120
108
  /**
121
109
  * Serialize a condition tree into an expression for `evaluateCondition`.
122
110
  * Returns an empty string for an empty tree (caller treats that as "no
123
111
  * condition" / always-visible).
124
112
  */
125
113
  export declare const serializeCondition: (node: ConditionNode$1) => string;
126
- //#endregion
127
- //#region src/markers.d.ts
128
114
  /**
129
115
  * Canonical grammar for the docxtpl dialect of Jinja — the single source of
130
116
  * truth shared by the fill pipeline (api), the editor highlighter (folio), and
@@ -388,8 +374,6 @@ type MarkerDefect = {
388
374
  export declare const classifyMarkerDefect: (innerRaw: string, form?: MarkerForm) => MarkerDefect | null;
389
375
  /** Exhaustiveness guard — pass the discriminant in a `switch` default branch. */
390
376
  export declare const assertNever: (value: never) => never;
391
- //#endregion
392
- //#region src/loop-scope.d.ts
393
377
  /**
394
378
  * The path a marker names, once the loops around it are taken into account.
395
379
  *
@@ -418,8 +402,6 @@ export declare const qualifyRowScopedPath: (path: string, rowPaths?: readonly st
418
402
  export declare const qualifyRowScopedPlaceholder: (path: string, rowScopes: readonly RowScope[]) => string;
419
403
  /** The manifest path for an array a `{% for %}` opens inside these loops. */
420
404
  export declare const qualifyLoopPath: (declaredPath: string, rowScopes: readonly RowScope[]) => string;
421
- //#endregion
422
- //#region src/field-config.d.ts
423
405
  /** Where a field's value comes from, when a record supplies it. Only the shape
424
406
  * the filters read: each caller's own union satisfies it. */
425
407
  type MarkerFieldSource = {
@@ -503,8 +485,6 @@ export declare const filtersFromFieldConfig: (field: MarkerFieldConfig) => Filte
503
485
  * value filter can never be written where the reader refuses it.
504
486
  */
505
487
  export declare const arrayFiltersFromFieldConfig: (field: MarkerFieldConfig) => FilterCall[];
506
- //#endregion
507
- //#region src/render.d.ts
508
488
  /** Why a value has no spelling the scanner reads back as itself. */
509
489
  type UnwritableReason = "tag-delimiter" | "number-spelling";
510
490
  /** The reason this literal cannot be written in a marker of this form, or
@@ -561,8 +541,6 @@ type ForOpenerOptions = {
561
541
  };
562
542
  /** One `{% for %}` opener, keeping its placement prefix. */
563
543
  export declare const renderForOpener: ({ alias, filters, path, prefix }: ForOpenerOptions) => string;
564
- //#endregion
565
- //#region src/row-blocks.d.ts
566
544
  /** One end of a row block, addressed within the row that was scanned. */
567
545
  type RowBlockMarker = {
568
546
  /** Index into the row's cells. */
@@ -589,8 +567,6 @@ type RowBlockPair = {
589
567
  * engine's existing structure errors rather than guessed at.
590
568
  */
591
569
  export declare const detectRowBlockPair: (cells: readonly (readonly string[])[]) => RowBlockPair | null;
592
- //#endregion
593
- //#region src/index.d.ts
594
570
  export type NamedCondition = {
595
571
  name: string;
596
572
  /** The `{% if %}` expression string. Authoritative unless `node` is set. */
@@ -623,5 +599,4 @@ export declare const MAX_CONDITION_DEPTH = 50;
623
599
  * branch true).
624
600
  */
625
601
  export declare const evaluateCondition: (expression: string, data: Record<string, unknown>, namedConditions?: readonly NamedCondition[], _resolved?: ReadonlySet<string>, _depth?: number) => boolean;
626
- //#endregion
627
- export { type BlockDirectiveKind, type CompareNode, type CompareOp, type Condition, type ConditionNode, type ConditionTagOptions, type DateFormatStyle, type DeterministicFieldConfig, type DirectiveKind, type FieldDateFormat, type FilterArgument, type FilterCall, type FilterName, type ForOpenerOptions, type GroupNode, type InvalidMarker, type LoopProperty, type MarkerDefect, type MarkerDefectKind, type MarkerFieldConfig, type MarkerFieldInputType, type MarkerFieldLookup, type MarkerFieldSource, type MarkerFieldValidation, type MarkerForm, type MarkerLiteral, type MarkerMeta, type MarkerPrefix, type NumericFunctionName, type Operand, type PredicateNode, type PredicateOp, type RowBlockMarker, type RowBlockPair, type RowScope, type ScannedMarker, type UnwritableReason, conditionHasFormula, conditionNodeSchema, conditionSchema, emptyCondition };
602
+ export { type BlockDirectiveKind, type CompareNode, type CompareOp, type Condition, type ConditionNode, type ConditionTagOptions, type DateFormatStyle, type DeterministicFieldConfig, type DirectiveKind, type FieldDateFormat, type FilterArgument, type FilterCall, type FilterName, type ForOpenerOptions, type GroupNode, type InvalidMarker, type LoopProperty, type MarkerDefect, type MarkerDefectKind, type MarkerFieldConfig, type MarkerFieldInputType, type MarkerFieldLookup, type MarkerFieldSource, type MarkerFieldValidation, type MarkerForm, type MarkerLiteral, type MarkerMeta, type MarkerPrefix, type NumericFunctionName, type Operand, type PredicateNode, type PredicateOp, type RowBlockMarker, type RowBlockPair, type RowScope, type ScannedMarker, type UnwritableReason, conditionHasFormula, conditionNodeSchema, conditionSchema, emptyCondition, resolvePath };
package/dist/index.js CHANGED
@@ -1,34 +1,8 @@
1
+ import { resolvePath } from "./path.js";
1
2
  import { conditionHasFormula, conditionNodeSchema, conditionSchema, emptyCondition, evaluateCondition as evaluateCondition$1 } from "@stll/conditions";
2
3
  import { Result, panic } from "better-result";
3
4
  import { Temporal } from "temporal-polyfill/full";
4
- //#region src/path.ts
5
- /**
6
- * Dotted-path resolution against a data record. Extracted from index.ts so both
7
- * the condition engine (index.ts) and the arithmetic evaluator (compute.ts) can
8
- * import it without a dependency cycle.
9
- */
10
- /**
11
- * Narrow `unknown` to something a path segment can be read from.
12
- *
13
- * Unlike the same-named predicates that screen JSON payload shapes, this one
14
- * accepts arrays on purpose: a dotted path segment may be an array index
15
- * (`parties.1.name`), and rejecting arrays would silently resolve those to
16
- * `undefined`.
17
- */
18
- const isNonNullObject = (v) => typeof v === "object" && v !== null;
19
- /** Resolve a dotted path like `company.name` against data. */
20
- const resolvePath = (path, data) => {
21
- if (Object.hasOwn(data, path)) return data[path];
22
- const parts = path.split(".");
23
- let current = data;
24
- for (const part of parts) {
25
- if (!isNonNullObject(current)) return;
26
- current = current[part];
27
- }
28
- return current;
29
- };
30
- //#endregion
31
- //#region src/compute.ts
5
+ // src/compute.ts
32
6
  /**
33
7
  * Arithmetic evaluator for computed template fields.
34
8
  *
@@ -189,8 +163,7 @@ const evaluateNumericExpression = (expression, data) => {
189
163
  return;
190
164
  }
191
165
  };
192
- //#endregion
193
- //#region src/parse.ts
166
+ // src/parse.ts
194
167
  /** Maximum combined nesting of parentheses and unary negation. */
195
168
  const MAX_CONDITION_NESTING = 256;
196
169
  const COMPARE_SYMBOL_TO_OP = {
@@ -452,8 +425,7 @@ const parseCondition = (expression) => {
452
425
  };
453
426
  return parseOr(0);
454
427
  };
455
- //#endregion
456
- //#region src/referenced-paths.ts
428
+ // src/referenced-paths.ts
457
429
  const operandsOf = (node) => node.type === "compare" ? [node.left, node.right] : [node.operand];
458
430
  /** Every field path the tree reads, or `null` when an operand names something
459
431
  * whose own references cannot be enumerated (a formula over other fields). */
@@ -486,8 +458,7 @@ const referencedConditionPaths = (expression) => {
486
458
  const node = parseCondition(expression);
487
459
  return node === null ? null : nodePaths(node);
488
460
  };
489
- //#endregion
490
- //#region src/field-values.ts
461
+ // src/field-values.ts
491
462
  /**
492
463
  * Single source of truth for the DETERMINISTIC field-value transforms a
493
464
  * template fill applies: formula (arithmetic over the other values) and
@@ -586,8 +557,7 @@ const renderDeterministicFieldValue = (field, values) => {
586
557
  }
587
558
  return null;
588
559
  };
589
- //#endregion
590
- //#region src/condition-builder.ts
560
+ // src/condition-builder.ts
591
561
  const COMPARE_OP_TO_SYMBOL = {
592
562
  eq: "==",
593
563
  neq: "!=",
@@ -644,8 +614,7 @@ const serializeNode = (node, top) => {
644
614
  * condition" / always-visible).
645
615
  */
646
616
  const serializeCondition = (node) => serializeNode(node, true);
647
- //#endregion
648
- //#region src/markers.ts
617
+ // src/markers.ts
649
618
  /**
650
619
  * Canonical grammar for the docxtpl dialect of Jinja — the single source of
651
620
  * truth shared by the fill pipeline (api), the editor highlighter (folio), and
@@ -1324,8 +1293,7 @@ const classifyMarkerDefect = (innerRaw, form = "output") => {
1324
1293
  };
1325
1294
  /** Exhaustiveness guard — pass the discriminant in a `switch` default branch. */
1326
1295
  const assertNever = (value) => panic(`Unhandled template directive: ${JSON.stringify(value)}`);
1327
- //#endregion
1328
- //#region src/loop-scope.ts
1296
+ // src/loop-scope.ts
1329
1297
  const rowScopePaths = (rowScopes) => rowScopes.map(({ scopedPath }) => scopedPath);
1330
1298
  /** A path already under the innermost repeat is left alone; anything else is
1331
1299
  * read as a name relative to it. */
@@ -1345,8 +1313,7 @@ const qualifyRowScopedPlaceholder = (path, rowScopes) => {
1345
1313
  };
1346
1314
  /** The manifest path for an array a `{% for %}` opens inside these loops. */
1347
1315
  const qualifyLoopPath = (declaredPath, rowScopes) => qualifyRowScopedPath(qualifyRowScopedPlaceholder(declaredPath, rowScopes), rowScopePaths(rowScopes));
1348
- //#endregion
1349
- //#region src/field-config.ts
1316
+ // src/field-config.ts
1350
1317
  /**
1351
1318
  * The filters that describe a REPEAT rather than a value: how many rows it
1352
1319
  * takes and what to call it. These are the ones a `{% for %}` tag may carry,
@@ -1468,8 +1435,7 @@ const filtersFromFieldConfig = (field) => Object.values(MARKER_FIELD_FILTERS).fl
1468
1435
  * value filter can never be written where the reader refuses it.
1469
1436
  */
1470
1437
  const arrayFiltersFromFieldConfig = (field) => filtersFromFieldConfig(field).filter(({ name }) => isArrayFilterName(name));
1471
- //#endregion
1472
- //#region src/render.ts
1438
+ // src/render.ts
1473
1439
  /** The number literals the scanner reads: no exponent, no `Infinity`. */
1474
1440
  const WRITABLE_NUMBER = /^-?\d+(?:\.\d+)?$/u;
1475
1441
  /** What a tag's body cannot carry: it has no quoted-run escape hatch, so a
@@ -1542,8 +1508,7 @@ const renderForOpener = ({ alias, filters, path, prefix }) => {
1542
1508
  const head = `{%${PREFIX_TOKEN[prefix]} for ${alias} in ${path}`;
1543
1509
  return chain === "" ? `${head} %}` : `${head} | ${chain} %}`;
1544
1510
  };
1545
- //#endregion
1546
- //#region src/row-blocks.ts
1511
+ // src/row-blocks.ts
1547
1512
  /**
1548
1513
  * Row-form block markers: the lenient placement authoring agents actually
1549
1514
  * write for a "one row per item" table.
@@ -1652,8 +1617,7 @@ const detectRowBlockPair = (cells) => {
1652
1617
  close
1653
1618
  };
1654
1619
  };
1655
- //#endregion
1656
- //#region src/index.ts
1620
+ // src/index.ts
1657
1621
  /**
1658
1622
  * Shared condition evaluation + marker grammar for DOCX templates. Small,
1659
1623
  * side-effect-free functions usable on both backend (Bun) and frontend
@@ -1726,5 +1690,4 @@ const evaluateCondition = (expression, data, namedConditions, _resolved = /* @__
1726
1690
  if (node === null) return false;
1727
1691
  return evaluateCondition$1(node, makeResolver(data, namedConditions, _resolved, _depth));
1728
1692
  };
1729
- //#endregion
1730
1693
  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/dist/path.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Dotted-path resolution against a data record. Extracted from index.ts so both
3
+ * the condition engine (index.ts) and the arithmetic evaluator (compute.ts) can
4
+ * import it without a dependency cycle.
5
+ */
6
+ /**
7
+ * Narrow `unknown` to something a path segment can be read from.
8
+ *
9
+ * Accepts arrays and class instances. A dotted path segment may be an array index
10
+ * (`parties.1.name`), and rejecting arrays would silently resolve those to
11
+ * `undefined`.
12
+ */
13
+ export declare const isNonNullObject: (v: unknown) => v is Record<string, unknown>;
14
+ /** Resolve a dotted path like `company.name` against data. */
15
+ export declare const resolvePath: (path: string, data: Record<string, unknown>) => unknown;
package/dist/path.js ADDED
@@ -0,0 +1,26 @@
1
+ // src/path.ts
2
+ /**
3
+ * Dotted-path resolution against a data record. Extracted from index.ts so both
4
+ * the condition engine (index.ts) and the arithmetic evaluator (compute.ts) can
5
+ * import it without a dependency cycle.
6
+ */
7
+ /**
8
+ * Narrow `unknown` to something a path segment can be read from.
9
+ *
10
+ * Accepts arrays and class instances. A dotted path segment may be an array index
11
+ * (`parties.1.name`), and rejecting arrays would silently resolve those to
12
+ * `undefined`.
13
+ */
14
+ const isNonNullObject = (v) => typeof v === "object" && v !== null;
15
+ /** Resolve a dotted path like `company.name` against data. */
16
+ const resolvePath = (path, data) => {
17
+ if (Object.hasOwn(data, path)) return data[path];
18
+ const parts = path.split(".");
19
+ let current = data;
20
+ for (const part of parts) {
21
+ if (!isNonNullObject(current)) return;
22
+ current = current[part];
23
+ }
24
+ return current;
25
+ };
26
+ export { isNonNullObject, resolvePath };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/template-conditions",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "A document-template marker and condition engine: {{...}} marker grammar, parse, compute, serialize, field values.",
5
5
  "keywords": [
6
6
  "condition",
@@ -31,6 +31,10 @@
31
31
  ".": {
32
32
  "types": "./dist/index.d.ts",
33
33
  "import": "./dist/index.js"
34
+ },
35
+ "./path": {
36
+ "types": "./dist/path.d.ts",
37
+ "import": "./dist/path.js"
34
38
  }
35
39
  },
36
40
  "publishConfig": {
@@ -41,24 +45,24 @@
41
45
  "build": "tsdown",
42
46
  "pack:dry-run": "bun pm pack --dry-run",
43
47
  "test": "bun test",
44
- "test:property": "bun test --preload @stll/property-testing/preload $(grep -rlF 'fc.assert' src --include='*.test.ts')",
45
- "typecheck": "bun ../../packages/scripts/src/tsc-native.ts --noEmit",
48
+ "test:property": "bun test --preload @stll/property-testing/preload $(grep -rlE 'fc\\.assert|assertProperty' src --include='*.test.ts')",
49
+ "typecheck": "bun check --no-pretty --all --project=tsconfig.json",
46
50
  "lint": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --report-unused-disable-directives-severity=error --type-aware --type-check packages/template-conditions",
47
51
  "lint:fix": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --type-aware --fix packages/template-conditions",
48
- "format": "bun ../../scripts/run-oxfmt.ts .",
49
52
  "prepack": "bun run build"
50
53
  },
51
54
  "dependencies": {
52
55
  "@stll/conditions": "^0.4.0",
53
56
  "better-result": "3.0.1",
54
- "temporal-polyfill": "1.0.5"
57
+ "temporal-polyfill": "1.0.6"
55
58
  },
56
59
  "devDependencies": {
57
60
  "@stll/property-testing": "0.0.0",
58
61
  "@stll/typescript-config": "0.0.0",
59
- "bun-types": "1.4.2",
60
- "fast-check": "^4.10.1",
61
- "tsdown": "0.23.0"
62
+ "bun-types": "1.4.4",
63
+ "fast-check": "^4.10.2",
64
+ "tsdown": "0.23.4",
65
+ "tsrs": "0.20.1-ts7.1.0-beta"
62
66
  },
63
67
  "main": "./dist/index.js",
64
68
  "types": "./dist/index.d.ts"