Skip to content

Commit c4620a2

Browse files
authored
feat: change command api (#91)
1 parent e563f52 commit c4620a2

File tree

11 files changed

+159
-120
lines changed

11 files changed

+159
-120
lines changed
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { createVersionedSpec } from "@fig/autocomplete-helpers";
22
const versionFiles = ["1.0.0", "2.0.0"];
3-
export const getVersionCommand: Fig.GetVersionCommand = async (
4-
executeShellCommand
5-
) => {
6-
const out = await executeShellCommand("fig --version");
7-
return out.slice(out.indexOf(" ") + 1);
3+
export const getVersionCommand: Fig.GetVersionCommand = async (executeCommand) => {
4+
const { stdout } = await executeCommand({
5+
command: "fig",
6+
args: ["--version"],
7+
});
8+
return stdout.slice(stdout.indexOf(" ") + 1);
89
};
910
export default createVersionedSpec("fig", versionFiles);
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { createVersionedSpec } from "@fig/autocomplete-helpers";
22
const versionFiles = ["1.0.0", "2.0.0"];
3-
export const getVersionCommand: Fig.GetVersionCommand = async (
4-
executeShellCommand
5-
) => {
6-
const out = await executeShellCommand("fig --version");
7-
return out.slice(out.indexOf(" ") + 1);
3+
export const getVersionCommand: Fig.GetVersionCommand = async (executeCommand) => {
4+
const { stdout } = await executeCommand({
5+
command: "fig",
6+
args: ["--version"],
7+
});
8+
return stdout.slice(stdout.indexOf(" ") + 1);
89
};
910
export default createVersionedSpec("fig", versionFiles);

generators/src/ai.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type GeneratorFn<T> = (args: {
22
tokens: string[];
3-
executeShellCommand: Fig.ExecuteShellCommandFunction;
3+
executeCommand: Fig.ExecuteCommandFunction;
44
generatorContext: Fig.GeneratorContext;
55
}) => Promise<T> | T;
66

@@ -35,20 +35,21 @@ export function ai({
3535
}): Fig.Generator {
3636
return {
3737
scriptTimeout: 15000,
38-
custom: async (tokens, executeShellCommand, generatorContext) => {
39-
const enabled = await executeShellCommand(
40-
"fig settings --format json autocomplete.ai.enabled"
41-
);
38+
custom: async (tokens, executeCommand, generatorContext) => {
39+
const settingOutput = await executeCommand({
40+
command: "fig",
41+
args: ["settings", "--format", "json", "autocomplete.ai.enabled"],
42+
});
4243

43-
if (!JSON.parse(enabled)) {
44+
if (!JSON.parse(settingOutput.stdout)) {
4445
return [];
4546
}
4647

4748
const promptString =
4849
typeof prompt === "function"
4950
? await prompt({
5051
tokens,
51-
executeShellCommand,
52+
executeCommand,
5253
generatorContext,
5354
})
5455
: prompt;
@@ -57,7 +58,7 @@ export function ai({
5758
typeof message === "function"
5859
? await message({
5960
tokens,
60-
executeShellCommand,
61+
executeCommand,
6162
generatorContext,
6263
})
6364
: message;
@@ -91,13 +92,12 @@ export function ai({
9192
};
9293

9394
const bodyJson = JSON.stringify(body);
94-
const escapedBodyJson = bodyJson.replace(/'/g, "'\"'\"'");
9595

96-
const res = await executeShellCommand(
97-
`fig _ request --route /ai/chat --method POST --body '${escapedBodyJson}'`
98-
);
99-
100-
const json = JSON.parse(res);
96+
const requestOutput = await executeCommand({
97+
command: "fig",
98+
args: ["_", "request", "--route", "/ai/chat", "--method", "POST", "--body", bodyJson],
99+
});
100+
const json = JSON.parse(requestOutput.stdout);
101101

102102
const a =
103103
json?.choices

generators/src/filepaths.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function filepathsFn(options: FilepathsOptions = {}): Fig.Generator {
176176
},
177177
getQueryTerm: (token) => token.slice(token.lastIndexOf("/") + 1),
178178

179-
custom: async (_, executeShellCommand, generatorContext) => {
179+
custom: async (_, executeCommand, generatorContext) => {
180180
const { isDangerous, currentWorkingDirectory, searchTerm } = generatorContext;
181181
const currentInsertedDirectory =
182182
getCurrentInsertedDirectory(
@@ -187,8 +187,12 @@ function filepathsFn(options: FilepathsOptions = {}): Fig.Generator {
187187

188188
try {
189189
// Use \ls command to avoid any aliases set for ls.
190-
const data = await executeShellCommand("command ls -1ApL", currentInsertedDirectory);
191-
const sortedFiles = sortFilesAlphabetically(data.split("\n"), [".DS_Store"]);
190+
const data = await executeCommand({
191+
command: "ls",
192+
args: ["-1ApL"],
193+
cwd: currentInsertedDirectory,
194+
});
195+
const sortedFiles = sortFilesAlphabetically(data.stdout.split("\n"), [".DS_Store"]);
192196

193197
const generatorOutputArray: Fig.TemplateSuggestion[] = [];
194198
// Then loop through them and add them to the generatorOutputArray

generators/test/filepaths.test.ts

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -140,33 +140,19 @@ describe("Test sortFilesAlphabetically", () => {
140140
});
141141

142142
describe("Test filepaths generators", () => {
143-
let globalSSHString: string;
144143
let currentCWD: string;
145-
let executeCommand: sinon.SinonStub;
146-
147-
async function executeCommandInDir(
148-
command: string,
149-
dir: string,
150-
sshContextString?: string,
151-
timeout?: number
152-
): Promise<string> {
153-
const inputDir = dir.replace(/[\s()[\]]/g, "\\$&");
154-
let commandString = `cd ${inputDir} && ${command} | cat`;
155-
156-
if (sshContextString) {
157-
commandString = commandString.replace(/'/g, `'"'"'`);
158-
commandString = `${sshContextString} '${commandString}'`;
159-
}
160-
161-
return executeCommand(commandString, timeout && timeout > 0 ? timeout : undefined);
162-
}
144+
let executeCommandStub: sinon.SinonStub;
163145

164-
async function executeShellCommand(cmd: string, overrideCWD?: string): Promise<string> {
146+
async function executeCommand(args: Fig.ExecuteCommandInput): Promise<Fig.ExecuteCommandOutput> {
165147
try {
166-
return executeCommandInDir(cmd, overrideCWD ?? currentCWD, globalSSHString);
148+
return executeCommandStub(args);
167149
} catch (err) {
168150
return new Promise((resolve) => {
169-
resolve("");
151+
resolve({
152+
stdout: "",
153+
stderr: "",
154+
status: 1,
155+
});
170156
});
171157
}
172158
}
@@ -176,20 +162,19 @@ describe("Test filepaths generators", () => {
176162
mockLSResults: string[],
177163
context = defaultContext
178164
): Promise<string[]> {
179-
executeCommand.resolves(mockLSResults.join("\n"));
180-
return (await filepaths(options).custom!([], executeShellCommand, context)).map(toName);
165+
executeCommandStub.resolves(mockLSResults.join("\n"));
166+
return (await filepaths(options).custom!([], executeCommand, context)).map(toName);
181167
}
182168

183169
beforeEach(() => {
184-
executeCommand = sinon.stub();
170+
executeCommandStub = sinon.stub();
185171
// these steps are approximately the ones performed by the engine before running a generator
186-
globalSSHString = "";
187172
currentCWD = "~/current_cwd/";
188173
defaultContext.currentWorkingDirectory = currentCWD;
189174
});
190175

191176
afterEach(() => {
192-
executeCommand.resetHistory();
177+
executeCommandStub.resetHistory();
193178
});
194179

195180
after(() => {
@@ -224,8 +209,8 @@ describe("Test filepaths generators", () => {
224209
describe("should return filepaths suggestions", () => {
225210
const suggestions = ["a/", "c/", "l", "x"];
226211
it("should show all suggestions when no options or search term is specified", async () => {
227-
executeCommand.resolves(suggestions.join("\n"));
228-
expect(await filepaths.custom!([], executeShellCommand, defaultContext)).to.eql(
212+
executeCommandStub.resolves(suggestions.join("\n"));
213+
expect(await filepaths.custom!([], executeCommand, defaultContext)).to.eql(
229214
[
230215
{ insertValue: "a/", name: "a/", type: "folder", context: { templateType: "folders" } },
231216
{ insertValue: "c/", name: "c/", type: "folder", context: { templateType: "folders" } },
@@ -395,7 +380,7 @@ describe("Test filepaths generators", () => {
395380

396381
describe("deprecated sshPrefix", () => {
397382
it("should call executeCommand with default user input dir ignoring ssh", async () => {
398-
await filepaths.custom!([], executeShellCommand, {
383+
await filepaths.custom!([], executeCommand, {
399384
...defaultContext,
400385
sshPrefix: "ssh -i blabla",
401386
});
@@ -405,20 +390,6 @@ describe("Test filepaths generators", () => {
405390
undefined
406391
);
407392
});
408-
409-
it("should call executeCommand with specified user input dir ignoring ssh but adding the global ssh string", async () => {
410-
globalSSHString = "some_ssh_string";
411-
await filepaths({ rootDirectory: "/etc" }).custom!([], executeShellCommand, {
412-
...defaultContext,
413-
searchTerm: "some_path/",
414-
sshPrefix: "ssh -i blabla",
415-
});
416-
417-
expect(executeCommand).to.have.been.calledWith(
418-
"some_ssh_string 'cd /etc/some_path/ && command ls -1ApL | cat'",
419-
undefined
420-
);
421-
});
422393
});
423394
});
424395

@@ -427,10 +398,8 @@ describe("Test filepaths generators", () => {
427398
const passing: string[] = ["folder1.txt/", "folder2.txt/", "folder3/"];
428399
const failing: string[] = ["file1.test.js", "file2.js", "file3.mjs", "file4.ts"];
429400

430-
executeCommand.resolves(passing.concat(failing).join("\n"));
431-
const results = (await folders().custom!([], executeShellCommand, defaultContext)).map(
432-
toName
433-
);
401+
executeCommandStub.resolves(passing.concat(failing).join("\n"));
402+
const results = (await folders().custom!([], executeCommand, defaultContext)).map(toName);
434403

435404
expect(results).to.eql(passing.concat("../"));
436405
});

generators/test/keyvalue.test.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@ function testSuggestions(
55
generator: Fig.Generator
66
): (token: string, expected: Fig.Suggestion[]) => Promise<void> {
77
return async (token, expected) => {
8-
const result = await generator.custom?.(["spec", token], () => Promise.resolve(""), {
9-
searchTerm: "",
10-
currentProcess: "",
11-
currentWorkingDirectory: "",
12-
sshPrefix: "",
13-
environmentVariables: {},
14-
});
8+
const result = await generator.custom?.(
9+
["spec", token],
10+
() =>
11+
Promise.resolve({
12+
status: 1,
13+
stderr: "",
14+
stdout: "",
15+
}),
16+
{
17+
searchTerm: "",
18+
currentProcess: "",
19+
currentWorkingDirectory: "",
20+
sshPrefix: "",
21+
environmentVariables: {},
22+
}
23+
);
1524
expect(result).to.deep.equal(expected);
1625
};
1726
}

helpers/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
"devDependencies": {
2929
"@tsconfig/recommended": "^1.0.1",
3030
"@types/jest": "^27.5.0",
31+
"@types/node": "^20.8.10",
3132
"@types/prettier": "^2.6.0",
3233
"@types/semver": "^7.3.9",
33-
"@withfig/autocomplete-types": "^1.15.0",
34+
"@withfig/autocomplete-types": "workspace:^",
3435
"jest": "^28.0.3",
3536
"prettier": "^2.6.2",
3637
"ts-jest": "^28.0.0",

shared/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
"devDependencies": {
2525
"@tsconfig/recommended": "^1.0.1",
2626
"@types/jest": "^27.5.0",
27+
"@types/node": "^20.8.10",
2728
"@types/semver": "^7.3.9",
28-
"@withfig/autocomplete-types": "^1.15.0",
29+
"@withfig/autocomplete-types": "workspace:^",
2930
"jest": "^28.0.3",
3031
"prettier": "^2.6.2",
3132
"ts-jest": "^28.0.0",

0 commit comments

Comments
 (0)