command-stream 0.7.0 → 0.8.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/README.md +265 -153
- package/package.json +36 -4
- package/src/$.mjs +3660 -1595
- package/src/$.utils.mjs +14 -6
- package/src/commands/$.basename.mjs +8 -6
- package/src/commands/$.cat.mjs +23 -6
- package/src/commands/$.cd.mjs +13 -4
- package/src/commands/$.cp.mjs +52 -25
- package/src/commands/$.dirname.mjs +6 -4
- package/src/commands/$.echo.mjs +11 -4
- package/src/commands/$.env.mjs +3 -3
- package/src/commands/$.exit.mjs +1 -1
- package/src/commands/$.false.mjs +1 -1
- package/src/commands/$.ls.mjs +28 -15
- package/src/commands/$.mkdir.mjs +24 -8
- package/src/commands/$.mv.mjs +48 -20
- package/src/commands/$.pwd.mjs +6 -3
- package/src/commands/$.rm.mjs +29 -12
- package/src/commands/$.seq.mjs +13 -9
- package/src/commands/$.sleep.mjs +83 -31
- package/src/commands/$.test.mjs +4 -4
- package/src/commands/$.touch.mjs +35 -10
- package/src/commands/$.true.mjs +1 -1
- package/src/commands/$.which.mjs +11 -6
- package/src/commands/$.yes.mjs +67 -23
- package/src/shell-parser.mjs +113 -85
package/src/$.utils.mjs
CHANGED
|
@@ -3,8 +3,11 @@ import path from 'path';
|
|
|
3
3
|
const VERBOSE = process.env.COMMAND_STREAM_VERBOSE === 'true';
|
|
4
4
|
|
|
5
5
|
export function trace(category, messageOrFunc) {
|
|
6
|
-
if (!VERBOSE)
|
|
7
|
-
|
|
6
|
+
if (!VERBOSE) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const message =
|
|
10
|
+
typeof messageOrFunc === 'function' ? messageOrFunc() : messageOrFunc;
|
|
8
11
|
const timestamp = new Date().toISOString();
|
|
9
12
|
console.error(`[TRACE ${timestamp}] [${category}] ${message}`);
|
|
10
13
|
}
|
|
@@ -47,7 +50,10 @@ export const VirtualUtils = {
|
|
|
47
50
|
if (minCount === 1) {
|
|
48
51
|
return this.missingOperandError(commandName);
|
|
49
52
|
} else {
|
|
50
|
-
return this.invalidArgumentError(
|
|
53
|
+
return this.invalidArgumentError(
|
|
54
|
+
commandName,
|
|
55
|
+
`requires at least ${minCount} arguments`
|
|
56
|
+
);
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
return null; // No error
|
|
@@ -58,7 +64,9 @@ export const VirtualUtils = {
|
|
|
58
64
|
*/
|
|
59
65
|
resolvePath(filePath, cwd = null) {
|
|
60
66
|
const basePath = cwd || process.cwd();
|
|
61
|
-
return path.isAbsolute(filePath)
|
|
67
|
+
return path.isAbsolute(filePath)
|
|
68
|
+
? filePath
|
|
69
|
+
: path.resolve(basePath, filePath);
|
|
62
70
|
},
|
|
63
71
|
|
|
64
72
|
/**
|
|
@@ -77,5 +85,5 @@ export const VirtualUtils = {
|
|
|
77
85
|
*/
|
|
78
86
|
createAsyncWrapper(promiseFactory) {
|
|
79
87
|
return new Promise(promiseFactory);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
88
|
+
},
|
|
89
|
+
};
|
|
@@ -3,17 +3,19 @@ import { VirtualUtils } from '../$.utils.mjs';
|
|
|
3
3
|
|
|
4
4
|
export default async function basename({ args }) {
|
|
5
5
|
const argError = VirtualUtils.validateArgs(args, 1, 'basename');
|
|
6
|
-
if (argError)
|
|
6
|
+
if (argError) {
|
|
7
|
+
return argError;
|
|
8
|
+
}
|
|
7
9
|
|
|
8
10
|
const filePath = args[0];
|
|
9
11
|
const suffix = args[1];
|
|
10
|
-
|
|
12
|
+
|
|
11
13
|
let result = path.basename(filePath);
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
// Remove suffix if provided and it matches
|
|
14
16
|
if (suffix && result.endsWith(suffix)) {
|
|
15
17
|
result = result.slice(0, -suffix.length);
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
return VirtualUtils.success(result
|
|
19
|
-
}
|
|
19
|
+
|
|
20
|
+
return VirtualUtils.success(`${result}\n`);
|
|
21
|
+
}
|
package/src/commands/$.cat.mjs
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
3
3
|
|
|
4
|
-
export default async function cat({
|
|
4
|
+
export default async function cat({
|
|
5
|
+
args,
|
|
6
|
+
stdin,
|
|
7
|
+
cwd,
|
|
8
|
+
isCancelled,
|
|
9
|
+
abortSignal,
|
|
10
|
+
}) {
|
|
5
11
|
if (args.length === 0) {
|
|
6
12
|
// Read from stdin if no files specified
|
|
7
13
|
if (stdin !== undefined && stdin !== '') {
|
|
@@ -18,8 +24,11 @@ export default async function cat({ args, stdin, cwd, isCancelled, abortSignal }
|
|
|
18
24
|
trace('VirtualCommand', () => `cat: cancelled while processing files`);
|
|
19
25
|
return { code: 130, stdout: '', stderr: '' }; // SIGINT exit code
|
|
20
26
|
}
|
|
21
|
-
|
|
22
|
-
trace(
|
|
27
|
+
|
|
28
|
+
trace(
|
|
29
|
+
'VirtualCommand',
|
|
30
|
+
() => `cat: reading file | ${JSON.stringify({ file }, null, 2)}`
|
|
31
|
+
);
|
|
23
32
|
const resolvedPath = VirtualUtils.resolvePath(file, cwd);
|
|
24
33
|
try {
|
|
25
34
|
const content = fs.readFileSync(resolvedPath, 'utf8');
|
|
@@ -35,10 +44,18 @@ export default async function cat({ args, stdin, cwd, isCancelled, abortSignal }
|
|
|
35
44
|
}
|
|
36
45
|
}
|
|
37
46
|
const output = outputs.join('');
|
|
38
|
-
trace(
|
|
47
|
+
trace(
|
|
48
|
+
'VirtualCommand',
|
|
49
|
+
() =>
|
|
50
|
+
`cat: success | ${JSON.stringify({ bytesRead: output.length }, null, 2)}`
|
|
51
|
+
);
|
|
39
52
|
return VirtualUtils.success(output);
|
|
40
53
|
} catch (error) {
|
|
41
|
-
trace(
|
|
54
|
+
trace(
|
|
55
|
+
'VirtualCommand',
|
|
56
|
+
() =>
|
|
57
|
+
`cat: unexpected error | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
58
|
+
);
|
|
42
59
|
return VirtualUtils.error(`cat: ${error.message}`);
|
|
43
60
|
}
|
|
44
|
-
}
|
|
61
|
+
}
|
package/src/commands/$.cd.mjs
CHANGED
|
@@ -2,16 +2,25 @@ import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
|
2
2
|
|
|
3
3
|
export default async function cd({ args }) {
|
|
4
4
|
const target = args[0] || process.env.HOME || process.env.USERPROFILE || '/';
|
|
5
|
-
trace(
|
|
5
|
+
trace(
|
|
6
|
+
'VirtualCommand',
|
|
7
|
+
() => `cd: changing directory | ${JSON.stringify({ target }, null, 2)}`
|
|
8
|
+
);
|
|
6
9
|
|
|
7
10
|
try {
|
|
8
11
|
process.chdir(target);
|
|
9
12
|
const newDir = process.cwd();
|
|
10
|
-
trace(
|
|
13
|
+
trace(
|
|
14
|
+
'VirtualCommand',
|
|
15
|
+
() => `cd: success | ${JSON.stringify({ newDir }, null, 2)}`
|
|
16
|
+
);
|
|
11
17
|
// cd command should not output anything on success, just like real cd
|
|
12
18
|
return VirtualUtils.success('');
|
|
13
19
|
} catch (error) {
|
|
14
|
-
trace(
|
|
20
|
+
trace(
|
|
21
|
+
'VirtualCommand',
|
|
22
|
+
() => `cd: failed | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
23
|
+
);
|
|
15
24
|
return { stderr: `cd: ${error.message}\n`, code: 1 };
|
|
16
25
|
}
|
|
17
|
-
}
|
|
26
|
+
}
|
package/src/commands/$.cp.mjs
CHANGED
|
@@ -4,12 +4,17 @@ import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
|
4
4
|
|
|
5
5
|
export default async function cp({ args, stdin, cwd }) {
|
|
6
6
|
const argError = VirtualUtils.validateArgs(args, 2, 'cp');
|
|
7
|
-
if (argError)
|
|
7
|
+
if (argError) {
|
|
8
|
+
return VirtualUtils.invalidArgumentError(
|
|
9
|
+
'cp',
|
|
10
|
+
'missing destination file operand'
|
|
11
|
+
);
|
|
12
|
+
}
|
|
8
13
|
|
|
9
14
|
// Parse flags and paths
|
|
10
15
|
const flags = new Set();
|
|
11
16
|
const paths = [];
|
|
12
|
-
|
|
17
|
+
|
|
13
18
|
for (const arg of args) {
|
|
14
19
|
if (arg === '-r' || arg === '-R' || arg === '--recursive') {
|
|
15
20
|
flags.add('r');
|
|
@@ -23,44 +28,48 @@ export default async function cp({ args, stdin, cwd }) {
|
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
if (paths.length < 2) {
|
|
26
|
-
return VirtualUtils.invalidArgumentError(
|
|
31
|
+
return VirtualUtils.invalidArgumentError(
|
|
32
|
+
'cp',
|
|
33
|
+
'missing destination file operand'
|
|
34
|
+
);
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
const recursive = flags.has('r') || flags.has('R');
|
|
30
38
|
const sources = paths.slice(0, -1);
|
|
31
39
|
const destination = paths[paths.length - 1];
|
|
32
|
-
|
|
40
|
+
|
|
33
41
|
try {
|
|
34
42
|
const destPath = VirtualUtils.resolvePath(destination, cwd);
|
|
35
43
|
let destExists = false;
|
|
36
44
|
let destIsDir = false;
|
|
37
|
-
|
|
45
|
+
|
|
38
46
|
try {
|
|
39
47
|
const destStats = fs.statSync(destPath);
|
|
40
48
|
destExists = true;
|
|
41
49
|
destIsDir = destStats.isDirectory();
|
|
42
50
|
} catch (error) {
|
|
43
|
-
if (error.code !== 'ENOENT')
|
|
51
|
+
if (error.code !== 'ENOENT') {
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
// Copying multiple files requires destination to be a directory
|
|
47
57
|
if (sources.length > 1 && destExists && !destIsDir) {
|
|
48
|
-
return VirtualUtils.error(
|
|
58
|
+
return VirtualUtils.error(
|
|
59
|
+
`cp: target '${destination}' is not a directory`
|
|
60
|
+
);
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
// Helper function to copy directory recursively
|
|
52
64
|
const copyRecursive = (src, dest) => {
|
|
53
65
|
const stats = fs.statSync(src);
|
|
54
|
-
|
|
66
|
+
|
|
55
67
|
if (stats.isDirectory()) {
|
|
56
68
|
fs.mkdirSync(dest, { recursive: true });
|
|
57
69
|
const entries = fs.readdirSync(src);
|
|
58
|
-
|
|
70
|
+
|
|
59
71
|
for (const entry of entries) {
|
|
60
|
-
copyRecursive(
|
|
61
|
-
path.join(src, entry),
|
|
62
|
-
path.join(dest, entry)
|
|
63
|
-
);
|
|
72
|
+
copyRecursive(path.join(src, entry), path.join(dest, entry));
|
|
64
73
|
}
|
|
65
74
|
} else {
|
|
66
75
|
fs.copyFileSync(src, dest);
|
|
@@ -69,11 +78,11 @@ export default async function cp({ args, stdin, cwd }) {
|
|
|
69
78
|
|
|
70
79
|
for (const source of sources) {
|
|
71
80
|
const sourcePath = VirtualUtils.resolvePath(source, cwd);
|
|
72
|
-
|
|
81
|
+
|
|
73
82
|
try {
|
|
74
83
|
const sourceStats = fs.statSync(sourcePath);
|
|
75
84
|
let finalDestPath = destPath;
|
|
76
|
-
|
|
85
|
+
|
|
77
86
|
if (destIsDir || (sources.length > 1 && !destExists)) {
|
|
78
87
|
// Copying into a directory
|
|
79
88
|
if (!destExists) {
|
|
@@ -83,30 +92,48 @@ export default async function cp({ args, stdin, cwd }) {
|
|
|
83
92
|
}
|
|
84
93
|
finalDestPath = path.join(destPath, path.basename(sourcePath));
|
|
85
94
|
}
|
|
86
|
-
|
|
95
|
+
|
|
87
96
|
if (sourceStats.isDirectory()) {
|
|
88
97
|
if (!recursive) {
|
|
89
|
-
return VirtualUtils.error(
|
|
98
|
+
return VirtualUtils.error(
|
|
99
|
+
`cp: -r not specified; omitting directory '${source}'`
|
|
100
|
+
);
|
|
90
101
|
}
|
|
91
|
-
trace(
|
|
102
|
+
trace(
|
|
103
|
+
'VirtualCommand',
|
|
104
|
+
() =>
|
|
105
|
+
`cp: copying directory | ${JSON.stringify({ from: sourcePath, to: finalDestPath }, null, 2)}`
|
|
106
|
+
);
|
|
92
107
|
copyRecursive(sourcePath, finalDestPath);
|
|
93
108
|
} else {
|
|
94
|
-
trace(
|
|
109
|
+
trace(
|
|
110
|
+
'VirtualCommand',
|
|
111
|
+
() =>
|
|
112
|
+
`cp: copying file | ${JSON.stringify({ from: sourcePath, to: finalDestPath }, null, 2)}`
|
|
113
|
+
);
|
|
95
114
|
fs.copyFileSync(sourcePath, finalDestPath);
|
|
96
115
|
}
|
|
97
|
-
|
|
98
116
|
} catch (error) {
|
|
99
117
|
if (error.code === 'ENOENT') {
|
|
100
|
-
return VirtualUtils.error(
|
|
118
|
+
return VirtualUtils.error(
|
|
119
|
+
`cp: cannot stat '${source}': No such file or directory`
|
|
120
|
+
);
|
|
101
121
|
}
|
|
102
122
|
throw error;
|
|
103
123
|
}
|
|
104
124
|
}
|
|
105
|
-
|
|
106
|
-
trace(
|
|
125
|
+
|
|
126
|
+
trace(
|
|
127
|
+
'VirtualCommand',
|
|
128
|
+
() =>
|
|
129
|
+
`cp: success | ${JSON.stringify({ filesCopied: sources.length }, null, 2)}`
|
|
130
|
+
);
|
|
107
131
|
return VirtualUtils.success();
|
|
108
132
|
} catch (error) {
|
|
109
|
-
trace(
|
|
133
|
+
trace(
|
|
134
|
+
'VirtualCommand',
|
|
135
|
+
() => `cp: error | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
136
|
+
);
|
|
110
137
|
return VirtualUtils.error(`cp: ${error.message}`);
|
|
111
138
|
}
|
|
112
|
-
}
|
|
139
|
+
}
|
|
@@ -3,10 +3,12 @@ import { VirtualUtils } from '../$.utils.mjs';
|
|
|
3
3
|
|
|
4
4
|
export default async function dirname({ args }) {
|
|
5
5
|
const argError = VirtualUtils.validateArgs(args, 1, 'dirname');
|
|
6
|
-
if (argError)
|
|
6
|
+
if (argError) {
|
|
7
|
+
return argError;
|
|
8
|
+
}
|
|
7
9
|
|
|
8
10
|
const filePath = args[0];
|
|
9
11
|
const result = path.dirname(filePath);
|
|
10
|
-
|
|
11
|
-
return VirtualUtils.success(result
|
|
12
|
-
}
|
|
12
|
+
|
|
13
|
+
return VirtualUtils.success(`${result}\n`);
|
|
14
|
+
}
|
package/src/commands/$.echo.mjs
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
2
2
|
|
|
3
3
|
export default async function echo({ args }) {
|
|
4
|
-
trace(
|
|
4
|
+
trace(
|
|
5
|
+
'VirtualCommand',
|
|
6
|
+
() =>
|
|
7
|
+
`echo: processing | ${JSON.stringify({ argsCount: args.length }, null, 2)}`
|
|
8
|
+
);
|
|
5
9
|
|
|
6
10
|
let output = args.join(' ');
|
|
7
11
|
if (args.includes('-n')) {
|
|
8
12
|
// Don't add newline
|
|
9
|
-
trace(
|
|
10
|
-
|
|
13
|
+
trace(
|
|
14
|
+
'VirtualCommand',
|
|
15
|
+
() => `BRANCH: echo => NO_NEWLINE | ${JSON.stringify({}, null, 2)}`
|
|
16
|
+
);
|
|
17
|
+
output = args.filter((arg) => arg !== '-n').join(' ');
|
|
11
18
|
} else {
|
|
12
19
|
output += '\n';
|
|
13
20
|
}
|
|
14
21
|
return VirtualUtils.success(output);
|
|
15
|
-
}
|
|
22
|
+
}
|
package/src/commands/$.env.mjs
CHANGED
|
@@ -4,11 +4,11 @@ export default async function env({ args, stdin, env }) {
|
|
|
4
4
|
if (args.length === 0) {
|
|
5
5
|
// Use custom env if provided, otherwise use process.env
|
|
6
6
|
const envVars = env || process.env;
|
|
7
|
-
const output = Object.entries(envVars)
|
|
7
|
+
const output = `${Object.entries(envVars)
|
|
8
8
|
.map(([key, value]) => `${key}=${value}`)
|
|
9
|
-
.join('\n')
|
|
9
|
+
.join('\n')}\n`;
|
|
10
10
|
return VirtualUtils.success(output);
|
|
11
11
|
}
|
|
12
12
|
// TODO: Support setting environment variables for subsequent command
|
|
13
13
|
return VirtualUtils.error('env: setting variables not yet supported');
|
|
14
|
-
}
|
|
14
|
+
}
|
package/src/commands/$.exit.mjs
CHANGED
package/src/commands/$.false.mjs
CHANGED
package/src/commands/$.ls.mjs
CHANGED
|
@@ -7,7 +7,7 @@ export default async function ls({ args, stdin, cwd }) {
|
|
|
7
7
|
// Parse flags
|
|
8
8
|
const flags = new Set();
|
|
9
9
|
const paths = [];
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
for (const arg of args) {
|
|
12
12
|
if (arg.startsWith('-')) {
|
|
13
13
|
for (const flag of arg.slice(1)) {
|
|
@@ -25,22 +25,26 @@ export default async function ls({ args, stdin, cwd }) {
|
|
|
25
25
|
|
|
26
26
|
const showAll = flags.has('a');
|
|
27
27
|
const longFormat = flags.has('l');
|
|
28
|
-
|
|
29
|
-
trace(
|
|
28
|
+
|
|
29
|
+
trace(
|
|
30
|
+
'VirtualCommand',
|
|
31
|
+
() =>
|
|
32
|
+
`ls: listing | ${JSON.stringify({ paths, flags: Array.from(flags) }, null, 2)}`
|
|
33
|
+
);
|
|
30
34
|
|
|
31
35
|
const outputs = [];
|
|
32
|
-
|
|
36
|
+
|
|
33
37
|
for (const targetPath of paths) {
|
|
34
38
|
const resolvedPath = VirtualUtils.resolvePath(targetPath, cwd);
|
|
35
39
|
const stats = fs.statSync(resolvedPath);
|
|
36
|
-
|
|
40
|
+
|
|
37
41
|
if (stats.isDirectory()) {
|
|
38
42
|
let entries = fs.readdirSync(resolvedPath);
|
|
39
|
-
|
|
43
|
+
|
|
40
44
|
if (!showAll) {
|
|
41
|
-
entries = entries.filter(e => !e.startsWith('.'));
|
|
45
|
+
entries = entries.filter((e) => !e.startsWith('.'));
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
|
|
44
48
|
if (longFormat) {
|
|
45
49
|
for (const entry of entries) {
|
|
46
50
|
const entryPath = path.join(resolvedPath, entry);
|
|
@@ -51,7 +55,7 @@ export default async function ls({ args, stdin, cwd }) {
|
|
|
51
55
|
outputs.push(`${mode} 1 user group ${size} ${mtime} ${entry}\n`);
|
|
52
56
|
}
|
|
53
57
|
} else {
|
|
54
|
-
outputs.push(entries.join('\n')
|
|
58
|
+
outputs.push(`${entries.join('\n')}\n`);
|
|
55
59
|
}
|
|
56
60
|
} else {
|
|
57
61
|
// Single file
|
|
@@ -62,18 +66,27 @@ export default async function ls({ args, stdin, cwd }) {
|
|
|
62
66
|
const basename = path.basename(resolvedPath);
|
|
63
67
|
outputs.push(`${mode} 1 user group ${size} ${mtime} ${basename}\n`);
|
|
64
68
|
} else {
|
|
65
|
-
outputs.push(path.basename(resolvedPath)
|
|
69
|
+
outputs.push(`${path.basename(resolvedPath)}\n`);
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
|
-
|
|
70
|
-
trace(
|
|
73
|
+
|
|
74
|
+
trace(
|
|
75
|
+
'VirtualCommand',
|
|
76
|
+
() =>
|
|
77
|
+
`ls: success | ${JSON.stringify({ entriesCount: outputs.length }, null, 2)}`
|
|
78
|
+
);
|
|
71
79
|
return VirtualUtils.success(outputs.join(''));
|
|
72
80
|
} catch (error) {
|
|
73
|
-
trace(
|
|
81
|
+
trace(
|
|
82
|
+
'VirtualCommand',
|
|
83
|
+
() => `ls: error | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
84
|
+
);
|
|
74
85
|
if (error.code === 'ENOENT') {
|
|
75
|
-
return VirtualUtils.error(
|
|
86
|
+
return VirtualUtils.error(
|
|
87
|
+
`ls: ${args[0] || '.'}: No such file or directory`
|
|
88
|
+
);
|
|
76
89
|
}
|
|
77
90
|
return VirtualUtils.error(`ls: ${error.message}`);
|
|
78
91
|
}
|
|
79
|
-
}
|
|
92
|
+
}
|
package/src/commands/$.mkdir.mjs
CHANGED
|
@@ -3,12 +3,14 @@ import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
|
3
3
|
|
|
4
4
|
export default async function mkdir({ args, stdin, cwd }) {
|
|
5
5
|
const argError = VirtualUtils.validateArgs(args, 1, 'mkdir');
|
|
6
|
-
if (argError)
|
|
6
|
+
if (argError) {
|
|
7
|
+
return argError;
|
|
8
|
+
}
|
|
7
9
|
|
|
8
10
|
// Parse flags and paths
|
|
9
11
|
const flags = new Set();
|
|
10
12
|
const paths = [];
|
|
11
|
-
|
|
13
|
+
|
|
12
14
|
for (const arg of args) {
|
|
13
15
|
if (arg === '-p' || arg === '--parents') {
|
|
14
16
|
flags.add('p');
|
|
@@ -26,20 +28,34 @@ export default async function mkdir({ args, stdin, cwd }) {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const recursive = flags.has('p');
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
try {
|
|
31
33
|
for (const dir of paths) {
|
|
32
34
|
const resolvedPath = VirtualUtils.resolvePath(dir, cwd);
|
|
33
|
-
trace(
|
|
35
|
+
trace(
|
|
36
|
+
'VirtualCommand',
|
|
37
|
+
() =>
|
|
38
|
+
`mkdir: creating | ${JSON.stringify({ dir: resolvedPath, recursive }, null, 2)}`
|
|
39
|
+
);
|
|
34
40
|
fs.mkdirSync(resolvedPath, { recursive });
|
|
35
41
|
}
|
|
36
|
-
trace(
|
|
42
|
+
trace(
|
|
43
|
+
'VirtualCommand',
|
|
44
|
+
() =>
|
|
45
|
+
`mkdir: success | ${JSON.stringify({ dirsCreated: paths.length }, null, 2)}`
|
|
46
|
+
);
|
|
37
47
|
return VirtualUtils.success();
|
|
38
48
|
} catch (error) {
|
|
39
|
-
trace(
|
|
49
|
+
trace(
|
|
50
|
+
'VirtualCommand',
|
|
51
|
+
() =>
|
|
52
|
+
`mkdir: error | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
53
|
+
);
|
|
40
54
|
if (error.code === 'EEXIST') {
|
|
41
|
-
return VirtualUtils.error(
|
|
55
|
+
return VirtualUtils.error(
|
|
56
|
+
`mkdir: cannot create directory '${paths[0]}': File exists`
|
|
57
|
+
);
|
|
42
58
|
}
|
|
43
59
|
return VirtualUtils.error(`mkdir: ${error.message}`);
|
|
44
60
|
}
|
|
45
|
-
}
|
|
61
|
+
}
|
package/src/commands/$.mv.mjs
CHANGED
|
@@ -4,12 +4,17 @@ import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
|
4
4
|
|
|
5
5
|
export default async function mv({ args, stdin, cwd }) {
|
|
6
6
|
const argError = VirtualUtils.validateArgs(args, 2, 'mv');
|
|
7
|
-
if (argError)
|
|
7
|
+
if (argError) {
|
|
8
|
+
return VirtualUtils.invalidArgumentError(
|
|
9
|
+
'mv',
|
|
10
|
+
'missing destination file operand'
|
|
11
|
+
);
|
|
12
|
+
}
|
|
8
13
|
|
|
9
14
|
// Parse flags and paths
|
|
10
15
|
const flags = new Set();
|
|
11
16
|
const paths = [];
|
|
12
|
-
|
|
17
|
+
|
|
13
18
|
for (const arg of args) {
|
|
14
19
|
if (arg.startsWith('-')) {
|
|
15
20
|
for (const flag of arg.slice(1)) {
|
|
@@ -21,69 +26,92 @@ export default async function mv({ args, stdin, cwd }) {
|
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
if (paths.length < 2) {
|
|
24
|
-
return VirtualUtils.invalidArgumentError(
|
|
29
|
+
return VirtualUtils.invalidArgumentError(
|
|
30
|
+
'mv',
|
|
31
|
+
'missing destination file operand'
|
|
32
|
+
);
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
const force = flags.has('f');
|
|
28
36
|
const sources = paths.slice(0, -1);
|
|
29
37
|
const destination = paths[paths.length - 1];
|
|
30
|
-
|
|
38
|
+
|
|
31
39
|
try {
|
|
32
40
|
const destPath = VirtualUtils.resolvePath(destination, cwd);
|
|
33
41
|
let destExists = false;
|
|
34
42
|
let destIsDir = false;
|
|
35
|
-
|
|
43
|
+
|
|
36
44
|
try {
|
|
37
45
|
const destStats = fs.statSync(destPath);
|
|
38
46
|
destExists = true;
|
|
39
47
|
destIsDir = destStats.isDirectory();
|
|
40
48
|
} catch (error) {
|
|
41
|
-
if (error.code !== 'ENOENT')
|
|
49
|
+
if (error.code !== 'ENOENT') {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
// Moving multiple files requires destination to be a directory
|
|
45
55
|
if (sources.length > 1 && destExists && !destIsDir) {
|
|
46
|
-
return VirtualUtils.error(
|
|
56
|
+
return VirtualUtils.error(
|
|
57
|
+
`mv: target '${destination}' is not a directory`
|
|
58
|
+
);
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
for (const source of sources) {
|
|
50
62
|
const sourcePath = VirtualUtils.resolvePath(source, cwd);
|
|
51
|
-
|
|
63
|
+
|
|
52
64
|
try {
|
|
53
65
|
const sourceStats = fs.statSync(sourcePath);
|
|
54
66
|
let finalDestPath = destPath;
|
|
55
|
-
|
|
67
|
+
|
|
56
68
|
if (destIsDir) {
|
|
57
69
|
// Moving into a directory
|
|
58
70
|
finalDestPath = path.join(destPath, path.basename(sourcePath));
|
|
59
71
|
}
|
|
60
|
-
|
|
72
|
+
|
|
61
73
|
// Check if destination exists and handle force flag
|
|
62
74
|
if (!force) {
|
|
63
75
|
try {
|
|
64
76
|
fs.statSync(finalDestPath);
|
|
65
77
|
// Destination exists and no force flag
|
|
66
|
-
return VirtualUtils.error(
|
|
78
|
+
return VirtualUtils.error(
|
|
79
|
+
`mv: cannot move '${source}': File exists`
|
|
80
|
+
);
|
|
67
81
|
} catch (error) {
|
|
68
|
-
if (error.code !== 'ENOENT')
|
|
82
|
+
if (error.code !== 'ENOENT') {
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
|
-
|
|
72
|
-
trace(
|
|
87
|
+
|
|
88
|
+
trace(
|
|
89
|
+
'VirtualCommand',
|
|
90
|
+
() =>
|
|
91
|
+
`mv: moving | ${JSON.stringify({ from: sourcePath, to: finalDestPath }, null, 2)}`
|
|
92
|
+
);
|
|
73
93
|
fs.renameSync(sourcePath, finalDestPath);
|
|
74
|
-
|
|
75
94
|
} catch (error) {
|
|
76
95
|
if (error.code === 'ENOENT') {
|
|
77
|
-
return VirtualUtils.error(
|
|
96
|
+
return VirtualUtils.error(
|
|
97
|
+
`mv: cannot stat '${source}': No such file or directory`
|
|
98
|
+
);
|
|
78
99
|
}
|
|
79
100
|
throw error;
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
|
-
|
|
83
|
-
trace(
|
|
103
|
+
|
|
104
|
+
trace(
|
|
105
|
+
'VirtualCommand',
|
|
106
|
+
() =>
|
|
107
|
+
`mv: success | ${JSON.stringify({ filesMoved: sources.length }, null, 2)}`
|
|
108
|
+
);
|
|
84
109
|
return VirtualUtils.success();
|
|
85
110
|
} catch (error) {
|
|
86
|
-
trace(
|
|
111
|
+
trace(
|
|
112
|
+
'VirtualCommand',
|
|
113
|
+
() => `mv: error | ${JSON.stringify({ error: error.message }, null, 2)}`
|
|
114
|
+
);
|
|
87
115
|
return VirtualUtils.error(`mv: ${error.message}`);
|
|
88
116
|
}
|
|
89
|
-
}
|
|
117
|
+
}
|
package/src/commands/$.pwd.mjs
CHANGED
|
@@ -3,6 +3,9 @@ import { trace, VirtualUtils } from '../$.utils.mjs';
|
|
|
3
3
|
export default async function pwd({ args, stdin, cwd }) {
|
|
4
4
|
// If cwd option is provided, return that instead of process.cwd()
|
|
5
5
|
const dir = cwd || process.cwd();
|
|
6
|
-
trace(
|
|
7
|
-
|
|
8
|
-
}
|
|
6
|
+
trace(
|
|
7
|
+
'VirtualCommand',
|
|
8
|
+
() => `pwd: getting directory | ${JSON.stringify({ dir }, null, 2)}`
|
|
9
|
+
);
|
|
10
|
+
return VirtualUtils.success(`${dir}\n`);
|
|
11
|
+
}
|