@microsoft/inshellisense 0.0.1-rc.8 → 0.0.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/LICENSE +21 -21
- package/README.md +111 -12
- package/SECURITY.md +41 -41
- package/bin.js +30 -0
- package/package.json +18 -66
- package/build/commands/complete.js +0 -15
- package/build/commands/root.js +0 -32
- package/build/commands/uninstall.js +0 -11
- package/build/index.js +0 -28
- package/build/isterm/commandManager.js +0 -220
- package/build/isterm/index.js +0 -4
- package/build/isterm/pty.js +0 -257
- package/build/runtime/generator.js +0 -53
- package/build/runtime/model.js +0 -3
- package/build/runtime/parser.js +0 -63
- package/build/runtime/runtime.js +0 -241
- package/build/runtime/suggestion.js +0 -204
- package/build/runtime/template.js +0 -41
- package/build/runtime/utils.js +0 -52
- package/build/ui/suggestionManager.js +0 -151
- package/build/ui/ui-root.js +0 -137
- package/build/ui/ui-uninstall.js +0 -9
- package/build/ui/utils.js +0 -41
- package/build/utils/ansi.js +0 -33
- package/build/utils/config.js +0 -68
- package/build/utils/log.js +0 -30
- package/build/utils/shell.js +0 -93
- package/build/utils/version.js +0 -13
- package/shell/bash-preexec.sh +0 -380
- package/shell/shellIntegration-env.zsh +0 -9
- package/shell/shellIntegration-login.zsh +0 -4
- package/shell/shellIntegration-profile.zsh +0 -4
- package/shell/shellIntegration-rc.zsh +0 -58
- package/shell/shellIntegration.bash +0 -68
- package/shell/shellIntegration.fish +0 -19
- package/shell/shellIntegration.ps1 +0 -24
package/build/runtime/runtime.js
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import speclist, { diffVersionedCompletions as versionedSpeclist,
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
} from "@withfig/autocomplete/build/index.js";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import { parseCommand } from "./parser.js";
|
|
9
|
-
import { getArgDrivenRecommendation, getSubcommandDrivenRecommendation } from "./suggestion.js";
|
|
10
|
-
import { buildExecuteShellCommand, resolveCwd } from "./utils.js";
|
|
11
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- recursive type, setting as any
|
|
12
|
-
const specSet = {};
|
|
13
|
-
speclist.forEach((s) => {
|
|
14
|
-
let activeSet = specSet;
|
|
15
|
-
const specRoutes = s.split("/");
|
|
16
|
-
specRoutes.forEach((route, idx) => {
|
|
17
|
-
if (typeof activeSet !== "object") {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (idx === specRoutes.length - 1) {
|
|
21
|
-
const prefix = versionedSpeclist.includes(s) ? "/index.js" : `.js`;
|
|
22
|
-
activeSet[route] = `@withfig/autocomplete/build/${s}${prefix}`;
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
activeSet[route] = activeSet[route] || {};
|
|
26
|
-
activeSet = activeSet[route];
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
const loadedSpecs = {};
|
|
31
|
-
const loadSpec = async (cmd) => {
|
|
32
|
-
const rootToken = cmd.at(0);
|
|
33
|
-
if (!rootToken?.complete) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (loadedSpecs[rootToken.token]) {
|
|
37
|
-
return loadedSpecs[rootToken.token];
|
|
38
|
-
}
|
|
39
|
-
if (specSet[rootToken.token]) {
|
|
40
|
-
const spec = (await import(specSet[rootToken.token])).default;
|
|
41
|
-
loadedSpecs[rootToken.token] = spec;
|
|
42
|
-
return spec;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
// this load spec function should only be used for `loadSpec` on the fly as it is cacheless
|
|
46
|
-
const lazyLoadSpec = async (key) => {
|
|
47
|
-
return (await import(`@withfig/autocomplete/build/${key}.js`)).default;
|
|
48
|
-
};
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- will be implemented in below TODO
|
|
50
|
-
const lazyLoadSpecLocation = async (location) => {
|
|
51
|
-
return; //TODO: implement spec location loading
|
|
52
|
-
};
|
|
53
|
-
export const getSuggestions = async (cmd, cwd, shell) => {
|
|
54
|
-
const activeCmd = parseCommand(cmd);
|
|
55
|
-
const rootToken = activeCmd.at(0);
|
|
56
|
-
if (activeCmd.length === 0 || !rootToken?.complete) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const spec = await loadSpec(activeCmd);
|
|
60
|
-
if (spec == null)
|
|
61
|
-
return;
|
|
62
|
-
const subcommand = getSubcommand(spec);
|
|
63
|
-
if (subcommand == null)
|
|
64
|
-
return;
|
|
65
|
-
const lastCommand = activeCmd.at(-1);
|
|
66
|
-
const { cwd: resolvedCwd, pathy, complete: pathyComplete } = await resolveCwd(lastCommand, cwd, shell);
|
|
67
|
-
if (pathy && lastCommand) {
|
|
68
|
-
lastCommand.isPath = true;
|
|
69
|
-
lastCommand.isPathComplete = pathyComplete;
|
|
70
|
-
}
|
|
71
|
-
const result = await runSubcommand(activeCmd.slice(1), subcommand, resolvedCwd);
|
|
72
|
-
if (result == null)
|
|
73
|
-
return;
|
|
74
|
-
let charactersToDrop = lastCommand?.complete ? 0 : lastCommand?.token.length ?? 0;
|
|
75
|
-
if (pathy) {
|
|
76
|
-
charactersToDrop = pathyComplete ? 0 : path.basename(lastCommand?.token ?? "").length;
|
|
77
|
-
}
|
|
78
|
-
return { ...result, charactersToDrop };
|
|
79
|
-
};
|
|
80
|
-
const getPersistentOptions = (persistentOptions, options) => {
|
|
81
|
-
const persistentOptionNames = new Set(persistentOptions.map((o) => (typeof o.name === "string" ? [o.name] : o.name)).flat());
|
|
82
|
-
return persistentOptions.concat((options ?? []).filter((o) => (typeof o.name == "string" ? !persistentOptionNames.has(o.name) : o.name.some((n) => !persistentOptionNames.has(n))) && o.isPersistent === true));
|
|
83
|
-
};
|
|
84
|
-
// TODO: handle subcommands that are versioned
|
|
85
|
-
const getSubcommand = (spec) => {
|
|
86
|
-
if (spec == null)
|
|
87
|
-
return;
|
|
88
|
-
if (typeof spec === "function") {
|
|
89
|
-
const potentialSubcommand = spec();
|
|
90
|
-
if (Object.prototype.hasOwnProperty.call(potentialSubcommand, "name")) {
|
|
91
|
-
return potentialSubcommand;
|
|
92
|
-
}
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
return spec;
|
|
96
|
-
};
|
|
97
|
-
const executeShellCommand = buildExecuteShellCommand(5000);
|
|
98
|
-
const genSubcommand = async (command, parentCommand) => {
|
|
99
|
-
if (!parentCommand.subcommands || parentCommand.subcommands.length === 0)
|
|
100
|
-
return;
|
|
101
|
-
const subcommandIdx = parentCommand.subcommands.findIndex((s) => (Array.isArray(s.name) ? s.name.includes(command) : s.name === command));
|
|
102
|
-
if (subcommandIdx === -1)
|
|
103
|
-
return;
|
|
104
|
-
const subcommand = parentCommand.subcommands[subcommandIdx];
|
|
105
|
-
// this pulls in the spec from the load spec and overwrites the subcommand in the parent with the loaded spec.
|
|
106
|
-
// then it returns the subcommand and clears the loadSpec field so that it doesn't get called again
|
|
107
|
-
switch (typeof subcommand.loadSpec) {
|
|
108
|
-
case "function": {
|
|
109
|
-
const partSpec = await subcommand.loadSpec(command, executeShellCommand);
|
|
110
|
-
if (partSpec instanceof Array) {
|
|
111
|
-
const locationSpecs = (await Promise.all(partSpec.map((s) => lazyLoadSpecLocation(s)))).filter((s) => s != null);
|
|
112
|
-
const subcommands = locationSpecs.map((s) => getSubcommand(s)).filter((s) => s != null);
|
|
113
|
-
parentCommand.subcommands[subcommandIdx] = {
|
|
114
|
-
...subcommand,
|
|
115
|
-
...(subcommands.find((s) => s?.name == command) ?? []),
|
|
116
|
-
loadSpec: undefined,
|
|
117
|
-
};
|
|
118
|
-
return parentCommand.subcommands[subcommandIdx];
|
|
119
|
-
}
|
|
120
|
-
else if (Object.prototype.hasOwnProperty.call(partSpec, "type")) {
|
|
121
|
-
const locationSingleSpec = await lazyLoadSpecLocation(partSpec);
|
|
122
|
-
parentCommand.subcommands[subcommandIdx] = {
|
|
123
|
-
...subcommand,
|
|
124
|
-
...(getSubcommand(locationSingleSpec) ?? []),
|
|
125
|
-
loadSpec: undefined,
|
|
126
|
-
};
|
|
127
|
-
return parentCommand.subcommands[subcommandIdx];
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
parentCommand.subcommands[subcommandIdx] = { ...subcommand, ...partSpec, loadSpec: undefined };
|
|
131
|
-
return parentCommand.subcommands[subcommandIdx];
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
case "string": {
|
|
135
|
-
const spec = await lazyLoadSpec(subcommand.loadSpec);
|
|
136
|
-
parentCommand.subcommands[subcommandIdx] = { ...subcommand, ...(getSubcommand(spec) ?? []), loadSpec: undefined };
|
|
137
|
-
return parentCommand.subcommands[subcommandIdx];
|
|
138
|
-
}
|
|
139
|
-
case "object": {
|
|
140
|
-
parentCommand.subcommands[subcommandIdx] = { ...subcommand, ...(subcommand.loadSpec ?? {}), loadSpec: undefined };
|
|
141
|
-
return parentCommand.subcommands[subcommandIdx];
|
|
142
|
-
}
|
|
143
|
-
case "undefined": {
|
|
144
|
-
return subcommand;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
const getOption = (activeToken, options) => {
|
|
149
|
-
return options.find((o) => (typeof o.name === "string" ? o.name === activeToken.token : o.name.includes(activeToken.token)));
|
|
150
|
-
};
|
|
151
|
-
const getPersistentTokens = (tokens) => {
|
|
152
|
-
return tokens.filter((t) => t.isPersistent === true);
|
|
153
|
-
};
|
|
154
|
-
const getArgs = (args) => {
|
|
155
|
-
return args instanceof Array ? args : args != null ? [args] : [];
|
|
156
|
-
};
|
|
157
|
-
const runOption = async (tokens, option, subcommand, cwd, persistentOptions, acceptedTokens) => {
|
|
158
|
-
if (tokens.length === 0) {
|
|
159
|
-
throw new Error("invalid state reached, option expected but no tokens found");
|
|
160
|
-
}
|
|
161
|
-
const activeToken = tokens[0];
|
|
162
|
-
const isPersistent = persistentOptions.some((o) => (typeof o.name === "string" ? o.name === activeToken.token : o.name.includes(activeToken.token)));
|
|
163
|
-
if ((option.args instanceof Array && option.args.length > 0) || option.args != null) {
|
|
164
|
-
const args = option.args instanceof Array ? option.args : [option.args];
|
|
165
|
-
return runArg(tokens.slice(1), args, subcommand, cwd, persistentOptions, acceptedTokens.concat(activeToken), true, false);
|
|
166
|
-
}
|
|
167
|
-
return runSubcommand(tokens.slice(1), subcommand, cwd, persistentOptions, acceptedTokens.concat({ ...activeToken, isPersistent }));
|
|
168
|
-
};
|
|
169
|
-
const runArg = async (tokens, args, subcommand, cwd, persistentOptions, acceptedTokens, fromOption, fromVariadic) => {
|
|
170
|
-
if (args.length === 0) {
|
|
171
|
-
return runSubcommand(tokens, subcommand, cwd, persistentOptions, acceptedTokens, true, !fromOption);
|
|
172
|
-
}
|
|
173
|
-
else if (tokens.length === 0) {
|
|
174
|
-
return await getArgDrivenRecommendation(args, subcommand, persistentOptions, undefined, acceptedTokens, fromVariadic, cwd);
|
|
175
|
-
}
|
|
176
|
-
else if (!tokens.at(0)?.complete) {
|
|
177
|
-
return await getArgDrivenRecommendation(args, subcommand, persistentOptions, tokens[0], acceptedTokens, fromVariadic, cwd);
|
|
178
|
-
}
|
|
179
|
-
const activeToken = tokens[0];
|
|
180
|
-
if (args.every((a) => a.isOptional)) {
|
|
181
|
-
if (activeToken.isOption) {
|
|
182
|
-
const option = getOption(activeToken, persistentOptions.concat(subcommand.options ?? []));
|
|
183
|
-
if (option != null) {
|
|
184
|
-
return runOption(tokens, option, subcommand, cwd, persistentOptions, acceptedTokens);
|
|
185
|
-
}
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
const nextSubcommand = await genSubcommand(activeToken.token, subcommand);
|
|
189
|
-
if (nextSubcommand != null) {
|
|
190
|
-
return runSubcommand(tokens.slice(1), nextSubcommand, cwd, persistentOptions, getPersistentTokens(acceptedTokens.concat(activeToken)));
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
const activeArg = args[0];
|
|
194
|
-
if (activeArg.isVariadic) {
|
|
195
|
-
return runArg(tokens.slice(1), args, subcommand, cwd, persistentOptions, acceptedTokens.concat(activeToken), fromOption, true);
|
|
196
|
-
}
|
|
197
|
-
else if (activeArg.isCommand) {
|
|
198
|
-
if (tokens.length <= 0) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
const spec = await loadSpec(tokens);
|
|
202
|
-
if (spec == null)
|
|
203
|
-
return;
|
|
204
|
-
const subcommand = getSubcommand(spec);
|
|
205
|
-
if (subcommand == null)
|
|
206
|
-
return;
|
|
207
|
-
return runSubcommand(tokens.slice(1), subcommand, cwd);
|
|
208
|
-
}
|
|
209
|
-
return runArg(tokens.slice(1), args.slice(1), subcommand, cwd, persistentOptions, acceptedTokens.concat(activeToken), fromOption, false);
|
|
210
|
-
};
|
|
211
|
-
const runSubcommand = async (tokens, subcommand, cwd, persistentOptions = [], acceptedTokens = [], argsDepleted = false, argsUsed = false) => {
|
|
212
|
-
if (tokens.length === 0) {
|
|
213
|
-
return getSubcommandDrivenRecommendation(subcommand, persistentOptions, undefined, argsDepleted, argsUsed, acceptedTokens, cwd);
|
|
214
|
-
}
|
|
215
|
-
else if (!tokens.at(0)?.complete) {
|
|
216
|
-
return getSubcommandDrivenRecommendation(subcommand, persistentOptions, tokens[0], argsDepleted, argsUsed, acceptedTokens, cwd);
|
|
217
|
-
}
|
|
218
|
-
const activeToken = tokens[0];
|
|
219
|
-
const activeArgsLength = subcommand.args instanceof Array ? subcommand.args.length : 1;
|
|
220
|
-
const allOptions = [...persistentOptions, ...(subcommand.options ?? [])];
|
|
221
|
-
if (activeToken.isOption) {
|
|
222
|
-
const option = getOption(activeToken, allOptions);
|
|
223
|
-
if (option != null) {
|
|
224
|
-
return runOption(tokens, option, subcommand, cwd, persistentOptions, acceptedTokens);
|
|
225
|
-
}
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const nextSubcommand = await genSubcommand(activeToken.token, subcommand);
|
|
229
|
-
if (nextSubcommand != null) {
|
|
230
|
-
return runSubcommand(tokens.slice(1), nextSubcommand, cwd, getPersistentOptions(persistentOptions, subcommand.options), getPersistentTokens(acceptedTokens.concat(activeToken)));
|
|
231
|
-
}
|
|
232
|
-
if (activeArgsLength <= 0) {
|
|
233
|
-
return; // not subcommand or option & no args exist
|
|
234
|
-
}
|
|
235
|
-
const args = getArgs(subcommand.args);
|
|
236
|
-
if (args.length != 0) {
|
|
237
|
-
return runArg(tokens, args, subcommand, cwd, allOptions, acceptedTokens, false, false);
|
|
238
|
-
}
|
|
239
|
-
// if the subcommand has no args specified, fallback to the subcommand and ignore this item
|
|
240
|
-
return runSubcommand(tokens.slice(1), subcommand, cwd, persistentOptions, acceptedTokens.concat(activeToken));
|
|
241
|
-
};
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { runGenerator } from "./generator.js";
|
|
5
|
-
import { runTemplates } from "./template.js";
|
|
6
|
-
var SuggestionIcons;
|
|
7
|
-
(function (SuggestionIcons) {
|
|
8
|
-
SuggestionIcons["File"] = "\uD83D\uDCC4";
|
|
9
|
-
SuggestionIcons["Folder"] = "\uD83D\uDCC1";
|
|
10
|
-
SuggestionIcons["Subcommand"] = "\uD83D\uDCE6";
|
|
11
|
-
SuggestionIcons["Option"] = "\uD83D\uDD17";
|
|
12
|
-
SuggestionIcons["Argument"] = "\uD83D\uDCB2";
|
|
13
|
-
SuggestionIcons["Mixin"] = "\uD83C\uDFDD\uFE0F";
|
|
14
|
-
SuggestionIcons["Shortcut"] = "\uD83D\uDD25";
|
|
15
|
-
SuggestionIcons["Special"] = "\u2B50";
|
|
16
|
-
SuggestionIcons["Default"] = "\uD83D\uDCC0";
|
|
17
|
-
})(SuggestionIcons || (SuggestionIcons = {}));
|
|
18
|
-
const getIcon = (suggestionType) => {
|
|
19
|
-
switch (suggestionType) {
|
|
20
|
-
case "arg":
|
|
21
|
-
return SuggestionIcons.Argument;
|
|
22
|
-
case "file":
|
|
23
|
-
return SuggestionIcons.File;
|
|
24
|
-
case "folder":
|
|
25
|
-
return SuggestionIcons.Folder;
|
|
26
|
-
case "option":
|
|
27
|
-
return SuggestionIcons.Option;
|
|
28
|
-
case "subcommand":
|
|
29
|
-
return SuggestionIcons.Subcommand;
|
|
30
|
-
case "mixin":
|
|
31
|
-
return SuggestionIcons.Mixin;
|
|
32
|
-
case "shortcut":
|
|
33
|
-
return SuggestionIcons.Shortcut;
|
|
34
|
-
case "special":
|
|
35
|
-
return SuggestionIcons.Special;
|
|
36
|
-
}
|
|
37
|
-
return SuggestionIcons.Default;
|
|
38
|
-
};
|
|
39
|
-
const getLong = (suggestion) => {
|
|
40
|
-
return suggestion instanceof Array ? suggestion.reduce((p, c) => (p.length > c.length ? p : c)) : suggestion;
|
|
41
|
-
};
|
|
42
|
-
const toSuggestion = (suggestion, name, type) => {
|
|
43
|
-
if (suggestion.name == null)
|
|
44
|
-
return;
|
|
45
|
-
return {
|
|
46
|
-
name: name ?? getLong(suggestion.name),
|
|
47
|
-
description: suggestion.description,
|
|
48
|
-
icon: getIcon(type ?? suggestion.type),
|
|
49
|
-
allNames: suggestion.name instanceof Array ? suggestion.name : [suggestion.name],
|
|
50
|
-
priority: suggestion.priority ?? 50,
|
|
51
|
-
insertValue: suggestion.insertValue,
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
function filter(suggestions, filterStrategy, partialCmd, suggestionType) {
|
|
55
|
-
if (!partialCmd)
|
|
56
|
-
return suggestions.map((s) => toSuggestion(s, undefined, suggestionType)).filter((s) => s != null);
|
|
57
|
-
switch (filterStrategy) {
|
|
58
|
-
case "fuzzy":
|
|
59
|
-
return suggestions
|
|
60
|
-
.map((s) => {
|
|
61
|
-
if (s.name == null)
|
|
62
|
-
return;
|
|
63
|
-
if (s.name instanceof Array) {
|
|
64
|
-
const matchedName = s.name.find((n) => n.toLowerCase().includes(partialCmd.toLowerCase()));
|
|
65
|
-
return matchedName != null
|
|
66
|
-
? {
|
|
67
|
-
name: matchedName,
|
|
68
|
-
description: s.description,
|
|
69
|
-
icon: getIcon(s.type ?? suggestionType),
|
|
70
|
-
allNames: s.name,
|
|
71
|
-
priority: s.priority ?? 50,
|
|
72
|
-
insertValue: s.insertValue,
|
|
73
|
-
}
|
|
74
|
-
: undefined;
|
|
75
|
-
}
|
|
76
|
-
return s.name.toLowerCase().includes(partialCmd.toLowerCase())
|
|
77
|
-
? {
|
|
78
|
-
name: s.name,
|
|
79
|
-
description: s.description,
|
|
80
|
-
icon: getIcon(s.type ?? suggestionType),
|
|
81
|
-
allNames: [s.name],
|
|
82
|
-
priority: s.priority ?? 50,
|
|
83
|
-
insertValue: s.insertValue,
|
|
84
|
-
}
|
|
85
|
-
: undefined;
|
|
86
|
-
})
|
|
87
|
-
.filter((s) => s != null);
|
|
88
|
-
default:
|
|
89
|
-
return suggestions
|
|
90
|
-
.map((s) => {
|
|
91
|
-
if (s.name == null)
|
|
92
|
-
return;
|
|
93
|
-
if (s.name instanceof Array) {
|
|
94
|
-
const matchedName = s.name.find((n) => n.toLowerCase().startsWith(partialCmd.toLowerCase()));
|
|
95
|
-
return matchedName != null
|
|
96
|
-
? {
|
|
97
|
-
name: matchedName,
|
|
98
|
-
description: s.description,
|
|
99
|
-
icon: getIcon(s.type ?? suggestionType),
|
|
100
|
-
allNames: s.name,
|
|
101
|
-
insertValue: s.insertValue,
|
|
102
|
-
priority: s.priority ?? 50,
|
|
103
|
-
}
|
|
104
|
-
: undefined;
|
|
105
|
-
}
|
|
106
|
-
return s.name.toLowerCase().startsWith(partialCmd.toLowerCase())
|
|
107
|
-
? {
|
|
108
|
-
name: s.name,
|
|
109
|
-
description: s.description,
|
|
110
|
-
icon: getIcon(s.type ?? suggestionType),
|
|
111
|
-
allNames: [s.name],
|
|
112
|
-
insertValue: s.insertValue,
|
|
113
|
-
priority: s.priority ?? 50,
|
|
114
|
-
}
|
|
115
|
-
: undefined;
|
|
116
|
-
})
|
|
117
|
-
.filter((s) => s != null);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const generatorSuggestions = async (generator, acceptedTokens, filterStrategy, partialCmd, cwd) => {
|
|
121
|
-
const generators = generator instanceof Array ? generator : generator ? [generator] : [];
|
|
122
|
-
const tokens = acceptedTokens.map((t) => t.token);
|
|
123
|
-
const suggestions = (await Promise.all(generators.map((gen) => runGenerator(gen, tokens, cwd)))).flat();
|
|
124
|
-
return filter(suggestions, filterStrategy, partialCmd, undefined);
|
|
125
|
-
};
|
|
126
|
-
const templateSuggestions = async (templates, filterStrategy, partialCmd, cwd) => {
|
|
127
|
-
return filter(await runTemplates(templates ?? [], cwd), filterStrategy, partialCmd, undefined);
|
|
128
|
-
};
|
|
129
|
-
const suggestionSuggestions = (suggestions, filterStrategy, partialCmd) => {
|
|
130
|
-
const cleanedSuggestions = suggestions?.map((s) => (typeof s === "string" ? { name: s } : s)) ?? [];
|
|
131
|
-
return filter(cleanedSuggestions ?? [], filterStrategy, partialCmd, undefined);
|
|
132
|
-
};
|
|
133
|
-
const subcommandSuggestions = (subcommands, filterStrategy, partialCmd) => {
|
|
134
|
-
return filter(subcommands ?? [], filterStrategy, partialCmd, "subcommand");
|
|
135
|
-
};
|
|
136
|
-
const optionSuggestions = (options, acceptedTokens, filterStrategy, partialCmd) => {
|
|
137
|
-
const usedOptions = new Set(acceptedTokens.filter((t) => t.isOption).map((t) => t.token));
|
|
138
|
-
const validOptions = options?.filter((o) => o.exclusiveOn?.every((exclusiveOption) => !usedOptions.has(exclusiveOption)) ?? true);
|
|
139
|
-
return filter(validOptions ?? [], filterStrategy, partialCmd, "option");
|
|
140
|
-
};
|
|
141
|
-
const removeAcceptedSuggestions = (suggestions, acceptedTokens) => {
|
|
142
|
-
const seen = new Set(acceptedTokens.map((t) => t.token));
|
|
143
|
-
return suggestions.filter((s) => s.allNames.every((n) => !seen.has(n)));
|
|
144
|
-
};
|
|
145
|
-
const removeDuplicateSuggestion = (suggestions) => {
|
|
146
|
-
const seen = new Set();
|
|
147
|
-
return suggestions
|
|
148
|
-
.map((s) => {
|
|
149
|
-
if (seen.has(s.name))
|
|
150
|
-
return null;
|
|
151
|
-
seen.add(s.name);
|
|
152
|
-
return s;
|
|
153
|
-
})
|
|
154
|
-
.filter((s) => s != null);
|
|
155
|
-
};
|
|
156
|
-
const removeEmptySuggestion = (suggestions) => {
|
|
157
|
-
return suggestions.filter((s) => s.name.length > 0);
|
|
158
|
-
};
|
|
159
|
-
export const getSubcommandDrivenRecommendation = async (subcommand, persistentOptions, partialToken, argsDepleted, argsFromSubcommand, acceptedTokens, cwd) => {
|
|
160
|
-
if (argsDepleted && argsFromSubcommand) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
let partialCmd = partialToken?.token;
|
|
164
|
-
if (partialToken?.isPath) {
|
|
165
|
-
partialCmd = partialToken.isPathComplete ? "" : path.basename(partialCmd ?? "");
|
|
166
|
-
}
|
|
167
|
-
const suggestions = [];
|
|
168
|
-
const argLength = subcommand.args instanceof Array ? subcommand.args.length : subcommand.args ? 1 : 0;
|
|
169
|
-
const allOptions = persistentOptions.concat(subcommand.options ?? []);
|
|
170
|
-
if (!argsFromSubcommand) {
|
|
171
|
-
suggestions.push(...subcommandSuggestions(subcommand.subcommands, subcommand.filterStrategy, partialCmd));
|
|
172
|
-
suggestions.push(...optionSuggestions(allOptions, acceptedTokens, subcommand.filterStrategy, partialCmd));
|
|
173
|
-
}
|
|
174
|
-
if (argLength != 0) {
|
|
175
|
-
const activeArg = subcommand.args instanceof Array ? subcommand.args[0] : subcommand.args;
|
|
176
|
-
suggestions.push(...(await generatorSuggestions(activeArg?.generators, acceptedTokens, activeArg?.filterStrategy, partialCmd, cwd)));
|
|
177
|
-
suggestions.push(...suggestionSuggestions(activeArg?.suggestions, activeArg?.filterStrategy, partialCmd));
|
|
178
|
-
suggestions.push(...(await templateSuggestions(activeArg?.template, activeArg?.filterStrategy, partialCmd, cwd)));
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
suggestions: removeDuplicateSuggestion(removeEmptySuggestion(removeAcceptedSuggestions(suggestions.sort((a, b) => b.priority - a.priority), acceptedTokens))),
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
export const getArgDrivenRecommendation = async (args, subcommand, persistentOptions, partialToken, acceptedTokens, variadicArgBound, cwd) => {
|
|
185
|
-
let partialCmd = partialToken?.token;
|
|
186
|
-
if (partialToken?.isPath) {
|
|
187
|
-
partialCmd = partialToken.isPathComplete ? "" : path.basename(partialCmd ?? "");
|
|
188
|
-
}
|
|
189
|
-
const activeArg = args[0];
|
|
190
|
-
const allOptions = persistentOptions.concat(subcommand.options ?? []);
|
|
191
|
-
const suggestions = [
|
|
192
|
-
...(await generatorSuggestions(args[0].generators, acceptedTokens, activeArg?.filterStrategy, partialCmd, cwd)),
|
|
193
|
-
...suggestionSuggestions(args[0].suggestions, activeArg?.filterStrategy, partialCmd),
|
|
194
|
-
...(await templateSuggestions(args[0].template, activeArg?.filterStrategy, partialCmd, cwd)),
|
|
195
|
-
];
|
|
196
|
-
if (activeArg.isOptional || (activeArg.isVariadic && variadicArgBound)) {
|
|
197
|
-
suggestions.push(...subcommandSuggestions(subcommand.subcommands, activeArg?.filterStrategy, partialCmd));
|
|
198
|
-
suggestions.push(...optionSuggestions(allOptions, acceptedTokens, activeArg?.filterStrategy, partialCmd));
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
suggestions: removeDuplicateSuggestion(removeEmptySuggestion(removeAcceptedSuggestions(suggestions.sort((a, b) => b.priority - a.priority), acceptedTokens))),
|
|
202
|
-
argumentDescription: activeArg.description ?? activeArg.name,
|
|
203
|
-
};
|
|
204
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import fsAsync from "node:fs/promises";
|
|
4
|
-
import log from "../utils/log.js";
|
|
5
|
-
const filepathsTemplate = async (cwd) => {
|
|
6
|
-
const files = await fsAsync.readdir(cwd, { withFileTypes: true });
|
|
7
|
-
return files.filter((f) => f.isFile() || f.isDirectory()).map((f) => ({ name: f.name, priority: 90, context: { templateType: "filepaths" } }));
|
|
8
|
-
};
|
|
9
|
-
const foldersTemplate = async (cwd) => {
|
|
10
|
-
const files = await fsAsync.readdir(cwd, { withFileTypes: true });
|
|
11
|
-
return files.filter((f) => f.isDirectory()).map((f) => ({ name: f.name, priority: 90, context: { templateType: "folders" } }));
|
|
12
|
-
};
|
|
13
|
-
// TODO: implement history template
|
|
14
|
-
const historyTemplate = () => {
|
|
15
|
-
return [];
|
|
16
|
-
};
|
|
17
|
-
// TODO: implement help template
|
|
18
|
-
const helpTemplate = () => {
|
|
19
|
-
return [];
|
|
20
|
-
};
|
|
21
|
-
export const runTemplates = async (template, cwd) => {
|
|
22
|
-
const templates = template instanceof Array ? template : [template];
|
|
23
|
-
return (await Promise.all(templates.map(async (t) => {
|
|
24
|
-
try {
|
|
25
|
-
switch (t) {
|
|
26
|
-
case "filepaths":
|
|
27
|
-
return await filepathsTemplate(cwd);
|
|
28
|
-
case "folders":
|
|
29
|
-
return await foldersTemplate(cwd);
|
|
30
|
-
case "history":
|
|
31
|
-
return historyTemplate();
|
|
32
|
-
case "help":
|
|
33
|
-
return helpTemplate();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (e) {
|
|
37
|
-
log.debug({ msg: "template failed", e, template: t, cwd });
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
}))).flat();
|
|
41
|
-
};
|
package/build/runtime/utils.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
|
-
import fsAsync from "node:fs/promises";
|
|
6
|
-
import { Shell } from "../utils/shell.js";
|
|
7
|
-
import log from "../utils/log.js";
|
|
8
|
-
export const buildExecuteShellCommand = (timeout) => async ({ command, env, args, cwd }) => {
|
|
9
|
-
const child = spawn(command, args, { cwd, env });
|
|
10
|
-
setTimeout(() => child.kill("SIGKILL"), timeout);
|
|
11
|
-
let stdout = "";
|
|
12
|
-
let stderr = "";
|
|
13
|
-
child.stdout.on("data", (data) => (stdout += data));
|
|
14
|
-
child.stderr.on("data", (data) => (stderr += data));
|
|
15
|
-
child.on("error", (err) => {
|
|
16
|
-
log.debug({ msg: "shell command failed", e: err.message });
|
|
17
|
-
});
|
|
18
|
-
return new Promise((resolve) => {
|
|
19
|
-
child.on("close", (code) => {
|
|
20
|
-
resolve({
|
|
21
|
-
status: code ?? 0,
|
|
22
|
-
stderr,
|
|
23
|
-
stdout,
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
export const resolveCwd = async (cmdToken, cwd, shell) => {
|
|
29
|
-
if (cmdToken == null)
|
|
30
|
-
return { cwd, pathy: false, complete: false };
|
|
31
|
-
const { token } = cmdToken;
|
|
32
|
-
const sep = shell == Shell.Bash ? "/" : path.sep;
|
|
33
|
-
if (!token.includes(sep))
|
|
34
|
-
return { cwd, pathy: false, complete: false };
|
|
35
|
-
const resolvedCwd = path.isAbsolute(token) ? token : path.join(cwd, token);
|
|
36
|
-
try {
|
|
37
|
-
await fsAsync.access(resolvedCwd, fsAsync.constants.R_OK);
|
|
38
|
-
return { cwd: resolvedCwd, pathy: true, complete: token.endsWith(sep) };
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// fallback to the parent folder if possible
|
|
42
|
-
const baselessCwd = resolvedCwd.substring(0, resolvedCwd.length - path.basename(resolvedCwd).length);
|
|
43
|
-
try {
|
|
44
|
-
await fsAsync.access(baselessCwd, fsAsync.constants.R_OK);
|
|
45
|
-
return { cwd: baselessCwd, pathy: true, complete: token.endsWith(sep) };
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
/*empty*/
|
|
49
|
-
}
|
|
50
|
-
return { cwd, pathy: false, complete: false };
|
|
51
|
-
}
|
|
52
|
-
};
|