@astrale-os/kernel-dsl 0.2.0-beta.9 → 1.0.0-beta.1
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/v1/addressing/class-key.js +5 -4
- package/dist/v1/addressing/method-key.js +3 -2
- package/dist/v1/addressing/patterns.d.ts +0 -5
- package/dist/v1/addressing/patterns.js +5 -5
- package/dist/v1/builder/callable/authoring.d.ts +87 -41
- package/dist/v1/builder/callable/authoring.js +29 -14
- package/dist/v1/builder/class/authoring.d.ts +311 -36
- package/dist/v1/builder/class/authoring.js +3 -4
- package/dist/v1/builder/class/property.d.ts +16 -8
- package/dist/v1/builder/class/property.js +21 -5
- package/dist/v1/builder/core/authoring.d.ts +28 -13
- package/dist/v1/builder/core/authoring.js +22 -2
- package/dist/v1/builder/index.d.ts +9 -8
- package/dist/v1/builder/index.js +2 -2
- package/dist/v1/builder/lowering/callable.d.ts +3 -1
- package/dist/v1/builder/lowering/callable.js +43 -51
- package/dist/v1/builder/lowering/class.d.ts +7 -0
- package/dist/v1/builder/lowering/class.js +79 -29
- package/dist/v1/builder/lowering/core.d.ts +3 -2
- package/dist/v1/builder/lowering/core.js +9 -6
- package/dist/v1/builder/lowering/policy.d.ts +8 -1
- package/dist/v1/builder/lowering/policy.js +35 -0
- package/dist/v1/builder/lowering/schema/capture.js +9 -4
- package/dist/v1/builder/lowering/schema/compile.d.ts +2 -2
- package/dist/v1/builder/lowering/schema/compile.js +15 -2
- package/dist/v1/builder/lowering/schema/context.d.ts +11 -8
- package/dist/v1/builder/lowering/schema/context.js +59 -29
- package/dist/v1/builder/lowering/schema/ownership.d.ts +3 -3
- package/dist/v1/builder/lowering/schema/ownership.js +2 -1
- package/dist/v1/builder/lowering/value/compile.js +14 -4
- package/dist/v1/builder/lowering/value/zod.d.ts +7 -6
- package/dist/v1/builder/lowering/value/zod.js +16 -7
- package/dist/v1/builder/lowering/view.d.ts +4 -3
- package/dist/v1/builder/lowering/view.js +2 -14
- package/dist/v1/builder/policy/authoring.d.ts +23 -6
- package/dist/v1/builder/policy/authoring.js +35 -8
- package/dist/v1/builder/schema/define.d.ts +8 -5
- package/dist/v1/builder/schema/diagnostic.d.ts +1 -1
- package/dist/v1/builder/schema/handle.d.ts +2 -1
- package/dist/v1/builder/schema/input.d.ts +9 -1
- package/dist/v1/builder/schema/projection/callable.d.ts +51 -0
- package/dist/v1/builder/schema/projection/callable.js +1 -0
- package/dist/v1/builder/schema/projection/class.d.ts +89 -0
- package/dist/v1/builder/schema/projection/class.js +1 -0
- package/dist/v1/builder/schema/projection/core-input.d.ts +32 -0
- package/dist/v1/builder/schema/projection/core-input.js +1 -0
- package/dist/v1/builder/schema/projection/domain.d.ts +59 -0
- package/dist/v1/builder/schema/projection/domain.js +1 -0
- package/dist/v1/builder/schema/projection/identity.d.ts +39 -0
- package/dist/v1/builder/schema/projection/identity.js +1 -0
- package/dist/v1/builder/schema/projection/model.d.ts +59 -0
- package/dist/v1/builder/schema/projection/model.js +1 -0
- package/dist/v1/builder/schema/projection/property.d.ts +32 -0
- package/dist/v1/builder/schema/projection/property.js +1 -0
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +76 -0
- package/dist/v1/builder/schema/projection/resolved-class.js +1 -0
- package/dist/v1/builder/schema/projection.d.ts +4 -258
- package/dist/v1/builder/value/full-match.js +6 -3
- package/dist/v1/builder/value/path.d.ts +2 -2
- package/dist/v1/builder/value/path.js +2 -2
- package/dist/v1/builder/view/authoring.d.ts +6 -14
- package/dist/v1/builder/view/authoring.js +13 -5
- package/dist/v1/bundle/structure.d.ts +2 -1
- package/dist/v1/compiled/admission/accept.d.ts +1 -1
- package/dist/v1/compiled/admission/accept.js +11 -814
- package/dist/v1/compiled/admission/closure.d.ts +3 -0
- package/dist/v1/compiled/admission/closure.js +173 -0
- package/dist/v1/compiled/admission/diagnostic.d.ts +7 -0
- package/dist/v1/compiled/admission/diagnostic.js +13 -0
- package/dist/v1/compiled/admission/revision.js +9 -1
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/cardinality.js +113 -0
- package/dist/v1/compiled/admission/semantics/class.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/class.js +125 -0
- package/dist/v1/compiled/admission/semantics/context.d.ts +60 -0
- package/dist/v1/compiled/admission/semantics/context.js +81 -0
- package/dist/v1/compiled/admission/semantics/core.d.ts +35 -0
- package/dist/v1/compiled/admission/semantics/core.js +123 -0
- package/dist/v1/compiled/admission/semantics/edge.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/edge.js +89 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.js +63 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.js +72 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +24 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +45 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.js +27 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +9 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.js +81 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.js +138 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +78 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +28 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.js +206 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +10 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.js +65 -0
- package/dist/v1/compiled/admission/semantics.d.ts +1 -1
- package/dist/v1/compiled/admission/semantics.js +8 -1078
- package/dist/v1/compiled/admission/wire/callable.d.ts +6 -0
- package/dist/v1/compiled/admission/wire/callable.js +90 -0
- package/dist/v1/compiled/admission/wire/class.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/class.js +133 -0
- package/dist/v1/compiled/admission/wire/core.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/core.js +32 -0
- package/dist/v1/compiled/admission/wire/dependency.d.ts +14 -0
- package/dist/v1/compiled/admission/wire/dependency.js +43 -0
- package/dist/v1/compiled/admission/wire/entry.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/entry.js +100 -0
- package/dist/v1/compiled/admission/wire/pattern.d.ts +12 -0
- package/dist/v1/compiled/admission/wire/pattern.js +111 -0
- package/dist/v1/compiled/admission/wire/policy.d.ts +10 -0
- package/dist/v1/compiled/admission/wire/policy.js +189 -0
- package/dist/v1/compiled/admission/wire/program.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/program.js +52 -0
- package/dist/v1/compiled/admission/wire/property.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/property.js +74 -0
- package/dist/v1/compiled/admission/wire/reference.d.ts +8 -0
- package/dist/v1/compiled/admission/wire/reference.js +33 -0
- package/dist/v1/compiled/admission/wire/value.d.ts +29 -0
- package/dist/v1/compiled/admission/wire/value.js +98 -0
- package/dist/v1/compiled/admission/wire/view.d.ts +3 -0
- package/dist/v1/compiled/admission/wire/view.js +17 -0
- package/dist/v1/compiled/compiler/compile.js +43 -11
- package/dist/v1/compiled/generated.d.ts +10 -0
- package/dist/v1/compiled/generated.js +15 -0
- package/dist/v1/compiled/loader/load.d.ts +5 -0
- package/dist/v1/compiled/loader/load.js +18 -4
- package/dist/v1/compiled/model/schema.d.ts +16 -7
- package/dist/v1/domain/create.js +18 -28
- package/dist/v1/domain/model/domain.d.ts +0 -1
- package/dist/v1/domain/model/input.d.ts +3 -0
- package/dist/v1/domain/projection/classes.js +13 -41
- package/dist/v1/domain/validation/create.d.ts +2 -0
- package/dist/v1/domain/validation/create.js +12 -0
- package/dist/v1/index.d.ts +5 -2
- package/dist/v1/index.js +3 -1
- package/dist/v1/language/callable/composition.d.ts +27 -0
- package/dist/v1/language/callable/composition.js +52 -0
- package/dist/v1/language/callable/executable.d.ts +6 -0
- package/dist/v1/language/callable/executable.js +4 -0
- package/dist/v1/language/callable/model/callable.d.ts +34 -9
- package/dist/v1/language/callable/model/callable.js +3 -1
- package/dist/v1/language/callable/resolved.d.ts +23 -8
- package/dist/v1/language/class/facets.d.ts +5 -2
- package/dist/v1/language/class/inheritance.d.ts +12 -0
- package/dist/v1/language/class/inheritance.js +25 -0
- package/dist/v1/language/class/lifetime.d.ts +17 -0
- package/dist/v1/language/class/lifetime.js +26 -0
- package/dist/v1/language/class/model/class.d.ts +8 -4
- package/dist/v1/language/class/model/property.d.ts +4 -2
- package/dist/v1/language/class/property-values.js +5 -2
- package/dist/v1/language/class/resolved.d.ts +25 -15
- package/dist/v1/language/core/model/core.d.ts +7 -1
- package/dist/v1/language/core/resolved.d.ts +6 -2
- package/dist/v1/language/definition/metadata.d.ts +8 -0
- package/dist/v1/language/definition/metadata.js +12 -0
- package/dist/v1/language/index.d.ts +9 -0
- package/dist/v1/language/index.js +6 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +4 -3
- package/dist/v1/language/policy/analysis/branches.js +54 -12
- package/dist/v1/language/policy/analysis/budgets.js +1 -1
- package/dist/v1/language/policy/analysis/checks.d.ts +28 -0
- package/dist/v1/language/policy/analysis/checks.js +80 -0
- package/dist/v1/language/policy/index.d.ts +1 -0
- package/dist/v1/language/policy/index.js +1 -0
- package/dist/v1/language/policy/model/policy.d.ts +71 -5
- package/dist/v1/language/policy/model/policy.js +52 -1
- package/dist/v1/language/policy/normalization/normalize.d.ts +12 -1
- package/dist/v1/language/policy/normalization/normalize.js +178 -44
- package/dist/v1/language/state/index.d.ts +3 -0
- package/dist/v1/language/state/index.js +1 -0
- package/dist/v1/language/state/machine.d.ts +28 -0
- package/dist/v1/language/state/machine.js +40 -0
- package/dist/v1/language/state/topology.d.ts +14 -0
- package/dist/v1/language/state/topology.js +69 -0
- package/dist/v1/language/value/compile/fields.d.ts +1 -1
- package/dist/v1/language/value/compile/load.d.ts +4 -2
- package/dist/v1/language/value/compile/load.js +22 -1
- package/dist/v1/language/value/compile/model.d.ts +16 -1
- package/dist/v1/language/value/evaluate/assertions.d.ts +2 -0
- package/dist/v1/language/value/evaluate/assertions.js +13 -0
- package/dist/v1/language/value/evaluate/evaluator.js +111 -28
- package/dist/v1/language/value/evaluate/preparation.d.ts +10 -1
- package/dist/v1/language/value/evaluate/preparation.js +17 -26
- package/dist/v1/language/value/evaluate/program.js +1 -1
- package/dist/v1/language/value/evaluate/validate.d.ts +6 -2
- package/dist/v1/language/value/evaluate/validate.js +18 -11
- package/dist/v1/language/value/inclusion/includes.d.ts +9 -0
- package/dist/v1/language/value/inclusion/includes.js +777 -0
- package/dist/v1/language/value/model/blob.d.ts +31 -0
- package/dist/v1/language/value/model/blob.js +90 -0
- package/dist/v1/language/value/model/instant.d.ts +0 -2
- package/dist/v1/language/value/model/instant.js +1 -1
- package/dist/v1/language/value/model/schema.d.ts +2 -1
- package/dist/v1/language/value/model/schema.js +1 -5
- package/dist/v1/language/value/ordering.d.ts +2 -0
- package/dist/v1/language/value/ordering.js +4 -8
- package/dist/v1/language/value/profile/json.validate.js +1 -1
- package/dist/v1/language/value/profile/rules.js +48 -12
- package/dist/v1/language/value/reference/registry.d.ts +2 -1
- package/dist/v1/language/value/regexp/ast.js +3 -64
- package/dist/v1/language/value/regexp/compile.d.ts +32 -3
- package/dist/v1/language/value/regexp/compile.js +117 -21
- package/dist/v1/language/value/regexp/matcher.d.ts +6 -3
- package/dist/v1/language/value/regexp/matcher.js +185 -28
- package/dist/v1/language/value/regexp/syntax.d.ts +12 -1
- package/dist/v1/language/value/regexp/syntax.js +14 -2
- package/dist/v1/language/value/regexp/unicode.d.ts +32 -0
- package/dist/v1/language/value/regexp/unicode.js +139 -0
- package/dist/v1/language/value/syntax/full-match.js +8 -5
- package/dist/v1/language/value/syntax/node-path/validate.js +4 -6
- package/dist/v1/language/view/model/view.d.ts +2 -4
- package/dist/v1/language/view/resolved.d.ts +2 -2
- package/dist/v1/schema/analysis/class.d.ts +36 -6
- package/dist/v1/schema/analysis/class.js +31 -66
- package/dist/v1/schema/canonical/revision.d.ts +2 -1
- package/dist/v1/schema/canonical/revision.js +4 -1
- package/dist/v1/schema/compatibility/api.d.ts +3 -0
- package/dist/v1/schema/compatibility/api.js +2 -0
- package/dist/v1/schema/compatibility/comparators/callables.d.ts +39 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +101 -0
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +47 -0
- package/dist/v1/schema/compatibility/comparators/classes.js +160 -0
- package/dist/v1/schema/compatibility/comparators/index.d.ts +12 -0
- package/dist/v1/schema/compatibility/comparators/index.js +53 -0
- package/dist/v1/schema/compatibility/comparators/members.d.ts +4 -0
- package/dist/v1/schema/compatibility/comparators/members.js +49 -0
- package/dist/v1/schema/compatibility/comparators/values.d.ts +5 -0
- package/dist/v1/schema/compatibility/comparators/values.js +37 -0
- package/dist/v1/schema/compatibility/compare.d.ts +5 -0
- package/dist/v1/schema/compatibility/compare.js +23 -0
- package/dist/v1/schema/compatibility/context.d.ts +19 -0
- package/dist/v1/schema/compatibility/context.js +49 -0
- package/dist/v1/schema/compatibility/coordinate.d.ts +40 -0
- package/dist/v1/schema/compatibility/coordinate.js +38 -0
- package/dist/v1/schema/compatibility/diff.d.ts +12 -0
- package/dist/v1/schema/compatibility/diff.js +39 -0
- package/dist/v1/schema/compatibility/evidence.d.ts +16 -0
- package/dist/v1/schema/compatibility/evidence.js +62 -0
- package/dist/v1/schema/compatibility/fields.d.ts +194 -0
- package/dist/v1/schema/compatibility/fields.js +94 -0
- package/dist/v1/schema/compatibility/index.d.ts +6 -0
- package/dist/v1/schema/compatibility/index.js +3 -0
- package/dist/v1/schema/compatibility/meaning/footprint.d.ts +7 -0
- package/dist/v1/schema/compatibility/meaning/footprint.js +59 -0
- package/dist/v1/schema/compatibility/meaning/index.d.ts +3 -0
- package/dist/v1/schema/compatibility/meaning/index.js +16 -0
- package/dist/v1/schema/compatibility/model.d.ts +131 -0
- package/dist/v1/schema/compatibility/model.js +1 -0
- package/dist/v1/schema/compatibility/references.d.ts +38 -0
- package/dist/v1/schema/compatibility/references.js +149 -0
- package/dist/v1/schema/compatibility/report.d.ts +27 -0
- package/dist/v1/schema/compatibility/report.js +100 -0
- package/dist/v1/schema/compatibility/scope.d.ts +36 -0
- package/dist/v1/schema/compatibility/scope.js +110 -0
- package/dist/v1/schema/compatibility/structure/index.d.ts +3 -0
- package/dist/v1/schema/compatibility/structure/index.js +40 -0
- package/dist/v1/schema/compatibility/structure/inheritance.d.ts +7 -0
- package/dist/v1/schema/compatibility/structure/inheritance.js +68 -0
- package/dist/v1/schema/compatibility/structure/requirements.d.ts +7 -0
- package/dist/v1/schema/compatibility/structure/requirements.js +97 -0
- package/dist/v1/schema/compatibility/subjects.d.ts +39 -0
- package/dist/v1/schema/compatibility/subjects.js +143 -0
- package/dist/v1/schema/compatibility/versioning/index.d.ts +8 -0
- package/dist/v1/schema/compatibility/versioning/index.js +50 -0
- package/dist/v1/schema/compatibility/versioning/members.d.ts +12 -0
- package/dist/v1/schema/compatibility/versioning/members.js +47 -0
- package/dist/v1/schema/compatibility/versioning/surface.d.ts +11 -0
- package/dist/v1/schema/compatibility/versioning/surface.js +61 -0
- package/dist/v1/schema/diagnostic.d.ts +1 -1
- package/dist/v1/schema/fingerprint.d.ts +2 -0
- package/dist/v1/schema/fingerprint.js +1 -0
- package/dist/v1/schema/index.d.ts +4 -3
- package/dist/v1/schema/index.js +2 -1
- package/dist/v1/schema/model/schema.d.ts +8 -11
- package/dist/v1/schema/normalization/domain.js +57 -13
- package/dist/v1/schema/resolution/definition.index.d.ts +1 -2
- package/dist/v1/schema/resolution/definition.index.js +0 -3
- package/dist/v1/schema/resolution/domain.d.ts +4 -1
- package/dist/v1/schema/resolution/domain.js +26 -18
- package/dist/v1/schema/resolution/origins.d.ts +28 -5
- package/dist/v1/schema/resolution/origins.js +68 -31
- package/dist/v1/schema/validation/callable.d.ts +4 -0
- package/dist/v1/schema/validation/callable.js +39 -0
- package/dist/v1/schema/validation/class.d.ts +10 -0
- package/dist/v1/schema/validation/class.js +79 -60
- package/dist/v1/schema/validation/core.js +83 -55
- package/dist/v1/schema/validation/domain.d.ts +2 -1
- package/dist/v1/schema/validation/domain.js +2 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +0 -2
- package/dist/v1/schema/validation/domain.structure.js +214 -171
- package/dist/v1/schema/validation/policy/budgets.js +36 -6
- package/dist/v1/schema/validation/policy/context.js +5 -16
- package/dist/v1/schema/validation/policy/objects.d.ts +4 -0
- package/dist/v1/schema/validation/policy/objects.js +71 -0
- package/dist/v1/schema/validation/policy/references.js +16 -4
- package/dist/v1/schema/validation/policy/typing.d.ts +2 -0
- package/dist/v1/schema/validation/policy/typing.js +55 -7
- package/dist/v1/schema/validation/policy/uses.js +73 -99
- package/dist/v1/schema/validation/value-api.d.ts +2 -0
- package/dist/v1/schema/validation/value-api.js +1 -0
- package/dist/v1/schema/validation/value.js +7 -1
- package/dist/v1/schema/validation/view.js +14 -9
- package/dist/value/accept.d.ts +9 -0
- package/dist/value/accept.js +106 -7
- package/dist/value/canonical.d.ts +3 -0
- package/dist/value/canonical.js +22 -6
- package/dist/value/immutable.optimization.d.ts +15 -0
- package/dist/value/immutable.optimization.js +34 -0
- package/dist/value/index.d.ts +1 -1
- package/dist/value/index.js +1 -1
- package/dist/value/json.d.ts +1 -1
- package/dist/value/json.js +1 -1
- package/dist/value/limits.d.ts +1 -1
- package/dist/value/unicode.d.ts +4 -1
- package/dist/value/unicode.js +28 -0
- package/package.json +19 -3
- package/dist/v1/schema/compatibility/meaning.d.ts +0 -29
- package/dist/v1/schema/compatibility/meaning.js +0 -605
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PolicyCheckExpression } from '../model/policy.js';
|
|
2
|
+
export type PolicyCheckLeaf = Extract<PolicyCheckExpression, {
|
|
3
|
+
readonly check: unknown;
|
|
4
|
+
}>;
|
|
5
|
+
/** How one check leaf types against the Classes its object accepts. */
|
|
6
|
+
export interface CheckLeafClasses {
|
|
7
|
+
/** Every Class the leaf's object accepts. */
|
|
8
|
+
readonly accepted: readonly string[];
|
|
9
|
+
/** The accepted Classes at least one normalized branch of the leaf's Policy is typed for. */
|
|
10
|
+
readonly admitted: ReadonlySet<string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The Classes a leaf admits, from the typing of each normalized branch of its Policy for each
|
|
14
|
+
* accepted Class of its object. `undefined` when the Policy does not expand, or when one branch is
|
|
15
|
+
* typed for no accepted Class: that branch can never match this object, so it is refused rather
|
|
16
|
+
* than silently erased.
|
|
17
|
+
*/
|
|
18
|
+
export declare function admittedCheckClasses(typing: ReadonlyMap<string, readonly boolean[] | undefined>): ReadonlySet<string> | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The accepted Classes of each object that the whole check tree can never admit.
|
|
21
|
+
*
|
|
22
|
+
* The tree is read in disjunctive normal form. A conjunction admits Class C of object O when every
|
|
23
|
+
* leaf over O in it admits C and every other object it checks keeps a Class that all of its leaves
|
|
24
|
+
* over that object admit; an object the conjunction does not check keeps every accepted Class.
|
|
25
|
+
* `sameNode` compares identities, not Classes, so it never removes a Class here. A tree over the
|
|
26
|
+
* check budget is already refused, so it is not expanded.
|
|
27
|
+
*/
|
|
28
|
+
export declare function neverAdmittedClasses(expression: PolicyCheckExpression, leaves: ReadonlyMap<PolicyCheckLeaf, CheckLeafClasses>): readonly (readonly [object: string, className: string])[];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { policyObjectKey } from '../model/policy.js';
|
|
2
|
+
import { MAX_BRANCHES, measureChecks } from './budgets.js';
|
|
3
|
+
/** Names a callable check object. Every leaf over one object sees the same Node at runtime. */
|
|
4
|
+
function checkObjectName(object) {
|
|
5
|
+
if (object.kind === 'self')
|
|
6
|
+
return 'self';
|
|
7
|
+
if (object.kind === 'input')
|
|
8
|
+
return `input.${object.field}`;
|
|
9
|
+
return policyObjectKey(object.ref);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The Classes a leaf admits, from the typing of each normalized branch of its Policy for each
|
|
13
|
+
* accepted Class of its object. `undefined` when the Policy does not expand, or when one branch is
|
|
14
|
+
* typed for no accepted Class: that branch can never match this object, so it is refused rather
|
|
15
|
+
* than silently erased.
|
|
16
|
+
*/
|
|
17
|
+
export function admittedCheckClasses(typing) {
|
|
18
|
+
const rows = [...typing];
|
|
19
|
+
if (!rows.every((row) => row[1] !== undefined)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const branches = Math.max(0, ...rows.map(([, row]) => row.length));
|
|
23
|
+
for (let index = 0; index < branches; index++) {
|
|
24
|
+
if (!rows.some(([, row]) => row[index] === true))
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return new Set(rows.filter(([, row]) => row.some(Boolean)).map(([name]) => name));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The accepted Classes of each object that the whole check tree can never admit.
|
|
31
|
+
*
|
|
32
|
+
* The tree is read in disjunctive normal form. A conjunction admits Class C of object O when every
|
|
33
|
+
* leaf over O in it admits C and every other object it checks keeps a Class that all of its leaves
|
|
34
|
+
* over that object admit; an object the conjunction does not check keeps every accepted Class.
|
|
35
|
+
* `sameNode` compares identities, not Classes, so it never removes a Class here. A tree over the
|
|
36
|
+
* check budget is already refused, so it is not expanded.
|
|
37
|
+
*/
|
|
38
|
+
export function neverAdmittedClasses(expression, leaves) {
|
|
39
|
+
if (measureChecks(expression).branches > MAX_BRANCHES)
|
|
40
|
+
return [];
|
|
41
|
+
const accepted = new Map();
|
|
42
|
+
for (const [leaf, classes] of leaves)
|
|
43
|
+
accepted.set(checkObjectName(leaf.object), classes.accepted);
|
|
44
|
+
const admitted = new Map();
|
|
45
|
+
for (const conjunction of disjunctiveForm(expression)) {
|
|
46
|
+
const constrained = new Map();
|
|
47
|
+
for (const leaf of conjunction) {
|
|
48
|
+
if (!('check' in leaf))
|
|
49
|
+
continue;
|
|
50
|
+
const classes = leaves.get(leaf);
|
|
51
|
+
if (classes === undefined)
|
|
52
|
+
continue;
|
|
53
|
+
const object = checkObjectName(leaf.object);
|
|
54
|
+
const previous = constrained.get(object);
|
|
55
|
+
constrained.set(object, previous === undefined
|
|
56
|
+
? classes.admitted
|
|
57
|
+
: new Set([...previous].filter((name) => classes.admitted.has(name))));
|
|
58
|
+
}
|
|
59
|
+
if ([...constrained.values()].some((classes) => classes.size === 0))
|
|
60
|
+
continue;
|
|
61
|
+
for (const [object, all] of accepted) {
|
|
62
|
+
const reached = admitted.get(object) ?? new Set();
|
|
63
|
+
for (const name of constrained.get(object) ?? all)
|
|
64
|
+
reached.add(name);
|
|
65
|
+
admitted.set(object, reached);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return [...accepted].flatMap(([object, all]) => all
|
|
69
|
+
.filter((name) => admitted.get(object)?.has(name) !== true)
|
|
70
|
+
.map((name) => [object, name]));
|
|
71
|
+
}
|
|
72
|
+
function disjunctiveForm(expression) {
|
|
73
|
+
if ('check' in expression || 'sameNode' in expression)
|
|
74
|
+
return [[expression]];
|
|
75
|
+
if ('anyOf' in expression)
|
|
76
|
+
return expression.anyOf.flatMap(disjunctiveForm);
|
|
77
|
+
return expression.allOf
|
|
78
|
+
.map(disjunctiveForm)
|
|
79
|
+
.reduce((left, right) => left.flatMap((prefix) => right.map((suffix) => [...prefix, ...suffix])), [[]]);
|
|
80
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export type * from './model/policy.js';
|
|
2
|
+
export { isClassRuleChecks, policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, projectedMemberClass, } from './model/policy.js';
|
|
2
3
|
export type * from './resolved.js';
|
|
3
4
|
export * from './normalization/normalize.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CoreRef, ClassRef, FunctionRef, PolicyRef, ViewRef, DefinitionBase } from '../../../addressing/index.js';
|
|
1
|
+
import type { CoreRef, ClassRef, FunctionRef, PolicyRef, ViewRef, DefinitionBase, MethodAddress } from '../../../addressing/index.js';
|
|
2
2
|
export type PolicyPatternTerm = {
|
|
3
3
|
readonly kind: 'subject';
|
|
4
4
|
} | {
|
|
@@ -10,14 +10,49 @@ export type PolicyPatternTerm = {
|
|
|
10
10
|
} | {
|
|
11
11
|
readonly kind: 'variable';
|
|
12
12
|
readonly id: number;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'ref';
|
|
15
|
+
readonly ref: PolicyObjectRef;
|
|
13
16
|
};
|
|
14
|
-
|
|
17
|
+
/** Identity equality; both terms must resolve to one valid Node. */
|
|
18
|
+
export interface PolicySameNode<Term> {
|
|
19
|
+
readonly sameNode: {
|
|
20
|
+
readonly left: Term;
|
|
21
|
+
readonly right: Term;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface ExactPolicyVariable {
|
|
15
25
|
readonly variable: {
|
|
16
26
|
readonly kind: 'variable';
|
|
17
27
|
readonly id: number;
|
|
18
28
|
};
|
|
19
29
|
readonly class: ClassRef;
|
|
20
30
|
}
|
|
31
|
+
export interface SelectedPolicyVariable {
|
|
32
|
+
readonly variable: {
|
|
33
|
+
readonly kind: 'variable';
|
|
34
|
+
readonly id: number;
|
|
35
|
+
};
|
|
36
|
+
readonly selector: {
|
|
37
|
+
readonly kind: 'any';
|
|
38
|
+
} | {
|
|
39
|
+
readonly kind: 'satisfies';
|
|
40
|
+
readonly class: ClassRef;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* An existential Node binding. The class-bearing legacy form is deliberately retained as the
|
|
45
|
+
* canonical exact selector so persisted V1 DomainSchema documents keep their original meaning.
|
|
46
|
+
*/
|
|
47
|
+
export type PolicyVariable = ExactPolicyVariable | SelectedPolicyVariable;
|
|
48
|
+
export type PolicyVariableSelector = {
|
|
49
|
+
readonly kind: 'exact';
|
|
50
|
+
readonly class: ClassRef;
|
|
51
|
+
} | SelectedPolicyVariable['selector'];
|
|
52
|
+
/** Resolve the semantic selector while preserving the legacy exact wire representation. */
|
|
53
|
+
export declare function policyVariableSelector(variable: PolicyVariable): PolicyVariableSelector;
|
|
54
|
+
/** Return the selector's referenced Class, when it has one. */
|
|
55
|
+
export declare function policyVariableClass(variable: PolicyVariable): ClassRef | undefined;
|
|
21
56
|
export interface PolicyRepeat {
|
|
22
57
|
readonly min: number;
|
|
23
58
|
readonly max: number;
|
|
@@ -28,7 +63,7 @@ export interface PolicyEdgePattern {
|
|
|
28
63
|
readonly target: PolicyPatternTerm;
|
|
29
64
|
readonly repeat?: PolicyRepeat;
|
|
30
65
|
}
|
|
31
|
-
export type PolicyPatternExpression = PolicyEdgePattern | {
|
|
66
|
+
export type PolicyPatternExpression = PolicyEdgePattern | PolicySameNode<PolicyPatternTerm> | {
|
|
32
67
|
readonly exists: {
|
|
33
68
|
readonly nodes: readonly PolicyVariable[];
|
|
34
69
|
readonly where: PolicyPatternExpression;
|
|
@@ -50,7 +85,33 @@ export interface PolicyDefinition extends DefinitionBase<PolicyRef> {
|
|
|
50
85
|
readonly description?: string;
|
|
51
86
|
}
|
|
52
87
|
/** Local Domain members whose installed projection resolves through one exact member Path. */
|
|
53
|
-
export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | CoreRef;
|
|
88
|
+
export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | CoreRef | MethodAddress;
|
|
89
|
+
/** Exact projected identity, including Class-owned Method declarations. */
|
|
90
|
+
export declare function policyObjectKey(ref: PolicyObjectRef): string;
|
|
91
|
+
export declare function policyObjectOrigin(ref: PolicyObjectRef): string;
|
|
92
|
+
export declare function projectedMemberClass(ref: Exclude<PolicyObjectRef, CoreRef>): ClassRef;
|
|
93
|
+
/**
|
|
94
|
+
* One Class observation slot: a named Policy, or `false`, the rule no caller satisfies. Its other
|
|
95
|
+
* value has no spelling there: an absent observation Policy already means `true`.
|
|
96
|
+
*/
|
|
97
|
+
export type ClassPolicy = PolicyRef | false;
|
|
98
|
+
/** What a Node Class rule may check: the observed Node, or one exact projected member. */
|
|
99
|
+
export type ClassRuleObject = Extract<PolicyCheckObject, {
|
|
100
|
+
readonly kind: 'self' | 'ref';
|
|
101
|
+
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Policy checks deciding one Node Class observation. `self` is the observed Node; a `ref` object
|
|
104
|
+
* is the same Node for every candidate. A lone check of `self` is spelled as its Policy reference.
|
|
105
|
+
*/
|
|
106
|
+
export type ClassRuleChecks = PolicyCheckExpression<PolicyRef, ClassRuleObject>;
|
|
107
|
+
/** One Node Class observation slot: a Class Policy, or Policy checks over the observed Node. */
|
|
108
|
+
export type NodeClassPolicy = ClassPolicy | ClassRuleChecks;
|
|
109
|
+
export declare function isClassRuleChecks(value: ClassPolicy | ClassRuleChecks | undefined): value is ClassRuleChecks;
|
|
110
|
+
/**
|
|
111
|
+
* Whether every way Policy checks can hold passes through a check, so that the caller decides each
|
|
112
|
+
* admission. `sameNode` compares two objects and names no caller.
|
|
113
|
+
*/
|
|
114
|
+
export declare function checksNameTheCaller(value: PolicyCheckExpression<unknown, unknown>): boolean;
|
|
54
115
|
export type PolicyCheckObject = {
|
|
55
116
|
readonly kind: 'self';
|
|
56
117
|
} | {
|
|
@@ -64,7 +125,7 @@ export type PolicyCheckObject = {
|
|
|
64
125
|
export type PolicyCheckExpression<Policy = PolicyRef, Object = PolicyCheckObject> = {
|
|
65
126
|
readonly check: Policy;
|
|
66
127
|
readonly object: Object;
|
|
67
|
-
} | {
|
|
128
|
+
} | PolicySameNode<Object> | {
|
|
68
129
|
readonly allOf: readonly [
|
|
69
130
|
PolicyCheckExpression<Policy, Object>,
|
|
70
131
|
...PolicyCheckExpression<Policy, Object>[]
|
|
@@ -75,3 +136,8 @@ export type PolicyCheckExpression<Policy = PolicyRef, Object = PolicyCheckObject
|
|
|
75
136
|
...PolicyCheckExpression<Policy, Object>[]
|
|
76
137
|
];
|
|
77
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* One authorized callable's caller rule: Policy checks, or `true`, the rule every caller satisfies.
|
|
141
|
+
* Its other value has no spelling there: an absent callable Policy already means `false`.
|
|
142
|
+
*/
|
|
143
|
+
export type CallablePolicy = PolicyCheckExpression | true;
|
|
@@ -1 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
/** Resolve the semantic selector while preserving the legacy exact wire representation. */
|
|
2
|
+
export function policyVariableSelector(variable) {
|
|
3
|
+
return 'class' in variable ? { kind: 'exact', class: variable.class } : variable.selector;
|
|
4
|
+
}
|
|
5
|
+
/** Return the selector's referenced Class, when it has one. */
|
|
6
|
+
export function policyVariableClass(variable) {
|
|
7
|
+
const selector = policyVariableSelector(variable);
|
|
8
|
+
return selector.kind === 'any' ? undefined : selector.class;
|
|
9
|
+
}
|
|
10
|
+
/** Exact projected identity, including Class-owned Method declarations. */
|
|
11
|
+
export function policyObjectKey(ref) {
|
|
12
|
+
return ref.kind === 'method'
|
|
13
|
+
? `${ref.owner.origin}:class.${ref.owner.name}.method.${ref.name}`
|
|
14
|
+
: `${ref.origin}:${ref.kind}.${ref.name}`;
|
|
15
|
+
}
|
|
16
|
+
export function policyObjectOrigin(ref) {
|
|
17
|
+
return ref.kind === 'method' ? ref.owner.origin : ref.origin;
|
|
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
|
+
}
|
|
36
|
+
export function isClassRuleChecks(value) {
|
|
37
|
+
return (typeof value === 'object' &&
|
|
38
|
+
('check' in value || 'sameNode' in value || 'allOf' in value || 'anyOf' in value));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether every way Policy checks can hold passes through a check, so that the caller decides each
|
|
42
|
+
* admission. `sameNode` compares two objects and names no caller.
|
|
43
|
+
*/
|
|
44
|
+
export function checksNameTheCaller(value) {
|
|
45
|
+
if ('check' in value)
|
|
46
|
+
return true;
|
|
47
|
+
if ('sameNode' in value)
|
|
48
|
+
return false;
|
|
49
|
+
if ('allOf' in value)
|
|
50
|
+
return value.allOf.some(checksNameTheCaller);
|
|
51
|
+
return value.anyOf.every(checksNameTheCaller);
|
|
52
|
+
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import type { PolicyCheckExpression, PolicyExpression, PolicyPatternExpression } from '../model/policy.js';
|
|
1
|
+
import type { NodeClassPolicy, PolicyCheckExpression, PolicyExpression, PolicyPatternExpression } from '../model/policy.js';
|
|
2
2
|
export declare function normalizePolicyExpression(value: PolicyExpression): PolicyExpression;
|
|
3
|
+
/**
|
|
4
|
+
* The fixed point of the single pass: a Pattern the single pass reproduces is returned unchanged,
|
|
5
|
+
* so the canonical form of every Pattern that was already stable keeps its bytes.
|
|
6
|
+
*/
|
|
3
7
|
export declare function normalizePolicyPattern(value: PolicyPatternExpression): PolicyPatternExpression;
|
|
8
|
+
/**
|
|
9
|
+
* The one spelling of a Node Class observation rule: normalized Policy checks without a composition
|
|
10
|
+
* of one operand, or the Policy that a lone check of `self` names, which is how a Class has always
|
|
11
|
+
* declared one. Callable checks keep their compositions of one operand: their revisions predate
|
|
12
|
+
* this rule.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeClassRule(value: NodeClassPolicy): NodeClassPolicy;
|
|
4
15
|
export declare function normalizePolicyChecks(value: PolicyCheckExpression): PolicyCheckExpression;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { definitionRefIndex, compareDefinitionRefs } from '../../../addressing/ordering.js';
|
|
3
|
-
|
|
3
|
+
import { isClassRuleChecks, policyObjectKey, policyVariableSelector } from '../model/policy.js';
|
|
4
4
|
export function normalizePolicyExpression(value) {
|
|
5
5
|
if ('match' in value) {
|
|
6
6
|
return { match: normalizePolicyPattern(value.match) };
|
|
@@ -10,13 +10,70 @@ export function normalizePolicyExpression(value) {
|
|
|
10
10
|
}
|
|
11
11
|
return { anyOf: uniqueRefs(value.anyOf) };
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Passes after the first, while one still changes the Pattern. A pass numbers variables by the
|
|
15
|
+
* operands as written, then merges duplicate operands and flattens nested ones, so its result can
|
|
16
|
+
* number differently when normalized again; the next pass numbers that result by itself. One
|
|
17
|
+
* further pass reached the fixed point on every Pattern tested, the other is margin, and a
|
|
18
|
+
* Pattern still changing keeps its last pass rather than failing.
|
|
19
|
+
*/
|
|
20
|
+
const SETTLING_PASSES = 2;
|
|
21
|
+
/**
|
|
22
|
+
* The fixed point of the single pass: a Pattern the single pass reproduces is returned unchanged,
|
|
23
|
+
* so the canonical form of every Pattern that was already stable keeps its bytes.
|
|
24
|
+
*/
|
|
13
25
|
export function normalizePolicyPattern(value) {
|
|
26
|
+
let current = normalizePatternOnce(value);
|
|
27
|
+
let encoding = json.serialize(current);
|
|
28
|
+
for (let pass = 0; pass < SETTLING_PASSES; pass++) {
|
|
29
|
+
const next = normalizePatternOnce(current);
|
|
30
|
+
const nextEncoding = json.serialize(next);
|
|
31
|
+
if (nextEncoding === encoding)
|
|
32
|
+
return current;
|
|
33
|
+
current = next;
|
|
34
|
+
encoding = nextEncoding;
|
|
35
|
+
}
|
|
36
|
+
return current;
|
|
37
|
+
}
|
|
38
|
+
function normalizePatternOnce(value) {
|
|
14
39
|
const rewritten = rewriteVariables(value, canonicalVariableIds(value));
|
|
15
40
|
return normalizePatternNode(rewritten);
|
|
16
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The one spelling of a Node Class observation rule: normalized Policy checks without a composition
|
|
44
|
+
* of one operand, or the Policy that a lone check of `self` names, which is how a Class has always
|
|
45
|
+
* declared one. Callable checks keep their compositions of one operand: their revisions predate
|
|
46
|
+
* this rule.
|
|
47
|
+
*/
|
|
48
|
+
export function normalizeClassRule(value) {
|
|
49
|
+
if (!isClassRuleChecks(value))
|
|
50
|
+
return value;
|
|
51
|
+
const checks = unwrapSingleOperands(normalizePolicyChecks(value));
|
|
52
|
+
return 'check' in checks && checks.object.kind === 'self' ? checks.check : checks;
|
|
53
|
+
}
|
|
54
|
+
/** Replace each composition of one operand by that operand, merging what it then nests. */
|
|
55
|
+
function unwrapSingleOperands(value) {
|
|
56
|
+
if ('check' in value || 'sameNode' in value)
|
|
57
|
+
return value;
|
|
58
|
+
const all = 'allOf' in value;
|
|
59
|
+
const children = uniqueJson((all ? value.allOf : value.anyOf).flatMap((child) => {
|
|
60
|
+
const unwrapped = unwrapSingleOperands(child);
|
|
61
|
+
if (all && 'allOf' in unwrapped)
|
|
62
|
+
return unwrapped.allOf;
|
|
63
|
+
if (!all && 'anyOf' in unwrapped)
|
|
64
|
+
return unwrapped.anyOf;
|
|
65
|
+
return [unwrapped];
|
|
66
|
+
}));
|
|
67
|
+
if (children.length === 1)
|
|
68
|
+
return children[0];
|
|
69
|
+
const operands = policyCheckComposition(children);
|
|
70
|
+
return all ? { allOf: operands } : { anyOf: operands };
|
|
71
|
+
}
|
|
17
72
|
export function normalizePolicyChecks(value) {
|
|
18
73
|
if ('check' in value)
|
|
19
74
|
return value;
|
|
75
|
+
if ('sameNode' in value)
|
|
76
|
+
return { sameNode: normalizeEquality(value.sameNode) };
|
|
20
77
|
if ('allOf' in value) {
|
|
21
78
|
const children = value.allOf.flatMap((child) => {
|
|
22
79
|
const normalized = normalizePolicyChecks(child);
|
|
@@ -36,6 +93,8 @@ function policyCheckComposition(values) {
|
|
|
36
93
|
return values;
|
|
37
94
|
}
|
|
38
95
|
function normalizePatternNode(value) {
|
|
96
|
+
if ('sameNode' in value)
|
|
97
|
+
return { sameNode: normalizeEquality(value.sameNode) };
|
|
39
98
|
if (isEdge(value)) {
|
|
40
99
|
const repeat = value.repeat;
|
|
41
100
|
if (repeat?.min === 1 && repeat.max === 1) {
|
|
@@ -67,24 +126,34 @@ function normalizePatternNode(value) {
|
|
|
67
126
|
}
|
|
68
127
|
function canonicalVariableIds(value) {
|
|
69
128
|
const declarations = new Map();
|
|
70
|
-
|
|
71
|
-
|
|
129
|
+
const depths = new Map();
|
|
130
|
+
collectDeclarations(value, declarations, depths);
|
|
131
|
+
const uses = new Map([...declarations.keys()].map((id) => [id, []]));
|
|
132
|
+
collectUses(value, uses);
|
|
133
|
+
let colors = declarations;
|
|
134
|
+
// Color refinement. Each round names a variable by its declaration and the sorted colors of its
|
|
135
|
+
// uses, then replaces every name by its fixed-width rank among the round's names. Ranks keep the
|
|
136
|
+
// names' byte order, so a round decides what it would decide over uncompressed names, while a
|
|
137
|
+
// name stays linear in its variable's degree instead of embedding every neighbour's name. A
|
|
138
|
+
// round that reproduces its input is a fixed point of the next ones.
|
|
72
139
|
for (let iteration = 0; iteration < declarations.size + 1; iteration++) {
|
|
73
|
-
const next = new Map()
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
uses.sort(compareUtf8Bytes);
|
|
78
|
-
next.set(id, `${declarations.get(id) ?? ''}|${uses.join('|')}`);
|
|
79
|
-
}
|
|
140
|
+
const next = rank(new Map([...uses].map(([id, list]) => {
|
|
141
|
+
const named = list.map(([prefix, term]) => `${prefix}${termColor(term, colors)}`);
|
|
142
|
+
return [id, `${declarations.get(id) ?? ''}|${named.sort(compareUtf8Bytes).join('|')}`];
|
|
143
|
+
})));
|
|
80
144
|
if ([...next].every(([id, color]) => colors.get(id) === color))
|
|
81
145
|
break;
|
|
82
|
-
colors
|
|
83
|
-
for (const [id, color] of next)
|
|
84
|
-
colors.set(id, color);
|
|
146
|
+
colors = next;
|
|
85
147
|
}
|
|
148
|
+
// Colors ignore where a variable is declared, so two variables can tie on color although
|
|
149
|
+
// different `exists` declare them, and which of them is numbered first decides which `exists`
|
|
150
|
+
// declares the smaller id. Their declaration depth tells them apart where it differs: operands of
|
|
151
|
+
// equal signature are ordered by their signature over depth-scoped colors before authored order,
|
|
152
|
+
// and the final order compares depth before the authored id (decision
|
|
153
|
+
// `policy-pattern-canonical-ties`). Both keys only order what color and first use leave tied.
|
|
154
|
+
const scoped = new Map([...colors].map(([id, color]) => [id, `${color}@${depths.get(id) ?? 0}`]));
|
|
86
155
|
const firstUse = new Map();
|
|
87
|
-
collectFirstUseKeys(value, colors, firstUse);
|
|
156
|
+
collectFirstUseKeys(value, colors, scoped, firstUse);
|
|
88
157
|
const ordered = [...declarations.keys()].sort((left, right) => {
|
|
89
158
|
const byColor = compareUtf8Bytes(colors.get(left) ?? '', colors.get(right) ?? '');
|
|
90
159
|
if (byColor !== 0)
|
|
@@ -92,49 +161,80 @@ function canonicalVariableIds(value) {
|
|
|
92
161
|
const byUse = compareUtf8Bytes(firstUse.get(left) ?? '', firstUse.get(right) ?? '');
|
|
93
162
|
if (byUse !== 0)
|
|
94
163
|
return byUse;
|
|
95
|
-
|
|
96
|
-
|
|
164
|
+
const byDepth = (depths.get(left) ?? 0) - (depths.get(right) ?? 0);
|
|
165
|
+
if (byDepth !== 0)
|
|
166
|
+
return byDepth;
|
|
167
|
+
// A remaining tie keeps the authored order of the ids: such variables were interchangeable in
|
|
168
|
+
// every admissible Pattern checked (`__tests__/canonical.test.ts`).
|
|
97
169
|
return left - right;
|
|
98
170
|
});
|
|
99
171
|
return new Map(ordered.map((id, index) => [id, index]));
|
|
100
172
|
}
|
|
101
|
-
|
|
173
|
+
/** Each declared variable's selector signature and the number of `exists` around its declaration. */
|
|
174
|
+
function collectDeclarations(value, result, depths, depth = 0) {
|
|
102
175
|
if ('exists' in value) {
|
|
103
176
|
for (const node of value.exists.nodes) {
|
|
104
|
-
result.set(node.variable.id,
|
|
177
|
+
result.set(node.variable.id, selectorSignature(node));
|
|
178
|
+
depths.set(node.variable.id, depth + 1);
|
|
105
179
|
}
|
|
106
|
-
collectDeclarations(value.exists.where, result);
|
|
180
|
+
collectDeclarations(value.exists.where, result, depths, depth + 1);
|
|
107
181
|
return;
|
|
108
182
|
}
|
|
109
183
|
if ('allOf' in value)
|
|
110
184
|
for (const child of value.allOf)
|
|
111
|
-
collectDeclarations(child, result);
|
|
185
|
+
collectDeclarations(child, result, depths, depth);
|
|
112
186
|
if ('anyOf' in value)
|
|
113
187
|
for (const child of value.anyOf)
|
|
114
|
-
collectDeclarations(child, result);
|
|
188
|
+
collectDeclarations(child, result, depths, depth);
|
|
115
189
|
}
|
|
116
|
-
function collectUses(value,
|
|
190
|
+
function collectUses(value, result) {
|
|
191
|
+
if ('sameNode' in value) {
|
|
192
|
+
const { left, right } = value.sameNode;
|
|
193
|
+
if (left.kind === 'variable')
|
|
194
|
+
result.get(left.id)?.push(['same:', right]);
|
|
195
|
+
if (right.kind === 'variable')
|
|
196
|
+
result.get(right.id)?.push(['same:', left]);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
117
199
|
if (isEdge(value)) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (value.target.kind === 'variable'
|
|
122
|
-
result.push(`t:${
|
|
123
|
-
}
|
|
200
|
+
const edge = definitionRefIndex(value.class);
|
|
201
|
+
if (value.source.kind === 'variable')
|
|
202
|
+
result.get(value.source.id)?.push([`s:${edge}:`, value.target]);
|
|
203
|
+
if (value.target.kind === 'variable')
|
|
204
|
+
result.get(value.target.id)?.push([`t:${edge}:`, value.source]);
|
|
124
205
|
return;
|
|
125
206
|
}
|
|
126
207
|
if ('exists' in value)
|
|
127
|
-
return collectUses(value.exists.where,
|
|
208
|
+
return collectUses(value.exists.where, result);
|
|
128
209
|
const children = 'allOf' in value ? value.allOf : value.anyOf;
|
|
129
210
|
for (const child of children)
|
|
130
|
-
collectUses(child,
|
|
211
|
+
collectUses(child, result);
|
|
212
|
+
}
|
|
213
|
+
function rank(names) {
|
|
214
|
+
const distinct = [...new Set(names.values())].sort(compareUtf8Bytes);
|
|
215
|
+
const width = String(distinct.length).length;
|
|
216
|
+
const ranks = new Map(distinct.map((name, index) => [name, String(index).padStart(width, '0')]));
|
|
217
|
+
return new Map([...names].map(([id, name]) => [id, ranks.get(name) ?? '']));
|
|
131
218
|
}
|
|
132
219
|
function termColor(term, colors) {
|
|
133
220
|
if (term.kind === 'variable')
|
|
134
221
|
return `variable:${colors.get(term.id) ?? '?'}`;
|
|
222
|
+
if (term.kind === 'ref')
|
|
223
|
+
return `ref:${term.ref.kind === 'method' ? policyObjectKey(term.ref) : definitionRefIndex(term.ref)}`;
|
|
135
224
|
return term.kind;
|
|
136
225
|
}
|
|
137
|
-
function collectFirstUseKeys(value, colors, result, prefix = '$') {
|
|
226
|
+
function collectFirstUseKeys(value, colors, scoped, result, prefix = '$') {
|
|
227
|
+
if ('sameNode' in value) {
|
|
228
|
+
for (const term of [value.sameNode.left, value.sameNode.right]) {
|
|
229
|
+
if (term.kind !== 'variable')
|
|
230
|
+
continue;
|
|
231
|
+
const key = `${prefix}:same`;
|
|
232
|
+
const current = result.get(term.id);
|
|
233
|
+
if (current === undefined || key < current)
|
|
234
|
+
result.set(term.id, key);
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
138
238
|
if (isEdge(value)) {
|
|
139
239
|
for (const [position, term] of [
|
|
140
240
|
['source', value.source],
|
|
@@ -150,15 +250,19 @@ function collectFirstUseKeys(value, colors, result, prefix = '$') {
|
|
|
150
250
|
return;
|
|
151
251
|
}
|
|
152
252
|
if ('exists' in value) {
|
|
153
|
-
collectFirstUseKeys(value.exists.where, colors, result, `${prefix}:exists`);
|
|
253
|
+
collectFirstUseKeys(value.exists.where, colors, scoped, result, `${prefix}:exists`);
|
|
154
254
|
return;
|
|
155
255
|
}
|
|
156
256
|
const key = 'allOf' in value ? 'allOf' : 'anyOf';
|
|
157
257
|
const operands = 'allOf' in value ? value.allOf : value.anyOf;
|
|
158
|
-
const children =
|
|
159
|
-
|
|
258
|
+
const children = operands
|
|
259
|
+
.map((child) => [patternSignature(child, colors), patternSignature(child, scoped), child])
|
|
260
|
+
.sort(([left, leftScoped], [right, rightScoped]) => compareUtf8Bytes(left, right) || compareUtf8Bytes(leftScoped, rightScoped));
|
|
261
|
+
children.forEach(([, , child], index) => collectFirstUseKeys(child, colors, scoped, result, `${prefix}:${key}:${index}`));
|
|
160
262
|
}
|
|
161
263
|
function patternSignature(value, colors) {
|
|
264
|
+
if ('sameNode' in value)
|
|
265
|
+
return `same:${[termColor(value.sameNode.left, colors), termColor(value.sameNode.right, colors)].sort(compareUtf8Bytes).join(':')}`;
|
|
162
266
|
if (isEdge(value)) {
|
|
163
267
|
return `edge:${definitionRefIndex(value.class)}:${termColor(value.source, colors)}:${termColor(value.target, colors)}:${value.repeat?.min ?? 1}:${value.repeat?.max ?? 1}`;
|
|
164
268
|
}
|
|
@@ -176,6 +280,13 @@ function patternSignature(value, colors) {
|
|
|
176
280
|
.join('|')}`;
|
|
177
281
|
}
|
|
178
282
|
function rewriteVariables(value, ids) {
|
|
283
|
+
if ('sameNode' in value)
|
|
284
|
+
return {
|
|
285
|
+
sameNode: {
|
|
286
|
+
left: rewriteTerm(value.sameNode.left, ids),
|
|
287
|
+
right: rewriteTerm(value.sameNode.right, ids),
|
|
288
|
+
},
|
|
289
|
+
};
|
|
179
290
|
if (isEdge(value)) {
|
|
180
291
|
return {
|
|
181
292
|
...value,
|
|
@@ -186,10 +297,15 @@ function rewriteVariables(value, ids) {
|
|
|
186
297
|
if ('exists' in value) {
|
|
187
298
|
return {
|
|
188
299
|
exists: {
|
|
189
|
-
nodes: value.exists.nodes.map((node) =>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
300
|
+
nodes: value.exists.nodes.map((node) => {
|
|
301
|
+
const variable = {
|
|
302
|
+
kind: 'variable',
|
|
303
|
+
id: ids.get(node.variable.id) ?? node.variable.id,
|
|
304
|
+
};
|
|
305
|
+
return 'class' in node
|
|
306
|
+
? { variable, class: node.class }
|
|
307
|
+
: { variable, selector: node.selector };
|
|
308
|
+
}),
|
|
193
309
|
where: rewriteVariables(value.exists.where, ids),
|
|
194
310
|
},
|
|
195
311
|
};
|
|
@@ -198,6 +314,10 @@ function rewriteVariables(value, ids) {
|
|
|
198
314
|
return { allOf: value.allOf.map((child) => rewriteVariables(child, ids)) };
|
|
199
315
|
return { anyOf: value.anyOf.map((child) => rewriteVariables(child, ids)) };
|
|
200
316
|
}
|
|
317
|
+
function selectorSignature(node) {
|
|
318
|
+
const selector = policyVariableSelector(node);
|
|
319
|
+
return selector.kind === 'any' ? 'any' : `${selector.kind}:${definitionRefIndex(selector.class)}`;
|
|
320
|
+
}
|
|
201
321
|
function rewriteTerm(value, ids) {
|
|
202
322
|
return value.kind === 'variable' ? { kind: 'variable', id: ids.get(value.id) ?? value.id } : value;
|
|
203
323
|
}
|
|
@@ -211,16 +331,30 @@ function uniqueJson(values) {
|
|
|
211
331
|
.sort(([left], [right]) => compareUtf8Bytes(left, right))
|
|
212
332
|
.map(([, value]) => value);
|
|
213
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* UTF-8 byte order without encoding: it is code-point order, which UTF-16 code units already follow
|
|
336
|
+
* except that surrogates (U+10000 and above) sort after U+E000–U+FFFF.
|
|
337
|
+
*/
|
|
214
338
|
function compareUtf8Bytes(left, right) {
|
|
215
|
-
const
|
|
216
|
-
const b = textEncoder.encode(right);
|
|
217
|
-
const length = Math.min(a.length, b.length);
|
|
339
|
+
const length = Math.min(left.length, right.length);
|
|
218
340
|
for (let index = 0; index < length; index++) {
|
|
219
|
-
|
|
220
|
-
|
|
341
|
+
const a = left.charCodeAt(index);
|
|
342
|
+
const b = right.charCodeAt(index);
|
|
343
|
+
if (a !== b)
|
|
344
|
+
return codePointOrder(a) - codePointOrder(b);
|
|
221
345
|
}
|
|
222
|
-
return
|
|
346
|
+
return left.length - right.length;
|
|
347
|
+
}
|
|
348
|
+
function codePointOrder(unit) {
|
|
349
|
+
if (unit >= 0xd800 && unit <= 0xdfff)
|
|
350
|
+
return unit + 0x2000;
|
|
351
|
+
return unit >= 0xe000 ? unit - 0x800 : unit;
|
|
223
352
|
}
|
|
224
353
|
function isEdge(value) {
|
|
225
354
|
return 'source' in value;
|
|
226
355
|
}
|
|
356
|
+
function normalizeEquality(value) {
|
|
357
|
+
return compareUtf8Bytes(json.serialize(value.left), json.serialize(value.right)) <= 0
|
|
358
|
+
? value
|
|
359
|
+
: { left: value.right, right: value.left };
|
|
360
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { stateMachine } from './machine.js';
|