shell-dsl 0.0.13 → 0.0.15

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "commonjs"
5
5
  }
@@ -88,88 +88,173 @@ function matchGlob(pattern, str, caseInsensitive = false) {
88
88
  return false;
89
89
  }
90
90
  }
91
+ function evalExpr(expr, basename, isFile, isDir) {
92
+ switch (expr.type) {
93
+ case "true":
94
+ return true;
95
+ case "name":
96
+ return matchGlob(expr.pattern, basename, expr.ignoreCase);
97
+ case "ftype":
98
+ return expr.value === "f" ? isFile : isDir;
99
+ case "and":
100
+ return evalExpr(expr.left, basename, isFile, isDir) && evalExpr(expr.right, basename, isFile, isDir);
101
+ case "or":
102
+ return evalExpr(expr.left, basename, isFile, isDir) || evalExpr(expr.right, basename, isFile, isDir);
103
+ case "not":
104
+ return !evalExpr(expr.expr, basename, isFile, isDir);
105
+ }
106
+ }
107
+
108
+ class ParseError extends Error {
109
+ constructor(msg) {
110
+ super(msg);
111
+ }
112
+ }
113
+ function parseExprArgs(args) {
114
+ if (args.length === 0)
115
+ return { type: "true" };
116
+ let pos = 0;
117
+ function peek() {
118
+ return args[pos];
119
+ }
120
+ function advance() {
121
+ return args[pos++];
122
+ }
123
+ function parseOr() {
124
+ let left = parseAnd();
125
+ while (peek() === "-o") {
126
+ advance();
127
+ const right = parseAnd();
128
+ left = { type: "or", left, right };
129
+ }
130
+ return left;
131
+ }
132
+ function parseAnd() {
133
+ let left = parseUnary();
134
+ while (pos < args.length) {
135
+ const next = peek();
136
+ if (next === "-o" || next === ")" || next === undefined)
137
+ break;
138
+ if (next === "-a") {
139
+ advance();
140
+ }
141
+ const right = parseUnary();
142
+ left = { type: "and", left, right };
143
+ }
144
+ return left;
145
+ }
146
+ function parseUnary() {
147
+ const next = peek();
148
+ if (next === "!" || next === "-not") {
149
+ advance();
150
+ const expr2 = parseUnary();
151
+ return { type: "not", expr: expr2 };
152
+ }
153
+ return parsePrimary();
154
+ }
155
+ function parsePrimary() {
156
+ const tok = peek();
157
+ if (tok === undefined) {
158
+ throw new ParseError("find: expected expression");
159
+ }
160
+ if (tok === "(") {
161
+ advance();
162
+ const expr2 = parseOr();
163
+ if (peek() !== ")") {
164
+ throw new ParseError("find: missing closing ')'");
165
+ }
166
+ advance();
167
+ return expr2;
168
+ }
169
+ if (tok === "-name" || tok === "-iname") {
170
+ advance();
171
+ const pattern = peek();
172
+ if (pattern === undefined) {
173
+ throw new ParseError(`find: missing argument to '${tok}'`);
174
+ }
175
+ advance();
176
+ return { type: "name", pattern, ignoreCase: tok === "-iname" };
177
+ }
178
+ if (tok === "-type") {
179
+ advance();
180
+ const val = peek();
181
+ if (val === undefined) {
182
+ throw new ParseError("find: missing argument to '-type'");
183
+ }
184
+ if (val !== "f" && val !== "d") {
185
+ throw new ParseError(`find: Unknown argument to -type: ${val}`);
186
+ }
187
+ advance();
188
+ return { type: "ftype", value: val };
189
+ }
190
+ throw new ParseError(`find: unknown predicate '${tok}'`);
191
+ }
192
+ const expr = parseOr();
193
+ if (pos < args.length) {
194
+ throw new ParseError(`find: unexpected '${args[pos]}'`);
195
+ }
196
+ return expr;
197
+ }
91
198
  var find = async (ctx) => {
92
199
  const args = [...ctx.args];
93
200
  const paths = [];
94
- const options = {};
95
201
  let i = 0;
96
- while (i < args.length && !args[i].startsWith("-")) {
202
+ while (i < args.length && !args[i].startsWith("-") && args[i] !== "!" && args[i] !== "(" && args[i] !== ")") {
97
203
  paths.push(args[i]);
98
204
  i++;
99
205
  }
100
206
  if (paths.length === 0) {
101
207
  paths.push(".");
102
208
  }
103
- while (i < args.length) {
104
- const arg = args[i];
105
- if (arg === "-name") {
106
- i++;
107
- if (i >= args.length) {
108
- await ctx.stderr.writeText(`find: missing argument to '-name'
109
- `);
110
- return 1;
111
- }
112
- options.namePattern = args[i];
113
- options.nameIgnoreCase = false;
114
- } else if (arg === "-iname") {
115
- i++;
116
- if (i >= args.length) {
117
- await ctx.stderr.writeText(`find: missing argument to '-iname'
118
- `);
119
- return 1;
120
- }
121
- options.namePattern = args[i];
122
- options.nameIgnoreCase = true;
123
- } else if (arg === "-type") {
124
- i++;
125
- if (i >= args.length) {
126
- await ctx.stderr.writeText(`find: missing argument to '-type'
127
- `);
128
- return 1;
129
- }
130
- const typeArg = args[i];
131
- if (typeArg !== "f" && typeArg !== "d") {
132
- await ctx.stderr.writeText(`find: Unknown argument to -type: ${typeArg}
133
- `);
134
- return 1;
135
- }
136
- options.type = typeArg;
137
- } else if (arg === "-maxdepth") {
138
- i++;
139
- if (i >= args.length) {
209
+ let maxDepth;
210
+ let minDepth;
211
+ const exprArgs = [];
212
+ let j = i;
213
+ while (j < args.length) {
214
+ const arg = args[j];
215
+ if (arg === "-maxdepth") {
216
+ j++;
217
+ if (j >= args.length) {
140
218
  await ctx.stderr.writeText(`find: missing argument to '-maxdepth'
141
219
  `);
142
220
  return 1;
143
221
  }
144
- const depth = parseInt(args[i], 10);
222
+ const depth = parseInt(args[j], 10);
145
223
  if (isNaN(depth) || depth < 0) {
146
- await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -maxdepth
224
+ await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth
147
225
  `);
148
226
  return 1;
149
227
  }
150
- options.maxDepth = depth;
228
+ maxDepth = depth;
151
229
  } else if (arg === "-mindepth") {
152
- i++;
153
- if (i >= args.length) {
230
+ j++;
231
+ if (j >= args.length) {
154
232
  await ctx.stderr.writeText(`find: missing argument to '-mindepth'
155
233
  `);
156
234
  return 1;
157
235
  }
158
- const depth = parseInt(args[i], 10);
236
+ const depth = parseInt(args[j], 10);
159
237
  if (isNaN(depth) || depth < 0) {
160
- await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -mindepth
238
+ await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth
161
239
  `);
162
240
  return 1;
163
241
  }
164
- options.minDepth = depth;
165
- } else if (arg.startsWith("-")) {
166
- await ctx.stderr.writeText(`find: unknown predicate '${arg}'
242
+ minDepth = depth;
243
+ } else {
244
+ exprArgs.push(arg);
245
+ }
246
+ j++;
247
+ }
248
+ let expr;
249
+ try {
250
+ expr = parseExprArgs(exprArgs);
251
+ } catch (e) {
252
+ if (e instanceof ParseError) {
253
+ await ctx.stderr.writeText(e.message + `
167
254
  `);
168
255
  return 1;
169
- } else {
170
- paths.push(arg);
171
256
  }
172
- i++;
257
+ throw e;
173
258
  }
174
259
  let hasError = false;
175
260
  for (const startPath of paths) {
@@ -185,7 +270,7 @@ var find = async (ctx) => {
185
270
  continue;
186
271
  }
187
272
  async function traverse(path, displayPath, depth) {
188
- if (options.maxDepth !== undefined && depth > options.maxDepth) {
273
+ if (maxDepth !== undefined && depth > maxDepth) {
189
274
  return;
190
275
  }
191
276
  let entryStat;
@@ -197,18 +282,8 @@ var find = async (ctx) => {
197
282
  const isDir = entryStat.isDirectory();
198
283
  const isFile = entryStat.isFile();
199
284
  const basename = ctx.fs.basename(path);
200
- let matches = true;
201
- if (options.type === "f" && !isFile) {
202
- matches = false;
203
- } else if (options.type === "d" && !isDir) {
204
- matches = false;
205
- }
206
- if (matches && options.namePattern !== undefined) {
207
- if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {
208
- matches = false;
209
- }
210
- }
211
- if (matches && (options.minDepth === undefined || depth >= options.minDepth)) {
285
+ const matches = evalExpr(expr, basename, isFile, isDir);
286
+ if (matches && (minDepth === undefined || depth >= minDepth)) {
212
287
  await ctx.stdout.writeText(displayPath + `
213
288
  `);
214
289
  }
@@ -225,20 +300,9 @@ var find = async (ctx) => {
225
300
  }
226
301
  }
227
302
  if (stat.isFile()) {
228
- let matches = true;
229
- if (options.type === "d") {
230
- matches = false;
231
- }
232
- if (matches && options.namePattern !== undefined) {
233
- const basename = ctx.fs.basename(resolvedStart);
234
- if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {
235
- matches = false;
236
- }
237
- }
238
- if (options.maxDepth !== undefined && options.maxDepth < 0) {
239
- matches = false;
240
- }
241
- if (matches && (options.minDepth === undefined || options.minDepth <= 0)) {
303
+ const basename = ctx.fs.basename(resolvedStart);
304
+ const matches = evalExpr(expr, basename, true, false);
305
+ if (maxDepth !== undefined && maxDepth < 0) {} else if (matches && (minDepth === undefined || minDepth <= 0)) {
242
306
  await ctx.stdout.writeText(normalizedPath + `
243
307
  `);
244
308
  }
@@ -249,4 +313,4 @@ var find = async (ctx) => {
249
313
  return hasError ? 1 : 0;
250
314
  };
251
315
 
252
- //# debugId=079983875D7F5C7264756E2164756E21
316
+ //# debugId=80CE5607A2F2B89F64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/commands/find/find.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../../types.cjs\";\n\n/**\n * Simple glob pattern matching (fnmatch-style)\n * Supports: * (any chars), ? (single char), [...] (character class)\n */\nfunction matchGlob(pattern: string, str: string, caseInsensitive = false): boolean {\n if (caseInsensitive) {\n pattern = pattern.toLowerCase();\n str = str.toLowerCase();\n }\n\n // Convert glob to regex\n let regex = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const c = pattern[i]!;\n switch (c) {\n case \"*\":\n regex += \".*\";\n break;\n case \"?\":\n regex += \".\";\n break;\n case \"[\": {\n // Find closing bracket\n let j = i + 1;\n // Handle negation\n if (pattern[j] === \"!\" || pattern[j] === \"^\") j++;\n // Handle ] as first char in class\n if (pattern[j] === \"]\") j++;\n while (j < pattern.length && pattern[j] !== \"]\") j++;\n if (j >= pattern.length) {\n // No closing bracket, treat [ as literal\n regex += \"\\\\[\";\n } else {\n let charClass = pattern.slice(i, j + 1);\n // Convert ! to ^ for negation in regex\n charClass = charClass.replace(/^\\[!/, \"[^\");\n regex += charClass;\n i = j;\n }\n break;\n }\n case \".\":\n case \"^\":\n case \"$\":\n case \"+\":\n case \"{\":\n case \"}\":\n case \"(\":\n case \")\":\n case \"|\":\n case \"\\\\\":\n regex += \"\\\\\" + c;\n break;\n default:\n regex += c;\n }\n }\n regex += \"$\";\n\n try {\n return new RegExp(regex).test(str);\n } catch {\n return false;\n }\n}\n\ninterface FindOptions {\n namePattern?: string;\n nameIgnoreCase?: boolean;\n type?: \"f\" | \"d\";\n maxDepth?: number;\n minDepth?: number;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n const options: FindOptions = {};\n\n // Parse arguments: paths come before first flag, then expressions\n let i = 0;\n\n // Collect paths (args before first -)\n while (i < args.length && !args[i]!.startsWith(\"-\")) {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Parse expression flags\n while (i < args.length) {\n const arg = args[i]!;\n\n if (arg === \"-name\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-name'\\n\");\n return 1;\n }\n options.namePattern = args[i]!;\n options.nameIgnoreCase = false;\n } else if (arg === \"-iname\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-iname'\\n\");\n return 1;\n }\n options.namePattern = args[i]!;\n options.nameIgnoreCase = true;\n } else if (arg === \"-type\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-type'\\n\");\n return 1;\n }\n const typeArg = args[i]!;\n if (typeArg !== \"f\" && typeArg !== \"d\") {\n await ctx.stderr.writeText(`find: Unknown argument to -type: ${typeArg}\\n`);\n return 1;\n }\n options.type = typeArg;\n } else if (arg === \"-maxdepth\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[i]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -maxdepth\\n`);\n return 1;\n }\n options.maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[i]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -mindepth\\n`);\n return 1;\n }\n options.minDepth = depth;\n } else if (arg.startsWith(\"-\")) {\n await ctx.stderr.writeText(`find: unknown predicate '${arg}'\\n`);\n return 1;\n } else {\n // This shouldn't happen since paths are parsed first, but treat as path\n paths.push(arg);\n }\n\n i++;\n }\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (options.maxDepth !== undefined && depth > options.maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n\n // Check if this entry matches filters\n let matches = true;\n\n // Type filter\n if (options.type === \"f\" && !isFile) {\n matches = false;\n } else if (options.type === \"d\" && !isDir) {\n matches = false;\n }\n\n // Name filter (only check basename)\n if (matches && options.namePattern !== undefined) {\n if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {\n matches = false;\n }\n }\n\n // Output if matches and above mindepth\n if (matches && (options.minDepth === undefined || depth >= options.minDepth)) {\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n // For a single file, it's at depth 0\n // For a directory, the directory itself is depth 0, contents are depth 1+\n if (stat.isFile()) {\n // Starting from a file - depth 0\n let matches = true;\n\n if (options.type === \"d\") {\n matches = false;\n }\n\n if (matches && options.namePattern !== undefined) {\n const basename = ctx.fs.basename(resolvedStart);\n if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {\n matches = false;\n }\n }\n\n if (options.maxDepth !== undefined && options.maxDepth < 0) {\n matches = false;\n }\n\n if (matches && (options.minDepth === undefined || options.minDepth <= 0)) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
5
+ "import type { Command } from \"../../types.cjs\";\n\n/**\n * Simple glob pattern matching (fnmatch-style)\n * Supports: * (any chars), ? (single char), [...] (character class)\n */\nfunction matchGlob(pattern: string, str: string, caseInsensitive = false): boolean {\n if (caseInsensitive) {\n pattern = pattern.toLowerCase();\n str = str.toLowerCase();\n }\n\n // Convert glob to regex\n let regex = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const c = pattern[i]!;\n switch (c) {\n case \"*\":\n regex += \".*\";\n break;\n case \"?\":\n regex += \".\";\n break;\n case \"[\": {\n // Find closing bracket\n let j = i + 1;\n // Handle negation\n if (pattern[j] === \"!\" || pattern[j] === \"^\") j++;\n // Handle ] as first char in class\n if (pattern[j] === \"]\") j++;\n while (j < pattern.length && pattern[j] !== \"]\") j++;\n if (j >= pattern.length) {\n // No closing bracket, treat [ as literal\n regex += \"\\\\[\";\n } else {\n let charClass = pattern.slice(i, j + 1);\n // Convert ! to ^ for negation in regex\n charClass = charClass.replace(/^\\[!/, \"[^\");\n regex += charClass;\n i = j;\n }\n break;\n }\n case \".\":\n case \"^\":\n case \"$\":\n case \"+\":\n case \"{\":\n case \"}\":\n case \"(\":\n case \")\":\n case \"|\":\n case \"\\\\\":\n regex += \"\\\\\" + c;\n break;\n default:\n regex += c;\n }\n }\n regex += \"$\";\n\n try {\n return new RegExp(regex).test(str);\n } catch {\n return false;\n }\n}\n\n// Expression tree types\ntype FindExpr =\n | { type: \"name\"; pattern: string; ignoreCase: boolean }\n | { type: \"ftype\"; value: \"f\" | \"d\" }\n | { type: \"and\"; left: FindExpr; right: FindExpr }\n | { type: \"or\"; left: FindExpr; right: FindExpr }\n | { type: \"not\"; expr: FindExpr }\n | { type: \"true\" };\n\nfunction evalExpr(expr: FindExpr, basename: string, isFile: boolean, isDir: boolean): boolean {\n switch (expr.type) {\n case \"true\":\n return true;\n case \"name\":\n return matchGlob(expr.pattern, basename, expr.ignoreCase);\n case \"ftype\":\n return expr.value === \"f\" ? isFile : isDir;\n case \"and\":\n return evalExpr(expr.left, basename, isFile, isDir) && evalExpr(expr.right, basename, isFile, isDir);\n case \"or\":\n return evalExpr(expr.left, basename, isFile, isDir) || evalExpr(expr.right, basename, isFile, isDir);\n case \"not\":\n return !evalExpr(expr.expr, basename, isFile, isDir);\n }\n}\n\nclass ParseError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n\nfunction parseExprArgs(args: string[]): FindExpr {\n if (args.length === 0) return { type: \"true\" };\n\n let pos = 0;\n\n function peek(): string | undefined {\n return args[pos];\n }\n\n function advance(): string {\n return args[pos++]!;\n }\n\n function parseOr(): FindExpr {\n let left = parseAnd();\n while (peek() === \"-o\") {\n advance();\n const right = parseAnd();\n left = { type: \"or\", left, right };\n }\n return left;\n }\n\n function parseAnd(): FindExpr {\n let left = parseUnary();\n while (pos < args.length) {\n const next = peek();\n if (next === \"-o\" || next === \")\" || next === undefined) break;\n if (next === \"-a\") {\n advance();\n }\n const right = parseUnary();\n left = { type: \"and\", left, right };\n }\n return left;\n }\n\n function parseUnary(): FindExpr {\n const next = peek();\n if (next === \"!\" || next === \"-not\") {\n advance();\n const expr = parseUnary();\n return { type: \"not\", expr };\n }\n return parsePrimary();\n }\n\n function parsePrimary(): FindExpr {\n const tok = peek();\n if (tok === undefined) {\n throw new ParseError(\"find: expected expression\");\n }\n\n if (tok === \"(\") {\n advance();\n const expr = parseOr();\n if (peek() !== \")\") {\n throw new ParseError(\"find: missing closing ')'\");\n }\n advance();\n return expr;\n }\n\n if (tok === \"-name\" || tok === \"-iname\") {\n advance();\n const pattern = peek();\n if (pattern === undefined) {\n throw new ParseError(`find: missing argument to '${tok}'`);\n }\n advance();\n return { type: \"name\", pattern, ignoreCase: tok === \"-iname\" };\n }\n\n if (tok === \"-type\") {\n advance();\n const val = peek();\n if (val === undefined) {\n throw new ParseError(\"find: missing argument to '-type'\");\n }\n if (val !== \"f\" && val !== \"d\") {\n throw new ParseError(`find: Unknown argument to -type: ${val}`);\n }\n advance();\n return { type: \"ftype\", value: val };\n }\n\n throw new ParseError(`find: unknown predicate '${tok}'`);\n }\n\n const expr = parseOr();\n if (pos < args.length) {\n throw new ParseError(`find: unexpected '${args[pos]}'`);\n }\n return expr;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n\n // Parse arguments: paths come before first flag/operator\n let i = 0;\n\n // Collect paths (args before first -, !, or ()\n while (i < args.length && !args[i]!.startsWith(\"-\") && args[i] !== \"!\" && args[i] !== \"(\" && args[i] !== \")\") {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Extract global options (-maxdepth, -mindepth) from remaining args\n let maxDepth: number | undefined;\n let minDepth: number | undefined;\n const exprArgs: string[] = [];\n\n let j = i;\n while (j < args.length) {\n const arg = args[j]!;\n if (arg === \"-maxdepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth\\n`);\n return 1;\n }\n maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth\\n`);\n return 1;\n }\n minDepth = depth;\n } else {\n exprArgs.push(arg);\n }\n j++;\n }\n\n // Parse expression tree\n let expr: FindExpr;\n try {\n expr = parseExprArgs(exprArgs);\n } catch (e) {\n if (e instanceof ParseError) {\n await ctx.stderr.writeText(e.message + \"\\n\");\n return 1;\n }\n throw e;\n }\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (maxDepth !== undefined && depth > maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n\n // Check if this entry matches the expression\n const matches = evalExpr(expr, basename, isFile, isDir);\n\n // Output if matches and above mindepth\n if (matches && (minDepth === undefined || depth >= minDepth)) {\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n if (stat.isFile()) {\n const basename = ctx.fs.basename(resolvedStart);\n const matches = evalExpr(expr, basename, true, false);\n\n if (maxDepth !== undefined && maxDepth < 0) {\n // skip\n } else if (matches && (minDepth === undefined || minDepth <= 0)) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,SAAS,SAAS,CAAC,SAAiB,KAAa,kBAAkB,OAAgB;AAAA,EACjF,IAAI,iBAAiB;AAAA,IACnB,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,IAAI,YAAY;AAAA,EACxB;AAAA,EAGA,IAAI,QAAQ;AAAA,EACZ,SAAS,IAAI,EAAG,IAAI,QAAQ,QAAQ,KAAK;AAAA,IACvC,MAAM,IAAI,QAAQ;AAAA,IAClB,QAAQ;AAAA,WACD;AAAA,QACH,SAAS;AAAA,QACT;AAAA,WACG;AAAA,QACH,SAAS;AAAA,QACT;AAAA,WACG,KAAK;AAAA,QAER,IAAI,IAAI,IAAI;AAAA,QAEZ,IAAI,QAAQ,OAAO,OAAO,QAAQ,OAAO;AAAA,UAAK;AAAA,QAE9C,IAAI,QAAQ,OAAO;AAAA,UAAK;AAAA,QACxB,OAAO,IAAI,QAAQ,UAAU,QAAQ,OAAO;AAAA,UAAK;AAAA,QACjD,IAAI,KAAK,QAAQ,QAAQ;AAAA,UAEvB,SAAS;AAAA,QACX,EAAO;AAAA,UACL,IAAI,YAAY,QAAQ,MAAM,GAAG,IAAI,CAAC;AAAA,UAEtC,YAAY,UAAU,QAAQ,QAAQ,IAAI;AAAA,UAC1C,SAAS;AAAA,UACT,IAAI;AAAA;AAAA,QAEN;AAAA,MACF;AAAA,WACK;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,QACH,SAAS,OAAO;AAAA,QAChB;AAAA;AAAA,QAEA,SAAS;AAAA;AAAA,EAEf;AAAA,EACA,SAAS;AAAA,EAET,IAAI;AAAA,IACF,OAAO,IAAI,OAAO,KAAK,EAAE,KAAK,GAAG;AAAA,IACjC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAYJ,IAAM,OAAgB,OAAO,QAAQ;AAAA,EAC1C,MAAM,OAAO,CAAC,GAAG,IAAI,IAAI;AAAA,EACzB,MAAM,QAAkB,CAAC;AAAA,EACzB,MAAM,UAAuB,CAAC;AAAA,EAG9B,IAAI,IAAI;AAAA,EAGR,OAAO,IAAI,KAAK,UAAU,CAAC,KAAK,GAAI,WAAW,GAAG,GAAG;AAAA,IACnD,MAAM,KAAK,KAAK,EAAG;AAAA,IACnB;AAAA,EACF;AAAA,EAGA,IAAI,MAAM,WAAW,GAAG;AAAA,IACtB,MAAM,KAAK,GAAG;AAAA,EAChB;AAAA,EAGA,OAAO,IAAI,KAAK,QAAQ;AAAA,IACtB,MAAM,MAAM,KAAK;AAAA,IAEjB,IAAI,QAAQ,SAAS;AAAA,MACnB;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAqC;AAAA,QAChE,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,cAAc,KAAK;AAAA,MAC3B,QAAQ,iBAAiB;AAAA,IAC3B,EAAO,SAAI,QAAQ,UAAU;AAAA,MAC3B;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAsC;AAAA,QACjE,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,cAAc,KAAK;AAAA,MAC3B,QAAQ,iBAAiB;AAAA,IAC3B,EAAO,SAAI,QAAQ,SAAS;AAAA,MAC1B;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAqC;AAAA,QAChE,OAAO;AAAA,MACT;AAAA,MACA,MAAM,UAAU,KAAK;AAAA,MACrB,IAAI,YAAY,OAAO,YAAY,KAAK;AAAA,QACtC,MAAM,IAAI,OAAO,UAAU,oCAAoC;AAAA,CAAW;AAAA,QAC1E,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,OAAO;AAAA,IACjB,EAAO,SAAI,QAAQ,aAAa;AAAA,MAC9B;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAyC;AAAA,QACpE,OAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,SAAS,KAAK,IAAK,EAAE;AAAA,MACnC,IAAI,MAAM,KAAK,KAAK,QAAQ,GAAG;AAAA,QAC7B,MAAM,IAAI,OAAO,UAAU,2BAA2B,KAAK;AAAA,CAAoB;AAAA,QAC/E,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,WAAW;AAAA,IACrB,EAAO,SAAI,QAAQ,aAAa;AAAA,MAC9B;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAyC;AAAA,QACpE,OAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,SAAS,KAAK,IAAK,EAAE;AAAA,MACnC,IAAI,MAAM,KAAK,KAAK,QAAQ,GAAG;AAAA,QAC7B,MAAM,IAAI,OAAO,UAAU,2BAA2B,KAAK;AAAA,CAAoB;AAAA,QAC/E,OAAO;AAAA,MACT;AAAA,MACA,QAAQ,WAAW;AAAA,IACrB,EAAO,SAAI,IAAI,WAAW,GAAG,GAAG;AAAA,MAC9B,MAAM,IAAI,OAAO,UAAU,4BAA4B;AAAA,CAAQ;AAAA,MAC/D,OAAO;AAAA,IACT,EAAO;AAAA,MAEL,MAAM,KAAK,GAAG;AAAA;AAAA,IAGhB;AAAA,EACF;AAAA,EAEA,IAAI,WAAW;AAAA,EAGf,WAAW,aAAa,OAAO;AAAA,IAC7B,MAAM,iBAAiB,cAAc,MAAM,MAAM,UAAU,QAAQ,QAAQ,EAAE;AAAA,IAC7E,MAAM,gBAAgB,IAAI,GAAG,QAAQ,IAAI,KAAK,SAAS;AAAA,IAGvD,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,OAAO,MAAM,IAAI,GAAG,KAAK,aAAa;AAAA,MACtC,MAAM;AAAA,MACN,MAAM,IAAI,OAAO,UAAU,UAAU;AAAA,CAAyC;AAAA,MAC9E,WAAW;AAAA,MACX;AAAA;AAAA,IAIF,eAAe,QAAQ,CAAC,MAAc,aAAqB,OAA8B;AAAA,MAEvF,IAAI,QAAQ,aAAa,aAAa,QAAQ,QAAQ,UAAU;AAAA,QAC9D;AAAA,MACF;AAAA,MAEA,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,YAAY,MAAM,IAAI,GAAG,KAAK,IAAI;AAAA,QAClC,MAAM;AAAA,QACN;AAAA;AAAA,MAGF,MAAM,QAAQ,UAAU,YAAY;AAAA,MACpC,MAAM,SAAS,UAAU,OAAO;AAAA,MAChC,MAAM,WAAW,IAAI,GAAG,SAAS,IAAI;AAAA,MAGrC,IAAI,UAAU;AAAA,MAGd,IAAI,QAAQ,SAAS,OAAO,CAAC,QAAQ;AAAA,QACnC,UAAU;AAAA,MACZ,EAAO,SAAI,QAAQ,SAAS,OAAO,CAAC,OAAO;AAAA,QACzC,UAAU;AAAA,MACZ;AAAA,MAGA,IAAI,WAAW,QAAQ,gBAAgB,WAAW;AAAA,QAChD,IAAI,CAAC,UAAU,QAAQ,aAAa,UAAU,QAAQ,cAAc,GAAG;AAAA,UACrE,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MAGA,IAAI,YAAY,QAAQ,aAAa,aAAa,SAAS,QAAQ,WAAW;AAAA,QAC5E,MAAM,IAAI,OAAO,UAAU,cAAc;AAAA,CAAI;AAAA,MAC/C;AAAA,MAGA,IAAI,OAAO;AAAA,QACT,IAAI;AAAA,UACF,MAAM,UAAU,MAAM,IAAI,GAAG,QAAQ,IAAI;AAAA,UACzC,QAAQ,KAAK;AAAA,UACb,WAAW,SAAS,SAAS;AAAA,YAC3B,MAAM,YAAY,IAAI,GAAG,QAAQ,MAAM,KAAK;AAAA,YAC5C,MAAM,mBAAmB,gBAAgB,MAAM,QAAQ,GAAG,eAAe;AAAA,YACzE,MAAM,SAAS,WAAW,kBAAkB,QAAQ,CAAC;AAAA,UACvD;AAAA,UACA,MAAM;AAAA,MAGV;AAAA;AAAA,IAMF,IAAI,KAAK,OAAO,GAAG;AAAA,MAEjB,IAAI,UAAU;AAAA,MAEd,IAAI,QAAQ,SAAS,KAAK;AAAA,QACxB,UAAU;AAAA,MACZ;AAAA,MAEA,IAAI,WAAW,QAAQ,gBAAgB,WAAW;AAAA,QAChD,MAAM,WAAW,IAAI,GAAG,SAAS,aAAa;AAAA,QAC9C,IAAI,CAAC,UAAU,QAAQ,aAAa,UAAU,QAAQ,cAAc,GAAG;AAAA,UACrE,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MAEA,IAAI,QAAQ,aAAa,aAAa,QAAQ,WAAW,GAAG;AAAA,QAC1D,UAAU;AAAA,MACZ;AAAA,MAEA,IAAI,YAAY,QAAQ,aAAa,aAAa,QAAQ,YAAY,IAAI;AAAA,QACxE,MAAM,IAAI,OAAO,UAAU,iBAAiB;AAAA,CAAI;AAAA,MAClD;AAAA,IACF,EAAO;AAAA,MACL,MAAM,SAAS,eAAe,gBAAgB,CAAC;AAAA;AAAA,EAEnD;AAAA,EAEA,OAAO,WAAW,IAAI;AAAA;",
8
- "debugId": "079983875D7F5C7264756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,SAAS,SAAS,CAAC,SAAiB,KAAa,kBAAkB,OAAgB;AAAA,EACjF,IAAI,iBAAiB;AAAA,IACnB,UAAU,QAAQ,YAAY;AAAA,IAC9B,MAAM,IAAI,YAAY;AAAA,EACxB;AAAA,EAGA,IAAI,QAAQ;AAAA,EACZ,SAAS,IAAI,EAAG,IAAI,QAAQ,QAAQ,KAAK;AAAA,IACvC,MAAM,IAAI,QAAQ;AAAA,IAClB,QAAQ;AAAA,WACD;AAAA,QACH,SAAS;AAAA,QACT;AAAA,WACG;AAAA,QACH,SAAS;AAAA,QACT;AAAA,WACG,KAAK;AAAA,QAER,IAAI,IAAI,IAAI;AAAA,QAEZ,IAAI,QAAQ,OAAO,OAAO,QAAQ,OAAO;AAAA,UAAK;AAAA,QAE9C,IAAI,QAAQ,OAAO;AAAA,UAAK;AAAA,QACxB,OAAO,IAAI,QAAQ,UAAU,QAAQ,OAAO;AAAA,UAAK;AAAA,QACjD,IAAI,KAAK,QAAQ,QAAQ;AAAA,UAEvB,SAAS;AAAA,QACX,EAAO;AAAA,UACL,IAAI,YAAY,QAAQ,MAAM,GAAG,IAAI,CAAC;AAAA,UAEtC,YAAY,UAAU,QAAQ,QAAQ,IAAI;AAAA,UAC1C,SAAS;AAAA,UACT,IAAI;AAAA;AAAA,QAEN;AAAA,MACF;AAAA,WACK;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,QACH,SAAS,OAAO;AAAA,QAChB;AAAA;AAAA,QAEA,SAAS;AAAA;AAAA,EAEf;AAAA,EACA,SAAS;AAAA,EAET,IAAI;AAAA,IACF,OAAO,IAAI,OAAO,KAAK,EAAE,KAAK,GAAG;AAAA,IACjC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAaX,SAAS,QAAQ,CAAC,MAAgB,UAAkB,QAAiB,OAAyB;AAAA,EAC5F,QAAQ,KAAK;AAAA,SACN;AAAA,MACH,OAAO;AAAA,SACJ;AAAA,MACH,OAAO,UAAU,KAAK,SAAS,UAAU,KAAK,UAAU;AAAA,SACrD;AAAA,MACH,OAAO,KAAK,UAAU,MAAM,SAAS;AAAA,SAClC;AAAA,MACH,OAAO,SAAS,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,SAAS,KAAK,OAAO,UAAU,QAAQ,KAAK;AAAA,SAChG;AAAA,MACH,OAAO,SAAS,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,SAAS,KAAK,OAAO,UAAU,QAAQ,KAAK;AAAA,SAChG;AAAA,MACH,OAAO,CAAC,SAAS,KAAK,MAAM,UAAU,QAAQ,KAAK;AAAA;AAAA;AAAA;AAIzD,MAAM,mBAAmB,MAAM;AAAA,EAC7B,WAAW,CAAC,KAAa;AAAA,IACvB,MAAM,GAAG;AAAA;AAEb;AAEA,SAAS,aAAa,CAAC,MAA0B;AAAA,EAC/C,IAAI,KAAK,WAAW;AAAA,IAAG,OAAO,EAAE,MAAM,OAAO;AAAA,EAE7C,IAAI,MAAM;AAAA,EAEV,SAAS,IAAI,GAAuB;AAAA,IAClC,OAAO,KAAK;AAAA;AAAA,EAGd,SAAS,OAAO,GAAW;AAAA,IACzB,OAAO,KAAK;AAAA;AAAA,EAGd,SAAS,OAAO,GAAa;AAAA,IAC3B,IAAI,OAAO,SAAS;AAAA,IACpB,OAAO,KAAK,MAAM,MAAM;AAAA,MACtB,QAAQ;AAAA,MACR,MAAM,QAAQ,SAAS;AAAA,MACvB,OAAO,EAAE,MAAM,MAAM,MAAM,MAAM;AAAA,IACnC;AAAA,IACA,OAAO;AAAA;AAAA,EAGT,SAAS,QAAQ,GAAa;AAAA,IAC5B,IAAI,OAAO,WAAW;AAAA,IACtB,OAAO,MAAM,KAAK,QAAQ;AAAA,MACxB,MAAM,OAAO,KAAK;AAAA,MAClB,IAAI,SAAS,QAAQ,SAAS,OAAO,SAAS;AAAA,QAAW;AAAA,MACzD,IAAI,SAAS,MAAM;AAAA,QACjB,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,QAAQ,WAAW;AAAA,MACzB,OAAO,EAAE,MAAM,OAAO,MAAM,MAAM;AAAA,IACpC;AAAA,IACA,OAAO;AAAA;AAAA,EAGT,SAAS,UAAU,GAAa;AAAA,IAC9B,MAAM,OAAO,KAAK;AAAA,IAClB,IAAI,SAAS,OAAO,SAAS,QAAQ;AAAA,MACnC,QAAQ;AAAA,MACR,MAAM,QAAO,WAAW;AAAA,MACxB,OAAO,EAAE,MAAM,OAAO,YAAK;AAAA,IAC7B;AAAA,IACA,OAAO,aAAa;AAAA;AAAA,EAGtB,SAAS,YAAY,GAAa;AAAA,IAChC,MAAM,MAAM,KAAK;AAAA,IACjB,IAAI,QAAQ,WAAW;AAAA,MACrB,MAAM,IAAI,WAAW,2BAA2B;AAAA,IAClD;AAAA,IAEA,IAAI,QAAQ,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,MAAM,QAAO,QAAQ;AAAA,MACrB,IAAI,KAAK,MAAM,KAAK;AAAA,QAClB,MAAM,IAAI,WAAW,2BAA2B;AAAA,MAClD;AAAA,MACA,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IAEA,IAAI,QAAQ,WAAW,QAAQ,UAAU;AAAA,MACvC,QAAQ;AAAA,MACR,MAAM,UAAU,KAAK;AAAA,MACrB,IAAI,YAAY,WAAW;AAAA,QACzB,MAAM,IAAI,WAAW,8BAA8B,MAAM;AAAA,MAC3D;AAAA,MACA,QAAQ;AAAA,MACR,OAAO,EAAE,MAAM,QAAQ,SAAS,YAAY,QAAQ,SAAS;AAAA,IAC/D;AAAA,IAEA,IAAI,QAAQ,SAAS;AAAA,MACnB,QAAQ;AAAA,MACR,MAAM,MAAM,KAAK;AAAA,MACjB,IAAI,QAAQ,WAAW;AAAA,QACrB,MAAM,IAAI,WAAW,mCAAmC;AAAA,MAC1D;AAAA,MACA,IAAI,QAAQ,OAAO,QAAQ,KAAK;AAAA,QAC9B,MAAM,IAAI,WAAW,oCAAoC,KAAK;AAAA,MAChE;AAAA,MACA,QAAQ;AAAA,MACR,OAAO,EAAE,MAAM,SAAS,OAAO,IAAI;AAAA,IACrC;AAAA,IAEA,MAAM,IAAI,WAAW,4BAA4B,MAAM;AAAA;AAAA,EAGzD,MAAM,OAAO,QAAQ;AAAA,EACrB,IAAI,MAAM,KAAK,QAAQ;AAAA,IACrB,MAAM,IAAI,WAAW,qBAAqB,KAAK,OAAO;AAAA,EACxD;AAAA,EACA,OAAO;AAAA;AAGF,IAAM,OAAgB,OAAO,QAAQ;AAAA,EAC1C,MAAM,OAAO,CAAC,GAAG,IAAI,IAAI;AAAA,EACzB,MAAM,QAAkB,CAAC;AAAA,EAGzB,IAAI,IAAI;AAAA,EAGR,OAAO,IAAI,KAAK,UAAU,CAAC,KAAK,GAAI,WAAW,GAAG,KAAK,KAAK,OAAO,OAAO,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK;AAAA,IAC5G,MAAM,KAAK,KAAK,EAAG;AAAA,IACnB;AAAA,EACF;AAAA,EAGA,IAAI,MAAM,WAAW,GAAG;AAAA,IACtB,MAAM,KAAK,GAAG;AAAA,EAChB;AAAA,EAGA,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM,WAAqB,CAAC;AAAA,EAE5B,IAAI,IAAI;AAAA,EACR,OAAO,IAAI,KAAK,QAAQ;AAAA,IACtB,MAAM,MAAM,KAAK;AAAA,IACjB,IAAI,QAAQ,aAAa;AAAA,MACvB;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAyC;AAAA,QACpE,OAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,SAAS,KAAK,IAAK,EAAE;AAAA,MACnC,IAAI,MAAM,KAAK,KAAK,QAAQ,GAAG;AAAA,QAC7B,MAAM,IAAI,OAAO,UAAU,2BAA2B,KAAK;AAAA,CAAoB;AAAA,QAC/E,OAAO;AAAA,MACT;AAAA,MACA,WAAW;AAAA,IACb,EAAO,SAAI,QAAQ,aAAa;AAAA,MAC9B;AAAA,MACA,IAAI,KAAK,KAAK,QAAQ;AAAA,QACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAyC;AAAA,QACpE,OAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,SAAS,KAAK,IAAK,EAAE;AAAA,MACnC,IAAI,MAAM,KAAK,KAAK,QAAQ,GAAG;AAAA,QAC7B,MAAM,IAAI,OAAO,UAAU,2BAA2B,KAAK;AAAA,CAAoB;AAAA,QAC/E,OAAO;AAAA,MACT;AAAA,MACA,WAAW;AAAA,IACb,EAAO;AAAA,MACL,SAAS,KAAK,GAAG;AAAA;AAAA,IAEnB;AAAA,EACF;AAAA,EAGA,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,OAAO,cAAc,QAAQ;AAAA,IAC7B,OAAO,GAAG;AAAA,IACV,IAAI,aAAa,YAAY;AAAA,MAC3B,MAAM,IAAI,OAAO,UAAU,EAAE,UAAU;AAAA,CAAI;AAAA,MAC3C,OAAO;AAAA,IACT;AAAA,IACA,MAAM;AAAA;AAAA,EAGR,IAAI,WAAW;AAAA,EAGf,WAAW,aAAa,OAAO;AAAA,IAC7B,MAAM,iBAAiB,cAAc,MAAM,MAAM,UAAU,QAAQ,QAAQ,EAAE;AAAA,IAC7E,MAAM,gBAAgB,IAAI,GAAG,QAAQ,IAAI,KAAK,SAAS;AAAA,IAGvD,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,OAAO,MAAM,IAAI,GAAG,KAAK,aAAa;AAAA,MACtC,MAAM;AAAA,MACN,MAAM,IAAI,OAAO,UAAU,UAAU;AAAA,CAAyC;AAAA,MAC9E,WAAW;AAAA,MACX;AAAA;AAAA,IAIF,eAAe,QAAQ,CAAC,MAAc,aAAqB,OAA8B;AAAA,MAEvF,IAAI,aAAa,aAAa,QAAQ,UAAU;AAAA,QAC9C;AAAA,MACF;AAAA,MAEA,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,YAAY,MAAM,IAAI,GAAG,KAAK,IAAI;AAAA,QAClC,MAAM;AAAA,QACN;AAAA;AAAA,MAGF,MAAM,QAAQ,UAAU,YAAY;AAAA,MACpC,MAAM,SAAS,UAAU,OAAO;AAAA,MAChC,MAAM,WAAW,IAAI,GAAG,SAAS,IAAI;AAAA,MAGrC,MAAM,UAAU,SAAS,MAAM,UAAU,QAAQ,KAAK;AAAA,MAGtD,IAAI,YAAY,aAAa,aAAa,SAAS,WAAW;AAAA,QAC5D,MAAM,IAAI,OAAO,UAAU,cAAc;AAAA,CAAI;AAAA,MAC/C;AAAA,MAGA,IAAI,OAAO;AAAA,QACT,IAAI;AAAA,UACF,MAAM,UAAU,MAAM,IAAI,GAAG,QAAQ,IAAI;AAAA,UACzC,QAAQ,KAAK;AAAA,UACb,WAAW,SAAS,SAAS;AAAA,YAC3B,MAAM,YAAY,IAAI,GAAG,QAAQ,MAAM,KAAK;AAAA,YAC5C,MAAM,mBAAmB,gBAAgB,MAAM,QAAQ,GAAG,eAAe;AAAA,YACzE,MAAM,SAAS,WAAW,kBAAkB,QAAQ,CAAC;AAAA,UACvD;AAAA,UACA,MAAM;AAAA,MAGV;AAAA;AAAA,IAIF,IAAI,KAAK,OAAO,GAAG;AAAA,MACjB,MAAM,WAAW,IAAI,GAAG,SAAS,aAAa;AAAA,MAC9C,MAAM,UAAU,SAAS,MAAM,UAAU,MAAM,KAAK;AAAA,MAEpD,IAAI,aAAa,aAAa,WAAW,GAAG,CAE5C,EAAO,SAAI,YAAY,aAAa,aAAa,YAAY,IAAI;AAAA,QAC/D,MAAM,IAAI,OAAO,UAAU,iBAAiB;AAAA,CAAI;AAAA,MAClD;AAAA,IACF,EAAO;AAAA,MACL,MAAM,SAAS,eAAe,gBAAgB,CAAC;AAAA;AAAA,EAEnD;AAAA,EAEA,OAAO,WAAW,IAAI;AAAA;",
8
+ "debugId": "80CE5607A2F2B89F64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -38,11 +38,12 @@ var spec = {
38
38
  flags: [
39
39
  { short: "a", long: "all" },
40
40
  { short: "l" },
41
- { short: "1" }
41
+ { short: "1" },
42
+ { short: "R" }
42
43
  ],
43
- usage: "ls [-al1] [file ...]"
44
+ usage: "ls [-alR1] [file ...]"
44
45
  };
45
- var defaults = { all: false, long: false, onePerLine: false };
46
+ var defaults = { all: false, long: false, onePerLine: false, recursive: false };
46
47
  var handler = (flags, flag) => {
47
48
  if (flag.short === "a")
48
49
  flags.all = true;
@@ -50,6 +51,8 @@ var handler = (flags, flag) => {
50
51
  flags.long = true;
51
52
  if (flag.short === "1")
52
53
  flags.onePerLine = true;
54
+ if (flag.short === "R")
55
+ flags.recursive = true;
53
56
  };
54
57
  var parser = import_flag_parser.createFlagParser(spec, defaults, handler);
55
58
  var ls = async (ctx) => {
@@ -58,8 +61,63 @@ var ls = async (ctx) => {
58
61
  await parser.writeError(result.error, ctx.stderr);
59
62
  return 1;
60
63
  }
61
- const { all: showAll, long: longFormat, onePerLine } = result.flags;
64
+ const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;
62
65
  const paths = result.args.length === 0 ? ["."] : result.args;
66
+ let needsBlankLine = false;
67
+ const listDir = async (dirPath, displayPath, showHeader) => {
68
+ if (needsBlankLine)
69
+ await ctx.stdout.writeText(`
70
+ `);
71
+ needsBlankLine = true;
72
+ if (showHeader) {
73
+ await ctx.stdout.writeText(`${displayPath}:
74
+ `);
75
+ }
76
+ let entries = await ctx.fs.readdir(dirPath);
77
+ if (!showAll) {
78
+ entries = entries.filter((e) => !e.startsWith("."));
79
+ }
80
+ entries.sort();
81
+ if (longFormat) {
82
+ for (const entry of entries) {
83
+ const entryPath = ctx.fs.resolve(dirPath, entry);
84
+ try {
85
+ const entryStat = await ctx.fs.stat(entryPath);
86
+ const type = entryStat.isDirectory() ? "d" : "-";
87
+ const perms = "rwxr-xr-x";
88
+ const size = String(entryStat.size).padStart(8);
89
+ const date = entryStat.mtime.toISOString().slice(0, 10);
90
+ await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}
91
+ `);
92
+ } catch {
93
+ await ctx.stdout.writeText(`?????????? ${entry}
94
+ `);
95
+ }
96
+ }
97
+ } else if (onePerLine) {
98
+ for (const entry of entries) {
99
+ await ctx.stdout.writeText(entry + `
100
+ `);
101
+ }
102
+ } else {
103
+ if (entries.length > 0) {
104
+ await ctx.stdout.writeText(entries.join(" ") + `
105
+ `);
106
+ }
107
+ }
108
+ if (recursive) {
109
+ for (const entry of entries) {
110
+ const entryPath = ctx.fs.resolve(dirPath, entry);
111
+ try {
112
+ const entryStat = await ctx.fs.stat(entryPath);
113
+ if (entryStat.isDirectory()) {
114
+ const subDisplay = displayPath === "." ? entry : `${displayPath}/${entry}`;
115
+ await listDir(entryPath, subDisplay, true);
116
+ }
117
+ } catch {}
118
+ }
119
+ }
120
+ };
63
121
  for (let i = 0;i < paths.length; i++) {
64
122
  const pathArg = paths[i];
65
123
  const path = ctx.fs.resolve(ctx.cwd, pathArg);
@@ -70,43 +128,8 @@ var ls = async (ctx) => {
70
128
  `);
71
129
  continue;
72
130
  }
73
- if (paths.length > 1) {
74
- if (i > 0)
75
- await ctx.stdout.writeText(`
76
- `);
77
- await ctx.stdout.writeText(`${pathArg}:
78
- `);
79
- }
80
- let entries = await ctx.fs.readdir(path);
81
- if (!showAll) {
82
- entries = entries.filter((e) => !e.startsWith("."));
83
- }
84
- entries.sort();
85
- if (longFormat) {
86
- for (const entry of entries) {
87
- const entryPath = ctx.fs.resolve(path, entry);
88
- try {
89
- const entryStat = await ctx.fs.stat(entryPath);
90
- const type = entryStat.isDirectory() ? "d" : "-";
91
- const perms = "rwxr-xr-x";
92
- const size = String(entryStat.size).padStart(8);
93
- const date = entryStat.mtime.toISOString().slice(0, 10);
94
- await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}
95
- `);
96
- } catch {
97
- await ctx.stdout.writeText(`?????????? ${entry}
98
- `);
99
- }
100
- }
101
- } else if (onePerLine) {
102
- for (const entry of entries) {
103
- await ctx.stdout.writeText(entry + `
104
- `);
105
- }
106
- } else {
107
- await ctx.stdout.writeText(entries.join(" ") + `
108
- `);
109
- }
131
+ const showHeader = recursive || paths.length > 1;
132
+ await listDir(path, pathArg, showHeader);
110
133
  } catch (err) {
111
134
  await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory
112
135
  `);
@@ -116,4 +139,4 @@ var ls = async (ctx) => {
116
139
  return 0;
117
140
  };
118
141
 
119
- //# debugId=4890CAC52EAF1A2264756E2164756E21
142
+ //# debugId=5A080C64ADFFC97C64756E2164756E21
@@ -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}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n ] as FlagDefinition[],\n usage: \"ls [-al1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: 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};\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 } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\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 // It's a file, just print the name\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n // It's a directory\n if (paths.length > 1) {\n if (i > 0) await ctx.stdout.writeText(\"\\n\");\n await ctx.stdout.writeText(`${pathArg}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(path);\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(path, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\"; // Simplified permissions\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 // Default: space-separated\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\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) {\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": "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",
8
- "debugId": "4890CAC52EAF1A2264756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5A080C64ADFFC97C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "module"
5
5
  }
@@ -55,88 +55,173 @@ function matchGlob(pattern, str, caseInsensitive = false) {
55
55
  return false;
56
56
  }
57
57
  }
58
+ function evalExpr(expr, basename, isFile, isDir) {
59
+ switch (expr.type) {
60
+ case "true":
61
+ return true;
62
+ case "name":
63
+ return matchGlob(expr.pattern, basename, expr.ignoreCase);
64
+ case "ftype":
65
+ return expr.value === "f" ? isFile : isDir;
66
+ case "and":
67
+ return evalExpr(expr.left, basename, isFile, isDir) && evalExpr(expr.right, basename, isFile, isDir);
68
+ case "or":
69
+ return evalExpr(expr.left, basename, isFile, isDir) || evalExpr(expr.right, basename, isFile, isDir);
70
+ case "not":
71
+ return !evalExpr(expr.expr, basename, isFile, isDir);
72
+ }
73
+ }
74
+
75
+ class ParseError extends Error {
76
+ constructor(msg) {
77
+ super(msg);
78
+ }
79
+ }
80
+ function parseExprArgs(args) {
81
+ if (args.length === 0)
82
+ return { type: "true" };
83
+ let pos = 0;
84
+ function peek() {
85
+ return args[pos];
86
+ }
87
+ function advance() {
88
+ return args[pos++];
89
+ }
90
+ function parseOr() {
91
+ let left = parseAnd();
92
+ while (peek() === "-o") {
93
+ advance();
94
+ const right = parseAnd();
95
+ left = { type: "or", left, right };
96
+ }
97
+ return left;
98
+ }
99
+ function parseAnd() {
100
+ let left = parseUnary();
101
+ while (pos < args.length) {
102
+ const next = peek();
103
+ if (next === "-o" || next === ")" || next === undefined)
104
+ break;
105
+ if (next === "-a") {
106
+ advance();
107
+ }
108
+ const right = parseUnary();
109
+ left = { type: "and", left, right };
110
+ }
111
+ return left;
112
+ }
113
+ function parseUnary() {
114
+ const next = peek();
115
+ if (next === "!" || next === "-not") {
116
+ advance();
117
+ const expr2 = parseUnary();
118
+ return { type: "not", expr: expr2 };
119
+ }
120
+ return parsePrimary();
121
+ }
122
+ function parsePrimary() {
123
+ const tok = peek();
124
+ if (tok === undefined) {
125
+ throw new ParseError("find: expected expression");
126
+ }
127
+ if (tok === "(") {
128
+ advance();
129
+ const expr2 = parseOr();
130
+ if (peek() !== ")") {
131
+ throw new ParseError("find: missing closing ')'");
132
+ }
133
+ advance();
134
+ return expr2;
135
+ }
136
+ if (tok === "-name" || tok === "-iname") {
137
+ advance();
138
+ const pattern = peek();
139
+ if (pattern === undefined) {
140
+ throw new ParseError(`find: missing argument to '${tok}'`);
141
+ }
142
+ advance();
143
+ return { type: "name", pattern, ignoreCase: tok === "-iname" };
144
+ }
145
+ if (tok === "-type") {
146
+ advance();
147
+ const val = peek();
148
+ if (val === undefined) {
149
+ throw new ParseError("find: missing argument to '-type'");
150
+ }
151
+ if (val !== "f" && val !== "d") {
152
+ throw new ParseError(`find: Unknown argument to -type: ${val}`);
153
+ }
154
+ advance();
155
+ return { type: "ftype", value: val };
156
+ }
157
+ throw new ParseError(`find: unknown predicate '${tok}'`);
158
+ }
159
+ const expr = parseOr();
160
+ if (pos < args.length) {
161
+ throw new ParseError(`find: unexpected '${args[pos]}'`);
162
+ }
163
+ return expr;
164
+ }
58
165
  var find = async (ctx) => {
59
166
  const args = [...ctx.args];
60
167
  const paths = [];
61
- const options = {};
62
168
  let i = 0;
63
- while (i < args.length && !args[i].startsWith("-")) {
169
+ while (i < args.length && !args[i].startsWith("-") && args[i] !== "!" && args[i] !== "(" && args[i] !== ")") {
64
170
  paths.push(args[i]);
65
171
  i++;
66
172
  }
67
173
  if (paths.length === 0) {
68
174
  paths.push(".");
69
175
  }
70
- while (i < args.length) {
71
- const arg = args[i];
72
- if (arg === "-name") {
73
- i++;
74
- if (i >= args.length) {
75
- await ctx.stderr.writeText(`find: missing argument to '-name'
76
- `);
77
- return 1;
78
- }
79
- options.namePattern = args[i];
80
- options.nameIgnoreCase = false;
81
- } else if (arg === "-iname") {
82
- i++;
83
- if (i >= args.length) {
84
- await ctx.stderr.writeText(`find: missing argument to '-iname'
85
- `);
86
- return 1;
87
- }
88
- options.namePattern = args[i];
89
- options.nameIgnoreCase = true;
90
- } else if (arg === "-type") {
91
- i++;
92
- if (i >= args.length) {
93
- await ctx.stderr.writeText(`find: missing argument to '-type'
94
- `);
95
- return 1;
96
- }
97
- const typeArg = args[i];
98
- if (typeArg !== "f" && typeArg !== "d") {
99
- await ctx.stderr.writeText(`find: Unknown argument to -type: ${typeArg}
100
- `);
101
- return 1;
102
- }
103
- options.type = typeArg;
104
- } else if (arg === "-maxdepth") {
105
- i++;
106
- if (i >= args.length) {
176
+ let maxDepth;
177
+ let minDepth;
178
+ const exprArgs = [];
179
+ let j = i;
180
+ while (j < args.length) {
181
+ const arg = args[j];
182
+ if (arg === "-maxdepth") {
183
+ j++;
184
+ if (j >= args.length) {
107
185
  await ctx.stderr.writeText(`find: missing argument to '-maxdepth'
108
186
  `);
109
187
  return 1;
110
188
  }
111
- const depth = parseInt(args[i], 10);
189
+ const depth = parseInt(args[j], 10);
112
190
  if (isNaN(depth) || depth < 0) {
113
- await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -maxdepth
191
+ await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth
114
192
  `);
115
193
  return 1;
116
194
  }
117
- options.maxDepth = depth;
195
+ maxDepth = depth;
118
196
  } else if (arg === "-mindepth") {
119
- i++;
120
- if (i >= args.length) {
197
+ j++;
198
+ if (j >= args.length) {
121
199
  await ctx.stderr.writeText(`find: missing argument to '-mindepth'
122
200
  `);
123
201
  return 1;
124
202
  }
125
- const depth = parseInt(args[i], 10);
203
+ const depth = parseInt(args[j], 10);
126
204
  if (isNaN(depth) || depth < 0) {
127
- await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -mindepth
205
+ await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth
128
206
  `);
129
207
  return 1;
130
208
  }
131
- options.minDepth = depth;
132
- } else if (arg.startsWith("-")) {
133
- await ctx.stderr.writeText(`find: unknown predicate '${arg}'
209
+ minDepth = depth;
210
+ } else {
211
+ exprArgs.push(arg);
212
+ }
213
+ j++;
214
+ }
215
+ let expr;
216
+ try {
217
+ expr = parseExprArgs(exprArgs);
218
+ } catch (e) {
219
+ if (e instanceof ParseError) {
220
+ await ctx.stderr.writeText(e.message + `
134
221
  `);
135
222
  return 1;
136
- } else {
137
- paths.push(arg);
138
223
  }
139
- i++;
224
+ throw e;
140
225
  }
141
226
  let hasError = false;
142
227
  for (const startPath of paths) {
@@ -152,7 +237,7 @@ var find = async (ctx) => {
152
237
  continue;
153
238
  }
154
239
  async function traverse(path, displayPath, depth) {
155
- if (options.maxDepth !== undefined && depth > options.maxDepth) {
240
+ if (maxDepth !== undefined && depth > maxDepth) {
156
241
  return;
157
242
  }
158
243
  let entryStat;
@@ -164,18 +249,8 @@ var find = async (ctx) => {
164
249
  const isDir = entryStat.isDirectory();
165
250
  const isFile = entryStat.isFile();
166
251
  const basename = ctx.fs.basename(path);
167
- let matches = true;
168
- if (options.type === "f" && !isFile) {
169
- matches = false;
170
- } else if (options.type === "d" && !isDir) {
171
- matches = false;
172
- }
173
- if (matches && options.namePattern !== undefined) {
174
- if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {
175
- matches = false;
176
- }
177
- }
178
- if (matches && (options.minDepth === undefined || depth >= options.minDepth)) {
252
+ const matches = evalExpr(expr, basename, isFile, isDir);
253
+ if (matches && (minDepth === undefined || depth >= minDepth)) {
179
254
  await ctx.stdout.writeText(displayPath + `
180
255
  `);
181
256
  }
@@ -192,20 +267,9 @@ var find = async (ctx) => {
192
267
  }
193
268
  }
194
269
  if (stat.isFile()) {
195
- let matches = true;
196
- if (options.type === "d") {
197
- matches = false;
198
- }
199
- if (matches && options.namePattern !== undefined) {
200
- const basename = ctx.fs.basename(resolvedStart);
201
- if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {
202
- matches = false;
203
- }
204
- }
205
- if (options.maxDepth !== undefined && options.maxDepth < 0) {
206
- matches = false;
207
- }
208
- if (matches && (options.minDepth === undefined || options.minDepth <= 0)) {
270
+ const basename = ctx.fs.basename(resolvedStart);
271
+ const matches = evalExpr(expr, basename, true, false);
272
+ if (maxDepth !== undefined && maxDepth < 0) {} else if (matches && (minDepth === undefined || minDepth <= 0)) {
209
273
  await ctx.stdout.writeText(normalizedPath + `
210
274
  `);
211
275
  }
@@ -219,4 +283,4 @@ export {
219
283
  find
220
284
  };
221
285
 
222
- //# debugId=DA671804DAD6CB3364756E2164756E21
286
+ //# debugId=5D73614E490180B964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/commands/find/find.ts"],
4
4
  "sourcesContent": [
5
- "import type { Command } from \"../../types.mjs\";\n\n/**\n * Simple glob pattern matching (fnmatch-style)\n * Supports: * (any chars), ? (single char), [...] (character class)\n */\nfunction matchGlob(pattern: string, str: string, caseInsensitive = false): boolean {\n if (caseInsensitive) {\n pattern = pattern.toLowerCase();\n str = str.toLowerCase();\n }\n\n // Convert glob to regex\n let regex = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const c = pattern[i]!;\n switch (c) {\n case \"*\":\n regex += \".*\";\n break;\n case \"?\":\n regex += \".\";\n break;\n case \"[\": {\n // Find closing bracket\n let j = i + 1;\n // Handle negation\n if (pattern[j] === \"!\" || pattern[j] === \"^\") j++;\n // Handle ] as first char in class\n if (pattern[j] === \"]\") j++;\n while (j < pattern.length && pattern[j] !== \"]\") j++;\n if (j >= pattern.length) {\n // No closing bracket, treat [ as literal\n regex += \"\\\\[\";\n } else {\n let charClass = pattern.slice(i, j + 1);\n // Convert ! to ^ for negation in regex\n charClass = charClass.replace(/^\\[!/, \"[^\");\n regex += charClass;\n i = j;\n }\n break;\n }\n case \".\":\n case \"^\":\n case \"$\":\n case \"+\":\n case \"{\":\n case \"}\":\n case \"(\":\n case \")\":\n case \"|\":\n case \"\\\\\":\n regex += \"\\\\\" + c;\n break;\n default:\n regex += c;\n }\n }\n regex += \"$\";\n\n try {\n return new RegExp(regex).test(str);\n } catch {\n return false;\n }\n}\n\ninterface FindOptions {\n namePattern?: string;\n nameIgnoreCase?: boolean;\n type?: \"f\" | \"d\";\n maxDepth?: number;\n minDepth?: number;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n const options: FindOptions = {};\n\n // Parse arguments: paths come before first flag, then expressions\n let i = 0;\n\n // Collect paths (args before first -)\n while (i < args.length && !args[i]!.startsWith(\"-\")) {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Parse expression flags\n while (i < args.length) {\n const arg = args[i]!;\n\n if (arg === \"-name\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-name'\\n\");\n return 1;\n }\n options.namePattern = args[i]!;\n options.nameIgnoreCase = false;\n } else if (arg === \"-iname\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-iname'\\n\");\n return 1;\n }\n options.namePattern = args[i]!;\n options.nameIgnoreCase = true;\n } else if (arg === \"-type\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-type'\\n\");\n return 1;\n }\n const typeArg = args[i]!;\n if (typeArg !== \"f\" && typeArg !== \"d\") {\n await ctx.stderr.writeText(`find: Unknown argument to -type: ${typeArg}\\n`);\n return 1;\n }\n options.type = typeArg;\n } else if (arg === \"-maxdepth\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[i]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -maxdepth\\n`);\n return 1;\n }\n options.maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n i++;\n if (i >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[i]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[i]}' to -mindepth\\n`);\n return 1;\n }\n options.minDepth = depth;\n } else if (arg.startsWith(\"-\")) {\n await ctx.stderr.writeText(`find: unknown predicate '${arg}'\\n`);\n return 1;\n } else {\n // This shouldn't happen since paths are parsed first, but treat as path\n paths.push(arg);\n }\n\n i++;\n }\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (options.maxDepth !== undefined && depth > options.maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n\n // Check if this entry matches filters\n let matches = true;\n\n // Type filter\n if (options.type === \"f\" && !isFile) {\n matches = false;\n } else if (options.type === \"d\" && !isDir) {\n matches = false;\n }\n\n // Name filter (only check basename)\n if (matches && options.namePattern !== undefined) {\n if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {\n matches = false;\n }\n }\n\n // Output if matches and above mindepth\n if (matches && (options.minDepth === undefined || depth >= options.minDepth)) {\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n // For a single file, it's at depth 0\n // For a directory, the directory itself is depth 0, contents are depth 1+\n if (stat.isFile()) {\n // Starting from a file - depth 0\n let matches = true;\n\n if (options.type === \"d\") {\n matches = false;\n }\n\n if (matches && options.namePattern !== undefined) {\n const basename = ctx.fs.basename(resolvedStart);\n if (!matchGlob(options.namePattern, basename, options.nameIgnoreCase)) {\n matches = false;\n }\n }\n\n if (options.maxDepth !== undefined && options.maxDepth < 0) {\n matches = false;\n }\n\n if (matches && (options.minDepth === undefined || options.minDepth <= 0)) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
5
+ "import type { Command } from \"../../types.mjs\";\n\n/**\n * Simple glob pattern matching (fnmatch-style)\n * Supports: * (any chars), ? (single char), [...] (character class)\n */\nfunction matchGlob(pattern: string, str: string, caseInsensitive = false): boolean {\n if (caseInsensitive) {\n pattern = pattern.toLowerCase();\n str = str.toLowerCase();\n }\n\n // Convert glob to regex\n let regex = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const c = pattern[i]!;\n switch (c) {\n case \"*\":\n regex += \".*\";\n break;\n case \"?\":\n regex += \".\";\n break;\n case \"[\": {\n // Find closing bracket\n let j = i + 1;\n // Handle negation\n if (pattern[j] === \"!\" || pattern[j] === \"^\") j++;\n // Handle ] as first char in class\n if (pattern[j] === \"]\") j++;\n while (j < pattern.length && pattern[j] !== \"]\") j++;\n if (j >= pattern.length) {\n // No closing bracket, treat [ as literal\n regex += \"\\\\[\";\n } else {\n let charClass = pattern.slice(i, j + 1);\n // Convert ! to ^ for negation in regex\n charClass = charClass.replace(/^\\[!/, \"[^\");\n regex += charClass;\n i = j;\n }\n break;\n }\n case \".\":\n case \"^\":\n case \"$\":\n case \"+\":\n case \"{\":\n case \"}\":\n case \"(\":\n case \")\":\n case \"|\":\n case \"\\\\\":\n regex += \"\\\\\" + c;\n break;\n default:\n regex += c;\n }\n }\n regex += \"$\";\n\n try {\n return new RegExp(regex).test(str);\n } catch {\n return false;\n }\n}\n\n// Expression tree types\ntype FindExpr =\n | { type: \"name\"; pattern: string; ignoreCase: boolean }\n | { type: \"ftype\"; value: \"f\" | \"d\" }\n | { type: \"and\"; left: FindExpr; right: FindExpr }\n | { type: \"or\"; left: FindExpr; right: FindExpr }\n | { type: \"not\"; expr: FindExpr }\n | { type: \"true\" };\n\nfunction evalExpr(expr: FindExpr, basename: string, isFile: boolean, isDir: boolean): boolean {\n switch (expr.type) {\n case \"true\":\n return true;\n case \"name\":\n return matchGlob(expr.pattern, basename, expr.ignoreCase);\n case \"ftype\":\n return expr.value === \"f\" ? isFile : isDir;\n case \"and\":\n return evalExpr(expr.left, basename, isFile, isDir) && evalExpr(expr.right, basename, isFile, isDir);\n case \"or\":\n return evalExpr(expr.left, basename, isFile, isDir) || evalExpr(expr.right, basename, isFile, isDir);\n case \"not\":\n return !evalExpr(expr.expr, basename, isFile, isDir);\n }\n}\n\nclass ParseError extends Error {\n constructor(msg: string) {\n super(msg);\n }\n}\n\nfunction parseExprArgs(args: string[]): FindExpr {\n if (args.length === 0) return { type: \"true\" };\n\n let pos = 0;\n\n function peek(): string | undefined {\n return args[pos];\n }\n\n function advance(): string {\n return args[pos++]!;\n }\n\n function parseOr(): FindExpr {\n let left = parseAnd();\n while (peek() === \"-o\") {\n advance();\n const right = parseAnd();\n left = { type: \"or\", left, right };\n }\n return left;\n }\n\n function parseAnd(): FindExpr {\n let left = parseUnary();\n while (pos < args.length) {\n const next = peek();\n if (next === \"-o\" || next === \")\" || next === undefined) break;\n if (next === \"-a\") {\n advance();\n }\n const right = parseUnary();\n left = { type: \"and\", left, right };\n }\n return left;\n }\n\n function parseUnary(): FindExpr {\n const next = peek();\n if (next === \"!\" || next === \"-not\") {\n advance();\n const expr = parseUnary();\n return { type: \"not\", expr };\n }\n return parsePrimary();\n }\n\n function parsePrimary(): FindExpr {\n const tok = peek();\n if (tok === undefined) {\n throw new ParseError(\"find: expected expression\");\n }\n\n if (tok === \"(\") {\n advance();\n const expr = parseOr();\n if (peek() !== \")\") {\n throw new ParseError(\"find: missing closing ')'\");\n }\n advance();\n return expr;\n }\n\n if (tok === \"-name\" || tok === \"-iname\") {\n advance();\n const pattern = peek();\n if (pattern === undefined) {\n throw new ParseError(`find: missing argument to '${tok}'`);\n }\n advance();\n return { type: \"name\", pattern, ignoreCase: tok === \"-iname\" };\n }\n\n if (tok === \"-type\") {\n advance();\n const val = peek();\n if (val === undefined) {\n throw new ParseError(\"find: missing argument to '-type'\");\n }\n if (val !== \"f\" && val !== \"d\") {\n throw new ParseError(`find: Unknown argument to -type: ${val}`);\n }\n advance();\n return { type: \"ftype\", value: val };\n }\n\n throw new ParseError(`find: unknown predicate '${tok}'`);\n }\n\n const expr = parseOr();\n if (pos < args.length) {\n throw new ParseError(`find: unexpected '${args[pos]}'`);\n }\n return expr;\n}\n\nexport const find: Command = async (ctx) => {\n const args = [...ctx.args];\n const paths: string[] = [];\n\n // Parse arguments: paths come before first flag/operator\n let i = 0;\n\n // Collect paths (args before first -, !, or ()\n while (i < args.length && !args[i]!.startsWith(\"-\") && args[i] !== \"!\" && args[i] !== \"(\" && args[i] !== \")\") {\n paths.push(args[i]!);\n i++;\n }\n\n // Default to current directory if no paths\n if (paths.length === 0) {\n paths.push(\".\");\n }\n\n // Extract global options (-maxdepth, -mindepth) from remaining args\n let maxDepth: number | undefined;\n let minDepth: number | undefined;\n const exprArgs: string[] = [];\n\n let j = i;\n while (j < args.length) {\n const arg = args[j]!;\n if (arg === \"-maxdepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-maxdepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -maxdepth\\n`);\n return 1;\n }\n maxDepth = depth;\n } else if (arg === \"-mindepth\") {\n j++;\n if (j >= args.length) {\n await ctx.stderr.writeText(\"find: missing argument to '-mindepth'\\n\");\n return 1;\n }\n const depth = parseInt(args[j]!, 10);\n if (isNaN(depth) || depth < 0) {\n await ctx.stderr.writeText(`find: Invalid argument '${args[j]}' to -mindepth\\n`);\n return 1;\n }\n minDepth = depth;\n } else {\n exprArgs.push(arg);\n }\n j++;\n }\n\n // Parse expression tree\n let expr: FindExpr;\n try {\n expr = parseExprArgs(exprArgs);\n } catch (e) {\n if (e instanceof ParseError) {\n await ctx.stderr.writeText(e.message + \"\\n\");\n return 1;\n }\n throw e;\n }\n\n let hasError = false;\n\n // Process each starting path\n for (const startPath of paths) {\n const normalizedPath = startPath === \"/\" ? \"/\" : startPath.replace(/\\/+$/, '');\n const resolvedStart = ctx.fs.resolve(ctx.cwd, startPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedStart);\n } catch {\n await ctx.stderr.writeText(`find: '${startPath}': No such file or directory\\n`);\n hasError = true;\n continue;\n }\n\n // Recursive traversal function\n async function traverse(path: string, displayPath: string, depth: number): Promise<void> {\n // Check maxdepth\n if (maxDepth !== undefined && depth > maxDepth) {\n return;\n }\n\n let entryStat;\n try {\n entryStat = await ctx.fs.stat(path);\n } catch {\n return;\n }\n\n const isDir = entryStat.isDirectory();\n const isFile = entryStat.isFile();\n const basename = ctx.fs.basename(path);\n\n // Check if this entry matches the expression\n const matches = evalExpr(expr, basename, isFile, isDir);\n\n // Output if matches and above mindepth\n if (matches && (minDepth === undefined || depth >= minDepth)) {\n await ctx.stdout.writeText(displayPath + \"\\n\");\n }\n\n // Recurse into directories\n if (isDir) {\n try {\n const entries = await ctx.fs.readdir(path);\n entries.sort();\n for (const entry of entries) {\n const childPath = ctx.fs.resolve(path, entry);\n const childDisplayPath = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await traverse(childPath, childDisplayPath, depth + 1);\n }\n } catch {\n // Ignore errors reading directory contents\n }\n }\n }\n\n // Start traversal\n if (stat.isFile()) {\n const basename = ctx.fs.basename(resolvedStart);\n const matches = evalExpr(expr, basename, true, false);\n\n if (maxDepth !== undefined && maxDepth < 0) {\n // skip\n } else if (matches && (minDepth === undefined || minDepth <= 0)) {\n await ctx.stdout.writeText(normalizedPath + \"\\n\");\n }\n } else {\n await traverse(resolvedStart, normalizedPath, 0);\n }\n }\n\n return hasError ? 1 : 0;\n};\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "DA671804DAD6CB3364756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5D73614E490180B964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -5,11 +5,12 @@ var spec = {
5
5
  flags: [
6
6
  { short: "a", long: "all" },
7
7
  { short: "l" },
8
- { short: "1" }
8
+ { short: "1" },
9
+ { short: "R" }
9
10
  ],
10
- usage: "ls [-al1] [file ...]"
11
+ usage: "ls [-alR1] [file ...]"
11
12
  };
12
- var defaults = { all: false, long: false, onePerLine: false };
13
+ var defaults = { all: false, long: false, onePerLine: false, recursive: false };
13
14
  var handler = (flags, flag) => {
14
15
  if (flag.short === "a")
15
16
  flags.all = true;
@@ -17,6 +18,8 @@ var handler = (flags, flag) => {
17
18
  flags.long = true;
18
19
  if (flag.short === "1")
19
20
  flags.onePerLine = true;
21
+ if (flag.short === "R")
22
+ flags.recursive = true;
20
23
  };
21
24
  var parser = createFlagParser(spec, defaults, handler);
22
25
  var ls = async (ctx) => {
@@ -25,8 +28,63 @@ var ls = async (ctx) => {
25
28
  await parser.writeError(result.error, ctx.stderr);
26
29
  return 1;
27
30
  }
28
- const { all: showAll, long: longFormat, onePerLine } = result.flags;
31
+ const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;
29
32
  const paths = result.args.length === 0 ? ["."] : result.args;
33
+ let needsBlankLine = false;
34
+ const listDir = async (dirPath, displayPath, showHeader) => {
35
+ if (needsBlankLine)
36
+ await ctx.stdout.writeText(`
37
+ `);
38
+ needsBlankLine = true;
39
+ if (showHeader) {
40
+ await ctx.stdout.writeText(`${displayPath}:
41
+ `);
42
+ }
43
+ let entries = await ctx.fs.readdir(dirPath);
44
+ if (!showAll) {
45
+ entries = entries.filter((e) => !e.startsWith("."));
46
+ }
47
+ entries.sort();
48
+ if (longFormat) {
49
+ for (const entry of entries) {
50
+ const entryPath = ctx.fs.resolve(dirPath, entry);
51
+ try {
52
+ const entryStat = await ctx.fs.stat(entryPath);
53
+ const type = entryStat.isDirectory() ? "d" : "-";
54
+ const perms = "rwxr-xr-x";
55
+ const size = String(entryStat.size).padStart(8);
56
+ const date = entryStat.mtime.toISOString().slice(0, 10);
57
+ await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}
58
+ `);
59
+ } catch {
60
+ await ctx.stdout.writeText(`?????????? ${entry}
61
+ `);
62
+ }
63
+ }
64
+ } else if (onePerLine) {
65
+ for (const entry of entries) {
66
+ await ctx.stdout.writeText(entry + `
67
+ `);
68
+ }
69
+ } else {
70
+ if (entries.length > 0) {
71
+ await ctx.stdout.writeText(entries.join(" ") + `
72
+ `);
73
+ }
74
+ }
75
+ if (recursive) {
76
+ for (const entry of entries) {
77
+ const entryPath = ctx.fs.resolve(dirPath, entry);
78
+ try {
79
+ const entryStat = await ctx.fs.stat(entryPath);
80
+ if (entryStat.isDirectory()) {
81
+ const subDisplay = displayPath === "." ? entry : `${displayPath}/${entry}`;
82
+ await listDir(entryPath, subDisplay, true);
83
+ }
84
+ } catch {}
85
+ }
86
+ }
87
+ };
30
88
  for (let i = 0;i < paths.length; i++) {
31
89
  const pathArg = paths[i];
32
90
  const path = ctx.fs.resolve(ctx.cwd, pathArg);
@@ -37,43 +95,8 @@ var ls = async (ctx) => {
37
95
  `);
38
96
  continue;
39
97
  }
40
- if (paths.length > 1) {
41
- if (i > 0)
42
- await ctx.stdout.writeText(`
43
- `);
44
- await ctx.stdout.writeText(`${pathArg}:
45
- `);
46
- }
47
- let entries = await ctx.fs.readdir(path);
48
- if (!showAll) {
49
- entries = entries.filter((e) => !e.startsWith("."));
50
- }
51
- entries.sort();
52
- if (longFormat) {
53
- for (const entry of entries) {
54
- const entryPath = ctx.fs.resolve(path, entry);
55
- try {
56
- const entryStat = await ctx.fs.stat(entryPath);
57
- const type = entryStat.isDirectory() ? "d" : "-";
58
- const perms = "rwxr-xr-x";
59
- const size = String(entryStat.size).padStart(8);
60
- const date = entryStat.mtime.toISOString().slice(0, 10);
61
- await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${entry}
62
- `);
63
- } catch {
64
- await ctx.stdout.writeText(`?????????? ${entry}
65
- `);
66
- }
67
- }
68
- } else if (onePerLine) {
69
- for (const entry of entries) {
70
- await ctx.stdout.writeText(entry + `
71
- `);
72
- }
73
- } else {
74
- await ctx.stdout.writeText(entries.join(" ") + `
75
- `);
76
- }
98
+ const showHeader = recursive || paths.length > 1;
99
+ await listDir(path, pathArg, showHeader);
77
100
  } catch (err) {
78
101
  await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory
79
102
  `);
@@ -86,4 +109,4 @@ export {
86
109
  ls
87
110
  };
88
111
 
89
- //# debugId=CEDE14395BFC6B1E64756E2164756E21
112
+ //# debugId=C0BF60626A0B8D0564756E2164756E21
@@ -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.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n ] as FlagDefinition[],\n usage: \"ls [-al1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: 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};\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 } = result.flags;\n const paths = result.args.length === 0 ? [\".\"] : result.args;\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 // It's a file, just print the name\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n // It's a directory\n if (paths.length > 1) {\n if (i > 0) await ctx.stdout.writeText(\"\\n\");\n await ctx.stdout.writeText(`${pathArg}:\\n`);\n }\n\n let entries = await ctx.fs.readdir(path);\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(path, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n const type = entryStat.isDirectory() ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\"; // Simplified permissions\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 // Default: space-separated\n await ctx.stdout.writeText(entries.join(\" \") + \"\\n\");\n }\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.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\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"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "CEDE14395BFC6B1E64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "C0BF60626A0B8D0564756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
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",