@telorun/templating 0.15.0 → 0.17.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/cel/catalog.d.ts.map +1 -1
- package/dist/cel/catalog.js +16 -8
- package/dist/engine.d.ts +12 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engines/cel.d.ts.map +1 -1
- package/dist/engines/cel.js +21 -0
- package/dist/engines/literal.d.ts.map +1 -1
- package/dist/engines/literal.js +14 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/package.json +2 -2
- package/src/cel/catalog.ts +16 -8
- package/src/engine.ts +12 -0
- package/src/engines/cel.ts +21 -0
- package/src/engines/literal.ts +15 -0
- package/src/index.ts +0 -5
- package/dist/manifest-schemas.d.ts +0 -122
- package/dist/manifest-schemas.d.ts.map +0 -1
- package/dist/manifest-schemas.js +0 -77
- package/src/manifest-schemas.ts +0 -81
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/cel/catalog.ts"],"names":[],"mappings":"AAGA;;;0DAG0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAClE,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CAClC;AA2CD,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,MAAM,GACN,MAAM,GACN,QAAQ,GACR,MAAM,GACN,YAAY,GACZ,MAAM,GACN,UAAU,GACV,SAAS,GACT,MAAM,CAAC;AAEX;;;qBAGqB;AACrB,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;0EACsE;IACtE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;yDAIqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;wBACoB;IACpB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;2EACuE;IACvE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;CACjE;AAED,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;AAwH5D,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/cel/catalog.ts"],"names":[],"mappings":"AAGA;;;0DAG0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAClE,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CAClC;AA2CD,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,MAAM,GACN,MAAM,GACN,QAAQ,GACR,MAAM,GACN,YAAY,GACZ,MAAM,GACN,UAAU,GACV,SAAS,GACT,MAAM,CAAC;AAEX;;;qBAGqB;AACrB,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;0EACsE;IACtE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;yDAIqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;wBACoB;IACpB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;2EACuE;IACvE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;CACjE;AAED,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;AAwH5D,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,EA8lBlD,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,kBAAkB,IAAI,eAAe,EAAE,CAEtD"}
|
package/dist/cel/catalog.js
CHANGED
|
@@ -352,17 +352,25 @@ export const CEL_FUNCTIONS = [
|
|
|
352
352
|
// already treats `size()` that way, and the alternative teaches an author that
|
|
353
353
|
// slicing bytes is a different operation from slicing a string.
|
|
354
354
|
//
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
355
|
+
// OVERLOADED BY PARAMETER TYPE, so a wrong receiver is rejected — `slice(42, 0,
|
|
356
|
+
// 1)` matches nothing. What cannot ALSO be registered is a `dyn` parameter
|
|
357
|
+
// variant: cel-js refuses overloads that overlap, and a `dyn` first parameter
|
|
358
|
+
// overlaps all three. That is why the RETURN is `dyn` rather than the input's
|
|
359
|
+
// own type. A step result whose producer declares no output type is `dyn`, and
|
|
360
|
+
// with concrete returns the checker resolves such a call to whichever overload
|
|
361
|
+
// was registered first and pins the result to it — so slicing an untyped byte
|
|
362
|
+
// buffer came back typed `string`, and a byte consumer downstream reported a
|
|
363
|
+
// mismatch against perfectly valid CEL. Precision on the way out would be lost
|
|
364
|
+
// at the CEL boundary anyway, where type arguments are erased; being wrong
|
|
365
|
+
// about an untyped receiver would not be.
|
|
363
366
|
{
|
|
364
367
|
name: "slice",
|
|
365
368
|
signature: "slice(dyn, int, int): dyn",
|
|
369
|
+
register: [
|
|
370
|
+
"slice(bytes, int, int): dyn",
|
|
371
|
+
"slice(string, int, int): dyn",
|
|
372
|
+
"slice(list, int, int): dyn",
|
|
373
|
+
],
|
|
366
374
|
// Not "string": it is the one function over strings, bytes AND lists, and the
|
|
367
375
|
// category is what groups it in the generated reference — filing it under
|
|
368
376
|
// strings hides it from the byte and list readers who need it most.
|
package/dist/engine.d.ts
CHANGED
|
@@ -19,6 +19,18 @@ export interface CompileEnv {
|
|
|
19
19
|
export interface AnalyzeEnv {
|
|
20
20
|
readonly celEnv: Environment;
|
|
21
21
|
readonly contextSchema: Record<string, unknown> | null;
|
|
22
|
+
/**
|
|
23
|
+
* The caller vouches that `celEnv` declares EVERY name legal at this site, so
|
|
24
|
+
* a root identifier it does not know is undeclared rather than merely
|
|
25
|
+
* unmodelled.
|
|
26
|
+
*
|
|
27
|
+
* Opt-in because the environment is only that complete when someone built it
|
|
28
|
+
* for a specific site: the base environment declares CEL's own type names and
|
|
29
|
+
* nothing else, so checking roots against it would report `variables` itself
|
|
30
|
+
* as unknown. Absent means the check is skipped, which is what every caller
|
|
31
|
+
* did before it existed.
|
|
32
|
+
*/
|
|
33
|
+
readonly rootsDeclared?: boolean;
|
|
22
34
|
}
|
|
23
35
|
/** A mechanically applicable repair for a diagnostic. `replacement` is the
|
|
24
36
|
* **whole analyzed source**, corrected — never a fragment — so a consumer can
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;wEAEwE;AACxE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;eASe;AACf,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;wEAEwE;AACxE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;eASe;AACf,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACvD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;;0EAa0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;oDAEoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED;;;;yBAIyB;AACzB,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IACrC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;oDAEgD;IAChD,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;iFAGiF;AACjF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;4CAgB4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;wBAEwB;AACxB,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;2EAKuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;;yDAGqD;IACrD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,aAAa,GAAG,OAAO,CAAC;IAElE;;iEAE6D;IAC7D,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,aAAa,CAAC;IAExD;;;;;;;;;;;;uBAYmB;IACnB,UAAU,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE,CAAC;IAExD;;;;;;;;;;;;;;;;;2CAiBuC;IACvC,YAAY,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cel.d.ts","sourceRoot":"","sources":["../../src/engines/cel.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAoB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElG;;;;;;;;;;2BAU2B;AAC3B,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"cel.d.ts","sourceRoot":"","sources":["../../src/engines/cel.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAoB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElG;;;;;;;;;;2BAU2B;AAC3B,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,aAAa,CAqGnF;AAYD;yCACyC;AACzC,eAAO,MAAM,SAAS,EAAE,gBAWvB,CAAC"}
|
package/dist/engines/cel.js
CHANGED
|
@@ -69,6 +69,27 @@ export function analyzeCelExpression(source, env) {
|
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
// An undeclared ROOT identifier. cel-js types an unknown name as `dyn` and
|
|
73
|
+
// accepts it, so `!cel "fff"` type-checked, reached the runtime and resolved
|
|
74
|
+
// to nothing — the one CEL mistake with no static report at all. Member
|
|
75
|
+
// access on a KNOWN root was already covered ("No such key"), which is why a
|
|
76
|
+
// typo one level in was caught and a typo at the root was not.
|
|
77
|
+
//
|
|
78
|
+
// Comprehension variables are not roots: `extractAccessChains` drops the
|
|
79
|
+
// names a `.all(x, …)` binds, so the check never sees them.
|
|
80
|
+
if (env.rootsDeclared) {
|
|
81
|
+
const reported = new Set();
|
|
82
|
+
for (const chain of extractAccessChains(parsed.ast)) {
|
|
83
|
+
const root = chain[0];
|
|
84
|
+
if (!root || reported.has(root) || env.celEnv.hasVariable(root))
|
|
85
|
+
continue;
|
|
86
|
+
reported.add(root);
|
|
87
|
+
out.push({
|
|
88
|
+
code: "CEL_UNKNOWN_IDENTIFIER",
|
|
89
|
+
message: `unknown identifier '${root}' — nothing by that name is in scope here.`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
72
93
|
if (env.contextSchema) {
|
|
73
94
|
const contextSchema = env.contextSchema;
|
|
74
95
|
for (const chain of extractAccessChains(parsed.ast)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"literal.d.ts","sourceRoot":"","sources":["../../src/engines/literal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;+CAE+C;AAC/C,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"literal.d.ts","sourceRoot":"","sources":["../../src/engines/literal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;+CAE+C;AAC/C,eAAO,MAAM,aAAa,EAAE,gBAyB3B,CAAC"}
|
package/dist/engines/literal.js
CHANGED
|
@@ -6,6 +6,20 @@ export const literalEngine = {
|
|
|
6
6
|
compile(source) {
|
|
7
7
|
return source;
|
|
8
8
|
},
|
|
9
|
+
/**
|
|
10
|
+
* Opaque text is TEXT — the type is a constant of the tag, exactly as an
|
|
11
|
+
* embed's is, not a function of the slot.
|
|
12
|
+
*
|
|
13
|
+
* Declaring nothing put `!literal` in the other category, the one `!cel` and
|
|
14
|
+
* `!ref` belong to, and everything downstream then treated it as producing
|
|
15
|
+
* whatever the slot asked for. So the editor offered it at a boolean
|
|
16
|
+
* predicate — where opaque text cannot satisfy the slot and `Run.Choice` has
|
|
17
|
+
* a runtime error saying so — and the analyzer type-checked one against a
|
|
18
|
+
* slot-shaped placeholder instead of the string it will actually be.
|
|
19
|
+
*/
|
|
20
|
+
producedType() {
|
|
21
|
+
return { type: "string" };
|
|
22
|
+
},
|
|
9
23
|
analyze() {
|
|
10
24
|
return { diagnostics: [], calls: [] };
|
|
11
25
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -14,5 +14,4 @@ export { builtinEngines, createDefaultRegistry, defaultRegistry, producedTypeOf,
|
|
|
14
14
|
export type { AnalyzeEnv, AnalyzeResult, CallSite, CompileEnv, DiagnosticFix, EngineDiagnostic, EngineFileClaim, TemplatingEngine, } from "./engine.js";
|
|
15
15
|
export { CEL_ENGINE, INCLUDE_BYTES_ENGINE, INCLUDE_ENGINE_NAMES, INCLUDE_TEXT_ENGINE, isIncludeSentinel, isRefSentinel, isTaggedSentinel, makeTaggedSentinel, plainChainOf, type TaggedSentinel, } from "./sentinel.js";
|
|
16
16
|
export { buildCustomTags, defaultCustomTags } from "./yaml-tags.js";
|
|
17
|
-
export { MANIFEST_SCHEMA_URI, ManifestRootSchema, ResourceRefSchema, } from "./manifest-schemas.js";
|
|
18
17
|
//# sourceMappingURL=index.d.ts.map
|
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,EACL,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAExF,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,QAAQ,EACR,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAExF,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,aAAa,EACb,QAAQ,EACR,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,4 +13,3 @@ export { TemplatingEngineRegistry } from "./registry.js";
|
|
|
13
13
|
export { builtinEngines, createDefaultRegistry, defaultRegistry, producedTypeOf, } from "./builtins.js";
|
|
14
14
|
export { CEL_ENGINE, INCLUDE_BYTES_ENGINE, INCLUDE_ENGINE_NAMES, INCLUDE_TEXT_ENGINE, isIncludeSentinel, isRefSentinel, isTaggedSentinel, makeTaggedSentinel, plainChainOf, } from "./sentinel.js";
|
|
15
15
|
export { buildCustomTags, defaultCustomTags } from "./yaml-tags.js";
|
|
16
|
-
export { MANIFEST_SCHEMA_URI, ManifestRootSchema, ResourceRefSchema, } from "./manifest-schemas.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telorun/templating",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Telo Templating - Engine registry and shared CEL core for Telo manifests.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"telo",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/node": "^20.0.0",
|
|
45
45
|
"typescript": "^5.0.0",
|
|
46
46
|
"vitest": "^2.1.8",
|
|
47
|
-
"@telorun/sdk": "0.
|
|
47
|
+
"@telorun/sdk": "0.82.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@telorun/sdk": "*"
|
package/src/cel/catalog.ts
CHANGED
|
@@ -424,17 +424,25 @@ export const CEL_FUNCTIONS: readonly CelFunctionDoc[] = [
|
|
|
424
424
|
// already treats `size()` that way, and the alternative teaches an author that
|
|
425
425
|
// slicing bytes is a different operation from slicing a string.
|
|
426
426
|
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
427
|
+
// OVERLOADED BY PARAMETER TYPE, so a wrong receiver is rejected — `slice(42, 0,
|
|
428
|
+
// 1)` matches nothing. What cannot ALSO be registered is a `dyn` parameter
|
|
429
|
+
// variant: cel-js refuses overloads that overlap, and a `dyn` first parameter
|
|
430
|
+
// overlaps all three. That is why the RETURN is `dyn` rather than the input's
|
|
431
|
+
// own type. A step result whose producer declares no output type is `dyn`, and
|
|
432
|
+
// with concrete returns the checker resolves such a call to whichever overload
|
|
433
|
+
// was registered first and pins the result to it — so slicing an untyped byte
|
|
434
|
+
// buffer came back typed `string`, and a byte consumer downstream reported a
|
|
435
|
+
// mismatch against perfectly valid CEL. Precision on the way out would be lost
|
|
436
|
+
// at the CEL boundary anyway, where type arguments are erased; being wrong
|
|
437
|
+
// about an untyped receiver would not be.
|
|
435
438
|
{
|
|
436
439
|
name: "slice",
|
|
437
440
|
signature: "slice(dyn, int, int): dyn",
|
|
441
|
+
register: [
|
|
442
|
+
"slice(bytes, int, int): dyn",
|
|
443
|
+
"slice(string, int, int): dyn",
|
|
444
|
+
"slice(list, int, int): dyn",
|
|
445
|
+
],
|
|
438
446
|
// Not "string": it is the one function over strings, bytes AND lists, and the
|
|
439
447
|
// category is what groups it in the generated reference — filing it under
|
|
440
448
|
// strings hides it from the byte and list readers who need it most.
|
package/src/engine.ts
CHANGED
|
@@ -21,6 +21,18 @@ export interface CompileEnv {
|
|
|
21
21
|
export interface AnalyzeEnv {
|
|
22
22
|
readonly celEnv: Environment;
|
|
23
23
|
readonly contextSchema: Record<string, unknown> | null;
|
|
24
|
+
/**
|
|
25
|
+
* The caller vouches that `celEnv` declares EVERY name legal at this site, so
|
|
26
|
+
* a root identifier it does not know is undeclared rather than merely
|
|
27
|
+
* unmodelled.
|
|
28
|
+
*
|
|
29
|
+
* Opt-in because the environment is only that complete when someone built it
|
|
30
|
+
* for a specific site: the base environment declares CEL's own type names and
|
|
31
|
+
* nothing else, so checking roots against it would report `variables` itself
|
|
32
|
+
* as unknown. Absent means the check is skipped, which is what every caller
|
|
33
|
+
* did before it existed.
|
|
34
|
+
*/
|
|
35
|
+
readonly rootsDeclared?: boolean;
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
/** A mechanically applicable repair for a diagnostic. `replacement` is the
|
package/src/engines/cel.ts
CHANGED
|
@@ -79,6 +79,27 @@ export function analyzeCelExpression(source: string, env: AnalyzeEnv): AnalyzeRe
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// An undeclared ROOT identifier. cel-js types an unknown name as `dyn` and
|
|
83
|
+
// accepts it, so `!cel "fff"` type-checked, reached the runtime and resolved
|
|
84
|
+
// to nothing — the one CEL mistake with no static report at all. Member
|
|
85
|
+
// access on a KNOWN root was already covered ("No such key"), which is why a
|
|
86
|
+
// typo one level in was caught and a typo at the root was not.
|
|
87
|
+
//
|
|
88
|
+
// Comprehension variables are not roots: `extractAccessChains` drops the
|
|
89
|
+
// names a `.all(x, …)` binds, so the check never sees them.
|
|
90
|
+
if (env.rootsDeclared) {
|
|
91
|
+
const reported = new Set<string>();
|
|
92
|
+
for (const chain of extractAccessChains(parsed.ast)) {
|
|
93
|
+
const root = chain[0];
|
|
94
|
+
if (!root || reported.has(root) || env.celEnv.hasVariable(root)) continue;
|
|
95
|
+
reported.add(root);
|
|
96
|
+
out.push({
|
|
97
|
+
code: "CEL_UNKNOWN_IDENTIFIER",
|
|
98
|
+
message: `unknown identifier '${root}' — nothing by that name is in scope here.`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
82
103
|
if (env.contextSchema) {
|
|
83
104
|
const contextSchema = env.contextSchema as Record<string, any>;
|
|
84
105
|
for (const chain of extractAccessChains(parsed.ast)) {
|
package/src/engines/literal.ts
CHANGED
|
@@ -10,6 +10,21 @@ export const literalEngine: TemplatingEngine = {
|
|
|
10
10
|
return source;
|
|
11
11
|
},
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Opaque text is TEXT — the type is a constant of the tag, exactly as an
|
|
15
|
+
* embed's is, not a function of the slot.
|
|
16
|
+
*
|
|
17
|
+
* Declaring nothing put `!literal` in the other category, the one `!cel` and
|
|
18
|
+
* `!ref` belong to, and everything downstream then treated it as producing
|
|
19
|
+
* whatever the slot asked for. So the editor offered it at a boolean
|
|
20
|
+
* predicate — where opaque text cannot satisfy the slot and `Run.Choice` has
|
|
21
|
+
* a runtime error saying so — and the analyzer type-checked one against a
|
|
22
|
+
* slot-shaped placeholder instead of the string it will actually be.
|
|
23
|
+
*/
|
|
24
|
+
producedType() {
|
|
25
|
+
return { type: "string" };
|
|
26
|
+
},
|
|
27
|
+
|
|
13
28
|
analyze() {
|
|
14
29
|
return { diagnostics: [], calls: [] };
|
|
15
30
|
},
|
package/src/index.ts
CHANGED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/** Shared JSON-Schema fragments referenced from every module's `telo.yaml`
|
|
2
|
-
* via `$ref: "telo://manifest#/$defs/<Name>"`. Lives in the templating
|
|
3
|
-
* package (alongside the YAML tag mechanism) because the analyzer cannot
|
|
4
|
-
* depend on the kernel — both consume this package, so this is the only
|
|
5
|
-
* layer where a single source of truth can sit. The kernel re-exports
|
|
6
|
-
* these symbols from its own `manifest-schemas` surface for downstream
|
|
7
|
-
* ergonomics. */
|
|
8
|
-
/** Schema fragment for a resource-reference slot. The only form a manifest
|
|
9
|
-
* author writes is the `!ref <name>` (or `!ref <Alias>.<name>`) YAML tag,
|
|
10
|
-
* which parses to a `TaggedSentinel` (engine "ref") whose `source` is the
|
|
11
|
-
* bare resource name. In practice module schemas mark a ref slot with a bare
|
|
12
|
-
* `x-telo-ref` annotation (plus, where the slot only ever holds a reference,
|
|
13
|
-
* `type: object` to reject a stray scalar); the analyzer's reference walker
|
|
14
|
-
* reads `x-telo-ref` to look the name up against that constraint, independent
|
|
15
|
-
* of this fragment. A slot opts into `$ref:
|
|
16
|
-
* "telo://manifest#/$defs/ResourceRef"` only when it wants this exact
|
|
17
|
-
* two-branch shape enforced at the AJV layer too — it is not required, and
|
|
18
|
-
* slots that also accept an inline value (e.g. `inputType` / `outputType`)
|
|
19
|
-
* deliberately do not use it (an inline JSON Schema has no `kind`).
|
|
20
|
-
*
|
|
21
|
-
* Two `anyOf` branches because the value's shape depends on the phase at
|
|
22
|
-
* which it is validated:
|
|
23
|
-
*
|
|
24
|
-
* 1. The raw `!ref` sentinel — what survives to AJV when a cross-module
|
|
25
|
-
* reference can't be resolved in standalone single-file analysis (the
|
|
26
|
-
* imported module isn't loaded). `substituteCelFields` deliberately
|
|
27
|
-
* keeps the sentinel so this branch matches.
|
|
28
|
-
* 2. A resolved reference object — `{kind, name, alias?}` substituted in
|
|
29
|
-
* place of a sentinel (or an inline definition `{kind, ...config}`
|
|
30
|
-
* reached through a local `$ref` that escapes extraction). Both the
|
|
31
|
-
* kernel and the analyzer validate ref slots *after* sentinel
|
|
32
|
-
* resolution, so this is the shape AJV usually sees.
|
|
33
|
-
*
|
|
34
|
-
* The object-form `{kind, name}` reference a user could once type directly
|
|
35
|
-
* is gone: a plain object at a ref slot is only ever an inline definition
|
|
36
|
-
* or the resolver's own substitution, never an author-written reference.
|
|
37
|
-
* That removal is enforced by the analyzer (it rejects an author-written
|
|
38
|
-
* `{kind, name}` before normalization), not by this schema — branch 2
|
|
39
|
-
* cannot distinguish an author's `{kind, name}` from the resolver's. */
|
|
40
|
-
export declare const ResourceRefSchema: {
|
|
41
|
-
title: string;
|
|
42
|
-
anyOf: ({
|
|
43
|
-
type: string;
|
|
44
|
-
required: string[];
|
|
45
|
-
properties: {
|
|
46
|
-
__tagged: {
|
|
47
|
-
const: boolean;
|
|
48
|
-
};
|
|
49
|
-
engine: {
|
|
50
|
-
const: string;
|
|
51
|
-
};
|
|
52
|
-
source: {
|
|
53
|
-
type: string;
|
|
54
|
-
minLength: number;
|
|
55
|
-
};
|
|
56
|
-
kind?: undefined;
|
|
57
|
-
};
|
|
58
|
-
additionalProperties: boolean;
|
|
59
|
-
} | {
|
|
60
|
-
type: string;
|
|
61
|
-
required: string[];
|
|
62
|
-
properties: {
|
|
63
|
-
kind: {
|
|
64
|
-
type: string;
|
|
65
|
-
};
|
|
66
|
-
__tagged?: undefined;
|
|
67
|
-
engine?: undefined;
|
|
68
|
-
source?: undefined;
|
|
69
|
-
};
|
|
70
|
-
additionalProperties: boolean;
|
|
71
|
-
})[];
|
|
72
|
-
};
|
|
73
|
-
/** Stable URI under which the shared manifest root schema is registered
|
|
74
|
-
* with module-side AJV instances. Module YAMLs reach the fragments via
|
|
75
|
-
* `$ref: "telo://manifest#/$defs/<Name>"`. The URI is the contract;
|
|
76
|
-
* the symbol names intentionally omit a host-specific prefix since the
|
|
77
|
-
* fragments live in `@telorun/templating` (the only layer both kernel
|
|
78
|
-
* and analyzer depend on). */
|
|
79
|
-
export declare const MANIFEST_SCHEMA_URI = "telo://manifest";
|
|
80
|
-
/** Root schema registered with AJV under `MANIFEST_SCHEMA_URI`. Carries
|
|
81
|
-
* `$defs` only — it isn't validated against directly. Adding a new
|
|
82
|
-
* shared fragment means putting it under `$defs` here and `$ref`-ing
|
|
83
|
-
* it from module schemas. */
|
|
84
|
-
export declare const ManifestRootSchema: {
|
|
85
|
-
$id: string;
|
|
86
|
-
$defs: {
|
|
87
|
-
ResourceRef: {
|
|
88
|
-
title: string;
|
|
89
|
-
anyOf: ({
|
|
90
|
-
type: string;
|
|
91
|
-
required: string[];
|
|
92
|
-
properties: {
|
|
93
|
-
__tagged: {
|
|
94
|
-
const: boolean;
|
|
95
|
-
};
|
|
96
|
-
engine: {
|
|
97
|
-
const: string;
|
|
98
|
-
};
|
|
99
|
-
source: {
|
|
100
|
-
type: string;
|
|
101
|
-
minLength: number;
|
|
102
|
-
};
|
|
103
|
-
kind?: undefined;
|
|
104
|
-
};
|
|
105
|
-
additionalProperties: boolean;
|
|
106
|
-
} | {
|
|
107
|
-
type: string;
|
|
108
|
-
required: string[];
|
|
109
|
-
properties: {
|
|
110
|
-
kind: {
|
|
111
|
-
type: string;
|
|
112
|
-
};
|
|
113
|
-
__tagged?: undefined;
|
|
114
|
-
engine?: undefined;
|
|
115
|
-
source?: undefined;
|
|
116
|
-
};
|
|
117
|
-
additionalProperties: boolean;
|
|
118
|
-
})[];
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
};
|
|
122
|
-
//# sourceMappingURL=manifest-schemas.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-schemas.d.ts","sourceRoot":"","sources":["../src/manifest-schemas.ts"],"names":[],"mappings":"AAAA;;;;;;kBAMkB;AAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yEA+ByE;AACzE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoB7B,CAAC;AAGF;;;;;+BAK+B;AAC/B,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;8BAG8B;AAC9B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAK9B,CAAC"}
|
package/dist/manifest-schemas.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/** Shared JSON-Schema fragments referenced from every module's `telo.yaml`
|
|
2
|
-
* via `$ref: "telo://manifest#/$defs/<Name>"`. Lives in the templating
|
|
3
|
-
* package (alongside the YAML tag mechanism) because the analyzer cannot
|
|
4
|
-
* depend on the kernel — both consume this package, so this is the only
|
|
5
|
-
* layer where a single source of truth can sit. The kernel re-exports
|
|
6
|
-
* these symbols from its own `manifest-schemas` surface for downstream
|
|
7
|
-
* ergonomics. */
|
|
8
|
-
/** Schema fragment for a resource-reference slot. The only form a manifest
|
|
9
|
-
* author writes is the `!ref <name>` (or `!ref <Alias>.<name>`) YAML tag,
|
|
10
|
-
* which parses to a `TaggedSentinel` (engine "ref") whose `source` is the
|
|
11
|
-
* bare resource name. In practice module schemas mark a ref slot with a bare
|
|
12
|
-
* `x-telo-ref` annotation (plus, where the slot only ever holds a reference,
|
|
13
|
-
* `type: object` to reject a stray scalar); the analyzer's reference walker
|
|
14
|
-
* reads `x-telo-ref` to look the name up against that constraint, independent
|
|
15
|
-
* of this fragment. A slot opts into `$ref:
|
|
16
|
-
* "telo://manifest#/$defs/ResourceRef"` only when it wants this exact
|
|
17
|
-
* two-branch shape enforced at the AJV layer too — it is not required, and
|
|
18
|
-
* slots that also accept an inline value (e.g. `inputType` / `outputType`)
|
|
19
|
-
* deliberately do not use it (an inline JSON Schema has no `kind`).
|
|
20
|
-
*
|
|
21
|
-
* Two `anyOf` branches because the value's shape depends on the phase at
|
|
22
|
-
* which it is validated:
|
|
23
|
-
*
|
|
24
|
-
* 1. The raw `!ref` sentinel — what survives to AJV when a cross-module
|
|
25
|
-
* reference can't be resolved in standalone single-file analysis (the
|
|
26
|
-
* imported module isn't loaded). `substituteCelFields` deliberately
|
|
27
|
-
* keeps the sentinel so this branch matches.
|
|
28
|
-
* 2. A resolved reference object — `{kind, name, alias?}` substituted in
|
|
29
|
-
* place of a sentinel (or an inline definition `{kind, ...config}`
|
|
30
|
-
* reached through a local `$ref` that escapes extraction). Both the
|
|
31
|
-
* kernel and the analyzer validate ref slots *after* sentinel
|
|
32
|
-
* resolution, so this is the shape AJV usually sees.
|
|
33
|
-
*
|
|
34
|
-
* The object-form `{kind, name}` reference a user could once type directly
|
|
35
|
-
* is gone: a plain object at a ref slot is only ever an inline definition
|
|
36
|
-
* or the resolver's own substitution, never an author-written reference.
|
|
37
|
-
* That removal is enforced by the analyzer (it rejects an author-written
|
|
38
|
-
* `{kind, name}` before normalization), not by this schema — branch 2
|
|
39
|
-
* cannot distinguish an author's `{kind, name}` from the resolver's. */
|
|
40
|
-
export const ResourceRefSchema = {
|
|
41
|
-
title: "Resource reference",
|
|
42
|
-
anyOf: [
|
|
43
|
-
{
|
|
44
|
-
type: "object",
|
|
45
|
-
required: ["__tagged", "engine", "source"],
|
|
46
|
-
properties: {
|
|
47
|
-
__tagged: { const: true },
|
|
48
|
-
engine: { const: "ref" },
|
|
49
|
-
source: { type: "string", minLength: 1 },
|
|
50
|
-
},
|
|
51
|
-
additionalProperties: false,
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
type: "object",
|
|
55
|
-
required: ["kind"],
|
|
56
|
-
properties: { kind: { type: "string" } },
|
|
57
|
-
additionalProperties: true,
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
};
|
|
61
|
-
/** Stable URI under which the shared manifest root schema is registered
|
|
62
|
-
* with module-side AJV instances. Module YAMLs reach the fragments via
|
|
63
|
-
* `$ref: "telo://manifest#/$defs/<Name>"`. The URI is the contract;
|
|
64
|
-
* the symbol names intentionally omit a host-specific prefix since the
|
|
65
|
-
* fragments live in `@telorun/templating` (the only layer both kernel
|
|
66
|
-
* and analyzer depend on). */
|
|
67
|
-
export const MANIFEST_SCHEMA_URI = "telo://manifest";
|
|
68
|
-
/** Root schema registered with AJV under `MANIFEST_SCHEMA_URI`. Carries
|
|
69
|
-
* `$defs` only — it isn't validated against directly. Adding a new
|
|
70
|
-
* shared fragment means putting it under `$defs` here and `$ref`-ing
|
|
71
|
-
* it from module schemas. */
|
|
72
|
-
export const ManifestRootSchema = {
|
|
73
|
-
$id: MANIFEST_SCHEMA_URI,
|
|
74
|
-
$defs: {
|
|
75
|
-
ResourceRef: ResourceRefSchema,
|
|
76
|
-
},
|
|
77
|
-
};
|
package/src/manifest-schemas.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/** Shared JSON-Schema fragments referenced from every module's `telo.yaml`
|
|
2
|
-
* via `$ref: "telo://manifest#/$defs/<Name>"`. Lives in the templating
|
|
3
|
-
* package (alongside the YAML tag mechanism) because the analyzer cannot
|
|
4
|
-
* depend on the kernel — both consume this package, so this is the only
|
|
5
|
-
* layer where a single source of truth can sit. The kernel re-exports
|
|
6
|
-
* these symbols from its own `manifest-schemas` surface for downstream
|
|
7
|
-
* ergonomics. */
|
|
8
|
-
|
|
9
|
-
/** Schema fragment for a resource-reference slot. The only form a manifest
|
|
10
|
-
* author writes is the `!ref <name>` (or `!ref <Alias>.<name>`) YAML tag,
|
|
11
|
-
* which parses to a `TaggedSentinel` (engine "ref") whose `source` is the
|
|
12
|
-
* bare resource name. In practice module schemas mark a ref slot with a bare
|
|
13
|
-
* `x-telo-ref` annotation (plus, where the slot only ever holds a reference,
|
|
14
|
-
* `type: object` to reject a stray scalar); the analyzer's reference walker
|
|
15
|
-
* reads `x-telo-ref` to look the name up against that constraint, independent
|
|
16
|
-
* of this fragment. A slot opts into `$ref:
|
|
17
|
-
* "telo://manifest#/$defs/ResourceRef"` only when it wants this exact
|
|
18
|
-
* two-branch shape enforced at the AJV layer too — it is not required, and
|
|
19
|
-
* slots that also accept an inline value (e.g. `inputType` / `outputType`)
|
|
20
|
-
* deliberately do not use it (an inline JSON Schema has no `kind`).
|
|
21
|
-
*
|
|
22
|
-
* Two `anyOf` branches because the value's shape depends on the phase at
|
|
23
|
-
* which it is validated:
|
|
24
|
-
*
|
|
25
|
-
* 1. The raw `!ref` sentinel — what survives to AJV when a cross-module
|
|
26
|
-
* reference can't be resolved in standalone single-file analysis (the
|
|
27
|
-
* imported module isn't loaded). `substituteCelFields` deliberately
|
|
28
|
-
* keeps the sentinel so this branch matches.
|
|
29
|
-
* 2. A resolved reference object — `{kind, name, alias?}` substituted in
|
|
30
|
-
* place of a sentinel (or an inline definition `{kind, ...config}`
|
|
31
|
-
* reached through a local `$ref` that escapes extraction). Both the
|
|
32
|
-
* kernel and the analyzer validate ref slots *after* sentinel
|
|
33
|
-
* resolution, so this is the shape AJV usually sees.
|
|
34
|
-
*
|
|
35
|
-
* The object-form `{kind, name}` reference a user could once type directly
|
|
36
|
-
* is gone: a plain object at a ref slot is only ever an inline definition
|
|
37
|
-
* or the resolver's own substitution, never an author-written reference.
|
|
38
|
-
* That removal is enforced by the analyzer (it rejects an author-written
|
|
39
|
-
* `{kind, name}` before normalization), not by this schema — branch 2
|
|
40
|
-
* cannot distinguish an author's `{kind, name}` from the resolver's. */
|
|
41
|
-
export const ResourceRefSchema = {
|
|
42
|
-
title: "Resource reference",
|
|
43
|
-
anyOf: [
|
|
44
|
-
{
|
|
45
|
-
type: "object",
|
|
46
|
-
required: ["__tagged", "engine", "source"],
|
|
47
|
-
properties: {
|
|
48
|
-
__tagged: { const: true },
|
|
49
|
-
engine: { const: "ref" },
|
|
50
|
-
source: { type: "string", minLength: 1 },
|
|
51
|
-
},
|
|
52
|
-
additionalProperties: false,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
type: "object",
|
|
56
|
-
required: ["kind"],
|
|
57
|
-
properties: { kind: { type: "string" } },
|
|
58
|
-
additionalProperties: true,
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/** Stable URI under which the shared manifest root schema is registered
|
|
65
|
-
* with module-side AJV instances. Module YAMLs reach the fragments via
|
|
66
|
-
* `$ref: "telo://manifest#/$defs/<Name>"`. The URI is the contract;
|
|
67
|
-
* the symbol names intentionally omit a host-specific prefix since the
|
|
68
|
-
* fragments live in `@telorun/templating` (the only layer both kernel
|
|
69
|
-
* and analyzer depend on). */
|
|
70
|
-
export const MANIFEST_SCHEMA_URI = "telo://manifest";
|
|
71
|
-
|
|
72
|
-
/** Root schema registered with AJV under `MANIFEST_SCHEMA_URI`. Carries
|
|
73
|
-
* `$defs` only — it isn't validated against directly. Adding a new
|
|
74
|
-
* shared fragment means putting it under `$defs` here and `$ref`-ing
|
|
75
|
-
* it from module schemas. */
|
|
76
|
-
export const ManifestRootSchema = {
|
|
77
|
-
$id: MANIFEST_SCHEMA_URI,
|
|
78
|
-
$defs: {
|
|
79
|
-
ResourceRef: ResourceRefSchema,
|
|
80
|
-
},
|
|
81
|
-
};
|