@astrale-os/kernel-dsl 0.2.0-beta.9 → 1.0.0-beta.2
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,31 @@
|
|
|
1
|
+
import type { JsonSchemaObject } from './schema.js';
|
|
2
|
+
declare const BLOB_SCHEMA: unique symbol;
|
|
3
|
+
/** The portable value read from a blob-kind Node property. */
|
|
4
|
+
export interface BlobRef {
|
|
5
|
+
readonly digest: `sha256:${string}`;
|
|
6
|
+
readonly mediaType: string;
|
|
7
|
+
readonly size: number;
|
|
8
|
+
}
|
|
9
|
+
/** An uploader-bound receipt is the only ordinary write input for a blob property. */
|
|
10
|
+
export type BlobReceipt = string & {
|
|
11
|
+
readonly __brand: 'BlobReceipt';
|
|
12
|
+
};
|
|
13
|
+
/** Type-only marker; the serialized schema remains ordinary JSON. */
|
|
14
|
+
export interface BlobSchema extends JsonSchemaObject {
|
|
15
|
+
readonly [BLOB_SCHEMA]: true;
|
|
16
|
+
}
|
|
17
|
+
export interface BlobOptions {
|
|
18
|
+
/** Required property-level bound, in bytes. */
|
|
19
|
+
readonly maxBytes: number;
|
|
20
|
+
/** Omission admits any canonical artifact media type. */
|
|
21
|
+
readonly mediaTypes?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export declare const BLOB_VALUE_KIND: 'blob';
|
|
24
|
+
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
25
|
+
export declare function blob(options: BlobOptions): BlobSchema;
|
|
26
|
+
/** Marker recognition on an already admitted V1 value schema. */
|
|
27
|
+
export declare function isBlobValueSchema(input: unknown): input is BlobSchema;
|
|
28
|
+
/** Exact canonical artifact media type, including ordered token parameters. */
|
|
29
|
+
export declare function canonicalMediaType(input: string): string;
|
|
30
|
+
export declare function isCanonicalBlobRef(input: unknown): input is BlobRef;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const BLOB_VALUE_KIND = 'blob';
|
|
2
|
+
const BLOB_DIGEST_PATTERN = 'sha256:[0-9a-f]{64}';
|
|
3
|
+
const BLOB_MEDIA_TYPE_PATTERN = "[a-z0-9!#$%&'*+.^_`|~-]+/[a-z0-9!#$%&'*+.^_`|~-]+(;[a-z0-9!#$%&'*+.^_`|~-]+=[!#$%&'*+.^_`|~0-9A-Za-z-]+)*";
|
|
4
|
+
const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
|
|
5
|
+
const DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
6
|
+
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
7
|
+
export function blob(options) {
|
|
8
|
+
if (!Number.isSafeInteger(options?.maxBytes) || options.maxBytes < 1) {
|
|
9
|
+
throw new TypeError('Blob maxBytes must be a positive safe integer.');
|
|
10
|
+
}
|
|
11
|
+
let mediaTypes;
|
|
12
|
+
if (options.mediaTypes !== undefined) {
|
|
13
|
+
if (!Array.isArray(options.mediaTypes) || options.mediaTypes.length === 0) {
|
|
14
|
+
throw new TypeError('Blob mediaTypes must be a non-empty list.');
|
|
15
|
+
}
|
|
16
|
+
mediaTypes = [...new Set(options.mediaTypes.map(canonicalMediaType))].sort();
|
|
17
|
+
}
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
type: 'object',
|
|
20
|
+
'x-astrale-value-kind': BLOB_VALUE_KIND,
|
|
21
|
+
properties: {
|
|
22
|
+
digest: { type: 'string', fullMatch: BLOB_DIGEST_PATTERN },
|
|
23
|
+
mediaType: mediaTypes === undefined
|
|
24
|
+
? { type: 'string', fullMatch: BLOB_MEDIA_TYPE_PATTERN }
|
|
25
|
+
: { enum: mediaTypes },
|
|
26
|
+
size: { type: 'integer', minimum: 0, maximum: options.maxBytes },
|
|
27
|
+
},
|
|
28
|
+
required: ['digest', 'mediaType', 'size'],
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Marker recognition on an already admitted V1 value schema. */
|
|
33
|
+
export function isBlobValueSchema(input) {
|
|
34
|
+
return (input !== null &&
|
|
35
|
+
typeof input === 'object' &&
|
|
36
|
+
!Array.isArray(input) &&
|
|
37
|
+
input['x-astrale-value-kind'] === BLOB_VALUE_KIND);
|
|
38
|
+
}
|
|
39
|
+
/** Exact canonical artifact media type, including ordered token parameters. */
|
|
40
|
+
export function canonicalMediaType(input) {
|
|
41
|
+
if (typeof input !== 'string')
|
|
42
|
+
throw new TypeError('Blob media type is invalid.');
|
|
43
|
+
const [essence, ...parametersInput] = input.split(';');
|
|
44
|
+
const [rawType, rawSubtype, ...extra] = essence.trim().split('/');
|
|
45
|
+
if (rawType === undefined ||
|
|
46
|
+
rawSubtype === undefined ||
|
|
47
|
+
extra.length !== 0 ||
|
|
48
|
+
!TOKEN.test(rawType) ||
|
|
49
|
+
!TOKEN.test(rawSubtype)) {
|
|
50
|
+
throw new TypeError('Blob media type is invalid.');
|
|
51
|
+
}
|
|
52
|
+
const parameters = parametersInput.map((part) => {
|
|
53
|
+
const separator = part.indexOf('=');
|
|
54
|
+
if (separator <= 0)
|
|
55
|
+
throw new TypeError('Blob media type parameter is invalid.');
|
|
56
|
+
const name = part.slice(0, separator).trim().toLowerCase();
|
|
57
|
+
const value = part.slice(separator + 1).trim();
|
|
58
|
+
if (!TOKEN.test(name) || !TOKEN.test(value)) {
|
|
59
|
+
throw new TypeError('Blob media type parameter is invalid.');
|
|
60
|
+
}
|
|
61
|
+
return [name, value];
|
|
62
|
+
});
|
|
63
|
+
parameters.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
64
|
+
if (new Set(parameters.map(([name]) => name)).size !== parameters.length) {
|
|
65
|
+
throw new TypeError('Blob media type parameters are duplicated.');
|
|
66
|
+
}
|
|
67
|
+
return parameters.reduce((result, [name, value]) => `${result};${name}=${value}`, `${rawType.toLowerCase()}/${rawSubtype.toLowerCase()}`);
|
|
68
|
+
}
|
|
69
|
+
export function isCanonicalBlobRef(input) {
|
|
70
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input))
|
|
71
|
+
return false;
|
|
72
|
+
const value = input;
|
|
73
|
+
if (Object.keys(value).length !== 3 ||
|
|
74
|
+
!Object.hasOwn(value, 'digest') ||
|
|
75
|
+
!Object.hasOwn(value, 'mediaType') ||
|
|
76
|
+
!Object.hasOwn(value, 'size') ||
|
|
77
|
+
typeof value.digest !== 'string' ||
|
|
78
|
+
!DIGEST.test(value.digest) ||
|
|
79
|
+
typeof value.mediaType !== 'string' ||
|
|
80
|
+
!Number.isSafeInteger(value.size) ||
|
|
81
|
+
value.size < 0) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
return canonicalMediaType(value.mediaType) === value.mediaType;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/** Exact portable UTC millisecond Instant used by the V1 value-schema dialect. */
|
|
2
|
-
/** Canonical value-language annotation for an Instant string. */
|
|
3
|
-
export declare const INSTANT_VALUE_KIND: 'instant';
|
|
4
2
|
export declare const instant: Readonly<{
|
|
5
3
|
readonly type: 'string';
|
|
6
4
|
readonly 'x-astrale-value-kind': 'instant';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Exact portable UTC millisecond Instant used by the V1 value-schema dialect. */
|
|
2
2
|
/** Canonical value-language annotation for an Instant string. */
|
|
3
|
-
|
|
3
|
+
const INSTANT_VALUE_KIND = 'instant';
|
|
4
4
|
export const instant = Object.freeze({
|
|
5
5
|
type: 'string',
|
|
6
6
|
'x-astrale-value-kind': INSTANT_VALUE_KIND,
|
|
@@ -21,5 +21,6 @@ export interface PathAnnotation {
|
|
|
21
21
|
readonly cardinality: 'one';
|
|
22
22
|
readonly accepts: readonly ClassRef[];
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
declare const VALUE_SCHEMA_CONTEXTS: readonly ['property-facet', 'callable-input', 'callable-output'];
|
|
25
25
|
export type ValueSchemaContext = (typeof VALUE_SCHEMA_CONTEXTS)[number];
|
|
26
|
+
export {};
|
|
@@ -4,8 +4,4 @@ export const JSON_SCHEMA_DIALECT = 'https://json-schema.org/draft/2020-12/schema
|
|
|
4
4
|
export const VALUE_SCHEMA_DIALECT = 'https://schemas.astrale.ai/dsl/v1/value-schema';
|
|
5
5
|
/** Required vocabulary carried by the V1 value-schema dialect. */
|
|
6
6
|
export const VALUE_SCHEMA_VOCABULARY = 'https://schemas.astrale.ai/dsl/v1/value-schema/vocabulary';
|
|
7
|
-
|
|
8
|
-
'property-facet',
|
|
9
|
-
'callable-input',
|
|
10
|
-
'callable-output',
|
|
11
|
-
];
|
|
7
|
+
const VALUE_SCHEMA_CONTEXTS = ['property-facet', 'callable-input', 'callable-output'];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ValueProgram } from './compile/model.js';
|
|
2
|
+
import type { CompiledInstanceSchema } from './evaluate/types.js';
|
|
2
3
|
import type { JsonSchema } from './model/schema.js';
|
|
3
4
|
import type { ValueSchemaRegistry } from './reference/registry.js';
|
|
4
5
|
export type OrderingKind = 'boolean' | 'number' | 'string' | 'instant';
|
|
@@ -11,3 +12,4 @@ export type OrderingKind = 'boolean' | 'number' | 'string' | 'instant';
|
|
|
11
12
|
export declare function classifyOrdering(contract: JsonSchema, registry: ValueSchemaRegistry): OrderingKind | undefined;
|
|
12
13
|
/** Recompute the scalar ordering classification from one admitted portable value program. */
|
|
13
14
|
export declare function classifyValueProgramOrdering(program: ValueProgram): OrderingKind | undefined;
|
|
15
|
+
export declare function classifyPreparedOrdering(compiled: CompiledInstanceSchema): OrderingKind | undefined;
|
|
@@ -18,17 +18,13 @@ export function classifyOrdering(contract, registry) {
|
|
|
18
18
|
const prepared = prepareValueSchema(contract, registry, '');
|
|
19
19
|
if (!prepared.compiled)
|
|
20
20
|
return undefined;
|
|
21
|
-
|
|
22
|
-
if (candidates.size !== 1)
|
|
23
|
-
return undefined;
|
|
24
|
-
const [kind] = candidates;
|
|
25
|
-
return kind === 'boolean' || kind === 'number' || kind === 'string' || kind === 'instant'
|
|
26
|
-
? kind
|
|
27
|
-
: undefined;
|
|
21
|
+
return classifyPreparedOrdering(prepared.value);
|
|
28
22
|
}
|
|
29
23
|
/** Recompute the scalar ordering classification from one admitted portable value program. */
|
|
30
24
|
export function classifyValueProgramOrdering(program) {
|
|
31
|
-
|
|
25
|
+
return classifyPreparedOrdering(loadValueProgram(program));
|
|
26
|
+
}
|
|
27
|
+
export function classifyPreparedOrdering(compiled) {
|
|
32
28
|
const candidates = new OrderingClassifier(compiled).classify(compiled.root);
|
|
33
29
|
if (candidates.size !== 1)
|
|
34
30
|
return undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { acceptForRead as acceptJsonValue, BoundaryError as JsonBoundaryError, } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { diagnostic } from '../../validation/diagnostic.js';
|
|
3
3
|
export function validateCanonicalJsonDomain(value, pointer) {
|
|
4
4
|
try {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { diagnostic } from '../../validation/diagnostic.js';
|
|
3
|
+
import { blob, BLOB_VALUE_KIND } from '../model/blob.js';
|
|
3
4
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
4
5
|
import { VALUE_SCHEMA_DIALECT } from '../model/schema.js';
|
|
5
|
-
import {
|
|
6
|
+
import { refuseIRegexp, stateBudgetMessage } from '../regexp/syntax.js';
|
|
6
7
|
import { walkSchema } from '../syntax/walk.js';
|
|
7
8
|
import { FORBIDDEN_DYNAMIC_KEYWORDS, STANDARD_SCHEMA_KEYWORDS } from './vocabulary.js';
|
|
8
9
|
export function validateSchemaProfile(schema, context, pointer) {
|
|
@@ -28,19 +29,50 @@ export function validateSchemaProfile(schema, context, pointer) {
|
|
|
28
29
|
diagnostics.push(diagnostic('VS_RESOURCE_ID', `${currentPointer}/$id`, '$id is forbidden in an embedded V1 value schema.'));
|
|
29
30
|
}
|
|
30
31
|
validateSemanticSets(location.schema, currentPointer, diagnostics);
|
|
31
|
-
validateValueKind(location.schema, currentPointer, diagnostics);
|
|
32
|
+
validateValueKind(location.schema, context, location.depth, currentPointer, diagnostics);
|
|
32
33
|
validateRegexes(location.schema, currentPointer, diagnostics);
|
|
33
34
|
});
|
|
34
|
-
void context;
|
|
35
35
|
return diagnostics;
|
|
36
36
|
}
|
|
37
|
-
function validateValueKind(schema, pointer, diagnostics) {
|
|
37
|
+
function validateValueKind(schema, context, depth, pointer, diagnostics) {
|
|
38
38
|
if (!Object.hasOwn(schema, 'x-astrale-value-kind'))
|
|
39
39
|
return;
|
|
40
|
-
if (schema['x-astrale-value-kind']
|
|
40
|
+
if (schema['x-astrale-value-kind'] === BLOB_VALUE_KIND) {
|
|
41
|
+
if (context !== 'property-facet' || depth !== 0 || !isCanonicalBlobSchema(schema)) {
|
|
42
|
+
diagnostics.push(diagnostic('VS_VALUE_KIND', `${pointer}/x-astrale-value-kind`, 'blob must be the exact schema.values.blob output at the root of a Node property.'));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (schema['x-astrale-value-kind'] !== 'instant' || schema.type !== 'string') {
|
|
41
46
|
diagnostics.push(diagnostic('VS_VALUE_KIND', `${pointer}/x-astrale-value-kind`, 'x-astrale-value-kind is exactly instant and requires type string at the same schema location.'));
|
|
42
47
|
}
|
|
43
48
|
}
|
|
49
|
+
function isCanonicalBlobSchema(input) {
|
|
50
|
+
const properties = input.properties;
|
|
51
|
+
if (!isJsonObject(properties))
|
|
52
|
+
return false;
|
|
53
|
+
const size = properties.size;
|
|
54
|
+
const mediaType = properties.mediaType;
|
|
55
|
+
if (!isJsonObject(size) || !isJsonObject(mediaType))
|
|
56
|
+
return false;
|
|
57
|
+
const maxBytes = size.maximum;
|
|
58
|
+
if (typeof maxBytes !== 'number' || !Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const mediaTypes = mediaType.enum;
|
|
62
|
+
if (mediaTypes !== undefined && (!Array.isArray(mediaTypes) || !mediaTypes.every(isString))) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return (json.serialize(input) ===
|
|
67
|
+
json.serialize(blob({ maxBytes, ...(mediaTypes === undefined ? {} : { mediaTypes }) })));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isString(input) {
|
|
74
|
+
return typeof input === 'string';
|
|
75
|
+
}
|
|
44
76
|
function validateSemanticSets(schema, pointer, diagnostics) {
|
|
45
77
|
if (Array.isArray(schema.type)) {
|
|
46
78
|
rejectPrimitiveDuplicates(schema.type, `${pointer}/type`, 'type', diagnostics);
|
|
@@ -63,20 +95,24 @@ function validateRegexes(schema, pointer, diagnostics) {
|
|
|
63
95
|
if (Object.hasOwn(schema, 'fullMatch') && typeof schema.fullMatch !== 'string') {
|
|
64
96
|
diagnostics.push(diagnostic('VS_META_SCHEMA', `${pointer}/fullMatch`, 'fullMatch must be an I-Regexp source string.'));
|
|
65
97
|
}
|
|
66
|
-
if (typeof schema.fullMatch === 'string'
|
|
67
|
-
|
|
98
|
+
if (typeof schema.fullMatch === 'string') {
|
|
99
|
+
portableRegex(schema.fullMatch, `${pointer}/fullMatch`, 'fullMatch', 'fullMatch must satisfy the complete RFC 9485 I-Regexp syntax.', diagnostics);
|
|
68
100
|
}
|
|
69
|
-
if (typeof schema.pattern === 'string'
|
|
70
|
-
|
|
101
|
+
if (typeof schema.pattern === 'string') {
|
|
102
|
+
portableRegex(schema.pattern, `${pointer}/pattern`, 'pattern', 'pattern must satisfy the complete RFC 9485 I-Regexp syntax.', diagnostics);
|
|
71
103
|
}
|
|
72
104
|
if (isJsonObject(schema.patternProperties)) {
|
|
73
105
|
for (const pattern of Object.keys(schema.patternProperties)) {
|
|
74
|
-
|
|
75
|
-
diagnostics.push(diagnostic('VS_REGEX_PORTABLE', `${pointer}/patternProperties/${escapeToken(pattern)}`, 'patternProperties keys must satisfy RFC 9485 I-Regexp syntax.'));
|
|
76
|
-
}
|
|
106
|
+
portableRegex(pattern, `${pointer}/patternProperties/${escapeToken(pattern)}`, 'A patternProperties key', 'patternProperties keys must satisfy RFC 9485 I-Regexp syntax.', diagnostics);
|
|
77
107
|
}
|
|
78
108
|
}
|
|
79
109
|
}
|
|
110
|
+
function portableRegex(source, pointer, subject, syntax, diagnostics) {
|
|
111
|
+
const refusal = refuseIRegexp(source);
|
|
112
|
+
if (refusal === undefined)
|
|
113
|
+
return;
|
|
114
|
+
diagnostics.push(diagnostic('VS_REGEX_PORTABLE', pointer, refusal === 'syntax' ? syntax : stateBudgetMessage(subject)));
|
|
115
|
+
}
|
|
80
116
|
function rejectPrimitiveDuplicates(values, pointer, name, diagnostics) {
|
|
81
117
|
const seen = new Set();
|
|
82
118
|
for (const value of values) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassRef } from '../../../addressing/index.js';
|
|
2
2
|
import type { JsonSchema } from '../model/schema.js';
|
|
3
|
-
|
|
3
|
+
interface ValueSchemaDependency {
|
|
4
4
|
readonly origin: string;
|
|
5
5
|
readonly revision: `sha256:${string}`;
|
|
6
6
|
}
|
|
@@ -22,3 +22,4 @@ export interface ValueSchemaRegistry {
|
|
|
22
22
|
readonly transitiveDependencies: readonly ValueSchemaDomainRegistry[];
|
|
23
23
|
readonly graphNodePath: JsonSchema;
|
|
24
24
|
}
|
|
25
|
+
export {};
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { categoryRanges, complement, mergeRanges } from './unicode.js';
|
|
2
|
+
const CATEGORY = /^(?:L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|Z[lps]?|S[ckmo]?|C[cfno]?)$/u;
|
|
2
3
|
const MAX_CODE_POINTS = 4096;
|
|
3
4
|
const MAX_NESTING = 32;
|
|
4
5
|
const MAX_REPEAT = 1000;
|
|
5
|
-
const SCALAR_RANGES = [
|
|
6
|
-
[0, 0xd7ff],
|
|
7
|
-
[0xe000, 0x10ffff],
|
|
8
|
-
];
|
|
9
6
|
const DOT_RANGES = [
|
|
10
7
|
[0, 9],
|
|
11
8
|
[11, 12],
|
|
@@ -200,7 +197,7 @@ class Parser {
|
|
|
200
197
|
if (this.peek() !== '\\')
|
|
201
198
|
return undefined;
|
|
202
199
|
const escaped = this.peek(1);
|
|
203
|
-
if (escaped === undefined || !'()*+-.?[\\]^nrt{}'.includes(escaped))
|
|
200
|
+
if (escaped === undefined || !'()*+-.?[\\]^nrt{|}'.includes(escaped))
|
|
204
201
|
return undefined;
|
|
205
202
|
this.index += 2;
|
|
206
203
|
const value = escaped === 'n' ? '\n' : escaped === 'r' ? '\r' : escaped === 't' ? '\t' : escaped;
|
|
@@ -237,68 +234,10 @@ class Parser {
|
|
|
237
234
|
return this.characters[this.index + offset];
|
|
238
235
|
}
|
|
239
236
|
}
|
|
240
|
-
const categories = new Map();
|
|
241
|
-
function categoryRanges(category) {
|
|
242
|
-
const retained = categories.get(category);
|
|
243
|
-
if (retained !== undefined)
|
|
244
|
-
return retained;
|
|
245
|
-
const expression = new RegExp(`^\\p{${category}}$`, 'u');
|
|
246
|
-
const output = [];
|
|
247
|
-
let start;
|
|
248
|
-
let previous = -2;
|
|
249
|
-
for (const [minimum, maximum] of SCALAR_RANGES) {
|
|
250
|
-
for (let scalar = minimum; scalar <= maximum; scalar++) {
|
|
251
|
-
if (!expression.test(String.fromCodePoint(scalar)))
|
|
252
|
-
continue;
|
|
253
|
-
if (start === undefined)
|
|
254
|
-
start = scalar;
|
|
255
|
-
else if (scalar !== previous + 1) {
|
|
256
|
-
output.push([start, previous]);
|
|
257
|
-
start = scalar;
|
|
258
|
-
}
|
|
259
|
-
previous = scalar;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if (start !== undefined)
|
|
263
|
-
output.push([start, previous]);
|
|
264
|
-
const frozen = Object.freeze(output.map((range) => Object.freeze(range)));
|
|
265
|
-
categories.set(category, frozen);
|
|
266
|
-
return frozen;
|
|
267
|
-
}
|
|
268
237
|
function singleton(value) {
|
|
269
238
|
const scalar = value.codePointAt(0);
|
|
270
239
|
return scalar === undefined ? [] : [[scalar, scalar]];
|
|
271
240
|
}
|
|
272
|
-
function mergeRanges(input) {
|
|
273
|
-
const sorted = [...input].sort((left, right) => left[0] - right[0] || left[1] - right[1]);
|
|
274
|
-
const output = [];
|
|
275
|
-
for (const range of sorted) {
|
|
276
|
-
const previous = output.at(-1);
|
|
277
|
-
if (previous === undefined || range[0] > previous[1] + 1)
|
|
278
|
-
output.push([range[0], range[1]]);
|
|
279
|
-
else
|
|
280
|
-
output[output.length - 1] = [previous[0], Math.max(previous[1], range[1])];
|
|
281
|
-
}
|
|
282
|
-
return output;
|
|
283
|
-
}
|
|
284
|
-
function complement(input) {
|
|
285
|
-
const output = [];
|
|
286
|
-
for (const [minimum, maximum] of SCALAR_RANGES) {
|
|
287
|
-
let cursor = minimum;
|
|
288
|
-
for (const [start, end] of input) {
|
|
289
|
-
if (end < minimum || start > maximum)
|
|
290
|
-
continue;
|
|
291
|
-
if (start > cursor)
|
|
292
|
-
output.push([cursor, Math.min(start - 1, maximum)]);
|
|
293
|
-
cursor = Math.max(cursor, end + 1);
|
|
294
|
-
if (cursor > maximum)
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
if (cursor <= maximum)
|
|
298
|
-
output.push([cursor, maximum]);
|
|
299
|
-
}
|
|
300
|
-
return output;
|
|
301
|
-
}
|
|
302
241
|
function isNormalCharacter(value) {
|
|
303
242
|
const code = value.codePointAt(0);
|
|
304
243
|
return (code !== undefined &&
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
-
import type { Pattern } from '../compile/model.js';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { Pattern, RunPattern } from '../compile/model.js';
|
|
2
|
+
import type { Expression } from './ast.js';
|
|
3
|
+
/**
|
|
4
|
+
* The most states the machine of one I-Regexp may have (`limits.regexp.maxStates`), an
|
|
5
|
+
* implementation limit as RFC 9485 §8 allows. Counted repetitions are expanded copy by copy, so the
|
|
6
|
+
* parser's bounds on length, nesting and counts alone admit machines of billions of states. The
|
|
7
|
+
* counted-run form never expands, so it is not subject to this budget.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MAX_STATES = 10000;
|
|
10
|
+
/**
|
|
11
|
+
* Thrown when an I-Regexp source compiles to a machine of more than `MAX_STATES` states. A short
|
|
12
|
+
* branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and cost seconds per
|
|
13
|
+
* validated value (P1-I-01); it is refused before any state is built.
|
|
14
|
+
*/
|
|
15
|
+
export declare class PatternComplexityError extends RangeError {
|
|
16
|
+
readonly limit: number;
|
|
17
|
+
constructor(limit?: number);
|
|
18
|
+
}
|
|
19
|
+
/** Compile scalar sequences as counted runs; preserve the NFA for branching expressions. */
|
|
20
|
+
export declare function compilePattern(source: string): Pattern | RunPattern;
|
|
21
|
+
/**
|
|
22
|
+
* Whether a parsed I-Regexp compiles within the state budget: as counted runs, which never expand,
|
|
23
|
+
* or as a machine of at most `MAX_STATES` states, counted from the AST before anything is built.
|
|
24
|
+
*/
|
|
25
|
+
export declare function withinStateBudget(expression: Expression): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The number of states `Builder` builds for an expression, computed from the AST alone: `states`
|
|
28
|
+
* in `proofs/Regexp.lean`, where `compile_size` proves it exact. Nesting and counts are bounded by
|
|
29
|
+
* the parser, so the count stays finite; it is exact up to `Number.MAX_SAFE_INTEGER`, and above it
|
|
30
|
+
* every rounding keeps it above the budget.
|
|
31
|
+
*/
|
|
32
|
+
export declare function states(expression: Expression): number;
|
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
import { parseIRegexp } from './ast.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The most states the machine of one I-Regexp may have (`limits.regexp.maxStates`), an
|
|
4
|
+
* implementation limit as RFC 9485 §8 allows. Counted repetitions are expanded copy by copy, so the
|
|
5
|
+
* parser's bounds on length, nesting and counts alone admit machines of billions of states. The
|
|
6
|
+
* counted-run form never expands, so it is not subject to this budget.
|
|
7
|
+
*/
|
|
8
|
+
export const MAX_STATES = 10_000;
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when an I-Regexp source compiles to a machine of more than `MAX_STATES` states. A short
|
|
11
|
+
* branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and cost seconds per
|
|
12
|
+
* validated value (P1-I-01); it is refused before any state is built.
|
|
13
|
+
*/
|
|
14
|
+
export class PatternComplexityError extends RangeError {
|
|
15
|
+
limit;
|
|
16
|
+
constructor(limit = MAX_STATES) {
|
|
17
|
+
super(`Cannot compile an I-Regexp machine of more than ${limit} states.`);
|
|
18
|
+
this.limit = limit;
|
|
19
|
+
this.name = 'PatternComplexityError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Compile scalar sequences as counted runs; preserve the NFA for branching expressions. */
|
|
3
23
|
export function compilePattern(source) {
|
|
4
24
|
const expression = parseIRegexp(source);
|
|
5
25
|
if (expression === undefined)
|
|
6
26
|
throw new TypeError('Cannot compile an invalid I-Regexp source.');
|
|
27
|
+
const runs = scalarRuns(expression);
|
|
28
|
+
if (runs !== undefined)
|
|
29
|
+
return Object.freeze({ source, runs });
|
|
30
|
+
if (states(expression) > MAX_STATES)
|
|
31
|
+
throw new PatternComplexityError();
|
|
7
32
|
const builder = new Builder();
|
|
8
33
|
const fragment = builder.expression(expression);
|
|
9
34
|
builder.states[fragment.end].accepting = true;
|
|
@@ -13,9 +38,77 @@ export function compilePattern(source) {
|
|
|
13
38
|
states: Object.freeze(builder.states.map(freezeState)),
|
|
14
39
|
});
|
|
15
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether a parsed I-Regexp compiles within the state budget: as counted runs, which never expand,
|
|
43
|
+
* or as a machine of at most `MAX_STATES` states, counted from the AST before anything is built.
|
|
44
|
+
*/
|
|
45
|
+
export function withinStateBudget(expression) {
|
|
46
|
+
return scalarRuns(expression) !== undefined || states(expression) <= MAX_STATES;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The number of states `Builder` builds for an expression, computed from the AST alone: `states`
|
|
50
|
+
* in `proofs/Regexp.lean`, where `compile_size` proves it exact. Nesting and counts are bounded by
|
|
51
|
+
* the parser, so the count stays finite; it is exact up to `Number.MAX_SAFE_INTEGER`, and above it
|
|
52
|
+
* every rounding keeps it above the budget.
|
|
53
|
+
*/
|
|
54
|
+
export function states(expression) {
|
|
55
|
+
const [only, ...others] = expression.alternatives;
|
|
56
|
+
if (only !== undefined && others.length === 0)
|
|
57
|
+
return sequenceStates(only);
|
|
58
|
+
return expression.alternatives.reduce((total, sequence) => total + sequenceStates(sequence), 2);
|
|
59
|
+
}
|
|
60
|
+
function sequenceStates({ pieces }) {
|
|
61
|
+
if (pieces.length === 0)
|
|
62
|
+
return 2;
|
|
63
|
+
return pieces.reduce((total, piece) => total + pieceStates(piece), 0);
|
|
64
|
+
}
|
|
65
|
+
/** `pieceStates`: `minimum` copies, then a star, or a shared end and the optional copies. */
|
|
66
|
+
function pieceStates({ atom, minimum, maximum }) {
|
|
67
|
+
const copy = atom.kind === 'ranges' ? 2 : states(atom.expression);
|
|
68
|
+
if (maximum === undefined)
|
|
69
|
+
return minimum * copy + (copy + 2);
|
|
70
|
+
return ((minimum === 0 ? 2 : minimum * copy) +
|
|
71
|
+
(maximum === minimum ? 0 : 1 + (maximum - minimum) * copy));
|
|
72
|
+
}
|
|
73
|
+
function scalarRuns(expression) {
|
|
74
|
+
if (expression.alternatives.length !== 1)
|
|
75
|
+
return undefined;
|
|
76
|
+
const pieces = expression.alternatives[0].pieces;
|
|
77
|
+
let counted = false;
|
|
78
|
+
for (let index = 0; index < pieces.length; index++) {
|
|
79
|
+
const piece = pieces[index];
|
|
80
|
+
if (piece.atom.kind !== 'ranges' ||
|
|
81
|
+
(index !== pieces.length - 1 && piece.minimum !== piece.maximum))
|
|
82
|
+
return undefined;
|
|
83
|
+
if (piece.maximum !== undefined && piece.maximum > 1)
|
|
84
|
+
counted = true;
|
|
85
|
+
}
|
|
86
|
+
if (!counted)
|
|
87
|
+
return undefined;
|
|
88
|
+
const runs = [];
|
|
89
|
+
for (const piece of pieces) {
|
|
90
|
+
if (piece.atom.kind !== 'ranges')
|
|
91
|
+
return undefined;
|
|
92
|
+
runs.push(Object.freeze({
|
|
93
|
+
ranges: freezeRanges(piece.atom.ranges),
|
|
94
|
+
minimum: piece.minimum,
|
|
95
|
+
...(piece.maximum === undefined ? {} : { maximum: piece.maximum }),
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
return Object.freeze(runs);
|
|
99
|
+
}
|
|
100
|
+
function freezeRanges(ranges) {
|
|
101
|
+
if (Object.isFrozen(ranges))
|
|
102
|
+
return ranges;
|
|
103
|
+
for (const range of ranges)
|
|
104
|
+
Object.freeze(range);
|
|
105
|
+
return Object.freeze(ranges);
|
|
106
|
+
}
|
|
16
107
|
class Builder {
|
|
17
108
|
states = [];
|
|
18
109
|
expression(expression) {
|
|
110
|
+
if (expression.alternatives.length === 1)
|
|
111
|
+
return this.sequence(expression.alternatives[0]);
|
|
19
112
|
const start = this.state();
|
|
20
113
|
const end = this.state();
|
|
21
114
|
for (const alternative of expression.alternatives) {
|
|
@@ -26,22 +119,34 @@ class Builder {
|
|
|
26
119
|
return { start, end };
|
|
27
120
|
}
|
|
28
121
|
sequence(sequence) {
|
|
29
|
-
let output
|
|
30
|
-
for (const piece of sequence.pieces)
|
|
31
|
-
|
|
32
|
-
|
|
122
|
+
let output;
|
|
123
|
+
for (const piece of sequence.pieces) {
|
|
124
|
+
const fragment = this.piece(piece);
|
|
125
|
+
output = output === undefined ? fragment : this.concat(output, fragment);
|
|
126
|
+
}
|
|
127
|
+
return output ?? this.empty();
|
|
33
128
|
}
|
|
34
129
|
piece(piece) {
|
|
35
|
-
let output
|
|
130
|
+
let output;
|
|
36
131
|
for (let index = 0; index < piece.minimum; index++) {
|
|
37
|
-
|
|
132
|
+
const fragment = this.atom(piece.atom);
|
|
133
|
+
output = output === undefined ? fragment : this.concat(output, fragment);
|
|
38
134
|
}
|
|
39
|
-
if (piece.maximum === undefined)
|
|
40
|
-
|
|
135
|
+
if (piece.maximum === undefined) {
|
|
136
|
+
const repeated = this.star(piece.atom);
|
|
137
|
+
return output === undefined ? repeated : this.concat(output, repeated);
|
|
138
|
+
}
|
|
139
|
+
if (piece.maximum === piece.minimum)
|
|
140
|
+
return output ?? this.empty();
|
|
141
|
+
output ??= this.empty();
|
|
142
|
+
const end = this.state();
|
|
41
143
|
for (let index = piece.minimum; index < piece.maximum; index++) {
|
|
42
|
-
|
|
144
|
+
// A shorter repetition exits the whole suffix, rather than skipping arbitrary copies.
|
|
145
|
+
this.epsilon(output.end, end);
|
|
146
|
+
output = this.concat(output, this.atom(piece.atom));
|
|
43
147
|
}
|
|
44
|
-
|
|
148
|
+
this.epsilon(output.end, end);
|
|
149
|
+
return { start: output.start, end };
|
|
45
150
|
}
|
|
46
151
|
atom(atom) {
|
|
47
152
|
if (atom.kind === 'expression')
|
|
@@ -51,15 +156,6 @@ class Builder {
|
|
|
51
156
|
this.states[start].transitions.push({ to: end, ranges: atom.ranges });
|
|
52
157
|
return { start, end };
|
|
53
158
|
}
|
|
54
|
-
optional(atom) {
|
|
55
|
-
const start = this.state();
|
|
56
|
-
const end = this.state();
|
|
57
|
-
const child = this.atom(atom);
|
|
58
|
-
this.epsilon(start, end);
|
|
59
|
-
this.epsilon(start, child.start);
|
|
60
|
-
this.epsilon(child.end, end);
|
|
61
|
-
return { start, end };
|
|
62
|
-
}
|
|
63
159
|
star(atom) {
|
|
64
160
|
const start = this.state();
|
|
65
161
|
const end = this.state();
|
|
@@ -90,7 +186,7 @@ class Builder {
|
|
|
90
186
|
function freezeState(state) {
|
|
91
187
|
return Object.freeze({
|
|
92
188
|
epsilon: Object.freeze(state.epsilon),
|
|
93
|
-
transitions: Object.freeze(state.transitions.map((transition) => Object.freeze({ to: transition.to, ranges:
|
|
189
|
+
transitions: Object.freeze(state.transitions.map((transition) => Object.freeze({ to: transition.to, ranges: freezeRanges(transition.ranges) }))),
|
|
94
190
|
...(state.accepting === true ? { accepting: true } : {}),
|
|
95
191
|
});
|
|
96
192
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type { Pattern } from '../compile/model.js';
|
|
1
|
+
import type { Pattern, RunPattern } from '../compile/model.js';
|
|
2
2
|
export interface IRegexpMatcher {
|
|
3
3
|
test(value: string): boolean;
|
|
4
4
|
matches(value: string): boolean;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Load the portable counted-run or Thompson NFA executor for search and whole-string matching.
|
|
8
|
+
* Scratch belongs to one invocation: no match-result cache, shared mutable cursor or DFA expansion.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadPattern(pattern: Pattern | RunPattern): IRegexpMatcher;
|