@aikidosec/safe-chain 1.0.15 → 1.0.17
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/README.md +10 -8
- package/bin/aikido-pnpm.js +8 -0
- package/bin/aikido-pnpx.js +8 -0
- package/docs/shell-integration.md +4 -4
- package/eslint.config.js +2 -1
- package/package.json +9 -4
- package/src/packagemanager/_shared/matchesCommand.js +13 -0
- package/src/packagemanager/currentPackageManager.js +8 -0
- package/src/packagemanager/pnpm/createPackageManager.js +46 -0
- package/src/packagemanager/pnpm/dependencyScanner/commandArgumentScanner.js +28 -0
- package/src/packagemanager/pnpm/parsing/parsePackagesFromArguments.js +88 -0
- package/src/packagemanager/pnpm/parsing/parsePackagesFromArguments.spec.js +138 -0
- package/src/packagemanager/pnpm/runPnpmCommand.js +24 -0
- package/src/shell-integration/helpers.js +31 -31
- package/src/shell-integration/setup.js +44 -95
- package/src/shell-integration/shellDetection.js +17 -66
- package/src/shell-integration/startup-scripts/init-fish.fish +58 -0
- package/src/shell-integration/startup-scripts/init-posix.sh +54 -0
- package/src/shell-integration/startup-scripts/init-pwsh.ps1 +80 -0
- package/src/shell-integration/supported-shells/bash.js +62 -0
- package/src/shell-integration/supported-shells/bash.spec.js +199 -0
- package/src/shell-integration/supported-shells/fish.js +65 -0
- package/src/shell-integration/supported-shells/fish.spec.js +183 -0
- package/src/shell-integration/supported-shells/powershell.js +65 -0
- package/src/shell-integration/supported-shells/powershell.spec.js +200 -0
- package/src/shell-integration/supported-shells/windowsPowershell.js +65 -0
- package/src/shell-integration/supported-shells/windowsPowershell.spec.js +200 -0
- package/src/shell-integration/supported-shells/zsh.js +62 -0
- package/src/shell-integration/supported-shells/zsh.spec.js +226 -0
- package/src/shell-integration/teardown.js +20 -99
- package/.github/workflows/build-and-release.yml +0 -41
- package/.github/workflows/test-on-pr.yml +0 -28
- package/src/shell-integration/setup.spec.js +0 -304
- package/src/shell-integration/teardown.spec.js +0 -177
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { EOL, tmpdir } from "node:os";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import { getAliases } from "./helpers.js";
|
|
6
|
-
import { readOrCreateStartupFile, appendAliasesToFile } from "./setup.js";
|
|
7
|
-
|
|
8
|
-
describe("setupShell", () => {
|
|
9
|
-
function runSetupTestsForEnvironment(shell, startupExtension, expectedAliases) {
|
|
10
|
-
describe(`${shell} shell setup`, () => {
|
|
11
|
-
it(`should add aliases to ${shell} file`, () => {
|
|
12
|
-
const lines = [`#!/usr/bin/env ${shell}`, "", "alias cls='clear'"];
|
|
13
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
14
|
-
|
|
15
|
-
const aliases = getAliases(filePath);
|
|
16
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
17
|
-
|
|
18
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
19
|
-
|
|
20
|
-
assert.strictEqual(result.addedCount, 3, "Should add 3 aliases");
|
|
21
|
-
assert.strictEqual(result.existingCount, 0, "Should find no existing aliases");
|
|
22
|
-
assert.strictEqual(result.failedCount, 0, "Should have no failed aliases");
|
|
23
|
-
|
|
24
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
25
|
-
for (const alias of expectedAliases) {
|
|
26
|
-
assert.ok(updatedContent.includes(alias), `Alias "${alias}" should be added`);
|
|
27
|
-
}
|
|
28
|
-
assert.ok(updatedContent.includes("alias cls='clear'"), "Original aliases should remain");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it(`should not add aliases if they already exist in ${shell} file`, () => {
|
|
32
|
-
const lines = [`#!/usr/bin/env ${shell}`, "", ...expectedAliases];
|
|
33
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
34
|
-
|
|
35
|
-
const aliases = getAliases(filePath);
|
|
36
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
37
|
-
|
|
38
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
39
|
-
|
|
40
|
-
assert.strictEqual(result.addedCount, 0, "Should add 0 aliases");
|
|
41
|
-
assert.strictEqual(result.existingCount, 3, "Should find 3 existing aliases");
|
|
42
|
-
assert.strictEqual(result.failedCount, 0, "Should have no failed aliases");
|
|
43
|
-
|
|
44
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
45
|
-
// Count occurrences to ensure no duplicates were added
|
|
46
|
-
for (const alias of expectedAliases) {
|
|
47
|
-
assert.strictEqual(countOccurrences(updatedContent, alias), 1, `Alias "${alias}" should appear exactly once`);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it(`should create file and add aliases if file does not exist for ${shell}`, () => {
|
|
52
|
-
const randomName = Math.random().toString(36).substring(2, 15);
|
|
53
|
-
const filePath = `${tmpdir()}/nonexistent-${randomName}${startupExtension}`;
|
|
54
|
-
if (fs.existsSync(filePath)) {
|
|
55
|
-
fs.rmSync(filePath, { force: true });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Test readOrCreateStartupFile function
|
|
59
|
-
const fileContent = readOrCreateStartupFile(filePath);
|
|
60
|
-
assert.strictEqual(fileContent, "", "Should return empty string for new file");
|
|
61
|
-
assert.ok(fs.existsSync(filePath), "File should be created");
|
|
62
|
-
|
|
63
|
-
// Test adding aliases to the newly created file
|
|
64
|
-
const aliases = getAliases(filePath);
|
|
65
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
66
|
-
|
|
67
|
-
assert.strictEqual(result.addedCount, 3, "Should add 3 aliases");
|
|
68
|
-
assert.strictEqual(result.existingCount, 0, "Should find no existing aliases");
|
|
69
|
-
assert.strictEqual(result.failedCount, 0, "Should have no failed aliases");
|
|
70
|
-
|
|
71
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
72
|
-
for (const alias of expectedAliases) {
|
|
73
|
-
assert.ok(updatedContent.includes(alias), `Alias "${alias}" should be added`);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it(`should add aliases only once when called multiple times for ${shell}`, () => {
|
|
78
|
-
const lines = [`#!/usr/bin/env ${shell}`, ""];
|
|
79
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
80
|
-
|
|
81
|
-
const aliases = getAliases(filePath);
|
|
82
|
-
|
|
83
|
-
// First call - should add aliases
|
|
84
|
-
let fileContent = fs.readFileSync(filePath, "utf-8");
|
|
85
|
-
const result1 = appendAliasesToFile(aliases, fileContent, filePath);
|
|
86
|
-
assert.strictEqual(result1.addedCount, 3, "First call should add 3 aliases");
|
|
87
|
-
|
|
88
|
-
// Second call - should detect existing aliases
|
|
89
|
-
fileContent = fs.readFileSync(filePath, "utf-8");
|
|
90
|
-
const result2 = appendAliasesToFile(aliases, fileContent, filePath);
|
|
91
|
-
assert.strictEqual(result2.addedCount, 0, "Second call should add 0 aliases");
|
|
92
|
-
assert.strictEqual(result2.existingCount, 3, "Second call should find 3 existing aliases");
|
|
93
|
-
|
|
94
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
95
|
-
for (const alias of expectedAliases) {
|
|
96
|
-
assert.strictEqual(countOccurrences(updatedContent, alias), 1, `Alias "${alias}" should appear exactly once`);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it(`should use real getAliases() for ${shell} file`, () => {
|
|
101
|
-
const filePath = `${tmpdir()}/test${startupExtension}`;
|
|
102
|
-
const aliases = getAliases(filePath);
|
|
103
|
-
|
|
104
|
-
// Verify we get the expected aliases for this shell type
|
|
105
|
-
assert.strictEqual(aliases.length, 3, "Should get 3 aliases (npm, npx, yarn)");
|
|
106
|
-
for (let i = 0; i < aliases.length; i++) {
|
|
107
|
-
assert.strictEqual(aliases[i], expectedAliases[i], `Alias ${i} should match expected format`);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it(`should handle mixed scenario - some existing, some new for ${shell}`, () => {
|
|
112
|
-
const lines = [`#!/usr/bin/env ${shell}`, "", expectedAliases[0], "alias other='command'"];
|
|
113
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
114
|
-
|
|
115
|
-
const aliases = getAliases(filePath);
|
|
116
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
117
|
-
|
|
118
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
119
|
-
|
|
120
|
-
assert.strictEqual(result.addedCount, 2, "Should add 2 new aliases");
|
|
121
|
-
assert.strictEqual(result.existingCount, 1, "Should find 1 existing alias");
|
|
122
|
-
assert.strictEqual(result.failedCount, 0, "Should have no failed aliases");
|
|
123
|
-
|
|
124
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
125
|
-
for (const alias of expectedAliases) {
|
|
126
|
-
assert.ok(updatedContent.includes(alias), `Alias "${alias}" should be present`);
|
|
127
|
-
}
|
|
128
|
-
assert.ok(updatedContent.includes("alias other='command'"), "Other aliases should remain");
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Test for each shell type using real getAliases() output
|
|
134
|
-
runSetupTestsForEnvironment("bash", ".bashrc", [
|
|
135
|
-
"alias npm='aikido-npm'",
|
|
136
|
-
"alias npx='aikido-npx'",
|
|
137
|
-
"alias yarn='aikido-yarn'"
|
|
138
|
-
]);
|
|
139
|
-
|
|
140
|
-
runSetupTestsForEnvironment("zsh", ".zshrc", [
|
|
141
|
-
"alias npm='aikido-npm'",
|
|
142
|
-
"alias npx='aikido-npx'",
|
|
143
|
-
"alias yarn='aikido-yarn'"
|
|
144
|
-
]);
|
|
145
|
-
|
|
146
|
-
runSetupTestsForEnvironment("fish", ".fish", [
|
|
147
|
-
'alias npm "aikido-npm"',
|
|
148
|
-
'alias npx "aikido-npx"',
|
|
149
|
-
'alias yarn "aikido-yarn"'
|
|
150
|
-
]);
|
|
151
|
-
|
|
152
|
-
runSetupTestsForEnvironment("pwsh", ".ps1", [
|
|
153
|
-
"Set-Alias npm aikido-npm",
|
|
154
|
-
"Set-Alias npx aikido-npx",
|
|
155
|
-
"Set-Alias yarn aikido-yarn"
|
|
156
|
-
]);
|
|
157
|
-
|
|
158
|
-
describe("readOrCreateStartupFile", () => {
|
|
159
|
-
it("should read existing file content", () => {
|
|
160
|
-
const lines = ["#!/usr/bin/env bash", "", "alias test='echo test'"];
|
|
161
|
-
const filePath = createShellStartupScript(lines, ".bashrc");
|
|
162
|
-
|
|
163
|
-
const content = readOrCreateStartupFile(filePath);
|
|
164
|
-
|
|
165
|
-
assert.ok(content.includes("#!/usr/bin/env bash"), "Should contain shebang");
|
|
166
|
-
assert.ok(content.includes("alias test='echo test'"), "Should contain existing aliases");
|
|
167
|
-
|
|
168
|
-
// Cleanup
|
|
169
|
-
fs.rmSync(filePath, { force: true });
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should create file if it doesn't exist", () => {
|
|
173
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
174
|
-
if (fs.existsSync(filePath)) {
|
|
175
|
-
fs.rmSync(filePath, { force: true });
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const content = readOrCreateStartupFile(filePath);
|
|
179
|
-
|
|
180
|
-
assert.strictEqual(content, "", "Should return empty string for new file");
|
|
181
|
-
assert.ok(fs.existsSync(filePath), "File should be created");
|
|
182
|
-
|
|
183
|
-
// Cleanup
|
|
184
|
-
fs.rmSync(filePath, { force: true });
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("should handle empty existing file", () => {
|
|
188
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
189
|
-
fs.writeFileSync(filePath, "", "utf-8");
|
|
190
|
-
|
|
191
|
-
const content = readOrCreateStartupFile(filePath);
|
|
192
|
-
|
|
193
|
-
assert.strictEqual(content, "", "Should return empty string for empty file");
|
|
194
|
-
assert.ok(fs.existsSync(filePath), "File should still exist");
|
|
195
|
-
|
|
196
|
-
// Cleanup
|
|
197
|
-
fs.rmSync(filePath, { force: true });
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe("appendAliasesToFile edge cases", () => {
|
|
202
|
-
it("should handle empty aliases array", () => {
|
|
203
|
-
const lines = ["#!/usr/bin/env bash", "", "alias test='echo test'"];
|
|
204
|
-
const filePath = createShellStartupScript(lines, ".bashrc");
|
|
205
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
206
|
-
|
|
207
|
-
const result = appendAliasesToFile([], fileContent, filePath);
|
|
208
|
-
|
|
209
|
-
assert.strictEqual(result.addedCount, 0, "Should add 0 aliases");
|
|
210
|
-
assert.strictEqual(result.existingCount, 0, "Should find 0 existing aliases");
|
|
211
|
-
assert.strictEqual(result.failedCount, 0, "Should have 0 failed aliases");
|
|
212
|
-
|
|
213
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
214
|
-
assert.ok(updatedContent.includes("alias test='echo test'"), "Original content should remain");
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("should handle partial substring matches correctly", () => {
|
|
218
|
-
const lines = [
|
|
219
|
-
"#!/usr/bin/env bash",
|
|
220
|
-
"",
|
|
221
|
-
"alias npmx='some-other-command'", // Contains 'npm' but shouldn't match 'alias npm='
|
|
222
|
-
"alias test='echo test'"
|
|
223
|
-
];
|
|
224
|
-
const filePath = createShellStartupScript(lines, ".bashrc");
|
|
225
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
226
|
-
|
|
227
|
-
const aliases = ["alias npm='aikido-npm'"];
|
|
228
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
229
|
-
|
|
230
|
-
assert.strictEqual(result.addedCount, 1, "Should add 1 alias (npm)");
|
|
231
|
-
assert.strictEqual(result.existingCount, 0, "Should find 0 existing aliases");
|
|
232
|
-
assert.strictEqual(result.failedCount, 0, "Should have 0 failed aliases");
|
|
233
|
-
|
|
234
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
235
|
-
assert.ok(updatedContent.includes("alias npm='aikido-npm'"), "npm alias should be added");
|
|
236
|
-
assert.ok(updatedContent.includes("alias npmx='some-other-command'"), "npmx alias should remain");
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("should handle file with only whitespace", () => {
|
|
240
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
241
|
-
const fileContent = `${EOL}${EOL} ${EOL}`;
|
|
242
|
-
fs.writeFileSync(filePath, fileContent, "utf-8");
|
|
243
|
-
|
|
244
|
-
const aliases = ["alias npm='aikido-npm'"];
|
|
245
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
246
|
-
|
|
247
|
-
assert.strictEqual(result.addedCount, 1, "Should add 1 alias");
|
|
248
|
-
assert.strictEqual(result.existingCount, 0, "Should find 0 existing aliases");
|
|
249
|
-
assert.strictEqual(result.failedCount, 0, "Should have 0 failed aliases");
|
|
250
|
-
|
|
251
|
-
const updatedContent = fs.readFileSync(filePath, "utf-8");
|
|
252
|
-
assert.ok(updatedContent.includes("alias npm='aikido-npm'"), "Alias should be added");
|
|
253
|
-
|
|
254
|
-
// Cleanup
|
|
255
|
-
fs.rmSync(filePath, { force: true });
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
describe("appendAliasesToFile error handling", () => {
|
|
260
|
-
it("should handle file permission errors gracefully", () => {
|
|
261
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
262
|
-
fs.writeFileSync(filePath, "#!/usr/bin/env bash", "utf-8");
|
|
263
|
-
|
|
264
|
-
// Make file read-only to simulate permission error
|
|
265
|
-
fs.chmodSync(filePath, 0o444);
|
|
266
|
-
|
|
267
|
-
const aliases = ["alias npm='aikido-npm'"];
|
|
268
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
269
|
-
|
|
270
|
-
const result = appendAliasesToFile(aliases, fileContent, filePath);
|
|
271
|
-
|
|
272
|
-
assert.strictEqual(result.addedCount, 0, "Should add 0 aliases due to permission error");
|
|
273
|
-
assert.strictEqual(result.existingCount, 0, "Should find 0 existing aliases");
|
|
274
|
-
assert.strictEqual(result.failedCount, 1, "Should have 1 failed alias");
|
|
275
|
-
|
|
276
|
-
// Restore permissions and cleanup
|
|
277
|
-
fs.chmodSync(filePath, 0o644);
|
|
278
|
-
fs.rmSync(filePath, { force: true });
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
function createShellStartupScript(lines, fileExtension) {
|
|
284
|
-
const randomFileName = Math.random().toString(36).substring(2, 15);
|
|
285
|
-
const filePath = `${tmpdir()}/${randomFileName}${fileExtension}`;
|
|
286
|
-
fs.writeFileSync(filePath, lines.join(EOL), "utf-8");
|
|
287
|
-
return filePath;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function readAndDeleteFile(filePath) {
|
|
291
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
292
|
-
fs.rmSync(filePath, { force: true });
|
|
293
|
-
return fileContent.split(EOL);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function countOccurrences(lines, searchString) {
|
|
297
|
-
let count = 0;
|
|
298
|
-
for (const line of lines) {
|
|
299
|
-
if (line.includes(searchString)) {
|
|
300
|
-
count++;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
return count;
|
|
304
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
import { EOL, tmpdir } from "node:os";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import { getAliases } from "./helpers.js";
|
|
6
|
-
import { removeAliasesFromFile } from "./teardown.js";
|
|
7
|
-
|
|
8
|
-
describe("teardown", () => {
|
|
9
|
-
function runRemovalTestsForEnvironment(shell, startupExtension, expectedAliases) {
|
|
10
|
-
describe(`${shell} shell removal`, () => {
|
|
11
|
-
it(`should remove aliases from ${shell} file`, () => {
|
|
12
|
-
const lines = [`#!/usr/bin/env ${shell}`, "", ...expectedAliases, ""];
|
|
13
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
14
|
-
|
|
15
|
-
// Test the removeAliasesFromFile function directly
|
|
16
|
-
const aliases = getAliases(filePath);
|
|
17
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
18
|
-
|
|
19
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
20
|
-
|
|
21
|
-
assert.strictEqual(result.removedCount, 3, "Should remove 3 aliases");
|
|
22
|
-
assert.strictEqual(result.notFoundCount, 0, "Should find all aliases");
|
|
23
|
-
|
|
24
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
25
|
-
for (const alias of expectedAliases) {
|
|
26
|
-
assert.ok(!updatedContent.includes(alias), `Alias "${alias}" should be removed`);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it(`should handle file with no aliases for ${shell}`, () => {
|
|
31
|
-
const lines = [`#!/usr/bin/env ${shell}`, "", "alias other='command'", ""];
|
|
32
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
33
|
-
|
|
34
|
-
const aliases = getAliases(filePath);
|
|
35
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
36
|
-
|
|
37
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
38
|
-
|
|
39
|
-
assert.strictEqual(result.removedCount, 0, "Should remove 0 aliases");
|
|
40
|
-
assert.strictEqual(result.notFoundCount, 3, "Should report 3 aliases not found");
|
|
41
|
-
|
|
42
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
43
|
-
assert.ok(updatedContent.includes("alias other='command'"), "Other aliases should remain unchanged");
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it(`should remove duplicate aliases from ${shell} file`, () => {
|
|
47
|
-
const lines = [
|
|
48
|
-
`#!/usr/bin/env ${shell}`,
|
|
49
|
-
"",
|
|
50
|
-
...expectedAliases,
|
|
51
|
-
"alias other='command'",
|
|
52
|
-
...expectedAliases, // duplicates
|
|
53
|
-
""
|
|
54
|
-
];
|
|
55
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
56
|
-
|
|
57
|
-
const aliases = getAliases(filePath);
|
|
58
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
59
|
-
|
|
60
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
61
|
-
|
|
62
|
-
assert.strictEqual(result.removedCount, 3, "Should remove 3 aliases (counting duplicates as single removal)");
|
|
63
|
-
assert.strictEqual(result.notFoundCount, 0, "Should find all aliases");
|
|
64
|
-
|
|
65
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
66
|
-
for (const alias of expectedAliases) {
|
|
67
|
-
assert.ok(!updatedContent.includes(alias), `Alias "${alias}" should be completely removed`);
|
|
68
|
-
}
|
|
69
|
-
assert.ok(updatedContent.includes("alias other='command'"), "Other aliases should remain");
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it(`should use real getAliases() for ${shell} file`, () => {
|
|
73
|
-
const filePath = `${tmpdir()}/test${startupExtension}`;
|
|
74
|
-
const aliases = getAliases(filePath);
|
|
75
|
-
|
|
76
|
-
// Verify we get the expected aliases for this shell type
|
|
77
|
-
assert.strictEqual(aliases.length, 3, "Should get 3 aliases (npm, npx, yarn)");
|
|
78
|
-
for (let i = 0; i < aliases.length; i++) {
|
|
79
|
-
assert.strictEqual(aliases[i], expectedAliases[i], `Alias ${i} should match expected format`);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it(`should handle partial alias matches for ${shell}`, () => {
|
|
84
|
-
const lines = [
|
|
85
|
-
`#!/usr/bin/env ${shell}`,
|
|
86
|
-
"",
|
|
87
|
-
expectedAliases[0], // Only first alias
|
|
88
|
-
"alias other='command'",
|
|
89
|
-
""
|
|
90
|
-
];
|
|
91
|
-
const filePath = createShellStartupScript(lines, startupExtension);
|
|
92
|
-
|
|
93
|
-
const aliases = getAliases(filePath);
|
|
94
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
95
|
-
|
|
96
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
97
|
-
|
|
98
|
-
assert.strictEqual(result.removedCount, 1, "Should remove 1 alias");
|
|
99
|
-
assert.strictEqual(result.notFoundCount, 2, "Should report 2 aliases not found");
|
|
100
|
-
|
|
101
|
-
const updatedContent = readAndDeleteFile(filePath);
|
|
102
|
-
assert.ok(!updatedContent.includes(expectedAliases[0]), "First alias should be removed");
|
|
103
|
-
assert.ok(updatedContent.includes("alias other='command'"), "Other aliases should remain");
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Test for each shell type using real getAliases() output
|
|
109
|
-
runRemovalTestsForEnvironment("bash", ".bashrc", [
|
|
110
|
-
"alias npm='aikido-npm'",
|
|
111
|
-
"alias npx='aikido-npx'",
|
|
112
|
-
"alias yarn='aikido-yarn'"
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
|
-
runRemovalTestsForEnvironment("zsh", ".zshrc", [
|
|
116
|
-
"alias npm='aikido-npm'",
|
|
117
|
-
"alias npx='aikido-npx'",
|
|
118
|
-
"alias yarn='aikido-yarn'"
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
runRemovalTestsForEnvironment("fish", ".fish", [
|
|
122
|
-
'alias npm "aikido-npm"',
|
|
123
|
-
'alias npx "aikido-npx"',
|
|
124
|
-
'alias yarn "aikido-yarn"'
|
|
125
|
-
]);
|
|
126
|
-
|
|
127
|
-
runRemovalTestsForEnvironment("pwsh", ".ps1", [
|
|
128
|
-
"Set-Alias npm aikido-npm",
|
|
129
|
-
"Set-Alias npx aikido-npx",
|
|
130
|
-
"Set-Alias yarn aikido-yarn"
|
|
131
|
-
]);
|
|
132
|
-
|
|
133
|
-
describe("removeAliasesFromFile edge cases", () => {
|
|
134
|
-
it("should handle empty file", () => {
|
|
135
|
-
const aliases = ["alias npm='aikido-npm'"];
|
|
136
|
-
const fileContent = "";
|
|
137
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
138
|
-
fs.writeFileSync(filePath, fileContent, "utf-8");
|
|
139
|
-
|
|
140
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
141
|
-
|
|
142
|
-
assert.strictEqual(result.removedCount, 0, "Should remove 0 aliases from empty file");
|
|
143
|
-
assert.strictEqual(result.notFoundCount, 1, "Should report 1 alias not found");
|
|
144
|
-
|
|
145
|
-
// Cleanup
|
|
146
|
-
fs.rmSync(filePath, { force: true });
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("should handle file with only whitespace", () => {
|
|
150
|
-
const aliases = ["alias npm='aikido-npm'"];
|
|
151
|
-
const fileContent = `${EOL}${EOL} ${EOL}`;
|
|
152
|
-
const filePath = `${tmpdir()}/test-${Math.random().toString(36).substring(2, 15)}.bashrc`;
|
|
153
|
-
fs.writeFileSync(filePath, fileContent, "utf-8");
|
|
154
|
-
|
|
155
|
-
const result = removeAliasesFromFile(aliases, fileContent, filePath);
|
|
156
|
-
|
|
157
|
-
assert.strictEqual(result.removedCount, 0, "Should remove 0 aliases from whitespace-only file");
|
|
158
|
-
assert.strictEqual(result.notFoundCount, 1, "Should report 1 alias not found");
|
|
159
|
-
|
|
160
|
-
// Cleanup
|
|
161
|
-
fs.rmSync(filePath, { force: true });
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
function createShellStartupScript(lines, fileExtension) {
|
|
167
|
-
const randomFileName = Math.random().toString(36).substring(2, 15);
|
|
168
|
-
const filePath = `${tmpdir()}/${randomFileName}${fileExtension}`;
|
|
169
|
-
fs.writeFileSync(filePath, lines.join(EOL), "utf-8");
|
|
170
|
-
return filePath;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function readAndDeleteFile(filePath) {
|
|
174
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
175
|
-
fs.rmSync(filePath, { force: true });
|
|
176
|
-
return fileContent.split(EOL);
|
|
177
|
-
}
|