@microsoft/inshellisense 0.0.1-rc.21 → 0.0.1-rc.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/package.json +11 -78
  2. package/CODE_OF_CONDUCT.md +0 -9
  3. package/LICENSE +0 -21
  4. package/README.md +0 -132
  5. package/SECURITY.md +0 -41
  6. package/SUPPORT.md +0 -13
  7. package/build/commands/complete.js +0 -16
  8. package/build/commands/doctor.js +0 -11
  9. package/build/commands/init.js +0 -24
  10. package/build/commands/root.js +0 -37
  11. package/build/commands/specs/list.js +0 -26
  12. package/build/commands/specs/root.js +0 -8
  13. package/build/commands/uninstall.js +0 -11
  14. package/build/index.js +0 -35
  15. package/build/isterm/commandManager.js +0 -184
  16. package/build/isterm/index.js +0 -4
  17. package/build/isterm/pty.js +0 -361
  18. package/build/runtime/alias.js +0 -66
  19. package/build/runtime/generator.js +0 -55
  20. package/build/runtime/model.js +0 -3
  21. package/build/runtime/parser.js +0 -133
  22. package/build/runtime/runtime.js +0 -282
  23. package/build/runtime/spec.js +0 -36
  24. package/build/runtime/suggestion.js +0 -232
  25. package/build/runtime/template.js +0 -50
  26. package/build/runtime/utils.js +0 -121
  27. package/build/ui/suggestionManager.js +0 -162
  28. package/build/ui/ui-doctor.js +0 -69
  29. package/build/ui/ui-root.js +0 -141
  30. package/build/ui/ui-uninstall.js +0 -9
  31. package/build/ui/utils.js +0 -57
  32. package/build/utils/ansi.js +0 -37
  33. package/build/utils/config.js +0 -99
  34. package/build/utils/log.js +0 -39
  35. package/build/utils/shell.js +0 -318
  36. package/build/utils/version.js +0 -13
  37. package/scripts/postinstall.js +0 -9
  38. package/shell/bash-preexec.sh +0 -380
  39. package/shell/shellIntegration-env.zsh +0 -12
  40. package/shell/shellIntegration-login.zsh +0 -9
  41. package/shell/shellIntegration-profile.zsh +0 -9
  42. package/shell/shellIntegration-rc.zsh +0 -66
  43. package/shell/shellIntegration.bash +0 -114
  44. package/shell/shellIntegration.fish +0 -27
  45. package/shell/shellIntegration.nu +0 -29
  46. package/shell/shellIntegration.ps1 +0 -26
  47. package/shell/shellIntegration.xsh +0 -31
  48. package/todo.md +0 -17
@@ -1,133 +0,0 @@
1
- // Copyright (c) Microsoft Corporation.
2
- // Licensed under the MIT License.
3
- import wcwidth from "wcwidth";
4
- import { getShellWhitespaceEscapeChar } from "./utils.js";
5
- const cmdDelim = /(\|\|)|(&&)|(;)|(\|)/;
6
- const spaceRegex = /\s/;
7
- export const parseCommand = (command, shell) => {
8
- const lastCommand = command.split(cmdDelim).at(-1)?.trimStart();
9
- const tokens = lastCommand ? lex(lastCommand, shell) : [];
10
- return sanitizeTokens(tokens, shell);
11
- };
12
- const sanitizeTokens = (cmdTokens, shell) => unwrapQuotedTokens(unescapeSpaceTokens(cmdTokens, shell), shell);
13
- // remove escapes around spaces
14
- const unescapeSpaceTokens = (cmdTokens, shell) => {
15
- const escapeChar = getShellWhitespaceEscapeChar(shell);
16
- return cmdTokens.map((cmdToken) => {
17
- const { token, isQuoted } = cmdToken;
18
- if (!isQuoted && token.includes(`${escapeChar} `)) {
19
- return { ...cmdToken, token: token.replaceAll(`${escapeChar} `, " ") };
20
- }
21
- return cmdToken;
22
- });
23
- };
24
- // need to unwrap tokens that are quoted with content after the quotes like `"hello"world`
25
- const unwrapQuotedTokens = (cmdTokens, shell) => {
26
- const escapeChar = getShellWhitespaceEscapeChar(shell);
27
- return cmdTokens.map((cmdToken) => {
28
- const { token, isQuoteContinued } = cmdToken;
29
- if (isQuoteContinued) {
30
- const quoteChar = token[0];
31
- const unquotedToken = token.replaceAll(`${escapeChar}${quoteChar}`, "\u001B").replaceAll(quoteChar, "").replaceAll("\u001B", quoteChar);
32
- return { ...cmdToken, token: unquotedToken };
33
- }
34
- return cmdToken;
35
- });
36
- };
37
- const lex = (command, shell) => {
38
- const tokens = [];
39
- const escapeChar = getShellWhitespaceEscapeChar(shell);
40
- let [readingQuotedString, readingQuoteContinuedString, readingFlag, readingCmd] = [false, false, false, false];
41
- let readingIdx = 0;
42
- let readingQuoteChar = "";
43
- [...command].forEach((char, idx) => {
44
- const reading = readingQuotedString || readingQuoteContinuedString || readingFlag || readingCmd;
45
- if (!reading && (char === `'` || char === `"` || char == "`")) {
46
- [readingQuotedString, readingIdx, readingQuoteChar] = [true, idx, char];
47
- return;
48
- }
49
- else if (!reading && char === `-`) {
50
- [readingFlag, readingIdx] = [true, idx];
51
- return;
52
- }
53
- else if (!reading && !spaceRegex.test(char)) {
54
- [readingCmd, readingIdx] = [true, idx];
55
- return;
56
- }
57
- if (readingQuotedString && char === readingQuoteChar && command.at(idx - 1) !== escapeChar && !spaceRegex.test(command.at(idx + 1) ?? " ")) {
58
- readingQuotedString = false;
59
- readingQuoteContinuedString = true;
60
- }
61
- else if (readingQuotedString && char === readingQuoteChar && command.at(idx - 1) !== escapeChar) {
62
- readingQuotedString = false;
63
- const complete = idx + 1 < command.length && spaceRegex.test(command[idx + 1]);
64
- tokens.push({
65
- token: command.slice(readingIdx + 1, idx),
66
- tokenLength: wcwidth(command.slice(readingIdx + 1, idx)) + 2,
67
- complete,
68
- isOption: false,
69
- isQuoted: true,
70
- });
71
- }
72
- else if (readingQuoteContinuedString && spaceRegex.test(char) && command.at(idx - 1) !== escapeChar) {
73
- readingQuoteContinuedString = false;
74
- tokens.push({
75
- token: command.slice(readingIdx, idx),
76
- tokenLength: wcwidth(command.slice(readingIdx, idx)),
77
- complete: true,
78
- isOption: false,
79
- isQuoted: true,
80
- isQuoteContinued: true,
81
- });
82
- }
83
- else if ((readingFlag && spaceRegex.test(char)) || char === "=") {
84
- readingFlag = false;
85
- tokens.push({
86
- token: command.slice(readingIdx, idx),
87
- tokenLength: wcwidth(command.slice(readingIdx, idx)),
88
- complete: true,
89
- isOption: true,
90
- });
91
- }
92
- else if (readingCmd && spaceRegex.test(char) && command.at(idx - 1) !== escapeChar) {
93
- readingCmd = false;
94
- tokens.push({
95
- token: command.slice(readingIdx, idx),
96
- tokenLength: wcwidth(command.slice(readingIdx, idx)),
97
- complete: true,
98
- isOption: false,
99
- });
100
- }
101
- });
102
- const reading = readingQuotedString || readingQuoteContinuedString || readingFlag || readingCmd;
103
- if (reading) {
104
- if (readingQuotedString) {
105
- tokens.push({
106
- token: command.slice(readingIdx + 1),
107
- tokenLength: wcwidth(command.slice(readingIdx + 1)) + 1,
108
- complete: false,
109
- isOption: false,
110
- isQuoted: true,
111
- });
112
- }
113
- else if (readingQuoteContinuedString) {
114
- tokens.push({
115
- token: command.slice(readingIdx),
116
- tokenLength: wcwidth(command.slice(readingIdx)),
117
- complete: false,
118
- isOption: false,
119
- isQuoted: true,
120
- isQuoteContinued: true,
121
- });
122
- }
123
- else {
124
- tokens.push({
125
- token: command.slice(readingIdx),
126
- tokenLength: wcwidth(command.slice(readingIdx)),
127
- complete: false,
128
- isOption: readingFlag,
129
- });
130
- }
131
- }
132
- return tokens;
133
- };
@@ -1,282 +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
- import { aliasExpand } from "./alias.js";
12
- import { getConfig } from "../utils/config.js";
13
- import log from "../utils/log.js";
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- recursive type, setting as any
15
- const specSet = {};
16
- function loadSpecsSet(speclist, versionedSpeclist, specsPath) {
17
- speclist.forEach((s) => {
18
- let activeSet = specSet;
19
- const specRoutes = s.split("/");
20
- specRoutes.forEach((route, idx) => {
21
- if (typeof activeSet !== "object") {
22
- return;
23
- }
24
- if (idx === specRoutes.length - 1) {
25
- const prefix = versionedSpeclist.includes(s) ? "/index.js" : `.js`;
26
- activeSet[route] = `${specsPath}/${s}${prefix}`;
27
- }
28
- else {
29
- activeSet[route] = activeSet[route] || {};
30
- activeSet = activeSet[route];
31
- }
32
- });
33
- });
34
- }
35
- loadSpecsSet(speclist, versionedSpeclist, `@withfig/autocomplete/build`);
36
- const loadedSpecs = {};
37
- const loadSpec = async (cmd) => {
38
- const rootToken = cmd.at(0);
39
- if (!rootToken?.complete) {
40
- return;
41
- }
42
- if (loadedSpecs[rootToken.token]) {
43
- return loadedSpecs[rootToken.token];
44
- }
45
- if (specSet[rootToken.token]) {
46
- const spec = (await import(specSet[rootToken.token])).default;
47
- loadedSpecs[rootToken.token] = spec;
48
- return spec;
49
- }
50
- };
51
- // this load spec function should only be used for `loadSpec` on the fly as it is cacheless
52
- const lazyLoadSpec = async (key) => {
53
- return (await import(`@withfig/autocomplete/build/${key}.js`)).default;
54
- };
55
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- will be implemented in below TODO
56
- const lazyLoadSpecLocation = async (location) => {
57
- return; //TODO: implement spec location loading
58
- };
59
- export const loadLocalSpecsSet = async () => {
60
- const specsPath = getConfig()?.specs?.path;
61
- if (!specsPath) {
62
- return;
63
- }
64
- try {
65
- await Promise.allSettled(specsPath.map((specPath) => import(path.join(specPath, "index.js"))
66
- .then((res) => {
67
- const { default: speclist, diffVersionedCompletions: versionedSpeclist } = res;
68
- loadSpecsSet(speclist, versionedSpeclist, specPath);
69
- })
70
- .catch((e) => {
71
- log.debug({ msg: "load local spec failed", e: e.message, specPath });
72
- })));
73
- }
74
- catch (e) {
75
- log.debug({ msg: "load local specs failed", e: e.message, specsPath });
76
- }
77
- };
78
- export const getSuggestions = async (cmd, cwd, shell) => {
79
- let activeCmd = parseCommand(cmd, shell);
80
- const rootToken = activeCmd.at(0);
81
- if (activeCmd.length === 0 || !rootToken?.complete) {
82
- return;
83
- }
84
- activeCmd = aliasExpand(activeCmd);
85
- const spec = await loadSpec(activeCmd);
86
- if (spec == null)
87
- return;
88
- const subcommand = getSubcommand(spec);
89
- if (subcommand == null)
90
- return;
91
- const lastCommand = activeCmd.at(-1);
92
- const { cwd: resolvedCwd, pathy, complete: pathyComplete } = await resolveCwd(lastCommand, cwd, shell);
93
- if (pathy && lastCommand) {
94
- lastCommand.isPath = true;
95
- lastCommand.isPathComplete = pathyComplete;
96
- }
97
- const result = await runSubcommand(activeCmd.slice(1), subcommand, resolvedCwd, shell);
98
- if (result == null)
99
- return;
100
- const charactersToDrop = lastCommand?.complete ? 0 : lastCommand?.tokenLength;
101
- return { ...result, charactersToDrop };
102
- };
103
- export const getSpecNames = () => {
104
- return Object.keys(specSet).filter((spec) => !spec.startsWith("@") && spec != "-");
105
- };
106
- const getPersistentOptions = (persistentOptions, options) => {
107
- const persistentOptionNames = new Set(persistentOptions.map((o) => (typeof o.name === "string" ? [o.name] : o.name)).flat());
108
- return persistentOptions.concat((options ?? []).filter((o) => (typeof o.name == "string" ? !persistentOptionNames.has(o.name) : o.name.some((n) => !persistentOptionNames.has(n))) && o.isPersistent === true));
109
- };
110
- // TODO: handle subcommands that are versioned
111
- const getSubcommand = (spec) => {
112
- if (spec == null)
113
- return;
114
- if (typeof spec === "function") {
115
- const potentialSubcommand = spec();
116
- if (Object.prototype.hasOwnProperty.call(potentialSubcommand, "name")) {
117
- return potentialSubcommand;
118
- }
119
- return;
120
- }
121
- return spec;
122
- };
123
- const executeShellCommand = await buildExecuteShellCommand(5000);
124
- const genSubcommand = async (command, parentCommand) => {
125
- if (!parentCommand.subcommands || parentCommand.subcommands.length === 0)
126
- return;
127
- const subcommandIdx = parentCommand.subcommands.findIndex((s) => (Array.isArray(s.name) ? s.name.includes(command) : s.name === command));
128
- if (subcommandIdx === -1)
129
- return;
130
- const subcommand = parentCommand.subcommands[subcommandIdx];
131
- // this pulls in the spec from the load spec and overwrites the subcommand in the parent with the loaded spec.
132
- // then it returns the subcommand and clears the loadSpec field so that it doesn't get called again
133
- switch (typeof subcommand.loadSpec) {
134
- case "function": {
135
- const partSpec = await subcommand.loadSpec(command, executeShellCommand);
136
- if (partSpec instanceof Array) {
137
- const locationSpecs = (await Promise.all(partSpec.map((s) => lazyLoadSpecLocation(s)))).filter((s) => s != null);
138
- const subcommands = locationSpecs.map((s) => getSubcommand(s)).filter((s) => s != null);
139
- parentCommand.subcommands[subcommandIdx] = {
140
- ...subcommand,
141
- ...(subcommands.find((s) => s?.name == command) ?? []),
142
- loadSpec: undefined,
143
- };
144
- return parentCommand.subcommands[subcommandIdx];
145
- }
146
- else if (Object.prototype.hasOwnProperty.call(partSpec, "type")) {
147
- const locationSingleSpec = await lazyLoadSpecLocation(partSpec);
148
- parentCommand.subcommands[subcommandIdx] = {
149
- ...subcommand,
150
- ...(getSubcommand(locationSingleSpec) ?? []),
151
- loadSpec: undefined,
152
- };
153
- return parentCommand.subcommands[subcommandIdx];
154
- }
155
- else {
156
- parentCommand.subcommands[subcommandIdx] = {
157
- ...subcommand,
158
- ...partSpec,
159
- loadSpec: undefined,
160
- };
161
- return parentCommand.subcommands[subcommandIdx];
162
- }
163
- }
164
- case "string": {
165
- const spec = await lazyLoadSpec(subcommand.loadSpec);
166
- parentCommand.subcommands[subcommandIdx] = {
167
- ...subcommand,
168
- ...(getSubcommand(spec) ?? []),
169
- loadSpec: undefined,
170
- };
171
- return parentCommand.subcommands[subcommandIdx];
172
- }
173
- case "object": {
174
- parentCommand.subcommands[subcommandIdx] = {
175
- ...subcommand,
176
- ...(subcommand.loadSpec ?? {}),
177
- loadSpec: undefined,
178
- };
179
- return parentCommand.subcommands[subcommandIdx];
180
- }
181
- case "undefined": {
182
- return subcommand;
183
- }
184
- }
185
- };
186
- const getOption = (activeToken, options) => {
187
- return options.find((o) => (typeof o.name === "string" ? o.name === activeToken.token : o.name.includes(activeToken.token)));
188
- };
189
- const getPersistentTokens = (tokens) => {
190
- return tokens.filter((t) => t.isPersistent === true);
191
- };
192
- const getArgs = (args) => {
193
- return args instanceof Array ? args : args != null ? [args] : [];
194
- };
195
- const runOption = async (tokens, option, subcommand, cwd, shell, persistentOptions, acceptedTokens) => {
196
- if (tokens.length === 0) {
197
- throw new Error("invalid state reached, option expected but no tokens found");
198
- }
199
- const activeToken = tokens[0];
200
- const isPersistent = persistentOptions.some((o) => (typeof o.name === "string" ? o.name === activeToken.token : o.name.includes(activeToken.token)));
201
- if ((option.args instanceof Array && option.args.length > 0) || option.args != null) {
202
- const args = option.args instanceof Array ? option.args : [option.args];
203
- return runArg(tokens.slice(1), args, subcommand, cwd, shell, persistentOptions, acceptedTokens.concat(activeToken), true, false);
204
- }
205
- return runSubcommand(tokens.slice(1), subcommand, cwd, shell, persistentOptions, acceptedTokens.concat({
206
- ...activeToken,
207
- isPersistent,
208
- }));
209
- };
210
- const runArg = async (tokens, args, subcommand, cwd, shell, persistentOptions, acceptedTokens, fromOption, fromVariadic) => {
211
- if (args.length === 0) {
212
- return runSubcommand(tokens, subcommand, cwd, shell, persistentOptions, acceptedTokens, true, !fromOption);
213
- }
214
- else if (tokens.length === 0) {
215
- return await getArgDrivenRecommendation(args, subcommand, persistentOptions, undefined, acceptedTokens, fromVariadic, cwd, shell);
216
- }
217
- else if (!tokens.at(0)?.complete) {
218
- return await getArgDrivenRecommendation(args, subcommand, persistentOptions, tokens[0], acceptedTokens, fromVariadic, cwd, shell);
219
- }
220
- const activeToken = tokens[0];
221
- if (args.every((a) => a.isOptional)) {
222
- if (activeToken.isOption) {
223
- const option = getOption(activeToken, persistentOptions.concat(subcommand.options ?? []));
224
- if (option != null) {
225
- return runOption(tokens, option, subcommand, cwd, shell, persistentOptions, acceptedTokens);
226
- }
227
- return;
228
- }
229
- const nextSubcommand = await genSubcommand(activeToken.token, subcommand);
230
- if (nextSubcommand != null) {
231
- return runSubcommand(tokens.slice(1), nextSubcommand, cwd, shell, persistentOptions, getPersistentTokens(acceptedTokens.concat(activeToken)));
232
- }
233
- }
234
- const activeArg = args[0];
235
- if (activeArg.isVariadic) {
236
- return runArg(tokens.slice(1), args, subcommand, cwd, shell, persistentOptions, acceptedTokens.concat(activeToken), fromOption, true);
237
- }
238
- else if (activeArg.isCommand) {
239
- if (tokens.length <= 0) {
240
- return;
241
- }
242
- const spec = await loadSpec(tokens);
243
- if (spec == null)
244
- return;
245
- const subcommand = getSubcommand(spec);
246
- if (subcommand == null)
247
- return;
248
- return runSubcommand(tokens.slice(1), subcommand, cwd, shell);
249
- }
250
- return runArg(tokens.slice(1), args.slice(1), subcommand, cwd, shell, persistentOptions, acceptedTokens.concat(activeToken), fromOption, false);
251
- };
252
- const runSubcommand = async (tokens, subcommand, cwd, shell, persistentOptions = [], acceptedTokens = [], argsDepleted = false, argsUsed = false) => {
253
- if (tokens.length === 0) {
254
- return getSubcommandDrivenRecommendation(subcommand, persistentOptions, undefined, argsDepleted, argsUsed, acceptedTokens, cwd, shell);
255
- }
256
- else if (!tokens.at(0)?.complete) {
257
- return getSubcommandDrivenRecommendation(subcommand, persistentOptions, tokens[0], argsDepleted, argsUsed, acceptedTokens, cwd, shell);
258
- }
259
- const activeToken = tokens[0];
260
- const activeArgsLength = subcommand.args instanceof Array ? subcommand.args.length : 1;
261
- const allOptions = [...persistentOptions, ...(subcommand.options ?? [])];
262
- if (activeToken.isOption) {
263
- const option = getOption(activeToken, allOptions);
264
- if (option != null) {
265
- return runOption(tokens, option, subcommand, cwd, shell, persistentOptions, acceptedTokens);
266
- }
267
- return;
268
- }
269
- const nextSubcommand = await genSubcommand(activeToken.token, subcommand);
270
- if (nextSubcommand != null) {
271
- return runSubcommand(tokens.slice(1), nextSubcommand, cwd, shell, getPersistentOptions(persistentOptions, subcommand.options), getPersistentTokens(acceptedTokens.concat(activeToken)));
272
- }
273
- if (activeArgsLength <= 0) {
274
- return; // not subcommand or option & no args exist
275
- }
276
- const args = getArgs(subcommand.args);
277
- if (args.length != 0) {
278
- return runArg(tokens, args, subcommand, cwd, shell, allOptions, acceptedTokens, false, false);
279
- }
280
- // if the subcommand has no args specified, fallback to the subcommand and ignore this item
281
- return runSubcommand(tokens.slice(1), subcommand, cwd, shell, persistentOptions, acceptedTokens.concat(activeToken));
282
- };
@@ -1,36 +0,0 @@
1
- "use strict";
2
- // Copyright (c) Microsoft Corporation.
3
- // Licensed under the MIT License.
4
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
- return new (P || (P = Promise))(function (resolve, reject) {
7
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
- step((generator = generator.apply(thisArg, _arguments || [])).next());
11
- });
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.getDiffVersionedSpeclist = exports.getSpeclist = void 0;
15
- let speclist = undefined;
16
- let versionedSpeclist = undefined;
17
- const getSpeclist = () => __awaiter(void 0, void 0, void 0, function* () {
18
- if (!speclist) {
19
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
20
- // @ts-ignore
21
- const autocomplete = yield import("@withfig/autocomplete/build/index.js");
22
- speclist = autocomplete.default;
23
- }
24
- return speclist;
25
- });
26
- exports.getSpeclist = getSpeclist;
27
- const getDiffVersionedSpeclist = () => __awaiter(void 0, void 0, void 0, function* () {
28
- if (!versionedSpeclist) {
29
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
30
- // @ts-ignore
31
- const autocomplete = yield import("@withfig/autocomplete/build/index.js");
32
- versionedSpeclist = autocomplete.diffVersionedCompletions;
33
- }
34
- return versionedSpeclist;
35
- });
36
- exports.getDiffVersionedSpeclist = getDiffVersionedSpeclist;
@@ -1,232 +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
- import log from "../utils/log.js";
7
- import { escapePath } from "./utils.js";
8
- import { addPathSeparator, getPathDirname, removePathSeparator } from "../utils/shell.js";
9
- export var SuggestionIcons;
10
- (function (SuggestionIcons) {
11
- SuggestionIcons["File"] = "\uD83D\uDCC4";
12
- SuggestionIcons["Folder"] = "\uD83D\uDCC1";
13
- SuggestionIcons["Subcommand"] = "\uD83D\uDCE6";
14
- SuggestionIcons["Option"] = "\uD83D\uDD17";
15
- SuggestionIcons["Argument"] = "\uD83D\uDCB2";
16
- SuggestionIcons["Mixin"] = "\uD83C\uDFDD\uFE0F";
17
- SuggestionIcons["Shortcut"] = "\uD83D\uDD25";
18
- SuggestionIcons["Special"] = "\u2B50";
19
- SuggestionIcons["Default"] = "\uD83D\uDCC0";
20
- })(SuggestionIcons || (SuggestionIcons = {}));
21
- const getIcon = (icon, suggestionType) => {
22
- // eslint-disable-next-line no-control-regex
23
- if (icon && /[^\u0000-\u00ff]/.test(icon)) {
24
- return icon;
25
- }
26
- switch (suggestionType) {
27
- case "arg":
28
- return SuggestionIcons.Argument;
29
- case "file":
30
- return SuggestionIcons.File;
31
- case "folder":
32
- return SuggestionIcons.Folder;
33
- case "option":
34
- return SuggestionIcons.Option;
35
- case "subcommand":
36
- return SuggestionIcons.Subcommand;
37
- case "mixin":
38
- return SuggestionIcons.Mixin;
39
- case "shortcut":
40
- return SuggestionIcons.Shortcut;
41
- case "special":
42
- return SuggestionIcons.Special;
43
- }
44
- return SuggestionIcons.Default;
45
- };
46
- const getLong = (suggestion) => {
47
- return suggestion instanceof Array ? suggestion.reduce((p, c) => (p.length > c.length ? p : c)) : suggestion;
48
- };
49
- const getPathy = (type) => {
50
- return type === "file" || type === "folder";
51
- };
52
- const toSuggestion = (suggestion, name, type) => {
53
- if (suggestion.name == null)
54
- return;
55
- return {
56
- name: name ?? getLong(suggestion.name),
57
- description: suggestion.description,
58
- icon: getIcon(suggestion.icon, type ?? suggestion.type),
59
- allNames: suggestion.name instanceof Array ? suggestion.name : [suggestion.name],
60
- priority: suggestion.priority ?? 50,
61
- insertValue: suggestion.insertValue,
62
- type: suggestion.type,
63
- };
64
- };
65
- function filter(suggestions, filterStrategy, partialCmd, suggestionType) {
66
- if (!partialCmd)
67
- return suggestions.map((s) => toSuggestion(s, undefined, suggestionType)).filter((s) => s != null);
68
- switch (filterStrategy) {
69
- case "fuzzy":
70
- return suggestions
71
- .map((s) => {
72
- if (s.name == null)
73
- return;
74
- if (s.name instanceof Array) {
75
- const matchedName = s.name.find((n) => n.toLowerCase().includes(partialCmd.toLowerCase()));
76
- return matchedName != null
77
- ? {
78
- name: matchedName,
79
- description: s.description,
80
- icon: getIcon(s.icon, s.type ?? suggestionType),
81
- allNames: s.name,
82
- priority: s.priority ?? 50,
83
- insertValue: s.insertValue,
84
- type: s.type,
85
- }
86
- : undefined;
87
- }
88
- return s.name.toLowerCase().includes(partialCmd.toLowerCase())
89
- ? {
90
- name: s.name,
91
- description: s.description,
92
- icon: getIcon(s.icon, s.type ?? suggestionType),
93
- allNames: [s.name],
94
- priority: s.priority ?? 50,
95
- insertValue: s.insertValue,
96
- type: s.type,
97
- }
98
- : undefined;
99
- })
100
- .filter((s) => s != null);
101
- default:
102
- return suggestions
103
- .map((s) => {
104
- if (s.name == null)
105
- return;
106
- if (s.name instanceof Array) {
107
- const matchedName = s.name.find((n) => n.toLowerCase().startsWith(partialCmd.toLowerCase()));
108
- return matchedName != null
109
- ? {
110
- name: matchedName,
111
- description: s.description,
112
- icon: getIcon(s.icon, s.type ?? suggestionType),
113
- allNames: s.name,
114
- insertValue: s.insertValue,
115
- priority: s.priority ?? 50,
116
- type: s.type,
117
- }
118
- : undefined;
119
- }
120
- return s.name.toLowerCase().startsWith(partialCmd.toLowerCase())
121
- ? {
122
- name: s.name,
123
- description: s.description,
124
- icon: getIcon(s.icon, s.type ?? suggestionType),
125
- allNames: [s.name],
126
- insertValue: s.insertValue,
127
- priority: s.priority ?? 50,
128
- type: s.type,
129
- }
130
- : undefined;
131
- })
132
- .filter((s) => s != null);
133
- }
134
- }
135
- const generatorSuggestions = async (generator, acceptedTokens, filterStrategy, partialCmd, cwd) => {
136
- const generators = generator instanceof Array ? generator : generator ? [generator] : [];
137
- const tokens = acceptedTokens.map((t) => t.token);
138
- if (partialCmd)
139
- tokens.push(partialCmd);
140
- const suggestions = (await Promise.all(generators.map((gen) => runGenerator(gen, tokens, cwd)))).flat();
141
- return filter(suggestions.map((suggestion) => ({ ...suggestion, priority: suggestion.priority ?? 60 })), filterStrategy, partialCmd, undefined);
142
- };
143
- const templateSuggestions = async (templates, filterStrategy, partialCmd, cwd) => {
144
- return filter(await runTemplates(templates ?? [], cwd), filterStrategy, partialCmd, undefined);
145
- };
146
- const suggestionSuggestions = (suggestions, filterStrategy, partialCmd) => {
147
- const cleanedSuggestions = suggestions?.map((s) => (typeof s === "string" ? { name: s } : s)) ?? [];
148
- return filter(cleanedSuggestions ?? [], filterStrategy, partialCmd, undefined);
149
- };
150
- const subcommandSuggestions = (subcommands, filterStrategy, partialCmd) => {
151
- return filter(subcommands ?? [], filterStrategy, partialCmd, "subcommand");
152
- };
153
- const optionSuggestions = (options, acceptedTokens, filterStrategy, partialCmd) => {
154
- const usedOptions = new Set(acceptedTokens.filter((t) => t.isOption).map((t) => t.token));
155
- const validOptions = options?.filter((o) => o.exclusiveOn?.every((exclusiveOption) => !usedOptions.has(exclusiveOption)) ?? true);
156
- return filter(validOptions ?? [], filterStrategy, partialCmd, "option");
157
- };
158
- function adjustPathSuggestions(suggestions, partialToken, shell) {
159
- return suggestions.map((s) => {
160
- const pathy = getPathy(s.type);
161
- const rawInsertValue = removePathSeparator(s.insertValue ?? s.name ?? "");
162
- const insertValue = s.type == "folder" ? addPathSeparator(rawInsertValue, shell) : rawInsertValue;
163
- const partialDir = getPathDirname(partialToken?.token ?? "", shell);
164
- const fullPath = partialToken?.isPath ? `${partialDir}${insertValue}` : insertValue;
165
- return pathy ? { ...s, insertValue: escapePath(fullPath, shell), name: removePathSeparator(s.name) } : s;
166
- });
167
- }
168
- const removeAcceptedSuggestions = (suggestions, acceptedTokens) => {
169
- const seen = new Set(acceptedTokens.map((t) => t.token));
170
- return suggestions.filter((s) => s.allNames.every((n) => !seen.has(n)));
171
- };
172
- const removeDuplicateSuggestion = (suggestions) => {
173
- const seen = new Set();
174
- return suggestions
175
- .map((s) => {
176
- if (seen.has(s.name))
177
- return null;
178
- seen.add(s.name);
179
- return s;
180
- })
181
- .filter((s) => s != null);
182
- };
183
- const removeEmptySuggestion = (suggestions) => {
184
- return suggestions.filter((s) => s.name.length > 0);
185
- };
186
- export const getSubcommandDrivenRecommendation = async (subcommand, persistentOptions, partialToken, argsDepleted, argsFromSubcommand, acceptedTokens, cwd, shell) => {
187
- log.debug({ msg: "suggestion point", subcommand, persistentOptions, partialToken, argsDepleted, argsFromSubcommand, acceptedTokens, cwd });
188
- if (argsDepleted && argsFromSubcommand) {
189
- return;
190
- }
191
- let partialCmd = partialToken?.token;
192
- if (partialToken?.isPath) {
193
- partialCmd = partialToken.isPathComplete ? "" : path.basename(partialCmd ?? "");
194
- }
195
- const suggestions = [];
196
- const argLength = subcommand.args instanceof Array ? subcommand.args.length : subcommand.args ? 1 : 0;
197
- const allOptions = persistentOptions.concat(subcommand.options ?? []);
198
- if (!argsFromSubcommand) {
199
- suggestions.push(...subcommandSuggestions(subcommand.subcommands, subcommand.filterStrategy, partialCmd));
200
- suggestions.push(...optionSuggestions(allOptions, acceptedTokens, subcommand.filterStrategy, partialCmd));
201
- }
202
- if (argLength != 0) {
203
- const activeArg = subcommand.args instanceof Array ? subcommand.args[0] : subcommand.args;
204
- suggestions.push(...(await generatorSuggestions(activeArg?.generators, acceptedTokens, activeArg?.filterStrategy, partialCmd, cwd)));
205
- suggestions.push(...suggestionSuggestions(activeArg?.suggestions, activeArg?.filterStrategy, partialCmd));
206
- suggestions.push(...(await templateSuggestions(activeArg?.template, activeArg?.filterStrategy, partialCmd, cwd)));
207
- }
208
- return {
209
- suggestions: removeDuplicateSuggestion(removeEmptySuggestion(removeAcceptedSuggestions(adjustPathSuggestions(suggestions.sort((a, b) => b.priority - a.priority), partialToken, shell), acceptedTokens))),
210
- };
211
- };
212
- export const getArgDrivenRecommendation = async (args, subcommand, persistentOptions, partialToken, acceptedTokens, variadicArgBound, cwd, shell) => {
213
- let partialCmd = partialToken?.token;
214
- if (partialToken?.isPath) {
215
- partialCmd = partialToken.isPathComplete ? "" : path.basename(partialCmd ?? "");
216
- }
217
- const activeArg = args[0];
218
- const allOptions = persistentOptions.concat(subcommand.options ?? []);
219
- const suggestions = [
220
- ...(await generatorSuggestions(args[0].generators, acceptedTokens, activeArg?.filterStrategy, partialCmd, cwd)),
221
- ...suggestionSuggestions(args[0].suggestions, activeArg?.filterStrategy, partialCmd),
222
- ...(await templateSuggestions(args[0].template, activeArg?.filterStrategy, partialCmd, cwd)),
223
- ];
224
- if (activeArg.isOptional || (activeArg.isVariadic && variadicArgBound)) {
225
- suggestions.push(...subcommandSuggestions(subcommand.subcommands, activeArg?.filterStrategy, partialCmd));
226
- suggestions.push(...optionSuggestions(allOptions, acceptedTokens, activeArg?.filterStrategy, partialCmd));
227
- }
228
- return {
229
- suggestions: removeDuplicateSuggestion(removeEmptySuggestion(removeAcceptedSuggestions(adjustPathSuggestions(suggestions.sort((a, b) => b.priority - a.priority), partialToken, shell), acceptedTokens))),
230
- argumentDescription: activeArg.description ?? activeArg.name,
231
- };
232
- };