@telorun/analyzer 0.57.0 → 0.58.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 (116) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/analyzer.js +91 -9
  3. package/dist/cel-environment.d.ts.map +1 -1
  4. package/dist/cel-environment.js +6 -3
  5. package/dist/definition-registry.d.ts +5 -0
  6. package/dist/definition-registry.d.ts.map +1 -1
  7. package/dist/definition-registry.js +9 -0
  8. package/dist/index.d.ts +10 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +6 -2
  11. package/dist/invocation-contract.d.ts +21 -13
  12. package/dist/invocation-contract.d.ts.map +1 -1
  13. package/dist/invocation-contract.js +43 -46
  14. package/dist/loaded-types.d.ts +13 -0
  15. package/dist/loaded-types.d.ts.map +1 -1
  16. package/dist/manifest-loader.d.ts +8 -1
  17. package/dist/manifest-loader.d.ts.map +1 -1
  18. package/dist/manifest-loader.js +33 -6
  19. package/dist/migrations/driver.d.ts +69 -0
  20. package/dist/migrations/driver.d.ts.map +1 -0
  21. package/dist/migrations/driver.js +200 -0
  22. package/dist/migrations/entries/index.d.ts +3 -0
  23. package/dist/migrations/entries/index.d.ts.map +1 -0
  24. package/dist/migrations/entries/index.js +9 -0
  25. package/dist/migrations/entries/normalize-value-types.json +48 -0
  26. package/dist/migrations/entries/ref-slot-scalar-type.json +20 -0
  27. package/dist/migrations/entry-data.d.ts +25 -0
  28. package/dist/migrations/entry-data.d.ts.map +1 -0
  29. package/dist/migrations/entry-data.js +171 -0
  30. package/dist/migrations/index.d.ts +22 -0
  31. package/dist/migrations/index.d.ts.map +1 -0
  32. package/dist/migrations/index.js +19 -0
  33. package/dist/migrations/match.d.ts +162 -0
  34. package/dist/migrations/match.d.ts.map +1 -0
  35. package/dist/migrations/match.js +295 -0
  36. package/dist/migrations/patch.d.ts +68 -0
  37. package/dist/migrations/patch.d.ts.map +1 -0
  38. package/dist/migrations/patch.js +236 -0
  39. package/dist/migrations/provenance.d.ts +25 -0
  40. package/dist/migrations/provenance.d.ts.map +1 -0
  41. package/dist/migrations/provenance.js +118 -0
  42. package/dist/migrations/registry.d.ts +35 -0
  43. package/dist/migrations/registry.d.ts.map +1 -0
  44. package/dist/migrations/registry.js +35 -0
  45. package/dist/migrations/report.d.ts +28 -0
  46. package/dist/migrations/report.d.ts.map +1 -0
  47. package/dist/migrations/report.js +144 -0
  48. package/dist/migrations/types.d.ts +115 -0
  49. package/dist/migrations/types.d.ts.map +1 -0
  50. package/dist/migrations/types.js +24 -0
  51. package/dist/migrations/yaml-edit.d.ts +21 -0
  52. package/dist/migrations/yaml-edit.d.ts.map +1 -0
  53. package/dist/migrations/yaml-edit.js +245 -0
  54. package/dist/parse-loaded-file.d.ts +8 -0
  55. package/dist/parse-loaded-file.d.ts.map +1 -1
  56. package/dist/parse-loaded-file.js +22 -13
  57. package/dist/resolve-schema-type-refs.d.ts +29 -12
  58. package/dist/resolve-schema-type-refs.d.ts.map +1 -1
  59. package/dist/resolve-schema-type-refs.js +89 -16
  60. package/dist/schema-compat.d.ts +35 -9
  61. package/dist/schema-compat.d.ts.map +1 -1
  62. package/dist/schema-compat.js +180 -64
  63. package/dist/schema-region.d.ts +33 -0
  64. package/dist/schema-region.d.ts.map +1 -0
  65. package/dist/schema-region.js +45 -0
  66. package/dist/types.d.ts +17 -0
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/validate-cel-context.d.ts.map +1 -1
  69. package/dist/validate-cel-context.js +29 -3
  70. package/dist/validate-step-inputs.d.ts +8 -1
  71. package/dist/validate-step-inputs.d.ts.map +1 -1
  72. package/dist/validate-step-inputs.js +47 -2
  73. package/dist/validate-value-type-slots.d.ts +43 -0
  74. package/dist/validate-value-type-slots.d.ts.map +1 -0
  75. package/dist/validate-value-type-slots.js +142 -0
  76. package/dist/value-type-keyword.d.ts +60 -0
  77. package/dist/value-type-keyword.d.ts.map +1 -0
  78. package/dist/value-type-keyword.js +119 -0
  79. package/dist/yaml-source-edit.d.ts +56 -0
  80. package/dist/yaml-source-edit.d.ts.map +1 -0
  81. package/dist/yaml-source-edit.js +93 -0
  82. package/package.json +3 -3
  83. package/src/analyzer.ts +99 -6
  84. package/src/cel-environment.ts +6 -3
  85. package/src/definition-registry.ts +10 -0
  86. package/src/index.ts +26 -2
  87. package/src/invocation-contract.ts +43 -48
  88. package/src/loaded-types.ts +13 -0
  89. package/src/manifest-loader.ts +37 -6
  90. package/src/migrations/driver.ts +262 -0
  91. package/src/migrations/entries/index.ts +10 -0
  92. package/src/migrations/entries/normalize-value-types.json +48 -0
  93. package/src/migrations/entries/ref-slot-scalar-type.json +20 -0
  94. package/src/migrations/entry-data.ts +207 -0
  95. package/src/migrations/index.ts +22 -0
  96. package/src/migrations/match.ts +382 -0
  97. package/src/migrations/patch.ts +265 -0
  98. package/src/migrations/provenance.ts +167 -0
  99. package/src/migrations/registry.ts +40 -0
  100. package/src/migrations/report.ts +169 -0
  101. package/src/migrations/types.ts +144 -0
  102. package/src/migrations/yaml-edit.ts +260 -0
  103. package/src/parse-loaded-file.ts +31 -12
  104. package/src/resolve-schema-type-refs.ts +93 -16
  105. package/src/schema-compat.ts +212 -74
  106. package/src/schema-region.ts +46 -0
  107. package/src/types.ts +17 -0
  108. package/src/validate-cel-context.ts +36 -3
  109. package/src/validate-step-inputs.ts +56 -1
  110. package/src/validate-value-type-slots.ts +182 -0
  111. package/src/value-type-keyword.ts +135 -0
  112. package/src/yaml-source-edit.ts +106 -0
  113. package/dist/binary-slot.d.ts +0 -39
  114. package/dist/binary-slot.d.ts.map +0 -1
  115. package/dist/binary-slot.js +0 -58
  116. package/src/binary-slot.ts +0 -71
@@ -0,0 +1,245 @@
1
+ /** Rendering a migration plan back into the author's YAML.
2
+ *
3
+ * Edits are BYTE SPLICES computed from the parsed document's node ranges, not
4
+ * `Document.toString()`. That is `cli/nodejs/src/commands/upgrade.ts`'s
5
+ * precedent and it is load-bearing here for the same reason: re-serializing
6
+ * re-folds block scalars, drops quote-style hints and reflows long strings, so
7
+ * a one-key repair would arrive as a whole-file diff. Everything outside the
8
+ * spliced ranges is byte-identical to the input.
9
+ *
10
+ * The document is parsed with the same `defaultCustomTags()` every other
11
+ * parse site uses, so a tagged scalar is a node here exactly as it is in the
12
+ * loader's tree. */
13
+ import { isMap, isPair, isScalar, isSeq } from "yaml";
14
+ import { renderFixReplacement } from "../yaml-source-edit.js";
15
+ export { applyTextEdits } from "../yaml-source-edit.js";
16
+ function nodeAt(doc, path) {
17
+ if (path.length === 0)
18
+ return doc.contents;
19
+ return doc.getIn(path, true);
20
+ }
21
+ function rangeOf(node) {
22
+ const range = node?.range;
23
+ if (!Array.isArray(range) || typeof range[0] !== "number" || typeof range[1] !== "number") {
24
+ return undefined;
25
+ }
26
+ return [range[0], range[1]];
27
+ }
28
+ /** The Pair whose key is `key` inside the map at `parent`. */
29
+ function pairAt(doc, parent, key) {
30
+ const map = nodeAt(doc, parent);
31
+ if (!isMap(map))
32
+ return undefined;
33
+ return map.items.find((item) => isPair(item) && isScalar(item.key) && String(item.key.value) === key);
34
+ }
35
+ /** Re-quote `value` in the style the author used at `original`.
36
+ *
37
+ * A non-string is rendered as its YAML spelling and then handed to the shared
38
+ * rule, so a migration and a quick fix quote the same value identically — the
39
+ * rule itself is `renderFixReplacement` (`../yaml-source-edit.js`), which both
40
+ * this and `@telorun/ide-support` read rather than restate. */
41
+ function renderScalar(original, value) {
42
+ if (value === null)
43
+ return "null";
44
+ if (typeof value === "boolean" || typeof value === "number")
45
+ return String(value);
46
+ if (typeof value !== "string")
47
+ return undefined;
48
+ return renderFixReplacement(original, value);
49
+ }
50
+ /** Column of `offset` within its line, and the offset of that line's start. */
51
+ function lineGeometry(text, offset) {
52
+ const lineStart = text.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
53
+ return { lineStart, indent: offset - lineStart };
54
+ }
55
+ /** One YAML edit per effect, or `undefined` when the effect cannot be written
56
+ * into this file — the same all-or-nothing rule the tree side has, so a
57
+ * partially applied patch never reaches disk. */
58
+ export function planTextEdits(doc, text, effects) {
59
+ if (effects.length === 0)
60
+ return [];
61
+ // **The document is never mutated.** A patch's later effects address the node
62
+ // by its POST-rename path, which the file does not have — so every effect is
63
+ // resolved at the one location the patch matched, read off the first effect.
64
+ // The tree applier and this one therefore agree without either replaying the
65
+ // other's state.
66
+ const first = effects[0];
67
+ const docPath = first.kind === "rename-key" ? [...first.parent, first.from] : first.path;
68
+ // A removal supersedes every other edit at the location: `planPatch` refuses
69
+ // anything after a `remove-entry`, and the line it deletes contains them.
70
+ const removal = effects.find((e) => e.kind === "remove-entry");
71
+ if (removal)
72
+ return removeEntryEdit(doc, text, docPath);
73
+ const edits = [];
74
+ let keyEdit;
75
+ // Value edits compose into ONE splice: a `set-tag` after a `set-value` must
76
+ // emit the tag in front of the NEW scalar, not re-read the old one.
77
+ let valueSpan;
78
+ let scalarText;
79
+ let tagText;
80
+ for (const effect of effects) {
81
+ switch (effect.kind) {
82
+ case "rename-key": {
83
+ const pair = pairAt(doc, docPath.slice(0, -1), String(docPath[docPath.length - 1]));
84
+ if (!isPair(pair) || !isScalar(pair.key))
85
+ return undefined;
86
+ const range = rangeOf(pair.key);
87
+ if (!range)
88
+ return undefined;
89
+ const rendered = renderScalar(text.slice(range[0], range[1]), effect.to);
90
+ if (rendered === undefined)
91
+ return undefined;
92
+ keyEdit = { start: range[0], end: range[1], newText: rendered };
93
+ break;
94
+ }
95
+ case "set-value": {
96
+ const range = rangeOf(nodeAt(doc, docPath));
97
+ if (!range)
98
+ return undefined;
99
+ const rendered = renderScalar(text.slice(range[0], range[1]), effect.value);
100
+ if (rendered === undefined)
101
+ return undefined;
102
+ valueSpan ??= range;
103
+ scalarText = rendered;
104
+ break;
105
+ }
106
+ case "set-tag": {
107
+ const node = nodeAt(doc, docPath);
108
+ if (!isScalar(node))
109
+ return undefined;
110
+ const range = rangeOf(node);
111
+ if (!range)
112
+ return undefined;
113
+ // The tag sits outside the scalar's own span, so an existing one is
114
+ // replaced by rewriting from where it starts; a plain scalar just gains
115
+ // a prefix.
116
+ const existing = typeof node.tag === "string" ? node.tag : undefined;
117
+ const tagStart = existing ? text.lastIndexOf(existing, range[0]) : -1;
118
+ valueSpan = [tagStart >= 0 ? tagStart : range[0], range[1]];
119
+ scalarText ??= text.slice(range[0], range[1]);
120
+ tagText = `!${effect.tag}`;
121
+ break;
122
+ }
123
+ case "insert-item": {
124
+ const edit = insertItemEdit(doc, text, docPath, effect.index, effect.value);
125
+ if (!edit)
126
+ return undefined;
127
+ edits.push(edit);
128
+ break;
129
+ }
130
+ case "remove-entry":
131
+ // Handled above.
132
+ break;
133
+ }
134
+ }
135
+ if (keyEdit)
136
+ edits.push(keyEdit);
137
+ if (valueSpan && scalarText !== undefined) {
138
+ edits.push({
139
+ start: valueSpan[0],
140
+ end: valueSpan[1],
141
+ newText: tagText ? `${tagText} ${scalarText}` : scalarText,
142
+ });
143
+ }
144
+ return edits;
145
+ }
146
+ function insertItemEdit(doc, text, path, index, value) {
147
+ const seq = nodeAt(doc, path);
148
+ // An empty sequence is written `[]` in flow style, which has no item line to
149
+ // extend — the one insert shape this cannot render.
150
+ if (!isSeq(seq) || seq.items.length === 0)
151
+ return undefined;
152
+ const rendered = renderScalar("", value);
153
+ if (rendered === undefined)
154
+ return undefined;
155
+ const anchorIndex = Math.min(index, seq.items.length - 1);
156
+ const anchor = rangeOf(seq.items[anchorIndex]);
157
+ if (!anchor)
158
+ return undefined;
159
+ const { lineStart, indent } = lineGeometry(text, anchor[0]);
160
+ // A block sequence's item starts two columns after its `- `; a flow sequence
161
+ // has no line of its own.
162
+ if (text.slice(lineStart, anchor[0]).trimStart() !== "- ")
163
+ return undefined;
164
+ const line = `${" ".repeat(Math.max(0, indent - 2))}- ${rendered}\n`;
165
+ if (index >= seq.items.length) {
166
+ const last = rangeOf(seq.items[seq.items.length - 1]);
167
+ if (!last)
168
+ return undefined;
169
+ const lineEnd = text.indexOf("\n", last[1]);
170
+ const at = lineEnd < 0 ? text.length : lineEnd + 1;
171
+ return { start: at, end: at, newText: line };
172
+ }
173
+ return { start: lineStart, end: lineStart, newText: line };
174
+ }
175
+ function removeEntryEdit(doc, text, path) {
176
+ const located = locateEntry(doc, path);
177
+ if (!located)
178
+ return undefined;
179
+ const { lineStart } = lineGeometry(text, located.start);
180
+ const prefix = text.slice(lineStart, located.start);
181
+ const opensSequenceItem = /^-\s+$/.test(prefix.trimStart());
182
+ // The entry OWNS its line — indentation for a mapping entry, indentation plus
183
+ // `- ` for a sequence item — so removing the line is exact.
184
+ if (located.item ? opensSequenceItem : prefix.trim() === "") {
185
+ const lineEnd = text.indexOf("\n", located.end);
186
+ return [{ start: lineStart, end: lineEnd < 0 ? text.length : lineEnd + 1, newText: "" }];
187
+ }
188
+ // A mapping entry that OPENS a sequence item shares its line with the `- `,
189
+ // and is the overwhelmingly common shape of the one thing a migration removes
190
+ // today: a legacy ref slot is almost always an `anyOf` branch, written
191
+ // `- type: string` with the annotation beneath it. Deleting the line would
192
+ // take the dash with it and fold the item into its predecessor — so the entry
193
+ // is spliced out up to the FOLLOWING sibling's key instead, which slides onto
194
+ // the dash at the column it already occupies. Refusing here would have made
195
+ // the diagnostic's own advice ("run `telo migrate`") dead for the case it is
196
+ // most often given in.
197
+ if (!located.item && opensSequenceItem) {
198
+ const next = nextSiblingKeyStart(doc, path);
199
+ // Nothing to promote onto the dash: the entry is the item's only one, and
200
+ // removing it would leave `- ` with no value.
201
+ if (next === undefined)
202
+ return undefined;
203
+ // Only whitespace may be swallowed. A comment or anything else between the
204
+ // two entries would be destroyed by the splice, so that stays a hand edit.
205
+ const between = text.slice(located.end, next);
206
+ if (!/^\s*$/.test(between) || !between.includes("\n"))
207
+ return undefined;
208
+ return [{ start: located.start, end: next, newText: "" }];
209
+ }
210
+ return undefined;
211
+ }
212
+ /** Offset of the key of the entry FOLLOWING `path` in its own mapping, or
213
+ * `undefined` when `path` is the last entry (or anything is not a plain
214
+ * key-scalar pair). */
215
+ function nextSiblingKeyStart(doc, path) {
216
+ const map = nodeAt(doc, path.slice(0, -1));
217
+ if (!isMap(map))
218
+ return undefined;
219
+ const key = String(path[path.length - 1]);
220
+ const at = map.items.findIndex((item) => isPair(item) && isScalar(item.key) && String(item.key.value) === key);
221
+ if (at < 0)
222
+ return undefined;
223
+ const next = map.items[at + 1];
224
+ if (!isPair(next) || !isScalar(next.key))
225
+ return undefined;
226
+ return rangeOf(next.key)?.[0];
227
+ }
228
+ /** Span of a whole mapping entry (key through value) or sequence item. */
229
+ function locateEntry(doc, path) {
230
+ const last = path[path.length - 1];
231
+ if (typeof last === "string") {
232
+ const pair = pairAt(doc, path.slice(0, -1), last);
233
+ if (!isPair(pair) || !isScalar(pair.key))
234
+ return undefined;
235
+ const keyRange = rangeOf(pair.key);
236
+ const valueRange = rangeOf(pair.value) ?? keyRange;
237
+ if (!keyRange || !valueRange)
238
+ return undefined;
239
+ return { start: keyRange[0], end: valueRange[1], item: false };
240
+ }
241
+ const range = rangeOf(nodeAt(doc, path));
242
+ if (!range)
243
+ return undefined;
244
+ return { start: range[0], end: range[1], item: true };
245
+ }
@@ -1,11 +1,19 @@
1
1
  import type { Environment } from "@marcbachmann/cel-js";
2
2
  import type { LoadedFile } from "./loaded-types.js";
3
+ import type { MigrationEntry } from "./migrations/types.js";
3
4
  export interface ParseOptions {
4
5
  /** When true, runs `precompileDoc` per document and stamps compiled CEL
5
6
  * on the manifests — same flag `LoadOptions.compile` carries today. */
6
7
  compile?: boolean;
7
8
  /** CEL environment for precompile. Defaults to `buildCelEnvironment()`. */
8
9
  celEnv?: Environment;
10
+ /** When true, the migration phase runs over the parsed documents — legacy
11
+ * spellings rewritten to the current ones before anything else reads the
12
+ * tree. Off by default so a round-trip consumer (the editor) keeps the
13
+ * author's vocabulary; see `LoadOptions.migrate`. */
14
+ migrate?: boolean;
15
+ /** Migration set. Defaults to the analyzer's own `CORE_MIGRATIONS`. */
16
+ migrations?: readonly MigrationEntry[];
9
17
  }
10
18
  /** Pure: text in, structured load result out. No I/O, no caches. */
11
19
  export declare function parseLoadedFile(source: string, requestedUrl: string, text: string, options?: ParseOptions): LoadedFile;
@@ -1 +1 @@
1
- {"version":3,"file":"parse-loaded-file.d.ts","sourceRoot":"","sources":["../src/parse-loaded-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,mBAAmB,CAAC;AAKhE,MAAM,WAAW,YAAY;IAC3B;4EACwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA4BD,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,GACrB,UAAU,CAiDZ"}
1
+ {"version":3,"file":"parse-loaded-file.d.ts","sourceRoot":"","sources":["../src/parse-loaded-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,mBAAmB,CAAC;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,MAAM,WAAW,YAAY;IAC3B;4EACwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;0DAGsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uEAAuE;IACvE,UAAU,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACxC;AA4BD,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,GACrB,UAAU,CA2DZ"}
@@ -1,6 +1,7 @@
1
1
  import { defaultCustomTags } from "@telorun/templating";
2
2
  import { parseAllDocuments } from "yaml";
3
3
  import { buildCelEnvironment } from "./cel-environment.js";
4
+ import { migrateManifests, NO_MIGRATIONS } from "./migrations/driver.js";
4
5
  import { buildDocumentPositions } from "./position-metadata.js";
5
6
  import { precompileDoc } from "./precompile.js";
6
7
  import { documentToAst } from "./yaml-ast.js";
@@ -42,27 +43,34 @@ export function parseLoadedFile(source, requestedUrl, text, options) {
42
43
  });
43
44
  }
44
45
  });
45
- const manifests = [];
46
- let env;
47
- for (const doc of documents) {
46
+ const manifests = documents.map((doc) => {
48
47
  const raw = doc.toJSON();
49
- if (raw === null || raw === undefined) {
50
- manifests.push(null);
51
- continue;
52
- }
53
- if (options?.compile) {
48
+ return raw === null || raw === undefined ? null : raw;
49
+ });
50
+ // The migration phase, immediately after parse. It runs BEFORE precompile so
51
+ // matchers see the values the author wrote rather than `CompiledValue`
52
+ // wrappers, and — through the loader — before `desugarLoadedFile`, so a rule
53
+ // only ever matches author-written nodes: a synthetic Telo.Import manifest
54
+ // has no YAML document to edit, records a path the file never had, and
55
+ // carries its `variables` / `secrets` by reference from the module doc, so a
56
+ // match inside one would apply twice.
57
+ const migrations = options?.migrate
58
+ ? migrateManifests({ source, manifests, entries: options.migrations })
59
+ : NO_MIGRATIONS;
60
+ let env;
61
+ if (options?.compile) {
62
+ for (let i = 0; i < manifests.length; i++) {
63
+ const raw = manifests[i];
64
+ if (raw === null)
65
+ continue;
54
66
  env ??= options.celEnv ?? buildCelEnvironment();
55
67
  try {
56
- const compiled = precompileDoc(raw, env);
57
- manifests.push(compiled);
68
+ manifests[i] = precompileDoc(raw, env);
58
69
  }
59
70
  catch (error) {
60
71
  throw new Error(`Failed to compile manifest in ${source}: ${error instanceof Error ? error.message : String(error)}`);
61
72
  }
62
73
  }
63
- else {
64
- manifests.push(raw);
65
- }
66
74
  }
67
75
  return {
68
76
  source,
@@ -73,5 +81,6 @@ export function parseLoadedFile(source, requestedUrl, text, options) {
73
81
  manifests,
74
82
  positions,
75
83
  parseErrors,
84
+ migrations,
76
85
  };
77
86
  }
@@ -1,20 +1,37 @@
1
1
  import type { ResourceManifest } from "@telorun/sdk";
2
2
  import type { AliasResolver } from "./alias-resolver.js";
3
3
  /**
4
- * Rewrites import-scoped schema references in place. A `$ref` of the form
5
- * `telo://<authority>/<typeName>` names a `Type.JsonSchema` (or any `Telo.Type`)
6
- * reached through an import: `telo://Self/<type>` for the declaring module's own
7
- * type, `telo://<Alias>/<type>` for an imported module's. Each authority is
8
- * resolved to the owning module's name and the ref is rewritten to the canonical
9
- * `telo://<module>/<type>` the type registered its schema under.
4
+ * Rewrites schema references to their canonical, module-scoped form, in place.
10
5
  *
11
- * The version lives on the `imports:` entry, never the URI only the pinned
12
- * version is loaded, so the canonical id is version-free.
6
+ * A named shape is written with the reference tag `!ref File` for the declaring
7
+ * module's own, `!ref <Alias>.<File>` for one an imported library exports — which
8
+ * is Telo's ONE reference grammar, and `use: schema` has been in the `x-telo-ref`
9
+ * vocabulary for exactly this relation all along (*names a shape; no runtime
10
+ * instance, no edge*). Phase 2.5 has already turned the tag into `{kind, name,
11
+ * alias?}`; this pass turns that into `{ $ref: "telo:<module>/<type>" }`, the id
12
+ * the type registered its schema under.
13
13
  *
14
- * Already-canonical refs (authority is a real module name, not an alias) and
15
- * fragment-bearing built-ins (`telo://manifest#/$defs/ResourceRef`) are left
16
- * untouched: the former because the authority resolves to nothing, the latter
17
- * because they don't match the `authority/type` grammar.
14
+ * WHY NORMALIZE RATHER THAN RESOLVE. Substituting the shape itself would inline
15
+ * it, which changes schema identity — the compiled-validator cache is keyed on it
16
+ * and would make a self-recursive shape inexpressible. Keeping a REFERENCE is
17
+ * what every validator wants, and it is not an AJV concern: a Rust validator
18
+ * wants a registered id just as much. So the tag is the authoring surface and the
19
+ * canonical `$ref` is the internal form, exactly as `resolveRefSentinels` and
20
+ * `resolveSchemaRefKinds` already split authoring sugar from canonical form.
21
+ *
22
+ * ALIAS SCOPE IS WHAT THE CANONICAL FORM CARRIES. The authority is resolved in
23
+ * the DECLARING module's scope, so the id names the owning module and two
24
+ * libraries declaring a shape of the same name stay distinct. A downstream
25
+ * resolver reads the module off the id instead of matching a bare name, which is
26
+ * how an alias used to get silently dropped.
27
+ *
28
+ * The legacy authoring spelling `$ref: "telo://<authority>/<type>"` is resolved
29
+ * the same way, since a published artifact carries it. The version lives on the
30
+ * `imports:` entry, never the URI — only the pinned version is loaded, so the
31
+ * canonical id is version-free. Already-canonical refs and fragment-bearing
32
+ * built-ins (`telo://manifest#/$defs/ResourceRef`) are left untouched: the former
33
+ * because the authority resolves to nothing, the latter because they do not match
34
+ * the `authority/type` grammar.
18
35
  */
19
36
  export declare function resolveSchemaTypeRefs(resources: ResourceManifest[], aliases?: AliasResolver, aliasesByModule?: Map<string, AliasResolver>): void;
20
37
  //# sourceMappingURL=resolve-schema-type-refs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-schema-type-refs.d.ts","sourceRoot":"","sources":["../src/resolve-schema-type-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKzD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,IAAI,CAyBN"}
1
+ {"version":3,"file":"resolve-schema-type-refs.d.ts","sourceRoot":"","sources":["../src/resolve-schema-type-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,IAAI,CA6DN"}
@@ -2,28 +2,51 @@ import { canonicalTypeSchemaId, parseTeloTypeRef } from "@telorun/sdk";
2
2
  /** Schema-bearing fields on a Telo.Definition / Telo.Type resource. */
3
3
  const SCHEMA_FIELDS = ["schema", "inputType", "outputType"];
4
4
  /**
5
- * Rewrites import-scoped schema references in place. A `$ref` of the form
6
- * `telo://<authority>/<typeName>` names a `Type.JsonSchema` (or any `Telo.Type`)
7
- * reached through an import: `telo://Self/<type>` for the declaring module's own
8
- * type, `telo://<Alias>/<type>` for an imported module's. Each authority is
9
- * resolved to the owning module's name and the ref is rewritten to the canonical
10
- * `telo://<module>/<type>` the type registered its schema under.
5
+ * Rewrites schema references to their canonical, module-scoped form, in place.
11
6
  *
12
- * The version lives on the `imports:` entry, never the URI only the pinned
13
- * version is loaded, so the canonical id is version-free.
7
+ * A named shape is written with the reference tag `!ref File` for the declaring
8
+ * module's own, `!ref <Alias>.<File>` for one an imported library exports — which
9
+ * is Telo's ONE reference grammar, and `use: schema` has been in the `x-telo-ref`
10
+ * vocabulary for exactly this relation all along (*names a shape; no runtime
11
+ * instance, no edge*). Phase 2.5 has already turned the tag into `{kind, name,
12
+ * alias?}`; this pass turns that into `{ $ref: "telo:<module>/<type>" }`, the id
13
+ * the type registered its schema under.
14
14
  *
15
- * Already-canonical refs (authority is a real module name, not an alias) and
16
- * fragment-bearing built-ins (`telo://manifest#/$defs/ResourceRef`) are left
17
- * untouched: the former because the authority resolves to nothing, the latter
18
- * because they don't match the `authority/type` grammar.
15
+ * WHY NORMALIZE RATHER THAN RESOLVE. Substituting the shape itself would inline
16
+ * it, which changes schema identity — the compiled-validator cache is keyed on it
17
+ * and would make a self-recursive shape inexpressible. Keeping a REFERENCE is
18
+ * what every validator wants, and it is not an AJV concern: a Rust validator
19
+ * wants a registered id just as much. So the tag is the authoring surface and the
20
+ * canonical `$ref` is the internal form, exactly as `resolveRefSentinels` and
21
+ * `resolveSchemaRefKinds` already split authoring sugar from canonical form.
22
+ *
23
+ * ALIAS SCOPE IS WHAT THE CANONICAL FORM CARRIES. The authority is resolved in
24
+ * the DECLARING module's scope, so the id names the owning module and two
25
+ * libraries declaring a shape of the same name stay distinct. A downstream
26
+ * resolver reads the module off the id instead of matching a bare name, which is
27
+ * how an alias used to get silently dropped.
28
+ *
29
+ * The legacy authoring spelling `$ref: "telo://<authority>/<type>"` is resolved
30
+ * the same way, since a published artifact carries it. The version lives on the
31
+ * `imports:` entry, never the URI — only the pinned version is loaded, so the
32
+ * canonical id is version-free. Already-canonical refs and fragment-bearing
33
+ * built-ins (`telo://manifest#/$defs/ResourceRef`) are left untouched: the former
34
+ * because the authority resolves to nothing, the latter because they do not match
35
+ * the `authority/type` grammar.
19
36
  */
20
37
  export function resolveSchemaTypeRefs(resources, aliases, aliasesByModule) {
21
- const walk = (value, resolveAuthority) => {
38
+ const walk = (value, resolveAuthority, ownModule,
39
+ // The type field's OWN value is a declared reference slot (`x-telo-ref:
40
+ // Telo.Type`), with its own reference validation and its own editor picker.
41
+ // Only what sits INSIDE it is schema, and only schema is this pass's to
42
+ // canonicalize — rewriting the slot itself would hand the reference checker
43
+ // a shape it is right to reject.
44
+ isSlotRoot) => {
22
45
  if (value === null || typeof value !== "object")
23
46
  return;
24
47
  if (Array.isArray(value)) {
25
48
  for (const item of value)
26
- walk(item, resolveAuthority);
49
+ walk(item, resolveAuthority, ownModule, false);
27
50
  return;
28
51
  }
29
52
  const obj = value;
@@ -33,15 +56,65 @@ export function resolveSchemaTypeRefs(resources, aliases, aliasesByModule) {
33
56
  if (module)
34
57
  obj.$ref = canonicalTypeSchemaId(module, parsed.typeName);
35
58
  }
59
+ // A reference the tag left behind. Rewritten in place rather than replaced,
60
+ // so a node that carried siblings (a `title`, a `description`) keeps them —
61
+ // a `$ref` beside other keywords is ordinary JSON Schema.
62
+ const named = resolvedRefInSchema(obj);
63
+ if (named) {
64
+ const module = named.alias === undefined ? ownModule : resolveAuthority(named.alias);
65
+ // An unresolvable alias is left exactly as written: `validateReferences`
66
+ // is what reports a reference that names nothing, and guessing a module
67
+ // here would turn a typo into a `$ref` that resolves to the wrong shape.
68
+ if (module) {
69
+ const canonical = canonicalTypeSchemaId(module, named.name);
70
+ if (isSlotRoot) {
71
+ // At the slot root the reference STAYS a reference — the canonical id
72
+ // is stamped beside it. That is what makes the resolver alias-aware
73
+ // here: it reads the module off the id instead of matching a bare
74
+ // `metadata.name` across a flattened list, where two libraries
75
+ // declaring a shape of the same name collide silently.
76
+ obj.$ref = canonical;
77
+ }
78
+ else {
79
+ delete obj.kind;
80
+ delete obj.name;
81
+ delete obj.alias;
82
+ obj.$ref = canonical;
83
+ }
84
+ }
85
+ }
36
86
  for (const key of Object.keys(obj))
37
- walk(obj[key], resolveAuthority);
87
+ walk(obj[key], resolveAuthority, ownModule, false);
38
88
  };
39
89
  for (const r of resources) {
40
90
  const ownModule = r.metadata?.module;
41
91
  const resolver = (ownModule ? aliasesByModule?.get(ownModule) : undefined) ?? aliases;
42
92
  const resolveAuthority = (authority) => authority === "Self" ? ownModule : resolver?.moduleForAlias(authority);
43
93
  for (const field of SCHEMA_FIELDS) {
44
- walk(r[field], resolveAuthority);
94
+ walk(r[field], resolveAuthority, ownModule, true);
45
95
  }
46
96
  }
47
97
  }
98
+ /**
99
+ * A resolved `!ref` sitting where a schema belongs, or null.
100
+ *
101
+ * Recognised structurally: Phase 2.5 writes `{kind, name, alias?}` and nothing
102
+ * else, and a node carrying JSON Schema keywords is a schema that happens to be
103
+ * beside one rather than a reference. Being conservative here is the safe
104
+ * direction — a node this declines to rewrite stays a reference for
105
+ * `validateReferences` to judge, while one it rewrote wrongly would silently
106
+ * become a different shape.
107
+ */
108
+ function resolvedRefInSchema(obj) {
109
+ if (typeof obj.kind !== "string" || typeof obj.name !== "string")
110
+ return null;
111
+ for (const key of Object.keys(obj)) {
112
+ // `$ref` is allowed so the pass is idempotent at a slot root, where the id
113
+ // is stamped BESIDE the reference rather than replacing it.
114
+ if (key !== "kind" && key !== "name" && key !== "alias" && key !== "$ref")
115
+ return null;
116
+ }
117
+ return typeof obj.alias === "string"
118
+ ? { name: obj.name, alias: obj.alias }
119
+ : { name: obj.name };
120
+ }
@@ -12,10 +12,29 @@ export interface CompatibilityResult {
12
12
  compatible: boolean;
13
13
  issues: string[];
14
14
  }
15
- /** Conservative structural JSON Schema compatibility check.
16
- * Only flags definite mismatches: missing required fields and primitive type conflicts.
17
- * Ambiguous cases (anyOf/oneOf/etc.) are treated as compatible. */
18
- export declare function checkSchemaCompatibility(source: Record<string, any>, target: Record<string, any>): CompatibilityResult;
15
+ /**
16
+ * Conservative structural JSON Schema compatibility check is a value shaped
17
+ * like `source` acceptable where `target` is declared?
18
+ *
19
+ * COVARIANT, because the values this compares are consumed by reading: a
20
+ * narrower element satisfies a slot declaring a wider one. Only DEFINITE
21
+ * mismatches are flagged — a missing required field, a primitive type conflict,
22
+ * a disagreeing type argument. Anything ambiguous (`anyOf` / `oneOf` / `allOf`,
23
+ * an absent `type`, an undeclared argument) is treated as compatible, so an
24
+ * unmigrated producer and consumer keep checking exactly as they did.
25
+ *
26
+ * The traversal is written here rather than reused: the function this replaced
27
+ * compared only `type` for the names in `target.required` and descended only
28
+ * into objects, so a stream of arrays of strings and a stream of arrays of
29
+ * integers both read as `array` and passed — leaving argument checking inert on
30
+ * exactly the nested shapes it exists for. What survives from it is its posture.
31
+ *
32
+ * `resolveRef` sees through a named shape. Declaring a shape once and
33
+ * referencing it is the sanctioned way to reuse one, so without it two such
34
+ * arguments present as opaque nodes carrying no information — the same reason
35
+ * {@link withLiveValuesSkipped} takes one.
36
+ */
37
+ export declare function checkSchemaCompatibility(source: Record<string, any>, target: Record<string, any>, resolveRef?: (ref: string) => Record<string, any> | undefined): CompatibilityResult;
19
38
  export declare function formatSingleError(err: any): string;
20
39
  export declare function formatAjvErrors(errors: any[] | null | undefined): string;
21
40
  /** A schema validation issue with a dotted-path pointer to the offending field. */
@@ -36,14 +55,21 @@ export declare function navigateJsonPointer(schema: unknown, pointer: string): u
36
55
  * Returns `undefined` if any segment cannot be resolved. */
37
56
  export declare function navigateSchemaToExprPath(schema: Record<string, any>, path: string): Record<string, any> | undefined;
38
57
  /**
39
- * Recognized `x-telo-type` value brands and the CEL primitive each refines.
58
+ * Every `json`-represented value type's CEL brand → the primitive it refines.
59
+ *
40
60
  * A brand is a nominal type the analyzer registers (see cel-environment.ts) so
41
- * structurally-identical values (a `TcpPort` and a `UdpPort` are both integers)
42
- * stay distinct for static wiring checks. Brands carry no runtime effect — the
43
- * value flows as its base type. Add new brands here (e.g. `Url: "string"`).
61
+ * structurally-identical values (a `Telo.TcpPort` and a `Telo.UdpPort` are both
62
+ * integers) stay distinct for static wiring checks. Brands carry no runtime
63
+ * effect — the value flows as its base type.
64
+ *
65
+ * DERIVED from the value-type vocabulary, never hand-written: a new brand is a
66
+ * new entry file, and a table here would be a second place to edit that could
67
+ * silently disagree with the one the runtime reads.
44
68
  */
45
69
  export declare const VALUE_BRAND_BASE: Record<string, string>;
46
- /** Read a recognized `x-telo-type` brand off a schema, or undefined. */
70
+ /** Read a `json`-represented value type's brand off a schema, or undefined.
71
+ * An `instance` type is not a brand — it replaces the JSON layer rather than
72
+ * refining it, so it carries its binding's CEL type instead. */
47
73
  export declare function brandOfSchema(schema: Record<string, any> | undefined): string | undefined;
48
74
  /** Map a JSON Schema type annotation to a CEL type string. */
49
75
  export declare function jsonSchemaToCelType(schema: Record<string, any> | undefined): string;
@@ -1 +1 @@
1
- {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,GAAG,KAA0C,CAAC;AAEpD;;;;;;;mCAOmC;AACnC,wBAAgB,SAAS,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,CAWpD;AAKD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;oEAEoE;AACpE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,mBAAmB,CAIrB;AAiDD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAelD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGxE;AAuBD,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAaD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,EAAE,CA2B/F;AAED;qFACqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ7E;AAED;;;;6DAI6D;AAC7D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAsBjC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzF;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CAyBnF;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAiChG;AAkED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CA0C/E;AAqBD,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOtG;AAyDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAwBlF;AAED;iGACiG;AACjG,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAChC;;;;;;;;6DAQ6D;AAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACrC,IAAI,SAAK,GACR,OAAO,CA2DT"}
1
+ {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"AAkBA,QAAA,MAAM,GAAG,KAA0C,CAAC;AAEpD;;;;;;;mCAOmC;AACnC,wBAAgB,SAAS,IAAI,YAAY,CAAC,OAAO,GAAG,CAAC,CAYpD;AAKD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,mBAAmB,CAIrB;AAyID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAelD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGxE;AAuBD,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAaD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,EAAE,CAsB/F;AAED;qFACqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ7E;AAED;;;;6DAI6D;AAC7D,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAsBjC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAqB,CAAC;AAE1E;;iEAEiE;AACjE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzF;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CA6BnF;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CA2ChG;AAkED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CA8C/E;AAqBD,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOtG;AAyDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAwBlF;AAED;iGACiG;AACjG,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAChC;;;;;;;;6DAQ6D;AAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACrC,IAAI,SAAK,GACR,OAAO,CAiET"}