command-stream 0.3.0 → 0.3.2
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 +4 -1
- package/package.json +4 -4
- package/{$.mjs → src/$.mjs} +95 -675
- package/src/$.utils.mjs +81 -0
- package/src/commands/$.basename.mjs +19 -0
- package/src/commands/$.cat.mjs +38 -0
- package/src/commands/$.cd.mjs +16 -0
- package/src/commands/$.cp.mjs +112 -0
- package/src/commands/$.dirname.mjs +12 -0
- package/src/commands/$.echo.mjs +15 -0
- package/src/commands/$.env.mjs +14 -0
- package/src/commands/$.exit.mjs +9 -0
- package/src/commands/$.false.mjs +3 -0
- package/src/commands/$.ls.mjs +79 -0
- package/src/commands/$.mkdir.mjs +45 -0
- package/src/commands/$.mv.mjs +89 -0
- package/src/commands/$.pwd.mjs +8 -0
- package/src/commands/$.rm.mjs +60 -0
- package/src/commands/$.seq.mjs +48 -0
- package/src/commands/$.sleep.mjs +15 -0
- package/src/commands/$.test.mjs +59 -0
- package/src/commands/$.touch.mjs +36 -0
- package/src/commands/$.true.mjs +5 -0
- package/src/commands/$.which.mjs +32 -0
- package/src/commands/$.yes.mjs +34 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { VirtualUtils } from '../$.utils.mjs';
|
|
3
|
+
|
|
4
|
+
export default async function test({ args }) {
|
|
5
|
+
if (args.length === 0) {
|
|
6
|
+
return { stdout: '', code: 1 };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const operator = args[0];
|
|
10
|
+
const operand = args[1];
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
switch (operator) {
|
|
14
|
+
case '-e': // File exists
|
|
15
|
+
try {
|
|
16
|
+
fs.statSync(operand);
|
|
17
|
+
return { stdout: '', code: 0 };
|
|
18
|
+
} catch {
|
|
19
|
+
return { stdout: '', code: 1 };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
case '-f': // Regular file
|
|
23
|
+
try {
|
|
24
|
+
const stats = fs.statSync(operand);
|
|
25
|
+
return { stdout: '', code: stats.isFile() ? 0 : 1 };
|
|
26
|
+
} catch {
|
|
27
|
+
return { stdout: '', code: 1 };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
case '-d': // Directory
|
|
31
|
+
try {
|
|
32
|
+
const stats = fs.statSync(operand);
|
|
33
|
+
return { stdout: '', code: stats.isDirectory() ? 0 : 1 };
|
|
34
|
+
} catch {
|
|
35
|
+
return { stdout: '', code: 1 };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
case '-s': // File exists and not empty
|
|
39
|
+
try {
|
|
40
|
+
const stats = fs.statSync(operand);
|
|
41
|
+
return { stdout: '', code: stats.size > 0 ? 0 : 1 };
|
|
42
|
+
} catch {
|
|
43
|
+
return { stdout: '', code: 1 };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
case '-z': // String is empty
|
|
47
|
+
return { stdout: '', code: (!operand || operand.length === 0) ? 0 : 1 };
|
|
48
|
+
|
|
49
|
+
case '-n': // String is not empty
|
|
50
|
+
return { stdout: '', code: (operand && operand.length > 0) ? 0 : 1 };
|
|
51
|
+
|
|
52
|
+
default:
|
|
53
|
+
// Simple string test (non-empty)
|
|
54
|
+
return { stdout: '', code: (operator && operator.length > 0) ? 0 : 1 };
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return VirtualUtils.error(`test: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
3
|
+
|
|
4
|
+
export default async function touch({ args, stdin, cwd }) {
|
|
5
|
+
const argError = VirtualUtils.validateArgs(args, 1, 'touch');
|
|
6
|
+
if (argError) return VirtualUtils.missingOperandError('touch', 'touch: missing file operand');
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
for (const file of args) {
|
|
10
|
+
const resolvedPath = VirtualUtils.resolvePath(file, cwd);
|
|
11
|
+
trace('VirtualCommand', () => `touch: processing | ${JSON.stringify({ file: resolvedPath }, null, 2)}`);
|
|
12
|
+
|
|
13
|
+
const now = new Date();
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// Try to update existing file's timestamp
|
|
17
|
+
fs.utimesSync(resolvedPath, now, now);
|
|
18
|
+
trace('VirtualCommand', () => `touch: updated timestamp | ${JSON.stringify({ file: resolvedPath }, null, 2)}`);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error.code === 'ENOENT') {
|
|
21
|
+
// File doesn't exist, create it
|
|
22
|
+
fs.writeFileSync(resolvedPath, '');
|
|
23
|
+
trace('VirtualCommand', () => `touch: created file | ${JSON.stringify({ file: resolvedPath }, null, 2)}`);
|
|
24
|
+
} else {
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
trace('VirtualCommand', () => `touch: success | ${JSON.stringify({ filesTouched: args.length }, null, 2)}`);
|
|
31
|
+
return VirtualUtils.success();
|
|
32
|
+
} catch (error) {
|
|
33
|
+
trace('VirtualCommand', () => `touch: error | ${JSON.stringify({ error: error.message }, null, 2)}`);
|
|
34
|
+
return VirtualUtils.error(`touch: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { VirtualUtils } from '../$.utils.mjs';
|
|
4
|
+
|
|
5
|
+
export default function createWhichCommand(virtualCommands) {
|
|
6
|
+
return async function which({ args }) {
|
|
7
|
+
const argError = VirtualUtils.validateArgs(args, 1, 'which');
|
|
8
|
+
if (argError) return argError;
|
|
9
|
+
|
|
10
|
+
const cmd = args[0];
|
|
11
|
+
|
|
12
|
+
if (virtualCommands.has(cmd)) {
|
|
13
|
+
return VirtualUtils.success(`${cmd}: shell builtin\n`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const paths = (process.env.PATH || '').split(process.platform === 'win32' ? ';' : ':');
|
|
17
|
+
const extensions = process.platform === 'win32' ? ['', '.exe', '.cmd', '.bat'] : [''];
|
|
18
|
+
|
|
19
|
+
for (const pathDir of paths) {
|
|
20
|
+
for (const ext of extensions) {
|
|
21
|
+
const fullPath = path.join(pathDir, cmd + ext);
|
|
22
|
+
try {
|
|
23
|
+
if (fs.statSync(fullPath).isFile()) {
|
|
24
|
+
return VirtualUtils.success(fullPath + '\n');
|
|
25
|
+
}
|
|
26
|
+
} catch { }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return VirtualUtils.error(`which: no ${cmd} in PATH`);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { trace } from '../$.utils.mjs';
|
|
2
|
+
|
|
3
|
+
export default async function* yes({ args, stdin, isCancelled, signal, ...rest }) {
|
|
4
|
+
const output = args.length > 0 ? args.join(' ') : 'y';
|
|
5
|
+
trace('VirtualCommand', () => `yes: starting infinite generator | ${JSON.stringify({ output }, null, 2)}`);
|
|
6
|
+
|
|
7
|
+
let iteration = 0;
|
|
8
|
+
const MAX_ITERATIONS = 1000000; // Safety limit
|
|
9
|
+
|
|
10
|
+
while (!isCancelled?.() && iteration < MAX_ITERATIONS) {
|
|
11
|
+
// Check for abort signal
|
|
12
|
+
if (signal?.aborted) {
|
|
13
|
+
trace('VirtualCommand', () => `yes: aborted via signal | ${JSON.stringify({ iteration }, null, 2)}`);
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Also check rest properties for various cancellation methods
|
|
18
|
+
if (rest.aborted || rest.cancelled || rest.stop) {
|
|
19
|
+
trace('VirtualCommand', () => `yes: stopped via property | ${JSON.stringify({ iteration }, null, 2)}`);
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
yield output + '\n';
|
|
24
|
+
|
|
25
|
+
iteration++;
|
|
26
|
+
|
|
27
|
+
// Yield control periodically to prevent blocking
|
|
28
|
+
if (iteration % 1000 === 0) {
|
|
29
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
trace('VirtualCommand', () => `yes: generator completed | ${JSON.stringify({ iteration }, null, 2)}`);
|
|
34
|
+
}
|