@astrale-os/kernel-dsl 0.2.0-beta.37 → 0.2.0-beta.39

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 (102) hide show
  1. package/dist/v1/builder/core/authoring.d.ts +7 -2
  2. package/dist/v1/builder/lowering/schema/context.d.ts +9 -4
  3. package/dist/v1/builder/lowering/schema/context.js +20 -20
  4. package/dist/v1/builder/policy/authoring.d.ts +6 -6
  5. package/dist/v1/builder/policy/authoring.js +3 -1
  6. package/dist/v1/compiled/admission/accept.js +97 -18
  7. package/dist/v1/compiled/admission/semantics.js +77 -24
  8. package/dist/v1/compiled/compiler/compile.js +23 -7
  9. package/dist/v1/compiled/loader/load.d.ts +11 -2
  10. package/dist/v1/compiled/loader/load.js +4 -1
  11. package/dist/v1/compiled/model/schema.d.ts +5 -4
  12. package/dist/v1/domain/create.js +17 -9
  13. package/dist/v1/index.d.ts +1 -1
  14. package/dist/v1/language/callable/composition.d.ts +13 -1
  15. package/dist/v1/language/callable/composition.js +13 -3
  16. package/dist/v1/language/core/model/core.d.ts +7 -1
  17. package/dist/v1/language/core/resolved.d.ts +6 -2
  18. package/dist/v1/language/index.d.ts +1 -1
  19. package/dist/v1/language/index.js +1 -1
  20. package/dist/v1/language/policy/index.d.ts +1 -1
  21. package/dist/v1/language/policy/index.js +1 -1
  22. package/dist/v1/language/policy/model/policy.d.ts +1 -0
  23. package/dist/v1/language/policy/model/policy.js +17 -0
  24. package/dist/v1/language/value/compile/fields.d.ts +1 -1
  25. package/dist/v1/language/value/compile/load.d.ts +4 -2
  26. package/dist/v1/language/value/compile/load.js +22 -1
  27. package/dist/v1/language/value/compile/model.d.ts +16 -1
  28. package/dist/v1/language/value/evaluate/assertions.d.ts +2 -0
  29. package/dist/v1/language/value/evaluate/assertions.js +13 -0
  30. package/dist/v1/language/value/evaluate/evaluator.js +78 -17
  31. package/dist/v1/language/value/evaluate/preparation.d.ts +10 -1
  32. package/dist/v1/language/value/evaluate/preparation.js +17 -26
  33. package/dist/v1/language/value/evaluate/program.js +1 -1
  34. package/dist/v1/language/value/evaluate/validate.d.ts +6 -2
  35. package/dist/v1/language/value/evaluate/validate.js +18 -11
  36. package/dist/v1/language/value/ordering.d.ts +2 -0
  37. package/dist/v1/language/value/ordering.js +4 -8
  38. package/dist/v1/language/value/regexp/compile.d.ts +3 -3
  39. package/dist/v1/language/value/regexp/compile.js +56 -11
  40. package/dist/v1/language/value/regexp/matcher.d.ts +3 -3
  41. package/dist/v1/language/value/regexp/matcher.js +75 -3
  42. package/dist/v1/schema/analysis/class.d.ts +21 -0
  43. package/dist/v1/schema/analysis/class.js +18 -9
  44. package/dist/v1/schema/compatibility/api.d.ts +2 -0
  45. package/dist/v1/schema/compatibility/api.js +1 -0
  46. package/dist/v1/schema/compatibility/comparators/callables.d.ts +28 -0
  47. package/dist/v1/schema/compatibility/comparators/callables.js +77 -0
  48. package/dist/v1/schema/compatibility/comparators/classes.d.ts +28 -0
  49. package/dist/v1/schema/compatibility/comparators/classes.js +96 -0
  50. package/dist/v1/schema/compatibility/comparators/index.d.ts +12 -0
  51. package/dist/v1/schema/compatibility/comparators/index.js +41 -0
  52. package/dist/v1/schema/compatibility/comparators/members.d.ts +4 -0
  53. package/dist/v1/schema/compatibility/comparators/members.js +49 -0
  54. package/dist/v1/schema/compatibility/comparators/values.d.ts +5 -0
  55. package/dist/v1/schema/compatibility/comparators/values.js +37 -0
  56. package/dist/v1/schema/compatibility/compare.d.ts +5 -57
  57. package/dist/v1/schema/compatibility/compare.js +19 -162
  58. package/dist/v1/schema/compatibility/coordinate.d.ts +2 -7
  59. package/dist/v1/schema/compatibility/coordinate.js +2 -6
  60. package/dist/v1/schema/compatibility/evidence.d.ts +5 -0
  61. package/dist/v1/schema/compatibility/evidence.js +51 -0
  62. package/dist/v1/schema/compatibility/fields.d.ts +6 -0
  63. package/dist/v1/schema/compatibility/fields.js +5 -0
  64. package/dist/v1/schema/compatibility/index.d.ts +5 -4
  65. package/dist/v1/schema/compatibility/index.js +3 -2
  66. package/dist/v1/schema/compatibility/legacy/index.d.ts +58 -0
  67. package/dist/v1/schema/compatibility/legacy/index.js +145 -0
  68. package/dist/v1/schema/compatibility/meaning/footprint.d.ts +7 -0
  69. package/dist/v1/schema/compatibility/meaning/footprint.js +57 -0
  70. package/dist/v1/schema/compatibility/meaning/index.d.ts +3 -0
  71. package/dist/v1/schema/compatibility/meaning/index.js +14 -0
  72. package/dist/v1/schema/compatibility/model.d.ts +96 -0
  73. package/dist/v1/schema/compatibility/model.js +1 -0
  74. package/dist/v1/schema/compatibility/references.d.ts +30 -0
  75. package/dist/v1/schema/compatibility/references.js +122 -0
  76. package/dist/v1/schema/compatibility/report.d.ts +26 -0
  77. package/dist/v1/schema/compatibility/report.js +100 -0
  78. package/dist/v1/schema/compatibility/scope.d.ts +27 -0
  79. package/dist/v1/schema/compatibility/scope.js +78 -0
  80. package/dist/v1/schema/compatibility/structure/index.d.ts +3 -0
  81. package/dist/v1/schema/compatibility/structure/index.js +16 -0
  82. package/dist/v1/schema/compatibility/structure/inheritance.d.ts +7 -0
  83. package/dist/v1/schema/compatibility/structure/inheritance.js +68 -0
  84. package/dist/v1/schema/compatibility/structure/requirements.d.ts +7 -0
  85. package/dist/v1/schema/compatibility/structure/requirements.js +70 -0
  86. package/dist/v1/schema/compatibility/subjects.d.ts +34 -0
  87. package/dist/v1/schema/compatibility/subjects.js +86 -0
  88. package/dist/v1/schema/fingerprint.d.ts +2 -2
  89. package/dist/v1/schema/fingerprint.js +1 -1
  90. package/dist/v1/schema/index.d.ts +3 -0
  91. package/dist/v1/schema/index.js +2 -0
  92. package/dist/v1/schema/normalization/domain.js +15 -1
  93. package/dist/v1/schema/resolution/domain.js +17 -10
  94. package/dist/v1/schema/resolution/origins.d.ts +3 -0
  95. package/dist/v1/schema/resolution/origins.js +12 -4
  96. package/dist/v1/schema/validation/core.js +78 -26
  97. package/dist/v1/schema/validation/domain.structure.js +7 -2
  98. package/package.json +2 -2
  99. package/dist/v1/schema/compatibility/footprint.d.ts +0 -25
  100. package/dist/v1/schema/compatibility/footprint.js +0 -263
  101. package/dist/v1/schema/compatibility/meaning.d.ts +0 -44
  102. package/dist/v1/schema/compatibility/meaning.js +0 -234
@@ -2,6 +2,7 @@ import { Key, MethodKey, PropertyKey as PropertyKeyValue } from '../../addressin
2
2
  import { compareUnicode } from '../../addressing/ordering.js';
3
3
  import { createDomain } from '../../domain/create.js';
4
4
  import { combineDomainValidation, createDomainValidation, unknownInputField, } from '../../domain/validation/create.js';
5
+ import { bindValueProgram } from '../../language/value/compile/load.js';
5
6
  import { validateValueProgram } from '../../language/value/evaluate/program.js';
6
7
  import { acceptCompiledSchema } from '../admission/accept.js';
7
8
  export function load(input) {
@@ -68,7 +69,9 @@ function loadEntry(entry) {
68
69
  ...entry.definitions.views,
69
70
  ...entry.definitions.core,
70
71
  ]),
71
- validation: programValidation(entry.values, propertyPrograms, propertyOrdering, callablePrograms),
72
+ validation: programValidation('patterns' in entry
73
+ ? entry.values.map((value) => bindValueProgram(value, entry.patterns))
74
+ : entry.values, propertyPrograms, propertyOrdering, callablePrograms),
72
75
  };
73
76
  }
74
77
  function loadMethod(entry, value) {
@@ -6,10 +6,10 @@ import type { ClassDefinition } from '../../language/class/model/class.js';
6
6
  import type { PropertyDefinition } from '../../language/class/model/property.js';
7
7
  import type { CoreDefinition, CoreEdge } from '../../language/core/model/core.js';
8
8
  import type { PolicyDefinition } from '../../language/policy/model/policy.js';
9
- import type { ValueProgram } from '../../language/value/compile/model.js';
9
+ import type { IndexedValueProgram, Pattern, RunPattern } from '../../language/value/compile/model.js';
10
10
  import type { OrderingKind } from '../../language/value/ordering.js';
11
11
  import type { ViewDefinition } from '../../language/view/model/view.js';
12
- export type { Pattern, PatternState, PatternTransition, ScalarRange, ValueNode, ValueProgram, } from '../../language/value/compile/model.js';
12
+ export type { Pattern, PatternState, PatternTransition, RunPattern, ScalarRun, ScalarRange, IndexedValueProgram, ValueNode, ValueProgram, } from '../../language/value/compile/model.js';
13
13
  export interface CompiledProperty extends Omit<PropertyDefinition, 'schema'> {
14
14
  readonly name: string;
15
15
  readonly value: number;
@@ -60,12 +60,13 @@ export interface CompiledSchemaEntry {
60
60
  readonly facts: {
61
61
  readonly core: readonly CoreEdge[];
62
62
  };
63
- readonly values: readonly ValueProgram[];
63
+ readonly values: readonly IndexedValueProgram[];
64
+ readonly patterns: readonly (Pattern | RunPattern)[];
64
65
  }
65
66
  declare const COMPILED_DOMAIN: unique symbol;
66
67
  export interface CompiledSchema<Resolved = Domain> {
67
68
  readonly format: 'astrale.dsl.compiled-schema';
68
- readonly version: 1;
69
+ readonly version: 2;
69
70
  readonly root: DomainDependency;
70
71
  readonly closure: readonly CompiledSchemaEntry[];
71
72
  readonly [COMPILED_DOMAIN]: Resolved;
@@ -1,4 +1,4 @@
1
- import { Key } from '../addressing/index.js';
1
+ import { Key, MethodKey } from '../addressing/index.js';
2
2
  import { frozenRecord } from './namespace/member-collection.js';
3
3
  import { createClasses } from './projection/classes.js';
4
4
  const admittedDomains = new WeakSet();
@@ -58,14 +58,13 @@ export function createDomain(input) {
58
58
  if (classValue?.kind !== 'edge') {
59
59
  throw new TypeError(`Core Edge has no Edge Class ${Key.of(edge.class)}.`);
60
60
  }
61
+ const endpoint = (ref) => ref.kind === 'domain'
62
+ ? domainEndpoint
63
+ : requiredCoreEndpoint(definitionsByKey, callables, ref);
61
64
  return Object.freeze({
62
65
  class: classValue,
63
- source: edge.source.kind === 'domain'
64
- ? domainEndpoint
65
- : requiredCore(definitionsByKey, edge.source),
66
- target: edge.target.kind === 'domain'
67
- ? domainEndpoint
68
- : requiredCore(definitionsByKey, edge.target),
66
+ source: endpoint(edge.source),
67
+ target: endpoint(edge.target),
69
68
  properties: edge.properties,
70
69
  });
71
70
  }));
@@ -241,9 +240,18 @@ function namespace(definitions, kind) {
241
240
  .filter((value) => value.ref.kind === kind)
242
241
  .map((value) => [value.ref.name, value]));
243
242
  }
244
- function requiredCore(definitions, ref) {
243
+ /** Every non-Domain Core endpoint addresses one already-resolved local Definition or Method. */
244
+ function requiredCoreEndpoint(definitions, callables, ref) {
245
+ if (ref.kind === 'method') {
246
+ const key = MethodKey.of(ref.owner, ref.name);
247
+ const method = callables.get(key);
248
+ if (method === undefined || !('owner' in method)) {
249
+ throw new TypeError(`Core endpoint ${key} is absent.`);
250
+ }
251
+ return method;
252
+ }
245
253
  const value = definitions.get(Key.of(ref));
246
- if (value?.ref.kind !== 'core')
254
+ if (value === undefined)
247
255
  throw new TypeError(`Core endpoint ${Key.of(ref)} is absent.`);
248
256
  return value;
249
257
  }
@@ -4,7 +4,7 @@ export { stateMachine } from './language/state/index.js';
4
4
  export type { EventOf, StateMachine, StateOf } from './language/state/index.js';
5
5
  export { PropertyValues } from './language/index.js';
6
6
  export * as metadata from './language/definition/metadata.js';
7
- export type { AnyResolvedClass, BoundMethodOf, BoundMethodShortcutsOf, CallableResultOf, CallableInputOf, CallableOutputOf, ClassSatisfactionKeysOf, ClassDefinition, CoreDefinition, CoreEdge, FunctionAuth, FunctionDefinition, MethodDefinition, MethodOwnerKeyOf, PolicyCheckExpression, PolicyDefinition, PropertyInputOf, PropertyAccessOf, PropertyOutputOf, PropertyShortcutsOf, PropertyValuesOf, ResolvedClass, ResolvedCoreDefinition, ResolvedData, ResolvedFunction, ExecutableMethod, ResolvedMethod, ResolvedMethodCollection, ResolvedPolicy, ResolvedProperty, ResolvedView, MethodAccessOf, SelfMethodsOf, SelfPropertiesOf, SelfStaticMethodsOf, StaticMethodsOf, ViewDefinition, } from './language/index.js';
7
+ export type { AnyResolvedClass, BoundMethodOf, BoundMethodShortcutsOf, CallableResultOf, CallableInputOf, CallableOutputOf, ClassSatisfactionKeysOf, ClassDefinition, CoreDefinition, CoreEdge, FunctionAuth, FunctionDefinition, MethodDefinition, MethodOwnerKeyOf, PolicyCheckExpression, PolicyDefinition, PropertyInputOf, PropertyAccessOf, PropertyOutputOf, PropertyShortcutsOf, PropertyValuesOf, ResolvedClass, ResolvedCoreDefinition, ResolvedCoreEndpoint, ResolvedData, ResolvedFunction, ExecutableMethod, ResolvedMethod, ResolvedMethodCollection, ResolvedPolicy, ResolvedProperty, ResolvedView, MethodAccessOf, SelfMethodsOf, SelfPropertiesOf, SelfStaticMethodsOf, StaticMethodsOf, ViewDefinition, } from './language/index.js';
8
8
  export { acceptDefinitionRef, callableAddress, ClassKey, equalDefinitionRefs, isDefinitionRef, Key, MethodKey, PropertyKey, } from './addressing/index.js';
9
9
  export type { ClassRef, CoreRef, DefinitionBase, DefinitionKey, DefinitionRef, FunctionRef, MethodAddress, PolicyRef, Revision, ViewRef, } from './addressing/index.js';
10
10
  export type { Definition } from './language/index.js';
@@ -10,6 +10,18 @@ export interface MethodComposition<Method> {
10
10
  readonly frontier: ReadonlyMap<string, Method>;
11
11
  readonly methods: ReadonlyMap<string, Method>;
12
12
  }
13
+ /** Structured failure facts; human diagnostic wording is not compatibility evidence. */
14
+ export type MethodCompositionIssue = {
15
+ readonly kind: 'signature';
16
+ readonly local: string;
17
+ readonly required: string;
18
+ } | {
19
+ readonly kind: 'ambiguous';
20
+ readonly methods: readonly [string, string];
21
+ } | {
22
+ readonly kind: 'missing';
23
+ readonly required: string;
24
+ };
13
25
  /** Concrete implementations never discharge a descendant's abstract obligations. */
14
- export declare function composeMethods<Method extends MethodMember>(parents: readonly MethodComposition<Method>[], own: ReadonlyMap<string, Method>, abstract: boolean, sameSignature: (left: Method, right: Method) => boolean, report: (message: string) => void): MethodComposition<Method>;
26
+ export declare function composeMethods<Method extends MethodMember>(parents: readonly MethodComposition<Method>[], own: ReadonlyMap<string, Method>, abstract: boolean, sameSignature: (left: Method, right: Method) => boolean, report: (message: string, issue: MethodCompositionIssue) => void): MethodComposition<Method>;
15
27
  export {};
@@ -5,7 +5,11 @@ export function composeMethods(parents, own, abstract, sameSignature, report) {
5
5
  for (const required of requirements.values()) {
6
6
  const local = own.get(required.name);
7
7
  if (local !== undefined && !sameSignature(local, required)) {
8
- report(`Method ${local.key} does not exactly preserve abstract signature ${required.key}.`);
8
+ report(`Method ${local.key} does not exactly preserve abstract signature ${required.key}.`, {
9
+ kind: 'signature',
10
+ local: local.key,
11
+ required: required.key,
12
+ });
9
13
  }
10
14
  }
11
15
  for (const local of own.values()) {
@@ -22,7 +26,10 @@ export function composeMethods(parents, own, abstract, sameSignature, report) {
22
26
  for (const inherited of frontier.values()) {
23
27
  const prior = methods.get(inherited.name);
24
28
  if (prior !== undefined && !own.has(inherited.name)) {
25
- report(`Inherited Method ${inherited.name} is ambiguous: ${prior.key}, ${inherited.key}.`);
29
+ report(`Inherited Method ${inherited.name} is ambiguous: ${prior.key}, ${inherited.key}.`, {
30
+ kind: 'ambiguous',
31
+ methods: [prior.key, inherited.key],
32
+ });
26
33
  }
27
34
  methods.set(inherited.name, inherited);
28
35
  }
@@ -34,7 +41,10 @@ export function composeMethods(parents, own, abstract, sameSignature, report) {
34
41
  const local = own.get(required.name);
35
42
  if (local === undefined && !missing.has(required.name)) {
36
43
  missing.add(required.name);
37
- report(`Concrete Class requires a local Method declaration of ${required.key}.`);
44
+ report(`Concrete Class requires a local Method declaration of ${required.key}.`, {
45
+ kind: 'missing',
46
+ required: required.key,
47
+ });
38
48
  }
39
49
  }
40
50
  }
@@ -1,9 +1,15 @@
1
1
  import type { ClassRef, CoreRef, DefinitionBase } from '../../../addressing/index.js';
2
2
  import type { PropertyValues } from '../../class/property-values.js';
3
+ import type { PolicyObjectRef } from '../../policy/model/policy.js';
3
4
  export interface DomainEndpointRef {
4
5
  readonly kind: 'domain';
5
6
  }
6
- export type CoreEndpointRef = CoreRef | DomainEndpointRef;
7
+ /**
8
+ * One Core Edge endpoint: the owning Domain itself, or any local Definition whose installed
9
+ * projection resolves through an exact member Path. That is the same projected-member vocabulary
10
+ * a Policy object names, so both languages address one identity the same way.
11
+ */
12
+ export type CoreEndpointRef = PolicyObjectRef | DomainEndpointRef;
7
13
  export interface CoreDefinition extends DefinitionBase<CoreRef> {
8
14
  readonly class: ClassRef;
9
15
  readonly properties: PropertyValues;
@@ -1,6 +1,8 @@
1
1
  import type { DefinitionKey } from '../../addressing/index.js';
2
+ import type { ResolvedMethod } from '../callable/resolved.js';
2
3
  import type { PropertyValues } from '../class/property-values.js';
3
4
  import type { ResolvedClass } from '../class/resolved.js';
5
+ import type { ResolvedDefinition } from '../resolved.js';
4
6
  import type { CoreDefinition } from './model/core.js';
5
7
  export interface ResolvedCoreDefinition {
6
8
  readonly ref: CoreDefinition['ref'];
@@ -13,9 +15,11 @@ export interface ResolvedDomainEndpoint {
13
15
  readonly kind: 'domain';
14
16
  readonly origin: string;
15
17
  }
18
+ /** The owning Domain, one local Definition, or one local Class-owned Method. */
19
+ export type ResolvedCoreEndpoint = ResolvedDefinition | ResolvedMethod | ResolvedDomainEndpoint;
16
20
  export interface ResolvedCoreEdge {
17
21
  readonly class: ResolvedClass<'edge'>;
18
- readonly source: ResolvedCoreDefinition | ResolvedDomainEndpoint;
19
- readonly target: ResolvedCoreDefinition | ResolvedDomainEndpoint;
22
+ readonly source: ResolvedCoreEndpoint;
23
+ readonly target: ResolvedCoreEndpoint;
20
24
  readonly properties: PropertyValues;
21
25
  }
@@ -21,7 +21,7 @@ export type { Definition } from './definition.js';
21
21
  export type { ResolvedDefinition, ResolvedDefinitionOf } from './resolved.js';
22
22
  export type { Diagnostic, DiagnosticCode } from './validation/diagnostic.js';
23
23
  export type * from './policy/model/policy.js';
24
- export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './policy/model/policy.js';
24
+ export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './policy/model/policy.js';
25
25
  export type * from './policy/resolved.js';
26
26
  export type * from './view/model/view.js';
27
27
  export type * from './view/resolved.js';
@@ -1,4 +1,4 @@
1
1
  export { isMethodExecutable } from './callable/executable.js';
2
2
  export { stateMachine } from './state/index.js';
3
3
  export { PropertyValues } from './class/property-values.js';
4
- export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './policy/model/policy.js';
4
+ export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './policy/model/policy.js';
@@ -1,4 +1,4 @@
1
1
  export type * from './model/policy.js';
2
- export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './model/policy.js';
2
+ export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './model/policy.js';
3
3
  export type * from './resolved.js';
4
4
  export * from './normalization/normalize.js';
@@ -1,2 +1,2 @@
1
- export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './model/policy.js';
1
+ export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './model/policy.js';
2
2
  export * from './normalization/normalize.js';
@@ -89,6 +89,7 @@ export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | Cor
89
89
  /** Exact projected identity, including Class-owned Method declarations. */
90
90
  export declare function policyObjectKey(ref: PolicyObjectRef): string;
91
91
  export declare function policyObjectOrigin(ref: PolicyObjectRef): string;
92
+ export declare function projectedMemberClass(ref: Exclude<PolicyObjectRef, CoreRef>): ClassRef;
92
93
  export type PolicyCheckObject = {
93
94
  readonly kind: 'self';
94
95
  } | {
@@ -16,3 +16,20 @@ export function policyObjectKey(ref) {
16
16
  export function policyObjectOrigin(ref) {
17
17
  return ref.kind === 'method' ? ref.owner.origin : ref.origin;
18
18
  }
19
+ /**
20
+ * The Kernel declaration Class each projected member materializes as. A Core Node is absent: it
21
+ * keeps the concrete Class its own Domain authored, which only that Domain's schema can resolve.
22
+ */
23
+ const PROJECTED_MEMBER_CLASSES = Object.freeze({
24
+ class: kernelClassRef('Class'),
25
+ function: kernelClassRef('Function'),
26
+ method: kernelClassRef('Function'),
27
+ policy: kernelClassRef('Policy'),
28
+ view: kernelClassRef('View'),
29
+ });
30
+ export function projectedMemberClass(ref) {
31
+ return PROJECTED_MEMBER_CLASSES[ref.kind];
32
+ }
33
+ function kernelClassRef(name) {
34
+ return Object.freeze({ origin: 'kernel.astrale.ai', kind: 'class', name });
35
+ }
@@ -1,3 +1,3 @@
1
1
  import type { ValueProgram } from './model.js';
2
2
  /** Exact field constraints available for independent scalar route validation. */
3
- export declare function inputFieldNodes(program: ValueProgram): Readonly<Record<string, readonly number[]>> | undefined;
3
+ export declare function inputFieldNodes(program: Pick<ValueProgram, 'root' | 'nodes'>): Readonly<Record<string, readonly number[]>> | undefined;
@@ -1,4 +1,6 @@
1
1
  import type { CompiledInstanceSchema } from '../evaluate/types.js';
2
- import type { ValueProgram } from './model.js';
2
+ import type { IndexedValueProgram, ValueProgram } from './model.js';
3
+ /** Bind already-admitted entry-local indices without copying any pattern machine. */
4
+ export declare function bindValueProgram(program: IndexedValueProgram, patterns: ValueProgram['patterns']): ValueProgram;
3
5
  /** Bind admitted portable indices to the canonical instance evaluator. */
4
- export declare function loadValueProgram(program: ValueProgram): CompiledInstanceSchema;
6
+ export declare function loadValueProgram(program: ValueProgram, rootIndex?: number): CompiledInstanceSchema;
@@ -1,7 +1,28 @@
1
1
  import { loadPattern } from '../regexp/matcher.js';
2
2
  import { appendPointer } from '../syntax/pointer.js';
3
+ const loadedPrograms = new WeakMap();
4
+ /** Bind already-admitted entry-local indices without copying any pattern machine. */
5
+ export function bindValueProgram(program, patterns) {
6
+ return Object.freeze({
7
+ ...program,
8
+ patterns: Object.freeze(program.patterns.map((index) => patterns[index])),
9
+ });
10
+ }
3
11
  /** Bind admitted portable indices to the canonical instance evaluator. */
4
- export function loadValueProgram(program) {
12
+ export function loadValueProgram(program, rootIndex = program.root) {
13
+ let compiled = loadedPrograms.get(program);
14
+ if (compiled === undefined) {
15
+ compiled = createValueProgram(program);
16
+ loadedPrograms.set(program, compiled);
17
+ }
18
+ if (rootIndex === program.root)
19
+ return compiled;
20
+ const root = compiled.locations.get(String(rootIndex));
21
+ if (root === undefined)
22
+ throw new TypeError('Compiled value program root is absent.');
23
+ return { ...compiled, root };
24
+ }
25
+ function createValueProgram(program) {
5
26
  const resource = { key: 'compiled', schema: true, ownerOrigin: 'compiled' };
6
27
  const locations = program.nodes.map((node, index) => ({
7
28
  key: String(index),
@@ -14,6 +14,17 @@ export interface Pattern {
14
14
  readonly start: number;
15
15
  readonly states: readonly PatternState[];
16
16
  }
17
+ /** A scalar run counts Unicode scalars, never UTF-16 code units. */
18
+ export interface ScalarRun {
19
+ readonly ranges: readonly ScalarRange[];
20
+ readonly minimum: number;
21
+ readonly maximum?: number;
22
+ }
23
+ /** All runs except the last have an exact finite length. */
24
+ export interface RunPattern {
25
+ readonly source: string;
26
+ readonly runs: readonly ScalarRun[];
27
+ }
17
28
  export interface ValueNode {
18
29
  readonly schema: JsonValue;
19
30
  readonly children: Readonly<Record<string, number>>;
@@ -23,5 +34,9 @@ export interface ValueNode {
23
34
  export interface ValueProgram {
24
35
  readonly root: number;
25
36
  readonly nodes: readonly ValueNode[];
26
- readonly patterns: readonly Pattern[];
37
+ readonly patterns: readonly (Pattern | RunPattern)[];
38
+ }
39
+ /** Pattern indices belong to the enclosing compiled entry's table. */
40
+ export interface IndexedValueProgram extends Omit<ValueProgram, 'patterns'> {
41
+ readonly patterns: readonly number[];
27
42
  }
@@ -1,6 +1,8 @@
1
1
  import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
2
2
  export declare function matchesType(input: string, value: JsonValue): boolean;
3
3
  export declare function jsonEqual(left: JsonValue, right: JsonValue): boolean;
4
+ /** Count Unicode code points with string-iterator semantics, without a character array. */
5
+ export declare function codePointLength(input: string): number;
4
6
  export declare function unique(values: readonly JsonValue[]): boolean;
5
7
  /** Compare finite JSON numbers as their exact ECMAScript decimal spellings. */
6
8
  export declare function isMultipleOf(value: number, divisor: number): boolean;
@@ -21,6 +21,19 @@ export function matchesType(input, value) {
21
21
  export function jsonEqual(left, right) {
22
22
  return equal(left, right);
23
23
  }
24
+ /** Count Unicode code points with string-iterator semantics, without a character array. */
25
+ export function codePointLength(input) {
26
+ let length = 0;
27
+ for (let index = 0; index < input.length; index++, length++) {
28
+ const first = input.charCodeAt(index);
29
+ if (first >= 0xd800 && first <= 0xdbff && index + 1 < input.length) {
30
+ const second = input.charCodeAt(index + 1);
31
+ if (second >= 0xdc00 && second <= 0xdfff)
32
+ index++;
33
+ }
34
+ }
35
+ return length;
36
+ }
24
37
  export function unique(values) {
25
38
  const seen = new Set();
26
39
  for (const value of values) {
@@ -1,15 +1,21 @@
1
1
  import { isInstantValue } from '../model/instant.js';
2
2
  import { isValueObject as isJsonObject } from '../model/object.js';
3
3
  import { appendPointer } from '../syntax/pointer.js';
4
- import { isMultipleOf, jsonEqual, matchesType, unique } from './assertions.js';
4
+ import { codePointLength, isMultipleOf, jsonEqual, matchesType, unique } from './assertions.js';
5
5
  import { evaluation, mergeAnnotations } from './types.js';
6
6
  /** Evaluate complete Draft 2020-12 acceptance without dynamic source generation. */
7
7
  export function evaluateInstance(compiled, input) {
8
8
  return new InstanceEvaluator(compiled).evaluate(compiled.root, input, '');
9
9
  }
10
+ /** Bound per-call retention independently of the size or diversity of an input value. */
11
+ const MAX_CACHED_PATTERN_RESULTS = 256;
12
+ const MAX_CACHED_PATTERN_INPUT_LENGTH = 128;
10
13
  class InstanceEvaluator {
11
14
  compiled;
12
15
  active = new Set();
16
+ searchResults = new Map();
17
+ fullMatchResults = new Map();
18
+ patternResultCount = 0;
13
19
  constructor(compiled) {
14
20
  this.compiled = compiled;
15
21
  }
@@ -79,14 +85,20 @@ class InstanceEvaluator {
79
85
  });
80
86
  const anyOf = schemaList(schema.anyOf);
81
87
  if (anyOf !== undefined) {
82
- const results = anyOf.map((_, index) => this.evaluate(this.child(location, 'anyOf', index), input, instancePointer));
83
- const admitted = results.filter(({ valid }) => valid);
84
- if (admitted.length === 0) {
88
+ let admitted = 0;
89
+ anyOf.forEach((_, index) => {
90
+ const branch = this.child(location, 'anyOf', index);
91
+ if (contradictsRequiredConst(branch.schema, input))
92
+ return;
93
+ const result = this.evaluate(branch, input, instancePointer);
94
+ if (!result.valid)
95
+ return;
96
+ admitted += 1;
97
+ mergeAnnotations(properties, items, result);
98
+ });
99
+ if (admitted === 0) {
85
100
  failures.push(invalid(instancePointer, 'anyOf', 'Value satisfies no anyOf branch.'));
86
101
  }
87
- else {
88
- admitted.forEach((result) => mergeAnnotations(properties, items, result));
89
- }
90
102
  }
91
103
  const oneOf = schemaList(schema.oneOf);
92
104
  if (oneOf !== undefined) {
@@ -154,18 +166,23 @@ class InstanceEvaluator {
154
166
  }
155
167
  }
156
168
  evaluateStringAssertions(schema, input, instancePointer, failures) {
157
- const length = Array.from(input).length;
158
- if (typeof schema.maxLength === 'number' && length > schema.maxLength) {
159
- failures.push(invalid(instancePointer, 'maxLength', 'String exceeds maxLength.'));
160
- }
161
- if (typeof schema.minLength === 'number' && length < schema.minLength) {
162
- failures.push(invalid(instancePointer, 'minLength', 'String is below minLength.'));
169
+ // For n UTF-16 units, ceil(n / 2) <= code points <= n. Count only if those
170
+ // bounds cannot already prove both length assertions; other assertions still run.
171
+ if ((typeof schema.maxLength === 'number' && input.length > schema.maxLength) ||
172
+ (typeof schema.minLength === 'number' && Math.ceil(input.length / 2) < schema.minLength)) {
173
+ const length = codePointLength(input);
174
+ if (typeof schema.maxLength === 'number' && length > schema.maxLength) {
175
+ failures.push(invalid(instancePointer, 'maxLength', 'String exceeds maxLength.'));
176
+ }
177
+ if (typeof schema.minLength === 'number' && length < schema.minLength) {
178
+ failures.push(invalid(instancePointer, 'minLength', 'String is below minLength.'));
179
+ }
163
180
  }
164
- if (typeof schema.pattern === 'string' && !this.compiled.matcher(schema.pattern).test(input)) {
181
+ if (typeof schema.pattern === 'string' && !this.matchesPattern(schema.pattern, input, false)) {
165
182
  failures.push(invalid(instancePointer, 'pattern', 'String does not match pattern.'));
166
183
  }
167
184
  if (typeof schema.fullMatch === 'string' &&
168
- !this.compiled.matcher(schema.fullMatch).matches(input)) {
185
+ !this.matchesPattern(schema.fullMatch, input, true)) {
169
186
  failures.push(invalid(instancePointer, 'fullMatch', 'String does not match fullMatch.'));
170
187
  }
171
188
  }
@@ -284,9 +301,8 @@ class InstanceEvaluator {
284
301
  const patternMatched = new Set();
285
302
  let patternsValid = true;
286
303
  for (const pattern of Object.keys(patterns)) {
287
- const matcher = this.compiled.matcher(pattern);
288
304
  for (const name of names) {
289
- if (!matcher.test(name))
305
+ if (!this.matchesPattern(pattern, name, false))
290
306
  continue;
291
307
  patternMatched.add(name);
292
308
  const result = this.evaluate(this.child(location, 'patternProperties', pattern), input[name], appendPointer(instancePointer, name));
@@ -349,6 +365,51 @@ class InstanceEvaluator {
349
365
  child(parent, keyword, member) {
350
366
  return this.compiled.child(parent, keyword, member);
351
367
  }
368
+ matchesPattern(source, input, whole) {
369
+ const cacheable = input.length <= MAX_CACHED_PATTERN_INPUT_LENGTH;
370
+ const cache = whole ? this.fullMatchResults : this.searchResults;
371
+ if (cacheable) {
372
+ const found = cache.get(source)?.get(input);
373
+ if (found !== undefined)
374
+ return found;
375
+ }
376
+ const matcher = this.compiled.matcher(source);
377
+ const result = whole ? matcher.matches(input) : matcher.test(input);
378
+ if (cacheable && this.patternResultCount < MAX_CACHED_PATTERN_RESULTS) {
379
+ let values = cache.get(source);
380
+ if (values === undefined) {
381
+ values = new Map();
382
+ cache.set(source, values);
383
+ }
384
+ values.set(input, result);
385
+ this.patternResultCount++;
386
+ }
387
+ return result;
388
+ }
389
+ }
390
+ /** A required property with a different primitive const makes the entire branch impossible. */
391
+ function contradictsRequiredConst(schema, input) {
392
+ if (!isJsonObject(schema) || !isJsonObject(input) || !Array.isArray(schema.required)) {
393
+ return false;
394
+ }
395
+ if (!isJsonObject(schema.properties))
396
+ return false;
397
+ for (const key of schema.required) {
398
+ if (typeof key !== 'string' || !Object.hasOwn(input, key))
399
+ continue;
400
+ const property = schema.properties[key];
401
+ if (!isJsonObject(property) || !Object.hasOwn(property, 'const'))
402
+ continue;
403
+ const expected = property.const;
404
+ if ((expected === null ||
405
+ typeof expected === 'string' ||
406
+ typeof expected === 'number' ||
407
+ typeof expected === 'boolean') &&
408
+ input[key] !== expected) {
409
+ return true;
410
+ }
411
+ }
412
+ return false;
352
413
  }
353
414
  function schemaList(input) {
354
415
  return Array.isArray(input) ? input : undefined;
@@ -1,6 +1,8 @@
1
1
  import type { JsonSchema } from '../model/schema.js';
2
2
  import type { ValueSchemaRegistry } from '../reference/registry.js';
3
+ import type { IRegexpMatcher } from '../regexp/matcher.js';
3
4
  import type { CompiledInstanceSchema } from './types.js';
5
+ import { compilePattern } from '../regexp/compile.js';
4
6
  export type InstanceSchemaCompilation = {
5
7
  readonly compiled: true;
6
8
  readonly value: CompiledInstanceSchema;
@@ -8,6 +10,13 @@ export type InstanceSchemaCompilation = {
8
10
  readonly compiled: false;
9
11
  readonly message: string;
10
12
  };
13
+ /** Owned by one compilation or source-resolution closure, not retained process-globally. */
14
+ interface PreparedPattern {
15
+ readonly pattern: ReturnType<typeof compilePattern>;
16
+ readonly matcher: IRegexpMatcher;
17
+ }
18
+ export type PatternPool = Map<string, PreparedPattern>;
11
19
  /** Prepare reference and linear-regexp state without generating executable source. */
12
- export declare function prepareValueSchema(schema: JsonSchema, registry: ValueSchemaRegistry, pointer: string): InstanceSchemaCompilation;
20
+ export declare function prepareValueSchema(schema: JsonSchema, registry: ValueSchemaRegistry, pointer: string, pool?: PatternPool): InstanceSchemaCompilation;
13
21
  export declare function childKey(pointer: string): string;
22
+ export {};