@astrale-os/kernel-dsl 1.0.0-beta.13 → 1.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/v1/addressing/key.js +2 -1
  2. package/dist/v1/addressing/patterns.d.ts +1 -0
  3. package/dist/v1/addressing/patterns.js +2 -1
  4. package/dist/v1/builder/class/property.d.ts +3 -9
  5. package/dist/v1/builder/class/property.js +1 -0
  6. package/dist/v1/builder/lowering/class.js +5 -1
  7. package/dist/v1/builder/lowering/policy.js +1 -0
  8. package/dist/v1/builder/policy/authoring.js +3 -2
  9. package/dist/v1/bundle/codec.js +2 -2
  10. package/dist/v1/bundle/diagnostic.d.ts +2 -0
  11. package/dist/v1/bundle/diagnostic.js +6 -0
  12. package/dist/v1/bundle/structure.js +2 -2
  13. package/dist/v1/domain/validation/create.d.ts +4 -1
  14. package/dist/v1/domain/validation/create.js +21 -34
  15. package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
  16. package/dist/v1/language/class/model/class.d.ts +4 -4
  17. package/dist/v1/language/class/model/edge.d.ts +2 -2
  18. package/dist/v1/language/class/model/property.d.ts +16 -7
  19. package/dist/v1/language/definition/metadata.d.ts +5 -0
  20. package/dist/v1/language/definition/metadata.js +7 -0
  21. package/dist/v1/language/policy/model/policy.d.ts +5 -5
  22. package/dist/v1/language/policy/normalization/normalize.js +17 -16
  23. package/dist/v1/language/validation/diagnostic.d.ts +1 -1
  24. package/dist/v1/language/validation/rule.d.ts +26 -0
  25. package/dist/v1/language/validation/rule.js +116 -0
  26. package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
  27. package/dist/v1/language/value/profile/rules.js +13 -37
  28. package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
  29. package/dist/v1/language/value/profile/vocabulary.js +52 -5
  30. package/dist/v1/language/value/reference/registry.index.js +2 -1
  31. package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
  32. package/dist/v1/language/value/syntax/keywords.js +4 -20
  33. package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
  34. package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2336 -0
  35. package/dist/v1/schema/analysis/class.js +33 -15
  36. package/dist/v1/schema/compatibility/api.d.ts +1 -1
  37. package/dist/v1/schema/compatibility/coordinate.js +3 -3
  38. package/dist/v1/schema/compatibility/model.d.ts +5 -0
  39. package/dist/v1/schema/diagnostic.d.ts +17 -3
  40. package/dist/v1/schema/diagnostic.js +11 -0
  41. package/dist/v1/schema/index.d.ts +3 -1
  42. package/dist/v1/schema/index.js +1 -0
  43. package/dist/v1/schema/model/schema.d.ts +19 -1
  44. package/dist/v1/schema/normalization/domain.js +1 -0
  45. package/dist/v1/schema/resolution/closure.js +2 -1
  46. package/dist/v1/schema/resolution/context.js +3 -1
  47. package/dist/v1/schema/rule.d.ts +29 -0
  48. package/dist/v1/schema/rule.js +415 -0
  49. package/dist/v1/schema/validation/callable.d.ts +4 -1
  50. package/dist/v1/schema/validation/callable.js +10 -1
  51. package/dist/v1/schema/validation/class.js +36 -44
  52. package/dist/v1/schema/validation/core.js +3 -3
  53. package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
  54. package/dist/v1/schema/validation/domain.json-schema.js +183 -0
  55. package/dist/v1/schema/validation/domain.structure.d.ts +4018 -0
  56. package/dist/v1/schema/validation/domain.structure.js +341 -151
  57. package/dist/v1/schema/validation/json.json-schema.d.ts +24 -0
  58. package/dist/v1/schema/validation/json.json-schema.js +36 -0
  59. package/dist/v1/schema/validation/policy/references.js +5 -21
  60. package/dist/v1/schema/validation/policy/uses.js +0 -3
  61. package/dist/v1/schema/validation/value-api.d.ts +12 -1
  62. package/dist/v1/schema/validation/value-api.js +10 -1
  63. package/dist/v1/schema/validation/value.js +3 -3
  64. package/dist/v1/schema/validation/value.json-schema.d.ts +51 -0
  65. package/dist/v1/schema/validation/value.json-schema.js +126 -0
  66. package/package.json +3 -1
@@ -0,0 +1,24 @@
1
+ import type { core as zodCore } from 'zod';
2
+ type JsonSchema = zodCore.JSONSchema.JSONSchema;
3
+ /**
4
+ * The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
5
+ * JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
6
+ * member name holds U+0000, and cannot state negative zero, a lone surrogate, a UTF-8 size, a
7
+ * nesting depth without one definition per level, a count of members, or what the text was.
8
+ */
9
+ export declare const jsonValueRules: {
10
+ readonly 'portable-json': {
11
+ readonly code: 'DV_JSON_VALUE';
12
+ readonly statement: string;
13
+ };
14
+ };
15
+ export type JsonValueRule = keyof typeof jsonValueRules;
16
+ /**
17
+ * Portable JSON in JSON Schema: `root` constrains the whole document, and `definitions` holds every
18
+ * value it reaches and every string. The named check leaves `x-astrale-rule` on `portable-json`.
19
+ */
20
+ export declare function jsonValueJsonSchema(): {
21
+ readonly root: JsonSchema;
22
+ readonly definitions: Readonly<Record<string, JsonSchema>>;
23
+ };
24
+ export {};
@@ -0,0 +1,36 @@
1
+ import { RULES } from '../rule.js';
2
+ /**
3
+ * The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
4
+ * JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
5
+ * member name holds U+0000, and cannot state negative zero, a lone surrogate, a UTF-8 size, a
6
+ * nesting depth without one definition per level, a count of members, or what the text was.
7
+ */
8
+ export const jsonValueRules = {
9
+ 'portable-json': { code: 'DV_JSON_VALUE', statement: RULES.DV_JSON_VALUE.statement },
10
+ };
11
+ const VALUE = '#/$defs/portable-json';
12
+ const TEXT = '#/$defs/portable-string';
13
+ /**
14
+ * Portable JSON in JSON Schema: `root` constrains the whole document, and `definitions` holds every
15
+ * value it reaches and every string. The named check leaves `x-astrale-rule` on `portable-json`.
16
+ */
17
+ export function jsonValueJsonSchema() {
18
+ return {
19
+ root: { $ref: VALUE },
20
+ definitions: {
21
+ 'portable-json': {
22
+ anyOf: [
23
+ { type: 'null' },
24
+ { type: 'boolean' },
25
+ { type: 'number' },
26
+ { $ref: TEXT },
27
+ { type: 'array', items: { $ref: VALUE } },
28
+ { type: 'object', propertyNames: { $ref: TEXT }, additionalProperties: { $ref: VALUE } },
29
+ ],
30
+ 'x-astrale-rule': 'portable-json',
31
+ },
32
+ // The pattern is the character itself, which every regular-expression dialect reads.
33
+ 'portable-string': { type: 'string', not: { pattern: '\u0000' } },
34
+ },
35
+ };
36
+ }
@@ -3,7 +3,6 @@ import { branchesOf, isConnected, targetMode } from '../../../language/policy/an
3
3
  import { policyVariableClass } from '../../../language/policy/model/policy.js';
4
4
  import { normalizePolicyExpression, normalizePolicyPattern, } from '../../../language/policy/normalization/normalize.js';
5
5
  import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
6
- import { MAX_REPEAT, MAX_VARIABLES } from './budgets.js';
7
6
  import { referenceContracts } from './objects.js';
8
7
  export function validatePolicyReferences(context) {
9
8
  for (const [name, declaration] of Object.entries(context.environment.candidate.policies)) {
@@ -15,9 +14,9 @@ export function validatePolicyReferences(context) {
15
14
  const expression = declaration.expression;
16
15
  context.normalized.set(name, normalizePolicyExpression(expression));
17
16
  if ('match' in expression)
18
- validateMatch(context, name, expression.match, pointer);
17
+ validateMatch(context, name, expression.match, `${pointer}/expression`);
19
18
  else
20
- validateComposition(context, expression, pointer);
19
+ validateComposition(context, expression, `${pointer}/expression`);
21
20
  }
22
21
  validateCycles(context);
23
22
  }
@@ -53,22 +52,13 @@ function validatePatternNode(context, pattern, pointer, scope, declarations, use
53
52
  context.resolveEdge(pattern.class, `${pointer}/class`);
54
53
  validateTerm(context, pattern.source, `${pointer}/source`, scope, uses);
55
54
  validateTerm(context, pattern.target, `${pointer}/target`, scope, uses);
56
- if (pattern.repeat !== undefined) {
57
- const { min, max } = pattern.repeat;
58
- if (!Number.isInteger(min) ||
59
- !Number.isInteger(max) ||
60
- min < 0 ||
61
- max < min ||
62
- max > MAX_REPEAT) {
63
- context.add('PL_REPEAT', `${pointer}/repeat`, `Repeat requires integral bounds 0 <= min <= max <= ${MAX_REPEAT}.`);
64
- }
55
+ // The structure bounds each to an integer from 0 to MAX_REPEAT; only their order is left.
56
+ if (pattern.repeat !== undefined && pattern.repeat.max < pattern.repeat.min) {
57
+ context.add('PL_REPEAT', `${pointer}/repeat`, 'Repeat requires min <= max.');
65
58
  }
66
59
  return;
67
60
  }
68
61
  if ('exists' in pattern) {
69
- if (pattern.exists.nodes.length > MAX_VARIABLES) {
70
- context.add('PL_BUDGET', `${pointer}/exists/nodes`, `An exists expression declares ${pattern.exists.nodes.length} variables; the maximum is ${MAX_VARIABLES}.`);
71
- }
72
62
  const nested = new Set(scope);
73
63
  for (const [index, node] of pattern.exists.nodes.entries()) {
74
64
  const id = node.variable.id;
@@ -92,9 +82,6 @@ function validatePatternNode(context, pattern, pointer, scope, declarations, use
92
82
  return;
93
83
  }
94
84
  const { key, values } = patternOperands(pattern);
95
- if (values.length === 0) {
96
- context.add('PL_COMPOSITION', `${pointer}/${key}`, `${key} must be non-empty.`);
97
- }
98
85
  values.forEach((child, index) => validatePatternNode(context, child, `${pointer}/${key}/${index}`, scope, declarations, uses));
99
86
  }
100
87
  function validateTerm(context, term, pointer, scope, uses) {
@@ -112,9 +99,6 @@ function validateTerm(context, term, pointer, scope, uses) {
112
99
  function validateComposition(context, declaration, pointer) {
113
100
  const key = 'allOf' in declaration ? 'allOf' : 'anyOf';
114
101
  const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
115
- if (refs.length === 0) {
116
- context.add('PL_COMPOSITION', `${pointer}/${key}`, `${key} must be non-empty.`);
117
- }
118
102
  refs.forEach((ref, index) => context.resolvePolicy(ref, `${pointer}/${key}/${index}`));
119
103
  }
120
104
  function validateCycles(context) {
@@ -147,9 +147,6 @@ function visitChecks(validation, typing, expression, context, pointer, leaves) {
147
147
  return;
148
148
  }
149
149
  const { key, values } = checkOperands(expression);
150
- if (values.length === 0) {
151
- validation.add('PL_COMPOSITION', `${pointer}/${key}`, `${key} must be non-empty.`);
152
- }
153
150
  values.forEach((child, index) => visitChecks(validation, typing, child, context, `${pointer}/${key}/${index}`, leaves));
154
151
  }
155
152
  function selfContracts(validation, context, pointer) {
@@ -10,11 +10,22 @@ export type { BlobOptions, BlobReceipt, BlobRef, BlobSchema, } from '../../langu
10
10
  export type { JsonSchema as Schema, JsonSchemaObject as SchemaObject, PathAnnotation, PropertyObjectSchema as PropertySchema, ValueSchemaContext as Context, } from '../../language/value/model/schema.js';
11
11
  export { instant } from '../../language/value/model/instant.js';
12
12
  export type { OrderingKind } from '../../language/value/ordering.js';
13
+ export { DECLARED_VALUE_KINDS as DECLARED_KINDS, FORBIDDEN_KEYWORDS, SUBSCHEMA_KEYWORDS, VALUE_KEYWORDS as KEYWORDS, } from '../../language/value/profile/vocabulary.js';
14
+ export type { DeclaredValueKind as DeclaredKind, ValueKeyword as Keyword, } from '../../language/value/profile/vocabulary.js';
15
+ export { VALUE_RULES as RULES } from '../../language/validation/rule.js';
16
+ export type { ValueRule as Rule, ValueRuleStage as RuleStage, } from '../../language/validation/rule.js';
13
17
  /** Validate one complete JSON value under the exact accepted schema that owns the contract. */
14
18
  export declare function validate(owner: DomainSchema, contract: JsonSchema, input: unknown, pointer?: string): readonly Diagnostic[];
15
19
  /** Return the one portable scalar ordering domain admitted by a property schema, if any. */
16
20
  export declare function classifyOrdering(owner: DomainSchema, contract: JsonSchema): OrderingKind | undefined;
17
- /** The value kind of a property schema: what a graph language may test on the property (Y4). */
21
+ /**
22
+ * The value kind of a property schema: what a graph language may test on the property (Y4). It is
23
+ * the one kind of every non-null value the schema admits: `text` for strings, `number` for numbers
24
+ * and integers, `instant` for strings declared `x-astrale-value-kind: instant`, `enum` for a finite
25
+ * set of strings (`const` or `enum`), `boolean`, and `set` for arrays of `uniqueItems`. An
26
+ * ambiguous union, an object, an array with repetitions, a blob or a schema that admits no value is
27
+ * `json`. `$ref`, `allOf`, `anyOf` and `oneOf` are followed; `null` is a point of every kind.
28
+ */
18
29
  export declare function classifyValueKind(owner: DomainSchema, contract: JsonSchema): ValueKind;
19
30
  /**
20
31
  * A warning for each class property whose value kind is `json` (an ambiguous union, an object, an
@@ -8,6 +8,8 @@ const registries = new WeakMap();
8
8
  export { VALUE_SCHEMA_DIALECT as DIALECT, VALUE_SCHEMA_VOCABULARY as VOCABULARY, } from '../../language/value/model/schema.js';
9
9
  export { blob, isBlobValueSchema as isBlob } from '../../language/value/model/blob.js';
10
10
  export { instant } from '../../language/value/model/instant.js';
11
+ export { DECLARED_VALUE_KINDS as DECLARED_KINDS, FORBIDDEN_KEYWORDS, SUBSCHEMA_KEYWORDS, VALUE_KEYWORDS as KEYWORDS, } from '../../language/value/profile/vocabulary.js';
12
+ export { VALUE_RULES as RULES } from '../../language/validation/rule.js';
11
13
  /** Validate one complete JSON value under the exact accepted schema that owns the contract. */
12
14
  export function validate(owner, contract, input, pointer = '') {
13
15
  return validateJsonInstance(contract, input, registryFor(owner), pointer);
@@ -16,7 +18,14 @@ export function validate(owner, contract, input, pointer = '') {
16
18
  export function classifyOrdering(owner, contract) {
17
19
  return classifyOrderingWithRegistry(contract, registryFor(owner));
18
20
  }
19
- /** The value kind of a property schema: what a graph language may test on the property (Y4). */
21
+ /**
22
+ * The value kind of a property schema: what a graph language may test on the property (Y4). It is
23
+ * the one kind of every non-null value the schema admits: `text` for strings, `number` for numbers
24
+ * and integers, `instant` for strings declared `x-astrale-value-kind: instant`, `enum` for a finite
25
+ * set of strings (`const` or `enum`), `boolean`, and `set` for arrays of `uniqueItems`. An
26
+ * ambiguous union, an object, an array with repetitions, a blob or a schema that admits no value is
27
+ * `json`. `$ref`, `allOf`, `anyOf` and `oneOf` are followed; `null` is a point of every kind.
28
+ */
20
29
  export function classifyValueKind(owner, contract) {
21
30
  return classifyValueKindWithRegistry(contract, registryFor(owner));
22
31
  }
@@ -1,7 +1,7 @@
1
1
  import { isBinaryInput } from '../../language/callable/model/callable.js';
2
2
  import { validateValueSchema } from '../../language/value/profile/validate.js';
3
3
  import { escapePointerToken } from '../../language/value/syntax/pointer.js';
4
- import { diagnostic } from '../diagnostic.js';
4
+ import { valueDiagnostic } from '../diagnostic.js';
5
5
  export function validateEmbeddedValueSchemas(schema, registry) {
6
6
  const diagnostics = [];
7
7
  for (const [name, declaration] of Object.entries(schema.classes)) {
@@ -37,7 +37,7 @@ function validateCallable(declaration, pointer, registry, diagnostics) {
37
37
  }
38
38
  }
39
39
  function validate(schema, context, pointer, registry, diagnostics) {
40
- for (const failure of validateValueSchema(schema, context, registry, pointer)) {
41
- diagnostics.push(diagnostic('DV_VALUE_SCHEMA', failure.pointer, `[${failure.code}] ${failure.message}`, failure.ref));
40
+ for (const refusal of validateValueSchema(schema, context, registry, pointer)) {
41
+ diagnostics.push(valueDiagnostic('DV_VALUE_SCHEMA', refusal));
42
42
  }
43
43
  }
@@ -0,0 +1,51 @@
1
+ import type { core as zodCore } from 'zod';
2
+ type JsonSchema = zodCore.JSONSchema.JSONSchema;
3
+ /**
4
+ * The checks on value schemas JSON Schema cannot state, which the published document names with
5
+ * the positions it constrains. The Kernel reports each as `DV_VALUE_SCHEMA`, with its value code.
6
+ */
7
+ export declare const valueSchemaRules: {
8
+ readonly 'value-blob': {
9
+ readonly code: 'DV_VALUE_SCHEMA';
10
+ readonly valueCode: 'VS_VALUE_KIND';
11
+ readonly statement: 'A blob is declared only by the whole schema of a Property, exactly as values.blob writes it.';
12
+ };
13
+ readonly 'value-path': {
14
+ readonly code: 'DV_VALUE_SCHEMA';
15
+ readonly valueCode: 'VS_PATH_EXTENSION';
16
+ readonly statement: 'x-astrale-path annotates only a direct Property of a callable input object, beside exactly the $ref of the graph NodePath schema, and reads target node, cardinality one and a non-empty set of Node Class refs it accepts.';
17
+ };
18
+ readonly 'value-recursion': {
19
+ readonly code: 'DV_VALUE_SCHEMA';
20
+ readonly valueCode: 'VS_RECURSION_PRODUCTIVE';
21
+ readonly statement: 'Every reference cycle of a value schema crosses a keyword that steps into the value: to a member, a member name or an item.';
22
+ };
23
+ readonly 'value-reference-form': {
24
+ readonly code: 'DV_VALUE_SCHEMA';
25
+ readonly valueCode: 'VS_REFERENCE_FORM';
26
+ readonly statement: 'A $ref is a JSON Pointer fragment into its own value schema, or the id of the graph NodePath schema beside x-astrale-path.';
27
+ };
28
+ readonly 'value-reference-resolution': {
29
+ readonly code: 'DV_VALUE_SCHEMA';
30
+ readonly valueCode: 'VS_REFERENCE_RESOLUTION';
31
+ readonly statement: 'A $ref resolves to a location of its own value schema, and x-astrale-path accepts Node Classes of the Domain or of a direct dependency.';
32
+ };
33
+ readonly 'value-regexp': {
34
+ readonly code: 'DV_VALUE_SCHEMA';
35
+ readonly valueCode: 'VS_REGEX_PORTABLE';
36
+ readonly statement: 'Every pattern, fullMatch and patternProperties name is an RFC 9485 I-Regexp within the regular-expression limits.';
37
+ };
38
+ };
39
+ export type ValueSchemaRule = keyof typeof valueSchemaRules;
40
+ /**
41
+ * The value language in JSON Schema, for the document that embeds value schemas: `root` constrains
42
+ * the `value-schema` definition with the published dialect and what the profile adds to it,
43
+ * `definitions` holds the locations it reaches, and `nodeProperty` constrains a Node Property
44
+ * definition. A named check leaves `x-astrale-rule` at the positions it constrains.
45
+ */
46
+ export declare function valueSchemaJsonSchema(): {
47
+ readonly root: readonly JsonSchema[];
48
+ readonly definitions: Readonly<Record<string, JsonSchema>>;
49
+ readonly nodeProperty: JsonSchema;
50
+ };
51
+ export {};
@@ -0,0 +1,126 @@
1
+ import { VALUE_SCHEMA_DIALECT } from '../../language/value/model/schema.js';
2
+ import { FORBIDDEN_KEYWORDS, SUBSCHEMA_KEYWORDS, VALUE_KEYWORDS, } from '../../language/value/profile/vocabulary.js';
3
+ /**
4
+ * The checks on value schemas JSON Schema cannot state, which the published document names with
5
+ * the positions it constrains. The Kernel reports each as `DV_VALUE_SCHEMA`, with its value code.
6
+ */
7
+ export const valueSchemaRules = {
8
+ 'value-blob': {
9
+ code: 'DV_VALUE_SCHEMA',
10
+ valueCode: 'VS_VALUE_KIND',
11
+ statement: 'A blob is declared only by the whole schema of a Property, exactly as values.blob writes it.',
12
+ },
13
+ 'value-path': {
14
+ code: 'DV_VALUE_SCHEMA',
15
+ valueCode: 'VS_PATH_EXTENSION',
16
+ statement: 'x-astrale-path annotates only a direct Property of a callable input object, beside exactly the $ref of the graph NodePath schema, and reads target node, cardinality one and a non-empty set of Node Class refs it accepts.',
17
+ },
18
+ 'value-recursion': {
19
+ code: 'DV_VALUE_SCHEMA',
20
+ valueCode: 'VS_RECURSION_PRODUCTIVE',
21
+ statement: 'Every reference cycle of a value schema crosses a keyword that steps into the value: to a member, a member name or an item.',
22
+ },
23
+ 'value-reference-form': {
24
+ code: 'DV_VALUE_SCHEMA',
25
+ valueCode: 'VS_REFERENCE_FORM',
26
+ statement: 'A $ref is a JSON Pointer fragment into its own value schema, or the id of the graph NodePath schema beside x-astrale-path.',
27
+ },
28
+ 'value-reference-resolution': {
29
+ code: 'DV_VALUE_SCHEMA',
30
+ valueCode: 'VS_REFERENCE_RESOLUTION',
31
+ statement: 'A $ref resolves to a location of its own value schema, and x-astrale-path accepts Node Classes of the Domain or of a direct dependency.',
32
+ },
33
+ 'value-regexp': {
34
+ code: 'DV_VALUE_SCHEMA',
35
+ valueCode: 'VS_REGEX_PORTABLE',
36
+ statement: 'Every pattern, fullMatch and patternProperties name is an RFC 9485 I-Regexp within the regular-expression limits.',
37
+ },
38
+ };
39
+ const KIND = 'x-astrale-value-kind';
40
+ const LOCATION = '#/$defs/value-location';
41
+ const SUBSCHEMA = '#/$defs/value-subschema';
42
+ /**
43
+ * The value language in JSON Schema, for the document that embeds value schemas: `root` constrains
44
+ * the `value-schema` definition with the published dialect and what the profile adds to it,
45
+ * `definitions` holds the locations it reaches, and `nodeProperty` constrains a Node Property
46
+ * definition. A named check leaves `x-astrale-rule` at the positions it constrains.
47
+ */
48
+ export function valueSchemaJsonSchema() {
49
+ return {
50
+ root: [
51
+ { $ref: VALUE_SCHEMA_DIALECT },
52
+ { $ref: LOCATION },
53
+ objectOrBoolean({
54
+ properties: {
55
+ $schema: { const: VALUE_SCHEMA_DIALECT },
56
+ [KIND]: {
57
+ enum: ['instant', 'blob'],
58
+ 'x-astrale-rule': 'value-blob',
59
+ },
60
+ },
61
+ }),
62
+ ],
63
+ definitions: {
64
+ // Every location, the root included: the closed vocabulary and the subschemas it holds.
65
+ 'value-location': objectOrBoolean({
66
+ propertyNames: {
67
+ enum: VALUE_KEYWORDS.filter((keyword) => !FORBIDDEN_KEYWORDS.includes(keyword)),
68
+ },
69
+ properties: {
70
+ $id: false,
71
+ $ref: {
72
+ type: 'string',
73
+ 'x-astrale-rule': [
74
+ 'value-recursion',
75
+ 'value-reference-form',
76
+ 'value-reference-resolution',
77
+ ],
78
+ },
79
+ enum: { type: 'array', uniqueItems: true },
80
+ fullMatch: { type: 'string', 'x-astrale-rule': 'value-regexp' },
81
+ pattern: { type: 'string', 'x-astrale-rule': 'value-regexp' },
82
+ 'x-astrale-path': { type: 'object', 'x-astrale-rule': 'value-path' },
83
+ ...Object.fromEntries(SUBSCHEMA_KEYWORDS.single.map((keyword) => [keyword, { $ref: SUBSCHEMA }])),
84
+ ...Object.fromEntries(SUBSCHEMA_KEYWORDS.array.map((keyword) => [
85
+ keyword,
86
+ { type: 'array', items: { $ref: SUBSCHEMA } },
87
+ ])),
88
+ ...Object.fromEntries(SUBSCHEMA_KEYWORDS.map.map((keyword) => [
89
+ keyword,
90
+ {
91
+ type: 'object',
92
+ additionalProperties: { $ref: SUBSCHEMA },
93
+ ...(keyword === 'patternProperties' ? { 'x-astrale-rule': 'value-regexp' } : {}),
94
+ },
95
+ ])),
96
+ },
97
+ // An instant is a string.
98
+ if: { required: [KIND], properties: { [KIND]: { const: 'instant' } } },
99
+ // oxlint-disable-next-line unicorn/no-thenable -- the JSON Schema keyword
100
+ then: { required: ['type'], properties: { type: { const: 'string' } } },
101
+ }),
102
+ // A location below the root: no $schema, and no blob.
103
+ 'value-subschema': {
104
+ allOf: [
105
+ { $ref: LOCATION },
106
+ objectOrBoolean({ properties: { $schema: false, [KIND]: { const: 'instant' } } }),
107
+ ],
108
+ },
109
+ },
110
+ // An automatic or State Property holds no blob.
111
+ nodeProperty: {
112
+ if: { anyOf: [{ required: ['auto'] }, { required: ['state'] }] },
113
+ // oxlint-disable-next-line unicorn/no-thenable -- the JSON Schema keyword
114
+ then: {
115
+ properties: {
116
+ schema: {
117
+ not: { type: 'object', required: [KIND], properties: { [KIND]: { const: 'blob' } } },
118
+ },
119
+ },
120
+ },
121
+ },
122
+ };
123
+ }
124
+ function objectOrBoolean(object) {
125
+ return { anyOf: [{ type: 'boolean' }, { type: 'object', ...object }] };
126
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-dsl",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.14",
4
4
  "description": "Astrale Kernel DSL - Schema authoring, inference, and IR serialization",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -79,6 +79,8 @@
79
79
  "types": "./dist/v1/schema/revision.d.ts",
80
80
  "import": "./dist/v1/schema/revision.js"
81
81
  },
82
+ "./v1/schema/domain-schema.schema.json": "./dist/v1/schema/.spec/schemas/domain-schema.schema.json",
83
+ "./v1/schema/value-schema.schema.json": "./dist/v1/language/.spec/schemas/value-schema.schema.json",
82
84
  "./v1/value/full-match": {
83
85
  "types": "./dist/v1/value/full-match.d.ts",
84
86
  "import": "./dist/v1/value/full-match.js"