shell-dsl 0.0.31 → 0.0.33
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 +110 -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 +26 -3
- package/dist/cjs/src/fs/memfs-adapter.cjs.map +3 -3
- package/dist/cjs/src/fs/real-fs.cjs +32 -1
- 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 +3 -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/vcs/diff.cjs +102 -0
- package/dist/cjs/src/vcs/diff.cjs.map +10 -0
- package/dist/cjs/src/vcs/index.cjs +47 -0
- package/dist/cjs/src/vcs/index.cjs.map +10 -0
- package/dist/cjs/src/vcs/match.cjs +106 -0
- package/dist/cjs/src/vcs/match.cjs.map +10 -0
- package/dist/cjs/src/vcs/snapshot.cjs +112 -0
- package/dist/cjs/src/vcs/snapshot.cjs.map +10 -0
- package/dist/cjs/src/vcs/storage.cjs +120 -0
- package/dist/cjs/src/vcs/storage.cjs.map +10 -0
- package/dist/cjs/src/vcs/types.cjs +30 -0
- package/dist/cjs/src/vcs/types.cjs.map +9 -0
- package/dist/cjs/src/vcs/vcs.cjs +305 -0
- package/dist/cjs/src/vcs/vcs.cjs.map +10 -0
- package/dist/cjs/src/vcs/walk.cjs +83 -0
- package/dist/cjs/src/vcs/walk.cjs.map +10 -0
- 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 +32 -3
- package/dist/mjs/src/fs/memfs-adapter.mjs.map +3 -3
- package/dist/mjs/src/fs/real-fs.mjs +38 -1
- 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 -1
- package/dist/mjs/src/index.mjs.map +3 -3
- package/dist/mjs/src/interpreter/interpreter.mjs +9 -8
- package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
- package/dist/mjs/src/vcs/diff.mjs +62 -0
- package/dist/mjs/src/vcs/diff.mjs.map +10 -0
- package/dist/mjs/src/vcs/index.mjs +7 -0
- package/dist/mjs/src/vcs/index.mjs.map +10 -0
- package/dist/mjs/src/vcs/match.mjs +66 -0
- package/dist/mjs/src/vcs/match.mjs.map +10 -0
- package/dist/mjs/src/vcs/snapshot.mjs +72 -0
- package/dist/mjs/src/vcs/snapshot.mjs.map +10 -0
- package/dist/mjs/src/vcs/storage.mjs +79 -0
- package/dist/mjs/src/vcs/storage.mjs.map +10 -0
- package/dist/mjs/src/vcs/types.mjs +2 -0
- package/dist/mjs/src/vcs/types.mjs.map +9 -0
- package/dist/mjs/src/vcs/vcs.mjs +265 -0
- package/dist/mjs/src/vcs/vcs.mjs.map +10 -0
- package/dist/mjs/src/vcs/walk.mjs +43 -0
- package/dist/mjs/src/vcs/walk.mjs.map +10 -0
- package/dist/types/src/fs/special-files.d.ts +8 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/vcs/diff.d.ts +10 -0
- package/dist/types/src/vcs/index.d.ts +2 -0
- package/dist/types/src/vcs/match.d.ts +5 -0
- package/dist/types/src/vcs/snapshot.d.ts +20 -0
- package/dist/types/src/vcs/storage.d.ts +22 -0
- package/dist/types/src/vcs/types.d.ts +74 -0
- package/dist/types/src/vcs/vcs.d.ts +35 -0
- package/dist/types/src/vcs/walk.d.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,6 +36,7 @@ bun add shell-dsl memfs
|
|
|
36
36
|
- **Automatic escaping** — Interpolated values are escaped by default for safety
|
|
37
37
|
- **POSIX-inspired syntax** — Pipes, redirects, control flow operators, and more
|
|
38
38
|
- **Streaming pipelines** — Commands communicate via async iteration
|
|
39
|
+
- **Version control** — Built-in VCS with commits, branches, checkout, and diffs on any virtual filesystem
|
|
39
40
|
- **TypeScript-first** — Full type definitions included
|
|
40
41
|
|
|
41
42
|
## Getting Started
|
|
@@ -564,7 +565,7 @@ import { echo, cat, grep, wc, cp, mv, touch, tee, tree, find, sed, awk, cut } fr
|
|
|
564
565
|
| `mv` | Move/rename files/directories (`-n` no-clobber) |
|
|
565
566
|
| `touch` | Create empty files or update timestamps (`-c` no-create) |
|
|
566
567
|
| `tee` | Duplicate stdin to stdout and files (`-a` append) |
|
|
567
|
-
| `tree` | Display directory structure as tree (`-a` all, `-d` dirs only, `-L <n>` depth) |
|
|
568
|
+
| `tree` | Display directory structure as tree (`-a` all, `-d` dirs only, `-L <n>` depth, `-I <pattern>` ignore, `--prune` remove empty dirs) |
|
|
568
569
|
| `find` | Search for files (`-name`, `-iname`, `-type f\|d`, `-maxdepth`, `-mindepth`) |
|
|
569
570
|
| `sed` | Stream editor (`s///`, `d`, `p`, `-n`, `-e`) |
|
|
570
571
|
| `awk` | Pattern scanning (`{print $1}`, `-F`, `NF`, `NR`) |
|
|
@@ -745,6 +746,109 @@ const fs = new FileSystem("/", {}, createWebUnderlyingFS(root));
|
|
|
745
746
|
```
|
|
746
747
|
|
|
747
748
|
|
|
749
|
+
## Version Control
|
|
750
|
+
|
|
751
|
+
`VersionControlSystem` adds git-like version control to any `VirtualFS`. It tracks changes as diffs, supports branching, and stores metadata in a `.vcs` directory.
|
|
752
|
+
|
|
753
|
+
```ts
|
|
754
|
+
import { VersionControlSystem, createVirtualFS } from "shell-dsl";
|
|
755
|
+
import { createFsFromVolume, Volume } from "memfs";
|
|
756
|
+
|
|
757
|
+
const vol = new Volume();
|
|
758
|
+
vol.fromJSON({
|
|
759
|
+
"/project/src/index.ts": 'console.log("hello")',
|
|
760
|
+
"/project/README.md": "# My Project",
|
|
761
|
+
});
|
|
762
|
+
const fs = createVirtualFS(createFsFromVolume(vol));
|
|
763
|
+
|
|
764
|
+
const vcs = new VersionControlSystem({
|
|
765
|
+
fs,
|
|
766
|
+
path: "/project",
|
|
767
|
+
});
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Committing Changes
|
|
771
|
+
|
|
772
|
+
```ts
|
|
773
|
+
// Commit all pending changes
|
|
774
|
+
const rev = await vcs.commit("initial commit");
|
|
775
|
+
|
|
776
|
+
// Selective commit with glob patterns (relative to root path)
|
|
777
|
+
await vcs.commit("update src only", { paths: ["/src/**"] });
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### Checking Status
|
|
781
|
+
|
|
782
|
+
`status()` returns a `DiffEntry[]` describing uncommitted changes:
|
|
783
|
+
|
|
784
|
+
```ts
|
|
785
|
+
const changes = await vcs.status();
|
|
786
|
+
for (const entry of changes) {
|
|
787
|
+
console.log(entry.type, entry.path); // "add" | "modify" | "delete"
|
|
788
|
+
}
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Checkout
|
|
792
|
+
|
|
793
|
+
```ts
|
|
794
|
+
// Checkout a specific revision (errors if working tree is dirty)
|
|
795
|
+
await vcs.checkout(1);
|
|
796
|
+
|
|
797
|
+
// Force checkout, discarding uncommitted changes
|
|
798
|
+
await vcs.checkout(1, { force: true });
|
|
799
|
+
|
|
800
|
+
// Partial checkout — restore specific files without changing HEAD
|
|
801
|
+
await vcs.checkout(1, { paths: ["/src/index.ts", "/**/*.txt"] });
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Branching
|
|
805
|
+
|
|
806
|
+
```ts
|
|
807
|
+
// Create a branch at HEAD
|
|
808
|
+
await vcs.branch("feature");
|
|
809
|
+
|
|
810
|
+
// Switch to a branch
|
|
811
|
+
await vcs.checkout("feature");
|
|
812
|
+
|
|
813
|
+
// List all branches
|
|
814
|
+
const branches = await vcs.branches();
|
|
815
|
+
// [{ name: "main", revision: 1, current: false },
|
|
816
|
+
// { name: "feature", revision: 1, current: true }]
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### History and Diffs
|
|
820
|
+
|
|
821
|
+
```ts
|
|
822
|
+
// Revision history
|
|
823
|
+
const entries = await vcs.log();
|
|
824
|
+
const filtered = await vcs.log({ path: "src/index.ts", limit: 10 });
|
|
825
|
+
|
|
826
|
+
// Diff between two revisions
|
|
827
|
+
const diff = await vcs.diff(1, 2);
|
|
828
|
+
for (const entry of diff) {
|
|
829
|
+
console.log(entry.type, entry.path); // "add" | "modify" | "delete"
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Current HEAD info
|
|
833
|
+
const head = await vcs.head();
|
|
834
|
+
// { branch: "main", revision: 2 }
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Separate VCS Storage
|
|
838
|
+
|
|
839
|
+
By default, metadata lives in `{path}/.vcs`. You can store it on a different filesystem:
|
|
840
|
+
|
|
841
|
+
```ts
|
|
842
|
+
const vcs = new VersionControlSystem({
|
|
843
|
+
fs: workingTreeFs,
|
|
844
|
+
path: "/project",
|
|
845
|
+
vcsPath: {
|
|
846
|
+
fs: metadataFs, // different VirtualFS instance
|
|
847
|
+
path: "/meta/.vcs", // custom location
|
|
848
|
+
},
|
|
849
|
+
});
|
|
850
|
+
```
|
|
851
|
+
|
|
748
852
|
## Low-Level API
|
|
749
853
|
|
|
750
854
|
For advanced use cases (custom tooling, AST inspection):
|
|
@@ -809,6 +913,11 @@ import type {
|
|
|
809
913
|
Permission,
|
|
810
914
|
PermissionRules,
|
|
811
915
|
UnderlyingFS,
|
|
916
|
+
VCSConfig,
|
|
917
|
+
Revision,
|
|
918
|
+
DiffEntry,
|
|
919
|
+
LogEntry,
|
|
920
|
+
BranchInfo,
|
|
812
921
|
} from "shell-dsl";
|
|
813
922
|
```
|
|
814
923
|
|
package/dist/cjs/package.json
CHANGED
|
@@ -43,6 +43,7 @@ __export(exports_mv, {
|
|
|
43
43
|
});
|
|
44
44
|
module.exports = __toCommonJS(exports_mv);
|
|
45
45
|
var import_flag_parser = require("../../utils/flag-parser.cjs");
|
|
46
|
+
var import_special_files = require("../../fs/special-files.cjs");
|
|
46
47
|
var spec = {
|
|
47
48
|
name: "mv",
|
|
48
49
|
flags: [
|
|
@@ -88,6 +89,11 @@ var mv = async (ctx) => {
|
|
|
88
89
|
try {
|
|
89
90
|
await ctx.fs.stat(srcPath);
|
|
90
91
|
const finalDest = destIsDir ? ctx.fs.resolve(destPath, ctx.fs.basename(srcPath)) : destPath;
|
|
92
|
+
if (import_special_files.isDevNullPath(srcPath) || import_special_files.isDevNullPath(finalDest)) {
|
|
93
|
+
await ctx.stderr.writeText(`mv: cannot move to or from special file '${import_special_files.DEV_NULL_PATH}'
|
|
94
|
+
`);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
91
97
|
if (noClobber) {
|
|
92
98
|
const exists = await ctx.fs.exists(finalDest);
|
|
93
99
|
if (exists)
|
|
@@ -132,4 +138,4 @@ async function moveDirectory(ctx, src, dest, noClobber) {
|
|
|
132
138
|
await ctx.fs.rm(src, { recursive: true });
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
//# debugId=
|
|
141
|
+
//# debugId=C4CE62A58C3EA07364756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/commands/mv/mv.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\n\ninterface MvFlags {\n noClobber: boolean;\n}\n\nconst spec = {\n name: \"mv\",\n flags: [\n { short: \"n\", long: \"no-clobber\" },\n { short: \"f\", long: \"force\" },\n ] as FlagDefinition[],\n usage: \"mv [-nf] source ... dest\",\n};\n\nconst defaults: MvFlags = { noClobber: false };\n\nconst handler = (flags: MvFlags, flag: FlagDefinition) => {\n if (flag.short === \"n\") flags.noClobber = true;\n // -f is default behavior, so we don't need to do anything\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const mv: 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 { noClobber } = result.flags;\n const paths = result.args;\n\n if (paths.length < 2) {\n await ctx.stderr.writeText(\"mv: missing destination file operand\\n\");\n return 1;\n }\n\n const sources = paths.slice(0, -1);\n const dest = paths[paths.length - 1]!;\n const destPath = ctx.fs.resolve(ctx.cwd, dest);\n\n // Check if destination is a directory\n let destIsDir = false;\n try {\n const stat = await ctx.fs.stat(destPath);\n destIsDir = stat.isDirectory();\n } catch {\n // Destination doesn't exist\n }\n\n // If multiple sources, dest must be a directory\n if (sources.length > 1 && !destIsDir) {\n await ctx.stderr.writeText(`mv: target '${dest}' is not a directory\\n`);\n return 1;\n }\n\n for (const source of sources) {\n const srcPath = ctx.fs.resolve(ctx.cwd, source);\n\n try {\n // Check source exists\n await ctx.fs.stat(srcPath);\n\n // Determine final destination path\n const finalDest = destIsDir\n ? ctx.fs.resolve(destPath, ctx.fs.basename(srcPath))\n : destPath;\n\n // Check if dest exists and noClobber\n if (noClobber) {\n const exists = await ctx.fs.exists(finalDest);\n if (exists) continue; // Skip silently\n }\n\n // Move: copy then delete\n const srcStat = await ctx.fs.stat(srcPath);\n if (srcStat.isDirectory()) {\n await moveDirectory(ctx, srcPath, finalDest, noClobber);\n } else {\n const content = await ctx.fs.readFile(srcPath);\n await ctx.fs.writeFile(finalDest, content);\n await ctx.fs.rm(srcPath);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await ctx.stderr.writeText(`mv: cannot stat '${source}': ${message}\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n\nasync function moveDirectory(\n ctx: Parameters<Command>[0],\n src: string,\n dest: string,\n noClobber: boolean\n): Promise<void> {\n // Create destination directory\n await ctx.fs.mkdir(dest, { recursive: true });\n\n // Read source directory contents\n const entries = await ctx.fs.readdir(src);\n\n for (const entry of entries) {\n const srcPath = ctx.fs.resolve(src, entry);\n const destPath = ctx.fs.resolve(dest, entry);\n\n const stat = await ctx.fs.stat(srcPath);\n\n if (stat.isDirectory()) {\n await moveDirectory(ctx, srcPath, destPath, noClobber);\n } else {\n if (noClobber) {\n const exists = await ctx.fs.exists(destPath);\n if (exists) continue;\n }\n const content = await ctx.fs.readFile(srcPath);\n await ctx.fs.writeFile(destPath, content);\n }\n }\n\n // Remove source directory after copying\n await ctx.fs.rm(src, { recursive: true });\n}\n"
|
|
5
|
+
"import type { Command } from \"../../types.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\nimport { DEV_NULL_PATH, isDevNullPath } from \"../../fs/special-files.cjs\";\n\ninterface MvFlags {\n noClobber: boolean;\n}\n\nconst spec = {\n name: \"mv\",\n flags: [\n { short: \"n\", long: \"no-clobber\" },\n { short: \"f\", long: \"force\" },\n ] as FlagDefinition[],\n usage: \"mv [-nf] source ... dest\",\n};\n\nconst defaults: MvFlags = { noClobber: false };\n\nconst handler = (flags: MvFlags, flag: FlagDefinition) => {\n if (flag.short === \"n\") flags.noClobber = true;\n // -f is default behavior, so we don't need to do anything\n};\n\nconst parser = createFlagParser(spec, defaults, handler);\n\nexport const mv: 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 { noClobber } = result.flags;\n const paths = result.args;\n\n if (paths.length < 2) {\n await ctx.stderr.writeText(\"mv: missing destination file operand\\n\");\n return 1;\n }\n\n const sources = paths.slice(0, -1);\n const dest = paths[paths.length - 1]!;\n const destPath = ctx.fs.resolve(ctx.cwd, dest);\n\n // Check if destination is a directory\n let destIsDir = false;\n try {\n const stat = await ctx.fs.stat(destPath);\n destIsDir = stat.isDirectory();\n } catch {\n // Destination doesn't exist\n }\n\n // If multiple sources, dest must be a directory\n if (sources.length > 1 && !destIsDir) {\n await ctx.stderr.writeText(`mv: target '${dest}' is not a directory\\n`);\n return 1;\n }\n\n for (const source of sources) {\n const srcPath = ctx.fs.resolve(ctx.cwd, source);\n\n try {\n // Check source exists\n await ctx.fs.stat(srcPath);\n\n // Determine final destination path\n const finalDest = destIsDir\n ? ctx.fs.resolve(destPath, ctx.fs.basename(srcPath))\n : destPath;\n\n if (isDevNullPath(srcPath) || isDevNullPath(finalDest)) {\n await ctx.stderr.writeText(`mv: cannot move to or from special file '${DEV_NULL_PATH}'\\n`);\n return 1;\n }\n\n // Check if dest exists and noClobber\n if (noClobber) {\n const exists = await ctx.fs.exists(finalDest);\n if (exists) continue; // Skip silently\n }\n\n // Move: copy then delete\n const srcStat = await ctx.fs.stat(srcPath);\n if (srcStat.isDirectory()) {\n await moveDirectory(ctx, srcPath, finalDest, noClobber);\n } else {\n const content = await ctx.fs.readFile(srcPath);\n await ctx.fs.writeFile(finalDest, content);\n await ctx.fs.rm(srcPath);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n await ctx.stderr.writeText(`mv: cannot stat '${source}': ${message}\\n`);\n return 1;\n }\n }\n\n return 0;\n};\n\nasync function moveDirectory(\n ctx: Parameters<Command>[0],\n src: string,\n dest: string,\n noClobber: boolean\n): Promise<void> {\n // Create destination directory\n await ctx.fs.mkdir(dest, { recursive: true });\n\n // Read source directory contents\n const entries = await ctx.fs.readdir(src);\n\n for (const entry of entries) {\n const srcPath = ctx.fs.resolve(src, entry);\n const destPath = ctx.fs.resolve(dest, entry);\n\n const stat = await ctx.fs.stat(srcPath);\n\n if (stat.isDirectory()) {\n await moveDirectory(ctx, srcPath, destPath, noClobber);\n } else {\n if (noClobber) {\n const exists = await ctx.fs.exists(destPath);\n if (exists) continue;\n }\n const content = await ctx.fs.readFile(srcPath);\n await ctx.fs.writeFile(destPath, content);\n }\n }\n\n // Remove source directory after copying\n await ctx.fs.rm(src, { recursive: true });\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;AAMA,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,IACL,EAAE,OAAO,KAAK,MAAM,aAAa;AAAA,IACjC,EAAE,OAAO,KAAK,MAAM,QAAQ;AAAA,EAC9B;AAAA,EACA,OAAO;AACT;AAEA,IAAM,WAAoB,EAAE,WAAW,MAAM;AAE7C,IAAM,UAAU,CAAC,OAAgB,SAAyB;AAAA,EACxD,IAAI,KAAK,UAAU;AAAA,IAAK,MAAM,YAAY;AAAA;AAI5C,IAAM,SAAS,oCAAiB,MAAM,UAAU,OAAO;AAEhD,IAAM,KAAc,OAAO,QAAQ;AAAA,EACxC,MAAM,SAAS,OAAO,MAAM,IAAI,IAAI;AAAA,EAEpC,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM,OAAO,WAAW,OAAO,OAAO,IAAI,MAAM;AAAA,IAChD,OAAO;AAAA,EACT;AAAA,EAEA,QAAQ,cAAc,OAAO;AAAA,EAC7B,MAAM,QAAQ,OAAO;AAAA,EAErB,IAAI,MAAM,SAAS,GAAG;AAAA,IACpB,MAAM,IAAI,OAAO,UAAU;AAAA,CAAwC;AAAA,IACnE,OAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,MAAM,MAAM,GAAG,EAAE;AAAA,EACjC,MAAM,OAAO,MAAM,MAAM,SAAS;AAAA,EAClC,MAAM,WAAW,IAAI,GAAG,QAAQ,IAAI,KAAK,IAAI;AAAA,EAG7C,IAAI,YAAY;AAAA,EAChB,IAAI;AAAA,IACF,MAAM,OAAO,MAAM,IAAI,GAAG,KAAK,QAAQ;AAAA,IACvC,YAAY,KAAK,YAAY;AAAA,IAC7B,MAAM;AAAA,EAKR,IAAI,QAAQ,SAAS,KAAK,CAAC,WAAW;AAAA,IACpC,MAAM,IAAI,OAAO,UAAU,eAAe;AAAA,CAA4B;AAAA,IACtE,OAAO;AAAA,EACT;AAAA,EAEA,WAAW,UAAU,SAAS;AAAA,IAC5B,MAAM,UAAU,IAAI,GAAG,QAAQ,IAAI,KAAK,MAAM;AAAA,IAE9C,IAAI;AAAA,MAEF,MAAM,IAAI,GAAG,KAAK,OAAO;AAAA,MAGzB,MAAM,YAAY,YACd,IAAI,GAAG,QAAQ,UAAU,IAAI,GAAG,SAAS,OAAO,CAAC,IACjD;AAAA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "C4CE62A58C3EA07364756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -51,11 +51,19 @@ var spec = {
|
|
|
51
51
|
{ short: "d" },
|
|
52
52
|
{ short: "L", takesValue: true },
|
|
53
53
|
{ short: "I", takesValue: true },
|
|
54
|
-
{ long: "dirsfirst" }
|
|
54
|
+
{ long: "dirsfirst" },
|
|
55
|
+
{ long: "prune" }
|
|
55
56
|
],
|
|
56
|
-
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [directory ...]"
|
|
57
|
+
usage: "tree [-adI] [-L level] [-I pattern] [--dirsfirst] [--prune] [directory ...]"
|
|
58
|
+
};
|
|
59
|
+
var defaults = {
|
|
60
|
+
all: false,
|
|
61
|
+
directoriesOnly: false,
|
|
62
|
+
maxDepth: Infinity,
|
|
63
|
+
dirsfirst: true,
|
|
64
|
+
prune: false,
|
|
65
|
+
ignorePatterns: []
|
|
57
66
|
};
|
|
58
|
-
var defaults = { all: false, directoriesOnly: false, maxDepth: Infinity, dirsfirst: true, ignorePatterns: [] };
|
|
59
67
|
var handlerResult = {};
|
|
60
68
|
var handler = (flags, flag, value) => {
|
|
61
69
|
if (flag.short === "a")
|
|
@@ -64,6 +72,8 @@ var handler = (flags, flag, value) => {
|
|
|
64
72
|
flags.directoriesOnly = true;
|
|
65
73
|
if (flag.long === "dirsfirst")
|
|
66
74
|
flags.dirsfirst = true;
|
|
75
|
+
if (flag.long === "prune")
|
|
76
|
+
flags.prune = true;
|
|
67
77
|
if (flag.short === "I" && value) {
|
|
68
78
|
if (flags.ignorePatterns === defaults.ignorePatterns) {
|
|
69
79
|
flags.ignorePatterns = [];
|
|
@@ -93,7 +103,7 @@ var tree = async (ctx) => {
|
|
|
93
103
|
await ctx.stderr.writeText(handlerResult.error);
|
|
94
104
|
return 1;
|
|
95
105
|
}
|
|
96
|
-
const { all: showAll, directoriesOnly, maxDepth, ignorePatterns } = result.flags;
|
|
106
|
+
const { all: showAll, directoriesOnly, maxDepth, prune, ignorePatterns } = result.flags;
|
|
97
107
|
const targetPath = result.args[0] ?? ".";
|
|
98
108
|
if (maxDepth < 1) {
|
|
99
109
|
await ctx.stderr.writeText(`tree: Invalid level, must be greater than 0
|
|
@@ -118,11 +128,14 @@ var tree = async (ctx) => {
|
|
|
118
128
|
}
|
|
119
129
|
let dirCount = 0;
|
|
120
130
|
let fileCount = 0;
|
|
131
|
+
const entriesCache = new Map;
|
|
132
|
+
const visibleContentCache = new Map;
|
|
121
133
|
await ctx.stdout.writeText(targetPath + `
|
|
122
134
|
`);
|
|
123
|
-
async function
|
|
124
|
-
|
|
125
|
-
|
|
135
|
+
async function getEntries(path) {
|
|
136
|
+
const cached = entriesCache.get(path);
|
|
137
|
+
if (cached)
|
|
138
|
+
return cached;
|
|
126
139
|
let entries = await ctx.fs.readdir(path);
|
|
127
140
|
if (!showAll) {
|
|
128
141
|
entries = entries.filter((e) => !e.startsWith("."));
|
|
@@ -131,39 +144,63 @@ var tree = async (ctx) => {
|
|
|
131
144
|
entries = entries.filter((e) => !ignorePatterns.some((p) => import_match_glob.matchGlob(p, e)));
|
|
132
145
|
}
|
|
133
146
|
entries.sort();
|
|
147
|
+
const resolvedEntries = [];
|
|
148
|
+
for (const name of entries) {
|
|
149
|
+
const entryPath = ctx.fs.resolve(path, name);
|
|
150
|
+
try {
|
|
151
|
+
const entryStat = await ctx.fs.stat(entryPath);
|
|
152
|
+
resolvedEntries.push({ name, path: entryPath, isDir: entryStat.isDirectory() });
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
155
|
+
entriesCache.set(path, resolvedEntries);
|
|
156
|
+
return resolvedEntries;
|
|
157
|
+
}
|
|
158
|
+
async function hasVisibleContent(path) {
|
|
159
|
+
const cached = visibleContentCache.get(path);
|
|
160
|
+
if (cached !== undefined)
|
|
161
|
+
return cached;
|
|
162
|
+
const entries = await getEntries(path);
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
if (!entry.isDir) {
|
|
165
|
+
visibleContentCache.set(path, true);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
if (await hasVisibleContent(entry.path)) {
|
|
169
|
+
visibleContentCache.set(path, true);
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
visibleContentCache.set(path, false);
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
async function printTree(path, prefix, depth) {
|
|
177
|
+
if (depth > maxDepth)
|
|
178
|
+
return;
|
|
179
|
+
const entries = await getEntries(path);
|
|
134
180
|
const dirEntries = [];
|
|
135
181
|
const fileEntries = [];
|
|
136
182
|
for (const entry of entries) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (entryStat.isDirectory()) {
|
|
141
|
-
dirEntries.push(entry);
|
|
142
|
-
} else {
|
|
143
|
-
fileEntries.push(entry);
|
|
183
|
+
if (entry.isDir) {
|
|
184
|
+
if (prune && !await hasVisibleContent(entry.path)) {
|
|
185
|
+
continue;
|
|
144
186
|
}
|
|
145
|
-
|
|
187
|
+
dirEntries.push(entry);
|
|
188
|
+
} else {
|
|
189
|
+
fileEntries.push(entry);
|
|
190
|
+
}
|
|
146
191
|
}
|
|
147
192
|
const sortedEntries = directoriesOnly ? dirEntries : [...dirEntries, ...fileEntries];
|
|
148
193
|
for (let i = 0;i < sortedEntries.length; i++) {
|
|
149
194
|
const entry = sortedEntries[i];
|
|
150
195
|
const isLast = i === sortedEntries.length - 1;
|
|
151
196
|
const connector = isLast ? "└── " : "├── ";
|
|
152
|
-
|
|
153
|
-
let isDir = false;
|
|
154
|
-
try {
|
|
155
|
-
const entryStat = await ctx.fs.stat(entryPath);
|
|
156
|
-
isDir = entryStat.isDirectory();
|
|
157
|
-
} catch {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
await ctx.stdout.writeText(prefix + connector + entry + `
|
|
197
|
+
await ctx.stdout.writeText(prefix + connector + entry.name + `
|
|
161
198
|
`);
|
|
162
|
-
if (isDir) {
|
|
199
|
+
if (entry.isDir) {
|
|
163
200
|
dirCount++;
|
|
164
201
|
if (depth < maxDepth) {
|
|
165
202
|
const newPrefix = prefix + (isLast ? " " : "│ ");
|
|
166
|
-
await printTree(
|
|
203
|
+
await printTree(entry.path, newPrefix, depth + 1);
|
|
167
204
|
}
|
|
168
205
|
} else {
|
|
169
206
|
fileCount++;
|
|
@@ -179,4 +216,4 @@ ${dirCount} ${dirWord}, ${fileCount} ${fileWord}
|
|
|
179
216
|
return 0;
|
|
180
217
|
};
|
|
181
218
|
|
|
182
|
-
//# debugId=
|
|
219
|
+
//# debugId=F4832ADA9F283A9964756E2164756E21
|
|
@@ -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.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\nimport { matchGlob } from \"../../utils/match-glob.cjs\";\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.cjs\";\nimport { createFlagParser, type FlagDefinition } from \"../../utils/flag-parser.cjs\";\nimport { matchGlob } from \"../../utils/match-glob.cjs\";\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACsD,IAAtD;AAC0B,IAA1B;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "F4832ADA9F283A9964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -68,21 +68,29 @@ __export(exports_memfs_adapter, {
|
|
|
68
68
|
module.exports = __toCommonJS(exports_memfs_adapter);
|
|
69
69
|
var pathModule = __toESM(require("path"));
|
|
70
70
|
var import_glob = require("../utils/glob.cjs");
|
|
71
|
+
var import_special_files = require("./special-files.cjs");
|
|
71
72
|
function createVirtualFS(memfs) {
|
|
72
73
|
const { promises: fs } = memfs;
|
|
73
74
|
return {
|
|
74
75
|
readFile: async (path, encoding) => {
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
const specialContent = import_special_files.readSpecialFile(path, encoding);
|
|
77
|
+
if (specialContent !== undefined)
|
|
78
|
+
return specialContent;
|
|
77
79
|
const content = await fs.readFile(path);
|
|
78
80
|
const buf = Buffer.from(content);
|
|
79
81
|
return encoding ? buf.toString(encoding) : buf;
|
|
80
82
|
},
|
|
81
83
|
async readdir(path) {
|
|
84
|
+
const specialError = import_special_files.getSpecialPathError(path, "readdir");
|
|
85
|
+
if (specialError)
|
|
86
|
+
throw specialError;
|
|
82
87
|
const entries = await fs.readdir(path);
|
|
83
88
|
return entries.map(String);
|
|
84
89
|
},
|
|
85
90
|
async stat(path) {
|
|
91
|
+
const specialStat = import_special_files.statSpecialFile(path);
|
|
92
|
+
if (specialStat)
|
|
93
|
+
return specialStat;
|
|
86
94
|
const stats = await fs.stat(path);
|
|
87
95
|
return {
|
|
88
96
|
isFile: () => stats.isFile(),
|
|
@@ -92,6 +100,9 @@ function createVirtualFS(memfs) {
|
|
|
92
100
|
};
|
|
93
101
|
},
|
|
94
102
|
async exists(path) {
|
|
103
|
+
const specialExists = import_special_files.existsSpecialFile(path);
|
|
104
|
+
if (specialExists !== undefined)
|
|
105
|
+
return specialExists;
|
|
95
106
|
try {
|
|
96
107
|
await fs.stat(path);
|
|
97
108
|
return true;
|
|
@@ -100,15 +111,27 @@ function createVirtualFS(memfs) {
|
|
|
100
111
|
}
|
|
101
112
|
},
|
|
102
113
|
async writeFile(path, data) {
|
|
114
|
+
if (import_special_files.discardsSpecialFileWrites(path)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
103
117
|
await fs.writeFile(path, data);
|
|
104
118
|
},
|
|
105
119
|
async appendFile(path, data) {
|
|
120
|
+
if (import_special_files.discardsSpecialFileWrites(path)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
106
123
|
await fs.appendFile(path, data);
|
|
107
124
|
},
|
|
108
125
|
async mkdir(path, opts) {
|
|
126
|
+
const specialError = import_special_files.getSpecialPathError(path, "mkdir");
|
|
127
|
+
if (specialError)
|
|
128
|
+
throw specialError;
|
|
109
129
|
await fs.mkdir(path, opts);
|
|
110
130
|
},
|
|
111
131
|
async rm(path, opts) {
|
|
132
|
+
const specialError = import_special_files.getSpecialPathError(path, "rm");
|
|
133
|
+
if (specialError)
|
|
134
|
+
throw specialError;
|
|
112
135
|
try {
|
|
113
136
|
const stats = await fs.stat(path);
|
|
114
137
|
if (stats.isDirectory()) {
|
|
@@ -141,4 +164,4 @@ function createVirtualFS(memfs) {
|
|
|
141
164
|
};
|
|
142
165
|
}
|
|
143
166
|
|
|
144
|
-
//# debugId=
|
|
167
|
+
//# debugId=F25975C12E3475B564756E2164756E21
|
|
@@ -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.cjs\";\nimport * as pathModule from \"path\";\nimport { globVirtualFS } from \"../utils/glob.cjs\";\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.cjs\";\nimport * as pathModule from \"path\";\nimport { globVirtualFS } from \"../utils/glob.cjs\";\nimport {\n discardsSpecialFileWrites,\n existsSpecialFile,\n getSpecialPathError,\n readSpecialFile,\n statSpecialFile,\n} from \"./special-files.cjs\";\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE4B,IAA5B;AAC8B,IAA9B;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "F25975C12E3475B564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -69,6 +69,7 @@ module.exports = __toCommonJS(exports_real_fs);
|
|
|
69
69
|
var path = __toESM(require("path"));
|
|
70
70
|
var nodeFs = __toESM(require("node:fs/promises"));
|
|
71
71
|
var import_glob = require("../utils/glob.cjs");
|
|
72
|
+
var import_special_files = require("./special-files.cjs");
|
|
72
73
|
var defaultFS = { promises: nodeFs };
|
|
73
74
|
var nodePathOps = {
|
|
74
75
|
separator: path.sep,
|
|
@@ -167,6 +168,10 @@ class FileSystem {
|
|
|
167
168
|
return resolved;
|
|
168
169
|
}
|
|
169
170
|
async readFile(filePath, encoding) {
|
|
171
|
+
const specialContent = import_special_files.readSpecialFile(filePath, encoding);
|
|
172
|
+
if (specialContent !== undefined) {
|
|
173
|
+
return specialContent;
|
|
174
|
+
}
|
|
170
175
|
this.checkPermission(filePath, "read");
|
|
171
176
|
const realPath = this.resolveSafePath(filePath);
|
|
172
177
|
const content = await this.underlyingFs.promises.readFile(realPath);
|
|
@@ -174,12 +179,20 @@ class FileSystem {
|
|
|
174
179
|
return encoding ? buf.toString(encoding) : buf;
|
|
175
180
|
}
|
|
176
181
|
async readdir(dirPath) {
|
|
182
|
+
const specialError = import_special_files.getSpecialPathError(dirPath, "readdir");
|
|
183
|
+
if (specialError) {
|
|
184
|
+
throw specialError;
|
|
185
|
+
}
|
|
177
186
|
this.checkPermission(dirPath, "read");
|
|
178
187
|
const realPath = this.resolveSafePath(dirPath);
|
|
179
188
|
const entries = await this.underlyingFs.promises.readdir(realPath);
|
|
180
189
|
return entries.map(String);
|
|
181
190
|
}
|
|
182
191
|
async stat(filePath) {
|
|
192
|
+
const specialStat = import_special_files.statSpecialFile(filePath);
|
|
193
|
+
if (specialStat) {
|
|
194
|
+
return specialStat;
|
|
195
|
+
}
|
|
183
196
|
this.checkPermission(filePath, "read");
|
|
184
197
|
const realPath = this.resolveSafePath(filePath);
|
|
185
198
|
const stats = await this.underlyingFs.promises.stat(realPath);
|
|
@@ -191,6 +204,10 @@ class FileSystem {
|
|
|
191
204
|
};
|
|
192
205
|
}
|
|
193
206
|
async exists(filePath) {
|
|
207
|
+
const specialExists = import_special_files.existsSpecialFile(filePath);
|
|
208
|
+
if (specialExists !== undefined) {
|
|
209
|
+
return specialExists;
|
|
210
|
+
}
|
|
194
211
|
try {
|
|
195
212
|
this.checkPermission(filePath, "read");
|
|
196
213
|
const realPath = this.resolveSafePath(filePath);
|
|
@@ -201,21 +218,35 @@ class FileSystem {
|
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
220
|
async writeFile(filePath, data) {
|
|
221
|
+
if (import_special_files.discardsSpecialFileWrites(filePath)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
204
224
|
this.checkPermission(filePath, "write");
|
|
205
225
|
const realPath = this.resolveSafePath(filePath);
|
|
206
226
|
await this.underlyingFs.promises.writeFile(realPath, data);
|
|
207
227
|
}
|
|
208
228
|
async appendFile(filePath, data) {
|
|
229
|
+
if (import_special_files.discardsSpecialFileWrites(filePath)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
209
232
|
this.checkPermission(filePath, "write");
|
|
210
233
|
const realPath = this.resolveSafePath(filePath);
|
|
211
234
|
await this.underlyingFs.promises.appendFile(realPath, data);
|
|
212
235
|
}
|
|
213
236
|
async mkdir(dirPath, opts) {
|
|
237
|
+
const specialError = import_special_files.getSpecialPathError(dirPath, "mkdir");
|
|
238
|
+
if (specialError) {
|
|
239
|
+
throw specialError;
|
|
240
|
+
}
|
|
214
241
|
this.checkPermission(dirPath, "write");
|
|
215
242
|
const realPath = this.resolveSafePath(dirPath);
|
|
216
243
|
await this.underlyingFs.promises.mkdir(realPath, opts);
|
|
217
244
|
}
|
|
218
245
|
async rm(filePath, opts) {
|
|
246
|
+
const specialError = import_special_files.getSpecialPathError(filePath, "rm");
|
|
247
|
+
if (specialError) {
|
|
248
|
+
throw specialError;
|
|
249
|
+
}
|
|
219
250
|
this.checkPermission(filePath, "write");
|
|
220
251
|
const realPath = this.resolveSafePath(filePath);
|
|
221
252
|
await this.underlyingFs.promises.rm(realPath, opts);
|
|
@@ -236,4 +267,4 @@ class FileSystem {
|
|
|
236
267
|
}
|
|
237
268
|
}
|
|
238
269
|
|
|
239
|
-
//# debugId=
|
|
270
|
+
//# debugId=58FDFA4CFF76BA5364756E2164756E21
|