shell-dsl 0.0.37 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/find/find.cjs +27 -11
- package/dist/cjs/src/commands/find/find.cjs.map +3 -3
- package/dist/cjs/src/commands/index.cjs +5 -1
- package/dist/cjs/src/commands/index.cjs.map +3 -3
- package/dist/cjs/src/commands/printf/printf.cjs +416 -0
- package/dist/cjs/src/commands/printf/printf.cjs.map +10 -0
- package/dist/cjs/src/commands/tree/tree.cjs +15 -8
- package/dist/cjs/src/commands/tree/tree.cjs.map +3 -3
- package/dist/mjs/index.mjs +3 -1
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/find/find.mjs +27 -11
- package/dist/mjs/src/commands/find/find.mjs.map +3 -3
- package/dist/mjs/src/commands/index.mjs +5 -1
- package/dist/mjs/src/commands/index.mjs.map +3 -3
- package/dist/mjs/src/commands/printf/printf.mjs +376 -0
- package/dist/mjs/src/commands/printf/printf.mjs.map +10 -0
- package/dist/mjs/src/commands/tree/tree.mjs +15 -8
- package/dist/mjs/src/commands/tree/tree.mjs.map +3 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/commands/printf/printf.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/commands/printf/printf.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Command } from \"../../types.mjs\";\n\ninterface EscapeResult {\n text: string;\n nextIndex: number;\n stop: boolean;\n}\n\ninterface FormatResult {\n output: string;\n error?: string;\n}\n\ninterface ConversionSpec {\n flags: string;\n width?: number;\n precision?: number;\n specifier: string;\n}\n\ninterface RenderPassResult {\n output: string;\n nextArgIndex: number;\n consumedArgs: number;\n stop: boolean;\n error?: string;\n}\n\nconst INTEGER_SPECIFIERS = new Set([\"d\", \"i\", \"u\", \"o\", \"x\", \"X\"]);\nconst FLOAT_SPECIFIERS = new Set([\"f\", \"F\", \"e\", \"E\", \"g\", \"G\"]);\nconst STRING_SPECIFIERS = new Set([\"s\", \"b\", \"c\"]);\nconst LENGTH_MODIFIERS = new Set([\"h\", \"l\", \"L\", \"j\", \"z\", \"t\"]);\n\nfunction isOctalDigit(char: string | undefined): boolean {\n return char !== undefined && char >= \"0\" && char <= \"7\";\n}\n\nfunction isDigit(char: string | undefined): boolean {\n return char !== undefined && char >= \"0\" && char <= \"9\";\n}\n\nfunction readEscape(input: string, index: number): EscapeResult {\n if (index + 1 >= input.length) {\n return { text: \"\\\\\", nextIndex: index + 1, stop: false };\n }\n\n const char = input[index + 1]!;\n\n if (char === \"c\") {\n return { text: \"\", nextIndex: index + 2, stop: true };\n }\n\n if (isOctalDigit(char)) {\n let digits = \"\";\n let nextIndex = index + 1;\n\n if (input[nextIndex] === \"0\") {\n nextIndex++;\n }\n\n while (digits.length < 3 && isOctalDigit(input[nextIndex])) {\n digits += input[nextIndex]!;\n nextIndex++;\n }\n\n const codePoint = digits === \"\" ? 0 : Number.parseInt(digits, 8);\n return { text: String.fromCharCode(codePoint), nextIndex, stop: false };\n }\n\n if (char === \"x\") {\n let digits = \"\";\n let nextIndex = index + 2;\n\n while (digits.length < 2 && nextIndex < input.length && /[0-9a-fA-F]/.test(input[nextIndex]!)) {\n digits += input[nextIndex]!;\n nextIndex++;\n }\n\n if (digits.length > 0) {\n return { text: String.fromCharCode(Number.parseInt(digits, 16)), nextIndex, stop: false };\n }\n }\n\n switch (char) {\n case \"a\":\n return { text: \"\\x07\", nextIndex: index + 2, stop: false };\n case \"b\":\n return { text: \"\\b\", nextIndex: index + 2, stop: false };\n case \"f\":\n return { text: \"\\f\", nextIndex: index + 2, stop: false };\n case \"n\":\n return { text: \"\\n\", nextIndex: index + 2, stop: false };\n case \"r\":\n return { text: \"\\r\", nextIndex: index + 2, stop: false };\n case \"t\":\n return { text: \"\\t\", nextIndex: index + 2, stop: false };\n case \"v\":\n return { text: \"\\v\", nextIndex: index + 2, stop: false };\n case \"\\\\\":\n return { text: \"\\\\\", nextIndex: index + 2, stop: false };\n default:\n return { text: `\\\\${char}`, nextIndex: index + 2, stop: false };\n }\n}\n\nfunction expandPrintfEscapes(input: string): { text: string; stop: boolean } {\n let text = \"\";\n\n for (let i = 0; i < input.length;) {\n if (input[i] !== \"\\\\\") {\n text += input[i]!;\n i++;\n continue;\n }\n\n const escape = readEscape(input, i);\n text += escape.text;\n i = escape.nextIndex;\n\n if (escape.stop) {\n return { text, stop: true };\n }\n }\n\n return { text, stop: false };\n}\n\nfunction readNumber(input: string, index: number): { value?: number; nextIndex: number } {\n let digits = \"\";\n let nextIndex = index;\n\n while (isDigit(input[nextIndex])) {\n digits += input[nextIndex]!;\n nextIndex++;\n }\n\n return {\n value: digits === \"\" ? undefined : Number.parseInt(digits, 10),\n nextIndex,\n };\n}\n\nfunction parseConversion(format: string, index: number): { spec?: ConversionSpec; nextIndex: number; error?: string } {\n let nextIndex = index + 1;\n let flags = \"\";\n\n while (true) {\n const flag = format[nextIndex];\n if (flag === undefined || !\"-+ #0\".includes(flag)) {\n break;\n }\n flags += flag;\n nextIndex++;\n }\n\n const widthResult = readNumber(format, nextIndex);\n const width = widthResult.value;\n nextIndex = widthResult.nextIndex;\n\n let precision: number | undefined;\n if (format[nextIndex] === \".\") {\n const precisionResult = readNumber(format, nextIndex + 1);\n precision = precisionResult.value ?? 0;\n nextIndex = precisionResult.nextIndex;\n }\n\n if (LENGTH_MODIFIERS.has(format[nextIndex] ?? \"\")) {\n const modifier = format[nextIndex]!;\n nextIndex++;\n if ((modifier === \"h\" && format[nextIndex] === \"h\") || (modifier === \"l\" && format[nextIndex] === \"l\")) {\n nextIndex++;\n }\n }\n\n const specifier = format[nextIndex];\n if (specifier === undefined) {\n return { nextIndex, error: \"missing format character\" };\n }\n\n if (\n !INTEGER_SPECIFIERS.has(specifier) &&\n !FLOAT_SPECIFIERS.has(specifier) &&\n !STRING_SPECIFIERS.has(specifier)\n ) {\n return { nextIndex: nextIndex + 1, error: `invalid format character '${specifier}'` };\n }\n\n return {\n spec: { flags, width, precision, specifier },\n nextIndex: nextIndex + 1,\n };\n}\n\nfunction pad(value: string, spec: ConversionSpec, numeric = false): string {\n const width = spec.width ?? 0;\n if (value.length >= width) {\n return value;\n }\n\n const leftAlign = spec.flags.includes(\"-\");\n const useZeroPad = numeric && spec.flags.includes(\"0\") && !leftAlign && spec.precision === undefined;\n const padChar = useZeroPad ? \"0\" : \" \";\n const padding = padChar.repeat(width - value.length);\n\n if (leftAlign) {\n return value + padding;\n }\n\n if (useZeroPad && (value.startsWith(\"-\") || value.startsWith(\"+\") || value.startsWith(\" \"))) {\n return value[0]! + padding + value.slice(1);\n }\n\n if (useZeroPad && (value.startsWith(\"0x\") || value.startsWith(\"0X\"))) {\n return value.slice(0, 2) + padding + value.slice(2);\n }\n\n return padding + value;\n}\n\nfunction integerFromArg(arg: string): number {\n const trimmed = arg.trim();\n if (/^[+-]?0[xX][0-9a-fA-F]+$/.test(trimmed)) {\n const sign = trimmed.startsWith(\"-\") ? -1 : 1;\n return sign * Number.parseInt(trimmed.replace(/^[+-]?0[xX]/, \"\"), 16);\n }\n\n const parsed = Number.parseInt(trimmed, 10);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\nfunction floatFromArg(arg: string): number {\n const parsed = Number.parseFloat(arg.trim());\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\nfunction formatInteger(arg: string, spec: ConversionSpec): string {\n const originalValue = Math.trunc(integerFromArg(arg));\n const unsignedValue = originalValue < 0 ? originalValue >>> 0 : originalValue;\n let value = spec.specifier === \"u\" || spec.specifier === \"o\" || spec.specifier === \"x\" || spec.specifier === \"X\"\n ? unsignedValue\n : originalValue;\n\n let sign = \"\";\n if ((spec.specifier === \"d\" || spec.specifier === \"i\") && value < 0) {\n sign = \"-\";\n value = Math.abs(value);\n } else if ((spec.specifier === \"d\" || spec.specifier === \"i\") && spec.flags.includes(\"+\")) {\n sign = \"+\";\n } else if ((spec.specifier === \"d\" || spec.specifier === \"i\") && spec.flags.includes(\" \")) {\n sign = \" \";\n }\n\n let digits: string;\n if (spec.specifier === \"o\") {\n digits = value.toString(8);\n } else if (spec.specifier === \"x\" || spec.specifier === \"X\") {\n digits = value.toString(16);\n if (spec.specifier === \"X\") {\n digits = digits.toUpperCase();\n }\n } else {\n digits = value.toString(10);\n }\n\n if (spec.precision !== undefined) {\n if (spec.precision === 0 && value === 0) {\n digits = \"\";\n } else {\n digits = digits.padStart(spec.precision, \"0\");\n }\n }\n\n let prefix = \"\";\n if (spec.flags.includes(\"#\")) {\n if (spec.specifier === \"o\" && !digits.startsWith(\"0\")) {\n prefix = \"0\";\n } else if (spec.specifier === \"x\" && value !== 0) {\n prefix = \"0x\";\n } else if (spec.specifier === \"X\" && value !== 0) {\n prefix = \"0X\";\n }\n }\n\n return pad(sign + prefix + digits, spec, true);\n}\n\nfunction formatFloat(arg: string, spec: ConversionSpec): string {\n const value = floatFromArg(arg);\n const precision = spec.precision ?? 6;\n let formatted: string;\n\n switch (spec.specifier) {\n case \"e\":\n case \"E\":\n formatted = value.toExponential(precision);\n break;\n case \"g\":\n case \"G\":\n formatted = value.toPrecision(precision === 0 ? 1 : precision);\n break;\n default:\n formatted = value.toFixed(precision);\n break;\n }\n\n if (spec.specifier === \"E\" || spec.specifier === \"G\" || spec.specifier === \"F\") {\n formatted = formatted.toUpperCase();\n }\n\n if (value >= 0 && spec.flags.includes(\"+\")) {\n formatted = `+${formatted}`;\n } else if (value >= 0 && spec.flags.includes(\" \")) {\n formatted = ` ${formatted}`;\n }\n\n return pad(formatted, spec, true);\n}\n\nfunction formatString(value: string, spec: ConversionSpec): string {\n const truncated = spec.precision === undefined ? value : value.slice(0, spec.precision);\n return pad(truncated, spec);\n}\n\nfunction renderConversion(\n spec: ConversionSpec,\n args: string[],\n argIndex: number\n): { output: string; nextArgIndex: number; consumedArg: boolean; stop: boolean } {\n const hasArg = argIndex < args.length;\n const arg = hasArg ? args[argIndex]! : \"\";\n const nextArgIndex = hasArg ? argIndex + 1 : argIndex;\n\n if (spec.specifier === \"s\") {\n return {\n output: formatString(arg, spec),\n nextArgIndex,\n consumedArg: hasArg,\n stop: false,\n };\n }\n\n if (spec.specifier === \"b\") {\n const expanded = expandPrintfEscapes(arg);\n return {\n output: formatString(expanded.text, spec),\n nextArgIndex,\n consumedArg: hasArg,\n stop: expanded.stop,\n };\n }\n\n if (spec.specifier === \"c\") {\n return {\n output: formatString(arg.slice(0, 1), spec),\n nextArgIndex,\n consumedArg: hasArg,\n stop: false,\n };\n }\n\n if (INTEGER_SPECIFIERS.has(spec.specifier)) {\n return {\n output: formatInteger(hasArg ? arg : \"0\", spec),\n nextArgIndex,\n consumedArg: hasArg,\n stop: false,\n };\n }\n\n return {\n output: formatFloat(hasArg ? arg : \"0\", spec),\n nextArgIndex,\n consumedArg: hasArg,\n stop: false,\n };\n}\n\nfunction renderPass(format: string, args: string[], startArgIndex: number): RenderPassResult {\n let output = \"\";\n let argIndex = startArgIndex;\n let consumedArgs = 0;\n\n for (let i = 0; i < format.length;) {\n const char = format[i]!;\n\n if (char === \"\\\\\") {\n const escape = readEscape(format, i);\n output += escape.text;\n i = escape.nextIndex;\n\n if (escape.stop) {\n return { output, nextArgIndex: argIndex, consumedArgs, stop: true };\n }\n continue;\n }\n\n if (char !== \"%\") {\n output += char;\n i++;\n continue;\n }\n\n if (format[i + 1] === \"%\") {\n output += \"%\";\n i += 2;\n continue;\n }\n\n const parsed = parseConversion(format, i);\n if (parsed.error || !parsed.spec) {\n return {\n output,\n nextArgIndex: argIndex,\n consumedArgs,\n stop: false,\n error: parsed.error ?? \"invalid format\",\n };\n }\n\n const rendered = renderConversion(parsed.spec, args, argIndex);\n output += rendered.output;\n argIndex = rendered.nextArgIndex;\n if (rendered.consumedArg) {\n consumedArgs++;\n }\n i = parsed.nextIndex;\n\n if (rendered.stop) {\n return { output, nextArgIndex: argIndex, consumedArgs, stop: true };\n }\n }\n\n return { output, nextArgIndex: argIndex, consumedArgs, stop: false };\n}\n\nfunction formatPrintf(format: string, args: string[]): FormatResult {\n let output = \"\";\n let argIndex = 0;\n let renderedAtLeastOnce = false;\n\n while (!renderedAtLeastOnce || argIndex < args.length) {\n const pass = renderPass(format, args, argIndex);\n renderedAtLeastOnce = true;\n output += pass.output;\n argIndex = pass.nextArgIndex;\n\n if (pass.error) {\n return { output, error: pass.error };\n }\n\n if (pass.stop) {\n return { output };\n }\n\n if (pass.consumedArgs === 0) {\n break;\n }\n }\n\n return { output };\n}\n\nexport const printf: Command = async (ctx) => {\n if (ctx.args.length === 0) {\n await ctx.stderr.writeText(\"printf: missing format operand\\n\");\n return 1;\n }\n\n const [format, ...args] = ctx.args;\n const result = formatPrintf(format!, args);\n\n if (result.output.length > 0) {\n await ctx.stdout.writeText(result.output);\n }\n\n if (result.error) {\n await ctx.stderr.writeText(`printf: ${result.error}\\n`);\n return 1;\n }\n\n return 0;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "E3692C39E2D017E164756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -9,9 +9,10 @@ var spec = {
|
|
|
9
9
|
{ short: "L", takesValue: true },
|
|
10
10
|
{ short: "I", takesValue: true },
|
|
11
11
|
{ long: "dirsfirst" },
|
|
12
|
-
{ long: "prune" }
|
|
12
|
+
{ long: "prune" },
|
|
13
|
+
{ long: "noreport" }
|
|
13
14
|
],
|
|
14
|
-
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]"
|
|
15
|
+
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [--noreport] [directory ...]"
|
|
15
16
|
};
|
|
16
17
|
var defaults = {
|
|
17
18
|
all: false,
|
|
@@ -19,6 +20,7 @@ var defaults = {
|
|
|
19
20
|
maxDepth: Infinity,
|
|
20
21
|
dirsfirst: true,
|
|
21
22
|
prune: false,
|
|
23
|
+
noReport: false,
|
|
22
24
|
ignorePatterns: []
|
|
23
25
|
};
|
|
24
26
|
var handlerResult = {};
|
|
@@ -31,6 +33,8 @@ var handler = (flags, flag, value) => {
|
|
|
31
33
|
flags.dirsfirst = true;
|
|
32
34
|
if (flag.long === "prune")
|
|
33
35
|
flags.prune = true;
|
|
36
|
+
if (flag.long === "noreport")
|
|
37
|
+
flags.noReport = true;
|
|
34
38
|
if (flag.short === "I" && value) {
|
|
35
39
|
if (flags.ignorePatterns === defaults.ignorePatterns) {
|
|
36
40
|
flags.ignorePatterns = [];
|
|
@@ -60,7 +64,7 @@ var tree = async (ctx) => {
|
|
|
60
64
|
await ctx.stderr.writeText(handlerResult.error);
|
|
61
65
|
return 1;
|
|
62
66
|
}
|
|
63
|
-
const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;
|
|
67
|
+
const { all: showAll, directoriesOnly, maxDepth, prune, noReport, ignorePatterns } = result.flags;
|
|
64
68
|
const targetPath = result.args[0] ?? ".";
|
|
65
69
|
if (maxDepth < 1) {
|
|
66
70
|
await ctx.stderr.writeText(`tree: Invalid level, must be greater than 0
|
|
@@ -77,7 +81,8 @@ var tree = async (ctx) => {
|
|
|
77
81
|
return 1;
|
|
78
82
|
}
|
|
79
83
|
if (stat.isFile()) {
|
|
80
|
-
await ctx.stdout.writeText(targetPath + `
|
|
84
|
+
await ctx.stdout.writeText(noReport ? targetPath + `
|
|
85
|
+
` : targetPath + `
|
|
81
86
|
|
|
82
87
|
0 directories, 1 file
|
|
83
88
|
`);
|
|
@@ -165,15 +170,17 @@ var tree = async (ctx) => {
|
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
await printTree(resolvedPath, "", 1);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
if (!noReport) {
|
|
174
|
+
const dirWord = dirCount === 1 ? "directory" : "directories";
|
|
175
|
+
const fileWord = fileCount === 1 ? "file" : "files";
|
|
176
|
+
await ctx.stdout.writeText(`
|
|
171
177
|
${dirCount} ${dirWord}, ${fileCount} ${fileWord}
|
|
172
178
|
`);
|
|
179
|
+
}
|
|
173
180
|
return 0;
|
|
174
181
|
};
|
|
175
182
|
export {
|
|
176
183
|
tree
|
|
177
184
|
};
|
|
178
185
|
|
|
179
|
-
//# debugId=
|
|
186
|
+
//# debugId=F796F052BBAF936964756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/tree/tree.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\nimport { matchGlob } from \"../../utils/match-glob.mjs\";\n\ninterface TreeFlags {\n all: boolean;\n directoriesOnly: boolean;\n maxDepth: number;\n dirsfirst: boolean;\n prune: boolean;\n ignorePatterns: string[];\n}\n\nconst spec = {\n name: \"tree\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"d\" },\n { short: \"L\", takesValue: true },\n { short: \"I\", takesValue: true },\n { long: \"dirsfirst\" },\n { long: \"prune\" },\n ] as FlagDefinition[],\n usage: \"tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]\",\n};\n\nconst defaults: TreeFlags = {\n all: false,\n directoriesOnly: false,\n maxDepth: Infinity,\n dirsfirst: true,\n prune: false,\n ignorePatterns: [],\n};\n\ninterface HandlerResult {\n error?: string;\n}\n\nlet handlerResult: HandlerResult = {};\n\nconst handler = (flags: TreeFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"d\") flags.directoriesOnly = true;\n if (flag.long === \"dirsfirst\") flags.dirsfirst = true;\n if (flag.long === \"prune\") flags.prune = true;\n if (flag.short === \"I\" && value) {\n if (flags.ignorePatterns === defaults.ignorePatterns) {\n flags.ignorePatterns = [];\n }\n flags.ignorePatterns.push(...value.split(\"|\"));\n }\n if (flag.short === \"L\" && value) {\n const depth = parseInt(value, 10);\n if (isNaN(depth) || !/^\\d+$/.test(value)) {\n handlerResult.error = `tree: -L option requires a numeric argument\\nusage: ${spec.usage}\\n`;\n } else {\n flags.maxDepth = depth;\n }\n }\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const tree: Command = async (ctx) => {\n // Reset handler result for each invocation\n handlerResult = {};\n\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n if (handlerResult.error) {\n await ctx.stderr.writeText(handlerResult.error);\n return 1;\n }\n\n const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;\n const targetPath = result.args[0] ?? \".\";\n\n // Validate maxDepth\n if (maxDepth < 1) {\n await ctx.stderr.writeText(\"tree: Invalid level, must be greater than 0\\n\");\n return 1;\n }\n\n const resolvedPath = ctx.fs.resolve(ctx.cwd, targetPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedPath);\n } catch {\n await ctx.stderr.writeText(`tree: ${targetPath}: No such file or directory\\n`);\n return 1;\n }\n\n // If it's a file, just print the filename\n if (stat.isFile()) {\n await ctx.stdout.writeText(targetPath + \"\\n\\n0 directories, 1 file\\n\");\n return 0;\n }\n\n let dirCount = 0;\n let fileCount = 0;\n const entriesCache = new Map<string, { name: string; path: string; isDir: boolean }[]>();\n const visibleContentCache = new Map<string, boolean>();\n\n // Print root\n await ctx.stdout.writeText(targetPath + \"\\n\");\n\n async function getEntries(path: string): Promise<{ name: string; path: string; isDir: boolean }[]> {\n const cached = entriesCache.get(path);\n if (cached) return cached;\n\n let entries = await ctx.fs.readdir(path);\n\n // Filter hidden files unless -a\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n // Filter by -I ignore patterns\n if (ignorePatterns.length > 0) {\n entries = entries.filter((e) => !ignorePatterns.some((p) => matchGlob(p, e)));\n }\n\n // Sort entries\n entries.sort();\n\n const resolvedEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const name of entries) {\n const entryPath = ctx.fs.resolve(path, name);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });\n } catch {\n // Skip entries we can't stat\n }\n }\n\n entriesCache.set(path, resolvedEntries);\n return resolvedEntries;\n }\n\n async function hasVisibleContent(path: string): Promise<boolean> {\n const cached = visibleContentCache.get(path);\n if (cached !== undefined) return cached;\n\n const entries = await getEntries(path);\n\n for (const entry of entries) {\n if (!entry.isDir) {\n visibleContentCache.set(path, true);\n return true;\n }\n\n if (await hasVisibleContent(entry.path)) {\n visibleContentCache.set(path, true);\n return true;\n }\n }\n\n visibleContentCache.set(path, false);\n return false;\n }\n\n // Recursive function to build tree\n async function printTree(path: string, prefix: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n const entries = await getEntries(path);\n\n // Separate dirs and files, dirs first\n const dirEntries: { name: string; path: string; isDir: boolean }[] = [];\n const fileEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const entry of entries) {\n if (entry.isDir) {\n if (prune && !(await hasVisibleContent(entry.path))) {\n continue;\n }\n dirEntries.push(entry);\n } else {\n fileEntries.push(entry);\n }\n }\n\n // Combine: directories first, then files (unless directoriesOnly)\n const sortedEntries = directoriesOnly\n ? dirEntries\n : [...dirEntries, ...fileEntries];\n\n for (let i = 0; i < sortedEntries.length; i++) {\n const entry = sortedEntries[i]!;\n const isLast = i === sortedEntries.length - 1;\n const connector = isLast ? \"└── \" : \"├── \";\n\n await ctx.stdout.writeText(prefix + connector + entry.name + \"\\n\");\n\n if (entry.isDir) {\n dirCount++;\n if (depth < maxDepth) {\n const newPrefix = prefix + (isLast ? \" \" : \"│ \");\n await printTree(entry.path, newPrefix, depth + 1);\n }\n } else {\n fileCount++;\n }\n }\n }\n\n await printTree(resolvedPath, \"\", 1);\n\n // Print summary\n
|
|
5
|
+
"import type { Command } from \"../../types.mjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.mjs\";\nimport { matchGlob } from \"../../utils/match-glob.mjs\";\n\ninterface TreeFlags {\n all: boolean;\n directoriesOnly: boolean;\n maxDepth: number;\n dirsfirst: boolean;\n prune: boolean;\n noReport: boolean;\n ignorePatterns: string[];\n}\n\nconst spec = {\n name: \"tree\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"d\" },\n { short: \"L\", takesValue: true },\n { short: \"I\", takesValue: true },\n { long: \"dirsfirst\" },\n { long: \"prune\" },\n { long: \"noreport\" },\n ] as FlagDefinition[],\n usage: \"tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [--noreport] [directory ...]\",\n};\n\nconst defaults: TreeFlags = {\n all: false,\n directoriesOnly: false,\n maxDepth: Infinity,\n dirsfirst: true,\n prune: false,\n noReport: false,\n ignorePatterns: [],\n};\n\ninterface HandlerResult {\n error?: string;\n}\n\nlet handlerResult: HandlerResult = {};\n\nconst handler = (flags: TreeFlags, flag: FlagDefinition, value?: string) => {\n if (flag.short === \"a\") flags.all = true;\n if (flag.short === \"d\") flags.directoriesOnly = true;\n if (flag.long === \"dirsfirst\") flags.dirsfirst = true;\n if (flag.long === \"prune\") flags.prune = true;\n if (flag.long === \"noreport\") flags.noReport = true;\n if (flag.short === \"I\" && value) {\n if (flags.ignorePatterns === defaults.ignorePatterns) {\n flags.ignorePatterns = [];\n }\n flags.ignorePatterns.push(...value.split(\"|\"));\n }\n if (flag.short === \"L\" && value) {\n const depth = parseInt(value, 10);\n if (isNaN(depth) || !/^\\d+$/.test(value)) {\n handlerResult.error = `tree: -L option requires a numeric argument\\nusage: ${spec.usage}\\n`;\n } else {\n flags.maxDepth = depth;\n }\n }\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const tree: Command = async (ctx) => {\n // Reset handler result for each invocation\n handlerResult = {};\n\n const result = parser.parse(ctx.args);\n\n if (result.error) {\n await parser.writeError(result.error, ctx.stderr);\n return 1;\n }\n\n if (handlerResult.error) {\n await ctx.stderr.writeText(handlerResult.error);\n return 1;\n }\n\n const { all: showAll, directoriesOnly, maxDepth, prune, noReport, ignorePatterns } = result.flags;\n const targetPath = result.args[0] ?? \".\";\n\n // Validate maxDepth\n if (maxDepth < 1) {\n await ctx.stderr.writeText(\"tree: Invalid level, must be greater than 0\\n\");\n return 1;\n }\n\n const resolvedPath = ctx.fs.resolve(ctx.cwd, targetPath);\n\n // Check if path exists\n let stat;\n try {\n stat = await ctx.fs.stat(resolvedPath);\n } catch {\n await ctx.stderr.writeText(`tree: ${targetPath}: No such file or directory\\n`);\n return 1;\n }\n\n // If it's a file, just print the filename\n if (stat.isFile()) {\n await ctx.stdout.writeText(noReport ? targetPath + \"\\n\" : targetPath + \"\\n\\n0 directories, 1 file\\n\");\n return 0;\n }\n\n let dirCount = 0;\n let fileCount = 0;\n const entriesCache = new Map<string, { name: string; path: string; isDir: boolean }[]>();\n const visibleContentCache = new Map<string, boolean>();\n\n // Print root\n await ctx.stdout.writeText(targetPath + \"\\n\");\n\n async function getEntries(path: string): Promise<{ name: string; path: string; isDir: boolean }[]> {\n const cached = entriesCache.get(path);\n if (cached) return cached;\n\n let entries = await ctx.fs.readdir(path);\n\n // Filter hidden files unless -a\n if (!showAll) {\n entries = entries.filter((e) => !e.startsWith(\".\"));\n }\n\n // Filter by -I ignore patterns\n if (ignorePatterns.length > 0) {\n entries = entries.filter((e) => !ignorePatterns.some((p) => matchGlob(p, e)));\n }\n\n // Sort entries\n entries.sort();\n\n const resolvedEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const name of entries) {\n const entryPath = ctx.fs.resolve(path, name);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });\n } catch {\n // Skip entries we can't stat\n }\n }\n\n entriesCache.set(path, resolvedEntries);\n return resolvedEntries;\n }\n\n async function hasVisibleContent(path: string): Promise<boolean> {\n const cached = visibleContentCache.get(path);\n if (cached !== undefined) return cached;\n\n const entries = await getEntries(path);\n\n for (const entry of entries) {\n if (!entry.isDir) {\n visibleContentCache.set(path, true);\n return true;\n }\n\n if (await hasVisibleContent(entry.path)) {\n visibleContentCache.set(path, true);\n return true;\n }\n }\n\n visibleContentCache.set(path, false);\n return false;\n }\n\n // Recursive function to build tree\n async function printTree(path: string, prefix: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n const entries = await getEntries(path);\n\n // Separate dirs and files, dirs first\n const dirEntries: { name: string; path: string; isDir: boolean }[] = [];\n const fileEntries: { name: string; path: string; isDir: boolean }[] = [];\n\n for (const entry of entries) {\n if (entry.isDir) {\n if (prune && !(await hasVisibleContent(entry.path))) {\n continue;\n }\n dirEntries.push(entry);\n } else {\n fileEntries.push(entry);\n }\n }\n\n // Combine: directories first, then files (unless directoriesOnly)\n const sortedEntries = directoriesOnly\n ? dirEntries\n : [...dirEntries, ...fileEntries];\n\n for (let i = 0; i < sortedEntries.length; i++) {\n const entry = sortedEntries[i]!;\n const isLast = i === sortedEntries.length - 1;\n const connector = isLast ? \"└── \" : \"├── \";\n\n await ctx.stdout.writeText(prefix + connector + entry.name + \"\\n\");\n\n if (entry.isDir) {\n dirCount++;\n if (depth < maxDepth) {\n const newPrefix = prefix + (isLast ? \" \" : \"│ \");\n await printTree(entry.path, newPrefix, depth + 1);\n }\n } else {\n fileCount++;\n }\n }\n }\n\n await printTree(resolvedPath, \"\", 1);\n\n if (!noReport) {\n // Print summary\n const dirWord = dirCount === 1 ? \"directory\" : \"directories\";\n const fileWord = fileCount === 1 ? \"file\" : \"files\";\n await ctx.stdout.writeText(`\\n${dirCount} ${dirWord}, ${fileCount} ${fileWord}\\n`);\n }\n\n return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AACA;AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "F796F052BBAF936964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from "./src/index.ts";
|
|
2
2
|
export { builtinCommands } from "./src/commands/index.ts";
|
|
3
|
-
export { echo, cat, grep, wc, head, tail, sort, uniq, pwd, ls, mkdir, rm, test, bracket, trueCmd, falseCmd, touch, cp, mv, tee, tree, find, sed, awk, breakCmd, continueCmd, od, } from "./src/commands/index.ts";
|
|
3
|
+
export { echo, printf, cat, grep, wc, head, tail, sort, uniq, pwd, ls, mkdir, rm, test, bracket, trueCmd, falseCmd, touch, cp, mv, tee, tree, find, sed, awk, breakCmd, continueCmd, od, } from "./src/commands/index.ts";
|
package/package.json
CHANGED