shell-dsl 0.0.36 → 0.0.38
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 -3
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/echo/echo.cjs +29 -23
- package/dist/cjs/src/commands/echo/echo.cjs.map +3 -3
- package/dist/cjs/src/commands/find/find.cjs +27 -11
- package/dist/cjs/src/commands/find/find.cjs.map +3 -3
- package/dist/cjs/src/commands/index.cjs +6 -2
- package/dist/cjs/src/commands/index.cjs.map +3 -3
- package/dist/cjs/src/commands/od/od.cjs +274 -0
- package/dist/cjs/src/commands/od/od.cjs.map +10 -0
- package/dist/cjs/src/commands/tree/tree.cjs +15 -8
- package/dist/cjs/src/commands/tree/tree.cjs.map +3 -3
- package/dist/mjs/index.mjs +4 -2
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/echo/echo.mjs +29 -23
- package/dist/mjs/src/commands/echo/echo.mjs.map +3 -3
- package/dist/mjs/src/commands/find/find.mjs +27 -11
- package/dist/mjs/src/commands/find/find.mjs.map +3 -3
- package/dist/mjs/src/commands/index.mjs +6 -2
- package/dist/mjs/src/commands/index.mjs.map +3 -3
- package/dist/mjs/src/commands/od/od.mjs +234 -0
- package/dist/mjs/src/commands/od/od.mjs.map +10 -0
- package/dist/mjs/src/commands/tree/tree.mjs +15 -8
- package/dist/mjs/src/commands/tree/tree.mjs.map +3 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/commands/od/od.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/commands/od/od.ts
|
|
40
|
+
var exports_od = {};
|
|
41
|
+
__export(exports_od, {
|
|
42
|
+
od: () => od
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(exports_od);
|
|
45
|
+
var import_flag_parser = require("../../utils/flag-parser.cjs");
|
|
46
|
+
var ADDRESS_WIDTH = 7;
|
|
47
|
+
var ADDRESS_SEPARATOR = " ";
|
|
48
|
+
var NO_ADDRESS_PREFIX = " ".repeat(ADDRESS_WIDTH + ADDRESS_SEPARATOR.length);
|
|
49
|
+
var LINE_BYTES = 16;
|
|
50
|
+
var spec = {
|
|
51
|
+
name: "od",
|
|
52
|
+
flags: [
|
|
53
|
+
{ short: "A", takesValue: true },
|
|
54
|
+
{ short: "b" },
|
|
55
|
+
{ short: "c" },
|
|
56
|
+
{ short: "j", takesValue: true },
|
|
57
|
+
{ short: "N", takesValue: true },
|
|
58
|
+
{ short: "o" },
|
|
59
|
+
{ short: "t", takesValue: true },
|
|
60
|
+
{ short: "v" },
|
|
61
|
+
{ short: "x" }
|
|
62
|
+
],
|
|
63
|
+
usage: "od [-bcovx] [-A radix] [-j skip] [-N count] [-t type] [file ...]"
|
|
64
|
+
};
|
|
65
|
+
var defaults = {
|
|
66
|
+
addressRadix: "o",
|
|
67
|
+
format: null,
|
|
68
|
+
formatConflict: null,
|
|
69
|
+
invalidType: null,
|
|
70
|
+
verbose: false,
|
|
71
|
+
skip: null,
|
|
72
|
+
count: null
|
|
73
|
+
};
|
|
74
|
+
function selectFormat(flags, format, source) {
|
|
75
|
+
if (flags.format === null) {
|
|
76
|
+
flags.format = format;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
flags.formatConflict = source;
|
|
80
|
+
}
|
|
81
|
+
function isOutputFormat(value) {
|
|
82
|
+
return value === "x1" || value === "x2" || value === "o1" || value === "o2" || value === "c";
|
|
83
|
+
}
|
|
84
|
+
var parser = import_flag_parser.createFlagParser(spec, defaults, (flags, flag, value) => {
|
|
85
|
+
switch (flag.short) {
|
|
86
|
+
case "A":
|
|
87
|
+
flags.addressRadix = value ?? "o";
|
|
88
|
+
break;
|
|
89
|
+
case "b":
|
|
90
|
+
selectFormat(flags, "o1", "-b");
|
|
91
|
+
break;
|
|
92
|
+
case "c":
|
|
93
|
+
selectFormat(flags, "c", "-c");
|
|
94
|
+
break;
|
|
95
|
+
case "j":
|
|
96
|
+
flags.skip = value ?? null;
|
|
97
|
+
break;
|
|
98
|
+
case "N":
|
|
99
|
+
flags.count = value ?? null;
|
|
100
|
+
break;
|
|
101
|
+
case "o":
|
|
102
|
+
selectFormat(flags, "o2", "-o");
|
|
103
|
+
break;
|
|
104
|
+
case "t":
|
|
105
|
+
if (value && isOutputFormat(value)) {
|
|
106
|
+
selectFormat(flags, value, "-t");
|
|
107
|
+
} else if (value) {
|
|
108
|
+
flags.invalidType = value;
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
case "v":
|
|
112
|
+
flags.verbose = true;
|
|
113
|
+
break;
|
|
114
|
+
case "x":
|
|
115
|
+
selectFormat(flags, "x2", "-x");
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
function isAddressRadix(value) {
|
|
120
|
+
return value === "o" || value === "d" || value === "x" || value === "n";
|
|
121
|
+
}
|
|
122
|
+
function parseNonNegativeInteger(value, label) {
|
|
123
|
+
if (!/^\d+$/.test(value)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const parsed = Number(value);
|
|
127
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
function formatAddress(offset, radix) {
|
|
133
|
+
const base = radix === "o" ? 8 : radix === "d" ? 10 : 16;
|
|
134
|
+
return offset.toString(base).padStart(ADDRESS_WIDTH, "0");
|
|
135
|
+
}
|
|
136
|
+
function formatCharacter(byte) {
|
|
137
|
+
let token;
|
|
138
|
+
if (byte === 0) {
|
|
139
|
+
token = "\\0";
|
|
140
|
+
} else if (byte === 9) {
|
|
141
|
+
token = "\\t";
|
|
142
|
+
} else if (byte === 10) {
|
|
143
|
+
token = "\\n";
|
|
144
|
+
} else if (byte >= 32 && byte <= 126) {
|
|
145
|
+
token = String.fromCharCode(byte);
|
|
146
|
+
} else {
|
|
147
|
+
token = `\\${byte.toString(8).padStart(3, "0")}`;
|
|
148
|
+
}
|
|
149
|
+
return token.length < 3 ? token.padStart(3, " ") : token;
|
|
150
|
+
}
|
|
151
|
+
function formatWord(bytes, index, radix) {
|
|
152
|
+
const low = bytes[index] ?? 0;
|
|
153
|
+
const high = bytes[index + 1] ?? 0;
|
|
154
|
+
const value = low | high << 8;
|
|
155
|
+
const base = radix === "hex" ? 16 : 8;
|
|
156
|
+
const width = radix === "hex" ? 4 : 6;
|
|
157
|
+
return value.toString(base).padStart(width, "0");
|
|
158
|
+
}
|
|
159
|
+
function formatRow(bytes, format) {
|
|
160
|
+
const values = [];
|
|
161
|
+
if (format === "x1") {
|
|
162
|
+
for (const byte of bytes) {
|
|
163
|
+
values.push(byte.toString(16).padStart(2, "0"));
|
|
164
|
+
}
|
|
165
|
+
} else if (format === "o1") {
|
|
166
|
+
for (const byte of bytes) {
|
|
167
|
+
values.push(byte.toString(8).padStart(3, "0"));
|
|
168
|
+
}
|
|
169
|
+
} else if (format === "c") {
|
|
170
|
+
for (const byte of bytes) {
|
|
171
|
+
values.push(formatCharacter(byte));
|
|
172
|
+
}
|
|
173
|
+
} else if (format === "x2") {
|
|
174
|
+
for (let i = 0;i < bytes.length; i += 2) {
|
|
175
|
+
values.push(formatWord(bytes, i, "hex"));
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
for (let i = 0;i < bytes.length; i += 2) {
|
|
179
|
+
values.push(formatWord(bytes, i, "octal"));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return values.join(" ");
|
|
183
|
+
}
|
|
184
|
+
async function readInput(ctx, files) {
|
|
185
|
+
if (files.length === 0) {
|
|
186
|
+
return await ctx.stdin.buffer();
|
|
187
|
+
}
|
|
188
|
+
const chunks = [];
|
|
189
|
+
for (const file of files) {
|
|
190
|
+
try {
|
|
191
|
+
const path = ctx.fs.resolve(ctx.cwd, file);
|
|
192
|
+
chunks.push(await ctx.fs.readFile(path));
|
|
193
|
+
} catch {
|
|
194
|
+
await ctx.stderr.writeText(`od: ${file}: No such file or directory
|
|
195
|
+
`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return Buffer.concat(chunks);
|
|
200
|
+
}
|
|
201
|
+
var od = async (ctx) => {
|
|
202
|
+
const result = parser.parse(ctx.args);
|
|
203
|
+
if (result.error) {
|
|
204
|
+
await parser.writeError(result.error, ctx.stderr);
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
const { addressRadix, formatConflict, invalidType, skip, count, verbose } = result.flags;
|
|
208
|
+
if (!isAddressRadix(addressRadix)) {
|
|
209
|
+
await ctx.stderr.writeText(`od: invalid address radix '${addressRadix}'
|
|
210
|
+
`);
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
if (invalidType !== null) {
|
|
214
|
+
await ctx.stderr.writeText(`od: invalid type string '${invalidType}'
|
|
215
|
+
`);
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
if (formatConflict !== null) {
|
|
219
|
+
await ctx.stderr.writeText(`od: multiple output formats are not supported
|
|
220
|
+
`);
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
const skipBytes = skip === null ? 0 : parseNonNegativeInteger(skip, "skip");
|
|
224
|
+
if (skipBytes === null) {
|
|
225
|
+
await ctx.stderr.writeText(`od: invalid skip '${skip}'
|
|
226
|
+
`);
|
|
227
|
+
return 1;
|
|
228
|
+
}
|
|
229
|
+
const countBytes = count === null ? null : parseNonNegativeInteger(count, "count");
|
|
230
|
+
if (count !== null && countBytes === null) {
|
|
231
|
+
await ctx.stderr.writeText(`od: invalid byte count '${count}'
|
|
232
|
+
`);
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
const input = await readInput(ctx, result.args);
|
|
236
|
+
if (input === null) {
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
const start = Math.min(skipBytes, input.length);
|
|
240
|
+
const sliced = countBytes === null ? input.subarray(start) : input.subarray(start, Math.min(start + countBytes, input.length));
|
|
241
|
+
if (sliced.length === 0) {
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
const format = result.flags.format ?? "o2";
|
|
245
|
+
let previousRow = null;
|
|
246
|
+
let emittedSqueezeMarker = false;
|
|
247
|
+
let offset = start;
|
|
248
|
+
for (let i = 0;i < sliced.length; i += LINE_BYTES) {
|
|
249
|
+
const rowBytes = sliced.subarray(i, Math.min(i + LINE_BYTES, sliced.length));
|
|
250
|
+
const row = formatRow(rowBytes, format);
|
|
251
|
+
if (!verbose && row === previousRow) {
|
|
252
|
+
if (!emittedSqueezeMarker) {
|
|
253
|
+
await ctx.stdout.writeText(`*
|
|
254
|
+
`);
|
|
255
|
+
emittedSqueezeMarker = true;
|
|
256
|
+
}
|
|
257
|
+
offset += rowBytes.length;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
previousRow = row;
|
|
261
|
+
emittedSqueezeMarker = false;
|
|
262
|
+
const prefix = addressRadix === "n" ? NO_ADDRESS_PREFIX : `${formatAddress(offset, addressRadix)}${ADDRESS_SEPARATOR}`;
|
|
263
|
+
await ctx.stdout.writeText(`${prefix}${row}
|
|
264
|
+
`);
|
|
265
|
+
offset += rowBytes.length;
|
|
266
|
+
}
|
|
267
|
+
if (addressRadix !== "n") {
|
|
268
|
+
await ctx.stdout.writeText(`${formatAddress(offset, addressRadix)}
|
|
269
|
+
`);
|
|
270
|
+
}
|
|
271
|
+
return 0;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
//# debugId=3DFF62CF5B2C215464756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/commands/od/od.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ntype AddressRadix = \"o\" | \"d\" | \"x\" | \"n\";\ntype OutputFormat = \"x1\" | \"x2\" | \"o1\" | \"o2\" | \"c\";\n\ninterface OdFlags {\n addressRadix: string;\n format: OutputFormat | null;\n formatConflict: string | null;\n invalidType: string | null;\n verbose: boolean;\n skip: string | null;\n count: string | null;\n}\n\nconst ADDRESS_WIDTH = 7;\nconst ADDRESS_SEPARATOR = \" \";\nconst NO_ADDRESS_PREFIX = \" \".repeat(ADDRESS_WIDTH + ADDRESS_SEPARATOR.length);\nconst LINE_BYTES = 16;\n\nconst spec = {\n name: \"od\",\n flags: [\n { short: \"A\", takesValue: true },\n { short: \"b\" },\n { short: \"c\" },\n { short: \"j\", takesValue: true },\n { short: \"N\", takesValue: true },\n { short: \"o\" },\n { short: \"t\", takesValue: true },\n { short: \"v\" },\n { short: \"x\" },\n ] as FlagDefinition[],\n usage: \"od [-bcovx] [-A radix] [-j skip] [-N count] [-t type] [file ...]\",\n};\n\nconst defaults: OdFlags = {\n addressRadix: \"o\",\n format: null,\n formatConflict: null,\n invalidType: null,\n verbose: false,\n skip: null,\n count: null,\n};\n\nfunction selectFormat(flags: OdFlags, format: OutputFormat, source: string): void {\n if (flags.format === null) {\n flags.format = format;\n return;\n }\n\n flags.formatConflict = source;\n}\n\nfunction isOutputFormat(value: string): value is OutputFormat {\n return value === \"x1\" || value === \"x2\" || value === \"o1\" || value === \"o2\" || value === \"c\";\n}\n\nconst parser = createFlagParser(spec, defaults, (flags, flag, value) => {\n switch (flag.short) {\n case \"A\":\n flags.addressRadix = value ?? \"o\";\n break;\n case \"b\":\n selectFormat(flags, \"o1\", \"-b\");\n break;\n case \"c\":\n selectFormat(flags, \"c\", \"-c\");\n break;\n case \"j\":\n flags.skip = value ?? null;\n break;\n case \"N\":\n flags.count = value ?? null;\n break;\n case \"o\":\n selectFormat(flags, \"o2\", \"-o\");\n break;\n case \"t\":\n if (value && isOutputFormat(value)) {\n selectFormat(flags, value, \"-t\");\n } else if (value) {\n flags.invalidType = value;\n }\n break;\n case \"v\":\n flags.verbose = true;\n break;\n case \"x\":\n selectFormat(flags, \"x2\", \"-x\");\n break;\n }\n});\n\nfunction isAddressRadix(value: string): value is AddressRadix {\n return value === \"o\" || value === \"d\" || value === \"x\" || value === \"n\";\n}\n\nfunction parseNonNegativeInteger(value: string, label: \"skip\" | \"count\"): number | null {\n if (!/^\\d+$/.test(value)) {\n return null;\n }\n\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed)) {\n return null;\n }\n\n return parsed;\n}\n\nfunction formatAddress(offset: number, radix: Exclude<AddressRadix, \"n\">): string {\n const base = radix === \"o\" ? 8 : radix === \"d\" ? 10 : 16;\n return offset.toString(base).padStart(ADDRESS_WIDTH, \"0\");\n}\n\nfunction formatCharacter(byte: number): string {\n let token: string;\n\n if (byte === 0) {\n token = \"\\\\0\";\n } else if (byte === 9) {\n token = \"\\\\t\";\n } else if (byte === 10) {\n token = \"\\\\n\";\n } else if (byte >= 32 && byte <= 126) {\n token = String.fromCharCode(byte);\n } else {\n token = `\\\\${byte.toString(8).padStart(3, \"0\")}`;\n }\n\n return token.length < 3 ? token.padStart(3, \" \") : token;\n}\n\nfunction formatWord(bytes: Uint8Array, index: number, radix: \"hex\" | \"octal\"): string {\n const low = bytes[index] ?? 0;\n const high = bytes[index + 1] ?? 0;\n const value = low | (high << 8);\n const base = radix === \"hex\" ? 16 : 8;\n const width = radix === \"hex\" ? 4 : 6;\n return value.toString(base).padStart(width, \"0\");\n}\n\nfunction formatRow(bytes: Uint8Array, format: OutputFormat): string {\n const values: string[] = [];\n\n if (format === \"x1\") {\n for (const byte of bytes) {\n values.push(byte.toString(16).padStart(2, \"0\"));\n }\n } else if (format === \"o1\") {\n for (const byte of bytes) {\n values.push(byte.toString(8).padStart(3, \"0\"));\n }\n } else if (format === \"c\") {\n for (const byte of bytes) {\n values.push(formatCharacter(byte));\n }\n } else if (format === \"x2\") {\n for (let i = 0; i < bytes.length; i += 2) {\n values.push(formatWord(bytes, i, \"hex\"));\n }\n } else {\n for (let i = 0; i < bytes.length; i += 2) {\n values.push(formatWord(bytes, i, \"octal\"));\n }\n }\n\n return values.join(\" \");\n}\n\nasync function readInput(ctx: Parameters<Command>[0], files: string[]): Promise<Buffer | null> {\n if (files.length === 0) {\n return await ctx.stdin.buffer();\n }\n\n const chunks: Buffer[] = [];\n\n for (const file of files) {\n try {\n const path = ctx.fs.resolve(ctx.cwd, file);\n chunks.push(await ctx.fs.readFile(path));\n } catch {\n await ctx.stderr.writeText(`od: ${file}: No such file or directory\\n`);\n return null;\n }\n }\n\n return Buffer.concat(chunks);\n}\n\nexport const od: 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 { addressRadix, formatConflict, invalidType, skip, count, verbose } = result.flags;\n\n if (!isAddressRadix(addressRadix)) {\n await ctx.stderr.writeText(`od: invalid address radix '${addressRadix}'\\n`);\n return 1;\n }\n\n if (invalidType !== null) {\n await ctx.stderr.writeText(`od: invalid type string '${invalidType}'\\n`);\n return 1;\n }\n\n if (formatConflict !== null) {\n await ctx.stderr.writeText(\"od: multiple output formats are not supported\\n\");\n return 1;\n }\n\n const skipBytes = skip === null ? 0 : parseNonNegativeInteger(skip, \"skip\");\n if (skipBytes === null) {\n await ctx.stderr.writeText(`od: invalid skip '${skip}'\\n`);\n return 1;\n }\n\n const countBytes = count === null ? null : parseNonNegativeInteger(count, \"count\");\n if (count !== null && countBytes === null) {\n await ctx.stderr.writeText(`od: invalid byte count '${count}'\\n`);\n return 1;\n }\n\n const input = await readInput(ctx, result.args);\n if (input === null) {\n return 1;\n }\n\n const start = Math.min(skipBytes, input.length);\n const sliced = countBytes === null\n ? input.subarray(start)\n : input.subarray(start, Math.min(start + countBytes, input.length));\n\n if (sliced.length === 0) {\n return 0;\n }\n\n const format = result.flags.format ?? \"o2\";\n\n let previousRow: string | null = null;\n let emittedSqueezeMarker = false;\n let offset = start;\n\n for (let i = 0; i < sliced.length; i += LINE_BYTES) {\n const rowBytes = sliced.subarray(i, Math.min(i + LINE_BYTES, sliced.length));\n const row = formatRow(rowBytes, format);\n\n if (!verbose && row === previousRow) {\n if (!emittedSqueezeMarker) {\n await ctx.stdout.writeText(\"*\\n\");\n emittedSqueezeMarker = true;\n }\n offset += rowBytes.length;\n continue;\n }\n\n previousRow = row;\n emittedSqueezeMarker = false;\n\n const prefix = addressRadix === \"n\"\n ? NO_ADDRESS_PREFIX\n : `${formatAddress(offset, addressRadix)}${ADDRESS_SEPARATOR}`;\n\n await ctx.stdout.writeText(`${prefix}${row}\\n`);\n offset += rowBytes.length;\n }\n\n if (addressRadix !== \"n\") {\n await ctx.stdout.writeText(`${formatAddress(offset, addressRadix)}\\n`);\n }\n\n return 0;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "3DFF62CF5B2C215464756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -52,9 +52,10 @@ var spec = {
|
|
|
52
52
|
{ short: "L", takesValue: true },
|
|
53
53
|
{ short: "I", takesValue: true },
|
|
54
54
|
{ long: "dirsfirst" },
|
|
55
|
-
{ long: "prune" }
|
|
55
|
+
{ long: "prune" },
|
|
56
|
+
{ long: "noreport" }
|
|
56
57
|
],
|
|
57
|
-
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]"
|
|
58
|
+
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [--noreport] [directory ...]"
|
|
58
59
|
};
|
|
59
60
|
var defaults = {
|
|
60
61
|
all: false,
|
|
@@ -62,6 +63,7 @@ var defaults = {
|
|
|
62
63
|
maxDepth: Infinity,
|
|
63
64
|
dirsfirst: true,
|
|
64
65
|
prune: false,
|
|
66
|
+
noReport: false,
|
|
65
67
|
ignorePatterns: []
|
|
66
68
|
};
|
|
67
69
|
var handlerResult = {};
|
|
@@ -74,6 +76,8 @@ var handler = (flags, flag, value) => {
|
|
|
74
76
|
flags.dirsfirst = true;
|
|
75
77
|
if (flag.long === "prune")
|
|
76
78
|
flags.prune = true;
|
|
79
|
+
if (flag.long === "noreport")
|
|
80
|
+
flags.noReport = true;
|
|
77
81
|
if (flag.short === "I" && value) {
|
|
78
82
|
if (flags.ignorePatterns === defaults.ignorePatterns) {
|
|
79
83
|
flags.ignorePatterns = [];
|
|
@@ -103,7 +107,7 @@ var tree = async (ctx) => {
|
|
|
103
107
|
await ctx.stderr.writeText(handlerResult.error);
|
|
104
108
|
return 1;
|
|
105
109
|
}
|
|
106
|
-
const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;
|
|
110
|
+
const { all: showAll, directoriesOnly, maxDepth, prune, noReport, ignorePatterns } = result.flags;
|
|
107
111
|
const targetPath = result.args[0] ?? ".";
|
|
108
112
|
if (maxDepth < 1) {
|
|
109
113
|
await ctx.stderr.writeText(`tree: Invalid level, must be greater than 0
|
|
@@ -120,7 +124,8 @@ var tree = async (ctx) => {
|
|
|
120
124
|
return 1;
|
|
121
125
|
}
|
|
122
126
|
if (stat.isFile()) {
|
|
123
|
-
await ctx.stdout.writeText(targetPath + `
|
|
127
|
+
await ctx.stdout.writeText(noReport ? targetPath + `
|
|
128
|
+
` : targetPath + `
|
|
124
129
|
|
|
125
130
|
0 directories, 1 file
|
|
126
131
|
`);
|
|
@@ -208,12 +213,14 @@ var tree = async (ctx) => {
|
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
await printTree(resolvedPath, "", 1);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
216
|
+
if (!noReport) {
|
|
217
|
+
const dirWord = dirCount === 1 ? "directory" : "directories";
|
|
218
|
+
const fileWord = fileCount === 1 ? "file" : "files";
|
|
219
|
+
await ctx.stdout.writeText(`
|
|
214
220
|
${dirCount} ${dirWord}, ${fileCount} ${fileWord}
|
|
215
221
|
`);
|
|
222
|
+
}
|
|
216
223
|
return 0;
|
|
217
224
|
};
|
|
218
225
|
|
|
219
|
-
//# debugId=
|
|
226
|
+
//# debugId=268A831CCE946C4064756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/tree/tree.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\nimport { matchGlob } from \"../../utils/match-glob.cjs\";\n\ninterface TreeFlags {\n all: boolean;\n directoriesOnly: boolean;\n maxDepth: number;\n dirsfirst: boolean;\n prune: boolean;\n ignorePatterns: string[];\n}\n\nconst spec = {\n name: \"tree\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"d\" },\n { short: \"L\", takesValue: true },\n { short: \"I\", takesValue: true },\n { long: \"dirsfirst\" },\n { long: \"prune\" },\n ] as FlagDefinition[],\n usage: \"tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]\",\n};\n\nconst defaults: TreeFlags = {\n all: false,\n directoriesOnly: false,\n maxDepth: Infinity,\n dirsfirst: true,\n prune: false,\n ignorePatterns: [],\n};\n\ninterface HandlerResult {\n error?: string;\n}\n\nlet handlerResult: HandlerResult = {};\n\nconst handler = (flags: TreeFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"d\") flags.directoriesOnly = true;\n if (flag.long === \"dirsfirst\") flags.dirsfirst = true;\n if (flag.long === \"prune\") flags.prune = true;\n if (flag.short === \"I\" && value) {\n if (flags.ignorePatterns === defaults.ignorePatterns) {\n flags.ignorePatterns = [];\n }\n flags.ignorePatterns.push(...value.split(\"|\"));\n }\n if (flag.short === \"L\" && value) {\n const depth = parseInt(value, 10);\n if (isNaN(depth) || !/^\\d+$/.test(value)) {\n handlerResult.error = `tree: -L option requires a numeric argument\\nusage: ${spec.usage}\\n`;\n } else {\n flags.maxDepth = depth;\n }\n }\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const tree: Command = async (ctx) => {\n // Reset handler result for each invocation\n handlerResult = {};\n\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 if (handlerResult.error) {\n await ctx.stderr.writeText(handlerResult.error);\n return 1;\n }\n\n const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;\n const targetPath = result.args[0] ?? \".\";\n\n // Validate maxDepth\n if (maxDepth < 1) {\n await ctx.stderr.writeText(\"tree: Invalid level, must be greater than 0\\n\");\n return 1;\n }\n\n const resolvedPath = ctx.fs.resolve(ctx.cwd, targetPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedPath);\n } catch {\n await ctx.stderr.writeText(`tree: ${targetPath}: No such file or directory\\n`);\n return 1;\n }\n\n // If it's a file, just print the filename\n if (stat.isFile()) {\n await ctx.stdout.writeText(targetPath + \"\\n\\n0 directories, 1 file\\n\");\n return 0;\n }\n\n let dirCount = 0;\n let fileCount = 0;\n const entriesCache = new Map<string, { name: string; path: string; isDir: boolean }[]>();\n const visibleContentCache = new Map<string, boolean>();\n\n // Print root\n await ctx.stdout.writeText(targetPath + \"\\n\");\n\n async function getEntries(path: string): Promise<{ name: string; path: string; isDir: boolean }[]> {\n const cached = entriesCache.get(path);\n if (cached) return cached;\n\n let entries = await ctx.fs.readdir(path);\n\n // Filter hidden files unless -a\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n // Filter by -I ignore patterns\n if (ignorePatterns.length > 0) {\n entries = entries.filter((e) => !ignorePatterns.some((p) => matchGlob(p, e)));\n }\n\n // Sort entries\n entries.sort();\n\n const resolvedEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const name of entries) {\n const entryPath = ctx.fs.resolve(path, name);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });\n } catch {\n // Skip entries we can't stat\n }\n }\n\n entriesCache.set(path, resolvedEntries);\n return resolvedEntries;\n }\n\n async function hasVisibleContent(path: string): Promise<boolean> {\n const cached = visibleContentCache.get(path);\n if (cached !== undefined) return cached;\n\n const entries = await getEntries(path);\n\n for (const entry of entries) {\n if (!entry.isDir) {\n visibleContentCache.set(path, true);\n return true;\n }\n\n if (await hasVisibleContent(entry.path)) {\n visibleContentCache.set(path, true);\n return true;\n }\n }\n\n visibleContentCache.set(path, false);\n return false;\n }\n\n // Recursive function to build tree\n async function printTree(path: string, prefix: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n const entries = await getEntries(path);\n\n // Separate dirs and files, dirs first\n const dirEntries: { name: string; path: string; isDir: boolean }[] = [];\n const fileEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const entry of entries) {\n if (entry.isDir) {\n if (prune && !(await hasVisibleContent(entry.path))) {\n continue;\n }\n dirEntries.push(entry);\n } else {\n fileEntries.push(entry);\n }\n }\n\n // Combine: directories first, then files (unless directoriesOnly)\n const sortedEntries = directoriesOnly\n ? dirEntries\n : [...dirEntries, ...fileEntries];\n\n for (let i = 0; i < sortedEntries.length; i++) {\n const entry = sortedEntries[i]!;\n const isLast = i === sortedEntries.length - 1;\n const connector = isLast ? \"└── \" : \"├── \";\n\n await ctx.stdout.writeText(prefix + connector + entry.name + \"\\n\");\n\n if (entry.isDir) {\n dirCount++;\n if (depth < maxDepth) {\n const newPrefix = prefix + (isLast ? \" \" : \"│ \");\n await printTree(entry.path, newPrefix, depth + 1);\n }\n } else {\n fileCount++;\n }\n }\n }\n\n await printTree(resolvedPath, \"\", 1);\n\n // Print summary\n
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\nimport { matchGlob } from \"../../utils/match-glob.cjs\";\n\ninterface TreeFlags {\n all: boolean;\n directoriesOnly: boolean;\n maxDepth: number;\n dirsfirst: boolean;\n prune: boolean;\n noReport: boolean;\n ignorePatterns: string[];\n}\n\nconst spec = {\n name: \"tree\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"d\" },\n { short: \"L\", takesValue: true },\n { short: \"I\", takesValue: true },\n { long: \"dirsfirst\" },\n { long: \"prune\" },\n { long: \"noreport\" },\n ] as FlagDefinition[],\n usage: \"tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [--noreport] [directory ...]\",\n};\n\nconst defaults: TreeFlags = {\n all: false,\n directoriesOnly: false,\n maxDepth: Infinity,\n dirsfirst: true,\n prune: false,\n noReport: false,\n ignorePatterns: [],\n};\n\ninterface HandlerResult {\n error?: string;\n}\n\nlet handlerResult: HandlerResult = {};\n\nconst handler = (flags: TreeFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"d\") flags.directoriesOnly = true;\n if (flag.long === \"dirsfirst\") flags.dirsfirst = true;\n if (flag.long === \"prune\") flags.prune = true;\n if (flag.long === \"noreport\") flags.noReport = true;\n if (flag.short === \"I\" && value) {\n if (flags.ignorePatterns === defaults.ignorePatterns) {\n flags.ignorePatterns = [];\n }\n flags.ignorePatterns.push(...value.split(\"|\"));\n }\n if (flag.short === \"L\" && value) {\n const depth = parseInt(value, 10);\n if (isNaN(depth) || !/^\\d+$/.test(value)) {\n handlerResult.error = `tree: -L option requires a numeric argument\\nusage: ${spec.usage}\\n`;\n } else {\n flags.maxDepth = depth;\n }\n }\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const tree: Command = async (ctx) => {\n // Reset handler result for each invocation\n handlerResult = {};\n\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 if (handlerResult.error) {\n await ctx.stderr.writeText(handlerResult.error);\n return 1;\n }\n\n const { all: showAll, directoriesOnly, maxDepth, prune, noReport, ignorePatterns } = result.flags;\n const targetPath = result.args[0] ?? \".\";\n\n // Validate maxDepth\n if (maxDepth < 1) {\n await ctx.stderr.writeText(\"tree: Invalid level, must be greater than 0\\n\");\n return 1;\n }\n\n const resolvedPath = ctx.fs.resolve(ctx.cwd, targetPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedPath);\n } catch {\n await ctx.stderr.writeText(`tree: ${targetPath}: No such file or directory\\n`);\n return 1;\n }\n\n // If it's a file, just print the filename\n if (stat.isFile()) {\n await ctx.stdout.writeText(noReport ? targetPath + \"\\n\" : targetPath + \"\\n\\n0 directories, 1 file\\n\");\n return 0;\n }\n\n let dirCount = 0;\n let fileCount = 0;\n const entriesCache = new Map<string, { name: string; path: string; isDir: boolean }[]>();\n const visibleContentCache = new Map<string, boolean>();\n\n // Print root\n await ctx.stdout.writeText(targetPath + \"\\n\");\n\n async function getEntries(path: string): Promise<{ name: string; path: string; isDir: boolean }[]> {\n const cached = entriesCache.get(path);\n if (cached) return cached;\n\n let entries = await ctx.fs.readdir(path);\n\n // Filter hidden files unless -a\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n // Filter by -I ignore patterns\n if (ignorePatterns.length > 0) {\n entries = entries.filter((e) => !ignorePatterns.some((p) => matchGlob(p, e)));\n }\n\n // Sort entries\n entries.sort();\n\n const resolvedEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const name of entries) {\n const entryPath = ctx.fs.resolve(path, name);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });\n } catch {\n // Skip entries we can't stat\n }\n }\n\n entriesCache.set(path, resolvedEntries);\n return resolvedEntries;\n }\n\n async function hasVisibleContent(path: string): Promise<boolean> {\n const cached = visibleContentCache.get(path);\n if (cached !== undefined) return cached;\n\n const entries = await getEntries(path);\n\n for (const entry of entries) {\n if (!entry.isDir) {\n visibleContentCache.set(path, true);\n return true;\n }\n\n if (await hasVisibleContent(entry.path)) {\n visibleContentCache.set(path, true);\n return true;\n }\n }\n\n visibleContentCache.set(path, false);\n return false;\n }\n\n // Recursive function to build tree\n async function printTree(path: string, prefix: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n const entries = await getEntries(path);\n\n // Separate dirs and files, dirs first\n const dirEntries: { name: string; path: string; isDir: boolean }[] = [];\n const fileEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const entry of entries) {\n if (entry.isDir) {\n if (prune && !(await hasVisibleContent(entry.path))) {\n continue;\n }\n dirEntries.push(entry);\n } else {\n fileEntries.push(entry);\n }\n }\n\n // Combine: directories first, then files (unless directoriesOnly)\n const sortedEntries = directoriesOnly\n ? dirEntries\n : [...dirEntries, ...fileEntries];\n\n for (let i = 0; i < sortedEntries.length; i++) {\n const entry = sortedEntries[i]!;\n const isLast = i === sortedEntries.length - 1;\n const connector = isLast ? \"└── \" : \"├── \";\n\n await ctx.stdout.writeText(prefix + connector + entry.name + \"\\n\");\n\n if (entry.isDir) {\n dirCount++;\n if (depth < maxDepth) {\n const newPrefix = prefix + (isLast ? \" \" : \"│ \");\n await printTree(entry.path, newPrefix, depth + 1);\n }\n } else {\n fileCount++;\n }\n }\n }\n\n await printTree(resolvedPath, \"\", 1);\n\n if (!noReport) {\n // Print summary\n const dirWord = dirCount === 1 ? \"directory\" : \"directories\";\n const fileWord = fileCount === 1 ? \"file\" : \"files\";\n await ctx.stdout.writeText(`\\n${dirCount} ${dirWord}, ${fileCount} ${fileWord}\\n`);\n }\n\n return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;AAC0B,IAA1B;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "268A831CCE946C4064756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/index.mjs
CHANGED
|
@@ -27,7 +27,8 @@ import {
|
|
|
27
27
|
sed,
|
|
28
28
|
awk,
|
|
29
29
|
breakCmd,
|
|
30
|
-
continueCmd
|
|
30
|
+
continueCmd,
|
|
31
|
+
od
|
|
31
32
|
} from "./src/commands/index.mjs";
|
|
32
33
|
export {
|
|
33
34
|
wc,
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
sed,
|
|
43
44
|
rm,
|
|
44
45
|
pwd,
|
|
46
|
+
od,
|
|
45
47
|
mv,
|
|
46
48
|
mkdir,
|
|
47
49
|
ls,
|
|
@@ -59,4 +61,4 @@ export {
|
|
|
59
61
|
awk
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
//# debugId=
|
|
64
|
+
//# debugId=0230C6604254204664756E2164756E21
|
package/dist/mjs/index.mjs.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"// Re-export everything from src\nexport * from \"./src/index.mjs\";\n\n// Re-export built-in commands\nexport { builtinCommands } from \"./src/commands/index.mjs\";\nexport {\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 trueCmd,\n falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n breakCmd,\n continueCmd,\n} from \"./src/commands/index.mjs\";\n"
|
|
5
|
+
"// Re-export everything from src\nexport * from \"./src/index.mjs\";\n\n// Re-export built-in commands\nexport { builtinCommands } from \"./src/commands/index.mjs\";\nexport {\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 trueCmd,\n falseCmd,\n touch,\n cp,\n mv,\n tee,\n tree,\n find,\n sed,\n awk,\n breakCmd,\n continueCmd,\n od,\n} from \"./src/commands/index.mjs\";\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AACA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AACA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
8
|
+
"debugId": "0230C6604254204664756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
// src/commands/echo/echo.ts
|
|
2
|
-
import { createFlagParser } from "../../utils/flag-parser.mjs";
|
|
3
2
|
import { expandEscapes } from "../../utils/expand-escapes.mjs";
|
|
4
|
-
var spec = {
|
|
5
|
-
name: "echo",
|
|
6
|
-
flags: [
|
|
7
|
-
{ short: "n" },
|
|
8
|
-
{ short: "e" }
|
|
9
|
-
],
|
|
10
|
-
usage: "echo [-neE] [string ...]",
|
|
11
|
-
stopAfterFirstPositional: true
|
|
12
|
-
};
|
|
13
3
|
var defaults = { noNewline: false, interpretEscapes: false };
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
if (flag.short === "e")
|
|
18
|
-
flags.interpretEscapes = true;
|
|
19
|
-
};
|
|
20
|
-
var parser = createFlagParser(spec, defaults, handler);
|
|
21
|
-
var echo = async (ctx) => {
|
|
22
|
-
const result = parser.parse(ctx.args);
|
|
23
|
-
if (result.error) {
|
|
24
|
-
await parser.writeError(result.error, ctx.stderr);
|
|
25
|
-
return 1;
|
|
4
|
+
function isEchoOption(arg) {
|
|
5
|
+
if (!arg.startsWith("-") || arg === "-") {
|
|
6
|
+
return false;
|
|
26
7
|
}
|
|
8
|
+
for (const char of arg.slice(1)) {
|
|
9
|
+
if (char !== "n" && char !== "e" && char !== "E") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
function parseEchoArgs(args) {
|
|
16
|
+
const flags = { ...defaults };
|
|
17
|
+
let index = 0;
|
|
18
|
+
while (index < args.length && isEchoOption(args[index])) {
|
|
19
|
+
for (const char of args[index].slice(1)) {
|
|
20
|
+
if (char === "n")
|
|
21
|
+
flags.noNewline = true;
|
|
22
|
+
if (char === "e")
|
|
23
|
+
flags.interpretEscapes = true;
|
|
24
|
+
if (char === "E")
|
|
25
|
+
flags.interpretEscapes = false;
|
|
26
|
+
}
|
|
27
|
+
index++;
|
|
28
|
+
}
|
|
29
|
+
return { flags, args: args.slice(index) };
|
|
30
|
+
}
|
|
31
|
+
var echo = async (ctx) => {
|
|
32
|
+
const result = parseEchoArgs(ctx.args);
|
|
27
33
|
let output = result.args.join(" ");
|
|
28
34
|
if (result.flags.interpretEscapes) {
|
|
29
35
|
output = expandEscapes(output);
|
|
@@ -39,4 +45,4 @@ export {
|
|
|
39
45
|
echo
|
|
40
46
|
};
|
|
41
47
|
|
|
42
|
-
//# debugId=
|
|
48
|
+
//# debugId=A414B87957271D3E64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/echo/echo.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.mjs\";\nimport {
|
|
5
|
+
"import type { Command } from \"../../types.mjs\";\nimport { expandEscapes } from \"../../utils/expand-escapes.mjs\";\n\ninterface EchoFlags {\n noNewline: boolean;\n interpretEscapes: boolean;\n}\n\nconst defaults: EchoFlags = { noNewline: false, interpretEscapes: false };\n\nfunction isEchoOption(arg: string): boolean {\n if (!arg.startsWith(\"-\") || arg === \"-\") {\n return false;\n }\n\n for (const char of arg.slice(1)) {\n if (char !== \"n\" && char !== \"e\" && char !== \"E\") {\n return false;\n }\n }\n\n return true;\n}\n\nfunction parseEchoArgs(args: string[]): { flags: EchoFlags; args: string[] } {\n const flags = { ...defaults };\n let index = 0;\n\n // Match common shell echo behavior: only leading -n/-e/-E clusters are\n // treated as options. Anything else, including \"--\" and \"--invalid\", is\n // printed literally.\n while (index < args.length && isEchoOption(args[index]!)) {\n for (const char of args[index]!.slice(1)) {\n if (char === \"n\") flags.noNewline = true;\n if (char === \"e\") flags.interpretEscapes = true;\n if (char === \"E\") flags.interpretEscapes = false;\n }\n index++;\n }\n\n return { flags, args: args.slice(index) };\n}\n\nexport const echo: Command = async (ctx) => {\n const result = parseEchoArgs(ctx.args);\n\n let output = result.args.join(\" \");\n\n if (result.flags.interpretEscapes) {\n output = expandEscapes(output);\n }\n\n if (!result.flags.noNewline) {\n output += \"\\n\";\n }\n\n await ctx.stdout.writeText(output);\n return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AACA;AAOA,IAAM,WAAsB,EAAE,WAAW,OAAO,kBAAkB,MAAM;AAExE,SAAS,YAAY,CAAC,KAAsB;AAAA,EAC1C,IAAI,CAAC,IAAI,WAAW,GAAG,KAAK,QAAQ,KAAK;AAAA,IACvC,OAAO;AAAA,EACT;AAAA,EAEA,WAAW,QAAQ,IAAI,MAAM,CAAC,GAAG;AAAA,IAC/B,IAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAAA,MAChD,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAGT,SAAS,aAAa,CAAC,MAAsD;AAAA,EAC3E,MAAM,QAAQ,KAAK,SAAS;AAAA,EAC5B,IAAI,QAAQ;AAAA,EAKZ,OAAO,QAAQ,KAAK,UAAU,aAAa,KAAK,MAAO,GAAG;AAAA,IACxD,WAAW,QAAQ,KAAK,OAAQ,MAAM,CAAC,GAAG;AAAA,MACxC,IAAI,SAAS;AAAA,QAAK,MAAM,YAAY;AAAA,MACpC,IAAI,SAAS;AAAA,QAAK,MAAM,mBAAmB;AAAA,MAC3C,IAAI,SAAS;AAAA,QAAK,MAAM,mBAAmB;AAAA,IAC7C;AAAA,IACA;AAAA,EACF;AAAA,EAEA,OAAO,EAAE,OAAO,MAAM,KAAK,MAAM,KAAK,EAAE;AAAA;AAGnC,IAAM,OAAgB,OAAO,QAAQ;AAAA,EAC1C,MAAM,SAAS,cAAc,IAAI,IAAI;AAAA,EAErC,IAAI,SAAS,OAAO,KAAK,KAAK,GAAG;AAAA,EAEjC,IAAI,OAAO,MAAM,kBAAkB;AAAA,IACjC,SAAS,cAAc,MAAM;AAAA,EAC/B;AAAA,EAEA,IAAI,CAAC,OAAO,MAAM,WAAW;AAAA,IAC3B,UAAU;AAAA;AAAA,EACZ;AAAA,EAEA,MAAM,IAAI,OAAO,UAAU,MAAM;AAAA,EACjC,OAAO;AAAA;",
|
|
8
|
+
"debugId": "A414B87957271D3E64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|