@telorun/analyzer 0.48.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis-registry.d.ts +22 -11
- package/dist/analysis-registry.d.ts.map +1 -1
- package/dist/analysis-registry.js +36 -39
- package/dist/analyzer.d.ts +38 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +115 -83
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +72 -1
- package/dist/extends-resolution.d.ts +41 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +68 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/invocation-contract.d.ts +100 -0
- package/dist/invocation-contract.d.ts.map +1 -0
- package/dist/invocation-contract.js +208 -0
- package/dist/schema-compat.d.ts +12 -4
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +185 -9
- package/dist/validate-base-mapping.js +11 -1
- package/dist/validate-cel-context.d.ts +0 -6
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +51 -4
- package/dist/validate-invocation-contract.d.ts +30 -0
- package/dist/validate-invocation-contract.d.ts.map +1 -0
- package/dist/validate-invocation-contract.js +394 -0
- package/dist/validate-step-inputs.d.ts +24 -0
- package/dist/validate-step-inputs.d.ts.map +1 -0
- package/dist/validate-step-inputs.js +87 -0
- package/dist/validate-throws-coverage.d.ts +1 -1
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +9 -1
- package/package.json +2 -2
- package/src/analysis-registry.ts +44 -34
- package/src/analyzer.ts +171 -100
- package/src/builtins.ts +74 -1
- package/src/extends-resolution.ts +86 -0
- package/src/index.ts +13 -1
- package/src/invocation-contract.ts +275 -0
- package/src/schema-compat.ts +191 -8
- package/src/validate-base-mapping.ts +14 -1
- package/src/validate-cel-context.ts +49 -4
- package/src/validate-invocation-contract.ts +450 -0
- package/src/validate-step-inputs.ts +117 -0
- package/src/validate-throws-coverage.ts +12 -2
package/dist/builtins.js
CHANGED
|
@@ -206,6 +206,64 @@ export const KERNEL_BUILTINS = [
|
|
|
206
206
|
additionalProperties: false,
|
|
207
207
|
},
|
|
208
208
|
},
|
|
209
|
+
{
|
|
210
|
+
// Telo.JsonSchema — the concrete data-shape kind, in the kernel rather than
|
|
211
|
+
// in an installable module for the same reason the mandatory sinks are:
|
|
212
|
+
// declaring a shape is not optional. Every kind with an invocation contract
|
|
213
|
+
// needs one, so requiring an import to write `inputType:` would put a tax on
|
|
214
|
+
// the one thing the contract wants authors to do more of — and a library
|
|
215
|
+
// declaring a contract would have to import a module purely to describe
|
|
216
|
+
// itself. `type.JsonSchema` remains as a deprecated alias of this kind.
|
|
217
|
+
kind: "Telo.Definition",
|
|
218
|
+
metadata: { name: "JsonSchema", module: "Telo" },
|
|
219
|
+
capability: "Telo.Type",
|
|
220
|
+
// Declared so the kind reads as controller-BEARING, which is what lets
|
|
221
|
+
// another definition inherit it by delegation (`extends: Telo.JsonSchema`
|
|
222
|
+
// with no controller of its own). The entry is never loaded from — the
|
|
223
|
+
// kernel registers this controller directly at boot, before any lazy
|
|
224
|
+
// resolution — it states truthfully who provides it.
|
|
225
|
+
controllers: [{ runtime: "kernel", entry: "Telo.JsonSchema" }],
|
|
226
|
+
schema: {
|
|
227
|
+
type: "object",
|
|
228
|
+
properties: {
|
|
229
|
+
schema: {
|
|
230
|
+
title: "Schema",
|
|
231
|
+
description: "JSON Schema definition for the declared data type.",
|
|
232
|
+
type: "object",
|
|
233
|
+
},
|
|
234
|
+
extends: {
|
|
235
|
+
title: "Extends",
|
|
236
|
+
description: "Parent type name or list of parent type names to inherit from.",
|
|
237
|
+
oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
|
|
238
|
+
},
|
|
239
|
+
rules: {
|
|
240
|
+
title: "Rules",
|
|
241
|
+
description: "CEL-based business invariant rules. Each rule's condition must return true for valid data.",
|
|
242
|
+
type: "array",
|
|
243
|
+
items: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
condition: {
|
|
247
|
+
type: "string",
|
|
248
|
+
description: "CEL expression evaluated with 'this' bound to the data. Must return true for valid data.",
|
|
249
|
+
},
|
|
250
|
+
code: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "Machine-readable error code surfaced on validation failure.",
|
|
253
|
+
},
|
|
254
|
+
message: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Optional human-readable hint for the validation failure.",
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
required: ["condition", "code"],
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
required: ["schema"],
|
|
264
|
+
additionalProperties: false,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
209
267
|
{
|
|
210
268
|
kind: "Telo.Definition",
|
|
211
269
|
metadata: { name: "Abstract", module: "Telo" },
|
|
@@ -479,6 +537,11 @@ export const KERNEL_BUILTINS = [
|
|
|
479
537
|
default: "shared",
|
|
480
538
|
},
|
|
481
539
|
targets: {
|
|
540
|
+
// Boot targets form a step list: a later target reads an earlier one's
|
|
541
|
+
// result as `steps.<name>.result`, exactly as a sequence step does, so
|
|
542
|
+
// the same annotation types that context and drives the call-site
|
|
543
|
+
// contract check.
|
|
544
|
+
"x-telo-step-context": { invoke: "invoke", outputType: "outputType" },
|
|
482
545
|
type: "array",
|
|
483
546
|
items: {
|
|
484
547
|
anyOf: [
|
|
@@ -552,7 +615,15 @@ export const KERNEL_BUILTINS = [
|
|
|
552
615
|
{ "x-telo-ref": "Telo.Runnable" },
|
|
553
616
|
],
|
|
554
617
|
},
|
|
555
|
-
inputs: {
|
|
618
|
+
inputs: {
|
|
619
|
+
// Same annotation Run.Sequence steps carry: it is what makes
|
|
620
|
+
// a boot target's inputs visible to the call-site contract
|
|
621
|
+
// check and to the wiring rule. Without it the kernel would
|
|
622
|
+
// validate these at dispatch and nothing before it.
|
|
623
|
+
"x-telo-topology-role": "inputs",
|
|
624
|
+
type: "object",
|
|
625
|
+
additionalProperties: true,
|
|
626
|
+
},
|
|
556
627
|
when: { type: "string" },
|
|
557
628
|
},
|
|
558
629
|
additionalProperties: false,
|
|
@@ -36,6 +36,47 @@ export declare function inheritedCapability(def: ResourceDefinition | undefined,
|
|
|
36
36
|
* `mergeTypeSchemas` that `Type.JsonSchema.extends` uses.
|
|
37
37
|
* - no `extends` → the own schema unchanged. */
|
|
38
38
|
export declare function effectiveAuthorSchema(def: ResourceDefinition | undefined, resolve: DefResolver): Record<string, any>;
|
|
39
|
+
/** The two directions of a kind's invocation contract. `inputType` is what a
|
|
40
|
+
* caller sends to `invoke()`; `outputType` is what `invoke()` / `provide()`
|
|
41
|
+
* returns. */
|
|
42
|
+
export type ContractDirection = "inputType" | "outputType";
|
|
43
|
+
/**
|
|
44
|
+
* The **nearest declaration** of an invocation contract along the `extends`
|
|
45
|
+
* chain, self first — the raw type-field value, still to be resolved to a schema
|
|
46
|
+
* by the caller (which is what keeps this module free of manifest lookup).
|
|
47
|
+
*
|
|
48
|
+
* Contracts RESOLVE, they never merge. A definition that declares one fully
|
|
49
|
+
* replaces its ancestor's; one that declares none inherits its ancestor's
|
|
50
|
+
* verbatim, at any depth. This is deliberately unlike {@link
|
|
51
|
+
* effectiveAuthorSchema} and {@link effectiveStatusSchema}: construction config
|
|
52
|
+
* and observed state are additive, a call signature is not. Folding a child's
|
|
53
|
+
* required fields into its parent's yields a union no caller can satisfy, and it
|
|
54
|
+
* would reject the very remapping `base:` + `inputs:` exists for — the point of
|
|
55
|
+
* a child declaring a signature is that it accepts something *different*.
|
|
56
|
+
*
|
|
57
|
+
* Substitutability is not weakened by that, because `extends` never carried the
|
|
58
|
+
* dispatch contract: it decides which slots accept a resource. Whether a
|
|
59
|
+
* particular slot may hold a resource whose contract differs from the slot's
|
|
60
|
+
* declared kind is a wiring question, answered per slot by
|
|
61
|
+
* `validate-invocation-contract`'s wiring rule.
|
|
62
|
+
*/
|
|
63
|
+
export declare function effectiveContractField(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): unknown;
|
|
64
|
+
/** The definition in the `extends` chain (self first) that actually DECLARES the
|
|
65
|
+
* contract for `direction` — the one whose scope its `telo#Type` references
|
|
66
|
+
* resolve in, and the one a diagnostic should name. Undefined when nothing in
|
|
67
|
+
* the chain declares it. */
|
|
68
|
+
export declare function contractDeclarer(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): ResourceDefinition | undefined;
|
|
69
|
+
/** True when this definition declares its own contract for `direction` while
|
|
70
|
+
* inheriting the controller that will execute it — the case that REQUIRES a
|
|
71
|
+
* bridging mapping (`inputs:` for inputs, `result:` for outputs), because the
|
|
72
|
+
* inherited controller only understands the ancestor's shape. A definition with
|
|
73
|
+
* its own controller or template body is exempt: its controller *is* the
|
|
74
|
+
* implementation of whatever it declares. */
|
|
75
|
+
export declare function needsContractMapping(def: ResourceDefinition | undefined, resolve: DefResolver, direction: ContractDirection): boolean;
|
|
76
|
+
/** The mapping field that bridges a replaced contract back to the inherited
|
|
77
|
+
* controller: `inputs:` maps the child's signature onto the parent's call,
|
|
78
|
+
* `result:` maps the parent's result back to the child's declared output. */
|
|
79
|
+
export declare function mappingFieldFor(direction: ContractDirection): "inputs" | "result";
|
|
39
80
|
/** The observed state a kind reports (`status:`), folded through `extends`:
|
|
40
81
|
* - with `base:` present → the **parent's** effective status unchanged; the
|
|
41
82
|
* child delegates to the parent's controller and *is* a parent instance, so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AA0BpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;eAEe;AACf,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAQT;AAED;;;6BAG6B;AAC7B,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,kBAAkB,GAAG,SAAS,CAShC;AAED;;;;;8CAK8C;AAC9C,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAKT;AAED;;8EAE8E;AAC9E,wBAAgB,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAEjF;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
|
|
@@ -80,6 +80,74 @@ export function effectiveAuthorSchema(def, resolve) {
|
|
|
80
80
|
const parentSchema = effectiveAuthorSchema(parent, resolve);
|
|
81
81
|
return mergeTypeSchemas([parentSchema, own]);
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* The **nearest declaration** of an invocation contract along the `extends`
|
|
85
|
+
* chain, self first — the raw type-field value, still to be resolved to a schema
|
|
86
|
+
* by the caller (which is what keeps this module free of manifest lookup).
|
|
87
|
+
*
|
|
88
|
+
* Contracts RESOLVE, they never merge. A definition that declares one fully
|
|
89
|
+
* replaces its ancestor's; one that declares none inherits its ancestor's
|
|
90
|
+
* verbatim, at any depth. This is deliberately unlike {@link
|
|
91
|
+
* effectiveAuthorSchema} and {@link effectiveStatusSchema}: construction config
|
|
92
|
+
* and observed state are additive, a call signature is not. Folding a child's
|
|
93
|
+
* required fields into its parent's yields a union no caller can satisfy, and it
|
|
94
|
+
* would reject the very remapping `base:` + `inputs:` exists for — the point of
|
|
95
|
+
* a child declaring a signature is that it accepts something *different*.
|
|
96
|
+
*
|
|
97
|
+
* Substitutability is not weakened by that, because `extends` never carried the
|
|
98
|
+
* dispatch contract: it decides which slots accept a resource. Whether a
|
|
99
|
+
* particular slot may hold a resource whose contract differs from the slot's
|
|
100
|
+
* declared kind is a wiring question, answered per slot by
|
|
101
|
+
* `validate-invocation-contract`'s wiring rule.
|
|
102
|
+
*/
|
|
103
|
+
export function effectiveContractField(def, resolve, direction) {
|
|
104
|
+
const own = body(def)[direction];
|
|
105
|
+
if (own !== undefined && own !== null)
|
|
106
|
+
return own;
|
|
107
|
+
for (const a of ancestorChain(def, resolve)) {
|
|
108
|
+
const inherited = body(a)[direction];
|
|
109
|
+
if (inherited !== undefined && inherited !== null)
|
|
110
|
+
return inherited;
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
/** The definition in the `extends` chain (self first) that actually DECLARES the
|
|
115
|
+
* contract for `direction` — the one whose scope its `telo#Type` references
|
|
116
|
+
* resolve in, and the one a diagnostic should name. Undefined when nothing in
|
|
117
|
+
* the chain declares it. */
|
|
118
|
+
export function contractDeclarer(def, resolve, direction) {
|
|
119
|
+
if (!def)
|
|
120
|
+
return undefined;
|
|
121
|
+
const own = body(def)[direction];
|
|
122
|
+
if (own !== undefined && own !== null)
|
|
123
|
+
return def;
|
|
124
|
+
for (const a of ancestorChain(def, resolve)) {
|
|
125
|
+
const inherited = body(a)[direction];
|
|
126
|
+
if (inherited !== undefined && inherited !== null)
|
|
127
|
+
return a;
|
|
128
|
+
}
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
/** True when this definition declares its own contract for `direction` while
|
|
132
|
+
* inheriting the controller that will execute it — the case that REQUIRES a
|
|
133
|
+
* bridging mapping (`inputs:` for inputs, `result:` for outputs), because the
|
|
134
|
+
* inherited controller only understands the ancestor's shape. A definition with
|
|
135
|
+
* its own controller or template body is exempt: its controller *is* the
|
|
136
|
+
* implementation of whatever it declares. */
|
|
137
|
+
export function needsContractMapping(def, resolve, direction) {
|
|
138
|
+
const own = body(def)[direction];
|
|
139
|
+
if (own === undefined || own === null)
|
|
140
|
+
return false;
|
|
141
|
+
if (hasOwnControllerOrTemplate(def))
|
|
142
|
+
return false;
|
|
143
|
+
return controllerBearingAncestor(def, resolve) !== undefined;
|
|
144
|
+
}
|
|
145
|
+
/** The mapping field that bridges a replaced contract back to the inherited
|
|
146
|
+
* controller: `inputs:` maps the child's signature onto the parent's call,
|
|
147
|
+
* `result:` maps the parent's result back to the child's declared output. */
|
|
148
|
+
export function mappingFieldFor(direction) {
|
|
149
|
+
return direction === "inputType" ? "inputs" : "result";
|
|
150
|
+
}
|
|
83
151
|
/** The observed state a kind reports (`status:`), folded through `extends`:
|
|
84
152
|
* - with `base:` present → the **parent's** effective status unchanged; the
|
|
85
153
|
* child delegates to the parent's controller and *is* a parent instance, so
|
package/dist/index.d.ts
CHANGED
|
@@ -9,8 +9,10 @@ export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateReso
|
|
|
9
9
|
export type { AnalyzedResource, ObservedStateRead } from "./validate-observed-state.js";
|
|
10
10
|
export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
|
|
11
11
|
export type { ModuleScopes } from "./alias-resolver.js";
|
|
12
|
-
export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
|
|
13
|
-
export type { DefResolver } from "./extends-resolution.js";
|
|
12
|
+
export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
|
|
13
|
+
export type { ContractDirection, DefResolver } from "./extends-resolution.js";
|
|
14
|
+
export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withStreamPropertiesSkipped, } from "./invocation-contract.js";
|
|
15
|
+
export type { ContractOrigin, ContractScope, ResolvedContract } from "./invocation-contract.js";
|
|
14
16
|
export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
|
|
15
17
|
export type { RedactionSegment } from "./redaction-path.js";
|
|
16
18
|
export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,gCAAgC,EAChC,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,iCAAiC,EACjC,wBAAwB,EACxB,iBAAiB,EACjB,iCAAiC,EACjC,qBAAqB,GACtB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,8 @@ export { flattenForAnalyzer, flattenLoadedModule, forwardReExportManifests, pars
|
|
|
5
5
|
export { buildEvalPaths, evalPathCovers } from "./eval-paths.js";
|
|
6
6
|
export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, OBSERVED_STATE_SCHEMA, } from "./validate-observed-state.js";
|
|
7
7
|
export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
|
|
8
|
-
export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
|
|
8
|
+
export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
|
|
9
|
+
export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withStreamPropertiesSkipped, } from "./invocation-contract.js";
|
|
9
10
|
export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
|
|
10
11
|
export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
|
|
11
12
|
export { visitManifest } from "./manifest-visitor.js";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { ResourceDefinition } from "@telorun/sdk";
|
|
2
|
+
import { type ContractDirection, type DefResolver } from "./extends-resolution.js";
|
|
3
|
+
export type { ContractDirection };
|
|
4
|
+
/**
|
|
5
|
+
* The one answer to "what is this target's input / output schema".
|
|
6
|
+
*
|
|
7
|
+
* Both halves of Telo consume it: `telo check` validates call sites against it,
|
|
8
|
+
* and the kernel binds it to the instance at creation. It lives here rather than
|
|
9
|
+
* in the kernel because it must be browser-safe and because a second
|
|
10
|
+
* implementation would drift — the same split already used for
|
|
11
|
+
* `buildEvalPaths` / `evalPathCovers` and the redaction path parser. Before this
|
|
12
|
+
* there were three one-hop lookups (the analysis registry's editor helpers, the
|
|
13
|
+
* template-body `inputs` typing, the step-context definition fallback) and a
|
|
14
|
+
* runtime that consulted only an explicitly-passed type ref, so static analysis
|
|
15
|
+
* and dispatch could disagree about the very contract they were both checking.
|
|
16
|
+
*/
|
|
17
|
+
/** Where a resolved contract was declared. Instance-level declarations let one
|
|
18
|
+
* call site narrow a kind's contract (`JS.Script` does this); kind-level ones
|
|
19
|
+
* are the kind's own signature. */
|
|
20
|
+
export type ContractOrigin = "instance" | "kind";
|
|
21
|
+
export interface ResolvedContract {
|
|
22
|
+
/** The JSON Schema a value is validated against. */
|
|
23
|
+
schema: Record<string, any>;
|
|
24
|
+
origin: ContractOrigin;
|
|
25
|
+
/** The definition that declared it, when `origin` is `"kind"` — the scope its
|
|
26
|
+
* named type references resolved in, and what a diagnostic should name. */
|
|
27
|
+
declaredBy?: ResourceDefinition;
|
|
28
|
+
}
|
|
29
|
+
export interface ContractScope {
|
|
30
|
+
/** Resolves a kind to its definition. Must be scoped to the module that
|
|
31
|
+
* DECLARED the definition being walked — `extends` aliases are lexical, so a
|
|
32
|
+
* chain crossing module boundaries re-scopes at each hop. */
|
|
33
|
+
resolveDefinition: DefResolver;
|
|
34
|
+
/**
|
|
35
|
+
* Manifests a named `telo#Type` reference resolves against, given the
|
|
36
|
+
* definition that DECLARED the type field.
|
|
37
|
+
*
|
|
38
|
+
* The parameter exists for a caller that keeps types per module. The analyzer
|
|
39
|
+
* does not: it works from one flattened list where names are already unique
|
|
40
|
+
* per module, so it ignores the argument and returns that list. A caller
|
|
41
|
+
* holding several scopes uses it to avoid resolving a bare name against the
|
|
42
|
+
* wrong module's type of the same name.
|
|
43
|
+
*/
|
|
44
|
+
typeManifestsFor(def: ResourceDefinition | undefined): Record<string, any>[];
|
|
45
|
+
}
|
|
46
|
+
/** The fallback for a target that declares no contract: anything goes. Not
|
|
47
|
+
* `additionalProperties: false` — an undeclared contract is an absence of a
|
|
48
|
+
* claim, not a claim of emptiness. */
|
|
49
|
+
export declare const PERMISSIVE_CONTRACT: Record<string, any>;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a dispatch target's contract, layering:
|
|
52
|
+
* 1. the **instance manifest's** own `inputType:` / `outputType:` — per-call-site
|
|
53
|
+
* narrowing, opted into simply by the kind declaring the property;
|
|
54
|
+
* 2. the **kind's** contract, resolved to the nearest declaration along
|
|
55
|
+
* `extends` (see {@link effectiveContractField} — nearest wins, no merge);
|
|
56
|
+
* 3. undefined — the caller decides whether that means permissive.
|
|
57
|
+
*
|
|
58
|
+
* Returns undefined rather than {@link PERMISSIVE_CONTRACT} so a caller can tell
|
|
59
|
+
* "declared nothing" from "declared anything", which the wiring rule and the
|
|
60
|
+
* `run()` guard both need.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveContract(direction: ContractDirection, manifest: Record<string, any> | undefined, definition: ResourceDefinition | undefined, scope: ContractScope): ResolvedContract | undefined;
|
|
63
|
+
/** {@link resolveContract}, falling back to {@link PERMISSIVE_CONTRACT}. For
|
|
64
|
+
* callers that need a schema unconditionally (CEL context typing), as opposed
|
|
65
|
+
* to needing to know whether one was declared. */
|
|
66
|
+
export declare function resolveContractSchema(direction: ContractDirection, manifest: Record<string, any> | undefined, definition: ResourceDefinition | undefined, scope: ContractScope): Record<string, any>;
|
|
67
|
+
/**
|
|
68
|
+
* A copy of `schema` with every `x-telo-stream`-marked property removed from
|
|
69
|
+
* `properties` and `required`, for validating a runtime value against.
|
|
70
|
+
*
|
|
71
|
+
* Streams travel in BOTH directions — `Codec.Encoder` marks `input` on its
|
|
72
|
+
* `inputType` and lists it in `required`, and `Record.Stream`, `Ai`, `Tar` and
|
|
73
|
+
* `Console` do the same — so a one-directional skip would walk a live `Stream`
|
|
74
|
+
* with AJV on the hottest path in the runtime. That is the same defect as
|
|
75
|
+
* `stripCompiledValues` walking a live `ResourceInstance` in a ref slot: a live
|
|
76
|
+
* object in a declared slot is not data to be traversed. The annotation already
|
|
77
|
+
* marks exactly the properties to leave alone.
|
|
78
|
+
*
|
|
79
|
+
* Structural (returns a new object, never mutates), and shared so the analyzer
|
|
80
|
+
* and the kernel exempt the same set.
|
|
81
|
+
*/
|
|
82
|
+
export declare function withStreamPropertiesSkipped(schema: Record<string, any>,
|
|
83
|
+
/** Resolves a `$ref` to the schema it names. Required to see through the
|
|
84
|
+
* reference form the runtime deliberately KEEPS intact for its validator: a
|
|
85
|
+
* contract written as `{ $ref: "telo:mod/Type" }` has none of its own
|
|
86
|
+
* properties, so a walk that cannot follow the reference exempts nothing and
|
|
87
|
+
* the stream is traversed after all. */
|
|
88
|
+
resolveRef?: (ref: string) => Record<string, any> | undefined): Record<string, any>;
|
|
89
|
+
/** Every property path in `schema` that can receive a `default:` — the paths a
|
|
90
|
+
* defaults pass may write to, and therefore exactly how far the caller's inputs
|
|
91
|
+
* must be copied before AJV's `useDefaults` runs. A flat shallow copy would not
|
|
92
|
+
* do: `useDefaults` writes at every level it finds a default, so a nested
|
|
93
|
+
* default would mutate the structure the caller still holds. Bounded by the
|
|
94
|
+
* schema's defaults rather than by the size of the payload. */
|
|
95
|
+
export declare function defaultBearingPaths(schema: Record<string, any>,
|
|
96
|
+
/** See {@link withStreamPropertiesSkipped} — a contract kept in `$ref` form
|
|
97
|
+
* declares its defaults behind the reference, and a walk that cannot follow
|
|
98
|
+
* it would report none, leaving the caller's data shared where a fill lands. */
|
|
99
|
+
resolveRef?: (ref: string) => Record<string, any> | undefined): string[][];
|
|
100
|
+
//# sourceMappingURL=invocation-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocation-contract.d.ts","sourceRoot":"","sources":["../src/invocation-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAEjB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AAEH;;oCAEoC;AACpC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB;gFAC4E;IAC5E,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;kEAE8D;IAC9D,iBAAiB,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CAC9E;AAED;;uCAEuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAGnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,gBAAgB,GAAG,SAAS,CAa9B;AAED;;mDAEmD;AACnD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;;;yCAIyC;AACzC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAiGD;;;;;gEAKgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;iFAEiF;AACjF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,EAAE,EAAE,CA+BZ"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { contractDeclarer, effectiveContractField, } from "./extends-resolution.js";
|
|
2
|
+
import { resolveTypeFieldToSchema } from "./validate-cel-context.js";
|
|
3
|
+
/** The fallback for a target that declares no contract: anything goes. Not
|
|
4
|
+
* `additionalProperties: false` — an undeclared contract is an absence of a
|
|
5
|
+
* claim, not a claim of emptiness. */
|
|
6
|
+
export const PERMISSIVE_CONTRACT = {
|
|
7
|
+
type: "object",
|
|
8
|
+
additionalProperties: true,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a dispatch target's contract, layering:
|
|
12
|
+
* 1. the **instance manifest's** own `inputType:` / `outputType:` — per-call-site
|
|
13
|
+
* narrowing, opted into simply by the kind declaring the property;
|
|
14
|
+
* 2. the **kind's** contract, resolved to the nearest declaration along
|
|
15
|
+
* `extends` (see {@link effectiveContractField} — nearest wins, no merge);
|
|
16
|
+
* 3. undefined — the caller decides whether that means permissive.
|
|
17
|
+
*
|
|
18
|
+
* Returns undefined rather than {@link PERMISSIVE_CONTRACT} so a caller can tell
|
|
19
|
+
* "declared nothing" from "declared anything", which the wiring rule and the
|
|
20
|
+
* `run()` guard both need.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveContract(direction, manifest, definition, scope) {
|
|
23
|
+
const own = manifest?.[direction];
|
|
24
|
+
if (own !== undefined && own !== null) {
|
|
25
|
+
const schema = resolveTypeFieldToSchema(own, scope.typeManifestsFor(definition));
|
|
26
|
+
if (schema)
|
|
27
|
+
return { schema, origin: "instance" };
|
|
28
|
+
}
|
|
29
|
+
const declared = effectiveContractField(definition, scope.resolveDefinition, direction);
|
|
30
|
+
if (declared === undefined || declared === null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const declarer = contractDeclarer(definition, scope.resolveDefinition, direction);
|
|
33
|
+
const schema = resolveTypeFieldToSchema(declared, scope.typeManifestsFor(declarer));
|
|
34
|
+
if (!schema)
|
|
35
|
+
return undefined;
|
|
36
|
+
return { schema, origin: "kind", declaredBy: declarer };
|
|
37
|
+
}
|
|
38
|
+
/** {@link resolveContract}, falling back to {@link PERMISSIVE_CONTRACT}. For
|
|
39
|
+
* callers that need a schema unconditionally (CEL context typing), as opposed
|
|
40
|
+
* to needing to know whether one was declared. */
|
|
41
|
+
export function resolveContractSchema(direction, manifest, definition, scope) {
|
|
42
|
+
return resolveContract(direction, manifest, definition, scope)?.schema ?? PERMISSIVE_CONTRACT;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A copy of `schema` with every `x-telo-stream`-marked property removed from
|
|
46
|
+
* `properties` and `required`, for validating a runtime value against.
|
|
47
|
+
*
|
|
48
|
+
* Streams travel in BOTH directions — `Codec.Encoder` marks `input` on its
|
|
49
|
+
* `inputType` and lists it in `required`, and `Record.Stream`, `Ai`, `Tar` and
|
|
50
|
+
* `Console` do the same — so a one-directional skip would walk a live `Stream`
|
|
51
|
+
* with AJV on the hottest path in the runtime. That is the same defect as
|
|
52
|
+
* `stripCompiledValues` walking a live `ResourceInstance` in a ref slot: a live
|
|
53
|
+
* object in a declared slot is not data to be traversed. The annotation already
|
|
54
|
+
* marks exactly the properties to leave alone.
|
|
55
|
+
*
|
|
56
|
+
* Structural (returns a new object, never mutates), and shared so the analyzer
|
|
57
|
+
* and the kernel exempt the same set.
|
|
58
|
+
*/
|
|
59
|
+
export function withStreamPropertiesSkipped(schema,
|
|
60
|
+
/** Resolves a `$ref` to the schema it names. Required to see through the
|
|
61
|
+
* reference form the runtime deliberately KEEPS intact for its validator: a
|
|
62
|
+
* contract written as `{ $ref: "telo:mod/Type" }` has none of its own
|
|
63
|
+
* properties, so a walk that cannot follow the reference exempts nothing and
|
|
64
|
+
* the stream is traversed after all. */
|
|
65
|
+
resolveRef) {
|
|
66
|
+
return stripStreams(schema, [], resolveRef);
|
|
67
|
+
}
|
|
68
|
+
function stripStreams(node,
|
|
69
|
+
// A PATH-scoped guard, not a global memo: a schema object reached twice from
|
|
70
|
+
// different parents must be stripped twice (a global `seen` would hand the
|
|
71
|
+
// second parent the unstripped original), while a cycle must still terminate.
|
|
72
|
+
path, resolveRef) {
|
|
73
|
+
if (Array.isArray(node)) {
|
|
74
|
+
let changed = false;
|
|
75
|
+
const items = node.map((item) => {
|
|
76
|
+
const next = stripStreams(item, path, resolveRef);
|
|
77
|
+
if (next !== item)
|
|
78
|
+
changed = true;
|
|
79
|
+
return next;
|
|
80
|
+
});
|
|
81
|
+
return changed ? items : node;
|
|
82
|
+
}
|
|
83
|
+
if (!node || typeof node !== "object")
|
|
84
|
+
return node;
|
|
85
|
+
let schema = node;
|
|
86
|
+
if (path.includes(schema))
|
|
87
|
+
return schema;
|
|
88
|
+
// Follow a whole-document reference to SEE the annotations behind it, but
|
|
89
|
+
// return the original node when nothing behind it was stripped. Substituting
|
|
90
|
+
// the resolved target unconditionally would break schema identity — the
|
|
91
|
+
// compiled-validator cache is keyed on it — and would move the target out of
|
|
92
|
+
// the document whose `$defs` its own internal `$ref`s resolve against.
|
|
93
|
+
if (resolveRef && typeof schema.$ref === "string") {
|
|
94
|
+
const target = resolveRef(schema.$ref);
|
|
95
|
+
if (target && !path.includes(target)) {
|
|
96
|
+
const stripped = stripStreams(target, [...path, schema], resolveRef);
|
|
97
|
+
if (stripped === target)
|
|
98
|
+
return node;
|
|
99
|
+
const { $ref: _ref, ...siblings } = schema;
|
|
100
|
+
return Object.keys(siblings).length > 0 ? { ...stripped, ...siblings } : stripped;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const here = [...path, schema];
|
|
104
|
+
let out = schema;
|
|
105
|
+
const properties = schema.properties;
|
|
106
|
+
if (properties) {
|
|
107
|
+
// A stream can be contributed by an `allOf` branch too (how type inheritance
|
|
108
|
+
// is expressed before the branches are merged), so the marked set is read
|
|
109
|
+
// from the folded view while the removal is applied here.
|
|
110
|
+
const streamed = Object.keys(properties).filter((key) => properties[key]?.["x-telo-stream"]);
|
|
111
|
+
if (streamed.length > 0) {
|
|
112
|
+
const kept = {};
|
|
113
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
114
|
+
if (!streamed.includes(key))
|
|
115
|
+
kept[key] = value;
|
|
116
|
+
}
|
|
117
|
+
// The key stays DECLARED but unconstrained, rather than being deleted.
|
|
118
|
+
// Deleting it would force `additionalProperties: false` open, and a closed
|
|
119
|
+
// contract would stop rejecting unknown keys the moment it grew a stream —
|
|
120
|
+
// trading one exemption for a hole across the whole shape.
|
|
121
|
+
for (const key of streamed)
|
|
122
|
+
kept[key] = {};
|
|
123
|
+
out = { ...schema, properties: kept };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Recurse: a stream one level down (an item, a branch, a nested object) is as
|
|
127
|
+
// live as one at the root, and walking it with AJV is the same defect.
|
|
128
|
+
//
|
|
129
|
+
// `properties` and `$defs` are MAPS of schemas, not schemas — descending into
|
|
130
|
+
// them as if they were would visit nothing, since a map has none of the
|
|
131
|
+
// keywords this walk looks for.
|
|
132
|
+
let changed = out !== schema;
|
|
133
|
+
const result = { ...out };
|
|
134
|
+
for (const key of ["properties", "$defs"]) {
|
|
135
|
+
const map = out[key];
|
|
136
|
+
if (!map || typeof map !== "object")
|
|
137
|
+
continue;
|
|
138
|
+
let mapChanged = false;
|
|
139
|
+
const next = {};
|
|
140
|
+
for (const [name, child] of Object.entries(map)) {
|
|
141
|
+
const stripped = stripStreams(child, here, resolveRef);
|
|
142
|
+
if (stripped !== child)
|
|
143
|
+
mapChanged = true;
|
|
144
|
+
next[name] = stripped;
|
|
145
|
+
}
|
|
146
|
+
if (mapChanged) {
|
|
147
|
+
result[key] = next;
|
|
148
|
+
changed = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (const key of ["items", "allOf", "anyOf", "oneOf"]) {
|
|
152
|
+
const child = out[key];
|
|
153
|
+
if (child === undefined)
|
|
154
|
+
continue;
|
|
155
|
+
const next = stripStreams(child, here, resolveRef);
|
|
156
|
+
if (next !== child) {
|
|
157
|
+
result[key] = next;
|
|
158
|
+
changed = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return changed ? result : schema;
|
|
162
|
+
}
|
|
163
|
+
/** Every property path in `schema` that can receive a `default:` — the paths a
|
|
164
|
+
* defaults pass may write to, and therefore exactly how far the caller's inputs
|
|
165
|
+
* must be copied before AJV's `useDefaults` runs. A flat shallow copy would not
|
|
166
|
+
* do: `useDefaults` writes at every level it finds a default, so a nested
|
|
167
|
+
* default would mutate the structure the caller still holds. Bounded by the
|
|
168
|
+
* schema's defaults rather than by the size of the payload. */
|
|
169
|
+
export function defaultBearingPaths(schema,
|
|
170
|
+
/** See {@link withStreamPropertiesSkipped} — a contract kept in `$ref` form
|
|
171
|
+
* declares its defaults behind the reference, and a walk that cannot follow
|
|
172
|
+
* it would report none, leaving the caller's data shared where a fill lands. */
|
|
173
|
+
resolveRef) {
|
|
174
|
+
const out = [];
|
|
175
|
+
// Path-scoped, for the same reason as the stream walk: a shared subschema
|
|
176
|
+
// reached from two parents contributes a path under each.
|
|
177
|
+
const walk = (node, path, chain) => {
|
|
178
|
+
if (!node || typeof node !== "object")
|
|
179
|
+
return;
|
|
180
|
+
let s = node;
|
|
181
|
+
if (chain.includes(s))
|
|
182
|
+
return;
|
|
183
|
+
if (resolveRef && typeof s.$ref === "string") {
|
|
184
|
+
const target = resolveRef(s.$ref);
|
|
185
|
+
if (!target || chain.includes(target))
|
|
186
|
+
return;
|
|
187
|
+
s = { ...target, ...s, $ref: undefined };
|
|
188
|
+
}
|
|
189
|
+
const here = [...chain, node];
|
|
190
|
+
if ("default" in s && path.length > 0)
|
|
191
|
+
out.push(path);
|
|
192
|
+
const properties = s.properties;
|
|
193
|
+
if (properties) {
|
|
194
|
+
for (const [key, child] of Object.entries(properties))
|
|
195
|
+
walk(child, [...path, key], here);
|
|
196
|
+
}
|
|
197
|
+
for (const branch of ["allOf", "anyOf", "oneOf"]) {
|
|
198
|
+
const list = s[branch];
|
|
199
|
+
if (Array.isArray(list))
|
|
200
|
+
for (const child of list)
|
|
201
|
+
walk(child, path, here);
|
|
202
|
+
}
|
|
203
|
+
if (s.items)
|
|
204
|
+
walk(s.items, [...path, "[]"], here);
|
|
205
|
+
};
|
|
206
|
+
walk(schema, [], []);
|
|
207
|
+
return out;
|
|
208
|
+
}
|
package/dist/schema-compat.d.ts
CHANGED
|
@@ -49,14 +49,22 @@ export declare function brandOfSchema(schema: Record<string, any> | undefined):
|
|
|
49
49
|
export declare function jsonSchemaToCelType(schema: Record<string, any> | undefined): string;
|
|
50
50
|
/** Check whether a CEL return type is compatible with a JSON Schema type constraint. */
|
|
51
51
|
export declare function celTypeSatisfiesJsonSchema(celType: string, schema: Record<string, any>): boolean;
|
|
52
|
-
|
|
53
|
-
export declare function celPlaceholderForSchema(schema: Record<string, any>): unknown;
|
|
52
|
+
export declare function celPlaceholderForSchema(rawSchema: Record<string, any>): unknown;
|
|
54
53
|
/** Resolve a `$ref` (only `#/$defs/...` form) against the root schema. */
|
|
55
54
|
export declare function resolveRef(schema: Record<string, any>, root: Record<string, any>): Record<string, any>;
|
|
56
|
-
/** Collect property schemas from top-level `properties` and all `oneOf`/`anyOf` sub-schemas. */
|
|
57
55
|
export declare function collectProperties(schema: Record<string, any>): Record<string, any>;
|
|
58
56
|
/** Deep-clone `data`, replacing every pure CEL template string (`${{ expr }}`) with a
|
|
59
57
|
* schema-appropriate placeholder so AJV can validate non-CEL fields without false positives. */
|
|
60
|
-
export declare function substituteCelFields(data: unknown, schema: Record<string, any>, rootSchema?: Record<string, any
|
|
58
|
+
export declare function substituteCelFields(data: unknown, schema: Record<string, any>, rootSchema?: Record<string, any>,
|
|
59
|
+
/** Called with the dotted path of every value replaced by a placeholder.
|
|
60
|
+
*
|
|
61
|
+
* A placeholder is a stand-in for something only known at runtime, so its
|
|
62
|
+
* VALUE says nothing: a caller that judges constraints at these paths reports
|
|
63
|
+
* against a value no author wrote. Some constraints cannot be satisfied by
|
|
64
|
+
* construction at all (`pattern`, `format`, a `oneOf` of unrelated shapes),
|
|
65
|
+
* so making every placeholder acceptable is not achievable in general —
|
|
66
|
+
* knowing where not to look is. Structural findings survive because they are
|
|
67
|
+
* located at the CONTAINER, not at the substituted leaf. */
|
|
68
|
+
onSubstitute?: (path: string) => void, path?: string): unknown;
|
|
61
69
|
export {};
|
|
62
70
|
//# sourceMappingURL=schema-compat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,GAAG,KAA0C,CAAC;AAEpD;;;;;;;mCAOmC;AACnC,wBAAgB,SAAS,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,CAOpD;AAKD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;oEAEoE;AACpE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,mBAAmB,CAIrB;AAiDD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAelD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGxE;AAuBD,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAaD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,EAAE,CA2B/F;AAED;qFACqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ7E;AAED;;;;6DAI6D;AAC7D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAsBjC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzF;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CAyBnF;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAiChG;
|
|
1
|
+
{"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,GAAG,KAA0C,CAAC;AAEpD;;;;;;;mCAOmC;AACnC,wBAAgB,SAAS,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,CAOpD;AAKD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;oEAEoE;AACpE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,mBAAmB,CAIrB;AAiDD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAelD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGxE;AAuBD,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAaD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,EAAE,CA2B/F;AAED;qFACqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ7E;AAED;;;;6DAI6D;AAC7D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAsBjC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzF;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CAyBnF;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAiChG;AAkED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAqC/E;AAqBD,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOtG;AAyDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAwBlF;AAED;iGACiG;AACjG,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAChC;;;;;;;;6DAQ6D;AAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACrC,IAAI,SAAK,GACR,OAAO,CAgDT"}
|