@telorun/analyzer 0.65.0 → 0.66.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/analyzer.d.ts +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +157 -63
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +7 -1
- package/dist/cel-environment.d.ts +12 -0
- package/dist/cel-environment.d.ts.map +1 -1
- package/dist/cel-environment.js +35 -19
- package/dist/cel-scope.d.ts.map +1 -1
- package/dist/cel-scope.js +24 -4
- package/dist/definition-registry.d.ts +24 -0
- package/dist/definition-registry.d.ts.map +1 -1
- package/dist/definition-registry.js +41 -0
- package/dist/eval-paths.d.ts +68 -0
- package/dist/eval-paths.d.ts.map +1 -1
- package/dist/eval-paths.js +138 -0
- package/dist/flatten-for-analyzer.d.ts +1 -1
- package/dist/flatten-for-analyzer.js +1 -1
- package/dist/import-resolution-diagnostics.d.ts +1 -1
- package/dist/import-resolution-diagnostics.js +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/manifest-visitor.d.ts.map +1 -1
- package/dist/manifest-visitor.js +8 -1
- package/dist/migrations/entries/index.d.ts.map +1 -1
- package/dist/migrations/entries/index.js +2 -0
- package/dist/migrations/entries/schema-prepare-bucket.json +27 -0
- package/dist/peer-binding.d.ts +232 -0
- package/dist/peer-binding.d.ts.map +1 -0
- package/dist/peer-binding.js +418 -0
- package/dist/ref-slot.d.ts +13 -0
- package/dist/ref-slot.d.ts.map +1 -1
- package/dist/ref-slot.js +26 -0
- package/dist/reference-field-map.d.ts +28 -0
- package/dist/reference-field-map.d.ts.map +1 -1
- package/dist/reference-field-map.js +25 -0
- package/dist/referrer-rule.d.ts +17 -0
- package/dist/referrer-rule.d.ts.map +1 -1
- package/dist/referrer-rule.js +4 -1
- package/dist/release/index.d.ts +1 -1
- package/dist/release/index.js +1 -1
- package/dist/resource-rule.d.ts +40 -27
- package/dist/resource-rule.d.ts.map +1 -1
- package/dist/resource-rule.js +61 -7
- package/dist/rule-condition.d.ts +11 -0
- package/dist/rule-condition.d.ts.map +1 -1
- package/dist/rule-condition.js +13 -0
- package/dist/schema-projection.d.ts +106 -4
- package/dist/schema-projection.d.ts.map +1 -1
- package/dist/schema-projection.js +206 -18
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/validate-cel-context.d.ts +1 -17
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +5 -70
- package/dist/validate-reference-forms.d.ts +10 -0
- package/dist/validate-reference-forms.d.ts.map +1 -1
- package/dist/validate-reference-forms.js +23 -0
- package/dist/validate-references.d.ts.map +1 -1
- package/dist/validate-references.js +9 -2
- package/dist/validate-referrer-rules.d.ts +38 -4
- package/dist/validate-referrer-rules.d.ts.map +1 -1
- package/dist/validate-referrer-rules.js +139 -31
- package/dist/validate-resource-rules.d.ts +11 -2
- package/dist/validate-resource-rules.d.ts.map +1 -1
- package/dist/validate-resource-rules.js +18 -12
- package/dist/validate-schema-projection.d.ts.map +1 -1
- package/dist/validate-schema-projection.js +33 -2
- package/dist/with-synthetic-positions.d.ts +1 -1
- package/dist/with-synthetic-positions.js +1 -1
- package/package.json +3 -3
- package/src/analyzer.ts +191 -68
- package/src/call-graph.ts +7 -1
- package/src/cel-environment.ts +48 -19
- package/src/cel-scope.ts +24 -6
- package/src/definition-registry.ts +42 -0
- package/src/eval-paths.ts +152 -0
- package/src/flatten-for-analyzer.ts +1 -1
- package/src/import-resolution-diagnostics.ts +1 -1
- package/src/index.ts +45 -4
- package/src/manifest-visitor.ts +8 -1
- package/src/migrations/entries/index.ts +2 -0
- package/src/migrations/entries/schema-prepare-bucket.json +27 -0
- package/src/peer-binding.ts +641 -0
- package/src/ref-slot.ts +36 -0
- package/src/reference-field-map.ts +42 -0
- package/src/referrer-rule.ts +20 -1
- package/src/release/index.ts +1 -1
- package/src/resource-rule.ts +69 -7
- package/src/rule-condition.ts +15 -0
- package/src/schema-projection.ts +283 -20
- package/src/telo-version.ts +1 -1
- package/src/validate-cel-context.ts +6 -71
- package/src/validate-reference-forms.ts +22 -0
- package/src/validate-references.ts +15 -2
- package/src/validate-referrer-rules.ts +215 -28
- package/src/validate-resource-rules.ts +26 -12
- package/src/validate-schema-projection.ts +50 -1
- package/src/with-synthetic-positions.ts +1 -1
package/dist/ref-slot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-slot.d.ts","sourceRoot":"","sources":["../src/ref-slot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;mDAEmD;AACnD,MAAM,MAAM,MAAM;AAChB,sEAAsE;AACpE,QAAQ;AACV,oEAAoE;GAClE,YAAY;AACd,gEAAgE;GAC9D,MAAM;AACR;oCACoC;GAClC,UAAU;AACZ;8EAC8E;GAC5E,iBAAiB;AACnB;kDACkD;GAChD,kBAAkB,CAAC;AAEvB,eAAO,MAAM,QAAQ,EAAE,SAAS,MAAM,EAOrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAExD;AAED;qCACqC;AACrC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;0DAE0D;AAC1D,MAAM,WAAW,WAAW;IAC1B;;8DAE0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,WAAW,OAAO;IACtB;;;yDAGqD;IACrD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;6DAIyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;;0CAEsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;6DACyD;IACzD,MAAM,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ref-slot.d.ts","sourceRoot":"","sources":["../src/ref-slot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;mDAEmD;AACnD,MAAM,MAAM,MAAM;AAChB,sEAAsE;AACpE,QAAQ;AACV,oEAAoE;GAClE,YAAY;AACd,gEAAgE;GAC9D,MAAM;AACR;oCACoC;GAClC,UAAU;AACZ;8EAC8E;GAC5E,iBAAiB;AACnB;kDACkD;GAChD,kBAAkB,CAAC;AAEvB,eAAO,MAAM,QAAQ,EAAE,SAAS,MAAM,EAOrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAExD;AAED;qCACqC;AACrC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;0DAE0D;AAC1D,MAAM,WAAW,WAAW;IAC1B;;8DAE0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AAED,4EAA4E;AAC5E,MAAM,WAAW,OAAO;IACtB;;;yDAGqD;IACrD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;6DAIyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;;0CAEsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;6DACyD;IACzD,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;+BAW2B;IAC3B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AAED;yDACyD;AACzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAOpD;AAED;kDACkD;AAClD,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAErD;AAiFD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CA8BtF;AAED;+DAC+D;AAC/D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,CAExE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACxC,IAAI,CAiBN"}
|
package/dist/ref-slot.js
CHANGED
|
@@ -121,6 +121,31 @@ function annotationNodes(node) {
|
|
|
121
121
|
}
|
|
122
122
|
return out;
|
|
123
123
|
}
|
|
124
|
+
/** The branches of a value-or-reference union — see {@link RefSlot.valueBranches}.
|
|
125
|
+
* Empty unless the node delegates its reference constraint to a branch. */
|
|
126
|
+
function valueBranchesOf(node) {
|
|
127
|
+
if (!node || typeof node !== "object")
|
|
128
|
+
return [];
|
|
129
|
+
if (node["x-telo-ref"] !== undefined)
|
|
130
|
+
return [];
|
|
131
|
+
const out = [];
|
|
132
|
+
for (const key of ["anyOf", "oneOf"]) {
|
|
133
|
+
const branches = node[key];
|
|
134
|
+
if (!Array.isArray(branches))
|
|
135
|
+
continue;
|
|
136
|
+
const carriesRef = branches.some((b) => b && typeof b === "object" && b["x-telo-ref"] !== undefined);
|
|
137
|
+
if (!carriesRef)
|
|
138
|
+
continue;
|
|
139
|
+
for (const branch of branches) {
|
|
140
|
+
if (!branch || typeof branch !== "object")
|
|
141
|
+
continue;
|
|
142
|
+
if (branch["x-telo-ref"] !== undefined)
|
|
143
|
+
continue;
|
|
144
|
+
out.push(branch);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
124
149
|
/**
|
|
125
150
|
* Reads a schema node as a reference slot, or `undefined` when it declares none.
|
|
126
151
|
*
|
|
@@ -160,6 +185,7 @@ export function readRefSlot(node) {
|
|
|
160
185
|
kinds,
|
|
161
186
|
uses: [...uses],
|
|
162
187
|
inline: node?.["x-telo-inline"] === true || nodes.some((n) => n["x-telo-inline"] === true),
|
|
188
|
+
valueBranches: valueBranchesOf(node),
|
|
163
189
|
};
|
|
164
190
|
if (useCases)
|
|
165
191
|
slot.useCases = useCases;
|
|
@@ -17,6 +17,10 @@ export interface RefFieldEntry {
|
|
|
17
17
|
inputs?: string;
|
|
18
18
|
/** True when the field path traversed through at least one array (path contains "[]"). */
|
|
19
19
|
isArray: boolean;
|
|
20
|
+
/** The slot's non-reference branches, when the reference constraint is a
|
|
21
|
+
* branch of a union — see {@link RefSlot.valueBranches}. A value satisfying
|
|
22
|
+
* one of these is a value, not a malformed reference. */
|
|
23
|
+
valueBranches?: Record<string, any>[];
|
|
20
24
|
/** x-telo-context schema declared on this ref slot, if any. Describes the CEL invocation
|
|
21
25
|
* context available to resources placed in this slot. */
|
|
22
26
|
context?: Record<string, any>;
|
|
@@ -52,6 +56,30 @@ export type FieldMapEntry = RefFieldEntry | ScopeFieldEntry | SchemaFromFieldEnt
|
|
|
52
56
|
* Paths use dot notation; array traversal is denoted by `[]` (e.g. "steps[].invoke"). */
|
|
53
57
|
export type ReferenceFieldMap = Map<string, FieldMapEntry>;
|
|
54
58
|
export declare function isRefEntry(entry: FieldMapEntry): entry is RefFieldEntry;
|
|
59
|
+
/** The half of a definition registry this question needs — structural, so the
|
|
60
|
+
* field map keeps depending on nothing. */
|
|
61
|
+
export interface ValueBranchValidator {
|
|
62
|
+
schemaCompileError(schema: Record<string, any>): string | undefined;
|
|
63
|
+
validateWithRefs(data: unknown, schema: Record<string, any>): string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* True when a value at a ref slot satisfies one of the slot's VALUE branches —
|
|
67
|
+
* a storage class beside a `!ref`, so it is a value and not a malformed
|
|
68
|
+
* reference.
|
|
69
|
+
*
|
|
70
|
+
* One implementation, because BOTH reference passes have to narrow the same way:
|
|
71
|
+
* `validateReferenceForms` would otherwise call it a removed string reference,
|
|
72
|
+
* and `validateReferences` a reference missing `kind` and `name`. Two copies of
|
|
73
|
+
* the rule would eventually disagree about which of the two reported a value.
|
|
74
|
+
*
|
|
75
|
+
* A branch AJV cannot COMPILE is not a branch the value satisfies.
|
|
76
|
+
* `validateWithRefs` returns no issues for one — it swallows the compile failure
|
|
77
|
+
* by design, so one bad schema does not abort the pass — and reading that as
|
|
78
|
+
* "no issues, therefore a value" would switch the reference-form rule off for
|
|
79
|
+
* the slot silently. The uncompilable schema is reported on its own definition
|
|
80
|
+
* by `schemaCompileError`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function satisfiesValueBranch(value: unknown, branches: readonly Record<string, any>[] | undefined, registry: ValueBranchValidator): boolean;
|
|
55
83
|
export declare function isScopeEntry(entry: FieldMapEntry): entry is ScopeFieldEntry;
|
|
56
84
|
export declare function isSchemaFromEntry(entry: FieldMapEntry): entry is SchemaFromFieldEntry;
|
|
57
85
|
/** Keys that a named reference object may have. Values beyond these indicate an inline resource. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,WAAW,EAAe,MAAM,eAAe,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAElE,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B;;6EAEyE;IACzE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;0DACsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,OAAO,CAAC;IACjB;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;;;;;;;;;;kCAU8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B;2CACuC;IACvC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAED;8CAC8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC;;qFAEiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEnF;0FAC0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,aAAa,CAEvE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,eAAe,CAE3E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,oBAAoB,CAErF;AAED,oGAAoG;AACpG,eAAO,MAAM,cAAc,aAAwC,CAAC;AAEpE;;;;;;;;;2EAS2E;AAC3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAItE;AAED;;;;sEAIsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;wDAUwD;AACxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAoCpF;AAED;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAExE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAQrF;AAED;;6CAE6C;AAC7C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAE/D;AAED;;;8CAG8C;AAC9C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAInB"}
|
|
1
|
+
{"version":3,"file":"reference-field-map.d.ts","sourceRoot":"","sources":["../src/reference-field-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,WAAW,EAAe,MAAM,eAAe,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAElE,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B;;6EAEyE;IACzE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;0DACsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,OAAO,CAAC;IACjB;;8DAE0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;IACtC;8DAC0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;;;;;;;;;;kCAU8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B;2CACuC;IACvC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAED;8CAC8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC;;qFAEiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEnF;0FAC0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,aAAa,CAEvE;AAED;4CAC4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IACpE,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC;CACxE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,SAAS,EACpD,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAOT;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,eAAe,CAE3E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,IAAI,oBAAoB,CAErF;AAED,oGAAoG;AACpG,eAAO,MAAM,cAAc,aAAwC,CAAC;AAEpE;;;;;;;;;2EAS2E;AAC3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAItE;AAED;;;;sEAIsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;wDAUwD;AACxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAoCpF;AAED;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAExE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAQrF;AAED;;6CAE6C;AAC7C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAE/D;AAED;;;8CAG8C;AAC9C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAInB"}
|
|
@@ -3,6 +3,29 @@ export { readRefSlot, isRefSlot, hasDeclaredUse } from "./ref-slot.js";
|
|
|
3
3
|
export function isRefEntry(entry) {
|
|
4
4
|
return "refs" in entry;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* True when a value at a ref slot satisfies one of the slot's VALUE branches —
|
|
8
|
+
* a storage class beside a `!ref`, so it is a value and not a malformed
|
|
9
|
+
* reference.
|
|
10
|
+
*
|
|
11
|
+
* One implementation, because BOTH reference passes have to narrow the same way:
|
|
12
|
+
* `validateReferenceForms` would otherwise call it a removed string reference,
|
|
13
|
+
* and `validateReferences` a reference missing `kind` and `name`. Two copies of
|
|
14
|
+
* the rule would eventually disagree about which of the two reported a value.
|
|
15
|
+
*
|
|
16
|
+
* A branch AJV cannot COMPILE is not a branch the value satisfies.
|
|
17
|
+
* `validateWithRefs` returns no issues for one — it swallows the compile failure
|
|
18
|
+
* by design, so one bad schema does not abort the pass — and reading that as
|
|
19
|
+
* "no issues, therefore a value" would switch the reference-form rule off for
|
|
20
|
+
* the slot silently. The uncompilable schema is reported on its own definition
|
|
21
|
+
* by `schemaCompileError`.
|
|
22
|
+
*/
|
|
23
|
+
export function satisfiesValueBranch(value, branches, registry) {
|
|
24
|
+
if (!branches?.length)
|
|
25
|
+
return false;
|
|
26
|
+
return branches.some((branch) => registry.schemaCompileError(branch) === undefined &&
|
|
27
|
+
registry.validateWithRefs(value, branch).length === 0);
|
|
28
|
+
}
|
|
6
29
|
export function isScopeEntry(entry) {
|
|
7
30
|
return "scope" in entry;
|
|
8
31
|
}
|
|
@@ -155,6 +178,8 @@ function traverseNode(node, path, map, root, visitedRefs = new Set()) {
|
|
|
155
178
|
entry.useCases = slot.useCases;
|
|
156
179
|
if (slot.inputs !== undefined)
|
|
157
180
|
entry.inputs = slot.inputs;
|
|
181
|
+
if (slot.valueBranches.length > 0)
|
|
182
|
+
entry.valueBranches = slot.valueBranches;
|
|
158
183
|
if (node["x-telo-context"])
|
|
159
184
|
entry.context = node["x-telo-context"];
|
|
160
185
|
if (slot.inline)
|
package/dist/referrer-rule.d.ts
CHANGED
|
@@ -35,6 +35,23 @@ export interface ReferrerRule {
|
|
|
35
35
|
* relation the rule is about, so a kind should write it.
|
|
36
36
|
*/
|
|
37
37
|
readonly referrer?: string;
|
|
38
|
+
/**
|
|
39
|
+
* JSON Pointer to a collection OF THE REFERRER to resolve — the binding that
|
|
40
|
+
* lets a rule state a relation between SIBLING declarations, which neither a
|
|
41
|
+
* resource rule (one resource) nor a plain referrer rule (a pair joined by one
|
|
42
|
+
* reference) can reach.
|
|
43
|
+
*
|
|
44
|
+
* Declaring it binds `peers` (the collection's OTHER entries) and `entry` (my
|
|
45
|
+
* own), and makes the rule evaluate once per entry rather than once per
|
|
46
|
+
* referrer: a rule reading `entry` is about the entry, and a resource listed
|
|
47
|
+
* twice has two entries to answer for.
|
|
48
|
+
*
|
|
49
|
+
* Entries bind AS WRITTEN with the references *inside them* resolved one level
|
|
50
|
+
* — `p` is the declaration where the entry is a bare `!ref`, `p.mount` is the
|
|
51
|
+
* declaration with `p.prefix` beside it where it is not. Nothing is guessed
|
|
52
|
+
* from the item schema and there is no second pointer to write.
|
|
53
|
+
*/
|
|
54
|
+
readonly peers?: string;
|
|
38
55
|
/** CEL source. TRUE when the rule holds. */
|
|
39
56
|
readonly condition: string;
|
|
40
57
|
/** The rule's own name, carried in `data.rule`. Never a diagnostic code —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"referrer-rule.d.ts","sourceRoot":"","sources":["../src/referrer-rule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAe,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;qEACiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAMD;;6CAE6C;AAC7C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG7D;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"referrer-rule.d.ts","sourceRoot":"","sources":["../src/referrer-rule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAe,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;qEACiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAMD;;6CAE6C;AAC7C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG7D;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,EAAE,CA0BjE;AAED;0EAC0E;AAC1E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAC5C,IAAI,CAQN"}
|
package/dist/referrer-rule.js
CHANGED
|
@@ -47,18 +47,21 @@ export function readReferrerRules(schema) {
|
|
|
47
47
|
if (!isObject(entry))
|
|
48
48
|
return;
|
|
49
49
|
const condition = celSourceOf(entry.condition);
|
|
50
|
-
const { code, message, referrer } = entry;
|
|
50
|
+
const { code, message, referrer, peers } = entry;
|
|
51
51
|
if (!condition || typeof code !== "string" || typeof message !== "string")
|
|
52
52
|
return;
|
|
53
53
|
if (code.length === 0 || message.length === 0)
|
|
54
54
|
return;
|
|
55
55
|
if (referrer !== undefined && typeof referrer !== "string")
|
|
56
56
|
return;
|
|
57
|
+
if (peers !== undefined && typeof peers !== "string")
|
|
58
|
+
return;
|
|
57
59
|
if (entry.severity !== undefined && entry.severity !== "warning" && entry.severity !== "error") {
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
rules.push({
|
|
61
63
|
...(referrer === undefined ? {} : { referrer }),
|
|
64
|
+
...(peers === undefined ? {} : { peers }),
|
|
62
65
|
condition,
|
|
63
66
|
code,
|
|
64
67
|
message,
|
package/dist/release/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The release model: module identity, fragments, the ledger, the edge graph,
|
|
3
3
|
* level propagation and version planning.
|
|
4
4
|
*
|
|
5
|
-
* Browser-safe by construction — pure data in, plan out — so
|
|
5
|
+
* Browser-safe by construction — pure data in, plan out — so telo studio can
|
|
6
6
|
* answer "what does changing this library bump?" from the same model the CLI
|
|
7
7
|
* releases from. Everything Node-shaped (finding the workspace, running the
|
|
8
8
|
* controller builder, building payloads, reading git, writing files) is
|
package/dist/release/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The release model: module identity, fragments, the ledger, the edge graph,
|
|
3
3
|
* level propagation and version planning.
|
|
4
4
|
*
|
|
5
|
-
* Browser-safe by construction — pure data in, plan out — so
|
|
5
|
+
* Browser-safe by construction — pure data in, plan out — so telo studio can
|
|
6
6
|
* answer "what does changing this library bump?" from the same model the CLI
|
|
7
7
|
* releases from. Everything Node-shaped (finding the workspace, running the
|
|
8
8
|
* controller builder, building payloads, reading git, writing files) is
|
package/dist/resource-rule.d.ts
CHANGED
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The single reader for `x-telo-resource-rules` — a kind declaring, as data,
|
|
3
|
-
* relationships between the fields of one resource that JSON Schema cannot
|
|
4
|
-
* state: an index naming a column its table does not declare, a foreign key
|
|
5
|
-
* whose two sides differ in length, a rename whose source is still declared.
|
|
6
|
-
*
|
|
7
|
-
* The predicate is CEL over `self` (the whole resource) and `this` (the element
|
|
8
|
-
* under test), so correlating two collections is a comprehension closure rather
|
|
9
|
-
* than a path language with wildcard bindings to design. `in:` names the
|
|
10
|
-
* collection to iterate and IS the diagnostic anchor: iterating what the pointer
|
|
11
|
-
* names is what makes a reported path exist by construction.
|
|
12
|
-
*
|
|
13
|
-
* Vocabulary borrowed from `Telo.JsonSchema.rules` — `condition` true when the
|
|
14
|
-
* rule HOLDS, the subject bound as `this`, plus `code` and `message` — because
|
|
15
|
-
* two CEL rule vocabularies with opposite polarity is a trap an author falls
|
|
16
|
-
* into once per rule. The two mechanisms stay separate: a `Telo.JsonSchema` rule
|
|
17
|
-
* runs at dispatch against a value, this one at `telo check` against a manifest.
|
|
18
|
-
*
|
|
19
|
-
* Lenient by design, the `ref-slot.ts` precedent: anything unreadable here reads
|
|
20
|
-
* as absent, and `validate-resource-rules.ts` is the strict half that reports it.
|
|
21
|
-
*
|
|
22
|
-
* Browser-safe: no Node built-ins.
|
|
23
|
-
*/
|
|
24
1
|
export declare const RESOURCE_RULES_ANNOTATION = "x-telo-resource-rules";
|
|
25
2
|
export type ResourceRuleSeverity = "error" | "warning";
|
|
26
3
|
export interface ResourceRule {
|
|
@@ -45,6 +22,22 @@ export interface RuleSubject {
|
|
|
45
22
|
/** Present when the collection is a map: the entry's key. */
|
|
46
23
|
readonly key?: string;
|
|
47
24
|
}
|
|
25
|
+
/** The engine of a non-CEL tagged sentinel — a `!ref`, an `!include-*` — or
|
|
26
|
+
* `undefined`. A reference is comparable and never blocks a rule; the other
|
|
27
|
+
* tags hold a value only known once the resource is created, so they do, and
|
|
28
|
+
* the diagnostic has to name the tag rather than claim CEL. */
|
|
29
|
+
export declare function deferredTagOf(value: unknown): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* True when a condition was written with the `!cel` tag.
|
|
32
|
+
*
|
|
33
|
+
* The readers stay lenient and take a bare string — a rule still runs either
|
|
34
|
+
* way. What an untagged condition loses is everything outside evaluation: to the
|
|
35
|
+
* editor's colouring, completion and hover it is a plain string, so a rule author
|
|
36
|
+
* writes CEL with no help and gets none of the checks a `!cel` scalar gets.
|
|
37
|
+
* Losing that silently is exactly what a strict half exists to move earlier, so
|
|
38
|
+
* the tag is reported by the strict halves and never enforced by the readers.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isTaggedCondition(value: unknown): boolean;
|
|
48
41
|
/** A precompiled `!cel` node keeps its author-written text on `source`; a plain
|
|
49
42
|
* string is taken verbatim so a rule reads the same however the loader was
|
|
50
43
|
* configured (a round-trip view runs with `compile` off). */
|
|
@@ -73,15 +66,35 @@ export declare function pointerToPath(pointer: string): string;
|
|
|
73
66
|
* declaration defect the strict half reports, and an empty list would hide it.
|
|
74
67
|
*/
|
|
75
68
|
export declare function resolveRuleSubjects(config: unknown, pointer: string): RuleSubject[] | undefined;
|
|
69
|
+
/** The first leaf a rule cannot compare, and what it is. `what` is a noun
|
|
70
|
+
* phrase the diagnostic quotes verbatim, because "a CEL expression" printed
|
|
71
|
+
* over an `!include-bytes` embed sends its author looking for an expression
|
|
72
|
+
* that is not there. */
|
|
73
|
+
export interface DynamicLeaf {
|
|
74
|
+
readonly path: string;
|
|
75
|
+
readonly what: string;
|
|
76
|
+
}
|
|
77
|
+
/** Classify ONE node, without descending. Exported because a caller that draws
|
|
78
|
+
* its own bound on how far to look (`peer-binding`'s top-level-scalar scan)
|
|
79
|
+
* must classify by the same rule as the recursive walk, or a `!ref` is a
|
|
80
|
+
* reference to one of them and an expression to the other. */
|
|
81
|
+
export declare function dynamicNode(value: unknown, path: string): DynamicLeaf | undefined;
|
|
76
82
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* the subject is skipped — and the
|
|
83
|
+
* The first leaf inside a value whose contents are not known until the resource
|
|
84
|
+
* is created, or `undefined` when every leaf is literal. A rule reading one
|
|
85
|
+
* would be comparing against a placeholder, so the subject is skipped — and the
|
|
86
|
+
* skip is reported, never silent.
|
|
87
|
+
*
|
|
88
|
+
* A `!ref` is NOT one of them. It is a tagged sentinel like `!cel`, and testing
|
|
89
|
+
* `__tagged` alone read every reference as an expression: a column whose `type:`
|
|
90
|
+
* holds a `!ref` switched off every rule touching `self.columns` and reported a
|
|
91
|
+
* CEL expression in a manifest containing none. A reference names a declaration
|
|
92
|
+
* — a value a rule compares perfectly well, and the one peer rules are built on.
|
|
80
93
|
*
|
|
81
94
|
* Stops at nested inline `{ kind }` declarations for the reason every other walk
|
|
82
95
|
* does: that CEL belongs to the nested kind, evaluated in its own scope.
|
|
83
96
|
*/
|
|
84
|
-
export declare function findDynamicLeaf(value: unknown, base?: string):
|
|
97
|
+
export declare function findDynamicLeaf(value: unknown, base?: string): DynamicLeaf | undefined;
|
|
85
98
|
/**
|
|
86
99
|
* The nodes a condition actually READS, resolved against the resource and the
|
|
87
100
|
* element under test — the input to the dynamic-leaf check.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-rule.d.ts","sourceRoot":"","sources":["../src/resource-rule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resource-rule.d.ts","sourceRoot":"","sources":["../src/resource-rule.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B;yEACqE;IACrE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;qEACiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;gEAGgE;AAChE,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;8DAE8D;AAC9D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAI9D;AAED;;6CAE6C;AAC7C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAG7D;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,EAAE,CA0BjE;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAOrE;AAED;;yEAEyE;AACzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAiBvE;AAED;+EAC+E;AAC/E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,GACd,WAAW,EAAE,GAAG,SAAS,CAe3B;AAED;;;yBAGyB;AACzB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;+DAG+D;AAC/D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAKjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAK,GAAG,WAAW,GAAG,SAAS,CAkBlF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE;AACtC;;2BAE2B;AAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,EAAE,CAqBX"}
|
package/dist/resource-rule.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* Browser-safe: no Node built-ins.
|
|
23
23
|
*/
|
|
24
|
+
import { CEL_ENGINE, isRefSentinel, isTaggedSentinel } from "@telorun/templating";
|
|
24
25
|
export const RESOURCE_RULES_ANNOTATION = "x-telo-resource-rules";
|
|
25
26
|
function isObject(value) {
|
|
26
27
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -29,9 +30,43 @@ function isObject(value) {
|
|
|
29
30
|
* Both markers are tested because they are not always both present: a
|
|
30
31
|
* registered definition's schema reaches the analyzer with `call` and
|
|
31
32
|
* `__compiled` dropped, keeping only `__tagged` + `source`. Testing one would
|
|
32
|
-
* make a rule readable on some paths and invisible on others.
|
|
33
|
+
* make a rule readable on some paths and invisible on others.
|
|
34
|
+
*
|
|
35
|
+
* A tagged sentinel of ANOTHER engine is not one. `__tagged` marks every tag
|
|
36
|
+
* the loader parses — `!ref` above all — so testing it alone read a reference
|
|
37
|
+
* as an expression: a column whose `type:` holds a `!ref` skipped every rule
|
|
38
|
+
* that touched `self.columns`, and said "the value holds a CEL expression" about
|
|
39
|
+
* a manifest containing none. A reference names a declaration and is a
|
|
40
|
+
* perfectly comparable value; what a rule cannot compare is a value COMPUTED at
|
|
41
|
+
* create time, which is what this predicate exists to find. */
|
|
33
42
|
function isCelNode(value) {
|
|
34
|
-
|
|
43
|
+
if (!isObject(value))
|
|
44
|
+
return false;
|
|
45
|
+
if (value.__compiled === true)
|
|
46
|
+
return true;
|
|
47
|
+
return value.__tagged === true && value.engine === CEL_ENGINE;
|
|
48
|
+
}
|
|
49
|
+
/** The engine of a non-CEL tagged sentinel — a `!ref`, an `!include-*` — or
|
|
50
|
+
* `undefined`. A reference is comparable and never blocks a rule; the other
|
|
51
|
+
* tags hold a value only known once the resource is created, so they do, and
|
|
52
|
+
* the diagnostic has to name the tag rather than claim CEL. */
|
|
53
|
+
export function deferredTagOf(value) {
|
|
54
|
+
if (!isTaggedSentinel(value) || isRefSentinel(value))
|
|
55
|
+
return undefined;
|
|
56
|
+
return value.engine === CEL_ENGINE ? undefined : value.engine;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* True when a condition was written with the `!cel` tag.
|
|
60
|
+
*
|
|
61
|
+
* The readers stay lenient and take a bare string — a rule still runs either
|
|
62
|
+
* way. What an untagged condition loses is everything outside evaluation: to the
|
|
63
|
+
* editor's colouring, completion and hover it is a plain string, so a rule author
|
|
64
|
+
* writes CEL with no help and gets none of the checks a `!cel` scalar gets.
|
|
65
|
+
* Losing that silently is exactly what a strict half exists to move earlier, so
|
|
66
|
+
* the tag is reported by the strict halves and never enforced by the readers.
|
|
67
|
+
*/
|
|
68
|
+
export function isTaggedCondition(value) {
|
|
69
|
+
return isCelNode(value);
|
|
35
70
|
}
|
|
36
71
|
/** A precompiled `!cel` node keeps its author-written text on `source`; a plain
|
|
37
72
|
* string is taken verbatim so a rule reads the same however the loader was
|
|
@@ -156,18 +191,37 @@ export function resolveRuleSubjects(config, pointer) {
|
|
|
156
191
|
}
|
|
157
192
|
return undefined;
|
|
158
193
|
}
|
|
194
|
+
/** Classify ONE node, without descending. Exported because a caller that draws
|
|
195
|
+
* its own bound on how far to look (`peer-binding`'s top-level-scalar scan)
|
|
196
|
+
* must classify by the same rule as the recursive walk, or a `!ref` is a
|
|
197
|
+
* reference to one of them and an expression to the other. */
|
|
198
|
+
export function dynamicNode(value, path) {
|
|
199
|
+
const at = path || "(value)";
|
|
200
|
+
if (isCelNode(value))
|
|
201
|
+
return { path: at, what: "a CEL expression" };
|
|
202
|
+
const tag = deferredTagOf(value);
|
|
203
|
+
return tag ? { path: at, what: `an !${tag} embed` } : undefined;
|
|
204
|
+
}
|
|
159
205
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* the subject is skipped — and the
|
|
206
|
+
* The first leaf inside a value whose contents are not known until the resource
|
|
207
|
+
* is created, or `undefined` when every leaf is literal. A rule reading one
|
|
208
|
+
* would be comparing against a placeholder, so the subject is skipped — and the
|
|
209
|
+
* skip is reported, never silent.
|
|
210
|
+
*
|
|
211
|
+
* A `!ref` is NOT one of them. It is a tagged sentinel like `!cel`, and testing
|
|
212
|
+
* `__tagged` alone read every reference as an expression: a column whose `type:`
|
|
213
|
+
* holds a `!ref` switched off every rule touching `self.columns` and reported a
|
|
214
|
+
* CEL expression in a manifest containing none. A reference names a declaration
|
|
215
|
+
* — a value a rule compares perfectly well, and the one peer rules are built on.
|
|
163
216
|
*
|
|
164
217
|
* Stops at nested inline `{ kind }` declarations for the reason every other walk
|
|
165
218
|
* does: that CEL belongs to the nested kind, evaluated in its own scope.
|
|
166
219
|
*/
|
|
167
220
|
export function findDynamicLeaf(value, base = "") {
|
|
168
221
|
if (isObject(value)) {
|
|
169
|
-
|
|
170
|
-
|
|
222
|
+
const own = dynamicNode(value, base);
|
|
223
|
+
if (own)
|
|
224
|
+
return own;
|
|
171
225
|
if (typeof value.kind === "string" && base !== "")
|
|
172
226
|
return undefined;
|
|
173
227
|
for (const [key, child] of Object.entries(value)) {
|
package/dist/rule-condition.d.ts
CHANGED
|
@@ -25,6 +25,17 @@ import { buildCelEnvironment } from "@telorun/templating";
|
|
|
25
25
|
* as defective rather than truncating coverage silently.
|
|
26
26
|
*/
|
|
27
27
|
export declare const RULE_BUDGET_MS = 50;
|
|
28
|
+
/**
|
|
29
|
+
* The one message for an untagged `condition:`, shared by every rule family so
|
|
30
|
+
* all of them say the same thing about the same defect.
|
|
31
|
+
*
|
|
32
|
+
* The readers stay lenient and a bare string still runs. What it loses is
|
|
33
|
+
* everything outside evaluation — to the editor's colouring, completion and
|
|
34
|
+
* hover an untagged condition is a plain string, so its author writes CEL with
|
|
35
|
+
* no help and none of the checks a `!cel` scalar gets. Losing that silently is
|
|
36
|
+
* the failure a strict half exists to move earlier.
|
|
37
|
+
*/
|
|
38
|
+
export declare const UNTAGGED_CONDITION: string;
|
|
28
39
|
/** The analyzer's own environment — no host handlers, so every `hostBacked`
|
|
29
40
|
* entry is a throwing stub. Built once; it is stateless. */
|
|
30
41
|
export declare function ruleEnv(): ReturnType<typeof buildCelEnvironment>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-condition.d.ts","sourceRoot":"","sources":["../src/rule-condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAEL,mBAAmB,EAGpB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"rule-condition.d.ts","sourceRoot":"","sources":["../src/rule-condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAEL,mBAAmB,EAGpB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,QAGgD,CAAC;AAQhF;6DAC6D;AAC7D,wBAAgB,OAAO,IAAI,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAGhE;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;CAAE,GAC7F;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAsBvB,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM;AACjB;wEACwE;AACxE,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,YAAY,CAoBd;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB7D"}
|
package/dist/rule-condition.js
CHANGED
|
@@ -25,6 +25,19 @@ import { CEL_FUNCTIONS, buildCelEnvironment, celEngine, extractAccessChains, } f
|
|
|
25
25
|
* as defective rather than truncating coverage silently.
|
|
26
26
|
*/
|
|
27
27
|
export const RULE_BUDGET_MS = 50;
|
|
28
|
+
/**
|
|
29
|
+
* The one message for an untagged `condition:`, shared by every rule family so
|
|
30
|
+
* all of them say the same thing about the same defect.
|
|
31
|
+
*
|
|
32
|
+
* The readers stay lenient and a bare string still runs. What it loses is
|
|
33
|
+
* everything outside evaluation — to the editor's colouring, completion and
|
|
34
|
+
* hover an untagged condition is a plain string, so its author writes CEL with
|
|
35
|
+
* no help and none of the checks a `!cel` scalar gets. Losing that silently is
|
|
36
|
+
* the failure a strict half exists to move earlier.
|
|
37
|
+
*/
|
|
38
|
+
export const UNTAGGED_CONDITION = "Write 'condition' with the !cel tag. The reader is lenient and a bare string still " +
|
|
39
|
+
"runs, but untagged the expression is not CEL to the editor's colouring, completion " +
|
|
40
|
+
"or hover, so a rule silently stops being CEL to every surface but this one.";
|
|
28
41
|
const HOST_BACKED = new Set(CEL_FUNCTIONS.filter((f) => f.hostBacked).map((f) => f.name));
|
|
29
42
|
const NON_DETERMINISTIC = new Set(CEL_FUNCTIONS.filter((f) => !f.deterministic).map((f) => f.name));
|
|
30
43
|
let sharedEnv;
|
|
@@ -47,6 +47,32 @@ export interface SchemaProjection {
|
|
|
47
47
|
readonly nullable?: string;
|
|
48
48
|
/** Entry field that wraps the mapped node in an array. */
|
|
49
49
|
readonly array?: string;
|
|
50
|
+
/**
|
|
51
|
+
* How an entry whose keyed field holds a REFERENCE projects.
|
|
52
|
+
*
|
|
53
|
+
* The map is keyed on the field's VALUE, and a reference is not a key, so a
|
|
54
|
+
* `type:` holding one falls through to this path. It is declared as data by the
|
|
55
|
+
* backend, which is what keeps the analyzer from learning that an enum exists:
|
|
56
|
+
* `from` names the field of the target declaration to read, `keyword` the
|
|
57
|
+
* schema keyword its values become, and `base` / `baseFrom` where the node's
|
|
58
|
+
* own type comes from — a literal for an engine whose named type IS its own
|
|
59
|
+
* base, a field of the target for one that declares a storage class.
|
|
60
|
+
*
|
|
61
|
+
* A backend that declares none projects exactly as it did before.
|
|
62
|
+
*/
|
|
63
|
+
readonly reference?: ProjectionReference;
|
|
64
|
+
}
|
|
65
|
+
/** The reference path of a projection — see {@link SchemaProjection.reference}. */
|
|
66
|
+
export interface ProjectionReference {
|
|
67
|
+
/** Field of the TARGET declaration whose value the keyword takes. */
|
|
68
|
+
readonly from: string;
|
|
69
|
+
/** The JSON Schema keyword those values become (`enum`). */
|
|
70
|
+
readonly keyword: string;
|
|
71
|
+
/** The node the keyword is added to, written literally. */
|
|
72
|
+
readonly base?: Record<string, unknown>;
|
|
73
|
+
/** Field of the target declaration naming a value in the kind's own
|
|
74
|
+
* `x-telo-schema-map`, whose mapped node is the base. */
|
|
75
|
+
readonly baseFrom?: string;
|
|
50
76
|
}
|
|
51
77
|
export type SchemaMap = Readonly<Record<string, Record<string, unknown>>>;
|
|
52
78
|
/** The projection a kind declares, or undefined. Invalid shapes read as absent;
|
|
@@ -59,6 +85,18 @@ export declare function rawSchemaProjection(definition: unknown): unknown;
|
|
|
59
85
|
/** True when the annotation was found inside `schema:` rather than on the
|
|
60
86
|
* document — the misplacement the strict half reports. */
|
|
61
87
|
export declare function schemaProjectionIsMisplaced(definition: unknown): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* The schema node that CARRIES the value vocabulary — the node itself, or the
|
|
90
|
+
* branch of a union that declares the map.
|
|
91
|
+
*
|
|
92
|
+
* A slot unioning a closed value vocabulary with a reference keeps its map on the
|
|
93
|
+
* value branch, exactly as the ref-slot reader peels the same union for its
|
|
94
|
+
* constraint. Exported because the strict half checks the map against the same
|
|
95
|
+
* branch's `enum`, and two implementations of "which branch is the value one"
|
|
96
|
+
* would eventually disagree — silently, since the failure of missing one is a
|
|
97
|
+
* completeness check that quietly stops running.
|
|
98
|
+
*/
|
|
99
|
+
export declare function schemaMapBranch(node: unknown): Record<string, unknown> | undefined;
|
|
62
100
|
export declare function readSchemaMap(node: unknown): SchemaMap | undefined;
|
|
63
101
|
/** The consumer-side annotation: a JSON Pointer to this resource's ref slot
|
|
64
102
|
* whose target declares the projection. */
|
|
@@ -83,7 +121,16 @@ export declare function projectionKeyMap(kindSchema: unknown, projection: Schema
|
|
|
83
121
|
* enough to double as a validator would move the domain's semantics into the
|
|
84
122
|
* type layer.
|
|
85
123
|
*/
|
|
86
|
-
export declare function projectEntries(manifest: unknown, projection: SchemaProjection, map: SchemaMap
|
|
124
|
+
export declare function projectEntries(manifest: unknown, projection: SchemaProjection, map: SchemaMap,
|
|
125
|
+
/** What a REFERENCE at the keyed field is resolved through, and where a
|
|
126
|
+
* failure to resolve one is reported. A caller with no scope cannot resolve
|
|
127
|
+
* one, so such an entry projects OPEN — present, untyped — rather than
|
|
128
|
+
* vanishing from the row. */
|
|
129
|
+
options?: {
|
|
130
|
+
readonly scope?: ProjectionScope;
|
|
131
|
+
readonly pointer?: string;
|
|
132
|
+
readonly failures?: ProjectionFailure[];
|
|
133
|
+
}): Record<string, unknown> | undefined;
|
|
87
134
|
/** A reference as the analyzer sees it: the internal `{kind, name, alias?}`
|
|
88
135
|
* shape `resolveRefSentinels` rewrites `!ref` to. */
|
|
89
136
|
export interface ProjectionRef {
|
|
@@ -91,8 +138,17 @@ export interface ProjectionRef {
|
|
|
91
138
|
readonly kind?: string;
|
|
92
139
|
readonly alias?: string;
|
|
93
140
|
}
|
|
94
|
-
/**
|
|
95
|
-
*
|
|
141
|
+
/**
|
|
142
|
+
* The `{kind, name, alias?}` reference a value holds, or undefined. Exported so
|
|
143
|
+
* a host whose slot may hold EITHER shape can fall back to this reading.
|
|
144
|
+
*
|
|
145
|
+
* The unresolved `!ref` SENTINEL is read too. `resolveRefSentinels` normally
|
|
146
|
+
* rewrites one before this pass, but not when the reference names nothing — and
|
|
147
|
+
* that is exactly when a projection failure is reported, so reading only the
|
|
148
|
+
* resolved shape made the diagnostic name the target `<unnamed>`, which is the
|
|
149
|
+
* one fact the author needed from it. A round-trip host (`compile` off) carries
|
|
150
|
+
* the sentinel for every reference, resolved or not.
|
|
151
|
+
*/
|
|
96
152
|
export declare function readProjectionRef(value: unknown): ProjectionRef | undefined;
|
|
97
153
|
/** What a reference resolved to. `"ambiguous"` is distinct from `undefined`
|
|
98
154
|
* because the two need different advice: one says disambiguate, the other says
|
|
@@ -139,6 +195,16 @@ export interface ProjectionScope {
|
|
|
139
195
|
* analysis has.
|
|
140
196
|
*/
|
|
141
197
|
export declare function manifestListScope(manifests: readonly Record<string, any>[], resolveDefinition: (kind: string) => Record<string, any> | undefined): ProjectionScope;
|
|
198
|
+
/**
|
|
199
|
+
* Why a slot could not be typed from a projection.
|
|
200
|
+
*
|
|
201
|
+
* Each reason is a DIFFERENT repair, which is why the three ways a target can
|
|
202
|
+
* carry no usable projection are kept apart rather than collapsed into
|
|
203
|
+
* `no-projection`: that one message ("declares no 'x-telo-schema-projection'")
|
|
204
|
+
* was printed for a kind that declares one whose key field carries no map, and
|
|
205
|
+
* for a declaration whose entry collection is simply absent — accusing the wrong
|
|
206
|
+
* author of the wrong omission in both.
|
|
207
|
+
*/
|
|
142
208
|
export type ProjectionFailure = {
|
|
143
209
|
readonly reason: "no-ref";
|
|
144
210
|
readonly pointer: string;
|
|
@@ -150,10 +216,36 @@ export type ProjectionFailure = {
|
|
|
150
216
|
readonly reason: "ambiguous";
|
|
151
217
|
readonly pointer: string;
|
|
152
218
|
readonly name: string;
|
|
153
|
-
}
|
|
219
|
+
}
|
|
220
|
+
/** The target's KIND declares no `x-telo-schema-projection` at all. */
|
|
221
|
+
| {
|
|
154
222
|
readonly reason: "no-projection";
|
|
155
223
|
readonly pointer: string;
|
|
156
224
|
readonly kind: string;
|
|
225
|
+
}
|
|
226
|
+
/** It declares one, but the field it keys on carries no `x-telo-schema-map`. */
|
|
227
|
+
| {
|
|
228
|
+
readonly reason: "no-projection-map";
|
|
229
|
+
readonly pointer: string;
|
|
230
|
+
readonly kind: string;
|
|
231
|
+
}
|
|
232
|
+
/** Both are declared and the DECLARATION holds no entry collection to project
|
|
233
|
+
* — an absent `columns:`, or a value that is not a collection. */
|
|
234
|
+
| {
|
|
235
|
+
readonly reason: "no-entries";
|
|
236
|
+
readonly pointer: string;
|
|
237
|
+
readonly kind: string;
|
|
238
|
+
readonly entries: string;
|
|
239
|
+
}
|
|
240
|
+
/** An ENTRY of the projected declaration references a shape that could not be
|
|
241
|
+
* read. Reported rather than dropped: the entry would silently vanish from
|
|
242
|
+
* the projected row, so a consumer naming it would be told the property does
|
|
243
|
+
* not exist. */
|
|
244
|
+
| {
|
|
245
|
+
readonly reason: "entry-reference";
|
|
246
|
+
readonly pointer: string;
|
|
247
|
+
readonly entry: string;
|
|
248
|
+
readonly name: string;
|
|
157
249
|
};
|
|
158
250
|
export declare function describeProjectionFailure(failure: ProjectionFailure): string;
|
|
159
251
|
/**
|
|
@@ -166,6 +258,16 @@ export declare function describeProjectionFailure(failure: ProjectionFailure): s
|
|
|
166
258
|
* `failures`, because degrading SILENTLY is the failure this whole mechanism
|
|
167
259
|
* exists to move earlier: the consumer's contract quietly reopens and a
|
|
168
260
|
* misspelled field passes `telo check` exactly as it did before.
|
|
261
|
+
*
|
|
262
|
+
* **A node that projected NOTHING is returned by IDENTITY**, and that is a
|
|
263
|
+
* correctness property of the caller rather than a micro-optimization:
|
|
264
|
+
* `DefinitionRegistry` memoizes a compiled AJV validator per schema OBJECT,
|
|
265
|
+
* because every resource of a kind is checked against the same one at keystroke
|
|
266
|
+
* time. Rebuilding each node unconditionally — which this did — misses that memo
|
|
267
|
+
* for every resource in the analysis, so AJV recompiled the whole kind schema
|
|
268
|
+
* once per resource: on `apps/hub` that was 197 compiles instead of 54, and 723
|
|
269
|
+
* ms instead of 97. Returning the input where nothing changed restores it for
|
|
270
|
+
* every kind that declares no projection at all, which is nearly all of them.
|
|
169
271
|
*/
|
|
170
272
|
export declare function resolveSchemaProjections(schema: unknown, manifest: Record<string, any> | undefined, scope: ProjectionScope, failures?: ProjectionFailure[]): unknown;
|
|
171
273
|
//# sourceMappingURL=schema-projection.d.ts.map
|