@telorun/ide-support 0.102.0 → 0.103.1

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.
@@ -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;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"}
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,EAEtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AA8L3E,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"}
@@ -2,7 +2,7 @@ import { parseToAst, } from "@telorun/analyzer";
2
2
  import { callInputsAt } from "./call-inputs.js";
3
3
  import { celCompletions } from "./cel-completions.js";
4
4
  import { docIdentity } from "../doc-identity.js";
5
- import { detectContext, lookupRefConstraints, navigateSchema } from "./detect-context.js";
5
+ import { detectContext, lookupRefSlot, navigateSchema } from "./detect-context.js";
6
6
  import { importSourceCompletions } from "./import-source.js";
7
7
  import { moduleFileCompletions } from "./module-file-completions.js";
8
8
  import { valueTagCompletions } from "./value-tag-completions.js";
@@ -27,8 +27,9 @@ function extractInFileResources(docs) {
27
27
  * kind match. Falls back to listing every in-file resource so the
28
28
  * user still sees something rather than nothing when the registry
29
29
  * doesn't recognize the kind yet. */
30
- function refNameCompletions(docs, refKind, refConstraints, registry, replaceRange) {
30
+ function refNameCompletions(docs, refKind, slot, registry, analysis, replaceRange) {
31
31
  const resources = extractInFileResources(docs);
32
+ const refConstraints = slot?.kinds ?? [];
32
33
  let acceptable;
33
34
  if (refKind) {
34
35
  acceptable = new Set([refKind]);
@@ -47,6 +48,11 @@ function refNameCompletions(docs, refKind, refConstraints, registry, replaceRang
47
48
  for (const r of resources) {
48
49
  if (acceptable && !acceptable.has(r.kind))
49
50
  continue;
51
+ // A target `telo check` refuses for what it returns is not a candidate. The
52
+ // analysis resolves the instance's own contract; without one the kind's
53
+ // decides.
54
+ if (slot && outputRefused(slot, r, registry, analysis))
55
+ continue;
50
56
  if (seen.has(r.name))
51
57
  continue;
52
58
  seen.add(r.name);
@@ -61,6 +67,14 @@ function refNameCompletions(docs, refKind, refConstraints, registry, replaceRang
61
67
  }
62
68
  return out;
63
69
  }
70
+ function outputRefused(slot, candidate, registry, analysis) {
71
+ if (!slot.outputType)
72
+ return false;
73
+ const refusal = analysis
74
+ ? analysis.outputRefusal(slot, { kind: candidate.kind, name: candidate.name })
75
+ : (registry?.outputRefusal(slot, { kind: candidate.kind }) ?? []);
76
+ return refusal.length > 0;
77
+ }
64
78
  /** Resolve the kinds that satisfy the `x-telo-ref` slot at `parentDocKind` +
65
79
  * `parentYamlPath`. Returns `undefined` (caller falls back to the full list)
66
80
  * when there's no constraint, the path doesn't resolve, or the ref can't
@@ -69,13 +83,15 @@ function refConstrainedKinds(registry, parentDocKind, parentYamlPath) {
69
83
  const definition = registry.resolveDefinition(parentDocKind);
70
84
  if (!definition?.schema)
71
85
  return undefined;
72
- const constraints = lookupRefConstraints(definition.schema, parentYamlPath, (from) => registry.resolveSchemaFrom(from, parentDocKind));
73
- if (constraints.length === 0)
86
+ const slot = lookupRefSlot(definition.schema, parentYamlPath, (from) => registry.resolveSchemaFrom(from, parentDocKind));
87
+ if (!slot || slot.kinds.length === 0)
74
88
  return undefined;
75
- const resolved = constraints.map((c) => registry.userFacingKindsForRef(c));
89
+ const resolved = slot.kinds.map((c) => registry.userFacingKindsForRef(c));
76
90
  if (!resolved.some(Boolean))
77
91
  return undefined;
78
- return [...new Set(resolved.flatMap((kinds) => kinds ?? []))];
92
+ // An inline declaration of a kind whose output the slot refuses would be
93
+ // refused by `telo check` the moment it is written.
94
+ return [...new Set(resolved.flatMap((kinds) => kinds ?? []))].filter((kind) => !outputRefused(slot, { kind }, registry, undefined));
79
95
  }
80
96
  function kindCompletions(registry, docKind, yamlPath, replaceRange) {
81
97
  let kinds;
@@ -166,10 +182,10 @@ analysis) {
166
182
  }
167
183
  if (ctx.type === "ref-name") {
168
184
  const definition = registry?.resolveDefinition(ctx.docKind);
169
- const refConstraints = registry && definition?.schema
170
- ? lookupRefConstraints(definition.schema, ctx.yamlPath, (from) => registry.resolveSchemaFrom(from, ctx.docKind))
171
- : [];
172
- return refNameCompletions(astDocs, ctx.refKind, refConstraints, registry, ctx.replaceRange);
185
+ const slot = registry && definition?.schema
186
+ ? lookupRefSlot(definition.schema, ctx.yamlPath, (from) => registry.resolveSchemaFrom(from, ctx.docKind))
187
+ : undefined;
188
+ return refNameCompletions(astDocs, ctx.refKind, slot, registry, analysis, ctx.replaceRange);
173
189
  }
174
190
  if (ctx.type === "field-value") {
175
191
  if (ctx.field === "import-source") {
@@ -1,4 +1,4 @@
1
- import { type AstDocument, type CelSegment } from "@telorun/analyzer";
1
+ import { type AstDocument, type CelSegment, type RefSlot } from "@telorun/analyzer";
2
2
  import type { ReplaceRange } from "../types.js";
3
3
  export type { ReplaceRange };
4
4
  export type CompletionCtx = {
@@ -137,6 +137,9 @@ export declare function fieldSchemaAt(schema: Record<string, any>, path: string[
137
137
  * `anyOf` / `oneOf` branches alike, so completion now offers what the slot
138
138
  * actually takes. */
139
139
  export declare function lookupRefConstraints(definitionSchema: Record<string, any>, yamlPath: string[], schemaFrom?: SchemaFromResolver): string[];
140
+ /** The whole `x-telo-ref` slot at `yamlPath` — its kinds and what it asks of a
141
+ * target's output — or undefined when the path declares none. */
142
+ export declare function lookupRefSlot(definitionSchema: Record<string, any>, yamlPath: string[], schemaFrom?: SchemaFromResolver): RefSlot | undefined;
140
143
  /** Derive a `CompletionCtx` from the AST-resolved cursor (Approach B). The
141
144
  * structural resolution lives in `resolveNodeAtPosition`; this only maps a
142
145
  * resolved slot onto the completion the editor should offer. `docs` lets a
@@ -1 +1 @@
1
- {"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"detect-context.d.ts","sourceRoot":"","sources":["../../src/completions/detect-context.ts"],"names":[],"mappings":"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"}
@@ -230,10 +230,13 @@ function unionLeaves(parent, leaves) {
230
230
  * `anyOf` / `oneOf` branches alike, so completion now offers what the slot
231
231
  * actually takes. */
232
232
  export function lookupRefConstraints(definitionSchema, yamlPath, schemaFrom) {
233
+ return lookupRefSlot(definitionSchema, yamlPath, schemaFrom)?.kinds ?? [];
234
+ }
235
+ /** The whole `x-telo-ref` slot at `yamlPath` — its kinds and what it asks of a
236
+ * target's output — or undefined when the path declares none. */
237
+ export function lookupRefSlot(definitionSchema, yamlPath, schemaFrom) {
233
238
  const node = navigateSchema(definitionSchema, yamlPath, schemaFrom);
234
- if (!node)
235
- return [];
236
- return readRefSlot(node)?.kinds ?? [];
239
+ return node ? readRefSlot(node) : undefined;
237
240
  }
238
241
  /** Derive a `CompletionCtx` from the AST-resolved cursor (Approach B). The
239
242
  * structural resolution lives in `resolveNodeAtPosition`; this only maps a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/ide-support",
3
- "version": "0.102.0",
3
+ "version": "0.103.1",
4
4
  "description": "Editor-host-agnostic IDE support (completions, diagnostic normalization) for Telo manifests.",
5
5
  "keywords": [
6
6
  "telo",
@@ -37,8 +37,8 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "yaml": "^2.8.3",
40
- "@telorun/analyzer": "0.102.0",
41
- "@telorun/templating": "0.102.0"
40
+ "@telorun/analyzer": "0.103.1",
41
+ "@telorun/templating": "0.103.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^20.0.0",
@@ -4,13 +4,14 @@ import {
4
4
  type AstDocument,
5
5
  type AstMap,
6
6
  type ManifestAnalysis,
7
+ type RefSlot,
7
8
  } from "@telorun/analyzer";
8
9
  import type { CompletionResult, IdeEnvironmentAdapter } from "../types.js";
9
10
  import type { ReplaceRange } from "./detect-context.js";
10
11
  import { callInputsAt } from "./call-inputs.js";
11
12
  import { celCompletions } from "./cel-completions.js";
12
13
  import { docIdentity } from "../doc-identity.js";
13
- import { detectContext, lookupRefConstraints, navigateSchema } from "./detect-context.js";
14
+ import { detectContext, lookupRefSlot, navigateSchema } from "./detect-context.js";
14
15
  import { importSourceCompletions } from "./import-source.js";
15
16
  import { moduleFileCompletions } from "./module-file-completions.js";
16
17
  import { valueTagCompletions } from "./value-tag-completions.js";
@@ -44,11 +45,13 @@ function extractInFileResources(docs: AstDocument[]): ResourceRecord[] {
44
45
  function refNameCompletions(
45
46
  docs: AstDocument[],
46
47
  refKind: string | undefined,
47
- refConstraints: string[],
48
+ slot: RefSlot | undefined,
48
49
  registry: AnalysisRegistry | undefined,
50
+ analysis: ManifestAnalysis | undefined,
49
51
  replaceRange: ReplaceRange,
50
52
  ): CompletionResult[] {
51
53
  const resources = extractInFileResources(docs);
54
+ const refConstraints = slot?.kinds ?? [];
52
55
  let acceptable: Set<string> | undefined;
53
56
 
54
57
  if (refKind) {
@@ -67,6 +70,10 @@ function refNameCompletions(
67
70
  const out: CompletionResult[] = [];
68
71
  for (const r of resources) {
69
72
  if (acceptable && !acceptable.has(r.kind)) continue;
73
+ // A target `telo check` refuses for what it returns is not a candidate. The
74
+ // analysis resolves the instance's own contract; without one the kind's
75
+ // decides.
76
+ if (slot && outputRefused(slot, r, registry, analysis)) continue;
70
77
  if (seen.has(r.name)) continue;
71
78
  seen.add(r.name);
72
79
  out.push({
@@ -81,6 +88,19 @@ function refNameCompletions(
81
88
  return out;
82
89
  }
83
90
 
91
+ function outputRefused(
92
+ slot: RefSlot,
93
+ candidate: { kind: string; name?: string },
94
+ registry: AnalysisRegistry | undefined,
95
+ analysis: ManifestAnalysis | undefined,
96
+ ): boolean {
97
+ if (!slot.outputType) return false;
98
+ const refusal = analysis
99
+ ? analysis.outputRefusal(slot, { kind: candidate.kind, name: candidate.name })
100
+ : (registry?.outputRefusal(slot, { kind: candidate.kind }) ?? []);
101
+ return refusal.length > 0;
102
+ }
103
+
84
104
  /** Resolve the kinds that satisfy the `x-telo-ref` slot at `parentDocKind` +
85
105
  * `parentYamlPath`. Returns `undefined` (caller falls back to the full list)
86
106
  * when there's no constraint, the path doesn't resolve, or the ref can't
@@ -92,15 +112,19 @@ function refConstrainedKinds(
92
112
  ): string[] | undefined {
93
113
  const definition = registry.resolveDefinition(parentDocKind);
94
114
  if (!definition?.schema) return undefined;
95
- const constraints = lookupRefConstraints(
115
+ const slot = lookupRefSlot(
96
116
  definition.schema as Record<string, any>,
97
117
  parentYamlPath,
98
118
  (from) => registry.resolveSchemaFrom(from, parentDocKind),
99
119
  );
100
- if (constraints.length === 0) return undefined;
101
- const resolved = constraints.map((c) => registry.userFacingKindsForRef(c));
120
+ if (!slot || slot.kinds.length === 0) return undefined;
121
+ const resolved = slot.kinds.map((c) => registry.userFacingKindsForRef(c));
102
122
  if (!resolved.some(Boolean)) return undefined;
103
- return [...new Set(resolved.flatMap((kinds) => kinds ?? []))];
123
+ // An inline declaration of a kind whose output the slot refuses would be
124
+ // refused by `telo check` the moment it is written.
125
+ return [...new Set(resolved.flatMap((kinds) => kinds ?? []))].filter(
126
+ (kind) => !outputRefused(slot, { kind }, registry, undefined),
127
+ );
104
128
  }
105
129
 
106
130
  function kindCompletions(
@@ -213,13 +237,13 @@ export async function buildCompletions(
213
237
  }
214
238
  if (ctx.type === "ref-name") {
215
239
  const definition = registry?.resolveDefinition(ctx.docKind);
216
- const refConstraints =
240
+ const slot =
217
241
  registry && definition?.schema
218
- ? lookupRefConstraints(definition.schema as Record<string, any>, ctx.yamlPath, (from) =>
242
+ ? lookupRefSlot(definition.schema as Record<string, any>, ctx.yamlPath, (from) =>
219
243
  registry.resolveSchemaFrom(from, ctx.docKind),
220
244
  )
221
- : [];
222
- return refNameCompletions(astDocs, ctx.refKind, refConstraints, registry, ctx.replaceRange);
245
+ : undefined;
246
+ return refNameCompletions(astDocs, ctx.refKind, slot, registry, analysis, ctx.replaceRange);
223
247
  }
224
248
  if (ctx.type === "field-value") {
225
249
  if (ctx.field === "import-source") {
@@ -4,6 +4,7 @@ import {
4
4
  refSlotAnnotation,
5
5
  type AstDocument,
6
6
  type CelSegment,
7
+ type RefSlot,
7
8
  } from "@telorun/analyzer";
8
9
  import type { ReplaceRange } from "../types.js";
9
10
  import { valueTag } from "../value-tags/offered-value-tags.js";
@@ -366,9 +367,18 @@ export function lookupRefConstraints(
366
367
  yamlPath: string[],
367
368
  schemaFrom?: SchemaFromResolver,
368
369
  ): string[] {
370
+ return lookupRefSlot(definitionSchema, yamlPath, schemaFrom)?.kinds ?? [];
371
+ }
372
+
373
+ /** The whole `x-telo-ref` slot at `yamlPath` — its kinds and what it asks of a
374
+ * target's output — or undefined when the path declares none. */
375
+ export function lookupRefSlot(
376
+ definitionSchema: Record<string, any>,
377
+ yamlPath: string[],
378
+ schemaFrom?: SchemaFromResolver,
379
+ ): RefSlot | undefined {
369
380
  const node = navigateSchema(definitionSchema, yamlPath, schemaFrom);
370
- if (!node) return [];
371
- return readRefSlot(node)?.kinds ?? [];
381
+ return node ? readRefSlot(node) : undefined;
372
382
  }
373
383
 
374
384
  /** Derive a `CompletionCtx` from the AST-resolved cursor (Approach B). The