@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.
Files changed (100) hide show
  1. package/dist/analyzer.d.ts +1 -1
  2. package/dist/analyzer.d.ts.map +1 -1
  3. package/dist/analyzer.js +157 -63
  4. package/dist/call-graph.d.ts.map +1 -1
  5. package/dist/call-graph.js +7 -1
  6. package/dist/cel-environment.d.ts +12 -0
  7. package/dist/cel-environment.d.ts.map +1 -1
  8. package/dist/cel-environment.js +35 -19
  9. package/dist/cel-scope.d.ts.map +1 -1
  10. package/dist/cel-scope.js +24 -4
  11. package/dist/definition-registry.d.ts +24 -0
  12. package/dist/definition-registry.d.ts.map +1 -1
  13. package/dist/definition-registry.js +41 -0
  14. package/dist/eval-paths.d.ts +68 -0
  15. package/dist/eval-paths.d.ts.map +1 -1
  16. package/dist/eval-paths.js +138 -0
  17. package/dist/flatten-for-analyzer.d.ts +1 -1
  18. package/dist/flatten-for-analyzer.js +1 -1
  19. package/dist/import-resolution-diagnostics.d.ts +1 -1
  20. package/dist/import-resolution-diagnostics.js +1 -1
  21. package/dist/index.d.ts +9 -7
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -5
  24. package/dist/manifest-visitor.d.ts.map +1 -1
  25. package/dist/manifest-visitor.js +8 -1
  26. package/dist/migrations/entries/index.d.ts.map +1 -1
  27. package/dist/migrations/entries/index.js +2 -0
  28. package/dist/migrations/entries/schema-prepare-bucket.json +27 -0
  29. package/dist/peer-binding.d.ts +232 -0
  30. package/dist/peer-binding.d.ts.map +1 -0
  31. package/dist/peer-binding.js +418 -0
  32. package/dist/ref-slot.d.ts +13 -0
  33. package/dist/ref-slot.d.ts.map +1 -1
  34. package/dist/ref-slot.js +26 -0
  35. package/dist/reference-field-map.d.ts +28 -0
  36. package/dist/reference-field-map.d.ts.map +1 -1
  37. package/dist/reference-field-map.js +25 -0
  38. package/dist/referrer-rule.d.ts +17 -0
  39. package/dist/referrer-rule.d.ts.map +1 -1
  40. package/dist/referrer-rule.js +4 -1
  41. package/dist/release/index.d.ts +1 -1
  42. package/dist/release/index.js +1 -1
  43. package/dist/resource-rule.d.ts +40 -27
  44. package/dist/resource-rule.d.ts.map +1 -1
  45. package/dist/resource-rule.js +61 -7
  46. package/dist/rule-condition.d.ts +11 -0
  47. package/dist/rule-condition.d.ts.map +1 -1
  48. package/dist/rule-condition.js +13 -0
  49. package/dist/schema-projection.d.ts +106 -4
  50. package/dist/schema-projection.d.ts.map +1 -1
  51. package/dist/schema-projection.js +206 -18
  52. package/dist/telo-version.d.ts +1 -1
  53. package/dist/telo-version.js +1 -1
  54. package/dist/validate-cel-context.d.ts +1 -17
  55. package/dist/validate-cel-context.d.ts.map +1 -1
  56. package/dist/validate-cel-context.js +5 -70
  57. package/dist/validate-reference-forms.d.ts +10 -0
  58. package/dist/validate-reference-forms.d.ts.map +1 -1
  59. package/dist/validate-reference-forms.js +23 -0
  60. package/dist/validate-references.d.ts.map +1 -1
  61. package/dist/validate-references.js +9 -2
  62. package/dist/validate-referrer-rules.d.ts +38 -4
  63. package/dist/validate-referrer-rules.d.ts.map +1 -1
  64. package/dist/validate-referrer-rules.js +139 -31
  65. package/dist/validate-resource-rules.d.ts +11 -2
  66. package/dist/validate-resource-rules.d.ts.map +1 -1
  67. package/dist/validate-resource-rules.js +18 -12
  68. package/dist/validate-schema-projection.d.ts.map +1 -1
  69. package/dist/validate-schema-projection.js +33 -2
  70. package/dist/with-synthetic-positions.d.ts +1 -1
  71. package/dist/with-synthetic-positions.js +1 -1
  72. package/package.json +3 -3
  73. package/src/analyzer.ts +191 -68
  74. package/src/call-graph.ts +7 -1
  75. package/src/cel-environment.ts +48 -19
  76. package/src/cel-scope.ts +24 -6
  77. package/src/definition-registry.ts +42 -0
  78. package/src/eval-paths.ts +152 -0
  79. package/src/flatten-for-analyzer.ts +1 -1
  80. package/src/import-resolution-diagnostics.ts +1 -1
  81. package/src/index.ts +45 -4
  82. package/src/manifest-visitor.ts +8 -1
  83. package/src/migrations/entries/index.ts +2 -0
  84. package/src/migrations/entries/schema-prepare-bucket.json +27 -0
  85. package/src/peer-binding.ts +641 -0
  86. package/src/ref-slot.ts +36 -0
  87. package/src/reference-field-map.ts +42 -0
  88. package/src/referrer-rule.ts +20 -1
  89. package/src/release/index.ts +1 -1
  90. package/src/resource-rule.ts +69 -7
  91. package/src/rule-condition.ts +15 -0
  92. package/src/schema-projection.ts +283 -20
  93. package/src/telo-version.ts +1 -1
  94. package/src/validate-cel-context.ts +6 -71
  95. package/src/validate-reference-forms.ts +22 -0
  96. package/src/validate-references.ts +15 -2
  97. package/src/validate-referrer-rules.ts +215 -28
  98. package/src/validate-resource-rules.ts +26 -12
  99. package/src/validate-schema-projection.ts +50 -1
  100. package/src/with-synthetic-positions.ts +1 -1
@@ -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;CACjB;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;AA2DD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CA6BtF;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"}
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":"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"}
@@ -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)
@@ -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,CAwBjE;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"}
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"}
@@ -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,
@@ -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 the telo editor can
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
@@ -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 the telo editor can
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
@@ -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
- * Path of the first CEL leaf inside a value, or `undefined` when every leaf is
78
- * literal. A rule reading an expression would be evaluating a placeholder, so
79
- * the subject is skipped — and the skip is reported, never silent.
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): string | undefined;
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,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;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;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAK,GAAG,MAAM,GAAG,SAAS,CAiB7E;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"}
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"}
@@ -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
- return isObject(value) && (value.__compiled === true || value.__tagged === true);
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
- * Path of the first CEL leaf inside a value, or `undefined` when every leaf is
161
- * literal. A rule reading an expression would be evaluating a placeholder, so
162
- * the subject is skipped — and the skip is reported, never silent.
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
- if (isCelNode(value))
170
- return base || "(value)";
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)) {
@@ -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;AAQjC;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"}
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"}
@@ -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): Record<string, unknown> | undefined;
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
- /** The `{kind, name, alias?}` reference a value holds, or undefined. Exported so
95
- * a host whose slot may hold EITHER shape can fall back to this reading. */
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