@telorun/ide-support 0.23.0 → 0.24.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.
- package/dist/completions/build.d.ts.map +1 -1
- package/dist/completions/build.js +7 -0
- package/dist/completions/detect-context.d.ts +33 -0
- package/dist/completions/detect-context.d.ts.map +1 -1
- package/dist/completions/detect-context.js +52 -0
- package/dist/completions/module-file-completions.d.ts +18 -0
- package/dist/completions/module-file-completions.d.ts.map +1 -0
- package/dist/completions/module-file-completions.js +59 -0
- package/dist/completions/resolve-node.d.ts +23 -5
- package/dist/completions/resolve-node.d.ts.map +1 -1
- package/dist/completions/resolve-node.js +54 -14
- package/dist/completions/value-tag-completions.d.ts +23 -0
- package/dist/completions/value-tag-completions.d.ts.map +1 -0
- package/dist/completions/value-tag-completions.js +39 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +13 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/value-tags/offered-value-tags.d.ts +56 -0
- package/dist/value-tags/offered-value-tags.d.ts.map +1 -0
- package/dist/value-tags/offered-value-tags.js +92 -0
- package/package.json +3 -2
- package/src/completions/build.ts +6 -0
- package/src/completions/detect-context.ts +84 -0
- package/src/completions/module-file-completions.ts +64 -0
- package/src/completions/resolve-node.ts +87 -19
- package/src/completions/value-tag-completions.ts +55 -0
- package/src/index.ts +2 -0
- package/src/types.ts +22 -1
- package/src/value-tags/offered-value-tags.ts +127 -0
|
@@ -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;
|
|
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;
|
|
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
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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
|
-
/**
|
|
42
|
-
*
|
|
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;;
|
|
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
|
-
|
|
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
|
|
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) ?? {
|
|
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
|
|
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, [], "",
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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
|
+
}
|
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
|
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,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,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;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGxF,YAAY,EACV,QAAQ,EACR,KAAK,EACL,kBAAkB,EAClB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACN,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|