shell-dsl 0.0.21 → 0.0.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.
- package/README.md +50 -2
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/cut/cut.cjs +188 -0
- package/dist/cjs/src/commands/cut/cut.cjs.map +10 -0
- package/dist/cjs/src/commands/index.cjs +6 -2
- package/dist/cjs/src/commands/index.cjs.map +3 -3
- package/dist/cjs/src/commands/ls/ls.cjs +2 -2
- package/dist/cjs/src/commands/ls/ls.cjs.map +3 -3
- package/dist/cjs/src/interpreter/interpreter.cjs +5 -3
- package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
- package/dist/cjs/src/io/stdout.cjs +11 -5
- package/dist/cjs/src/io/stdout.cjs.map +3 -3
- package/dist/cjs/src/parser/parser.cjs +3 -2
- package/dist/cjs/src/parser/parser.cjs.map +3 -3
- package/dist/cjs/src/shell-dsl.cjs +9 -4
- package/dist/cjs/src/shell-dsl.cjs.map +3 -3
- package/dist/cjs/src/types.cjs.map +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/cut/cut.mjs +158 -0
- package/dist/mjs/src/commands/cut/cut.mjs.map +10 -0
- package/dist/mjs/src/commands/index.mjs +6 -2
- package/dist/mjs/src/commands/index.mjs.map +3 -3
- package/dist/mjs/src/commands/ls/ls.mjs +2 -2
- package/dist/mjs/src/commands/ls/ls.mjs.map +3 -3
- package/dist/mjs/src/interpreter/interpreter.mjs +5 -3
- package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
- package/dist/mjs/src/io/stdout.mjs +11 -5
- package/dist/mjs/src/io/stdout.mjs.map +3 -3
- package/dist/mjs/src/parser/parser.mjs +3 -5
- package/dist/mjs/src/parser/parser.mjs.map +3 -3
- package/dist/mjs/src/shell-dsl.mjs +9 -4
- package/dist/mjs/src/shell-dsl.mjs.map +3 -3
- package/dist/mjs/src/types.mjs.map +2 -2
- package/dist/types/src/commands/cut/cut.d.ts +2 -0
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/interpreter/interpreter.d.ts +2 -0
- package/dist/types/src/io/stdout.d.ts +6 -2
- package/dist/types/src/shell-dsl.d.ts +1 -0
- package/dist/types/src/types.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -279,6 +279,52 @@ await sh`echo $API_KEY`.text(); // "secret\n"
|
|
|
279
279
|
sh.resetEnv(); // Restore initial environment
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
+
## TTY Detection
|
|
283
|
+
|
|
284
|
+
Commands can check `ctx.stdout.isTTY` to vary their output format depending on whether they're writing to a terminal or a pipe/file, just like real shell commands do (e.g. `ls` uses columnar output on a terminal but one-per-line when piped).
|
|
285
|
+
|
|
286
|
+
Enable TTY mode via the `isTTY` config option (default `false`):
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
const sh = createShellDSL({
|
|
290
|
+
fs: createVirtualFS(createFsFromVolume(vol)),
|
|
291
|
+
cwd: "/",
|
|
292
|
+
env: {},
|
|
293
|
+
commands: builtinCommands,
|
|
294
|
+
isTTY: true,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Standalone command — stdout.isTTY is true
|
|
298
|
+
await sh`ls /dir`.text(); // "file1.txt file2.txt subdir\n"
|
|
299
|
+
|
|
300
|
+
// Piped command — intermediate stdout.isTTY is always false
|
|
301
|
+
await sh`ls /dir | grep file`.text(); // "file1.txt\nfile2.txt\n"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
| Context | `stdout.isTTY` |
|
|
305
|
+
|---------|----------------|
|
|
306
|
+
| Standalone command, shell has `isTTY: true` | `true` |
|
|
307
|
+
| Intermediate command in pipeline | `false` |
|
|
308
|
+
| Output redirected to file (`> file`) | `false` |
|
|
309
|
+
| Command substitution (`$(cmd)`) | `false` |
|
|
310
|
+
| Shell has `isTTY: false` (default) | `false` |
|
|
311
|
+
|
|
312
|
+
### Using isTTY in Custom Commands
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
const myls: Command = async (ctx) => {
|
|
316
|
+
const entries = await ctx.fs.readdir(ctx.cwd);
|
|
317
|
+
if (ctx.stdout.isTTY) {
|
|
318
|
+
await ctx.stdout.writeText(entries.join(" ") + "\n");
|
|
319
|
+
} else {
|
|
320
|
+
for (const entry of entries) {
|
|
321
|
+
await ctx.stdout.writeText(entry + "\n");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return 0;
|
|
325
|
+
};
|
|
326
|
+
```
|
|
327
|
+
|
|
282
328
|
## Glob Expansion
|
|
283
329
|
|
|
284
330
|
Globs are expanded by the interpreter before command execution:
|
|
@@ -356,6 +402,7 @@ interface Stdin {
|
|
|
356
402
|
interface Stdout {
|
|
357
403
|
write(chunk: Uint8Array): Promise<void>; // Write bytes
|
|
358
404
|
writeText(str: string): Promise<void>; // Write UTF-8 string
|
|
405
|
+
isTTY: boolean; // Whether output is a terminal
|
|
359
406
|
}
|
|
360
407
|
```
|
|
361
408
|
|
|
@@ -496,7 +543,7 @@ import { builtinCommands } from "shell-dsl/commands";
|
|
|
496
543
|
Or import individually:
|
|
497
544
|
|
|
498
545
|
```ts
|
|
499
|
-
import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "shell-dsl/commands";
|
|
546
|
+
import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut } from "shell-dsl/commands";
|
|
500
547
|
```
|
|
501
548
|
|
|
502
549
|
| Command | Description |
|
|
@@ -510,7 +557,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "s
|
|
|
510
557
|
| `sort` | Sort lines (`-r` reverse, `-n` numeric) |
|
|
511
558
|
| `uniq` | Remove duplicate adjacent lines (`-c` count) |
|
|
512
559
|
| `pwd` | Print working directory |
|
|
513
|
-
| `ls` | List directory contents |
|
|
560
|
+
| `ls` | List directory contents (TTY-aware: space-separated on TTY, one-per-line when piped) |
|
|
514
561
|
| `mkdir` | Create directories (`-p` parents) |
|
|
515
562
|
| `rm` | Remove files/directories (`-r` recursive, `-f` force) |
|
|
516
563
|
| `cp` | Copy files/directories (`-r` recursive, `-n` no-clobber) |
|
|
@@ -521,6 +568,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "s
|
|
|
521
568
|
| `find` | Search for files (`-name`, `-iname`, `-type f\|d`, `-maxdepth`, `-mindepth`) |
|
|
522
569
|
| `sed` | Stream editor (`s///`, `d`, `p`, `-n`, `-e`) |
|
|
523
570
|
| `awk` | Pattern scanning (`{print $1}`, `-F`, `NF`, `NR`) |
|
|
571
|
+
| `cut` | Select fields/characters (`-f`, `-d`, `-c`, `-b`, `-s`, `--complement`) |
|
|
524
572
|
| `test` / `[` | File and string tests (`-f`, `-d`, `-e`, `-z`, `-n`, `=`, `!=`) |
|
|
525
573
|
| `true` | Exit with code 0 |
|
|
526
574
|
| `false` | Exit with code 1 |
|
package/dist/cjs/package.json
CHANGED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/commands/cut/cut.ts
|
|
30
|
+
var exports_cut = {};
|
|
31
|
+
__export(exports_cut, {
|
|
32
|
+
cut: () => cut
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(exports_cut);
|
|
35
|
+
var import_flag_parser = require("../../utils/flag-parser.cjs");
|
|
36
|
+
var spec = {
|
|
37
|
+
name: "cut",
|
|
38
|
+
flags: [
|
|
39
|
+
{ short: "b", long: "bytes", takesValue: true },
|
|
40
|
+
{ short: "c", long: "characters", takesValue: true },
|
|
41
|
+
{ short: "d", long: "delimiter", takesValue: true },
|
|
42
|
+
{ short: "f", long: "fields", takesValue: true },
|
|
43
|
+
{ short: "s", long: "only-delimited" },
|
|
44
|
+
{ long: "complement" },
|
|
45
|
+
{ long: "output-delimiter", takesValue: true }
|
|
46
|
+
],
|
|
47
|
+
usage: `cut -b list [-n] [file ...]
|
|
48
|
+
cut -c list [file ...]
|
|
49
|
+
cut -f list [-d delim] [-s] [file ...]`
|
|
50
|
+
};
|
|
51
|
+
var defaults = {
|
|
52
|
+
bytes: null,
|
|
53
|
+
characters: null,
|
|
54
|
+
delimiter: "\t",
|
|
55
|
+
fields: null,
|
|
56
|
+
onlyDelimited: false,
|
|
57
|
+
complement: false,
|
|
58
|
+
outputDelimiter: null
|
|
59
|
+
};
|
|
60
|
+
var handler = (flags, flag, value) => {
|
|
61
|
+
if (flag.short === "b")
|
|
62
|
+
flags.bytes = value ?? null;
|
|
63
|
+
if (flag.short === "c")
|
|
64
|
+
flags.characters = value ?? null;
|
|
65
|
+
if (flag.short === "d")
|
|
66
|
+
flags.delimiter = value ?? "\t";
|
|
67
|
+
if (flag.short === "f")
|
|
68
|
+
flags.fields = value ?? null;
|
|
69
|
+
if (flag.short === "s")
|
|
70
|
+
flags.onlyDelimited = true;
|
|
71
|
+
if (flag.long === "complement")
|
|
72
|
+
flags.complement = true;
|
|
73
|
+
if (flag.long === "output-delimiter")
|
|
74
|
+
flags.outputDelimiter = value ?? null;
|
|
75
|
+
};
|
|
76
|
+
var parser = import_flag_parser.createFlagParser(spec, defaults, handler);
|
|
77
|
+
function parseListSpec(listStr) {
|
|
78
|
+
const ranges = [];
|
|
79
|
+
for (const part of listStr.split(",")) {
|
|
80
|
+
const trimmed = part.trim();
|
|
81
|
+
if (trimmed.includes("-")) {
|
|
82
|
+
const [startStr, endStr] = trimmed.split("-", 2);
|
|
83
|
+
const start = startStr === "" ? null : parseInt(startStr, 10);
|
|
84
|
+
const end = endStr === "" ? null : parseInt(endStr, 10);
|
|
85
|
+
ranges.push({ start, end });
|
|
86
|
+
} else {
|
|
87
|
+
const n = parseInt(trimmed, 10);
|
|
88
|
+
ranges.push({ start: n, end: n });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return (index, total) => {
|
|
92
|
+
for (const { start, end } of ranges) {
|
|
93
|
+
const s = start ?? 1;
|
|
94
|
+
const e = end ?? total;
|
|
95
|
+
if (index >= s && index <= e)
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
var cut = async (ctx) => {
|
|
102
|
+
const result = parser.parse(ctx.args);
|
|
103
|
+
if (result.error) {
|
|
104
|
+
await parser.writeError(result.error, ctx.stderr);
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
const { bytes, characters, fields, delimiter, onlyDelimited, complement, outputDelimiter } = result.flags;
|
|
108
|
+
const modeCount = [bytes, characters, fields].filter((v) => v !== null).length;
|
|
109
|
+
if (modeCount === 0) {
|
|
110
|
+
await ctx.stderr.writeText(`cut: you must specify a list of bytes, characters, or fields
|
|
111
|
+
`);
|
|
112
|
+
return 1;
|
|
113
|
+
}
|
|
114
|
+
if (modeCount > 1) {
|
|
115
|
+
await ctx.stderr.writeText(`cut: only one type of list may be specified
|
|
116
|
+
`);
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
const listStr = bytes ?? characters ?? fields;
|
|
120
|
+
const selector = parseListSpec(listStr);
|
|
121
|
+
const mode = bytes !== null ? "bytes" : characters !== null ? "chars" : "fields";
|
|
122
|
+
const processLine = async (line) => {
|
|
123
|
+
if (mode === "fields") {
|
|
124
|
+
if (!line.includes(delimiter)) {
|
|
125
|
+
if (onlyDelimited)
|
|
126
|
+
return;
|
|
127
|
+
await ctx.stdout.writeText(line + `
|
|
128
|
+
`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const parts = line.split(delimiter);
|
|
132
|
+
const total = parts.length;
|
|
133
|
+
const selected = [];
|
|
134
|
+
for (let i = 0;i < total; i++) {
|
|
135
|
+
const idx = i + 1;
|
|
136
|
+
const isSelected = selector(idx, total);
|
|
137
|
+
if (complement ? !isSelected : isSelected) {
|
|
138
|
+
selected.push(parts[i]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const outDelim = outputDelimiter ?? delimiter;
|
|
142
|
+
await ctx.stdout.writeText(selected.join(outDelim) + `
|
|
143
|
+
`);
|
|
144
|
+
} else {
|
|
145
|
+
const chars = [...line];
|
|
146
|
+
const total = chars.length;
|
|
147
|
+
const selected = [];
|
|
148
|
+
for (let i = 0;i < total; i++) {
|
|
149
|
+
const idx = i + 1;
|
|
150
|
+
const isSelected = selector(idx, total);
|
|
151
|
+
if (complement ? !isSelected : isSelected) {
|
|
152
|
+
selected.push(chars[i]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const outDelim = outputDelimiter ?? "";
|
|
156
|
+
await ctx.stdout.writeText(selected.join(outDelim) + `
|
|
157
|
+
`);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const files = result.args;
|
|
161
|
+
if (files.length === 0) {
|
|
162
|
+
for await (const line of ctx.stdin.lines()) {
|
|
163
|
+
await processLine(line);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
for (const file of files) {
|
|
167
|
+
try {
|
|
168
|
+
const path = ctx.fs.resolve(ctx.cwd, file);
|
|
169
|
+
const content = (await ctx.fs.readFile(path)).toString();
|
|
170
|
+
const lines = content.split(`
|
|
171
|
+
`);
|
|
172
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
173
|
+
lines.pop();
|
|
174
|
+
}
|
|
175
|
+
for (const line of lines) {
|
|
176
|
+
await processLine(line);
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
await ctx.stderr.writeText(`cut: ${file}: No such file or directory
|
|
180
|
+
`);
|
|
181
|
+
return 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return 0;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
//# debugId=27E02324E2E46D1D64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/commands/cut/cut.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface CutFlags {\n bytes: string | null;\n characters: string | null;\n delimiter: string;\n fields: string | null;\n onlyDelimited: boolean;\n complement: boolean;\n outputDelimiter: string | null;\n}\n\nconst spec = {\n name: \"cut\",\n flags: [\n { short: \"b\", long: \"bytes\", takesValue: true },\n { short: \"c\", long: \"characters\", takesValue: true },\n { short: \"d\", long: \"delimiter\", takesValue: true },\n { short: \"f\", long: \"fields\", takesValue: true },\n { short: \"s\", long: \"only-delimited\" },\n { long: \"complement\" },\n { long: \"output-delimiter\", takesValue: true },\n ] as FlagDefinition[],\n usage: \"cut -b list [-n] [file ...]\\n cut -c list [file ...]\\n cut -f list [-d delim] [-s] [file ...]\",\n};\n\nconst defaults: CutFlags = {\n bytes: null,\n characters: null,\n delimiter: \"\\t\",\n fields: null,\n onlyDelimited: false,\n complement: false,\n outputDelimiter: null,\n};\n\nconst handler = (flags: CutFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"b\") flags.bytes = value ?? null;\n if (flag.short === \"c\") flags.characters = value ?? null;\n if (flag.short === \"d\") flags.delimiter = value ?? \"\\t\";\n if (flag.short === \"f\") flags.fields = value ?? null;\n if (flag.short === \"s\") flags.onlyDelimited = true;\n if (flag.long === \"complement\") flags.complement = true;\n if (flag.long === \"output-delimiter\") flags.outputDelimiter = value ?? null;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\n/**\n * Parse a list specification like \"1\", \"1,3,5\", \"1-3\", \"1-\", \"-3\", \"1-3,7,9-\"\n * Returns a function that checks if a 1-based index is selected.\n */\nfunction parseListSpec(\n listStr: string\n): (index: number, total: number) => boolean {\n const ranges: Array<{ start: number | null; end: number | null }> = [];\n\n for (const part of listStr.split(\",\")) {\n const trimmed = part.trim();\n if (trimmed.includes(\"-\")) {\n const [startStr, endStr] = trimmed.split(\"-\", 2);\n const start = startStr === \"\" ? null : parseInt(startStr!, 10);\n const end = endStr === \"\" ? null : parseInt(endStr!, 10);\n ranges.push({ start, end });\n } else {\n const n = parseInt(trimmed, 10);\n ranges.push({ start: n, end: n });\n }\n }\n\n return (index: number, total: number): boolean => {\n for (const { start, end } of ranges) {\n const s = start ?? 1;\n const e = end ?? total;\n if (index >= s && index <= e) return true;\n }\n return false;\n };\n}\n\nexport const cut: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { bytes, characters, fields, delimiter, onlyDelimited, complement, outputDelimiter } =\n result.flags;\n\n // Validate: exactly one of -b, -c, -f must be given\n const modeCount = [bytes, characters, fields].filter((v) => v !== null).length;\n if (modeCount === 0) {\n await ctx.stderr.writeText(\n \"cut: you must specify a list of bytes, characters, or fields\\n\"\n );\n return 1;\n }\n if (modeCount > 1) {\n await ctx.stderr.writeText(\n \"cut: only one type of list may be specified\\n\"\n );\n return 1;\n }\n\n const listStr = (bytes ?? characters ?? fields)!;\n const selector = parseListSpec(listStr);\n const mode = bytes !== null ? \"bytes\" : characters !== null ? \"chars\" : \"fields\";\n\n const processLine = async (line: string) => {\n if (mode === \"fields\") {\n // Check if delimiter exists in line\n if (!line.includes(delimiter)) {\n if (onlyDelimited) return;\n await ctx.stdout.writeText(line + \"\\n\");\n return;\n }\n\n const parts = line.split(delimiter);\n const total = parts.length;\n const selected: string[] = [];\n\n for (let i = 0; i < total; i++) {\n const idx = i + 1; // 1-based\n const isSelected = selector(idx, total);\n if (complement ? !isSelected : isSelected) {\n selected.push(parts[i]!);\n }\n }\n\n const outDelim = outputDelimiter ?? delimiter;\n await ctx.stdout.writeText(selected.join(outDelim) + \"\\n\");\n } else {\n // bytes/chars mode (equivalent for simplicity)\n const chars = [...line];\n const total = chars.length;\n const selected: string[] = [];\n\n for (let i = 0; i < total; i++) {\n const idx = i + 1; // 1-based\n const isSelected = selector(idx, total);\n if (complement ? !isSelected : isSelected) {\n selected.push(chars[i]!);\n }\n }\n\n const outDelim = outputDelimiter ?? \"\";\n await ctx.stdout.writeText(selected.join(outDelim) + \"\\n\");\n }\n };\n\n const files = result.args;\n\n if (files.length === 0) {\n // Read from stdin\n for await (const line of ctx.stdin.lines()) {\n await processLine(line);\n }\n } else {\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n const content = (await ctx.fs.readFile(path)).toString();\n const lines = content.split(\"\\n\");\n // Remove trailing empty line from final newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n for (const line of lines) {\n await processLine(line);\n }\n } catch {\n await ctx.stderr.writeText(`cut: ${file}: No such file or directory\\n`);\n return 1;\n }\n }\n }\n\n return 0;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "27E02324E2E46D1D64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -50,6 +50,7 @@ __export(exports_commands, {
|
|
|
50
50
|
find: () => import_find.find,
|
|
51
51
|
falseCmd: () => import_true_false.falseCmd,
|
|
52
52
|
echo: () => import_echo.echo,
|
|
53
|
+
cut: () => import_cut.cut,
|
|
53
54
|
cp: () => import_cp.cp,
|
|
54
55
|
continueCmd: () => import_break_continue.continueCmd,
|
|
55
56
|
colon: () => import_colon.colon,
|
|
@@ -87,6 +88,7 @@ var import_break_continue = require("./break-continue/break-continue.cjs");
|
|
|
87
88
|
var import_colon = require("./colon/colon.cjs");
|
|
88
89
|
var import_cd = require("./cd/cd.cjs");
|
|
89
90
|
var import_tr = require("./tr/tr.cjs");
|
|
91
|
+
var import_cut = require("./cut/cut.cjs");
|
|
90
92
|
var import_echo2 = require("./echo/echo.cjs");
|
|
91
93
|
var import_cat2 = require("./cat/cat.cjs");
|
|
92
94
|
var import_grep2 = require("./grep/grep.cjs");
|
|
@@ -113,6 +115,7 @@ var import_break_continue2 = require("./break-continue/break-continue.cjs");
|
|
|
113
115
|
var import_colon2 = require("./colon/colon.cjs");
|
|
114
116
|
var import_cd2 = require("./cd/cd.cjs");
|
|
115
117
|
var import_tr2 = require("./tr/tr.cjs");
|
|
118
|
+
var import_cut2 = require("./cut/cut.cjs");
|
|
116
119
|
var builtinCommands = {
|
|
117
120
|
echo: import_echo2.echo,
|
|
118
121
|
cat: import_cat2.cat,
|
|
@@ -142,7 +145,8 @@ var builtinCommands = {
|
|
|
142
145
|
continue: import_break_continue2.continueCmd,
|
|
143
146
|
":": import_colon2.colon,
|
|
144
147
|
cd: import_cd2.cd,
|
|
145
|
-
tr: import_tr2.tr
|
|
148
|
+
tr: import_tr2.tr,
|
|
149
|
+
cut: import_cut2.cut
|
|
146
150
|
};
|
|
147
151
|
|
|
148
|
-
//# debugId=
|
|
152
|
+
//# debugId=BFE70ED48B7DB93D64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/commands/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../types.cjs\";\n\nexport { echo } from \"./echo/echo.cjs\";\nexport { cat } from \"./cat/cat.cjs\";\nexport { grep } from \"./grep/grep.cjs\";\nexport { wc } from \"./wc/wc.cjs\";\nexport { head } from \"./head/head.cjs\";\nexport { tail } from \"./tail/tail.cjs\";\nexport { sort } from \"./sort/sort.cjs\";\nexport { uniq } from \"./uniq/uniq.cjs\";\nexport { pwd } from \"./pwd/pwd.cjs\";\nexport { ls } from \"./ls/ls.cjs\";\nexport { mkdir } from \"./mkdir/mkdir.cjs\";\nexport { rm } from \"./rm/rm.cjs\";\nexport { test, bracket } from \"./test/test.cjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nexport { touch } from \"./touch/touch.cjs\";\nexport { cp } from \"./cp/cp.cjs\";\nexport { mv } from \"./mv/mv.cjs\";\nexport { tee } from \"./tee/tee.cjs\";\nexport { tree } from \"./tree/tree.cjs\";\nexport { find } from \"./find/find.cjs\";\nexport { sed } from \"./sed/sed.cjs\";\nexport { awk } from \"./awk/awk.cjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nexport { colon } from \"./colon/colon.cjs\";\nexport { cd } from \"./cd/cd.cjs\";\nexport { tr } from \"./tr/tr.cjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.cjs\";\nimport { cat } from \"./cat/cat.cjs\";\nimport { grep } from \"./grep/grep.cjs\";\nimport { wc } from \"./wc/wc.cjs\";\nimport { head } from \"./head/head.cjs\";\nimport { tail } from \"./tail/tail.cjs\";\nimport { sort } from \"./sort/sort.cjs\";\nimport { uniq } from \"./uniq/uniq.cjs\";\nimport { pwd } from \"./pwd/pwd.cjs\";\nimport { ls } from \"./ls/ls.cjs\";\nimport { mkdir } from \"./mkdir/mkdir.cjs\";\nimport { rm } from \"./rm/rm.cjs\";\nimport { test, bracket } from \"./test/test.cjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nimport { touch } from \"./touch/touch.cjs\";\nimport { cp } from \"./cp/cp.cjs\";\nimport { mv } from \"./mv/mv.cjs\";\nimport { tee } from \"./tee/tee.cjs\";\nimport { tree } from \"./tree/tree.cjs\";\nimport { find } from \"./find/find.cjs\";\nimport { sed } from \"./sed/sed.cjs\";\nimport { awk } from \"./awk/awk.cjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nimport { colon } from \"./colon/colon.cjs\";\nimport { cd } from \"./cd/cd.cjs\";\nimport { tr } from \"./tr/tr.cjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n};\n"
|
|
5
|
+
"import type { Command } from \"../types.cjs\";\n\nexport { echo } from \"./echo/echo.cjs\";\nexport { cat } from \"./cat/cat.cjs\";\nexport { grep } from \"./grep/grep.cjs\";\nexport { wc } from \"./wc/wc.cjs\";\nexport { head } from \"./head/head.cjs\";\nexport { tail } from \"./tail/tail.cjs\";\nexport { sort } from \"./sort/sort.cjs\";\nexport { uniq } from \"./uniq/uniq.cjs\";\nexport { pwd } from \"./pwd/pwd.cjs\";\nexport { ls } from \"./ls/ls.cjs\";\nexport { mkdir } from \"./mkdir/mkdir.cjs\";\nexport { rm } from \"./rm/rm.cjs\";\nexport { test, bracket } from \"./test/test.cjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nexport { touch } from \"./touch/touch.cjs\";\nexport { cp } from \"./cp/cp.cjs\";\nexport { mv } from \"./mv/mv.cjs\";\nexport { tee } from \"./tee/tee.cjs\";\nexport { tree } from \"./tree/tree.cjs\";\nexport { find } from \"./find/find.cjs\";\nexport { sed } from \"./sed/sed.cjs\";\nexport { awk } from \"./awk/awk.cjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nexport { colon } from \"./colon/colon.cjs\";\nexport { cd } from \"./cd/cd.cjs\";\nexport { tr } from \"./tr/tr.cjs\";\nexport { cut } from \"./cut/cut.cjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.cjs\";\nimport { cat } from \"./cat/cat.cjs\";\nimport { grep } from \"./grep/grep.cjs\";\nimport { wc } from \"./wc/wc.cjs\";\nimport { head } from \"./head/head.cjs\";\nimport { tail } from \"./tail/tail.cjs\";\nimport { sort } from \"./sort/sort.cjs\";\nimport { uniq } from \"./uniq/uniq.cjs\";\nimport { pwd } from \"./pwd/pwd.cjs\";\nimport { ls } from \"./ls/ls.cjs\";\nimport { mkdir } from \"./mkdir/mkdir.cjs\";\nimport { rm } from \"./rm/rm.cjs\";\nimport { test, bracket } from \"./test/test.cjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.cjs\";\nimport { touch } from \"./touch/touch.cjs\";\nimport { cp } from \"./cp/cp.cjs\";\nimport { mv } from \"./mv/mv.cjs\";\nimport { tee } from \"./tee/tee.cjs\";\nimport { tree } from \"./tree/tree.cjs\";\nimport { find } from \"./find/find.cjs\";\nimport { sed } from \"./sed/sed.cjs\";\nimport { awk } from \"./awk/awk.cjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.cjs\";\nimport { colon } from \"./colon/colon.cjs\";\nimport { cd } from \"./cd/cd.cjs\";\nimport { tr } from \"./tr/tr.cjs\";\nimport { cut } from \"./cut/cut.cjs\";\n\nexport const builtinCommands: Record<string, Command> = {\n echo,\n cat,\n grep,\n wc,\n head,\n tail,\n sort,\n uniq,\n pwd,\n ls,\n mkdir,\n rm,\n test,\n \"[\": bracket,\n true: trueCmd,\n false: falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n break: breakCmd,\n continue: continueCmd,\n \":\": colon,\n cd,\n tr,\n cut,\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEqB,IAArB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AAGqB,IAArB;AACoB,IAApB;AACqB,IAArB;AACmB,IAAnB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACmB,IAAnB;AACsB,IAAtB;AACmB,IAAnB;AAC8B,IAA9B;AACkC,IAAlC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AACqB,IAArB;AACqB,IAArB;AACoB,IAApB;AACoB,IAApB;AACsC,IAAtC;AACsB,IAAtB;AACmB,IAAnB;AACmB,IAAnB;AACoB,IAApB;AAEO,IAAM,kBAA2C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL;AAAA,EACA;AAAA,EACA;AACF;",
|
|
8
|
+
"debugId": "BFE70ED48B7DB93D64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -94,7 +94,7 @@ var ls = async (ctx) => {
|
|
|
94
94
|
`);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
} else if (onePerLine) {
|
|
97
|
+
} else if (onePerLine || !ctx.stdout.isTTY) {
|
|
98
98
|
for (const entry of entries) {
|
|
99
99
|
await ctx.stdout.writeText(entry + `
|
|
100
100
|
`);
|
|
@@ -139,4 +139,4 @@ var ls = async (ctx) => {
|
|
|
139
139
|
return 0;
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
-
//# debugId=
|
|
142
|
+
//# debugId=74ED3BA04DAC332A64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/ls/ls.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n recursive: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false };\n\nconst handler = (flags: LsFlags, flag: FlagDefinition) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"l\") flags.long = true;\n if (flag.short === \"1\") flags.onePerLine = true;\n if (flag.short === \"R\") flags.recursive = true;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const ls: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\n let needsBlankLine = false;\n\n const listDir = async (dirPath: string, displayPath: string, showHeader: boolean) => {\n if (needsBlankLine) await ctx.stdout.writeText(\"\\n\");\n needsBlankLine = true;\n\n if (showHeader) {\n await ctx.stdout.writeText(`${displayPath}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(dirPath);\n\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n entries.sort();\n\n if (longFormat) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = String(entryStat.size).padStart(8);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine) {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n } else {\n if (entries.length > 0) {\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\n }\n\n if (recursive) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n if (entryStat.isDirectory()) {\n const subDisplay = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await listDir(entryPath, subDisplay, true);\n }\n } catch {\n // skip entries we can't stat\n }\n }\n }\n };\n\n for (let i = 0; i < paths.length; i++) {\n const pathArg = paths[i]!;\n const path = ctx.fs.resolve(ctx.cwd, pathArg);\n\n try {\n const stat = await ctx.fs.stat(path);\n\n if (stat.isFile()) {\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n const showHeader = recursive || paths.length > 1;\n await listDir(path, pathArg, showHeader);\n } catch (err) {\n await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n"
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n recursive: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false };\n\nconst handler = (flags: LsFlags, flag: FlagDefinition) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"l\") flags.long = true;\n if (flag.short === \"1\") flags.onePerLine = true;\n if (flag.short === \"R\") flags.recursive = true;\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const ls: Command = async (ctx) => {\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\n let needsBlankLine = false;\n\n const listDir = async (dirPath: string, displayPath: string, showHeader: boolean) => {\n if (needsBlankLine) await ctx.stdout.writeText(\"\\n\");\n needsBlankLine = true;\n\n if (showHeader) {\n await ctx.stdout.writeText(`${displayPath}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(dirPath);\n\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n entries.sort();\n\n if (longFormat) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = String(entryStat.size).padStart(8);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine || !ctx.stdout.isTTY) {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n } else {\n if (entries.length > 0) {\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\n }\n\n if (recursive) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n if (entryStat.isDirectory()) {\n const subDisplay = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await listDir(entryPath, subDisplay, true);\n }\n } catch {\n // skip entries we can't stat\n }\n }\n }\n };\n\n for (let i = 0; i < paths.length; i++) {\n const pathArg = paths[i]!;\n const path = ctx.fs.resolve(ctx.cwd, pathArg);\n\n try {\n const stat = await ctx.fs.stat(path);\n\n if (stat.isFile()) {\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n const showHeader = recursive || paths.length > 1;\n await listDir(path, pathArg, showHeader);\n } catch (err) {\n await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;AASA,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,IACL,EAAE,OAAO,KAAK,MAAM,MAAM;AAAA,IAC1B,EAAE,OAAO,IAAI;AAAA,IACb,EAAE,OAAO,IAAI;AAAA,IACb,EAAE,OAAO,IAAI;AAAA,EACf;AAAA,EACA,OAAO;AACT;AAEA,IAAM,WAAoB,EAAE,KAAK,OAAO,MAAM,OAAO,YAAY,OAAO,WAAW,MAAM;AAEzF,IAAM,UAAU,CAAC,OAAgB,SAAyB;AAAA,EACxD,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,MAAM;AAAA,EACpC,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,OAAO;AAAA,EACrC,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,aAAa;AAAA,EAC3C,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,YAAY;AAAA;AAG5C,IAAM,SAAS,oCAAiB,MAAM,UAAU,OAAO;AAEhD,IAAM,KAAc,OAAO,QAAQ;AAAA,EACxC,MAAM,SAAS,OAAO,MAAM,IAAI,IAAI;AAAA,EAEpC,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM,OAAO,WAAW,OAAO,OAAO,IAAI,MAAM;AAAA,IAChD,OAAO;AAAA,EACT;AAAA,EAEA,QAAQ,KAAK,SAAS,MAAM,YAAY,YAAY,cAAc,OAAO;AAAA,EACzE,MAAM,QAAQ,OAAO,KAAK,WAAW,IAAI,CAAC,GAAG,IAAI,OAAO;AAAA,EACxD,IAAI,iBAAiB;AAAA,EAErB,MAAM,UAAU,OAAO,SAAiB,aAAqB,eAAwB;AAAA,IACnF,IAAI;AAAA,MAAgB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAI;AAAA,IACnD,iBAAiB;AAAA,IAEjB,IAAI,YAAY;AAAA,MACd,MAAM,IAAI,OAAO,UAAU,GAAG;AAAA,CAAgB;AAAA,IAChD;AAAA,IAEA,IAAI,UAAU,MAAM,IAAI,GAAG,QAAQ,OAAO;AAAA,IAE1C,IAAI,CAAC,SAAS;AAAA,MACZ,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC;AAAA,IACpD;AAAA,IAEA,QAAQ,KAAK;AAAA,IAEb,IAAI,YAAY;AAAA,MACd,WAAW,SAAS,SAAS;AAAA,QAC3B,MAAM,YAAY,IAAI,GAAG,QAAQ,SAAS,KAAK;AAAA,QAC/C,IAAI;AAAA,UACF,MAAM,YAAY,MAAM,IAAI,GAAG,KAAK,SAAS;AAAA,UAC7C,MAAM,OAAO,UAAU,YAAY,IAAI,MAAM;AAAA,UAC7C,MAAM,QAAQ;AAAA,UACd,MAAM,OAAO,OAAO,UAAU,IAAI,EAAE,SAAS,CAAC;AAAA,UAC9C,MAAM,OAAO,UAAU,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE;AAAA,UACtD,MAAM,IAAI,OAAO,UAAU,GAAG,OAAO,SAAS,QAAQ,QAAQ;AAAA,CAAS;AAAA,UACvE,MAAM;AAAA,UACN,MAAM,IAAI,OAAO,UAAU,cAAc;AAAA,CAAS;AAAA;AAAA,MAEtD;AAAA,IACF,EAAO,SAAI,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "74ED3BA04DAC332A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -61,19 +61,21 @@ class Interpreter {
|
|
|
61
61
|
commands;
|
|
62
62
|
redirectObjects;
|
|
63
63
|
loopDepth = 0;
|
|
64
|
+
isTTY;
|
|
64
65
|
constructor(options) {
|
|
65
66
|
this.fs = options.fs;
|
|
66
67
|
this.cwd = options.cwd;
|
|
67
68
|
this.env = { ...options.env };
|
|
68
69
|
this.commands = options.commands;
|
|
69
70
|
this.redirectObjects = options.redirectObjects ?? {};
|
|
71
|
+
this.isTTY = options.isTTY ?? false;
|
|
70
72
|
}
|
|
71
73
|
getLoopDepth() {
|
|
72
74
|
return this.loopDepth;
|
|
73
75
|
}
|
|
74
76
|
async execute(ast) {
|
|
75
|
-
const stdout = import_stdout.createStdout();
|
|
76
|
-
const stderr = import_stdout.createStderr();
|
|
77
|
+
const stdout = import_stdout.createStdout(this.isTTY);
|
|
78
|
+
const stderr = import_stdout.createStderr(this.isTTY);
|
|
77
79
|
const exitCode = await this.executeNode(ast, null, stdout, stderr);
|
|
78
80
|
stdout.close();
|
|
79
81
|
stderr.close();
|
|
@@ -810,4 +812,4 @@ class Interpreter {
|
|
|
810
812
|
}
|
|
811
813
|
}
|
|
812
814
|
|
|
813
|
-
//# debugId=
|
|
815
|
+
//# debugId=7B263C6315A30CB564756E2164756E21
|