@telorun/ide-support 0.15.0 → 0.16.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.
- package/dist/cel/cursor-chain.d.ts +30 -0
- package/dist/cel/cursor-chain.d.ts.map +1 -0
- package/dist/cel/cursor-chain.js +30 -0
- package/dist/cel/symbols.d.ts +82 -0
- package/dist/cel/symbols.d.ts.map +1 -0
- package/dist/cel/symbols.js +147 -0
- package/dist/cel/tokens.d.ts +32 -0
- package/dist/cel/tokens.d.ts.map +1 -0
- package/dist/cel/tokens.js +162 -0
- package/dist/completions/build.d.ts +6 -2
- package/dist/completions/build.d.ts.map +1 -1
- package/dist/completions/build.js +52 -24
- package/dist/completions/call-inputs.d.ts +25 -0
- package/dist/completions/call-inputs.d.ts.map +1 -0
- package/dist/completions/call-inputs.js +78 -0
- package/dist/completions/cel-completions.d.ts +26 -0
- package/dist/completions/cel-completions.d.ts.map +1 -0
- package/dist/completions/cel-completions.js +78 -0
- package/dist/completions/detect-context.d.ts +47 -8
- package/dist/completions/detect-context.d.ts.map +1 -1
- package/dist/completions/detect-context.js +51 -15
- package/dist/completions/prop-keys.d.ts +5 -1
- package/dist/completions/prop-keys.d.ts.map +1 -1
- package/dist/completions/prop-keys.js +51 -3
- package/dist/completions/resolve-node.d.ts +9 -2
- package/dist/completions/resolve-node.d.ts.map +1 -1
- package/dist/completions/resolve-node.js +63 -21
- package/dist/completions/valid-capabilities.js +1 -1
- package/dist/definition/build-definition.d.ts +6 -2
- package/dist/definition/build-definition.d.ts.map +1 -1
- package/dist/definition/build-definition.js +16 -3
- package/dist/definition/locate-context-binding.d.ts +15 -0
- package/dist/definition/locate-context-binding.d.ts.map +1 -0
- package/dist/definition/locate-context-binding.js +35 -0
- package/dist/definition/locate-step.d.ts +13 -0
- package/dist/definition/locate-step.d.ts.map +1 -0
- package/dist/definition/locate-step.js +33 -0
- package/dist/definition/resolve-cel-target.d.ts +11 -1
- package/dist/definition/resolve-cel-target.d.ts.map +1 -1
- package/dist/definition/resolve-cel-target.js +14 -14
- package/dist/doc-identity.d.ts +17 -0
- package/dist/doc-identity.d.ts.map +1 -0
- package/dist/doc-identity.js +19 -0
- package/dist/hover/build-hover.d.ts +6 -2
- package/dist/hover/build-hover.d.ts.map +1 -1
- package/dist/hover/build-hover.js +64 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/semantic-tokens/build-semantic-tokens.d.ts +13 -8
- package/dist/semantic-tokens/build-semantic-tokens.d.ts.map +1 -1
- package/dist/semantic-tokens/build-semantic-tokens.js +81 -37
- package/dist/types.d.ts +25 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +16 -2
- package/package.json +2 -2
- package/src/cel/cursor-chain.ts +58 -0
- package/src/cel/symbols.ts +189 -0
- package/src/cel/tokens.ts +169 -0
- package/src/completions/build.ts +85 -22
- package/src/completions/call-inputs.ts +92 -0
- package/src/completions/cel-completions.ts +108 -0
- package/src/completions/detect-context.ts +107 -13
- package/src/completions/prop-keys.ts +59 -2
- package/src/completions/resolve-node.ts +82 -17
- package/src/completions/valid-capabilities.ts +1 -1
- package/src/definition/build-definition.ts +30 -2
- package/src/definition/locate-context-binding.ts +53 -0
- package/src/definition/locate-step.ts +50 -0
- package/src/definition/resolve-cel-target.ts +25 -0
- package/src/doc-identity.ts +31 -0
- package/src/hover/build-hover.ts +67 -1
- package/src/index.ts +4 -0
- package/src/semantic-tokens/build-semantic-tokens.ts +84 -30
- package/src/types.ts +47 -6
|
@@ -36,7 +36,11 @@ function enter(scope, map, ancestorsLen) {
|
|
|
36
36
|
const kind = resourceKindOf(map);
|
|
37
37
|
return kind ? { kind, depth: ancestorsLen } : scope;
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
/** Append one key segment to a concrete path (`routes[0]` + `handler`). */
|
|
40
|
+
function joinKey(concrete, key) {
|
|
41
|
+
return concrete ? `${concrete}.${key}` : key;
|
|
42
|
+
}
|
|
43
|
+
function descend(node, ancestors, concrete, offset, scope) {
|
|
40
44
|
if (node.kind === "map") {
|
|
41
45
|
const mapScope = enter(scope, node, ancestors.length);
|
|
42
46
|
for (const pair of node.entries) {
|
|
@@ -46,6 +50,7 @@ function descend(node, ancestors, offset, scope) {
|
|
|
46
50
|
type: "key",
|
|
47
51
|
container: node,
|
|
48
52
|
path: ancestors,
|
|
53
|
+
concretePath: concrete,
|
|
49
54
|
keyNode: pair.key,
|
|
50
55
|
keyName,
|
|
51
56
|
scope: mapScope,
|
|
@@ -53,13 +58,15 @@ function descend(node, ancestors, offset, scope) {
|
|
|
53
58
|
}
|
|
54
59
|
if (pair.value && within(pair.value.range, offset)) {
|
|
55
60
|
const childAncestors = keyName != null ? [...ancestors, keyName] : ancestors;
|
|
61
|
+
const childConcrete = keyName != null ? joinKey(concrete, keyName) : concrete;
|
|
56
62
|
if (pair.value.kind === "map" || pair.value.kind === "seq") {
|
|
57
|
-
return descend(pair.value, childAncestors, offset, mapScope) ?? { type: "empty" };
|
|
63
|
+
return descend(pair.value, childAncestors, childConcrete, offset, mapScope) ?? { type: "empty" };
|
|
58
64
|
}
|
|
59
65
|
return {
|
|
60
66
|
type: "value",
|
|
61
67
|
container: node,
|
|
62
68
|
path: ancestors,
|
|
69
|
+
concretePath: childConcrete,
|
|
63
70
|
keyName,
|
|
64
71
|
keyEnd: pair.key.range[1],
|
|
65
72
|
valueNode: pair.value,
|
|
@@ -70,23 +77,33 @@ function descend(node, ancestors, offset, scope) {
|
|
|
70
77
|
}
|
|
71
78
|
if (node.kind === "seq") {
|
|
72
79
|
// Sequence items are transparent to the key path (mirrors the schema
|
|
73
|
-
// walker, which auto-descends arrays)
|
|
74
|
-
|
|
80
|
+
// walker, which auto-descends arrays) but NOT to the concrete path: an
|
|
81
|
+
// `x-telo-context` scope, an error-bearing region and a step's identity are
|
|
82
|
+
// all addressed per item, so a CEL site is unreachable without the index.
|
|
83
|
+
for (const [index, item] of node.items.entries()) {
|
|
75
84
|
if (within(item.range, offset)) {
|
|
85
|
+
const itemConcrete = `${concrete}[${index}]`;
|
|
76
86
|
if (item.kind === "map" || item.kind === "seq") {
|
|
77
|
-
return descend(item, ancestors, offset, scope) ?? { type: "empty" };
|
|
87
|
+
return descend(item, ancestors, itemConcrete, offset, scope) ?? { type: "empty" };
|
|
78
88
|
}
|
|
79
89
|
// A bare scalar list item (`targets:\n - One`) has no enclosing map of
|
|
80
90
|
// keyed siblings — leave `container` undefined rather than treating the
|
|
81
91
|
// seq as a map.
|
|
82
|
-
return {
|
|
92
|
+
return {
|
|
93
|
+
type: "value",
|
|
94
|
+
container: undefined,
|
|
95
|
+
path: ancestors,
|
|
96
|
+
concretePath: itemConcrete,
|
|
97
|
+
keyEnd: item.range[0],
|
|
98
|
+
valueNode: item,
|
|
99
|
+
};
|
|
83
100
|
}
|
|
84
101
|
}
|
|
85
102
|
return undefined;
|
|
86
103
|
}
|
|
87
104
|
return undefined;
|
|
88
105
|
}
|
|
89
|
-
function collectScopes(node, ancestors, scope, lineOffsets, maps, pairs) {
|
|
106
|
+
function collectScopes(node, ancestors, concrete, scope, lineOffsets, maps, pairs) {
|
|
90
107
|
if (node.kind === "map") {
|
|
91
108
|
const mapScope = enter(scope, node, ancestors.length);
|
|
92
109
|
const keys = new Set();
|
|
@@ -99,11 +116,19 @@ function collectScopes(node, ancestors, scope, lineOffsets, maps, pairs) {
|
|
|
99
116
|
childColumn = offsetToPosition(pair.key.range[0], lineOffsets).character;
|
|
100
117
|
}
|
|
101
118
|
if (childColumn >= 0) {
|
|
102
|
-
maps.push({
|
|
119
|
+
maps.push({
|
|
120
|
+
path: ancestors,
|
|
121
|
+
concrete,
|
|
122
|
+
childColumn,
|
|
123
|
+
keys,
|
|
124
|
+
rangeStart: node.range[0],
|
|
125
|
+
scope: mapScope,
|
|
126
|
+
});
|
|
103
127
|
}
|
|
104
128
|
for (const pair of node.entries) {
|
|
105
129
|
const keyName = scalarString(pair.key);
|
|
106
130
|
const fullPath = keyName != null ? [...ancestors, keyName] : ancestors;
|
|
131
|
+
const fullConcrete = keyName != null ? joinKey(concrete, keyName) : concrete;
|
|
107
132
|
const childKeys = new Set();
|
|
108
133
|
if (pair.value?.kind === "map") {
|
|
109
134
|
for (const p of pair.value.entries) {
|
|
@@ -114,18 +139,19 @@ function collectScopes(node, ancestors, scope, lineOffsets, maps, pairs) {
|
|
|
114
139
|
}
|
|
115
140
|
pairs.push({
|
|
116
141
|
path: fullPath,
|
|
142
|
+
concrete: fullConcrete,
|
|
117
143
|
keyColumn: offsetToPosition(pair.key.range[0], lineOffsets).character,
|
|
118
144
|
keyOffset: pair.key.range[0],
|
|
119
145
|
childKeys,
|
|
120
146
|
scope: mapScope,
|
|
121
147
|
});
|
|
122
|
-
if (pair.value)
|
|
123
|
-
collectScopes(pair.value, fullPath, mapScope, lineOffsets, maps, pairs);
|
|
148
|
+
if (pair.value) {
|
|
149
|
+
collectScopes(pair.value, fullPath, fullConcrete, mapScope, lineOffsets, maps, pairs);
|
|
150
|
+
}
|
|
124
151
|
}
|
|
125
152
|
}
|
|
126
153
|
else if (node.kind === "seq") {
|
|
127
|
-
|
|
128
|
-
collectScopes(item, ancestors, scope, lineOffsets, maps, pairs);
|
|
154
|
+
node.items.forEach((item, index) => collectScopes(item, ancestors, `${concrete}[${index}]`, scope, lineOffsets, maps, pairs));
|
|
129
155
|
}
|
|
130
156
|
}
|
|
131
157
|
/** Resolve the container a new key at `cursorColumn` belongs to. Prefers an
|
|
@@ -134,7 +160,7 @@ function collectScopes(node, ancestors, scope, lineOffsets, maps, pairs) {
|
|
|
134
160
|
function columnSearch(root, cursorColumn, cursorOffset, lineOffsets) {
|
|
135
161
|
const maps = [];
|
|
136
162
|
const pairs = [];
|
|
137
|
-
collectScopes(root, [], { depth: 0 }, lineOffsets, maps, pairs);
|
|
163
|
+
collectScopes(root, [], "", { depth: 0 }, lineOffsets, maps, pairs);
|
|
138
164
|
// Sibling level: a map whose children already sit at the cursor's column.
|
|
139
165
|
let sibling;
|
|
140
166
|
for (const m of maps) {
|
|
@@ -143,8 +169,14 @@ function columnSearch(root, cursorColumn, cursorOffset, lineOffsets) {
|
|
|
143
169
|
sibling = m;
|
|
144
170
|
}
|
|
145
171
|
}
|
|
146
|
-
if (sibling)
|
|
147
|
-
return {
|
|
172
|
+
if (sibling) {
|
|
173
|
+
return {
|
|
174
|
+
path: sibling.path,
|
|
175
|
+
concrete: sibling.concrete,
|
|
176
|
+
existingKeys: sibling.keys,
|
|
177
|
+
scope: sibling.scope,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
148
180
|
// Nest under the nearest-preceding key shallower than the cursor.
|
|
149
181
|
let nest;
|
|
150
182
|
for (const p of pairs) {
|
|
@@ -156,9 +188,15 @@ function columnSearch(root, cursorColumn, cursorOffset, lineOffsets) {
|
|
|
156
188
|
}
|
|
157
189
|
}
|
|
158
190
|
}
|
|
159
|
-
if (nest)
|
|
160
|
-
return {
|
|
161
|
-
|
|
191
|
+
if (nest) {
|
|
192
|
+
return {
|
|
193
|
+
path: nest.path,
|
|
194
|
+
concrete: nest.concrete,
|
|
195
|
+
existingKeys: nest.childKeys,
|
|
196
|
+
scope: nest.scope,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return { path: [], concrete: "", existingKeys: new Set(), scope: { depth: 0 } };
|
|
162
200
|
}
|
|
163
201
|
// ---------------------------------------------------------------------------
|
|
164
202
|
function selectDoc(docs, offset) {
|
|
@@ -189,7 +227,7 @@ export function resolveNodeAtPosition(text, docs, line, character) {
|
|
|
189
227
|
return undefined;
|
|
190
228
|
const doc = docs[docIndex];
|
|
191
229
|
const docKind = docKindOf(doc);
|
|
192
|
-
const found = doc.root ? descend(doc.root, [], offset, { depth: 0 }) : undefined;
|
|
230
|
+
const found = doc.root ? descend(doc.root, [], "", offset, { depth: 0 }) : undefined;
|
|
193
231
|
// Cursor sits on an existing map key → key/prop-key position.
|
|
194
232
|
if (found?.type === "key") {
|
|
195
233
|
const existingKeys = new Set();
|
|
@@ -204,6 +242,7 @@ export function resolveNodeAtPosition(text, docs, line, character) {
|
|
|
204
242
|
docKind,
|
|
205
243
|
slot: "key",
|
|
206
244
|
path: found.path,
|
|
245
|
+
concretePath: found.concretePath,
|
|
207
246
|
node: found.keyNode,
|
|
208
247
|
replaceRange: { start: toPos(found.keyNode.range[0]), end: toPos(found.keyNode.range[1]) },
|
|
209
248
|
container: found.container,
|
|
@@ -226,13 +265,14 @@ export function resolveNodeAtPosition(text, docs, line, character) {
|
|
|
226
265
|
toPos(value.range[0]).line !== toPos(found.keyEnd).line;
|
|
227
266
|
if (isPartialKey && doc.root) {
|
|
228
267
|
const col = toPos(value.range[0]).character;
|
|
229
|
-
const { path, existingKeys, scope } = columnSearch(doc.root, col, offset, lineOffsets);
|
|
268
|
+
const { path, concrete, existingKeys, scope } = columnSearch(doc.root, col, offset, lineOffsets);
|
|
230
269
|
return {
|
|
231
270
|
docIndex,
|
|
232
271
|
offset,
|
|
233
272
|
docKind,
|
|
234
273
|
slot: "key",
|
|
235
274
|
path,
|
|
275
|
+
concretePath: concrete,
|
|
236
276
|
container: found.container,
|
|
237
277
|
existingKeys,
|
|
238
278
|
resourceKind: scope.kind,
|
|
@@ -246,6 +286,7 @@ export function resolveNodeAtPosition(text, docs, line, character) {
|
|
|
246
286
|
docKind,
|
|
247
287
|
slot: "value",
|
|
248
288
|
path: found.keyName != null ? [...found.path, found.keyName] : found.path,
|
|
289
|
+
concretePath: found.concretePath,
|
|
249
290
|
node: value,
|
|
250
291
|
container: found.container,
|
|
251
292
|
prefix: text.slice(value.range[0], clampedEnd),
|
|
@@ -259,13 +300,14 @@ export function resolveNodeAtPosition(text, docs, line, character) {
|
|
|
259
300
|
// resolved by cursor column.
|
|
260
301
|
const resolution = doc.root
|
|
261
302
|
? columnSearch(doc.root, character, offset, lineOffsets)
|
|
262
|
-
: { path: [], existingKeys: new Set(), scope: { depth: 0 } };
|
|
303
|
+
: { path: [], concrete: "", existingKeys: new Set(), scope: { depth: 0 } };
|
|
263
304
|
return {
|
|
264
305
|
docIndex,
|
|
265
306
|
offset,
|
|
266
307
|
docKind,
|
|
267
308
|
slot: "key",
|
|
268
309
|
path: resolution.path,
|
|
310
|
+
concretePath: resolution.concrete,
|
|
269
311
|
existingKeys: resolution.existingKeys,
|
|
270
312
|
resourceKind: resolution.scope.kind,
|
|
271
313
|
resourceDepth: resolution.scope.depth,
|
|
@@ -9,7 +9,7 @@ export const CAPABILITY_VALUES = [
|
|
|
9
9
|
/** One-line role summary per capability, surfaced on hover. Kept in sync with
|
|
10
10
|
* the capability list in `CLAUDE.md` / the kernel builtins. */
|
|
11
11
|
export const CAPABILITY_DOCS = {
|
|
12
|
-
"Telo.Service": "Long-lived resource: `init()` +
|
|
12
|
+
"Telo.Service": "Long-lived resource: `init()` + `run()`, returning what undoes them (servers, pools).",
|
|
13
13
|
"Telo.Runnable": "One-shot task: `run()` (pipelines, boot steps).",
|
|
14
14
|
"Telo.Invocable": "Request handler: `invoke(inputs)` (scripts, endpoints).",
|
|
15
15
|
"Telo.Provider": "Value-flow source: `init()` + optional `provide()` (config, secrets).",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AstDocument, type LoadedGraph } from "@telorun/analyzer";
|
|
1
|
+
import { type AstDocument, type ManifestAnalysis, type LoadedGraph } from "@telorun/analyzer";
|
|
2
2
|
import type { DefinitionResult } from "../types.js";
|
|
3
3
|
/** Resolve the symbol under the cursor to where it is declared.
|
|
4
4
|
*
|
|
@@ -16,5 +16,9 @@ import type { DefinitionResult } from "../types.js";
|
|
|
16
16
|
* cursor is on nothing navigable, or the target can't be found (a kernel
|
|
17
17
|
* built-in, a scope-local name, an unexported entry, or an import that failed
|
|
18
18
|
* to load). */
|
|
19
|
-
export declare function buildDefinition(text: string, line: number, character: number, graph: LoadedGraph, currentFilePath: string, docs?: AstDocument[]
|
|
19
|
+
export declare function buildDefinition(text: string, line: number, character: number, graph: LoadedGraph, currentFilePath: string, docs?: AstDocument[],
|
|
20
|
+
/** Lets a `steps.<name>` read navigate to the step that produced it, and a
|
|
21
|
+
* context binding to its declaration — both need the declaring kind's own
|
|
22
|
+
* annotations, which only the analysis can read. */
|
|
23
|
+
analysis?: ManifestAnalysis): DefinitionResult | undefined;
|
|
20
24
|
//# sourceMappingURL=build-definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-definition.d.ts","sourceRoot":"","sources":["../../src/definition/build-definition.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"build-definition.d.ts","sourceRoot":"","sources":["../../src/definition/build-definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAUpD;;;;;;;;;;;;;;;gBAegB;AAChB,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,WAAW,EAClB,eAAe,EAAE,MAAM,EACvB,IAAI,CAAC,EAAE,WAAW,EAAE;AACpB;;qDAEqD;AACrD,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,gBAAgB,GAAG,SAAS,CAoC9B"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { parseToAst } from "@telorun/analyzer";
|
|
1
|
+
import { parseToAst, } from "@telorun/analyzer";
|
|
2
2
|
import { resolveNodeAtPosition } from "../completions/resolve-node.js";
|
|
3
3
|
import { splitAliasQualified } from "./alias-qualified-value.js";
|
|
4
|
+
import { locateContextBinding } from "./locate-context-binding.js";
|
|
5
|
+
import { locateStepDeclaration } from "./locate-step.js";
|
|
4
6
|
import { moduleForFile } from "./manifest-navigation.js";
|
|
5
7
|
import { resolveCelTarget } from "./resolve-cel-target.js";
|
|
6
8
|
import { isKindSlot, resolveKindTarget } from "./resolve-kind-target.js";
|
|
@@ -21,14 +23,25 @@ import { resolveRefTarget } from "./resolve-ref-target.js";
|
|
|
21
23
|
* cursor is on nothing navigable, or the target can't be found (a kernel
|
|
22
24
|
* built-in, a scope-local name, an unexported entry, or an import that failed
|
|
23
25
|
* to load). */
|
|
24
|
-
export function buildDefinition(text, line, character, graph, currentFilePath, docs
|
|
26
|
+
export function buildDefinition(text, line, character, graph, currentFilePath, docs,
|
|
27
|
+
/** Lets a `steps.<name>` read navigate to the step that produced it, and a
|
|
28
|
+
* context binding to its declaration — both need the declaring kind's own
|
|
29
|
+
* annotations, which only the analysis can read. */
|
|
30
|
+
analysis) {
|
|
25
31
|
const astDocs = docs ?? parseToAst(text);
|
|
26
32
|
const resolved = resolveNodeAtPosition(text, astDocs, line, character);
|
|
27
33
|
if (!resolved)
|
|
28
34
|
return undefined;
|
|
29
35
|
const currentModule = moduleForFile(graph, currentFilePath) ?? graph.entry;
|
|
30
36
|
if (resolved.cel) {
|
|
31
|
-
return resolveCelTarget(graph, currentModule, resolved.cel.segment, resolved.cel.offset
|
|
37
|
+
return resolveCelTarget(graph, currentModule, resolved.cel.segment, resolved.cel.offset, {
|
|
38
|
+
// A step is resolved in the CURRENT document — `steps.<name>.result` is
|
|
39
|
+
// readable only inside the resource that declares it, which is one
|
|
40
|
+
// document. Supplied as a closure so the chain resolver stays free of the
|
|
41
|
+
// AST and the scope query alike.
|
|
42
|
+
locateStep: (stepName) => locateStepDeclaration(graph, currentFilePath, astDocs, resolved.docIndex, stepName, analysis?.celScope),
|
|
43
|
+
locateContextBinding: (parts) => locateContextBinding(graph, astDocs, resolved.docIndex, resolved.concretePath ?? "", parts, analysis?.celScope),
|
|
44
|
+
});
|
|
32
45
|
}
|
|
33
46
|
const node = resolved.node;
|
|
34
47
|
if (resolved.slot !== "value" || node?.kind !== "scalar")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a CEL context binding was declared.
|
|
3
|
+
*
|
|
4
|
+
* `request.query` is written in the route's own `request.schema`, `self.<field>`
|
|
5
|
+
* in the definition's `schema`, `result.<field>` in the INVOKED resource's
|
|
6
|
+
* `outputType` — each derived by an `x-telo-context-*` annotation rather than
|
|
7
|
+
* reached through a reference slot, so none of them is navigable by the graph
|
|
8
|
+
* walk the other CEL roots use. The scope query resolves the annotation to a
|
|
9
|
+
* manifest identity plus a path; locating that path in the loaded files is what
|
|
10
|
+
* this adds.
|
|
11
|
+
*/
|
|
12
|
+
import type { AstDocument, CelScopeQuery, LoadedGraph } from "@telorun/analyzer";
|
|
13
|
+
import type { DefinitionResult } from "../types.js";
|
|
14
|
+
export declare function locateContextBinding(graph: LoadedGraph, docs: AstDocument[], docIndex: number, sitePath: string, parts: string[], scopeQuery: CelScopeQuery | undefined): DefinitionResult | undefined;
|
|
15
|
+
//# sourceMappingURL=locate-context-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate-context-binding.d.ts","sourceRoot":"","sources":["../../src/definition/locate-context-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAYpD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,WAAW,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EAAE,EACf,UAAU,EAAE,aAAa,GAAG,SAAS,GACpC,gBAAgB,GAAG,SAAS,CAqB9B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { docIdentity } from "../doc-identity.js";
|
|
2
|
+
/** Every file of every module in the graph — a binding's declaration may sit in
|
|
3
|
+
* another module (an invoked handler's `outputType`), so the search is not
|
|
4
|
+
* confined to the current file. */
|
|
5
|
+
function allFiles(graph) {
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const mod of graph.modules.values())
|
|
8
|
+
out.push(mod.owner, ...mod.partials);
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
export function locateContextBinding(graph, docs, docIndex, sitePath, parts, scopeQuery) {
|
|
12
|
+
if (!scopeQuery)
|
|
13
|
+
return undefined;
|
|
14
|
+
const identity = docIdentity(docs[docIndex]);
|
|
15
|
+
const resource = scopeQuery.resourceFor(identity.kind, identity.name);
|
|
16
|
+
if (!resource)
|
|
17
|
+
return undefined;
|
|
18
|
+
const site = scopeQuery.contextDeclarationSite(resource, sitePath, parts);
|
|
19
|
+
if (!site)
|
|
20
|
+
return undefined;
|
|
21
|
+
for (const file of allFiles(graph)) {
|
|
22
|
+
for (let i = 0; i < file.manifests.length; i++) {
|
|
23
|
+
const manifest = file.manifests[i];
|
|
24
|
+
if (manifest?.kind !== site.kind || manifest.metadata?.name !== site.name)
|
|
25
|
+
continue;
|
|
26
|
+
const index = file.positions[i]?.positionIndex;
|
|
27
|
+
// The KEY span, so the jump underlines `query:` rather than the block that
|
|
28
|
+
// follows it — a declaration, not a selection.
|
|
29
|
+
const range = index?.get(`@key:${site.path}`) ?? index?.get(site.path);
|
|
30
|
+
if (range)
|
|
31
|
+
return { uri: file.source, range };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a `Run` step is declared.
|
|
3
|
+
*
|
|
4
|
+
* The one CEL scope whose members really are written in the manifest but are
|
|
5
|
+
* reached through no reference slot — `steps.encode.result` names something a
|
|
6
|
+
* `!ref` resolver has never heard of. Finding it needs the declaring kind's own
|
|
7
|
+
* step-body annotation, which is why it goes through the scope query rather
|
|
8
|
+
* than through the graph navigation the other CEL roots use.
|
|
9
|
+
*/
|
|
10
|
+
import type { AstDocument, CelScopeQuery, LoadedGraph } from "@telorun/analyzer";
|
|
11
|
+
import type { DefinitionResult } from "../types.js";
|
|
12
|
+
export declare function locateStepDeclaration(graph: LoadedGraph, filePath: string, docs: AstDocument[], docIndex: number, stepName: string, scopeQuery: CelScopeQuery | undefined): DefinitionResult | undefined;
|
|
13
|
+
//# sourceMappingURL=locate-step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate-step.d.ts","sourceRoot":"","sources":["../../src/definition/locate-step.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAcpD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,aAAa,GAAG,SAAS,GACpC,gBAAgB,GAAG,SAAS,CAkB9B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { docIdentity } from "../doc-identity.js";
|
|
2
|
+
/** The loaded file for `filePath`, whose position index maps a manifest path to
|
|
3
|
+
* a source range. */
|
|
4
|
+
function loadedFile(graph, filePath) {
|
|
5
|
+
for (const mod of graph.modules.values()) {
|
|
6
|
+
if (mod.owner.source === filePath)
|
|
7
|
+
return mod.owner;
|
|
8
|
+
const partial = mod.partials.find((p) => p.source === filePath);
|
|
9
|
+
if (partial)
|
|
10
|
+
return partial;
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
export function locateStepDeclaration(graph, filePath, docs, docIndex, stepName, scopeQuery) {
|
|
15
|
+
if (!scopeQuery)
|
|
16
|
+
return undefined;
|
|
17
|
+
const identity = docIdentity(docs[docIndex]);
|
|
18
|
+
const resource = scopeQuery.resourceFor(identity.kind, identity.name);
|
|
19
|
+
if (!resource)
|
|
20
|
+
return undefined;
|
|
21
|
+
const stepPath = scopeQuery.stepDeclarationPath(resource, stepName);
|
|
22
|
+
if (!stepPath)
|
|
23
|
+
return undefined;
|
|
24
|
+
const file = loadedFile(graph, filePath);
|
|
25
|
+
const index = file?.positions[docIndex]?.positionIndex;
|
|
26
|
+
if (!index)
|
|
27
|
+
return undefined;
|
|
28
|
+
// The step's own `name:` value is what the jump underlines — the step object's
|
|
29
|
+
// range would highlight the whole block, which reads as a selection rather
|
|
30
|
+
// than as a declaration.
|
|
31
|
+
const range = index.get(`${stepPath}.name`) ?? index.get(`@key:${stepPath}.name`) ?? index.get(stepPath);
|
|
32
|
+
return range ? { uri: file.source, range } : undefined;
|
|
33
|
+
}
|
|
@@ -13,5 +13,15 @@ import type { DefinitionResult } from "../types.js";
|
|
|
13
13
|
* analyzer reports the syntax error itself. Only that failure is tolerated: a
|
|
14
14
|
* defect in the CEL wrapper propagates rather than reading as "nothing to
|
|
15
15
|
* navigate to". */
|
|
16
|
-
export
|
|
16
|
+
export interface CelTargetResolvers {
|
|
17
|
+
/** Where a step of the CURRENT resource is declared. Supplied by the caller
|
|
18
|
+
* because finding one needs the declaring kind's step-body annotation, which
|
|
19
|
+
* the graph alone does not carry. */
|
|
20
|
+
locateStep?(stepName: string): DefinitionResult | undefined;
|
|
21
|
+
/** Where a context binding (`request.query`, `self.<field>`,
|
|
22
|
+
* `result.<field>`) was declared. Same reason: the site is derived by an
|
|
23
|
+
* `x-telo-context-*` annotation, which only the scope query can read. */
|
|
24
|
+
locateContextBinding?(parts: string[]): DefinitionResult | undefined;
|
|
25
|
+
}
|
|
26
|
+
export declare function resolveCelTarget(graph: LoadedGraph, currentModule: LoadedModule, segment: CelSegment, offset: number, resolvers?: CelTargetResolvers): DefinitionResult | undefined;
|
|
17
27
|
//# sourceMappingURL=resolve-cel-target.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-cel-target.d.ts","sourceRoot":"","sources":["../../src/definition/resolve-cel-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqCpD;;;;;;;;;;;;oBAYoB;AACpB,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,YAAY,EAC3B,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"resolve-cel-target.d.ts","sourceRoot":"","sources":["../../src/definition/resolve-cel-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqCpD;;;;;;;;;;;;oBAYoB;AACpB,MAAM,WAAW,kBAAkB;IACjC;;0CAEsC;IACtC,UAAU,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC5D;;8EAE0E;IAC1E,oBAAoB,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,GAAG,SAAS,CAAC;CACtE;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,YAAY,EAC3B,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,kBAAkB,GAC7B,gBAAgB,GAAG,SAAS,CAkC9B"}
|
|
@@ -25,20 +25,7 @@ function resolveResourceChain(graph, currentModule, parts, index) {
|
|
|
25
25
|
return resolveExportedResource(graph, edge.targetSource, parts[2].name);
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
* `variables` / `secrets` / `ports` navigate to their block on the module doc,
|
|
31
|
-
* and their member to that block's entry. `resources` navigates through the
|
|
32
|
-
* same instance lookup a `!ref` uses. Anything else (a step result, a handler
|
|
33
|
-
* scope like `request`, a member of a resolved value) has no manifest
|
|
34
|
-
* declaration to jump to and resolves to nothing.
|
|
35
|
-
*
|
|
36
|
-
* A body the author is still writing may not parse; that means there is no
|
|
37
|
-
* chain to hit-test, not an error to surface from a navigation request — the
|
|
38
|
-
* analyzer reports the syntax error itself. Only that failure is tolerated: a
|
|
39
|
-
* defect in the CEL wrapper propagates rather than reading as "nothing to
|
|
40
|
-
* navigate to". */
|
|
41
|
-
export function resolveCelTarget(graph, currentModule, segment, offset) {
|
|
28
|
+
export function resolveCelTarget(graph, currentModule, segment, offset, resolvers) {
|
|
42
29
|
let ast;
|
|
43
30
|
try {
|
|
44
31
|
ast = segment.ast();
|
|
@@ -62,5 +49,18 @@ export function resolveCelTarget(graph, currentModule, segment, offset) {
|
|
|
62
49
|
}
|
|
63
50
|
if (root === "resources")
|
|
64
51
|
return resolveResourceChain(graph, currentModule, parts, index);
|
|
52
|
+
// `steps.<name>` navigates to the step; `steps` itself and `.result` do not —
|
|
53
|
+
// the first names no one step, the second is the contract's output, which is
|
|
54
|
+
// declared by the invoked target rather than at the read site.
|
|
55
|
+
if (root === "steps" && index === 1 && resolvers?.locateStep) {
|
|
56
|
+
return resolvers.locateStep(parts[1].name);
|
|
57
|
+
}
|
|
58
|
+
// Anything else in scope came from an `x-telo-context-*` annotation, which
|
|
59
|
+
// names a real manifest node for `request` / `self` / `result` and friends.
|
|
60
|
+
// The chain UP TO the cursor is what resolves — hovering `query` in
|
|
61
|
+
// `request.query.lastEventId` navigates to `query`, not to the leaf.
|
|
62
|
+
if (index >= 1 && resolvers?.locateContextBinding) {
|
|
63
|
+
return resolvers.locateContextBinding(parts.slice(0, index + 1).map((p) => p.name));
|
|
64
|
+
}
|
|
65
65
|
return undefined;
|
|
66
66
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A document's `kind` + `metadata.name` — the pair that names the resource an
|
|
3
|
+
* analyzed manifest set holds it under.
|
|
4
|
+
*
|
|
5
|
+
* Its own module because it is a document-identity primitive, not a completion
|
|
6
|
+
* one: hover, semantic tokens and both declaration locators need it, and
|
|
7
|
+
* reaching it through the completion entry point dragged that whole module
|
|
8
|
+
* graph — CEL completion, call-input resolution, the import-source machinery —
|
|
9
|
+
* into surfaces that use none of it.
|
|
10
|
+
*/
|
|
11
|
+
import type { AstDocument } from "@telorun/analyzer";
|
|
12
|
+
/** Either half may be absent while the author is still writing the document. */
|
|
13
|
+
export declare function docIdentity(doc: AstDocument | undefined): {
|
|
14
|
+
kind?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=doc-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-identity.d.ts","sourceRoot":"","sources":["../src/doc-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,mBAAmB,CAAC;AAK7D,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAc1F"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const scalar = (node) => node?.kind === "scalar" && typeof node.value === "string" ? node.value : undefined;
|
|
2
|
+
/** Either half may be absent while the author is still writing the document. */
|
|
3
|
+
export function docIdentity(doc) {
|
|
4
|
+
if (doc?.root?.kind !== "map")
|
|
5
|
+
return {};
|
|
6
|
+
let kind;
|
|
7
|
+
let name;
|
|
8
|
+
for (const pair of doc.root.entries) {
|
|
9
|
+
const key = scalar(pair.key);
|
|
10
|
+
if (key === "kind")
|
|
11
|
+
kind = scalar(pair.value);
|
|
12
|
+
else if (key === "metadata" && pair.value?.kind === "map") {
|
|
13
|
+
const meta = pair.value;
|
|
14
|
+
const nameEntry = meta.entries.find((e) => scalar(e.key) === "name");
|
|
15
|
+
name = scalar(nameEntry?.value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { kind, name };
|
|
19
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { type AnalysisRegistry, type AstDocument } from "@telorun/analyzer";
|
|
1
|
+
import { type AnalysisRegistry, type AstDocument, type ManifestAnalysis } from "@telorun/analyzer";
|
|
2
2
|
import type { HoverResult } from "../types.js";
|
|
3
|
-
export declare function buildHover(text: string, line: number, character: number, registry: AnalysisRegistry | undefined, docs?: AstDocument[]
|
|
3
|
+
export declare function buildHover(text: string, line: number, character: number, registry: AnalysisRegistry | undefined, docs?: AstDocument[],
|
|
4
|
+
/** The host's analysis. Without it a CEL identifier hovers as nothing — its
|
|
5
|
+
* type is a property of the resolved scope, and there is no second source
|
|
6
|
+
* for it. */
|
|
7
|
+
analysis?: ManifestAnalysis): HoverResult | undefined;
|
|
4
8
|
//# sourceMappingURL=build-hover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-hover.d.ts","sourceRoot":"","sources":["../../src/hover/build-hover.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"build-hover.d.ts","sourceRoot":"","sources":["../../src/hover/build-hover.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAGhB,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA8F/C,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,IAAI,CAAC,EAAE,WAAW,EAAE;AACpB;;cAEc;AACd,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,WAAW,GAAG,SAAS,CAczB"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { parseToAst, readRefSlot, } from "@telorun/analyzer";
|
|
1
|
+
import { CelParseError, parseToAst, readRefSlot, } from "@telorun/analyzer";
|
|
2
|
+
import { chainAt } from "../cel-chain.js";
|
|
3
|
+
import { celSymbolAt } from "../cel/symbols.js";
|
|
4
|
+
import { docIdentity } from "../doc-identity.js";
|
|
2
5
|
import { navigateSchema } from "../completions/detect-context.js";
|
|
3
6
|
import { resolveNodeAtPosition, scalarString, } from "../completions/resolve-node.js";
|
|
4
7
|
import { CAPABILITY_DOCS } from "../completions/valid-capabilities.js";
|
|
@@ -79,17 +82,75 @@ function fieldSchemaFor(resourceKind, relativePath, registry) {
|
|
|
79
82
|
const def = registry.resolveDefinition(resourceKind);
|
|
80
83
|
if (!def?.schema)
|
|
81
84
|
return undefined;
|
|
82
|
-
return navigateSchema(def.schema, relativePath);
|
|
85
|
+
return navigateSchema(def.schema, relativePath, (from) => registry.resolveSchemaFrom(from, resourceKind));
|
|
83
86
|
}
|
|
84
|
-
export function buildHover(text, line, character, registry, docs
|
|
87
|
+
export function buildHover(text, line, character, registry, docs,
|
|
88
|
+
/** The host's analysis. Without it a CEL identifier hovers as nothing — its
|
|
89
|
+
* type is a property of the resolved scope, and there is no second source
|
|
90
|
+
* for it. */
|
|
91
|
+
analysis) {
|
|
85
92
|
const astDocs = docs ?? parseToAst(text);
|
|
86
93
|
const resolved = resolveNodeAtPosition(text, astDocs, line, character);
|
|
87
94
|
if (!resolved)
|
|
88
95
|
return undefined;
|
|
96
|
+
if (resolved.cel) {
|
|
97
|
+
const hover = hoverForCel(resolved, astDocs, analysis?.celScope);
|
|
98
|
+
// A CEL body is still a field value; when the cursor is on nothing
|
|
99
|
+
// nameable inside it (an operator, a literal), fall through to the field's
|
|
100
|
+
// own hover rather than reporting nothing.
|
|
101
|
+
if (hover)
|
|
102
|
+
return hover;
|
|
103
|
+
}
|
|
89
104
|
if (resolved.slot === "value")
|
|
90
105
|
return hoverForValue(resolved, registry);
|
|
91
106
|
return hoverForKey(resolved, registry);
|
|
92
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Hover for one identifier of a CEL chain.
|
|
110
|
+
*
|
|
111
|
+
* The TYPE comes from the resolved scope; a DESCRIPTION comes from whatever
|
|
112
|
+
* schema node declared the name. Where to jump is the other half's answer
|
|
113
|
+
* (`resolveCelTarget`) and is deliberately not consulted here — hover must
|
|
114
|
+
* still say what `steps.encode.result` IS even though nothing in the manifest
|
|
115
|
+
* declares it.
|
|
116
|
+
*/
|
|
117
|
+
function hoverForCel(resolved, docs, scopeQuery) {
|
|
118
|
+
if (!resolved.cel || !scopeQuery)
|
|
119
|
+
return undefined;
|
|
120
|
+
const identity = docIdentity(docs[resolved.docIndex]);
|
|
121
|
+
const resource = scopeQuery.resourceFor(identity.kind, identity.name);
|
|
122
|
+
if (!resource)
|
|
123
|
+
return undefined;
|
|
124
|
+
let ast;
|
|
125
|
+
try {
|
|
126
|
+
ast = resolved.cel.segment.ast();
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// An expression the author is still writing does not parse. That means
|
|
130
|
+
// there is no chain to hit-test, not an error to report from a hover — the
|
|
131
|
+
// analyzer reports the syntax error itself. Only that failure is tolerated.
|
|
132
|
+
if (!(error instanceof CelParseError))
|
|
133
|
+
throw error;
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const hit = chainAt(ast, resolved.cel.offset);
|
|
137
|
+
if (!hit)
|
|
138
|
+
return undefined;
|
|
139
|
+
// The chain UP TO the cursor, not the whole chain: hovering `resources` in
|
|
140
|
+
// `resources.db.url` describes `resources`.
|
|
141
|
+
const parts = hit.parts.slice(0, hit.index + 1).map((p) => p.name);
|
|
142
|
+
const scope = scopeQuery.scopeAt(resource, resolved.concretePath ?? "");
|
|
143
|
+
const symbol = celSymbolAt(scope, parts);
|
|
144
|
+
if (!symbol)
|
|
145
|
+
return undefined;
|
|
146
|
+
const lines = [symbol.type ? `**${symbol.name}**: \`${symbol.type}\`` : `**${symbol.name}**`];
|
|
147
|
+
if (symbol.description)
|
|
148
|
+
lines.push("", symbol.description);
|
|
149
|
+
const chainText = parts.join(".");
|
|
150
|
+
if (chainText !== symbol.name)
|
|
151
|
+
lines.push("", `\`${chainText}\``);
|
|
152
|
+
return { contents: lines.join("\n") };
|
|
153
|
+
}
|
|
93
154
|
function hoverForValue(resolved, registry) {
|
|
94
155
|
const key = resolved.path[resolved.path.length - 1];
|
|
95
156
|
const value = scalarString(resolved.node);
|
package/dist/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export * from "./semantic-tokens/index.js";
|
|
|
6
6
|
export * from "./definition/index.js";
|
|
7
7
|
export * from "./rename/index.js";
|
|
8
8
|
export * from "./import-upgrades/index.js";
|
|
9
|
+
export { walkCel, flattenChain, chainAt, type ChainPart } from "./cel-chain.js";
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,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,4BAA4B,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,4BAA4B,CAAC;AAI3C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,3 +6,7 @@ export * from "./semantic-tokens/index.js";
|
|
|
6
6
|
export * from "./definition/index.js";
|
|
7
7
|
export * from "./rename/index.js";
|
|
8
8
|
export * from "./import-upgrades/index.js";
|
|
9
|
+
// The repo's single CEL-tree walk. Exported because every host that has to
|
|
10
|
+
// answer "where is this name read" needs it and a second copy would be a second
|
|
11
|
+
// answer — the editor asks it before deleting a resource.
|
|
12
|
+
export { walkCel, flattenChain, chainAt } from "./cel-chain.js";
|