shell-dsl 0.0.25 → 0.0.26
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/dist/cjs/package.json
CHANGED
|
@@ -38,30 +38,56 @@ var spec = {
|
|
|
38
38
|
flags: [
|
|
39
39
|
{ short: "a", long: "all" },
|
|
40
40
|
{ short: "l" },
|
|
41
|
+
{ short: "h" },
|
|
41
42
|
{ short: "1" },
|
|
42
43
|
{ short: "R" }
|
|
43
44
|
],
|
|
44
|
-
usage: "ls [-
|
|
45
|
+
usage: "ls [-alhR1] [file ...]"
|
|
45
46
|
};
|
|
46
|
-
var defaults = { all: false, long: false, onePerLine: false, recursive: false };
|
|
47
|
+
var defaults = { all: false, long: false, onePerLine: false, recursive: false, humanReadable: false };
|
|
47
48
|
var handler = (flags, flag) => {
|
|
48
49
|
if (flag.short === "a")
|
|
49
50
|
flags.all = true;
|
|
50
51
|
if (flag.short === "l")
|
|
51
52
|
flags.long = true;
|
|
53
|
+
if (flag.short === "h")
|
|
54
|
+
flags.humanReadable = true;
|
|
52
55
|
if (flag.short === "1")
|
|
53
56
|
flags.onePerLine = true;
|
|
54
57
|
if (flag.short === "R")
|
|
55
58
|
flags.recursive = true;
|
|
56
59
|
};
|
|
57
60
|
var parser = import_flag_parser.createFlagParser(spec, defaults, handler);
|
|
61
|
+
var BOLD_BLUE = "\x1B[1;34m";
|
|
62
|
+
var RESET = "\x1B[0m";
|
|
63
|
+
function formatSize(bytes, humanReadable) {
|
|
64
|
+
if (!humanReadable)
|
|
65
|
+
return String(bytes).padStart(8);
|
|
66
|
+
if (bytes < 1024)
|
|
67
|
+
return String(bytes).padStart(8);
|
|
68
|
+
const units = ["K", "M", "G", "T"];
|
|
69
|
+
let value = bytes;
|
|
70
|
+
let unitIndex = -1;
|
|
71
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
72
|
+
value /= 1024;
|
|
73
|
+
unitIndex++;
|
|
74
|
+
}
|
|
75
|
+
const formatted = value < 10 ? value.toFixed(1) : String(Math.floor(value));
|
|
76
|
+
return (formatted + units[unitIndex]).padStart(8);
|
|
77
|
+
}
|
|
78
|
+
function colorize(name, isDirectory, isTTY) {
|
|
79
|
+
if (!isTTY || !isDirectory)
|
|
80
|
+
return name;
|
|
81
|
+
return `${BOLD_BLUE}${name}${RESET}`;
|
|
82
|
+
}
|
|
58
83
|
var ls = async (ctx) => {
|
|
59
84
|
const result = parser.parse(ctx.args);
|
|
60
85
|
if (result.error) {
|
|
61
86
|
await parser.writeError(result.error, ctx.stderr);
|
|
62
87
|
return 1;
|
|
63
88
|
}
|
|
64
|
-
const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;
|
|
89
|
+
const { all: showAll, long: longFormat, onePerLine, recursive, humanReadable } = result.flags;
|
|
90
|
+
const isTTY = ctx.stdout.isTTY;
|
|
65
91
|
const paths = result.args.length === 0 ? ["."] : result.args;
|
|
66
92
|
let needsBlankLine = false;
|
|
67
93
|
const listDir = async (dirPath, displayPath, showHeader) => {
|
|
@@ -83,25 +109,51 @@ var ls = async (ctx) => {
|
|
|
83
109
|
const entryPath = ctx.fs.resolve(dirPath, entry);
|
|
84
110
|
try {
|
|
85
111
|
const entryStat = await ctx.fs.stat(entryPath);
|
|
86
|
-
const
|
|
112
|
+
const isDir = entryStat.isDirectory();
|
|
113
|
+
const type = isDir ? "d" : "-";
|
|
87
114
|
const perms = "rwxr-xr-x";
|
|
88
|
-
const size =
|
|
115
|
+
const size = formatSize(entryStat.size, humanReadable);
|
|
89
116
|
const date = entryStat.mtime.toISOString().slice(0, 10);
|
|
90
|
-
|
|
117
|
+
const name = colorize(entry, isDir, isTTY);
|
|
118
|
+
await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${name}
|
|
91
119
|
`);
|
|
92
120
|
} catch {
|
|
93
121
|
await ctx.stdout.writeText(`?????????? ${entry}
|
|
94
122
|
`);
|
|
95
123
|
}
|
|
96
124
|
}
|
|
97
|
-
} else if (onePerLine || !
|
|
98
|
-
|
|
99
|
-
|
|
125
|
+
} else if (onePerLine || !isTTY) {
|
|
126
|
+
if (isTTY) {
|
|
127
|
+
const dirSet = new Set;
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
try {
|
|
130
|
+
const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));
|
|
131
|
+
if (entryStat.isDirectory())
|
|
132
|
+
dirSet.add(entry);
|
|
133
|
+
} catch {}
|
|
134
|
+
}
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
await ctx.stdout.writeText(colorize(entry, dirSet.has(entry), true) + `
|
|
100
137
|
`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
await ctx.stdout.writeText(entry + `
|
|
142
|
+
`);
|
|
143
|
+
}
|
|
101
144
|
}
|
|
102
145
|
} else {
|
|
103
146
|
if (entries.length > 0) {
|
|
104
|
-
|
|
147
|
+
const dirSet = new Set;
|
|
148
|
+
for (const entry of entries) {
|
|
149
|
+
try {
|
|
150
|
+
const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));
|
|
151
|
+
if (entryStat.isDirectory())
|
|
152
|
+
dirSet.add(entry);
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
155
|
+
const colored = entries.map((e) => colorize(e, dirSet.has(e), true));
|
|
156
|
+
await ctx.stdout.writeText(colored.join(" ") + `
|
|
105
157
|
`);
|
|
106
158
|
}
|
|
107
159
|
}
|
|
@@ -139,4 +191,4 @@ var ls = async (ctx) => {
|
|
|
139
191
|
return 0;
|
|
140
192
|
};
|
|
141
193
|
|
|
142
|
-
//# debugId=
|
|
194
|
+
//# debugId=B9FA5A0657F2D55664756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/ls/ls.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface LsFlags {\n all: boolean;\n long: boolean;\n onePerLine: boolean;\n recursive: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-
|
|
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 humanReadable: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"h\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alhR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false, humanReadable: 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 === \"h\") flags.humanReadable = 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\nconst BOLD_BLUE = \"\\x1b[1;34m\";\nconst RESET = \"\\x1b[0m\";\n\nfunction formatSize(bytes: number, humanReadable: boolean): string {\n if (!humanReadable) return String(bytes).padStart(8);\n if (bytes < 1024) return String(bytes).padStart(8);\n const units = [\"K\", \"M\", \"G\", \"T\"];\n let value = bytes;\n let unitIndex = -1;\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024;\n unitIndex++;\n }\n const formatted = value < 10 ? value.toFixed(1) : String(Math.floor(value));\n return (formatted + units[unitIndex]!).padStart(8);\n}\n\nfunction colorize(name: string, isDirectory: boolean, isTTY: boolean): string {\n if (!isTTY || !isDirectory) return name;\n return `${BOLD_BLUE}${name}${RESET}`;\n}\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, humanReadable } = result.flags;\n const isTTY = ctx.stdout.isTTY;\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 isDir = entryStat.isDirectory();\n const type = isDir ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = formatSize(entryStat.size, humanReadable);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n const name = colorize(entry, isDir, isTTY);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${name}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine || !isTTY) {\n if (isTTY) {\n // -1 flag with TTY: still colorize directories\n const dirSet = new Set<string>();\n for (const entry of entries) {\n try {\n const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));\n if (entryStat.isDirectory()) dirSet.add(entry);\n } catch {}\n }\n for (const entry of entries) {\n await ctx.stdout.writeText(colorize(entry, dirSet.has(entry), true) + \"\\n\");\n }\n } else {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n }\n } else {\n // TTY default: space-separated with colors\n if (entries.length > 0) {\n const dirSet = new Set<string>();\n for (const entry of entries) {\n try {\n const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));\n if (entryStat.isDirectory()) dirSet.add(entry);\n } catch {}\n }\n const colored = entries.map((e) => colorize(e, dirSet.has(e), true));\n await ctx.stdout.writeText(colored.join(\" \") + \"\\n\");\n }\n }\n\n if (recursive) {\n for (const entry of entries) {\n const entryPath = ctx.fs.resolve(dirPath, entry);\n try {\n const entryStat = await ctx.fs.stat(entryPath);\n if (entryStat.isDirectory()) {\n const subDisplay = displayPath === \".\" ? entry : `${displayPath}/${entry}`;\n await listDir(entryPath, subDisplay, true);\n }\n } catch {\n // skip entries we can't stat\n }\n }\n }\n };\n\n for (let i = 0; i < paths.length; i++) {\n const pathArg = paths[i]!;\n const path = ctx.fs.resolve(ctx.cwd, pathArg);\n\n try {\n const stat = await ctx.fs.stat(path);\n\n if (stat.isFile()) {\n await ctx.stdout.writeText(ctx.fs.basename(path) + \"\\n\");\n continue;\n }\n\n const showHeader = recursive || paths.length > 1;\n await listDir(path, pathArg, showHeader);\n } catch (err) {\n await ctx.stderr.writeText(`ls: cannot access '${pathArg}': No such file or directory\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "B9FA5A0657F2D55664756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED
|
@@ -5,30 +5,56 @@ var spec = {
|
|
|
5
5
|
flags: [
|
|
6
6
|
{ short: "a", long: "all" },
|
|
7
7
|
{ short: "l" },
|
|
8
|
+
{ short: "h" },
|
|
8
9
|
{ short: "1" },
|
|
9
10
|
{ short: "R" }
|
|
10
11
|
],
|
|
11
|
-
usage: "ls [-
|
|
12
|
+
usage: "ls [-alhR1] [file ...]"
|
|
12
13
|
};
|
|
13
|
-
var defaults = { all: false, long: false, onePerLine: false, recursive: false };
|
|
14
|
+
var defaults = { all: false, long: false, onePerLine: false, recursive: false, humanReadable: false };
|
|
14
15
|
var handler = (flags, flag) => {
|
|
15
16
|
if (flag.short === "a")
|
|
16
17
|
flags.all = true;
|
|
17
18
|
if (flag.short === "l")
|
|
18
19
|
flags.long = true;
|
|
20
|
+
if (flag.short === "h")
|
|
21
|
+
flags.humanReadable = true;
|
|
19
22
|
if (flag.short === "1")
|
|
20
23
|
flags.onePerLine = true;
|
|
21
24
|
if (flag.short === "R")
|
|
22
25
|
flags.recursive = true;
|
|
23
26
|
};
|
|
24
27
|
var parser = createFlagParser(spec, defaults, handler);
|
|
28
|
+
var BOLD_BLUE = "\x1B[1;34m";
|
|
29
|
+
var RESET = "\x1B[0m";
|
|
30
|
+
function formatSize(bytes, humanReadable) {
|
|
31
|
+
if (!humanReadable)
|
|
32
|
+
return String(bytes).padStart(8);
|
|
33
|
+
if (bytes < 1024)
|
|
34
|
+
return String(bytes).padStart(8);
|
|
35
|
+
const units = ["K", "M", "G", "T"];
|
|
36
|
+
let value = bytes;
|
|
37
|
+
let unitIndex = -1;
|
|
38
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
39
|
+
value /= 1024;
|
|
40
|
+
unitIndex++;
|
|
41
|
+
}
|
|
42
|
+
const formatted = value < 10 ? value.toFixed(1) : String(Math.floor(value));
|
|
43
|
+
return (formatted + units[unitIndex]).padStart(8);
|
|
44
|
+
}
|
|
45
|
+
function colorize(name, isDirectory, isTTY) {
|
|
46
|
+
if (!isTTY || !isDirectory)
|
|
47
|
+
return name;
|
|
48
|
+
return `${BOLD_BLUE}${name}${RESET}`;
|
|
49
|
+
}
|
|
25
50
|
var ls = async (ctx) => {
|
|
26
51
|
const result = parser.parse(ctx.args);
|
|
27
52
|
if (result.error) {
|
|
28
53
|
await parser.writeError(result.error, ctx.stderr);
|
|
29
54
|
return 1;
|
|
30
55
|
}
|
|
31
|
-
const { all: showAll, long: longFormat, onePerLine, recursive } = result.flags;
|
|
56
|
+
const { all: showAll, long: longFormat, onePerLine, recursive, humanReadable } = result.flags;
|
|
57
|
+
const isTTY = ctx.stdout.isTTY;
|
|
32
58
|
const paths = result.args.length === 0 ? ["."] : result.args;
|
|
33
59
|
let needsBlankLine = false;
|
|
34
60
|
const listDir = async (dirPath, displayPath, showHeader) => {
|
|
@@ -50,25 +76,51 @@ var ls = async (ctx) => {
|
|
|
50
76
|
const entryPath = ctx.fs.resolve(dirPath, entry);
|
|
51
77
|
try {
|
|
52
78
|
const entryStat = await ctx.fs.stat(entryPath);
|
|
53
|
-
const
|
|
79
|
+
const isDir = entryStat.isDirectory();
|
|
80
|
+
const type = isDir ? "d" : "-";
|
|
54
81
|
const perms = "rwxr-xr-x";
|
|
55
|
-
const size =
|
|
82
|
+
const size = formatSize(entryStat.size, humanReadable);
|
|
56
83
|
const date = entryStat.mtime.toISOString().slice(0, 10);
|
|
57
|
-
|
|
84
|
+
const name = colorize(entry, isDir, isTTY);
|
|
85
|
+
await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${name}
|
|
58
86
|
`);
|
|
59
87
|
} catch {
|
|
60
88
|
await ctx.stdout.writeText(`?????????? ${entry}
|
|
61
89
|
`);
|
|
62
90
|
}
|
|
63
91
|
}
|
|
64
|
-
} else if (onePerLine || !
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
} else if (onePerLine || !isTTY) {
|
|
93
|
+
if (isTTY) {
|
|
94
|
+
const dirSet = new Set;
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
try {
|
|
97
|
+
const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));
|
|
98
|
+
if (entryStat.isDirectory())
|
|
99
|
+
dirSet.add(entry);
|
|
100
|
+
} catch {}
|
|
101
|
+
}
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
await ctx.stdout.writeText(colorize(entry, dirSet.has(entry), true) + `
|
|
67
104
|
`);
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
await ctx.stdout.writeText(entry + `
|
|
109
|
+
`);
|
|
110
|
+
}
|
|
68
111
|
}
|
|
69
112
|
} else {
|
|
70
113
|
if (entries.length > 0) {
|
|
71
|
-
|
|
114
|
+
const dirSet = new Set;
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
try {
|
|
117
|
+
const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));
|
|
118
|
+
if (entryStat.isDirectory())
|
|
119
|
+
dirSet.add(entry);
|
|
120
|
+
} catch {}
|
|
121
|
+
}
|
|
122
|
+
const colored = entries.map((e) => colorize(e, dirSet.has(e), true));
|
|
123
|
+
await ctx.stdout.writeText(colored.join(" ") + `
|
|
72
124
|
`);
|
|
73
125
|
}
|
|
74
126
|
}
|
|
@@ -109,4 +161,4 @@ export {
|
|
|
109
161
|
ls
|
|
110
162
|
};
|
|
111
163
|
|
|
112
|
-
//# debugId=
|
|
164
|
+
//# debugId=775E65F60E1DA64F64756E2164756E21
|
|
@@ -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 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 [-
|
|
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 humanReadable: boolean;\n}\n\nconst spec = {\n name: \"ls\",\n flags: [\n { short: \"a\", long: \"all\" },\n { short: \"l\" },\n { short: \"h\" },\n { short: \"1\" },\n { short: \"R\" },\n ] as FlagDefinition[],\n usage: \"ls [-alhR1] [file ...]\",\n};\n\nconst defaults: LsFlags = { all: false, long: false, onePerLine: false, recursive: false, humanReadable: 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 === \"h\") flags.humanReadable = 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\nconst BOLD_BLUE = \"\\x1b[1;34m\";\nconst RESET = \"\\x1b[0m\";\n\nfunction formatSize(bytes: number, humanReadable: boolean): string {\n if (!humanReadable) return String(bytes).padStart(8);\n if (bytes < 1024) return String(bytes).padStart(8);\n const units = [\"K\", \"M\", \"G\", \"T\"];\n let value = bytes;\n let unitIndex = -1;\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024;\n unitIndex++;\n }\n const formatted = value < 10 ? value.toFixed(1) : String(Math.floor(value));\n return (formatted + units[unitIndex]!).padStart(8);\n}\n\nfunction colorize(name: string, isDirectory: boolean, isTTY: boolean): string {\n if (!isTTY || !isDirectory) return name;\n return `${BOLD_BLUE}${name}${RESET}`;\n}\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, humanReadable } = result.flags;\n const isTTY = ctx.stdout.isTTY;\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 isDir = entryStat.isDirectory();\n const type = isDir ? \"d\" : \"-\";\n const perms = \"rwxr-xr-x\";\n const size = formatSize(entryStat.size, humanReadable);\n const date = entryStat.mtime.toISOString().slice(0, 10);\n const name = colorize(entry, isDir, isTTY);\n await ctx.stdout.writeText(`${type}${perms} ${size} ${date} ${name}\\n`);\n } catch {\n await ctx.stdout.writeText(`?????????? ${entry}\\n`);\n }\n }\n } else if (onePerLine || !isTTY) {\n if (isTTY) {\n // -1 flag with TTY: still colorize directories\n const dirSet = new Set<string>();\n for (const entry of entries) {\n try {\n const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));\n if (entryStat.isDirectory()) dirSet.add(entry);\n } catch {}\n }\n for (const entry of entries) {\n await ctx.stdout.writeText(colorize(entry, dirSet.has(entry), true) + \"\\n\");\n }\n } else {\n for (const entry of entries) {\n await ctx.stdout.writeText(entry + \"\\n\");\n }\n }\n } else {\n // TTY default: space-separated with colors\n if (entries.length > 0) {\n const dirSet = new Set<string>();\n for (const entry of entries) {\n try {\n const entryStat = await ctx.fs.stat(ctx.fs.resolve(dirPath, entry));\n if (entryStat.isDirectory()) dirSet.add(entry);\n } catch {}\n }\n const colored = entries.map((e) => colorize(e, dirSet.has(e), true));\n await ctx.stdout.writeText(colored.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": ";AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "775E65F60E1DA64F64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/package.json
CHANGED