shell-dsl 0.0.21 → 0.0.22

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 CHANGED
@@ -496,7 +496,7 @@ import { builtinCommands } from "shell-dsl/commands";
496
496
  Or import individually:
497
497
 
498
498
  ```ts
499
- import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "shell-dsl/commands";
499
+ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut } from "shell-dsl/commands";
500
500
  ```
501
501
 
502
502
  | Command | Description |
@@ -521,6 +521,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk } from "s
521
521
  | `find` | Search for files (`-name`, `-iname`, `-type f\|d`, `-maxdepth`, `-mindepth`) |
522
522
  | `sed` | Stream editor (`s///`, `d`, `p`, `-n`, `-e`) |
523
523
  | `awk` | Pattern scanning (`{print $1}`, `-F`, `NF`, `NR`) |
524
+ | `cut` | Select fields/characters (`-f`, `-d`, `-c`, `-b`, `-s`, `--complement`) |
524
525
  | `test` / `[` | File and string tests (`-f`, `-d`, `-e`, `-z`, `-n`, `=`, `!=`) |
525
526
  | `true` | Exit with code 0 |
526
527
  | `false` | Exit with code 1 |
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "type": "commonjs"
5
5
  }
@@ -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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;AAYA,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,IACL,EAAE,OAAO,KAAK,MAAM,SAAS,YAAY,KAAK;AAAA,IAC9C,EAAE,OAAO,KAAK,MAAM,cAAc,YAAY,KAAK;AAAA,IACnD,EAAE,OAAO,KAAK,MAAM,aAAa,YAAY,KAAK;AAAA,IAClD,EAAE,OAAO,KAAK,MAAM,UAAU,YAAY,KAAK;AAAA,IAC/C,EAAE,OAAO,KAAK,MAAM,iBAAiB;AAAA,IACrC,EAAE,MAAM,aAAa;AAAA,IACrB,EAAE,MAAM,oBAAoB,YAAY,KAAK;AAAA,EAC/C;AAAA,EACA,OAAO;AAAA;AAAA;AACT;AAEA,IAAM,WAAqB;AAAA,EACzB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,iBAAiB;AACnB;AAEA,IAAM,UAAU,CAAC,OAAiB,MAAsB,UAAmB;AAAA,EACzE,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,QAAQ,SAAS;AAAA,EAC/C,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,aAAa,SAAS;AAAA,EACpD,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,YAAY,SAAS;AAAA,EACnD,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,SAAS,SAAS;AAAA,EAChD,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,gBAAgB;AAAA,EAC9C,IAAI,KAAK,SAAS;AAAA,IAAc,MAAM,aAAa;AAAA,EACnD,IAAI,KAAK,SAAS;AAAA,IAAoB,MAAM,kBAAkB,SAAS;AAAA;AAGzE,IAAM,SAAS,oCAAiB,MAAM,UAAU,OAAO;AAMvD,SAAS,aAAa,CACpB,SAC2C;AAAA,EAC3C,MAAM,SAA8D,CAAC;AAAA,EAErE,WAAW,QAAQ,QAAQ,MAAM,GAAG,GAAG;AAAA,IACrC,MAAM,UAAU,KAAK,KAAK;AAAA,IAC1B,IAAI,QAAQ,SAAS,GAAG,GAAG;AAAA,MACzB,OAAO,UAAU,UAAU,QAAQ,MAAM,KAAK,CAAC;AAAA,MAC/C,MAAM,QAAQ,aAAa,KAAK,OAAO,SAAS,UAAW,EAAE;AAAA,MAC7D,MAAM,MAAM,WAAW,KAAK,OAAO,SAAS,QAAS,EAAE;AAAA,MACvD,OAAO,KAAK,EAAE,OAAO,IAAI,CAAC;AAAA,IAC5B,EAAO;AAAA,MACL,MAAM,IAAI,SAAS,SAAS,EAAE;AAAA,MAC9B,OAAO,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,CAAC;AAAA;AAAA,EAEpC;AAAA,EAEA,OAAO,CAAC,OAAe,UAA2B;AAAA,IAChD,aAAa,OAAO,SAAS,QAAQ;AAAA,MACnC,MAAM,IAAI,SAAS;AAAA,MACnB,MAAM,IAAI,OAAO;AAAA,MACjB,IAAI,SAAS,KAAK,SAAS;AAAA,QAAG,OAAO;AAAA,IACvC;AAAA,IACA,OAAO;AAAA;AAAA;AAIJ,IAAM,MAAe,OAAO,QAAQ;AAAA,EACzC,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,OAAO,YAAY,QAAQ,WAAW,eAAe,YAAY,oBACvE,OAAO;AAAA,EAGT,MAAM,YAAY,CAAC,OAAO,YAAY,MAAM,EAAE,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE;AAAA,EACxE,IAAI,cAAc,GAAG;AAAA,IACnB,MAAM,IAAI,OAAO,UACf;AAAA,CACF;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,IAAI,YAAY,GAAG;AAAA,IACjB,MAAM,IAAI,OAAO,UACf;AAAA,CACF;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAW,SAAS,cAAc;AAAA,EACxC,MAAM,WAAW,cAAc,OAAO;AAAA,EACtC,MAAM,OAAO,UAAU,OAAO,UAAU,eAAe,OAAO,UAAU;AAAA,EAExE,MAAM,cAAc,OAAO,SAAiB;AAAA,IAC1C,IAAI,SAAS,UAAU;AAAA,MAErB,IAAI,CAAC,KAAK,SAAS,SAAS,GAAG;AAAA,QAC7B,IAAI;AAAA,UAAe;AAAA,QACnB,MAAM,IAAI,OAAO,UAAU,OAAO;AAAA,CAAI;AAAA,QACtC;AAAA,MACF;AAAA,MAEA,MAAM,QAAQ,KAAK,MAAM,SAAS;AAAA,MAClC,MAAM,QAAQ,MAAM;AAAA,MACpB,MAAM,WAAqB,CAAC;AAAA,MAE5B,SAAS,IAAI,EAAG,IAAI,OAAO,KAAK;AAAA,QAC9B,MAAM,MAAM,IAAI;AAAA,QAChB,MAAM,aAAa,SAAS,KAAK,KAAK;AAAA,QACtC,IAAI,aAAa,CAAC,aAAa,YAAY;AAAA,UACzC,SAAS,KAAK,MAAM,EAAG;AAAA,QACzB;AAAA,MACF;AAAA,MAEA,MAAM,WAAW,mBAAmB;AAAA,MACpC,MAAM,IAAI,OAAO,UAAU,SAAS,KAAK,QAAQ,IAAI;AAAA,CAAI;AAAA,IAC3D,EAAO;AAAA,MAEL,MAAM,QAAQ,CAAC,GAAG,IAAI;AAAA,MACtB,MAAM,QAAQ,MAAM;AAAA,MACpB,MAAM,WAAqB,CAAC;AAAA,MAE5B,SAAS,IAAI,EAAG,IAAI,OAAO,KAAK;AAAA,QAC9B,MAAM,MAAM,IAAI;AAAA,QAChB,MAAM,aAAa,SAAS,KAAK,KAAK;AAAA,QACtC,IAAI,aAAa,CAAC,aAAa,YAAY;AAAA,UACzC,SAAS,KAAK,MAAM,EAAG;AAAA,QACzB;AAAA,MACF;AAAA,MAEA,MAAM,WAAW,mBAAmB;AAAA,MACpC,MAAM,IAAI,OAAO,UAAU,SAAS,KAAK,QAAQ,IAAI;AAAA,CAAI;AAAA;AAAA;AAAA,EAI7D,MAAM,QAAQ,OAAO;AAAA,EAErB,IAAI,MAAM,WAAW,GAAG;AAAA,IAEtB,iBAAiB,QAAQ,IAAI,MAAM,MAAM,GAAG;AAAA,MAC1C,MAAM,YAAY,IAAI;AAAA,IACxB;AAAA,EACF,EAAO;AAAA,IACL,WAAW,QAAQ,OAAO;AAAA,MACxB,IAAI;AAAA,QACF,MAAM,OAAO,IAAI,GAAG,QAAQ,IAAI,KAAK,IAAI;AAAA,QACzC,MAAM,WAAW,MAAM,IAAI,GAAG,SAAS,IAAI,GAAG,SAAS;AAAA,QACvD,MAAM,QAAQ,QAAQ,MAAM;AAAA,CAAI;AAAA,QAEhC,IAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,IAAI;AAAA,UACtD,MAAM,IAAI;AAAA,QACZ;AAAA,QACA,WAAW,QAAQ,OAAO;AAAA,UACxB,MAAM,YAAY,IAAI;AAAA,QACxB;AAAA,QACA,MAAM;AAAA,QACN,MAAM,IAAI,OAAO,UAAU,QAAQ;AAAA,CAAmC;AAAA,QACtE,OAAO;AAAA;AAAA,IAEX;AAAA;AAAA,EAGF,OAAO;AAAA;",
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=17598CDDC0006B1664756E2164756E21
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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;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;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;AACF;",
8
- "debugId": "17598CDDC0006B1664756E2164756E21",
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
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "type": "module"
5
5
  }
@@ -0,0 +1,158 @@
1
+ // src/commands/cut/cut.ts
2
+ import { createFlagParser } from "../../utils/flag-parser.mjs";
3
+ var spec = {
4
+ name: "cut",
5
+ flags: [
6
+ { short: "b", long: "bytes", takesValue: true },
7
+ { short: "c", long: "characters", takesValue: true },
8
+ { short: "d", long: "delimiter", takesValue: true },
9
+ { short: "f", long: "fields", takesValue: true },
10
+ { short: "s", long: "only-delimited" },
11
+ { long: "complement" },
12
+ { long: "output-delimiter", takesValue: true }
13
+ ],
14
+ usage: `cut -b list [-n] [file ...]
15
+ cut -c list [file ...]
16
+ cut -f list [-d delim] [-s] [file ...]`
17
+ };
18
+ var defaults = {
19
+ bytes: null,
20
+ characters: null,
21
+ delimiter: "\t",
22
+ fields: null,
23
+ onlyDelimited: false,
24
+ complement: false,
25
+ outputDelimiter: null
26
+ };
27
+ var handler = (flags, flag, value) => {
28
+ if (flag.short === "b")
29
+ flags.bytes = value ?? null;
30
+ if (flag.short === "c")
31
+ flags.characters = value ?? null;
32
+ if (flag.short === "d")
33
+ flags.delimiter = value ?? "\t";
34
+ if (flag.short === "f")
35
+ flags.fields = value ?? null;
36
+ if (flag.short === "s")
37
+ flags.onlyDelimited = true;
38
+ if (flag.long === "complement")
39
+ flags.complement = true;
40
+ if (flag.long === "output-delimiter")
41
+ flags.outputDelimiter = value ?? null;
42
+ };
43
+ var parser = createFlagParser(spec, defaults, handler);
44
+ function parseListSpec(listStr) {
45
+ const ranges = [];
46
+ for (const part of listStr.split(",")) {
47
+ const trimmed = part.trim();
48
+ if (trimmed.includes("-")) {
49
+ const [startStr, endStr] = trimmed.split("-", 2);
50
+ const start = startStr === "" ? null : parseInt(startStr, 10);
51
+ const end = endStr === "" ? null : parseInt(endStr, 10);
52
+ ranges.push({ start, end });
53
+ } else {
54
+ const n = parseInt(trimmed, 10);
55
+ ranges.push({ start: n, end: n });
56
+ }
57
+ }
58
+ return (index, total) => {
59
+ for (const { start, end } of ranges) {
60
+ const s = start ?? 1;
61
+ const e = end ?? total;
62
+ if (index >= s && index <= e)
63
+ return true;
64
+ }
65
+ return false;
66
+ };
67
+ }
68
+ var cut = async (ctx) => {
69
+ const result = parser.parse(ctx.args);
70
+ if (result.error) {
71
+ await parser.writeError(result.error, ctx.stderr);
72
+ return 1;
73
+ }
74
+ const { bytes, characters, fields, delimiter, onlyDelimited, complement, outputDelimiter } = result.flags;
75
+ const modeCount = [bytes, characters, fields].filter((v) => v !== null).length;
76
+ if (modeCount === 0) {
77
+ await ctx.stderr.writeText(`cut: you must specify a list of bytes, characters, or fields
78
+ `);
79
+ return 1;
80
+ }
81
+ if (modeCount > 1) {
82
+ await ctx.stderr.writeText(`cut: only one type of list may be specified
83
+ `);
84
+ return 1;
85
+ }
86
+ const listStr = bytes ?? characters ?? fields;
87
+ const selector = parseListSpec(listStr);
88
+ const mode = bytes !== null ? "bytes" : characters !== null ? "chars" : "fields";
89
+ const processLine = async (line) => {
90
+ if (mode === "fields") {
91
+ if (!line.includes(delimiter)) {
92
+ if (onlyDelimited)
93
+ return;
94
+ await ctx.stdout.writeText(line + `
95
+ `);
96
+ return;
97
+ }
98
+ const parts = line.split(delimiter);
99
+ const total = parts.length;
100
+ const selected = [];
101
+ for (let i = 0;i < total; i++) {
102
+ const idx = i + 1;
103
+ const isSelected = selector(idx, total);
104
+ if (complement ? !isSelected : isSelected) {
105
+ selected.push(parts[i]);
106
+ }
107
+ }
108
+ const outDelim = outputDelimiter ?? delimiter;
109
+ await ctx.stdout.writeText(selected.join(outDelim) + `
110
+ `);
111
+ } else {
112
+ const chars = [...line];
113
+ const total = chars.length;
114
+ const selected = [];
115
+ for (let i = 0;i < total; i++) {
116
+ const idx = i + 1;
117
+ const isSelected = selector(idx, total);
118
+ if (complement ? !isSelected : isSelected) {
119
+ selected.push(chars[i]);
120
+ }
121
+ }
122
+ const outDelim = outputDelimiter ?? "";
123
+ await ctx.stdout.writeText(selected.join(outDelim) + `
124
+ `);
125
+ }
126
+ };
127
+ const files = result.args;
128
+ if (files.length === 0) {
129
+ for await (const line of ctx.stdin.lines()) {
130
+ await processLine(line);
131
+ }
132
+ } else {
133
+ for (const file of files) {
134
+ try {
135
+ const path = ctx.fs.resolve(ctx.cwd, file);
136
+ const content = (await ctx.fs.readFile(path)).toString();
137
+ const lines = content.split(`
138
+ `);
139
+ if (lines.length > 0 && lines[lines.length - 1] === "") {
140
+ lines.pop();
141
+ }
142
+ for (const line of lines) {
143
+ await processLine(line);
144
+ }
145
+ } catch {
146
+ await ctx.stderr.writeText(`cut: ${file}: No such file or directory
147
+ `);
148
+ return 1;
149
+ }
150
+ }
151
+ }
152
+ return 0;
153
+ };
154
+ export {
155
+ cut
156
+ };
157
+
158
+ //# debugId=2D00AF426B0DE6E464756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/commands/cut/cut.ts"],
4
+ "sourcesContent": [
5
+ "import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\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": "2D00AF426B0DE6E464756E2164756E21",
9
+ "names": []
10
+ }
@@ -25,6 +25,7 @@ import { breakCmd, continueCmd } from "./break-continue/break-continue.mjs";
25
25
  import { colon } from "./colon/colon.mjs";
26
26
  import { cd } from "./cd/cd.mjs";
27
27
  import { tr } from "./tr/tr.mjs";
28
+ import { cut } from "./cut/cut.mjs";
28
29
  import { echo as echo2 } from "./echo/echo.mjs";
29
30
  import { cat as cat2 } from "./cat/cat.mjs";
30
31
  import { grep as grep2 } from "./grep/grep.mjs";
@@ -51,6 +52,7 @@ import { breakCmd as breakCmd2, continueCmd as continueCmd2 } from "./break-cont
51
52
  import { colon as colon2 } from "./colon/colon.mjs";
52
53
  import { cd as cd2 } from "./cd/cd.mjs";
53
54
  import { tr as tr2 } from "./tr/tr.mjs";
55
+ import { cut as cut2 } from "./cut/cut.mjs";
54
56
  var builtinCommands = {
55
57
  echo: echo2,
56
58
  cat: cat2,
@@ -80,7 +82,8 @@ var builtinCommands = {
80
82
  continue: continueCmd2,
81
83
  ":": colon2,
82
84
  cd: cd2,
83
- tr: tr2
85
+ tr: tr2,
86
+ cut: cut2
84
87
  };
85
88
  export {
86
89
  wc,
@@ -104,6 +107,7 @@ export {
104
107
  find,
105
108
  falseCmd,
106
109
  echo,
110
+ cut,
107
111
  cp,
108
112
  continueCmd,
109
113
  colon,
@@ -115,4 +119,4 @@ export {
115
119
  awk
116
120
  };
117
121
 
118
- //# debugId=D1FD821D9116613964756E2164756E21
122
+ //# debugId=FD4335F8123BE07364756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/commands/index.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../types.mjs\";\n\nexport { echo } from \"./echo/echo.mjs\";\nexport { cat } from \"./cat/cat.mjs\";\nexport { grep } from \"./grep/grep.mjs\";\nexport { wc } from \"./wc/wc.mjs\";\nexport { head } from \"./head/head.mjs\";\nexport { tail } from \"./tail/tail.mjs\";\nexport { sort } from \"./sort/sort.mjs\";\nexport { uniq } from \"./uniq/uniq.mjs\";\nexport { pwd } from \"./pwd/pwd.mjs\";\nexport { ls } from \"./ls/ls.mjs\";\nexport { mkdir } from \"./mkdir/mkdir.mjs\";\nexport { rm } from \"./rm/rm.mjs\";\nexport { test, bracket } from \"./test/test.mjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nexport { touch } from \"./touch/touch.mjs\";\nexport { cp } from \"./cp/cp.mjs\";\nexport { mv } from \"./mv/mv.mjs\";\nexport { tee } from \"./tee/tee.mjs\";\nexport { tree } from \"./tree/tree.mjs\";\nexport { find } from \"./find/find.mjs\";\nexport { sed } from \"./sed/sed.mjs\";\nexport { awk } from \"./awk/awk.mjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nexport { colon } from \"./colon/colon.mjs\";\nexport { cd } from \"./cd/cd.mjs\";\nexport { tr } from \"./tr/tr.mjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.mjs\";\nimport { cat } from \"./cat/cat.mjs\";\nimport { grep } from \"./grep/grep.mjs\";\nimport { wc } from \"./wc/wc.mjs\";\nimport { head } from \"./head/head.mjs\";\nimport { tail } from \"./tail/tail.mjs\";\nimport { sort } from \"./sort/sort.mjs\";\nimport { uniq } from \"./uniq/uniq.mjs\";\nimport { pwd } from \"./pwd/pwd.mjs\";\nimport { ls } from \"./ls/ls.mjs\";\nimport { mkdir } from \"./mkdir/mkdir.mjs\";\nimport { rm } from \"./rm/rm.mjs\";\nimport { test, bracket } from \"./test/test.mjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nimport { touch } from \"./touch/touch.mjs\";\nimport { cp } from \"./cp/cp.mjs\";\nimport { mv } from \"./mv/mv.mjs\";\nimport { tee } from \"./tee/tee.mjs\";\nimport { tree } from \"./tree/tree.mjs\";\nimport { find } from \"./find/find.mjs\";\nimport { sed } from \"./sed/sed.mjs\";\nimport { awk } from \"./awk/awk.mjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nimport { colon } from \"./colon/colon.mjs\";\nimport { cd } from \"./cd/cd.mjs\";\nimport { tr } from \"./tr/tr.mjs\";\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.mjs\";\n\nexport { echo } from \"./echo/echo.mjs\";\nexport { cat } from \"./cat/cat.mjs\";\nexport { grep } from \"./grep/grep.mjs\";\nexport { wc } from \"./wc/wc.mjs\";\nexport { head } from \"./head/head.mjs\";\nexport { tail } from \"./tail/tail.mjs\";\nexport { sort } from \"./sort/sort.mjs\";\nexport { uniq } from \"./uniq/uniq.mjs\";\nexport { pwd } from \"./pwd/pwd.mjs\";\nexport { ls } from \"./ls/ls.mjs\";\nexport { mkdir } from \"./mkdir/mkdir.mjs\";\nexport { rm } from \"./rm/rm.mjs\";\nexport { test, bracket } from \"./test/test.mjs\";\nexport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nexport { touch } from \"./touch/touch.mjs\";\nexport { cp } from \"./cp/cp.mjs\";\nexport { mv } from \"./mv/mv.mjs\";\nexport { tee } from \"./tee/tee.mjs\";\nexport { tree } from \"./tree/tree.mjs\";\nexport { find } from \"./find/find.mjs\";\nexport { sed } from \"./sed/sed.mjs\";\nexport { awk } from \"./awk/awk.mjs\";\nexport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nexport { colon } from \"./colon/colon.mjs\";\nexport { cd } from \"./cd/cd.mjs\";\nexport { tr } from \"./tr/tr.mjs\";\nexport { cut } from \"./cut/cut.mjs\";\n\n// Re-export all commands as a bundle\nimport { echo } from \"./echo/echo.mjs\";\nimport { cat } from \"./cat/cat.mjs\";\nimport { grep } from \"./grep/grep.mjs\";\nimport { wc } from \"./wc/wc.mjs\";\nimport { head } from \"./head/head.mjs\";\nimport { tail } from \"./tail/tail.mjs\";\nimport { sort } from \"./sort/sort.mjs\";\nimport { uniq } from \"./uniq/uniq.mjs\";\nimport { pwd } from \"./pwd/pwd.mjs\";\nimport { ls } from \"./ls/ls.mjs\";\nimport { mkdir } from \"./mkdir/mkdir.mjs\";\nimport { rm } from \"./rm/rm.mjs\";\nimport { test, bracket } from \"./test/test.mjs\";\nimport { trueCmd, falseCmd } from \"./true-false/true-false.mjs\";\nimport { touch } from \"./touch/touch.mjs\";\nimport { cp } from \"./cp/cp.mjs\";\nimport { mv } from \"./mv/mv.mjs\";\nimport { tee } from \"./tee/tee.mjs\";\nimport { tree } from \"./tree/tree.mjs\";\nimport { find } from \"./find/find.mjs\";\nimport { sed } from \"./sed/sed.mjs\";\nimport { awk } from \"./awk/awk.mjs\";\nimport { breakCmd, continueCmd } from \"./break-continue/break-continue.mjs\";\nimport { colon } from \"./colon/colon.mjs\";\nimport { cd } from \"./cd/cd.mjs\";\nimport { tr } from \"./tr/tr.mjs\";\nimport { cut } from \"./cut/cut.mjs\";\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": ";AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,iBAAS;AACT,gBAAS;AACT,iBAAS;AACT,eAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,eAAS;AACT,kBAAS;AACT,eAAS;AACT,iBAAS,kBAAM;AACf,oBAAS,sBAAS;AAClB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,gBAAS;AACT,qBAAS,0BAAU;AACnB,kBAAS;AACT,eAAS;AACT,eAAS;AAEF,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;AACF;",
8
- "debugId": "D1FD821D9116613964756E2164756E21",
7
+ "mappings": ";AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,iBAAS;AACT,gBAAS;AACT,iBAAS;AACT,eAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,eAAS;AACT,kBAAS;AACT,eAAS;AACT,iBAAS,kBAAM;AACf,oBAAS,sBAAS;AAClB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AACT,iBAAS;AACT,iBAAS;AACT,gBAAS;AACT,gBAAS;AACT,qBAAS,0BAAU;AACnB,kBAAS;AACT,eAAS;AACT,eAAS;AACT,gBAAS;AAEF,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": "FD4335F8123BE07364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "../../types.ts";
2
+ export declare const cut: Command;
@@ -25,4 +25,5 @@ export { breakCmd, continueCmd } from "./break-continue/break-continue.ts";
25
25
  export { colon } from "./colon/colon.ts";
26
26
  export { cd } from "./cd/cd.ts";
27
27
  export { tr } from "./tr/tr.ts";
28
+ export { cut } from "./cut/cut.ts";
28
29
  export declare const builtinCommands: Record<string, Command>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "A sandboxed shell-style DSL for running scriptable command pipelines in-process without host OS access",
5
5
  "author": "ricsam <oss@ricsam.dev>",
6
6
  "license": "MIT",