shell-dsl 0.0.33 → 0.0.34
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 +23 -2
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/index.cjs.map +1 -1
- package/dist/cjs/src/vcs/diff.cjs +46 -41
- package/dist/cjs/src/vcs/diff.cjs.map +3 -3
- package/dist/cjs/src/vcs/index.cjs.map +1 -1
- package/dist/cjs/src/vcs/rules.cjs +180 -0
- package/dist/cjs/src/vcs/rules.cjs.map +10 -0
- package/dist/cjs/src/vcs/snapshot.cjs +137 -21
- package/dist/cjs/src/vcs/snapshot.cjs.map +3 -3
- package/dist/cjs/src/vcs/vcs.cjs +48 -31
- package/dist/cjs/src/vcs/vcs.cjs.map +3 -3
- package/dist/cjs/src/vcs/walk.cjs +24 -18
- package/dist/cjs/src/vcs/walk.cjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/index.mjs.map +1 -1
- package/dist/mjs/src/vcs/diff.mjs +46 -41
- package/dist/mjs/src/vcs/diff.mjs.map +3 -3
- package/dist/mjs/src/vcs/index.mjs.map +1 -1
- package/dist/mjs/src/vcs/rules.mjs +140 -0
- package/dist/mjs/src/vcs/rules.mjs.map +10 -0
- package/dist/mjs/src/vcs/snapshot.mjs +138 -22
- package/dist/mjs/src/vcs/snapshot.mjs.map +3 -3
- package/dist/mjs/src/vcs/vcs.mjs +48 -31
- package/dist/mjs/src/vcs/vcs.mjs.map +3 -3
- package/dist/mjs/src/vcs/walk.mjs +24 -18
- package/dist/mjs/src/vcs/walk.mjs.map +3 -3
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/vcs/diff.d.ts +3 -2
- package/dist/types/src/vcs/index.d.ts +1 -1
- package/dist/types/src/vcs/rules.d.ts +23 -0
- package/dist/types/src/vcs/snapshot.d.ts +7 -1
- package/dist/types/src/vcs/types.d.ts +26 -1
- package/dist/types/src/vcs/vcs.d.ts +2 -2
- package/dist/types/src/vcs/walk.d.ts +15 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -750,6 +750,8 @@ const fs = new FileSystem("/", {}, createWebUnderlyingFS(root));
|
|
|
750
750
|
|
|
751
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
752
|
|
|
753
|
+
Ignore and attribute rules are configured directly on the constructor:
|
|
754
|
+
|
|
753
755
|
```ts
|
|
754
756
|
import { VersionControlSystem, createVirtualFS } from "shell-dsl";
|
|
755
757
|
import { createFsFromVolume, Volume } from "memfs";
|
|
@@ -764,9 +766,25 @@ const fs = createVirtualFS(createFsFromVolume(vol));
|
|
|
764
766
|
const vcs = new VersionControlSystem({
|
|
765
767
|
fs,
|
|
766
768
|
path: "/project",
|
|
769
|
+
ignore: ["dist", "*.log"],
|
|
770
|
+
attributes: [
|
|
771
|
+
{ pattern: "assets/*.png", diff: "binary" },
|
|
772
|
+
{ pattern: "secrets/**", diff: "none" },
|
|
773
|
+
],
|
|
767
774
|
});
|
|
768
775
|
```
|
|
769
776
|
|
|
777
|
+
Ignore patterns apply only to untracked paths:
|
|
778
|
+
|
|
779
|
+
- Ignored untracked files are skipped by `status()` and full `commit()`
|
|
780
|
+
- Files already tracked by VCS remain tracked even if they later match an ignore rule
|
|
781
|
+
- Full `checkout()` preserves ignored untracked files
|
|
782
|
+
|
|
783
|
+
Attribute rules are applied in declaration order, with later matches winning. Supported properties:
|
|
784
|
+
|
|
785
|
+
- `binary?: boolean`
|
|
786
|
+
- `diff?: "text" | "binary" | "none"`
|
|
787
|
+
|
|
770
788
|
### Committing Changes
|
|
771
789
|
|
|
772
790
|
```ts
|
|
@@ -784,10 +802,13 @@ await vcs.commit("update src only", { paths: ["/src/**"] });
|
|
|
784
802
|
```ts
|
|
785
803
|
const changes = await vcs.status();
|
|
786
804
|
for (const entry of changes) {
|
|
787
|
-
console.log(entry.type, entry.path);
|
|
805
|
+
console.log(entry.type, entry.path, entry.diff, entry.binary);
|
|
806
|
+
// "add" | "modify" | "delete", "text" | "binary" | "none", boolean
|
|
788
807
|
}
|
|
789
808
|
```
|
|
790
809
|
|
|
810
|
+
When `diff` is `"none"`, the entry still reports the path and change type, but omits `content` and `previousContent`.
|
|
811
|
+
|
|
791
812
|
### Checkout
|
|
792
813
|
|
|
793
814
|
```ts
|
|
@@ -826,7 +847,7 @@ const filtered = await vcs.log({ path: "src/index.ts", limit: 10 });
|
|
|
826
847
|
// Diff between two revisions
|
|
827
848
|
const diff = await vcs.diff(1, 2);
|
|
828
849
|
for (const entry of diff) {
|
|
829
|
-
console.log(entry.type, entry.path);
|
|
850
|
+
console.log(entry.type, entry.path, entry.diff);
|
|
830
851
|
}
|
|
831
852
|
|
|
832
853
|
// Current HEAD info
|
package/dist/cjs/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n ArithmeticNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n isArithmeticNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n FileEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
|
|
5
|
+
"// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n ArithmeticNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n isArithmeticNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAgB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAuCO,IAjBP;AAoBwF,IAAxF;AAGgC,IAAhC;AAUO,IATP;AAYuC,IAAvC;AACwF,IAAxF;AAG8D,IAA9D;AAIqC,IAArC;",
|
|
8
8
|
"debugId": "27F0973A44539CA064756E2164756E21",
|
|
@@ -43,60 +43,65 @@ __export(exports_diff, {
|
|
|
43
43
|
diffManifests: () => diffManifests
|
|
44
44
|
});
|
|
45
45
|
module.exports = __toCommonJS(exports_diff);
|
|
46
|
-
var
|
|
47
|
-
|
|
46
|
+
var import_rules = require("./rules.cjs");
|
|
47
|
+
var import_snapshot = require("./snapshot.cjs");
|
|
48
|
+
function diffManifests(before, after, rules = new import_rules.VCSRules) {
|
|
48
49
|
const entries = [];
|
|
49
50
|
const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
50
51
|
for (const path of allPaths) {
|
|
51
52
|
const prev = before[path];
|
|
52
53
|
const curr = after[path];
|
|
53
54
|
if (!prev && curr) {
|
|
54
|
-
entries.push(
|
|
55
|
+
entries.push(createDiffEntry("add", path, curr, undefined, rules));
|
|
55
56
|
} else if (prev && !curr) {
|
|
56
|
-
entries.push(
|
|
57
|
-
} else if (prev && curr && prev
|
|
58
|
-
entries.push(
|
|
59
|
-
type: "modify",
|
|
60
|
-
path,
|
|
61
|
-
content: curr.content,
|
|
62
|
-
previousContent: prev.content
|
|
63
|
-
});
|
|
57
|
+
entries.push(createDiffEntry("delete", path, undefined, prev, rules));
|
|
58
|
+
} else if (prev && curr && !entriesEqual(prev, curr)) {
|
|
59
|
+
entries.push(createDiffEntry("modify", path, curr, prev, rules));
|
|
64
60
|
}
|
|
65
61
|
}
|
|
66
62
|
return entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
67
63
|
}
|
|
68
|
-
async function diffWorkingTree(fs, rootPath, manifest,
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
64
|
+
async function diffWorkingTree(fs, rootPath, manifest, rules = new import_rules.VCSRules({ internalDirName: ".vcs" })) {
|
|
65
|
+
const workingManifest = await import_snapshot.buildTreeManifest(fs, rootPath, {
|
|
66
|
+
rules,
|
|
67
|
+
trackedPaths: Object.keys(manifest)
|
|
68
|
+
});
|
|
69
|
+
return diffManifests(manifest, workingManifest, rules);
|
|
70
|
+
}
|
|
71
|
+
function createDiffEntry(type, path, current, previous, rules) {
|
|
72
|
+
const attributes = rules.resolveAttributes(path);
|
|
73
|
+
const entryKind = getEntryKind(current ?? previous);
|
|
74
|
+
const previousEntryKind = previous ? getEntryKind(previous) : undefined;
|
|
75
|
+
const entry = {
|
|
76
|
+
type,
|
|
77
|
+
path,
|
|
78
|
+
binary: attributes.binary,
|
|
79
|
+
diff: attributes.diff,
|
|
80
|
+
entryKind,
|
|
81
|
+
previousEntryKind
|
|
82
|
+
};
|
|
83
|
+
if (attributes.diff !== "none") {
|
|
84
|
+
if (isFileEntry(current)) {
|
|
85
|
+
entry.content = current.content;
|
|
88
86
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!seenPaths.has(manifestPath)) {
|
|
92
|
-
entries.push({
|
|
93
|
-
type: "delete",
|
|
94
|
-
path: manifestPath,
|
|
95
|
-
previousContent: manifest[manifestPath].content
|
|
96
|
-
});
|
|
87
|
+
if (isFileEntry(previous)) {
|
|
88
|
+
entry.previousContent = previous.content;
|
|
97
89
|
}
|
|
98
90
|
}
|
|
99
|
-
return
|
|
91
|
+
return entry;
|
|
92
|
+
}
|
|
93
|
+
function entriesEqual(a, b) {
|
|
94
|
+
if (getEntryKind(a) !== getEntryKind(b))
|
|
95
|
+
return false;
|
|
96
|
+
if (!isFileEntry(a) || !isFileEntry(b))
|
|
97
|
+
return true;
|
|
98
|
+
return a.content === b.content;
|
|
99
|
+
}
|
|
100
|
+
function getEntryKind(entry) {
|
|
101
|
+
return entry?.kind === "directory" ? "directory" : "file";
|
|
102
|
+
}
|
|
103
|
+
function isFileEntry(entry) {
|
|
104
|
+
return !!entry && entry.kind !== "directory";
|
|
100
105
|
}
|
|
101
106
|
|
|
102
|
-
//# debugId=
|
|
107
|
+
//# debugId=F0849DE3546011FF64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/diff.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.cjs\";\nimport type { TreeManifest, DiffEntry } from \"./types.cjs\";\nimport {
|
|
5
|
+
"import type { VirtualFS } from \"../types.cjs\";\nimport type { TreeManifest, DiffEntry, TreeEntry } from \"./types.cjs\";\nimport { VCSRules } from \"./rules.cjs\";\nimport { buildTreeManifest } from \"./snapshot.cjs\";\n\n/**\n * Compute diff entries between two tree manifests.\n */\nexport function diffManifests(\n before: TreeManifest,\n after: TreeManifest,\n rules: VCSRules = new VCSRules(),\n): DiffEntry[] {\n const entries: DiffEntry[] = [];\n const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n for (const path of allPaths) {\n const prev = before[path];\n const curr = after[path];\n\n if (!prev && curr) {\n entries.push(createDiffEntry(\"add\", path, curr, undefined, rules));\n } else if (prev && !curr) {\n entries.push(createDiffEntry(\"delete\", path, undefined, prev, rules));\n } else if (prev && curr && !entriesEqual(prev, curr)) {\n entries.push(createDiffEntry(\"modify\", path, curr, prev, rules));\n }\n }\n\n return entries.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/**\n * Compute diff between a tree manifest and the current working tree.\n */\nexport async function diffWorkingTree(\n fs: VirtualFS,\n rootPath: string,\n manifest: TreeManifest,\n rules: VCSRules = new VCSRules({ internalDirName: \".vcs\" }),\n): Promise<DiffEntry[]> {\n const workingManifest = await buildTreeManifest(fs, rootPath, {\n rules,\n trackedPaths: Object.keys(manifest),\n });\n return diffManifests(manifest, workingManifest, rules);\n}\n\nfunction createDiffEntry(\n type: DiffEntry[\"type\"],\n path: string,\n current: TreeEntry | undefined,\n previous: TreeEntry | undefined,\n rules: VCSRules,\n): DiffEntry {\n const attributes = rules.resolveAttributes(path);\n const entryKind = getEntryKind(current ?? previous);\n const previousEntryKind = previous ? getEntryKind(previous) : undefined;\n const entry: DiffEntry = {\n type,\n path,\n binary: attributes.binary,\n diff: attributes.diff,\n entryKind,\n previousEntryKind,\n };\n\n if (attributes.diff !== \"none\") {\n if (isFileEntry(current)) {\n entry.content = current.content;\n }\n if (isFileEntry(previous)) {\n entry.previousContent = previous.content;\n }\n }\n\n return entry;\n}\n\nfunction entriesEqual(a: TreeEntry, b: TreeEntry): boolean {\n if (getEntryKind(a) !== getEntryKind(b)) return false;\n if (!isFileEntry(a) || !isFileEntry(b)) return true;\n return a.content === b.content;\n}\n\nfunction getEntryKind(entry: TreeEntry | undefined): \"file\" | \"directory\" {\n return entry?.kind === \"directory\" ? \"directory\" : \"file\";\n}\n\nfunction isFileEntry(entry: TreeEntry | undefined): entry is Extract<TreeEntry, { kind?: \"file\" }> {\n return !!entry && entry.kind !== \"directory\";\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEyB,IAAzB;AAKO,SAAS,aAAa,CAC3B,QACA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEyB,IAAzB;AACkC,IAAlC;AAKO,SAAS,aAAa,CAC3B,QACA,OACA,QAAkB,IAAI,uBACT;AAAA,EACb,MAAM,UAAuB,CAAC;AAAA,EAC9B,MAAM,WAAW,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC;AAAA,EAExE,WAAW,QAAQ,UAAU;AAAA,IAC3B,MAAM,OAAO,OAAO;AAAA,IACpB,MAAM,OAAO,MAAM;AAAA,IAEnB,IAAI,CAAC,QAAQ,MAAM;AAAA,MACjB,QAAQ,KAAK,gBAAgB,OAAO,MAAM,MAAM,WAAW,KAAK,CAAC;AAAA,IACnE,EAAO,SAAI,QAAQ,CAAC,MAAM;AAAA,MACxB,QAAQ,KAAK,gBAAgB,UAAU,MAAM,WAAW,MAAM,KAAK,CAAC;AAAA,IACtE,EAAO,SAAI,QAAQ,QAAQ,CAAC,aAAa,MAAM,IAAI,GAAG;AAAA,MACpD,QAAQ,KAAK,gBAAgB,UAAU,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,OAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAM5D,eAAsB,eAAe,CACnC,IACA,UACA,UACA,QAAkB,IAAI,sBAAS,EAAE,iBAAiB,OAAO,CAAC,GACpC;AAAA,EACtB,MAAM,kBAAkB,MAAM,kCAAkB,IAAI,UAAU;AAAA,IAC5D;AAAA,IACA,cAAc,OAAO,KAAK,QAAQ;AAAA,EACpC,CAAC;AAAA,EACD,OAAO,cAAc,UAAU,iBAAiB,KAAK;AAAA;AAGvD,SAAS,eAAe,CACtB,MACA,MACA,SACA,UACA,OACW;AAAA,EACX,MAAM,aAAa,MAAM,kBAAkB,IAAI;AAAA,EAC/C,MAAM,YAAY,aAAa,WAAW,QAAQ;AAAA,EAClD,MAAM,oBAAoB,WAAW,aAAa,QAAQ,IAAI;AAAA,EAC9D,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,QAAQ,WAAW;AAAA,IACnB,MAAM,WAAW;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AAAA,EAEA,IAAI,WAAW,SAAS,QAAQ;AAAA,IAC9B,IAAI,YAAY,OAAO,GAAG;AAAA,MACxB,MAAM,UAAU,QAAQ;AAAA,IAC1B;AAAA,IACA,IAAI,YAAY,QAAQ,GAAG;AAAA,MACzB,MAAM,kBAAkB,SAAS;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAGT,SAAS,YAAY,CAAC,GAAc,GAAuB;AAAA,EACzD,IAAI,aAAa,CAAC,MAAM,aAAa,CAAC;AAAA,IAAG,OAAO;AAAA,EAChD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC;AAAA,IAAG,OAAO;AAAA,EAC/C,OAAO,EAAE,YAAY,EAAE;AAAA;AAGzB,SAAS,YAAY,CAAC,OAAoD;AAAA,EACxE,OAAO,OAAO,SAAS,cAAc,cAAc;AAAA;AAGrD,SAAS,WAAW,CAAC,OAA8E;AAAA,EACjG,OAAO,CAAC,CAAC,SAAS,MAAM,SAAS;AAAA;",
|
|
8
|
+
"debugId": "F0849DE3546011FF64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"export { VersionControlSystem } from \"./vcs.cjs\";\nexport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n FileEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\n"
|
|
5
|
+
"export { VersionControlSystem } from \"./vcs.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqC,IAArC;",
|
|
8
8
|
"debugId": "882B2013CEEDB5D864756E2164756E21",
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/vcs/rules.ts
|
|
40
|
+
var exports_rules = {};
|
|
41
|
+
__export(exports_rules, {
|
|
42
|
+
matchVCSPath: () => matchVCSPath,
|
|
43
|
+
VCSRules: () => VCSRules
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(exports_rules);
|
|
46
|
+
var import_match = require("./match.cjs");
|
|
47
|
+
|
|
48
|
+
class VCSRules {
|
|
49
|
+
internalPath;
|
|
50
|
+
ignorePatterns;
|
|
51
|
+
attributeRules;
|
|
52
|
+
constructor(config = {}) {
|
|
53
|
+
this.internalPath = normalizePath(config.internalPath ?? config.internalDirName ?? "");
|
|
54
|
+
this.ignorePatterns = [...config.ignore ?? []];
|
|
55
|
+
this.attributeRules = [...config.attributes ?? []];
|
|
56
|
+
}
|
|
57
|
+
isInternalPath(relPath) {
|
|
58
|
+
if (!this.internalPath)
|
|
59
|
+
return false;
|
|
60
|
+
const normalizedPath = normalizePath(relPath);
|
|
61
|
+
if (!normalizedPath)
|
|
62
|
+
return false;
|
|
63
|
+
return normalizedPath === this.internalPath || normalizedPath.startsWith(`${this.internalPath}/`);
|
|
64
|
+
}
|
|
65
|
+
isIgnored(relPath) {
|
|
66
|
+
if (this.isInternalPath(relPath))
|
|
67
|
+
return true;
|
|
68
|
+
return this.ignorePatterns.some((pattern) => matchVCSPath(pattern, relPath));
|
|
69
|
+
}
|
|
70
|
+
shouldEnterDirectory(relPath, trackedPaths) {
|
|
71
|
+
if (this.isInternalPath(relPath))
|
|
72
|
+
return false;
|
|
73
|
+
if (!this.isIgnored(relPath))
|
|
74
|
+
return true;
|
|
75
|
+
return hasTrackedPathAtOrBelow(relPath, trackedPaths);
|
|
76
|
+
}
|
|
77
|
+
shouldIncludeWorkingFile(relPath, trackedPaths) {
|
|
78
|
+
if (this.isInternalPath(relPath))
|
|
79
|
+
return false;
|
|
80
|
+
if (trackedPaths.has(relPath))
|
|
81
|
+
return true;
|
|
82
|
+
return !this.isIgnored(relPath);
|
|
83
|
+
}
|
|
84
|
+
shouldIncludeEmptyDirectory(relPath, trackedPaths) {
|
|
85
|
+
if (this.isInternalPath(relPath))
|
|
86
|
+
return false;
|
|
87
|
+
if (trackedPaths.has(relPath))
|
|
88
|
+
return true;
|
|
89
|
+
return !this.isIgnored(relPath);
|
|
90
|
+
}
|
|
91
|
+
shouldIncludeRestoreScanFile(relPath) {
|
|
92
|
+
return !this.isInternalPath(relPath);
|
|
93
|
+
}
|
|
94
|
+
shouldPreserveUntrackedIgnored(relPath, trackedPaths) {
|
|
95
|
+
if (trackedPaths.has(relPath))
|
|
96
|
+
return false;
|
|
97
|
+
return this.isIgnored(relPath);
|
|
98
|
+
}
|
|
99
|
+
resolveAttributes(relPath) {
|
|
100
|
+
let binary = false;
|
|
101
|
+
let diff = "text";
|
|
102
|
+
for (const rule of this.attributeRules) {
|
|
103
|
+
if (!matchVCSPath(rule.pattern, relPath))
|
|
104
|
+
continue;
|
|
105
|
+
if (rule.binary !== undefined) {
|
|
106
|
+
binary = rule.binary;
|
|
107
|
+
}
|
|
108
|
+
if (rule.diff !== undefined) {
|
|
109
|
+
diff = rule.diff;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (diff === "binary") {
|
|
113
|
+
binary = true;
|
|
114
|
+
}
|
|
115
|
+
return { binary, diff };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function matchVCSPath(pattern, relPath) {
|
|
119
|
+
const normalizedPattern = normalizePattern(pattern);
|
|
120
|
+
const normalizedPath = normalizePath(relPath);
|
|
121
|
+
if (!normalizedPattern || !normalizedPath)
|
|
122
|
+
return false;
|
|
123
|
+
if (normalizedPattern.mode === "root-path") {
|
|
124
|
+
return import_match.matchGlobPath(normalizedPattern.pattern, normalizedPath);
|
|
125
|
+
}
|
|
126
|
+
if (normalizedPattern.mode === "root-segment") {
|
|
127
|
+
const [firstSegment] = normalizedPath.split("/");
|
|
128
|
+
return firstSegment ? import_match.matchGlobPath(normalizedPattern.pattern, firstSegment) : false;
|
|
129
|
+
}
|
|
130
|
+
if (normalizedPattern.mode === "root-prefix") {
|
|
131
|
+
return import_match.matchGlobPath(normalizedPattern.pattern, normalizedPath) || import_match.matchGlobPath(`${normalizedPattern.pattern}/**`, normalizedPath);
|
|
132
|
+
}
|
|
133
|
+
const segments = normalizedPath.split("/");
|
|
134
|
+
return segments.some((segment) => import_match.matchGlobPath(normalizedPattern.pattern, segment));
|
|
135
|
+
}
|
|
136
|
+
function normalizePath(relPath) {
|
|
137
|
+
return relPath.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
138
|
+
}
|
|
139
|
+
function normalizePattern(pattern) {
|
|
140
|
+
let normalized = pattern.trim();
|
|
141
|
+
if (!normalized)
|
|
142
|
+
return null;
|
|
143
|
+
normalized = normalized.replace(/\\/g, "/");
|
|
144
|
+
const anchored = normalized.startsWith("/");
|
|
145
|
+
const directoryOnly = normalized.endsWith("/");
|
|
146
|
+
normalized = normalized.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
147
|
+
if (!normalized)
|
|
148
|
+
return null;
|
|
149
|
+
if (normalized.includes("/")) {
|
|
150
|
+
return {
|
|
151
|
+
pattern: normalized,
|
|
152
|
+
mode: directoryOnly ? "root-prefix" : "root-path"
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (anchored) {
|
|
156
|
+
return {
|
|
157
|
+
pattern: normalized,
|
|
158
|
+
mode: "root-segment"
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
pattern: normalized,
|
|
163
|
+
mode: "segment"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function hasTrackedPathAtOrBelow(relPath, trackedPaths) {
|
|
167
|
+
const normalizedPath = normalizePath(relPath);
|
|
168
|
+
if (!normalizedPath)
|
|
169
|
+
return false;
|
|
170
|
+
const prefix = normalizedPath + "/";
|
|
171
|
+
for (const trackedPath of trackedPaths) {
|
|
172
|
+
const normalizedTrackedPath = normalizePath(trackedPath);
|
|
173
|
+
if (normalizedTrackedPath === normalizedPath || normalizedTrackedPath.startsWith(prefix)) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
//# debugId=FD722B600498944364756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/vcs/rules.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { matchGlobPath } from \"./match.cjs\";\nimport type { VCSAttributeRule, VCSResolvedAttributes } from \"./types.cjs\";\n\ninterface VCSRulesConfig {\n internalPath?: string;\n internalDirName?: string;\n ignore?: string[];\n attributes?: VCSAttributeRule[];\n}\n\nexport class VCSRules {\n private readonly internalPath: string;\n private readonly ignorePatterns: string[];\n private readonly attributeRules: VCSAttributeRule[];\n\n constructor(config: VCSRulesConfig = {}) {\n this.internalPath = normalizePath(config.internalPath ?? config.internalDirName ?? \"\");\n this.ignorePatterns = [...(config.ignore ?? [])];\n this.attributeRules = [...(config.attributes ?? [])];\n }\n\n isInternalPath(relPath: string): boolean {\n if (!this.internalPath) return false;\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n return normalizedPath === this.internalPath || normalizedPath.startsWith(`${this.internalPath}/`);\n }\n\n isIgnored(relPath: string): boolean {\n if (this.isInternalPath(relPath)) return true;\n return this.ignorePatterns.some((pattern) => matchVCSPath(pattern, relPath));\n }\n\n shouldEnterDirectory(relPath: string, trackedPaths: Iterable<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (!this.isIgnored(relPath)) return true;\n return hasTrackedPathAtOrBelow(relPath, trackedPaths);\n }\n\n shouldIncludeWorkingFile(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeEmptyDirectory(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (this.isInternalPath(relPath)) return false;\n if (trackedPaths.has(relPath)) return true;\n return !this.isIgnored(relPath);\n }\n\n shouldIncludeRestoreScanFile(relPath: string): boolean {\n return !this.isInternalPath(relPath);\n }\n\n shouldPreserveUntrackedIgnored(relPath: string, trackedPaths: ReadonlySet<string>): boolean {\n if (trackedPaths.has(relPath)) return false;\n return this.isIgnored(relPath);\n }\n\n resolveAttributes(relPath: string): VCSResolvedAttributes {\n let binary = false;\n let diff: VCSResolvedAttributes[\"diff\"] = \"text\";\n\n for (const rule of this.attributeRules) {\n if (!matchVCSPath(rule.pattern, relPath)) continue;\n if (rule.binary !== undefined) {\n binary = rule.binary;\n }\n if (rule.diff !== undefined) {\n diff = rule.diff;\n }\n }\n\n if (diff === \"binary\") {\n binary = true;\n }\n\n return { binary, diff };\n }\n}\n\nexport function matchVCSPath(pattern: string, relPath: string): boolean {\n const normalizedPattern = normalizePattern(pattern);\n const normalizedPath = normalizePath(relPath);\n\n if (!normalizedPattern || !normalizedPath) return false;\n\n if (normalizedPattern.mode === \"root-path\") {\n return matchGlobPath(normalizedPattern.pattern, normalizedPath);\n }\n\n if (normalizedPattern.mode === \"root-segment\") {\n const [firstSegment] = normalizedPath.split(\"/\");\n return firstSegment ? matchGlobPath(normalizedPattern.pattern, firstSegment) : false;\n }\n\n if (normalizedPattern.mode === \"root-prefix\") {\n return (\n matchGlobPath(normalizedPattern.pattern, normalizedPath) ||\n matchGlobPath(`${normalizedPattern.pattern}/**`, normalizedPath)\n );\n }\n\n const segments = normalizedPath.split(\"/\");\n return segments.some((segment) => matchGlobPath(normalizedPattern.pattern, segment));\n}\n\nfunction normalizePath(relPath: string): string {\n return relPath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction normalizePattern(pattern: string): {\n pattern: string;\n mode: \"root-path\" | \"root-prefix\" | \"root-segment\" | \"segment\";\n} | null {\n let normalized = pattern.trim();\n if (!normalized) return null;\n\n normalized = normalized.replace(/\\\\/g, \"/\");\n const anchored = normalized.startsWith(\"/\");\n const directoryOnly = normalized.endsWith(\"/\");\n normalized = normalized.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (!normalized) return null;\n\n if (normalized.includes(\"/\")) {\n return {\n pattern: normalized,\n mode: directoryOnly ? \"root-prefix\" : \"root-path\",\n };\n }\n\n if (anchored) {\n return {\n pattern: normalized,\n mode: \"root-segment\",\n };\n }\n\n return {\n pattern: normalized,\n mode: \"segment\",\n };\n}\n\nfunction hasTrackedPathAtOrBelow(relPath: string, trackedPaths: Iterable<string>): boolean {\n const normalizedPath = normalizePath(relPath);\n if (!normalizedPath) return false;\n\n const prefix = normalizedPath + \"/\";\n for (const trackedPath of trackedPaths) {\n const normalizedTrackedPath = normalizePath(trackedPath);\n if (\n normalizedTrackedPath === normalizedPath ||\n normalizedTrackedPath.startsWith(prefix)\n ) {\n return true;\n }\n }\n return false;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "FD722B600498944364756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -44,15 +44,27 @@ __export(exports_snapshot, {
|
|
|
44
44
|
buildPartialManifest: () => buildPartialManifest
|
|
45
45
|
});
|
|
46
46
|
module.exports = __toCommonJS(exports_snapshot);
|
|
47
|
+
var import_rules = require("./rules.cjs");
|
|
47
48
|
var import_walk = require("./walk.cjs");
|
|
48
|
-
async function buildTreeManifest(fs, rootPath,
|
|
49
|
+
async function buildTreeManifest(fs, rootPath, options) {
|
|
49
50
|
const manifest = {};
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const rules = options?.rules ?? new import_rules.VCSRules({ internalDirName: ".vcs" });
|
|
52
|
+
const trackedPaths = new Set(options?.trackedPaths ?? []);
|
|
53
|
+
const entries = await import_walk.walkTreeEntries(fs, rootPath, {
|
|
54
|
+
enterDirectory: (relPath) => rules.shouldEnterDirectory(relPath, trackedPaths),
|
|
55
|
+
includeFile: (relPath) => rules.shouldIncludeWorkingFile(relPath, trackedPaths),
|
|
56
|
+
includeDirectory: (relPath, info) => info.empty && rules.shouldIncludeEmptyDirectory(relPath, trackedPaths)
|
|
57
|
+
});
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
if (entry.kind === "directory") {
|
|
60
|
+
manifest[entry.path] = { kind: "directory", size: 0 };
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const fullPath = fs.resolve(rootPath, entry.path);
|
|
53
64
|
const content = await fs.readFile(fullPath);
|
|
54
65
|
const buf = Buffer.from(content);
|
|
55
|
-
manifest[
|
|
66
|
+
manifest[entry.path] = {
|
|
67
|
+
kind: "file",
|
|
56
68
|
content: buf.toString("base64"),
|
|
57
69
|
size: buf.length
|
|
58
70
|
};
|
|
@@ -66,11 +78,19 @@ async function buildPartialManifest(fs, rootPath, paths) {
|
|
|
66
78
|
if (!await fs.exists(fullPath))
|
|
67
79
|
continue;
|
|
68
80
|
const stat = await fs.stat(fullPath);
|
|
81
|
+
if (stat.isDirectory()) {
|
|
82
|
+
const entries = await fs.readdir(fullPath);
|
|
83
|
+
if (entries.length === 0) {
|
|
84
|
+
manifest[relPath] = { kind: "directory", size: 0 };
|
|
85
|
+
}
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
69
88
|
if (!stat.isFile())
|
|
70
89
|
continue;
|
|
71
90
|
const content = await fs.readFile(fullPath);
|
|
72
91
|
const buf = Buffer.from(content);
|
|
73
92
|
manifest[relPath] = {
|
|
93
|
+
kind: "file",
|
|
74
94
|
content: buf.toString("base64"),
|
|
75
95
|
size: buf.length
|
|
76
96
|
};
|
|
@@ -79,18 +99,55 @@ async function buildPartialManifest(fs, rootPath, paths) {
|
|
|
79
99
|
}
|
|
80
100
|
async function restoreTree(fs, rootPath, manifest, options) {
|
|
81
101
|
const fullRestore = options?.fullRestore ?? false;
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
const rules = options?.rules ?? new import_rules.VCSRules({ internalDirName: ".vcs" });
|
|
103
|
+
const trackedPaths = new Set(options?.trackedPaths ?? []);
|
|
104
|
+
const scopePatterns = options?.paths ?? null;
|
|
105
|
+
const scopedEntries = Object.entries(manifest).filter(([relPath]) => isPathInScope(relPath, scopePatterns)).sort(([a], [b]) => a.localeCompare(b));
|
|
106
|
+
const targetPaths = new Set(scopedEntries.map(([relPath]) => relPath));
|
|
107
|
+
const requiredDirectories = collectRequiredDirectories(scopedEntries);
|
|
108
|
+
const shouldDeleteExtras = fullRestore || scopePatterns !== null;
|
|
109
|
+
if (shouldDeleteExtras) {
|
|
110
|
+
const currentEntries = await import_walk.walkTreeEntries(fs, rootPath, {
|
|
111
|
+
enterDirectory: (relPath) => !rules.isInternalPath(relPath),
|
|
112
|
+
includeFile: (relPath) => rules.shouldIncludeRestoreScanFile(relPath),
|
|
113
|
+
includeDirectory: () => true
|
|
114
|
+
});
|
|
115
|
+
for (const current of currentEntries) {
|
|
116
|
+
if (current.kind !== "file")
|
|
117
|
+
continue;
|
|
118
|
+
if (!isPathInScope(current.path, scopePatterns))
|
|
119
|
+
continue;
|
|
120
|
+
if (targetPaths.has(current.path))
|
|
121
|
+
continue;
|
|
122
|
+
if (rules.shouldPreserveUntrackedIgnored(current.path, trackedPaths))
|
|
123
|
+
continue;
|
|
124
|
+
await fs.rm(fs.resolve(rootPath, current.path));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const directory of [...requiredDirectories].sort(comparePathDepth)) {
|
|
128
|
+
await ensureDirectoryExists(fs, fs.resolve(rootPath, directory));
|
|
129
|
+
}
|
|
130
|
+
for (const [relPath, entry] of scopedEntries) {
|
|
131
|
+
if (isDirectoryEntry(entry)) {
|
|
132
|
+
await ensureDirectoryExists(fs, fs.resolve(rootPath, relPath));
|
|
85
133
|
continue;
|
|
134
|
+
}
|
|
86
135
|
await writeFileFromEntry(fs, rootPath, relPath, entry);
|
|
87
136
|
}
|
|
88
|
-
if (
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
137
|
+
if (shouldDeleteExtras) {
|
|
138
|
+
const currentEntries = await import_walk.walkTreeEntries(fs, rootPath, {
|
|
139
|
+
enterDirectory: (relPath) => !rules.isInternalPath(relPath),
|
|
140
|
+
includeFile: () => true,
|
|
141
|
+
includeDirectory: () => true
|
|
142
|
+
});
|
|
143
|
+
const directories = currentEntries.filter((entry) => entry.kind === "directory").map((entry) => entry.path).filter((relPath) => isPathInScope(relPath, scopePatterns)).sort((a, b) => comparePathDepth(b, a));
|
|
144
|
+
for (const relPath of directories) {
|
|
145
|
+
if (requiredDirectories.has(relPath))
|
|
146
|
+
continue;
|
|
147
|
+
if (rules.shouldPreserveUntrackedIgnored(relPath, trackedPaths))
|
|
148
|
+
continue;
|
|
149
|
+
const fullPath = fs.resolve(rootPath, relPath);
|
|
150
|
+
if (await isEmptyDirectory(fs, fullPath)) {
|
|
94
151
|
await fs.rm(fullPath);
|
|
95
152
|
}
|
|
96
153
|
}
|
|
@@ -98,15 +155,74 @@ async function restoreTree(fs, rootPath, manifest, options) {
|
|
|
98
155
|
}
|
|
99
156
|
async function writeFileFromEntry(fs, rootPath, relPath, entry) {
|
|
100
157
|
const fullPath = fs.resolve(rootPath, relPath);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await fs.mkdir(dir, { recursive: true });
|
|
104
|
-
}
|
|
158
|
+
await ensureDirectoryExists(fs, fs.dirname(fullPath));
|
|
159
|
+
await removeDirectoryAtPath(fs, fullPath);
|
|
105
160
|
const buf = Buffer.from(entry.content, "base64");
|
|
106
161
|
await fs.writeFile(fullPath, buf);
|
|
107
162
|
}
|
|
108
|
-
function
|
|
109
|
-
return
|
|
163
|
+
function isDirectoryEntry(entry) {
|
|
164
|
+
return entry.kind === "directory";
|
|
165
|
+
}
|
|
166
|
+
function isPathInScope(relPath, patterns) {
|
|
167
|
+
if (!patterns || patterns.length === 0)
|
|
168
|
+
return true;
|
|
169
|
+
return patterns.some((pattern) => import_rules.matchVCSPath(pattern, relPath));
|
|
170
|
+
}
|
|
171
|
+
function collectRequiredDirectories(entries) {
|
|
172
|
+
const directories = new Set;
|
|
173
|
+
for (const [relPath, entry] of entries) {
|
|
174
|
+
if (isDirectoryEntry(entry)) {
|
|
175
|
+
directories.add(relPath);
|
|
176
|
+
}
|
|
177
|
+
for (const parent of parentDirectories(relPath)) {
|
|
178
|
+
directories.add(parent);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return directories;
|
|
182
|
+
}
|
|
183
|
+
function parentDirectories(relPath) {
|
|
184
|
+
const parts = relPath.split("/").filter(Boolean);
|
|
185
|
+
const parents = [];
|
|
186
|
+
for (let i = 1;i < parts.length; i++) {
|
|
187
|
+
parents.push(parts.slice(0, i).join("/"));
|
|
188
|
+
}
|
|
189
|
+
return parents;
|
|
190
|
+
}
|
|
191
|
+
function comparePathDepth(a, b) {
|
|
192
|
+
const depthA = a.split("/").filter(Boolean).length;
|
|
193
|
+
const depthB = b.split("/").filter(Boolean).length;
|
|
194
|
+
if (depthA !== depthB)
|
|
195
|
+
return depthA - depthB;
|
|
196
|
+
return a.localeCompare(b);
|
|
197
|
+
}
|
|
198
|
+
async function ensureDirectoryExists(fs, dirPath) {
|
|
199
|
+
const parent = fs.dirname(dirPath);
|
|
200
|
+
if (parent !== dirPath) {
|
|
201
|
+
await ensureDirectoryExists(fs, parent);
|
|
202
|
+
}
|
|
203
|
+
if (await fs.exists(dirPath)) {
|
|
204
|
+
const stat = await fs.stat(dirPath);
|
|
205
|
+
if (stat.isDirectory())
|
|
206
|
+
return;
|
|
207
|
+
await fs.rm(dirPath, { recursive: true, force: true });
|
|
208
|
+
}
|
|
209
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
210
|
+
}
|
|
211
|
+
async function removeDirectoryAtPath(fs, path) {
|
|
212
|
+
if (!await fs.exists(path))
|
|
213
|
+
return;
|
|
214
|
+
const stat = await fs.stat(path);
|
|
215
|
+
if (stat.isDirectory()) {
|
|
216
|
+
await fs.rm(path, { recursive: true, force: true });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function isEmptyDirectory(fs, dirPath) {
|
|
220
|
+
try {
|
|
221
|
+
const entries = await fs.readdir(dirPath);
|
|
222
|
+
return entries.length === 0;
|
|
223
|
+
} catch {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
110
226
|
}
|
|
111
227
|
|
|
112
|
-
//# debugId=
|
|
228
|
+
//# debugId=7E15F1F035E56CC164756E2164756E21
|