@telorun/ide-support 0.23.0 → 0.102.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 (42) hide show
  1. package/dist/completions/build.d.ts.map +1 -1
  2. package/dist/completions/build.js +7 -0
  3. package/dist/completions/detect-context.d.ts +33 -0
  4. package/dist/completions/detect-context.d.ts.map +1 -1
  5. package/dist/completions/detect-context.js +52 -0
  6. package/dist/completions/module-file-completions.d.ts +18 -0
  7. package/dist/completions/module-file-completions.d.ts.map +1 -0
  8. package/dist/completions/module-file-completions.js +59 -0
  9. package/dist/completions/resolve-node.d.ts +23 -5
  10. package/dist/completions/resolve-node.d.ts.map +1 -1
  11. package/dist/completions/resolve-node.js +54 -14
  12. package/dist/completions/value-tag-completions.d.ts +23 -0
  13. package/dist/completions/value-tag-completions.d.ts.map +1 -0
  14. package/dist/completions/value-tag-completions.js +39 -0
  15. package/dist/import-upgrades/build-import-upgrades.d.ts +3 -3
  16. package/dist/import-upgrades/build-import-upgrades.d.ts.map +1 -1
  17. package/dist/import-upgrades/index.d.ts +0 -1
  18. package/dist/import-upgrades/index.d.ts.map +1 -1
  19. package/dist/import-upgrades/index.js +0 -1
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -0
  23. package/dist/types.d.ts +13 -1
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/value-tags/offered-value-tags.d.ts +56 -0
  26. package/dist/value-tags/offered-value-tags.d.ts.map +1 -0
  27. package/dist/value-tags/offered-value-tags.js +92 -0
  28. package/package.json +3 -2
  29. package/src/completions/build.ts +6 -0
  30. package/src/completions/detect-context.ts +84 -0
  31. package/src/completions/module-file-completions.ts +64 -0
  32. package/src/completions/resolve-node.ts +87 -19
  33. package/src/completions/value-tag-completions.ts +55 -0
  34. package/src/import-upgrades/build-import-upgrades.ts +3 -3
  35. package/src/import-upgrades/index.ts +0 -1
  36. package/src/index.ts +2 -0
  37. package/src/types.ts +22 -1
  38. package/src/value-tags/offered-value-tags.ts +127 -0
  39. package/dist/import-upgrades/parse-module-versions.d.ts +0 -19
  40. package/dist/import-upgrades/parse-module-versions.d.ts.map +0 -1
  41. package/dist/import-upgrades/parse-module-versions.js +0 -29
  42. package/src/import-upgrades/parse-module-versions.ts +0 -30
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/completions/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAqK3E,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,qBAAqB,EAC/B,IAAI,CAAC,EAAE,WAAW,EAAE;AACpB;;gCAEgC;AAChC,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAuD7B"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/completions/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAuK3E,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,qBAAqB,EAC/B,IAAI,CAAC,EAAE,WAAW,EAAE;AACpB;;gCAEgC;AAChC,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2D7B"}
@@ -4,6 +4,8 @@ import { celCompletions } from "./cel-completions.js";
4
4
  import { docIdentity } from "../doc-identity.js";
5
5
  import { detectContext, lookupRefConstraints, navigateSchema } from "./detect-context.js";
6
6
  import { importSourceCompletions } from "./import-source.js";
7
+ import { moduleFileCompletions } from "./module-file-completions.js";
8
+ import { valueTagCompletions } from "./value-tag-completions.js";
7
9
  import { propKeyCompletions } from "./prop-keys.js";
8
10
  import { CAPABILITY_VALUES } from "./valid-capabilities.js";
9
11
  /** Read the top-level `kind` and `metadata.name` scalar of each document from
@@ -151,6 +153,11 @@ analysis) {
151
153
  }
152
154
  if (ctx.type === "capability")
153
155
  return capabilityCompletions();
156
+ if (ctx.type === "value-tag")
157
+ return valueTagCompletions(ctx, registry);
158
+ if (ctx.type === "module-file") {
159
+ return moduleFileCompletions(ctx.names, ctx.prefix, ctx.replaceRange, adapter);
160
+ }
154
161
  if (ctx.type === "value-suggestions") {
155
162
  return valueSuggestions(registry, ctx.docKind, ctx.yamlPath, ctx.replaceRange);
156
163
  }
@@ -74,6 +74,30 @@ export type CompletionCtx = {
74
74
  segment: CelSegment;
75
75
  /** Cursor as a document offset. */
76
76
  offset: number;
77
+ } | {
78
+ /** Cursor sits on a value's YAML tag (`root: !mo|`). What is offered is
79
+ * every tag the field takes, so its schema is addressed relative to the
80
+ * nearest enclosing resource. */
81
+ type: "value-tag";
82
+ /** Absent at a document declaring no resource kind. */
83
+ kind?: string;
84
+ yamlPath: string[];
85
+ /** Resource-relative, sequence indices kept — what the eval mode is
86
+ * resolved at. */
87
+ concretePath: string;
88
+ /** The value is a sequence item, so the field's schema is its item's. */
89
+ isItem: boolean;
90
+ /** Nothing follows the tag yet, so a pick may lead into the value. */
91
+ bare: boolean;
92
+ replaceRange: ReplaceRange;
93
+ } | {
94
+ /** Cursor sits in the value of a tag naming a location inside the module
95
+ * (`!module-path ./pu|`). */
96
+ type: "module-file";
97
+ names: "file" | "file-or-directory";
98
+ /** Text from the start of the value to the cursor. */
99
+ prefix: string;
100
+ replaceRange: ReplaceRange;
77
101
  };
78
102
  /**
79
103
  * Resolves an `x-telo-schema-from` annotation to the schema it derives. Supplied
@@ -89,6 +113,15 @@ export type SchemaFromResolver = (schemaFrom: string) => Record<string, any> | u
89
113
  * intersection — enough for propKeyCompletions to surface every key a value at
90
114
  * this slot can legally carry. */
91
115
  export declare function navigateSchema(schema: Record<string, any>, path: string[], schemaFrom?: SchemaFromResolver): Record<string, any> | undefined;
116
+ /**
117
+ * The schema of the field at `path`, as DECLARED — combinators kept.
118
+ *
119
+ * `navigateSchema` merges a leaf's branches into one object node, which is what
120
+ * key completion wants and exactly what a type comparison must not see: a
121
+ * `Telo.HostPath` branch of an `anyOf` stops being one. `isItem` selects the
122
+ * field's item schema, for a value written as a sequence item.
123
+ */
124
+ export declare function fieldSchemaAt(schema: Record<string, any>, path: string[], isItem: boolean, schemaFrom?: SchemaFromResolver): Record<string, any> | undefined;
92
125
  /** Walks up and down from `cursorLine` looking for a sibling line at the
93
126
  * exact same indent whose key is `kind`. The value of the first such line
94
127
  * is returned (alias form, e.g. `"Sql.Connection"`). Used by ref-name
@@ -1 +1 @@
1
- {"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,MAAM,CAAC;IACb;;;uEAGmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;+BAE2B;IAC3B,YAAY,EAAE,YAAY,CAAC;CAC5B,GACD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;2BAEuB;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B,GACD;IACE;;;gDAG4C;IAC5C,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;6DACyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC5B,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,YAAY,EAAE,YAAY,CAAC;CAC5B,GACD;IACE;;;gCAG4B;IAC5B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;CAC5B,GACD;IACE;;;;wDAIoD;IACpD,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;+CAC2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB;uBACmB;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAyEN;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;AA0BzF;;;;;;mCAMmC;AACnC,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,CAAC,EAAE,kBAAkB,GAC9B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA6CjC;AAwCD;;;;;wDAKwD;AACxD;;;;;;;sBAOsB;AACtB,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,CAAC,EAAE,kBAAkB,GAC9B,MAAM,EAAE,CAIV;AAED;;;;oBAIoB;AACpB,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,WAAW,EAAE,GACnB,aAAa,GAAG,SAAS,CAqF3B"}
1
+ {"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { parseToAst, readRefSlot, refSlotAnnotation, } from "@telorun/analyzer";
2
+ import { valueTag } from "../value-tags/offered-value-tags.js";
2
3
  import { resolveNodeAtPosition } from "./resolve-node.js";
3
4
  /** Returns every schema branch reachable from `node` after peeling `anyOf` /
4
5
  * `oneOf` recursively. A branch with no combinators is its own only entry.
@@ -153,6 +154,35 @@ export function navigateSchema(schema, path, schemaFrom) {
153
154
  return leaves[0];
154
155
  return unionLeaves(current, leaves);
155
156
  }
157
+ /**
158
+ * The schema of the field at `path`, as DECLARED — combinators kept.
159
+ *
160
+ * `navigateSchema` merges a leaf's branches into one object node, which is what
161
+ * key completion wants and exactly what a type comparison must not see: a
162
+ * `Telo.HostPath` branch of an `anyOf` stops being one. `isItem` selects the
163
+ * field's item schema, for a value written as a sequence item.
164
+ */
165
+ export function fieldSchemaAt(schema, path, isItem, schemaFrom) {
166
+ if (path.length === 0)
167
+ return undefined;
168
+ const parent = navigateSchema(schema, path.slice(0, -1), schemaFrom);
169
+ const key = path[path.length - 1];
170
+ let field = parent?.properties?.[key] ?? parent?.additionalProperties;
171
+ if (!field || typeof field !== "object")
172
+ return undefined;
173
+ field = resolveLocalRef(field, schema);
174
+ if (isItem) {
175
+ while (field?.type === "array" && field.items)
176
+ field = resolveLocalRef(field.items, schema);
177
+ }
178
+ return field;
179
+ }
180
+ /** `concretePath` relative to the resource map at `resourceConcrete`. */
181
+ function relativeConcretePath(concretePath, resourceConcrete) {
182
+ if (!resourceConcrete)
183
+ return concretePath;
184
+ return concretePath.slice(resourceConcrete.length).replace(/^\./, "");
185
+ }
156
186
  /** Merge multiple peeled schema branches into one node for completion purposes.
157
187
  * Property maps are unioned (first branch wins on key collision). `required`
158
188
  * becomes the intersection so optional-in-any-branch keys still surface.
@@ -216,6 +246,28 @@ export function detectContext(text, line, character, docs) {
216
246
  return undefined;
217
247
  const { docKind } = resolved;
218
248
  if (resolved.slot === "value") {
249
+ const tag = resolved.tag;
250
+ if (tag?.prefix !== undefined) {
251
+ const depth = resolved.resourceDepth ?? 0;
252
+ return {
253
+ type: "value-tag",
254
+ kind: resolved.resourceKind ?? docKind,
255
+ yamlPath: resolved.path.slice(depth),
256
+ concretePath: relativeConcretePath(resolved.concretePath ?? "", resolved.resourceConcretePath ?? ""),
257
+ isItem: resolved.container === undefined,
258
+ bare: tag.bare,
259
+ replaceRange: tag.replaceRange,
260
+ };
261
+ }
262
+ const names = tag ? valueTag(tag.text.slice(1))?.names : undefined;
263
+ if (names && resolved.replaceRange) {
264
+ return {
265
+ type: "module-file",
266
+ names,
267
+ prefix: resolved.prefix ?? "",
268
+ replaceRange: resolved.replaceRange,
269
+ };
270
+ }
219
271
  // Inside a CEL body — structural completion does not apply; what completes
220
272
  // are the names the expression may use.
221
273
  if (resolved.cel) {
@@ -0,0 +1,18 @@
1
+ import type { CompletionResult, IdeEnvironmentAdapter, ReplaceRange } from "../types.js";
2
+ /**
3
+ * Completions for the value of a tag naming a location inside the module
4
+ * (`!include-text`, `!include-bytes`, `!module-path`).
5
+ *
6
+ * Paths are measured from the MODULE ROOT, never from the declaring file, so the
7
+ * listing is asked of the host against that root. The typed text up to its last
8
+ * `/` is the directory listed, and is kept on every insertion, so `./` stays
9
+ * where the author wrote it. A directory is a value in its own right where the
10
+ * tag may name one; where it names a file, a directory is only a way down, so a
11
+ * pick inserts its `/` and reopens completion. Dot-entries are listed only once
12
+ * the typed name starts with `.`, as a shell completes them.
13
+ *
14
+ * Nothing is offered above the root or for an absolute or URL-shaped path: the
15
+ * tag refuses those, and a listing there would offer what cannot be written.
16
+ */
17
+ export declare function moduleFileCompletions(names: "file" | "file-or-directory", prefix: string, replaceRange: ReplaceRange, adapter: IdeEnvironmentAdapter | undefined): Promise<CompletionResult[]>;
18
+ //# sourceMappingURL=module-file-completions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-file-completions.d.ts","sourceRoot":"","sources":["../../src/completions/module-file-completions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKzF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EACnC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,qBAAqB,GAAG,SAAS,GACzC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAyB7B"}
@@ -0,0 +1,59 @@
1
+ /** Caps one listing; a popover shows far fewer. */
2
+ const ENTRY_LIMIT = 200;
3
+ /**
4
+ * Completions for the value of a tag naming a location inside the module
5
+ * (`!include-text`, `!include-bytes`, `!module-path`).
6
+ *
7
+ * Paths are measured from the MODULE ROOT, never from the declaring file, so the
8
+ * listing is asked of the host against that root. The typed text up to its last
9
+ * `/` is the directory listed, and is kept on every insertion, so `./` stays
10
+ * where the author wrote it. A directory is a value in its own right where the
11
+ * tag may name one; where it names a file, a directory is only a way down, so a
12
+ * pick inserts its `/` and reopens completion. Dot-entries are listed only once
13
+ * the typed name starts with `.`, as a shell completes them.
14
+ *
15
+ * Nothing is offered above the root or for an absolute or URL-shaped path: the
16
+ * tag refuses those, and a listing there would offer what cannot be written.
17
+ */
18
+ export async function moduleFileCompletions(names, prefix, replaceRange, adapter) {
19
+ if (!adapter || /^["']/.test(prefix))
20
+ return [];
21
+ const lastSlash = prefix.lastIndexOf("/");
22
+ const dirPart = prefix.slice(0, lastSlash + 1);
23
+ const namePart = prefix.slice(lastSlash + 1);
24
+ if (!staysInModule(dirPart))
25
+ return [];
26
+ const entries = await adapter.listModuleEntries(dirPart === "" ? "." : dirPart);
27
+ return entries
28
+ .filter((e) => e.name.startsWith(namePart) && (namePart.startsWith(".") || !e.name.startsWith(".")))
29
+ .sort((a, b) => Number(b.directory) - Number(a.directory) || a.name.localeCompare(b.name))
30
+ .slice(0, ENTRY_LIMIT)
31
+ .map((entry) => {
32
+ const navigateOnly = entry.directory && names === "file";
33
+ const path = dirPart + entry.name + (navigateOnly ? "/" : "");
34
+ return {
35
+ label: entry.directory ? `${entry.name}/` : entry.name,
36
+ kind: entry.directory ? "folder" : "file",
37
+ insertText: path,
38
+ filterText: path,
39
+ replaceRange,
40
+ retrigger: navigateOnly,
41
+ sortText: `${entry.directory ? 0 : 1}_${entry.name}`,
42
+ };
43
+ });
44
+ }
45
+ /** Whether a module-root-relative directory stays inside the module. Pure string
46
+ * work, by the rule the tags' own path grammar applies. */
47
+ function staysInModule(dir) {
48
+ if (/^([/\\]|[a-z][a-z0-9+.-]*:)/i.test(dir))
49
+ return false;
50
+ let depth = 0;
51
+ for (const segment of dir.split(/[/\\]+/)) {
52
+ if (segment === "" || segment === ".")
53
+ continue;
54
+ depth += segment === ".." ? -1 : 1;
55
+ if (depth < 0)
56
+ return false;
57
+ }
58
+ return true;
59
+ }
@@ -34,13 +34,18 @@ export interface ResolvedCursor {
34
34
  /** Key slot: keys already present in the container (the key under the cursor
35
35
  * excluded so it still suggests itself). */
36
36
  existingKeys?: Set<string>;
37
- /** Key slot: the kind of the nearest enclosing inline resource (or the root
38
- * resource), whose schema the prop keys are completed against. Falls back to
39
- * the document kind at the root. */
37
+ /** The kind of the nearest enclosing inline resource (or the root resource),
38
+ * whose schema the slot is completed against. Absent at a root declaring no
39
+ * resource kind. */
40
40
  resourceKind?: string;
41
- /** Key slot: number of `path` segments that reach `resourceKind`'s map, so
42
- * the schema-relative path is `path.slice(resourceDepth)`. */
41
+ /** Number of `path` segments that reach `resourceKind`'s map, so the
42
+ * schema-relative path is `path.slice(resourceDepth)`. */
43
43
  resourceDepth?: number;
44
+ /** Value slot: the concrete path of `resourceKind`'s map, so the
45
+ * resource-relative concrete path is what follows it in `concretePath`. */
46
+ resourceConcretePath?: string;
47
+ /** Value slot: the scalar's tag, when written out in front of it. */
48
+ tag?: ResolvedTag;
44
49
  /** The path with sequence INDICES kept (`routes[0].handler.url`),
45
50
  * as distinct from `path`, through which arrays are transparent. This is the
46
51
  * address the analyzer speaks — an `x-telo-context` scope, an error-bearing
@@ -55,6 +60,19 @@ export interface ResolvedCursor {
55
60
  offset: number;
56
61
  };
57
62
  }
63
+ export interface ResolvedTag {
64
+ /** The tag as written, `!` included. */
65
+ text: string;
66
+ replaceRange: {
67
+ start: Position;
68
+ end: Position;
69
+ };
70
+ /** Set when the cursor sits on the tag: its text up to the cursor. */
71
+ prefix?: string;
72
+ /** True when nothing follows the tag on its line — the value is still to be
73
+ * written. */
74
+ bare: boolean;
75
+ }
58
76
  export declare function scalarString(node: AstNode | undefined): string | undefined;
59
77
  /** Resolve `(line, character)` against the AST (Approach B: AST for structure,
60
78
  * cursor column only to place empty-space key positions). */
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-node.d.ts","sourceRoot":"","sources":["../../src/completions/resolve-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,OAAO,EAEZ,KAAK,UAAU,EACf,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAE3B;;;;0CAI0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;sCAGkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB;4DACwD;IACxD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,CAAC;IAClD,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;gFAC4E;IAC5E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;gCAC4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;iDAC6C;IAC7C,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B;;yCAEqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;mEAC+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;oCAIgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;mDAE+C;IAC/C,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG1E;AA8SD;8DAC8D;AAC9D,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,WAAW,EAAE,EACnB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,cAAc,GAAG,SAAS,CAoG5B"}
1
+ {"version":3,"file":"resolve-node.d.ts","sourceRoot":"","sources":["../../src/completions/resolve-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,OAAO,EAEZ,KAAK,UAAU,EACf,KAAK,QAAQ,EACd,MAAM,mBAAmB,CAAC;AAE3B;;;;0CAI0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;sCAGkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB;4DACwD;IACxD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,CAAC;IAClD,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;gFAC4E;IAC5E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;gCAC4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;iDAC6C;IAC7C,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B;;yBAEqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;+DAC2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;gFAC4E;IAC5E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB;;;;oCAIgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;mDAE+C;IAC/C,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,QAAQ,CAAA;KAAE,CAAC;IACjD,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;mBACe;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG1E;AAkVD;8DAC8D;AAC9D,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,WAAW,EAAE,EACnB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,cAAc,GAAG,SAAS,CAoH5B"}
@@ -32,17 +32,37 @@ function resourceKindOf(map) {
32
32
  const kind = siblingKindOf(map);
33
33
  return kind && /^\w+\.\w+/.test(kind) ? kind : undefined;
34
34
  }
35
- function enter(scope, map, ancestorsLen) {
35
+ const ROOT_SCOPE = { depth: 0, concrete: "" };
36
+ function enter(scope, map, ancestorsLen, concrete) {
36
37
  const kind = resourceKindOf(map);
37
- return kind ? { kind, depth: ancestorsLen } : scope;
38
+ return kind ? { kind, depth: ancestorsLen, concrete } : scope;
39
+ }
40
+ /** The span of a scalar's tag, when it is written out in front of the value.
41
+ * The AST's range covers the value alone; the tag precedes it, separated by
42
+ * whitespace — or ends exactly at the range for a tag with no value yet. A tag
43
+ * whose text does not read back verbatim (`!!str`, which the parser expands)
44
+ * has no span. */
45
+ function tagSpan(node, text) {
46
+ if (node.kind !== "scalar" || !node.tag)
47
+ return undefined;
48
+ let end = node.range[0];
49
+ while (end > 0 && /\s/.test(text[end - 1]))
50
+ end--;
51
+ const start = end - node.tag.length;
52
+ return start >= 0 && text.slice(start, end) === node.tag ? [start, end] : undefined;
53
+ }
54
+ /** A value's span with its tag included, so a cursor on the tag is on the value. */
55
+ function valueSpan(node, text) {
56
+ const tag = tagSpan(node, text);
57
+ return tag ? [tag[0], node.range[1]] : node.range;
38
58
  }
39
59
  /** Append one key segment to a concrete path (`routes[0]` + `handler`). */
40
60
  function joinKey(concrete, key) {
41
61
  return concrete ? `${concrete}.${key}` : key;
42
62
  }
43
- function descend(node, ancestors, concrete, offset, scope) {
63
+ function descend(node, ancestors, concrete, offset, scope, text) {
44
64
  if (node.kind === "map") {
45
- const mapScope = enter(scope, node, ancestors.length);
65
+ const mapScope = enter(scope, node, ancestors.length, concrete);
46
66
  for (const pair of node.entries) {
47
67
  const keyName = scalarString(pair.key);
48
68
  if (within(pair.key.range, offset)) {
@@ -56,11 +76,13 @@ function descend(node, ancestors, concrete, offset, scope) {
56
76
  scope: mapScope,
57
77
  };
58
78
  }
59
- if (pair.value && within(pair.value.range, offset)) {
79
+ if (pair.value && within(valueSpan(pair.value, text), offset)) {
60
80
  const childAncestors = keyName != null ? [...ancestors, keyName] : ancestors;
61
81
  const childConcrete = keyName != null ? joinKey(concrete, keyName) : concrete;
62
82
  if (pair.value.kind === "map" || pair.value.kind === "seq") {
63
- return descend(pair.value, childAncestors, childConcrete, offset, mapScope) ?? { type: "empty" };
83
+ return (descend(pair.value, childAncestors, childConcrete, offset, mapScope, text) ?? {
84
+ type: "empty",
85
+ });
64
86
  }
65
87
  return {
66
88
  type: "value",
@@ -70,6 +92,7 @@ function descend(node, ancestors, concrete, offset, scope) {
70
92
  keyName,
71
93
  keyEnd: pair.key.range[1],
72
94
  valueNode: pair.value,
95
+ scope: mapScope,
73
96
  };
74
97
  }
75
98
  }
@@ -81,10 +104,10 @@ function descend(node, ancestors, concrete, offset, scope) {
81
104
  // `x-telo-context` scope, an error-bearing region and a step's identity are
82
105
  // all addressed per item, so a CEL site is unreachable without the index.
83
106
  for (const [index, item] of node.items.entries()) {
84
- if (within(item.range, offset)) {
107
+ if (within(valueSpan(item, text), offset)) {
85
108
  const itemConcrete = `${concrete}[${index}]`;
86
109
  if (item.kind === "map" || item.kind === "seq") {
87
- return descend(item, ancestors, itemConcrete, offset, scope) ?? { type: "empty" };
110
+ return descend(item, ancestors, itemConcrete, offset, scope, text) ?? { type: "empty" };
88
111
  }
89
112
  // A bare scalar list item (`targets:\n - One`) has no enclosing map of
90
113
  // keyed siblings — leave `container` undefined rather than treating the
@@ -96,6 +119,7 @@ function descend(node, ancestors, concrete, offset, scope) {
96
119
  concretePath: itemConcrete,
97
120
  keyEnd: item.range[0],
98
121
  valueNode: item,
122
+ scope,
99
123
  };
100
124
  }
101
125
  }
@@ -105,7 +129,7 @@ function descend(node, ancestors, concrete, offset, scope) {
105
129
  }
106
130
  function collectScopes(node, ancestors, concrete, scope, lineOffsets, maps, pairs) {
107
131
  if (node.kind === "map") {
108
- const mapScope = enter(scope, node, ancestors.length);
132
+ const mapScope = enter(scope, node, ancestors.length, concrete);
109
133
  const keys = new Set();
110
134
  let childColumn = -1;
111
135
  for (const pair of node.entries) {
@@ -160,7 +184,7 @@ function collectScopes(node, ancestors, concrete, scope, lineOffsets, maps, pair
160
184
  function columnSearch(root, cursorColumn, cursorOffset, lineOffsets) {
161
185
  const maps = [];
162
186
  const pairs = [];
163
- collectScopes(root, [], "", { depth: 0 }, lineOffsets, maps, pairs);
187
+ collectScopes(root, [], "", ROOT_SCOPE, lineOffsets, maps, pairs);
164
188
  // Sibling level: a map whose children already sit at the cursor's column.
165
189
  let sibling;
166
190
  for (const m of maps) {
@@ -196,7 +220,7 @@ function columnSearch(root, cursorColumn, cursorOffset, lineOffsets) {
196
220
  scope: nest.scope,
197
221
  };
198
222
  }
199
- return { path: [], concrete: "", existingKeys: new Set(), scope: { depth: 0 } };
223
+ return { path: [], concrete: "", existingKeys: new Set(), scope: ROOT_SCOPE };
200
224
  }
201
225
  // ---------------------------------------------------------------------------
202
226
  function selectDoc(docs, offset) {
@@ -227,7 +251,7 @@ export function resolveNodeAtPosition(text, docs, line, character) {
227
251
  return undefined;
228
252
  const doc = docs[docIndex];
229
253
  const docKind = docKindOf(doc);
230
- const found = doc.root ? descend(doc.root, [], "", offset, { depth: 0 }) : undefined;
254
+ const found = doc.root ? descend(doc.root, [], "", offset, ROOT_SCOPE, text) : undefined;
231
255
  // Cursor sits on an existing map key → key/prop-key position.
232
256
  if (found?.type === "key") {
233
257
  const existingKeys = new Set();
@@ -280,6 +304,17 @@ export function resolveNodeAtPosition(text, docs, line, character) {
280
304
  };
281
305
  }
282
306
  const clampedEnd = Math.min(offset, value.range[1]);
307
+ const span = tagSpan(value, text);
308
+ let tag;
309
+ if (span) {
310
+ const lineEnd = text.indexOf("\n", span[1]);
311
+ tag = {
312
+ text: value.tag,
313
+ replaceRange: { start: toPos(span[0]), end: toPos(span[1]) },
314
+ prefix: within(span, offset) ? text.slice(span[0], offset) : undefined,
315
+ bare: text.slice(span[1], lineEnd < 0 ? text.length : lineEnd).trim() === "",
316
+ };
317
+ }
283
318
  return {
284
319
  docIndex,
285
320
  offset,
@@ -293,14 +328,19 @@ export function resolveNodeAtPosition(text, docs, line, character) {
293
328
  spaceAfterColon: value.range[0] - found.keyEnd >= 2,
294
329
  siblingKind: found.container ? siblingKindOf(found.container) : undefined,
295
330
  replaceRange: { start: toPos(value.range[0]), end: toPos(value.range[1]) },
296
- cel,
331
+ resourceKind: found.scope.kind,
332
+ resourceDepth: found.scope.depth,
333
+ resourceConcretePath: found.scope.concrete,
334
+ tag,
335
+ // The tag is not the value: a cursor on it is not inside its expression.
336
+ cel: tag?.prefix !== undefined ? undefined : cel,
297
337
  };
298
338
  }
299
339
  // Empty space (blank line, trailing indent, empty document) → key position,
300
340
  // resolved by cursor column.
301
341
  const resolution = doc.root
302
342
  ? columnSearch(doc.root, character, offset, lineOffsets)
303
- : { path: [], concrete: "", existingKeys: new Set(), scope: { depth: 0 } };
343
+ : { path: [], concrete: "", existingKeys: new Set(), scope: ROOT_SCOPE };
304
344
  return {
305
345
  docIndex,
306
346
  offset,
@@ -0,0 +1,23 @@
1
+ import type { AnalysisRegistry } from "@telorun/analyzer";
2
+ import type { CompletionResult, ReplaceRange } from "../types.js";
3
+ export interface ValueTagSite {
4
+ kind?: string;
5
+ yamlPath: string[];
6
+ concretePath: string;
7
+ isItem: boolean;
8
+ bare: boolean;
9
+ replaceRange: ReplaceRange;
10
+ }
11
+ /**
12
+ * The YAML tags the field under the cursor takes.
13
+ *
14
+ * The same rule studio's schema form applies (`offeredValueTags`), asked of the
15
+ * field's declared schema and of the analyzer's eval mode at the site. Where the
16
+ * field cannot be resolved nothing is known against a tag, so every one is
17
+ * offered rather than none.
18
+ *
19
+ * On a tag with nothing after it, a pick carries a trailing space and, for a tag
20
+ * naming a module location, reopens completion on the path.
21
+ */
22
+ export declare function valueTagCompletions(site: ValueTagSite, registry: AnalysisRegistry | undefined): CompletionResult[];
23
+ //# sourceMappingURL=value-tag-completions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-tag-completions.d.ts","sourceRoot":"","sources":["../../src/completions/value-tag-completions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQlE,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GACrC,gBAAgB,EAAE,CAUpB"}
@@ -0,0 +1,39 @@
1
+ import { offeredValueTags } from "../value-tags/offered-value-tags.js";
2
+ import { fieldSchemaAt, lookupRefConstraints } from "./detect-context.js";
3
+ /** `!ref` names a resource rather than producing a value, so it is offered at a
4
+ * reference slot alone — never beside the value tags. */
5
+ const REF_TAG = { id: "ref", label: "!ref", hint: "A reference to a named resource." };
6
+ /**
7
+ * The YAML tags the field under the cursor takes.
8
+ *
9
+ * The same rule studio's schema form applies (`offeredValueTags`), asked of the
10
+ * field's declared schema and of the analyzer's eval mode at the site. Where the
11
+ * field cannot be resolved nothing is known against a tag, so every one is
12
+ * offered rather than none.
13
+ *
14
+ * On a tag with nothing after it, a pick carries a trailing space and, for a tag
15
+ * naming a module location, reopens completion on the path.
16
+ */
17
+ export function valueTagCompletions(site, registry) {
18
+ return tagsAt(site, registry).map((tag, index) => ({
19
+ label: tag.label,
20
+ kind: "keyword",
21
+ detail: tag.hint,
22
+ insertText: site.bare ? `${tag.label} ` : tag.label,
23
+ replaceRange: site.replaceRange,
24
+ retrigger: site.bare && tag.names !== undefined,
25
+ sortText: String(index).padStart(2, "0"),
26
+ }));
27
+ }
28
+ function tagsAt(site, registry) {
29
+ const { kind } = site;
30
+ const schema = kind ? registry?.resolveDefinition(kind)?.schema : undefined;
31
+ if (!registry || !kind || !schema)
32
+ return [...offeredValueTags(undefined, undefined), REF_TAG];
33
+ const schemaFrom = (from) => registry.resolveSchemaFrom(from, kind);
34
+ if (lookupRefConstraints(schema, site.yamlPath, schemaFrom).length > 0) {
35
+ return [REF_TAG];
36
+ }
37
+ const field = fieldSchemaAt(schema, site.yamlPath, site.isItem, schemaFrom);
38
+ return offeredValueTags(field, registry.celEvalModeAt(kind, site.concretePath));
39
+ }
@@ -20,9 +20,9 @@ export interface ModuleVersion {
20
20
  *
21
21
  * Deliberately NOT `adapter.listVersionsForRef`, which answers `string[]`:
22
22
  * completion offers names, an upgrade writes a pin, so the two want different
23
- * things from one route. A host backed by the hub fetches
24
- * `GET /module/versions` and passes the body through
25
- * {@link parseModuleVersions}. */
23
+ * things from one route. A host backed by the hub reads
24
+ * `GET /module/versions`, carrying an `integrity` only when it is a canonical
25
+ * pin. */
26
26
  export type ModuleVersionLookup = (baseRef: string) => Promise<ModuleVersion[]>;
27
27
  /** Everything an upgrade needs from its host: what versions exist, and whether
28
28
  * this runtime can host one.
@@ -1 +1 @@
1
- {"version":3,"file":"build-import-upgrades.d.ts","sourceRoot":"","sources":["../../src/import-upgrades/build-import-upgrades.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-import-upgrades.d.ts","sourceRoot":"","sources":["../../src/import-upgrades/build-import-upgrades.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  export { buildImportUpgrades, describeReason, describeRemedy, } from "./build-import-upgrades.js";
2
2
  export type { ImportPin, ImportUpgrade, ImportUpgradeEdit, ImportUpgradeEnvironment, ImportUpgradeSet, ImportUpgradeSkip, ModuleVersion, ModuleVersionLookup, } from "./build-import-upgrades.js";
3
3
  export { moduleManifestCacheUrl } from "./manifest-cache-url.js";
4
- export { parseModuleVersions } from "./parse-module-versions.js";
5
4
  export { findImportEntries } from "./find-import-entries.js";
6
5
  export type { ImportEntry, ImportEntryIntegrity, ImportsBlock, } from "./find-import-entries.js";
7
6
  export { createVersionCompatibility, markVersionCompatibility, noneRunnableReason, selectCompatibleVersion, uncheckedVersionCompatibility, } from "./version-compatibility.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/import-upgrades/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,kBAAkB,EAClB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/import-upgrades/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,kBAAkB,EAClB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC"}
@@ -1,5 +1,4 @@
1
1
  export { buildImportUpgrades, describeReason, describeRemedy, } from "./build-import-upgrades.js";
2
2
  export { moduleManifestCacheUrl } from "./manifest-cache-url.js";
3
- export { parseModuleVersions } from "./parse-module-versions.js";
4
3
  export { findImportEntries } from "./find-import-entries.js";
5
4
  export { createVersionCompatibility, markVersionCompatibility, noneRunnableReason, selectCompatibleVersion, uncheckedVersionCompatibility, } from "./version-compatibility.js";
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./rename/index.js";
8
8
  export * from "./signature-help/index.js";
9
9
  export * from "./import-upgrades/index.js";
10
10
  export * from "./workspace/index.js";
11
+ export { offeredValueTags, valueTag, type ValueTag } from "./value-tags/offered-value-tags.js";
11
12
  export { walkCel, flattenChain, chainAt, type ChainPart } from "./cel-chain.js";
12
13
  export { functionSignature } from "./cel/module-calls.js";
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAIrC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAI/F,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -8,6 +8,8 @@ export * from "./rename/index.js";
8
8
  export * from "./signature-help/index.js";
9
9
  export * from "./import-upgrades/index.js";
10
10
  export * from "./workspace/index.js";
11
+ // Which YAML tags a field takes — shared so every host offers the same set.
12
+ export { offeredValueTags, valueTag } from "./value-tags/offered-value-tags.js";
11
13
  // The repo's single CEL-tree walk. Exported because every host that has to
12
14
  // answer "where is this name read" needs it and a second copy would be a second
13
15
  // answer — the editor asks it before deleting a resource.
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { AnalysisRegistry, DiagnosticSeverity, DiagnosticTag } from "@telorun/analyzer";
2
2
  export type { Position, Range, AnalysisDiagnostic, PositionIndex, } from "@telorun/analyzer";
3
3
  import type { AnalysisRegistry, DiagnosticFixTag, DiagnosticSeverity, DiagnosticTag, Position, PositionIndex, Range } from "@telorun/analyzer";
4
- export type CompletionKind = "class" | "enumMember" | "property" | "folder" | "module" | "value";
4
+ export type CompletionKind = "class" | "enumMember" | "property" | "folder" | "file" | "module" | "value" | "keyword";
5
5
  /** A source span the host replaces wholesale when a completion is accepted. */
6
6
  export interface ReplaceRange {
7
7
  start: Position;
@@ -24,6 +24,9 @@ export interface CompletionResult {
24
24
  * containing non-word characters (`/`, `@`, `.`). A zero-width range is a
25
25
  * pure insert. */
26
26
  replaceRange?: ReplaceRange;
27
+ /** The host reopens completion once this item is accepted — what comes next
28
+ * has completions of its own (a tag's value, a directory's entries). */
29
+ retrigger?: boolean;
27
30
  }
28
31
  /** Rendered hover for the symbol under the cursor. `contents` is GitHub-flavored
29
32
  * markdown; `range` (when present) is the source span the host underlines. */
@@ -125,6 +128,15 @@ export interface IdeEnvironmentAdapter {
125
128
  * (`GET /module/versions?ref=`). The browser cannot call OCI `tags/list`;
126
129
  * the hub holds them from ingest. */
127
130
  listVersionsForRef(ref: string): Promise<string[]>;
131
+ /** Entries of `relPath`, resolved against the ROOT of the module the manifest
132
+ * belongs to — the directory every `!include-*` / `!module-path` path is
133
+ * measured from, which for a partial is not the partial's own directory.
134
+ * Returns [] if the path doesn't exist or isn't a directory. */
135
+ listModuleEntries(relPath: string): Promise<ModuleEntry[]>;
136
+ }
137
+ export interface ModuleEntry {
138
+ name: string;
139
+ directory: boolean;
128
140
  }
129
141
  export interface NormalizedDiagnostic {
130
142
  range: Range;