shell-dsl 0.0.30 → 0.0.32
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 +27 -1
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/commands/mv/mv.cjs +7 -1
- package/dist/cjs/src/commands/mv/mv.cjs.map +3 -3
- package/dist/cjs/src/commands/tree/tree.cjs +64 -27
- package/dist/cjs/src/commands/tree/tree.cjs.map +3 -3
- package/dist/cjs/src/fs/memfs-adapter.cjs +32 -110
- package/dist/cjs/src/fs/memfs-adapter.cjs.map +3 -3
- package/dist/cjs/src/fs/real-fs.cjs +34 -112
- package/dist/cjs/src/fs/real-fs.cjs.map +3 -3
- package/dist/cjs/src/fs/special-files.cjs +98 -0
- package/dist/cjs/src/fs/special-files.cjs.map +10 -0
- package/dist/cjs/src/index.cjs +2 -1
- package/dist/cjs/src/index.cjs.map +3 -3
- package/dist/cjs/src/interpreter/interpreter.cjs +9 -8
- package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
- package/dist/cjs/src/utils/glob.cjs +129 -0
- package/dist/cjs/src/utils/glob.cjs.map +10 -0
- package/dist/cjs/src/utils/index.cjs +3 -1
- package/dist/cjs/src/utils/index.cjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/commands/mv/mv.mjs +7 -1
- package/dist/mjs/src/commands/mv/mv.mjs.map +3 -3
- package/dist/mjs/src/commands/tree/tree.mjs +64 -27
- package/dist/mjs/src/commands/tree/tree.mjs.map +3 -3
- package/dist/mjs/src/fs/memfs-adapter.mjs +38 -110
- package/dist/mjs/src/fs/memfs-adapter.mjs.map +3 -3
- package/dist/mjs/src/fs/real-fs.mjs +40 -112
- package/dist/mjs/src/fs/real-fs.mjs.map +3 -3
- package/dist/mjs/src/fs/special-files.mjs +58 -0
- package/dist/mjs/src/fs/special-files.mjs.map +10 -0
- package/dist/mjs/src/index.mjs +3 -2
- package/dist/mjs/src/index.mjs.map +2 -2
- package/dist/mjs/src/interpreter/interpreter.mjs +9 -8
- package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
- package/dist/mjs/src/utils/glob.mjs +89 -0
- package/dist/mjs/src/utils/glob.mjs.map +10 -0
- package/dist/mjs/src/utils/index.mjs +3 -1
- package/dist/mjs/src/utils/index.mjs.map +3 -3
- package/dist/types/src/fs/real-fs.d.ts +0 -5
- package/dist/types/src/fs/special-files.d.ts +8 -0
- package/dist/types/src/index.d.ts +2 -1
- package/dist/types/src/utils/glob.d.ts +6 -0
- package/dist/types/src/utils/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -8,11 +8,19 @@ var spec = {
|
|
|
8
8
|
{ short: "d" },
|
|
9
9
|
{ short: "L", takesValue: true },
|
|
10
10
|
{ short: "I", takesValue: true },
|
|
11
|
-
{ long: "dirsfirst" }
|
|
11
|
+
{ long: "dirsfirst" },
|
|
12
|
+
{ long: "prune" }
|
|
12
13
|
],
|
|
13
|
-
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [directory ...]"
|
|
14
|
+
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]"
|
|
15
|
+
};
|
|
16
|
+
var defaults = {
|
|
17
|
+
all: false,
|
|
18
|
+
directoriesOnly: false,
|
|
19
|
+
maxDepth: Infinity,
|
|
20
|
+
dirsfirst: true,
|
|
21
|
+
prune: false,
|
|
22
|
+
ignorePatterns: []
|
|
14
23
|
};
|
|
15
|
-
var defaults = { all: false, directoriesOnly: false, maxDepth: Infinity, dirsfirst: true, ignorePatterns: [] };
|
|
16
24
|
var handlerResult = {};
|
|
17
25
|
var handler = (flags, flag, value) => {
|
|
18
26
|
if (flag.short === "a")
|
|
@@ -21,6 +29,8 @@ var handler = (flags, flag, value) => {
|
|
|
21
29
|
flags.directoriesOnly = true;
|
|
22
30
|
if (flag.long === "dirsfirst")
|
|
23
31
|
flags.dirsfirst = true;
|
|
32
|
+
if (flag.long === "prune")
|
|
33
|
+
flags.prune = true;
|
|
24
34
|
if (flag.short === "I" && value) {
|
|
25
35
|
if (flags.ignorePatterns === defaults.ignorePatterns) {
|
|
26
36
|
flags.ignorePatterns = [];
|
|
@@ -50,7 +60,7 @@ var tree = async (ctx) => {
|
|
|
50
60
|
await ctx.stderr.writeText(handlerResult.error);
|
|
51
61
|
return 1;
|
|
52
62
|
}
|
|
53
|
-
const { all: showAll, directoriesOnly, maxDepth, ignorePatterns } = result.flags;
|
|
63
|
+
const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;
|
|
54
64
|
const targetPath = result.args[0] ?? ".";
|
|
55
65
|
if (maxDepth < 1) {
|
|
56
66
|
await ctx.stderr.writeText(`tree: Invalid level, must be greater than 0
|
|
@@ -75,11 +85,14 @@ var tree = async (ctx) => {
|
|
|
75
85
|
}
|
|
76
86
|
let dirCount = 0;
|
|
77
87
|
let fileCount = 0;
|
|
88
|
+
const entriesCache = new Map;
|
|
89
|
+
const visibleContentCache = new Map;
|
|
78
90
|
await ctx.stdout.writeText(targetPath + `
|
|
79
91
|
`);
|
|
80
|
-
async function
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
async function getEntries(path) {
|
|
93
|
+
const cached = entriesCache.get(path);
|
|
94
|
+
if (cached)
|
|
95
|
+
return cached;
|
|
83
96
|
let entries = await ctx.fs.readdir(path);
|
|
84
97
|
if (!showAll) {
|
|
85
98
|
entries = entries.filter((e) => !e.startsWith("."));
|
|
@@ -88,39 +101,63 @@ var tree = async (ctx) => {
|
|
|
88
101
|
entries = entries.filter((e) => !ignorePatterns.some((p) => matchGlob(p, e)));
|
|
89
102
|
}
|
|
90
103
|
entries.sort();
|
|
104
|
+
const resolvedEntries = [];
|
|
105
|
+
for (const name of entries) {
|
|
106
|
+
const entryPath = ctx.fs.resolve(path, name);
|
|
107
|
+
try {
|
|
108
|
+
const entryStat = await ctx.fs.stat(entryPath);
|
|
109
|
+
resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });
|
|
110
|
+
} catch {}
|
|
111
|
+
}
|
|
112
|
+
entriesCache.set(path, resolvedEntries);
|
|
113
|
+
return resolvedEntries;
|
|
114
|
+
}
|
|
115
|
+
async function hasVisibleContent(path) {
|
|
116
|
+
const cached = visibleContentCache.get(path);
|
|
117
|
+
if (cached !== undefined)
|
|
118
|
+
return cached;
|
|
119
|
+
const entries = await getEntries(path);
|
|
120
|
+
for (const entry of entries) {
|
|
121
|
+
if (!entry.isDir) {
|
|
122
|
+
visibleContentCache.set(path, true);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (await hasVisibleContent(entry.path)) {
|
|
126
|
+
visibleContentCache.set(path, true);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
visibleContentCache.set(path, false);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
async function printTree(path, prefix, depth) {
|
|
134
|
+
if (depth > maxDepth)
|
|
135
|
+
return;
|
|
136
|
+
const entries = await getEntries(path);
|
|
91
137
|
const dirEntries = [];
|
|
92
138
|
const fileEntries = [];
|
|
93
139
|
for (const entry of entries) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (entryStat.isDirectory()) {
|
|
98
|
-
dirEntries.push(entry);
|
|
99
|
-
} else {
|
|
100
|
-
fileEntries.push(entry);
|
|
140
|
+
if (entry.isDir) {
|
|
141
|
+
if (prune && !await hasVisibleContent(entry.path)) {
|
|
142
|
+
continue;
|
|
101
143
|
}
|
|
102
|
-
|
|
144
|
+
dirEntries.push(entry);
|
|
145
|
+
} else {
|
|
146
|
+
fileEntries.push(entry);
|
|
147
|
+
}
|
|
103
148
|
}
|
|
104
149
|
const sortedEntries = directoriesOnly ? dirEntries : [...dirEntries, ...fileEntries];
|
|
105
150
|
for (let i = 0;i < sortedEntries.length; i++) {
|
|
106
151
|
const entry = sortedEntries[i];
|
|
107
152
|
const isLast = i === sortedEntries.length - 1;
|
|
108
153
|
const connector = isLast ? "└── " : "├── ";
|
|
109
|
-
|
|
110
|
-
let isDir = false;
|
|
111
|
-
try {
|
|
112
|
-
const entryStat = await ctx.fs.stat(entryPath);
|
|
113
|
-
isDir = entryStat.isDirectory();
|
|
114
|
-
} catch {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
await ctx.stdout.writeText(prefix + connector + entry + `
|
|
154
|
+
await ctx.stdout.writeText(prefix + connector + entry.name + `
|
|
118
155
|
`);
|
|
119
|
-
if (isDir) {
|
|
156
|
+
if (entry.isDir) {
|
|
120
157
|
dirCount++;
|
|
121
158
|
if (depth < maxDepth) {
|
|
122
159
|
const newPrefix = prefix + (isLast ? " " : "│ ");
|
|
123
|
-
await printTree(
|
|
160
|
+
await printTree(entry.path, newPrefix, depth + 1);
|
|
124
161
|
}
|
|
125
162
|
} else {
|
|
126
163
|
fileCount++;
|
|
@@ -139,4 +176,4 @@ export {
|
|
|
139
176
|
tree
|
|
140
177
|
};
|
|
141
178
|
|
|
142
|
-
//# debugId=
|
|
179
|
+
//# debugId=CEDB38313AEAA77264756E2164756E21
|
|
@@ -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 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 ] as FlagDefinition[],\n usage: \"tree [-adI] [-L level] [-I pattern] [--dirsfirst] [directory ...]\",\n};\n\nconst defaults: TreeFlags = {
|
|
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 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 return 0;\n};\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AACA;AACA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "CEDB38313AEAA77264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
// src/fs/memfs-adapter.ts
|
|
2
2
|
import * as pathModule from "path";
|
|
3
|
+
import { globVirtualFS } from "../utils/glob.mjs";
|
|
4
|
+
import {
|
|
5
|
+
discardsSpecialFileWrites,
|
|
6
|
+
existsSpecialFile,
|
|
7
|
+
getSpecialPathError,
|
|
8
|
+
readSpecialFile,
|
|
9
|
+
statSpecialFile
|
|
10
|
+
} from "./special-files.mjs";
|
|
3
11
|
function createVirtualFS(memfs) {
|
|
4
12
|
const { promises: fs } = memfs;
|
|
5
13
|
return {
|
|
6
14
|
readFile: async (path, encoding) => {
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
const specialContent = readSpecialFile(path, encoding);
|
|
16
|
+
if (specialContent !== undefined)
|
|
17
|
+
return specialContent;
|
|
9
18
|
const content = await fs.readFile(path);
|
|
10
19
|
const buf = Buffer.from(content);
|
|
11
20
|
return encoding ? buf.toString(encoding) : buf;
|
|
12
21
|
},
|
|
13
22
|
async readdir(path) {
|
|
23
|
+
const specialError = getSpecialPathError(path, "readdir");
|
|
24
|
+
if (specialError)
|
|
25
|
+
throw specialError;
|
|
14
26
|
const entries = await fs.readdir(path);
|
|
15
27
|
return entries.map(String);
|
|
16
28
|
},
|
|
17
29
|
async stat(path) {
|
|
30
|
+
const specialStat = statSpecialFile(path);
|
|
31
|
+
if (specialStat)
|
|
32
|
+
return specialStat;
|
|
18
33
|
const stats = await fs.stat(path);
|
|
19
34
|
return {
|
|
20
35
|
isFile: () => stats.isFile(),
|
|
@@ -24,6 +39,9 @@ function createVirtualFS(memfs) {
|
|
|
24
39
|
};
|
|
25
40
|
},
|
|
26
41
|
async exists(path) {
|
|
42
|
+
const specialExists = existsSpecialFile(path);
|
|
43
|
+
if (specialExists !== undefined)
|
|
44
|
+
return specialExists;
|
|
27
45
|
try {
|
|
28
46
|
await fs.stat(path);
|
|
29
47
|
return true;
|
|
@@ -32,15 +50,27 @@ function createVirtualFS(memfs) {
|
|
|
32
50
|
}
|
|
33
51
|
},
|
|
34
52
|
async writeFile(path, data) {
|
|
53
|
+
if (discardsSpecialFileWrites(path)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
35
56
|
await fs.writeFile(path, data);
|
|
36
57
|
},
|
|
37
58
|
async appendFile(path, data) {
|
|
59
|
+
if (discardsSpecialFileWrites(path)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
38
62
|
await fs.appendFile(path, data);
|
|
39
63
|
},
|
|
40
64
|
async mkdir(path, opts) {
|
|
65
|
+
const specialError = getSpecialPathError(path, "mkdir");
|
|
66
|
+
if (specialError)
|
|
67
|
+
throw specialError;
|
|
41
68
|
await fs.mkdir(path, opts);
|
|
42
69
|
},
|
|
43
70
|
async rm(path, opts) {
|
|
71
|
+
const specialError = getSpecialPathError(path, "rm");
|
|
72
|
+
if (specialError)
|
|
73
|
+
throw specialError;
|
|
44
74
|
try {
|
|
45
75
|
const stats = await fs.stat(path);
|
|
46
76
|
if (stats.isDirectory()) {
|
|
@@ -64,118 +94,16 @@ function createVirtualFS(memfs) {
|
|
|
64
94
|
},
|
|
65
95
|
async glob(pattern, opts) {
|
|
66
96
|
const cwd = opts?.cwd ?? "/";
|
|
67
|
-
return
|
|
97
|
+
return globVirtualFS({
|
|
98
|
+
readdir: (filePath) => this.readdir(filePath),
|
|
99
|
+
stat: (filePath) => this.stat(filePath),
|
|
100
|
+
resolve: (...paths) => this.resolve(...paths)
|
|
101
|
+
}, pattern, { cwd });
|
|
68
102
|
}
|
|
69
103
|
};
|
|
70
104
|
}
|
|
71
|
-
async function expandGlob(memfs, pattern, cwd) {
|
|
72
|
-
const { promises: fs } = memfs;
|
|
73
|
-
const patterns = expandBraces(pattern);
|
|
74
|
-
const allMatches = [];
|
|
75
|
-
for (const pat of patterns) {
|
|
76
|
-
const matches = await matchPattern(fs, pat, cwd);
|
|
77
|
-
allMatches.push(...matches);
|
|
78
|
-
}
|
|
79
|
-
return [...new Set(allMatches)].sort();
|
|
80
|
-
}
|
|
81
|
-
function expandBraces(pattern) {
|
|
82
|
-
const braceMatch = pattern.match(/\{([^{}]+)\}/);
|
|
83
|
-
if (!braceMatch)
|
|
84
|
-
return [pattern];
|
|
85
|
-
const before = pattern.slice(0, braceMatch.index);
|
|
86
|
-
const after = pattern.slice(braceMatch.index + braceMatch[0].length);
|
|
87
|
-
const options = braceMatch[1].split(",");
|
|
88
|
-
const results = [];
|
|
89
|
-
for (const opt of options) {
|
|
90
|
-
const expanded = expandBraces(before + opt + after);
|
|
91
|
-
results.push(...expanded);
|
|
92
|
-
}
|
|
93
|
-
return results;
|
|
94
|
-
}
|
|
95
|
-
async function matchPattern(fs, pattern, cwd) {
|
|
96
|
-
const parts = pattern.split("/").filter((p) => p !== "");
|
|
97
|
-
const isAbsolute = pattern.startsWith("/");
|
|
98
|
-
const startDir = isAbsolute ? "/" : cwd;
|
|
99
|
-
return matchParts(fs, parts, startDir, isAbsolute);
|
|
100
|
-
}
|
|
101
|
-
async function matchParts(fs, parts, currentPath, isAbsolute) {
|
|
102
|
-
if (parts.length === 0) {
|
|
103
|
-
return [currentPath];
|
|
104
|
-
}
|
|
105
|
-
const [part, ...rest] = parts;
|
|
106
|
-
if (part === "**") {
|
|
107
|
-
const results = [];
|
|
108
|
-
const withoutStar = await matchParts(fs, rest, currentPath, isAbsolute);
|
|
109
|
-
results.push(...withoutStar);
|
|
110
|
-
try {
|
|
111
|
-
const entries = await fs.readdir(currentPath);
|
|
112
|
-
for (const entry of entries) {
|
|
113
|
-
const entryPath = pathModule.join(currentPath, String(entry));
|
|
114
|
-
try {
|
|
115
|
-
const stat = await fs.stat(entryPath);
|
|
116
|
-
if (stat.isDirectory()) {
|
|
117
|
-
const subMatches = await matchParts(fs, parts, entryPath, isAbsolute);
|
|
118
|
-
results.push(...subMatches);
|
|
119
|
-
}
|
|
120
|
-
} catch {}
|
|
121
|
-
}
|
|
122
|
-
} catch {}
|
|
123
|
-
return results;
|
|
124
|
-
}
|
|
125
|
-
const regex = globToRegex(part);
|
|
126
|
-
try {
|
|
127
|
-
const entries = await fs.readdir(currentPath);
|
|
128
|
-
const results = [];
|
|
129
|
-
for (const entry of entries) {
|
|
130
|
-
const entryName = String(entry);
|
|
131
|
-
if (regex.test(entryName)) {
|
|
132
|
-
const entryPath = pathModule.join(currentPath, entryName);
|
|
133
|
-
if (rest.length === 0) {
|
|
134
|
-
results.push(entryPath);
|
|
135
|
-
} else {
|
|
136
|
-
try {
|
|
137
|
-
const stat = await fs.stat(entryPath);
|
|
138
|
-
if (stat.isDirectory()) {
|
|
139
|
-
const subMatches = await matchParts(fs, rest, entryPath, isAbsolute);
|
|
140
|
-
results.push(...subMatches);
|
|
141
|
-
}
|
|
142
|
-
} catch {}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return results;
|
|
147
|
-
} catch {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function globToRegex(pattern) {
|
|
152
|
-
let regex = "^";
|
|
153
|
-
for (let i = 0;i < pattern.length; i++) {
|
|
154
|
-
const char = pattern[i];
|
|
155
|
-
if (char === "*") {
|
|
156
|
-
regex += "[^/]*";
|
|
157
|
-
} else if (char === "?") {
|
|
158
|
-
regex += "[^/]";
|
|
159
|
-
} else if (char === "[") {
|
|
160
|
-
let j = i + 1;
|
|
161
|
-
let classContent = "";
|
|
162
|
-
while (j < pattern.length && pattern[j] !== "]") {
|
|
163
|
-
classContent += pattern[j];
|
|
164
|
-
j++;
|
|
165
|
-
}
|
|
166
|
-
regex += `[${classContent}]`;
|
|
167
|
-
i = j;
|
|
168
|
-
} else if (".+^${}()|\\".includes(char)) {
|
|
169
|
-
regex += "\\" + char;
|
|
170
|
-
} else {
|
|
171
|
-
regex += char;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
regex += "$";
|
|
175
|
-
return new RegExp(regex);
|
|
176
|
-
}
|
|
177
105
|
export {
|
|
178
106
|
createVirtualFS
|
|
179
107
|
};
|
|
180
108
|
|
|
181
|
-
//# debugId=
|
|
109
|
+
//# debugId=DF93BEF2761EBF0164756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/fs/memfs-adapter.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { IFs } from \"memfs\";\nimport type { VirtualFS, FileStat } from \"../types.mjs\";\nimport * as pathModule from \"path\";\n\nexport function createVirtualFS(memfs: IFs): VirtualFS {\n const { promises: fs } = memfs;\n\n return {\n readFile: (async (path: string, encoding?: BufferEncoding): Promise<Buffer | string> => {\n
|
|
5
|
+
"import type { IFs } from \"memfs\";\nimport type { VirtualFS, FileStat } from \"../types.mjs\";\nimport * as pathModule from \"path\";\nimport { globVirtualFS } from \"../utils/glob.mjs\";\nimport {\n discardsSpecialFileWrites,\n existsSpecialFile,\n getSpecialPathError,\n readSpecialFile,\n statSpecialFile,\n} from \"./special-files.mjs\";\n\nexport function createVirtualFS(memfs: IFs): VirtualFS {\n const { promises: fs } = memfs;\n\n return {\n readFile: (async (path: string, encoding?: BufferEncoding): Promise<Buffer | string> => {\n const specialContent = readSpecialFile(path, encoding);\n if (specialContent !== undefined) return specialContent;\n const content = await fs.readFile(path);\n const buf = Buffer.from(content);\n return encoding ? buf.toString(encoding) : buf;\n }) as VirtualFS[\"readFile\"],\n\n async readdir(path: string): Promise<string[]> {\n const specialError = getSpecialPathError(path, \"readdir\");\n if (specialError) throw specialError;\n const entries = await fs.readdir(path);\n return entries.map(String);\n },\n\n async stat(path: string): Promise<FileStat> {\n const specialStat = statSpecialFile(path);\n if (specialStat) return specialStat;\n const stats = await fs.stat(path);\n return {\n isFile: () => stats.isFile(),\n isDirectory: () => stats.isDirectory(),\n size: Number(stats.size),\n mtime: new Date(stats.mtime),\n };\n },\n\n async exists(path: string): Promise<boolean> {\n const specialExists = existsSpecialFile(path);\n if (specialExists !== undefined) return specialExists;\n try {\n await fs.stat(path);\n return true;\n } catch {\n return false;\n }\n },\n\n async writeFile(path: string, data: Buffer | string): Promise<void> {\n if (discardsSpecialFileWrites(path)) {\n return;\n }\n await fs.writeFile(path, data);\n },\n\n async appendFile(path: string, data: Buffer | string): Promise<void> {\n if (discardsSpecialFileWrites(path)) {\n return;\n }\n await fs.appendFile(path, data);\n },\n\n async mkdir(path: string, opts?: { recursive?: boolean }): Promise<void> {\n const specialError = getSpecialPathError(path, \"mkdir\");\n if (specialError) throw specialError;\n await fs.mkdir(path, opts);\n },\n\n async rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void> {\n const specialError = getSpecialPathError(path, \"rm\");\n if (specialError) throw specialError;\n try {\n const stats = await fs.stat(path);\n if (stats.isDirectory()) {\n await fs.rmdir(path, { recursive: opts?.recursive });\n } else {\n await fs.unlink(path);\n }\n } catch (err) {\n if (!opts?.force) throw err;\n }\n },\n\n resolve(...paths: string[]): string {\n return pathModule.resolve(...paths);\n },\n\n dirname(path: string): string {\n return pathModule.dirname(path);\n },\n\n basename(path: string): string {\n return pathModule.basename(path);\n },\n\n async glob(pattern: string, opts?: { cwd?: string }): Promise<string[]> {\n const cwd = opts?.cwd ?? \"/\";\n return globVirtualFS(\n {\n readdir: (filePath: string) => this.readdir(filePath),\n stat: (filePath: string) => this.stat(filePath),\n resolve: (...paths: string[]) => this.resolve(...paths),\n },\n pattern,\n { cwd }\n );\n },\n };\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAEA;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "DF93BEF2761EBF0164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|