@coldsmirk/abacus-core 0.10.0 → 0.12.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.
package/dist/index.cjs CHANGED
@@ -361,7 +361,7 @@ function isZenConsistentNumber(value) {
361
361
  const SUBJECT_PATTERN = /^[A-Z_$][\w$]*(?:\.[A-Z_$][\w$]*|\[\d+\])*$/i;
362
362
  const SUBJECT_IDENTIFIER_PATTERN = /[A-Z_$][\w$]*/gi;
363
363
  const SUBJECT_INDEX_PATTERN = /\[(?<index>\d+)\]/g;
364
- const ZEN_ROOT_RESERVED_WORDS = new Set([
364
+ const ZEN_RESERVED_WORDS = /* @__PURE__ */ new Set([
365
365
  "and",
366
366
  "or",
367
367
  "not",
@@ -370,11 +370,14 @@ const ZEN_ROOT_RESERVED_WORDS = new Set([
370
370
  "false",
371
371
  "null"
372
372
  ]);
373
- const ZEN_MEMBER_RESERVED_WORDS = new Set(["true", "false"]);
373
+ const ZEN_MEMBER_RESERVED_WORDS = /* @__PURE__ */ new Set(["true", "false"]);
374
+ function isZenReservedWord(word) {
375
+ return ZEN_RESERVED_WORDS.has(word);
376
+ }
374
377
  function isIdentifierPath(subject) {
375
378
  if (!SUBJECT_PATTERN.test(subject)) return false;
376
379
  const [root, ...members] = subject.match(SUBJECT_IDENTIFIER_PATTERN) ?? [];
377
- if (root === void 0 || ZEN_ROOT_RESERVED_WORDS.has(root) || members.some((member) => ZEN_MEMBER_RESERVED_WORDS.has(member))) return false;
380
+ if (root === void 0 || isZenReservedWord(root) || members.some((member) => ZEN_MEMBER_RESERVED_WORDS.has(member))) return false;
378
381
  for (const match of subject.matchAll(SUBJECT_INDEX_PATTERN)) if (match.groups?.index === void 0 || !isZenUnsignedIntegerText(match.groups.index)) return false;
379
382
  return true;
380
383
  }
@@ -640,23 +643,23 @@ function compileRule(rule) {
640
643
  function matchesOperatorArity(rule) {
641
644
  switch (conditionOperatorArity(rule.operator)) {
642
645
  case "scalar": return isConditionScalar(rule.right);
643
- case "array": return isScalarArray(rule.right);
646
+ case "array": return isConditionScalarArray(rule.right);
644
647
  case "none": return rule.right === void 0;
645
648
  }
646
649
  }
647
650
  function isConditionScalar(value) {
648
651
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
649
652
  }
650
- function isScalarArray(value) {
653
+ function isConditionScalarArray(value) {
651
654
  return isArray(value) && value.every((item) => isConditionScalar(item));
652
655
  }
653
- const TWO_CHAR_PUNCTUATION = new Set([
656
+ const TWO_CHAR_PUNCTUATION = /* @__PURE__ */ new Set([
654
657
  "==",
655
658
  "!=",
656
659
  "<=",
657
660
  ">="
658
661
  ]);
659
- const ONE_CHAR_PUNCTUATION = new Set([
662
+ const ONE_CHAR_PUNCTUATION = /* @__PURE__ */ new Set([
660
663
  "(",
661
664
  ")",
662
665
  "[",
@@ -672,7 +675,7 @@ const IDENT_PART = /[\w$]/;
672
675
  const DIGIT = /\d/;
673
676
  const NUMBER_PATTERN = /^\d+(?:\.\d+)?(?:e[+-]?\d+)?/i;
674
677
  const INTEGER_PATTERN = /^\d+$/;
675
- function parseCanonicalNumber(text) {
678
+ function parseCanonicalZenNumber(text) {
676
679
  const value = Number(text);
677
680
  return String(value) === text && isZenRepresentableNumber(value) ? value : null;
678
681
  }
@@ -734,7 +737,7 @@ function liftConditionTree(expression) {
734
737
  return token.value;
735
738
  }
736
739
  if (token.kind === "number") {
737
- const value = parseCanonicalNumber(token.value);
740
+ const value = parseCanonicalZenNumber(token.value);
738
741
  if (value === null) return null;
739
742
  pos += 1;
740
743
  return value;
@@ -753,7 +756,7 @@ function liftConditionTree(expression) {
753
756
  if (token.kind === "punct" && token.value === "-") {
754
757
  const digits = peek(1);
755
758
  if (digits === void 0 || digits.kind !== "number") return null;
756
- const value = parseCanonicalNumber(digits.value);
759
+ const value = parseCanonicalZenNumber(digits.value);
757
760
  if (value === null || value === 0 || !isZenRepresentableNumber(-value)) return null;
758
761
  pos += 2;
759
762
  return -value;
@@ -1159,7 +1162,7 @@ const zhCNMessages = {
1159
1162
  expectedBoolean: (actualType) => `期望布尔测试表达式,实际类型为 \`${actualType}\`。`,
1160
1163
  expectedType: (expectedType, actualType) => `期望 \`${expectedType}\`,实际为 \`${actualType}\`。`
1161
1164
  };
1162
- const localeRegistry = new Map([["en-US", enMessages], ["zh-CN", zhCNMessages]]);
1165
+ const localeRegistry = /* @__PURE__ */ new Map([["en-US", enMessages], ["zh-CN", zhCNMessages]]);
1163
1166
  let activeBaseMessages = enMessages;
1164
1167
  let activeMessages = enMessages;
1165
1168
  const messageListeners = /* @__PURE__ */ new Set();
@@ -1367,11 +1370,14 @@ exports.getEngineSync = getEngineSync;
1367
1370
  exports.getExpressionMessages = getExpressionMessages;
1368
1371
  exports.getTemplateDiagnostics = getTemplateDiagnostics;
1369
1372
  exports.getTemplateDiagnosticsSync = getTemplateDiagnosticsSync;
1373
+ exports.isConditionScalarArray = isConditionScalarArray;
1370
1374
  exports.isEngineReady = isEngineReady;
1371
1375
  exports.isZenRepresentableNumber = isZenRepresentableNumber;
1376
+ exports.isZenReservedWord = isZenReservedWord;
1372
1377
  exports.liftConditionTree = liftConditionTree;
1373
1378
  exports.loadEngine = loadEngine;
1374
1379
  exports.newConditionNodeId = newConditionNodeId;
1380
+ exports.parseCanonicalZenNumber = parseCanonicalZenNumber;
1375
1381
  exports.parseTemplateHoles = parseTemplateHoles;
1376
1382
  exports.registerExpressionLocale = registerExpressionLocale;
1377
1383
  exports.resetEngine = resetEngine;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { InitInput } from "@gorules/zen-engine-wasm";
2
2
  import { SchemaTree } from "@coldsmirk/caliper-core";
3
-
4
3
  /**
5
4
  * How an expression editor interprets its document:
6
5
  *
@@ -541,15 +540,53 @@ declare function emptyConditionGroup(): ConditionTreeGroup;
541
540
  * the tree is compilable (see the module note for the drop semantics).
542
541
  */
543
542
  declare function compileConditionTree(tree: ConditionTreeGroup): string;
543
+ /**
544
+ * Whether a rule's `right` is an array of scalars — the membership-operand shape.
545
+ * Deliberately stricter than `Array.isArray`: every element must itself be a
546
+ * {@link ConditionScalar}, because a `null` slipping through the type as JSON data
547
+ * would make `toZenLiteral` serialize a `null` literal outside the canonical
548
+ * grammar rather than throw. Also the narrowing predicate for the
549
+ * scalar-or-array {@link ConditionTreeValue} union, which a bare `Array.isArray`
550
+ * narrows poorly over `readonly` arrays.
551
+ */
552
+ declare function isConditionScalarArray(value: ConditionTreeValue | undefined): value is readonly ConditionScalar[];
553
+ /**
554
+ * Parse `text` as a **canonical** ZEN number — exactly what the condition compiler
555
+ * emits: the `String(n)` rendering of a ZEN-representable value
556
+ * ({@link isZenRepresentableNumber}). Anything else — extra precision float64
557
+ * cannot hold (`9007199254740993` would silently round to `…992`), a magnitude
558
+ * that collapses to Infinity (`1e999`), redundant digits (`1.50`), or a value
559
+ * outside ZEN's decimal domain — returns `null`. For this lifter those are shapes
560
+ * {@link compileConditionTree} can never produce (lifting one would silently
561
+ * rewrite the expression instead of returning `null` as the module contract
562
+ * requires); for a value editor they are inputs whose numeric meaning would
563
+ * change if committed as a number.
564
+ */
565
+ declare function parseCanonicalZenNumber(text: string): number | null;
544
566
  /**
545
567
  * Lift a ZEN expression to a condition tree, or `null` when it is not in the
546
568
  * canonical form {@link compileConditionTree} produces (the consumer then keeps the
547
569
  * raw expression). Groups nested deeper than 64 parenthesized levels are refused as
548
570
  * non-canonical rather than risking parser-stack overflow on adversarial input, and
549
- * number literals must be canonical (see `parseCanonicalNumber`). The returned root
571
+ * number literals must be canonical (see {@link parseCanonicalZenNumber}). The returned root
550
572
  * is always a group, and every node carries a fresh {@link ConditionTreeRule.id}.
551
573
  */
552
574
  declare function liftConditionTree(expression: string): ConditionTreeGroup | null;
575
+ /**
576
+ * Shared subject-path guard for the condition compilers. A subject / left-hand
577
+ * path is emitted **verbatim** into ZEN source, so both {@link compileCondition}
578
+ * (which writes that source) and {@link liftConditionTree} (which reads it back)
579
+ * gate paths through this one predicate — a single definition of "what is a safe
580
+ * field path" that cannot drift between the writer and the reader, which matters
581
+ * because the guard is also the compiler's injection defense.
582
+ */
583
+ /**
584
+ * Whether `word` is one of ZEN's reserved words — the keywords the grammar
585
+ * claims as operators (`and`, `or`, `not`, `in`) or literals (`true`, `false`,
586
+ * `null`). A reserved word can never start an identifier path, and editor
587
+ * tooling treats one as not reachable through plain dot access.
588
+ */
589
+ declare function isZenReservedWord(word: string): boolean;
553
590
  /**
554
591
  * Return `tree` with every node carrying a stable UI id. The shared structural
555
592
  * policy is checked before recursive normalization, so invalid external data fails
@@ -657,10 +694,7 @@ interface ConfigureMessagesOptions {
657
694
  * override, or both (overrides win). Idempotent and module-global, so a host
658
695
  * configures it once (e.g. through `ExpressionConfigProvider`).
659
696
  */
660
- declare function configureExpressionMessages({
661
- locale,
662
- messages
663
- }: ConfigureMessagesOptions): void;
697
+ declare function configureExpressionMessages({ locale, messages }: ConfigureMessagesOptions): void;
664
698
  /**
665
699
  * The active {@link ExpressionMessages} catalog (English by default).
666
700
  */
@@ -743,4 +777,4 @@ declare function getTemplateDiagnosticsSync(source: string): ExpressionDiagnosti
743
777
  * Async {@link getTemplateDiagnosticsSync}, loading the engine on first use.
744
778
  */
745
779
  declare function getTemplateDiagnostics(source: string): Promise<ExpressionDiagnostic[]>;
746
- export { type BranchSelection, type BuiltInExpressionLocale, CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, type ConditionBranchInput, type ConditionGroupInput, type ConditionInput, type ConditionOperator, type ConditionOperatorArity, type ConditionScalar, type ConditionTreeGroup, type ConditionTreeNode, type ConditionTreeOperator, type ConditionTreeRule, type ConditionTreeValue, type ConfigureMessagesOptions, type ExpressionAnalysis, type ExpressionCompletion, type ExpressionConditionInput, type ExpressionContext, type ExpressionDiagnostic, type ExpressionEngine, ExpressionError, type ExpressionLocale, type ExpressionMessages, type ExpressionMessagesListener, type ExpressionMode, ExpressionNotReadyError, type ExpressionType, type ExpressionTypeSpan, type FieldConditionInput, type LoadEngineOptions, MAX_CONDITION_TREE_DEPTH, type TemplateHole, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isEngineReady, isZenRepresentableNumber, liftConditionTree, loadEngine, newConditionNodeId, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
780
+ export { type BranchSelection, type BuiltInExpressionLocale, CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, type ConditionBranchInput, type ConditionGroupInput, type ConditionInput, type ConditionOperator, type ConditionOperatorArity, type ConditionScalar, type ConditionTreeGroup, type ConditionTreeNode, type ConditionTreeOperator, type ConditionTreeRule, type ConditionTreeValue, type ConfigureMessagesOptions, type ExpressionAnalysis, type ExpressionCompletion, type ExpressionConditionInput, type ExpressionContext, type ExpressionDiagnostic, type ExpressionEngine, ExpressionError, type ExpressionLocale, type ExpressionMessages, type ExpressionMessagesListener, type ExpressionMode, ExpressionNotReadyError, type ExpressionType, type ExpressionTypeSpan, type FieldConditionInput, type LoadEngineOptions, MAX_CONDITION_TREE_DEPTH, type TemplateHole, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isConditionScalarArray, isEngineReady, isZenRepresentableNumber, isZenReservedWord, liftConditionTree, loadEngine, newConditionNodeId, parseCanonicalZenNumber, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { InitInput } from "@gorules/zen-engine-wasm";
2
2
  import { SchemaTree } from "@coldsmirk/caliper-core";
3
-
4
3
  /**
5
4
  * How an expression editor interprets its document:
6
5
  *
@@ -541,15 +540,53 @@ declare function emptyConditionGroup(): ConditionTreeGroup;
541
540
  * the tree is compilable (see the module note for the drop semantics).
542
541
  */
543
542
  declare function compileConditionTree(tree: ConditionTreeGroup): string;
543
+ /**
544
+ * Whether a rule's `right` is an array of scalars — the membership-operand shape.
545
+ * Deliberately stricter than `Array.isArray`: every element must itself be a
546
+ * {@link ConditionScalar}, because a `null` slipping through the type as JSON data
547
+ * would make `toZenLiteral` serialize a `null` literal outside the canonical
548
+ * grammar rather than throw. Also the narrowing predicate for the
549
+ * scalar-or-array {@link ConditionTreeValue} union, which a bare `Array.isArray`
550
+ * narrows poorly over `readonly` arrays.
551
+ */
552
+ declare function isConditionScalarArray(value: ConditionTreeValue | undefined): value is readonly ConditionScalar[];
553
+ /**
554
+ * Parse `text` as a **canonical** ZEN number — exactly what the condition compiler
555
+ * emits: the `String(n)` rendering of a ZEN-representable value
556
+ * ({@link isZenRepresentableNumber}). Anything else — extra precision float64
557
+ * cannot hold (`9007199254740993` would silently round to `…992`), a magnitude
558
+ * that collapses to Infinity (`1e999`), redundant digits (`1.50`), or a value
559
+ * outside ZEN's decimal domain — returns `null`. For this lifter those are shapes
560
+ * {@link compileConditionTree} can never produce (lifting one would silently
561
+ * rewrite the expression instead of returning `null` as the module contract
562
+ * requires); for a value editor they are inputs whose numeric meaning would
563
+ * change if committed as a number.
564
+ */
565
+ declare function parseCanonicalZenNumber(text: string): number | null;
544
566
  /**
545
567
  * Lift a ZEN expression to a condition tree, or `null` when it is not in the
546
568
  * canonical form {@link compileConditionTree} produces (the consumer then keeps the
547
569
  * raw expression). Groups nested deeper than 64 parenthesized levels are refused as
548
570
  * non-canonical rather than risking parser-stack overflow on adversarial input, and
549
- * number literals must be canonical (see `parseCanonicalNumber`). The returned root
571
+ * number literals must be canonical (see {@link parseCanonicalZenNumber}). The returned root
550
572
  * is always a group, and every node carries a fresh {@link ConditionTreeRule.id}.
551
573
  */
552
574
  declare function liftConditionTree(expression: string): ConditionTreeGroup | null;
575
+ /**
576
+ * Shared subject-path guard for the condition compilers. A subject / left-hand
577
+ * path is emitted **verbatim** into ZEN source, so both {@link compileCondition}
578
+ * (which writes that source) and {@link liftConditionTree} (which reads it back)
579
+ * gate paths through this one predicate — a single definition of "what is a safe
580
+ * field path" that cannot drift between the writer and the reader, which matters
581
+ * because the guard is also the compiler's injection defense.
582
+ */
583
+ /**
584
+ * Whether `word` is one of ZEN's reserved words — the keywords the grammar
585
+ * claims as operators (`and`, `or`, `not`, `in`) or literals (`true`, `false`,
586
+ * `null`). A reserved word can never start an identifier path, and editor
587
+ * tooling treats one as not reachable through plain dot access.
588
+ */
589
+ declare function isZenReservedWord(word: string): boolean;
553
590
  /**
554
591
  * Return `tree` with every node carrying a stable UI id. The shared structural
555
592
  * policy is checked before recursive normalization, so invalid external data fails
@@ -657,10 +694,7 @@ interface ConfigureMessagesOptions {
657
694
  * override, or both (overrides win). Idempotent and module-global, so a host
658
695
  * configures it once (e.g. through `ExpressionConfigProvider`).
659
696
  */
660
- declare function configureExpressionMessages({
661
- locale,
662
- messages
663
- }: ConfigureMessagesOptions): void;
697
+ declare function configureExpressionMessages({ locale, messages }: ConfigureMessagesOptions): void;
664
698
  /**
665
699
  * The active {@link ExpressionMessages} catalog (English by default).
666
700
  */
@@ -743,4 +777,4 @@ declare function getTemplateDiagnosticsSync(source: string): ExpressionDiagnosti
743
777
  * Async {@link getTemplateDiagnosticsSync}, loading the engine on first use.
744
778
  */
745
779
  declare function getTemplateDiagnostics(source: string): Promise<ExpressionDiagnostic[]>;
746
- export { type BranchSelection, type BuiltInExpressionLocale, CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, type ConditionBranchInput, type ConditionGroupInput, type ConditionInput, type ConditionOperator, type ConditionOperatorArity, type ConditionScalar, type ConditionTreeGroup, type ConditionTreeNode, type ConditionTreeOperator, type ConditionTreeRule, type ConditionTreeValue, type ConfigureMessagesOptions, type ExpressionAnalysis, type ExpressionCompletion, type ExpressionConditionInput, type ExpressionContext, type ExpressionDiagnostic, type ExpressionEngine, ExpressionError, type ExpressionLocale, type ExpressionMessages, type ExpressionMessagesListener, type ExpressionMode, ExpressionNotReadyError, type ExpressionType, type ExpressionTypeSpan, type FieldConditionInput, type LoadEngineOptions, MAX_CONDITION_TREE_DEPTH, type TemplateHole, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isEngineReady, isZenRepresentableNumber, liftConditionTree, loadEngine, newConditionNodeId, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
780
+ export { type BranchSelection, type BuiltInExpressionLocale, CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, type ConditionBranchInput, type ConditionGroupInput, type ConditionInput, type ConditionOperator, type ConditionOperatorArity, type ConditionScalar, type ConditionTreeGroup, type ConditionTreeNode, type ConditionTreeOperator, type ConditionTreeRule, type ConditionTreeValue, type ConfigureMessagesOptions, type ExpressionAnalysis, type ExpressionCompletion, type ExpressionConditionInput, type ExpressionContext, type ExpressionDiagnostic, type ExpressionEngine, ExpressionError, type ExpressionLocale, type ExpressionMessages, type ExpressionMessagesListener, type ExpressionMode, ExpressionNotReadyError, type ExpressionType, type ExpressionTypeSpan, type FieldConditionInput, type LoadEngineOptions, MAX_CONDITION_TREE_DEPTH, type TemplateHole, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isConditionScalarArray, isEngineReady, isZenRepresentableNumber, isZenReservedWord, liftConditionTree, loadEngine, newConditionNodeId, parseCanonicalZenNumber, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
package/dist/index.js CHANGED
@@ -360,7 +360,7 @@ function isZenConsistentNumber(value) {
360
360
  const SUBJECT_PATTERN = /^[A-Z_$][\w$]*(?:\.[A-Z_$][\w$]*|\[\d+\])*$/i;
361
361
  const SUBJECT_IDENTIFIER_PATTERN = /[A-Z_$][\w$]*/gi;
362
362
  const SUBJECT_INDEX_PATTERN = /\[(?<index>\d+)\]/g;
363
- const ZEN_ROOT_RESERVED_WORDS = new Set([
363
+ const ZEN_RESERVED_WORDS = /* @__PURE__ */ new Set([
364
364
  "and",
365
365
  "or",
366
366
  "not",
@@ -369,11 +369,14 @@ const ZEN_ROOT_RESERVED_WORDS = new Set([
369
369
  "false",
370
370
  "null"
371
371
  ]);
372
- const ZEN_MEMBER_RESERVED_WORDS = new Set(["true", "false"]);
372
+ const ZEN_MEMBER_RESERVED_WORDS = /* @__PURE__ */ new Set(["true", "false"]);
373
+ function isZenReservedWord(word) {
374
+ return ZEN_RESERVED_WORDS.has(word);
375
+ }
373
376
  function isIdentifierPath(subject) {
374
377
  if (!SUBJECT_PATTERN.test(subject)) return false;
375
378
  const [root, ...members] = subject.match(SUBJECT_IDENTIFIER_PATTERN) ?? [];
376
- if (root === void 0 || ZEN_ROOT_RESERVED_WORDS.has(root) || members.some((member) => ZEN_MEMBER_RESERVED_WORDS.has(member))) return false;
379
+ if (root === void 0 || isZenReservedWord(root) || members.some((member) => ZEN_MEMBER_RESERVED_WORDS.has(member))) return false;
377
380
  for (const match of subject.matchAll(SUBJECT_INDEX_PATTERN)) if (match.groups?.index === void 0 || !isZenUnsignedIntegerText(match.groups.index)) return false;
378
381
  return true;
379
382
  }
@@ -639,23 +642,23 @@ function compileRule(rule) {
639
642
  function matchesOperatorArity(rule) {
640
643
  switch (conditionOperatorArity(rule.operator)) {
641
644
  case "scalar": return isConditionScalar(rule.right);
642
- case "array": return isScalarArray(rule.right);
645
+ case "array": return isConditionScalarArray(rule.right);
643
646
  case "none": return rule.right === void 0;
644
647
  }
645
648
  }
646
649
  function isConditionScalar(value) {
647
650
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
648
651
  }
649
- function isScalarArray(value) {
652
+ function isConditionScalarArray(value) {
650
653
  return isArray(value) && value.every((item) => isConditionScalar(item));
651
654
  }
652
- const TWO_CHAR_PUNCTUATION = new Set([
655
+ const TWO_CHAR_PUNCTUATION = /* @__PURE__ */ new Set([
653
656
  "==",
654
657
  "!=",
655
658
  "<=",
656
659
  ">="
657
660
  ]);
658
- const ONE_CHAR_PUNCTUATION = new Set([
661
+ const ONE_CHAR_PUNCTUATION = /* @__PURE__ */ new Set([
659
662
  "(",
660
663
  ")",
661
664
  "[",
@@ -671,7 +674,7 @@ const IDENT_PART = /[\w$]/;
671
674
  const DIGIT = /\d/;
672
675
  const NUMBER_PATTERN = /^\d+(?:\.\d+)?(?:e[+-]?\d+)?/i;
673
676
  const INTEGER_PATTERN = /^\d+$/;
674
- function parseCanonicalNumber(text) {
677
+ function parseCanonicalZenNumber(text) {
675
678
  const value = Number(text);
676
679
  return String(value) === text && isZenRepresentableNumber(value) ? value : null;
677
680
  }
@@ -733,7 +736,7 @@ function liftConditionTree(expression) {
733
736
  return token.value;
734
737
  }
735
738
  if (token.kind === "number") {
736
- const value = parseCanonicalNumber(token.value);
739
+ const value = parseCanonicalZenNumber(token.value);
737
740
  if (value === null) return null;
738
741
  pos += 1;
739
742
  return value;
@@ -752,7 +755,7 @@ function liftConditionTree(expression) {
752
755
  if (token.kind === "punct" && token.value === "-") {
753
756
  const digits = peek(1);
754
757
  if (digits === void 0 || digits.kind !== "number") return null;
755
- const value = parseCanonicalNumber(digits.value);
758
+ const value = parseCanonicalZenNumber(digits.value);
756
759
  if (value === null || value === 0 || !isZenRepresentableNumber(-value)) return null;
757
760
  pos += 2;
758
761
  return -value;
@@ -1158,7 +1161,7 @@ const zhCNMessages = {
1158
1161
  expectedBoolean: (actualType) => `期望布尔测试表达式,实际类型为 \`${actualType}\`。`,
1159
1162
  expectedType: (expectedType, actualType) => `期望 \`${expectedType}\`,实际为 \`${actualType}\`。`
1160
1163
  };
1161
- const localeRegistry = new Map([["en-US", enMessages], ["zh-CN", zhCNMessages]]);
1164
+ const localeRegistry = /* @__PURE__ */ new Map([["en-US", enMessages], ["zh-CN", zhCNMessages]]);
1162
1165
  let activeBaseMessages = enMessages;
1163
1166
  let activeMessages = enMessages;
1164
1167
  const messageListeners = /* @__PURE__ */ new Set();
@@ -1334,4 +1337,4 @@ async function getTemplateDiagnostics(source) {
1334
1337
  await loadEngine();
1335
1338
  return getTemplateDiagnosticsSync(source);
1336
1339
  }
1337
- export { CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, ExpressionError, ExpressionNotReadyError, MAX_CONDITION_TREE_DEPTH, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isEngineReady, isZenRepresentableNumber, liftConditionTree, loadEngine, newConditionNodeId, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
1340
+ export { CONDITION_OPERATORS, CONDITION_TREE_OPERATORS, ExpressionError, ExpressionNotReadyError, MAX_CONDITION_TREE_DEPTH, analyzeTemplate, analyzeTemplateSync, analyzeTypes, analyzeTypesSync, compileBranch, compileCondition, compileConditionTree, compileGroup, conditionOperatorArity, configureEngine, configureExpressionMessages, emptyConditionGroup, enMessages, ensureConditionNodeIds, evaluate, evaluateSync, evaluateUnary, evaluateUnarySync, getCompletionItems, getCompletionItemsSync, getDiagnostics, getDiagnosticsSync, getEngineError, getEngineSync, getExpressionMessages, getTemplateDiagnostics, getTemplateDiagnosticsSync, isConditionScalarArray, isEngineReady, isZenRepresentableNumber, isZenReservedWord, liftConditionTree, loadEngine, newConditionNodeId, parseCanonicalZenNumber, parseTemplateHoles, registerExpressionLocale, resetEngine, satisfiesType, satisfiesTypeSync, schemaTreeToExpressionType, selectBranch, selectBranchWith, subscribeExpressionMessages, templateHoleAt, toZenLiteral, zhCNMessages };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldsmirk/abacus-core",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Framework-agnostic ZEN expression engine: compile, evaluate, and type-analyze expressions over the GoRules ZEN WASM engine.",
5
5
  "keywords": [
6
6
  "zen",