shell-dsl 0.0.34 → 0.0.35
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 +16 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/fs/memfs-adapter.cjs +56 -2
- package/dist/cjs/src/fs/memfs-adapter.cjs.map +3 -3
- package/dist/cjs/src/fs/real-fs.cjs +134 -3
- package/dist/cjs/src/fs/real-fs.cjs.map +3 -3
- package/dist/cjs/src/fs/special-files.cjs +3 -2
- package/dist/cjs/src/fs/special-files.cjs.map +3 -3
- package/dist/cjs/src/fs/web-fs.cjs +72 -3
- package/dist/cjs/src/fs/web-fs.cjs.map +3 -3
- package/dist/cjs/src/index.cjs.map +2 -2
- package/dist/cjs/src/types.cjs.map +2 -2
- package/dist/cjs/src/vcs/content.cjs +106 -0
- package/dist/cjs/src/vcs/content.cjs.map +10 -0
- package/dist/cjs/src/vcs/diff.cjs +72 -28
- 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/objects.cjs +141 -0
- package/dist/cjs/src/vcs/objects.cjs.map +10 -0
- package/dist/cjs/src/vcs/rules.cjs +6 -3
- package/dist/cjs/src/vcs/rules.cjs.map +3 -3
- package/dist/cjs/src/vcs/snapshot.cjs +89 -39
- package/dist/cjs/src/vcs/snapshot.cjs.map +3 -3
- package/dist/cjs/src/vcs/storage.cjs +44 -3
- package/dist/cjs/src/vcs/storage.cjs.map +3 -3
- package/dist/cjs/src/vcs/text-diff.cjs +219 -0
- package/dist/cjs/src/vcs/text-diff.cjs.map +10 -0
- package/dist/cjs/src/vcs/vcs.cjs +108 -61
- package/dist/cjs/src/vcs/vcs.cjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/src/fs/memfs-adapter.mjs +57 -2
- package/dist/mjs/src/fs/memfs-adapter.mjs.map +3 -3
- package/dist/mjs/src/fs/real-fs.mjs +135 -3
- package/dist/mjs/src/fs/real-fs.mjs.map +3 -3
- package/dist/mjs/src/fs/special-files.mjs +3 -2
- package/dist/mjs/src/fs/special-files.mjs.map +3 -3
- package/dist/mjs/src/fs/web-fs.mjs +72 -3
- package/dist/mjs/src/fs/web-fs.mjs.map +3 -3
- package/dist/mjs/src/index.mjs.map +2 -2
- package/dist/mjs/src/types.mjs.map +2 -2
- package/dist/mjs/src/vcs/content.mjs +66 -0
- package/dist/mjs/src/vcs/content.mjs.map +10 -0
- package/dist/mjs/src/vcs/diff.mjs +72 -28
- 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/objects.mjs +106 -0
- package/dist/mjs/src/vcs/objects.mjs.map +10 -0
- package/dist/mjs/src/vcs/rules.mjs +6 -3
- package/dist/mjs/src/vcs/rules.mjs.map +3 -3
- package/dist/mjs/src/vcs/snapshot.mjs +89 -39
- package/dist/mjs/src/vcs/snapshot.mjs.map +3 -3
- package/dist/mjs/src/vcs/storage.mjs +45 -3
- package/dist/mjs/src/vcs/storage.mjs.map +3 -3
- package/dist/mjs/src/vcs/text-diff.mjs +179 -0
- package/dist/mjs/src/vcs/text-diff.mjs.map +10 -0
- package/dist/mjs/src/vcs/vcs.mjs +115 -63
- package/dist/mjs/src/vcs/vcs.mjs.map +3 -3
- package/dist/types/src/fs/real-fs.d.ts +12 -1
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/types.d.ts +10 -0
- package/dist/types/src/vcs/content.d.ts +6 -0
- package/dist/types/src/vcs/diff.d.ts +10 -7
- package/dist/types/src/vcs/index.d.ts +1 -1
- package/dist/types/src/vcs/objects.d.ts +22 -0
- package/dist/types/src/vcs/snapshot.d.ts +13 -8
- package/dist/types/src/vcs/storage.d.ts +7 -1
- package/dist/types/src/vcs/text-diff.d.ts +1 -0
- package/dist/types/src/vcs/types.d.ts +20 -5
- package/dist/types/src/vcs/vcs.d.ts +6 -0
- package/package.json +7 -2
package/dist/mjs/src/vcs/vcs.mjs
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
// src/vcs/vcs.ts
|
|
2
2
|
import { VCSStorage } from "./storage.mjs";
|
|
3
|
-
import { diffManifests
|
|
3
|
+
import { diffManifests } from "./diff.mjs";
|
|
4
|
+
import { VCSObjectStore } from "./objects.mjs";
|
|
4
5
|
import { matchVCSPath, VCSRules } from "./rules.mjs";
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
buildTreeManifest,
|
|
8
|
+
rebuildIndexForManifest,
|
|
9
|
+
restoreTree,
|
|
10
|
+
updateIndexForScopedPaths
|
|
11
|
+
} from "./snapshot.mjs";
|
|
6
12
|
|
|
7
13
|
class VersionControlSystem {
|
|
8
14
|
workFs;
|
|
9
15
|
workPath;
|
|
10
16
|
storage;
|
|
17
|
+
objectStore;
|
|
11
18
|
vcsInternalPath;
|
|
12
19
|
rules;
|
|
13
20
|
constructor(config) {
|
|
@@ -16,6 +23,7 @@ class VersionControlSystem {
|
|
|
16
23
|
const metaFs = config.vcsPath?.fs ?? config.fs;
|
|
17
24
|
const metaPath = config.vcsPath?.path ?? metaFs.resolve(config.path, ".vcs");
|
|
18
25
|
this.storage = new VCSStorage(metaFs, metaPath);
|
|
26
|
+
this.objectStore = new VCSObjectStore(this.storage.fileSystem, this.storage.resolve());
|
|
19
27
|
this.vcsInternalPath = resolveInternalPath(config.fs, metaFs, this.workPath, metaPath);
|
|
20
28
|
this.rules = new VCSRules({
|
|
21
29
|
internalPath: this.vcsInternalPath,
|
|
@@ -24,14 +32,19 @@ class VersionControlSystem {
|
|
|
24
32
|
});
|
|
25
33
|
}
|
|
26
34
|
async init() {
|
|
27
|
-
if (await this.storage.isInitialized())
|
|
35
|
+
if (await this.storage.isInitialized()) {
|
|
36
|
+
await this.storage.assertSupportedFormat();
|
|
28
37
|
return;
|
|
38
|
+
}
|
|
29
39
|
await this.storage.initialize();
|
|
40
|
+
await this.objectStore.initialize();
|
|
30
41
|
}
|
|
31
42
|
async ensureInit() {
|
|
32
43
|
if (!await this.storage.isInitialized()) {
|
|
33
44
|
await this.init();
|
|
45
|
+
return;
|
|
34
46
|
}
|
|
47
|
+
await this.storage.assertSupportedFormat();
|
|
35
48
|
}
|
|
36
49
|
async resolveHead() {
|
|
37
50
|
const head = await this.storage.readHead();
|
|
@@ -52,44 +65,57 @@ class VersionControlSystem {
|
|
|
52
65
|
const rev = await this.storage.readRevision(revision);
|
|
53
66
|
return rev.tree;
|
|
54
67
|
}
|
|
68
|
+
async currentIndex() {
|
|
69
|
+
return this.storage.readIndex();
|
|
70
|
+
}
|
|
55
71
|
async commit(message, opts) {
|
|
56
72
|
await this.ensureInit();
|
|
57
73
|
const { branch, revision: parentId } = await this.resolveHead();
|
|
58
74
|
const parentManifest = parentId !== null ? (await this.storage.readRevision(parentId)).tree : {};
|
|
75
|
+
const previousIndex = await this.currentIndex();
|
|
76
|
+
const working = await buildTreeManifest(this.workFs, this.workPath, {
|
|
77
|
+
objectStore: this.objectStore,
|
|
78
|
+
rules: this.rules,
|
|
79
|
+
trackedPaths: Object.keys(parentManifest),
|
|
80
|
+
indexEntries: previousIndex
|
|
81
|
+
});
|
|
59
82
|
let newTree;
|
|
60
83
|
let changes;
|
|
61
84
|
if (opts?.paths && opts.paths.length > 0) {
|
|
62
|
-
const
|
|
63
|
-
rules: this.rules,
|
|
64
|
-
trackedPaths: Object.keys(parentManifest)
|
|
65
|
-
});
|
|
66
|
-
const matchedPaths = filterPathsByGlobs(Object.keys(fullManifest), opts.paths);
|
|
67
|
-
newTree = { ...parentManifest };
|
|
85
|
+
const matchedPaths = filterPathsByGlobs(Object.keys(working.manifest), opts.paths);
|
|
68
86
|
const parentMatchedPaths = filterPathsByGlobs(Object.keys(parentManifest), opts.paths);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
newTree = { ...parentManifest };
|
|
88
|
+
for (const path of parentMatchedPaths) {
|
|
89
|
+
if (!working.manifest[path]) {
|
|
90
|
+
delete newTree[path];
|
|
72
91
|
}
|
|
73
92
|
}
|
|
74
|
-
for (const
|
|
75
|
-
newTree[
|
|
93
|
+
for (const path of matchedPaths) {
|
|
94
|
+
newTree[path] = working.manifest[path];
|
|
76
95
|
}
|
|
77
96
|
const relevantBefore = {};
|
|
78
97
|
const relevantAfter = {};
|
|
79
98
|
const allRelevant = new Set([...matchedPaths, ...parentMatchedPaths]);
|
|
80
|
-
for (const
|
|
81
|
-
if (parentManifest[
|
|
82
|
-
relevantBefore[
|
|
83
|
-
if (newTree[
|
|
84
|
-
relevantAfter[
|
|
99
|
+
for (const path of allRelevant) {
|
|
100
|
+
if (parentManifest[path])
|
|
101
|
+
relevantBefore[path] = parentManifest[path];
|
|
102
|
+
if (newTree[path])
|
|
103
|
+
relevantAfter[path] = newTree[path];
|
|
85
104
|
}
|
|
86
|
-
changes = diffManifests(relevantBefore, relevantAfter,
|
|
105
|
+
changes = await diffManifests(relevantBefore, relevantAfter, {
|
|
106
|
+
rules: this.rules,
|
|
107
|
+
objectStore: this.objectStore,
|
|
108
|
+
beforeIndex: previousIndex,
|
|
109
|
+
afterIndex: working.indexEntries
|
|
110
|
+
});
|
|
87
111
|
} else {
|
|
88
|
-
newTree =
|
|
112
|
+
newTree = working.manifest;
|
|
113
|
+
changes = await diffManifests(parentManifest, newTree, {
|
|
89
114
|
rules: this.rules,
|
|
90
|
-
|
|
115
|
+
objectStore: this.objectStore,
|
|
116
|
+
beforeIndex: previousIndex,
|
|
117
|
+
afterIndex: working.indexEntries
|
|
91
118
|
});
|
|
92
|
-
changes = diffManifests(parentManifest, newTree, this.rules);
|
|
93
119
|
}
|
|
94
120
|
if (changes.length === 0) {
|
|
95
121
|
throw new Error("nothing to commit");
|
|
@@ -105,6 +131,7 @@ class VersionControlSystem {
|
|
|
105
131
|
tree: newTree
|
|
106
132
|
};
|
|
107
133
|
await this.storage.writeRevision(rev);
|
|
134
|
+
await this.storage.writeIndex(working.indexEntries);
|
|
108
135
|
if (branch) {
|
|
109
136
|
await this.storage.writeBranch(branch, { revision: id });
|
|
110
137
|
} else {
|
|
@@ -136,30 +163,33 @@ class VersionControlSystem {
|
|
|
136
163
|
}
|
|
137
164
|
const currentManifest = await this.headManifest();
|
|
138
165
|
if (isPartial) {
|
|
139
|
-
await restoreTree(this.workFs, this.workPath, rev.tree, {
|
|
166
|
+
await restoreTree(this.workFs, this.workPath, rev.tree, this.objectStore, {
|
|
140
167
|
fullRestore: false,
|
|
141
168
|
paths: opts.paths,
|
|
142
169
|
rules: this.rules,
|
|
143
170
|
trackedPaths: Object.keys(currentManifest)
|
|
144
171
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
fullRestore: true,
|
|
154
|
-
rules: this.rules,
|
|
155
|
-
trackedPaths: Object.keys(currentManifest)
|
|
156
|
-
});
|
|
157
|
-
if (targetBranch) {
|
|
158
|
-
await this.storage.writeHead({ ref: `refs/heads/${targetBranch}` });
|
|
159
|
-
} else {
|
|
160
|
-
await this.storage.writeHead({ revision: targetRevision });
|
|
172
|
+
const updatedIndex = await updateIndexForScopedPaths(this.workFs, this.workPath, rev.tree, this.objectStore, await this.currentIndex(), opts.paths);
|
|
173
|
+
await this.storage.writeIndex(updatedIndex);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!opts?.force) {
|
|
177
|
+
const changes = await this.status();
|
|
178
|
+
if (changes.length > 0) {
|
|
179
|
+
throw new Error("working tree has uncommitted changes (use force to discard)");
|
|
161
180
|
}
|
|
162
181
|
}
|
|
182
|
+
await restoreTree(this.workFs, this.workPath, rev.tree, this.objectStore, {
|
|
183
|
+
fullRestore: true,
|
|
184
|
+
rules: this.rules,
|
|
185
|
+
trackedPaths: Object.keys(currentManifest)
|
|
186
|
+
});
|
|
187
|
+
await this.storage.writeIndex(await rebuildIndexForManifest(this.workFs, this.workPath, rev.tree, this.objectStore));
|
|
188
|
+
if (targetBranch) {
|
|
189
|
+
await this.storage.writeHead({ ref: `refs/heads/${targetBranch}` });
|
|
190
|
+
} else {
|
|
191
|
+
await this.storage.writeHead({ revision: targetRevision });
|
|
192
|
+
}
|
|
163
193
|
}
|
|
164
194
|
async branch(name) {
|
|
165
195
|
await this.ensureInit();
|
|
@@ -215,29 +245,22 @@ class VersionControlSystem {
|
|
|
215
245
|
} catch {
|
|
216
246
|
break;
|
|
217
247
|
}
|
|
218
|
-
const changedPaths = rev.changes.map((
|
|
248
|
+
const changedPaths = rev.changes.map((change) => change.path);
|
|
219
249
|
if (opts?.path) {
|
|
220
|
-
const matchesPath = changedPaths.some((
|
|
221
|
-
if (matchesPath) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
parent: rev.parent,
|
|
225
|
-
branch: rev.branch,
|
|
226
|
-
message: rev.message,
|
|
227
|
-
timestamp: rev.timestamp,
|
|
228
|
-
paths: changedPaths
|
|
229
|
-
});
|
|
250
|
+
const matchesPath = changedPaths.some((path) => matchVCSPath(opts.path, path));
|
|
251
|
+
if (!matchesPath) {
|
|
252
|
+
currentId = rev.parent;
|
|
253
|
+
continue;
|
|
230
254
|
}
|
|
231
|
-
} else {
|
|
232
|
-
entries.push({
|
|
233
|
-
id: rev.id,
|
|
234
|
-
parent: rev.parent,
|
|
235
|
-
branch: rev.branch,
|
|
236
|
-
message: rev.message,
|
|
237
|
-
timestamp: rev.timestamp,
|
|
238
|
-
paths: changedPaths
|
|
239
|
-
});
|
|
240
255
|
}
|
|
256
|
+
entries.push({
|
|
257
|
+
id: rev.id,
|
|
258
|
+
parent: rev.parent,
|
|
259
|
+
branch: rev.branch,
|
|
260
|
+
message: rev.message,
|
|
261
|
+
timestamp: rev.timestamp,
|
|
262
|
+
paths: changedPaths
|
|
263
|
+
});
|
|
241
264
|
currentId = rev.parent;
|
|
242
265
|
}
|
|
243
266
|
return entries;
|
|
@@ -245,13 +268,42 @@ class VersionControlSystem {
|
|
|
245
268
|
async status() {
|
|
246
269
|
await this.ensureInit();
|
|
247
270
|
const manifest = await this.headManifest();
|
|
248
|
-
|
|
271
|
+
const previousIndex = await this.currentIndex();
|
|
272
|
+
const working = await buildTreeManifest(this.workFs, this.workPath, {
|
|
273
|
+
objectStore: this.objectStore,
|
|
274
|
+
rules: this.rules,
|
|
275
|
+
trackedPaths: Object.keys(manifest),
|
|
276
|
+
indexEntries: previousIndex
|
|
277
|
+
});
|
|
278
|
+
await this.storage.writeIndex(working.indexEntries);
|
|
279
|
+
return diffManifests(manifest, working.manifest, {
|
|
280
|
+
rules: this.rules,
|
|
281
|
+
objectStore: this.objectStore,
|
|
282
|
+
beforeIndex: previousIndex,
|
|
283
|
+
afterIndex: working.indexEntries
|
|
284
|
+
});
|
|
249
285
|
}
|
|
250
286
|
async diff(revA, revB) {
|
|
251
287
|
await this.ensureInit();
|
|
252
288
|
const a = await this.storage.readRevision(revA);
|
|
253
289
|
const b = await this.storage.readRevision(revB);
|
|
254
|
-
return diffManifests(a.tree, b.tree,
|
|
290
|
+
return diffManifests(a.tree, b.tree, {
|
|
291
|
+
rules: this.rules,
|
|
292
|
+
objectStore: this.objectStore
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
async readBlob(blobId, encoding) {
|
|
296
|
+
const content = await this.objectStore.readBlob(blobId);
|
|
297
|
+
return encoding ? content.toString(encoding) : content;
|
|
298
|
+
}
|
|
299
|
+
async readRevisionFile(revisionId, path, encoding) {
|
|
300
|
+
const revision = await this.storage.readRevision(revisionId);
|
|
301
|
+
const normalizedPath = path.replace(/^\/+/, "");
|
|
302
|
+
const entry = revision.tree[normalizedPath];
|
|
303
|
+
if (!entry || entry.kind === "directory") {
|
|
304
|
+
throw new Error(`file "${path}" not found in revision ${revisionId}`);
|
|
305
|
+
}
|
|
306
|
+
return this.readBlob(entry.blobId, encoding);
|
|
255
307
|
}
|
|
256
308
|
async head() {
|
|
257
309
|
await this.ensureInit();
|
|
@@ -279,4 +331,4 @@ export {
|
|
|
279
331
|
VersionControlSystem
|
|
280
332
|
};
|
|
281
333
|
|
|
282
|
-
//# debugId=
|
|
334
|
+
//# debugId=CA82B0F6ED31CC1264756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/vcs.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.mjs\";\nimport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.mjs\";\nimport { VCSStorage } from \"./storage.mjs\";\nimport { diffManifests, diffWorkingTree } from \"./diff.mjs\";\nimport { matchVCSPath, VCSRules } from \"./rules.mjs\";\nimport { buildTreeManifest, restoreTree } from \"./snapshot.mjs\";\n\nexport class VersionControlSystem {\n private readonly workFs: VirtualFS;\n private readonly workPath: string;\n private readonly storage: VCSStorage;\n private readonly vcsInternalPath: string;\n private readonly rules: VCSRules;\n\n constructor(config: VCSConfig) {\n this.workFs = config.fs;\n this.workPath = config.fs.resolve(config.path);\n\n const metaFs = config.vcsPath?.fs ?? config.fs;\n const metaPath = config.vcsPath?.path ?? metaFs.resolve(config.path, \".vcs\");\n this.storage = new VCSStorage(metaFs, metaPath);\n\n this.vcsInternalPath = resolveInternalPath(config.fs, metaFs, this.workPath, metaPath);\n\n this.rules = new VCSRules({\n internalPath: this.vcsInternalPath,\n ignore: config.ignore,\n attributes: config.attributes,\n });\n }\n\n /** Initialize the .vcs directory. Called automatically on first operation if needed. */\n async init(): Promise<void> {\n if (await this.storage.isInitialized()) return;\n await this.storage.initialize();\n }\n\n private async ensureInit(): Promise<void> {\n if (!(await this.storage.isInitialized())) {\n await this.init();\n }\n }\n\n /** Get the current HEAD revision number, or null if no commits yet. */\n private async resolveHead(): Promise<{ branch: string | null; revision: number | null }> {\n const head = await this.storage.readHead();\n if (head.revision !== undefined) {\n return { branch: null, revision: head.revision };\n }\n if (head.ref) {\n const branchName = head.ref.replace(\"refs/heads/\", \"\");\n const branchRef = await this.storage.readBranch(branchName);\n return { branch: branchName, revision: branchRef?.revision ?? null };\n }\n return { branch: null, revision: null };\n }\n\n /** Get current HEAD manifest, or empty if no commits. */\n private async headManifest(): Promise<TreeManifest> {\n const { revision } = await this.resolveHead();\n if (revision === null) return {};\n const rev = await this.storage.readRevision(revision);\n return rev.tree;\n }\n\n /** Commit all pending changes, or selective changes if paths are provided. */\n async commit(message: string, opts?: CommitOptions): Promise<Revision> {\n await this.ensureInit();\n\n const { branch, revision: parentId } = await this.resolveHead();\n const parentManifest = parentId !== null\n ? (await this.storage.readRevision(parentId)).tree\n : {};\n\n let newTree: TreeManifest;\n let changes: DiffEntry[];\n\n if (opts?.paths && opts.paths.length > 0) {\n // Selective commit: only include matching files\n const fullManifest = await buildTreeManifest(this.workFs, this.workPath, {\n rules: this.rules,\n trackedPaths: Object.keys(parentManifest),\n });\n const matchedPaths = filterPathsByGlobs(Object.keys(fullManifest), opts.paths);\n\n // Start with parent manifest, overlay matched files from working tree\n newTree = { ...parentManifest };\n\n // Also check for deletions: files in parent that match patterns but are gone from working tree\n const parentMatchedPaths = filterPathsByGlobs(Object.keys(parentManifest), opts.paths);\n for (const p of parentMatchedPaths) {\n if (!fullManifest[p]) {\n delete newTree[p]; // file was deleted\n }\n }\n\n for (const p of matchedPaths) {\n newTree[p] = fullManifest[p]!;\n }\n\n // Compute changes only for matched paths\n const relevantBefore: TreeManifest = {};\n const relevantAfter: TreeManifest = {};\n const allRelevant = new Set([...matchedPaths, ...parentMatchedPaths]);\n for (const p of allRelevant) {\n if (parentManifest[p]) relevantBefore[p] = parentManifest[p]!;\n if (newTree[p]) relevantAfter[p] = newTree[p]!;\n }\n changes = diffManifests(relevantBefore, relevantAfter, this.rules);\n } else {\n // Full commit\n newTree = await buildTreeManifest(this.workFs, this.workPath, {\n rules: this.rules,\n trackedPaths: Object.keys(parentManifest),\n });\n changes = diffManifests(parentManifest, newTree, this.rules);\n }\n\n if (changes.length === 0) {\n throw new Error(\"nothing to commit\");\n }\n\n const id = await this.storage.nextRevisionId();\n const rev: Revision = {\n id,\n parent: parentId,\n branch: branch ?? \"detached\",\n message,\n timestamp: new Date().toISOString(),\n changes,\n tree: newTree,\n };\n\n await this.storage.writeRevision(rev);\n\n // Update branch ref or HEAD\n if (branch) {\n await this.storage.writeBranch(branch, { revision: id });\n } else {\n await this.storage.writeHead({ revision: id });\n }\n\n return rev;\n }\n\n /** Checkout a revision number or branch name. */\n async checkout(target: string | number, opts?: CheckoutOptions): Promise<void> {\n await this.ensureInit();\n\n const isPartial = opts?.paths && opts.paths.length > 0;\n\n let targetRevision: number;\n let targetBranch: string | null = null;\n\n if (typeof target === \"string\") {\n // Check if it's a branch name\n const branchRef = await this.storage.readBranch(target);\n if (branchRef) {\n targetBranch = target;\n targetRevision = branchRef.revision;\n } else {\n throw new Error(`unknown branch or revision: \"${target}\"`);\n }\n } else {\n targetRevision = target;\n }\n\n // Verify revision exists\n let rev: Revision;\n try {\n rev = await this.storage.readRevision(targetRevision);\n } catch {\n throw new Error(`revision ${targetRevision} not found`);\n }\n\n const currentManifest = await this.headManifest();\n\n if (isPartial) {\n // Partial checkout: restore specific files, don't update HEAD\n await restoreTree(this.workFs, this.workPath, rev.tree, {\n fullRestore: false,\n paths: opts!.paths!,\n rules: this.rules,\n trackedPaths: Object.keys(currentManifest),\n });\n } else {\n // Full checkout\n if (!opts?.force) {\n const changes = await this.status();\n if (changes.length > 0) {\n throw new Error(\"working tree has uncommitted changes (use force to discard)\");\n }\n }\n\n await restoreTree(this.workFs, this.workPath, rev.tree, {\n fullRestore: true,\n rules: this.rules,\n trackedPaths: Object.keys(currentManifest),\n });\n\n // Update HEAD\n if (targetBranch) {\n await this.storage.writeHead({ ref: `refs/heads/${targetBranch}` });\n } else {\n await this.storage.writeHead({ revision: targetRevision });\n }\n }\n }\n\n /** Create a new branch at HEAD. */\n async branch(name: string): Promise<void> {\n await this.ensureInit();\n\n const existing = await this.storage.readBranch(name);\n if (existing) {\n throw new Error(`branch \"${name}\" already exists`);\n }\n\n const { revision } = await this.resolveHead();\n if (revision === null) {\n throw new Error(\"cannot create branch: no commits yet\");\n }\n\n await this.storage.writeBranch(name, { revision });\n }\n\n /** List all branches. */\n async branches(): Promise<BranchInfo[]> {\n await this.ensureInit();\n\n const names = await this.storage.listBranches();\n const head = await this.resolveHead();\n const result: BranchInfo[] = [];\n\n for (const name of names) {\n const ref = await this.storage.readBranch(name);\n if (ref) {\n result.push({\n name,\n revision: ref.revision,\n current: head.branch === name,\n });\n }\n }\n\n return result.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Get revision history. */\n async log(opts?: LogOptions): Promise<LogEntry[]> {\n await this.ensureInit();\n\n let startRevision: number | null;\n\n if (opts?.branch) {\n const branchRef = await this.storage.readBranch(opts.branch);\n if (!branchRef) throw new Error(`branch \"${opts.branch}\" not found`);\n startRevision = branchRef.revision;\n } else {\n const { revision } = await this.resolveHead();\n startRevision = revision;\n }\n\n if (startRevision === null) return [];\n\n const entries: LogEntry[] = [];\n let currentId: number | null = startRevision;\n\n while (currentId !== null) {\n if (opts?.limit && entries.length >= opts.limit) break;\n\n let rev: Revision;\n try {\n rev = await this.storage.readRevision(currentId);\n } catch {\n break;\n }\n\n const changedPaths = rev.changes.map((c) => c.path);\n\n if (opts?.path) {\n // Filter: only include if this revision touches the specified path\n const matchesPath = changedPaths.some((p) => matchVCSPath(opts.path!, p));\n if (matchesPath) {\n entries.push({\n id: rev.id,\n parent: rev.parent,\n branch: rev.branch,\n message: rev.message,\n timestamp: rev.timestamp,\n paths: changedPaths,\n });\n }\n } else {\n entries.push({\n id: rev.id,\n parent: rev.parent,\n branch: rev.branch,\n message: rev.message,\n timestamp: rev.timestamp,\n paths: changedPaths,\n });\n }\n\n currentId = rev.parent;\n }\n\n return entries;\n }\n\n /** Get uncommitted changes as DiffEntry[]. */\n async status(): Promise<DiffEntry[]> {\n await this.ensureInit();\n const manifest = await this.headManifest();\n return diffWorkingTree(this.workFs, this.workPath, manifest, this.rules);\n }\n\n /** Diff between two revisions. */\n async diff(revA: number, revB: number): Promise<DiffEntry[]> {\n await this.ensureInit();\n const a = await this.storage.readRevision(revA);\n const b = await this.storage.readRevision(revB);\n return diffManifests(a.tree, b.tree, this.rules);\n }\n\n /** Get current HEAD info. */\n async head(): Promise<{ branch: string | null; revision: number | null }> {\n await this.ensureInit();\n return this.resolveHead();\n }\n}\n\n/**\n * Filter a list of paths to only those matching any of the given glob patterns.\n * Patterns may start with `/` which is stripped before matching.\n */\nfunction filterPathsByGlobs(paths: string[], patterns: string[]): string[] {\n return paths.filter((filePath) =>\n patterns.some((pattern) => matchVCSPath(pattern, filePath)),\n );\n}\n\nfunction resolveInternalPath(\n workFs: VirtualFS,\n metaFs: VirtualFS,\n workPath: string,\n metaPath: string,\n): string {\n if (workFs !== metaFs) return \"\";\n\n const normalizedWork = normalizeFsPath(workPath);\n const normalizedMeta = normalizeFsPath(metaFs.resolve(metaPath));\n\n if (normalizedMeta === normalizedWork) return \"\";\n if (!normalizedMeta.startsWith(`${normalizedWork}/`)) return \"\";\n\n return normalizedMeta.slice(normalizedWork.length + 1);\n}\n\nfunction normalizeFsPath(path: string): string {\n return path.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n"
|
|
5
|
+
"import type { VirtualFS } from \"../types.mjs\";\nimport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n VCSIndexEntry,\n} from \"./types.mjs\";\nimport { VCSStorage } from \"./storage.mjs\";\nimport { diffManifests } from \"./diff.mjs\";\nimport { VCSObjectStore } from \"./objects.mjs\";\nimport { matchVCSPath, VCSRules } from \"./rules.mjs\";\nimport {\n buildTreeManifest,\n rebuildIndexForManifest,\n restoreTree,\n updateIndexForScopedPaths,\n} from \"./snapshot.mjs\";\n\nexport class VersionControlSystem {\n private readonly workFs: VirtualFS;\n private readonly workPath: string;\n private readonly storage: VCSStorage;\n private readonly objectStore: VCSObjectStore;\n private readonly vcsInternalPath: string;\n private readonly rules: VCSRules;\n\n constructor(config: VCSConfig) {\n this.workFs = config.fs;\n this.workPath = config.fs.resolve(config.path);\n\n const metaFs = config.vcsPath?.fs ?? config.fs;\n const metaPath = config.vcsPath?.path ?? metaFs.resolve(config.path, \".vcs\");\n this.storage = new VCSStorage(metaFs, metaPath);\n this.objectStore = new VCSObjectStore(this.storage.fileSystem, this.storage.resolve());\n\n this.vcsInternalPath = resolveInternalPath(config.fs, metaFs, this.workPath, metaPath);\n\n this.rules = new VCSRules({\n internalPath: this.vcsInternalPath,\n ignore: config.ignore,\n attributes: config.attributes,\n });\n }\n\n /** Initialize the .vcs directory. Called automatically on first operation if needed. */\n async init(): Promise<void> {\n if (await this.storage.isInitialized()) {\n await this.storage.assertSupportedFormat();\n return;\n }\n await this.storage.initialize();\n await this.objectStore.initialize();\n }\n\n private async ensureInit(): Promise<void> {\n if (!(await this.storage.isInitialized())) {\n await this.init();\n return;\n }\n await this.storage.assertSupportedFormat();\n }\n\n /** Get the current HEAD revision number, or null if no commits yet. */\n private async resolveHead(): Promise<{ branch: string | null; revision: number | null }> {\n const head = await this.storage.readHead();\n if (head.revision !== undefined) {\n return { branch: null, revision: head.revision };\n }\n if (head.ref) {\n const branchName = head.ref.replace(\"refs/heads/\", \"\");\n const branchRef = await this.storage.readBranch(branchName);\n return { branch: branchName, revision: branchRef?.revision ?? null };\n }\n return { branch: null, revision: null };\n }\n\n /** Get current HEAD manifest, or empty if no commits. */\n private async headManifest(): Promise<TreeManifest> {\n const { revision } = await this.resolveHead();\n if (revision === null) return {};\n const rev = await this.storage.readRevision(revision);\n return rev.tree;\n }\n\n private async currentIndex(): Promise<Record<string, VCSIndexEntry>> {\n return this.storage.readIndex();\n }\n\n /** Commit all pending changes, or selective changes if paths are provided. */\n async commit(message: string, opts?: CommitOptions): Promise<Revision> {\n await this.ensureInit();\n\n const { branch, revision: parentId } = await this.resolveHead();\n const parentManifest = parentId !== null\n ? (await this.storage.readRevision(parentId)).tree\n : {};\n const previousIndex = await this.currentIndex();\n const working = await buildTreeManifest(this.workFs, this.workPath, {\n objectStore: this.objectStore,\n rules: this.rules,\n trackedPaths: Object.keys(parentManifest),\n indexEntries: previousIndex,\n });\n\n let newTree: TreeManifest;\n let changes: DiffEntry[];\n\n if (opts?.paths && opts.paths.length > 0) {\n const matchedPaths = filterPathsByGlobs(Object.keys(working.manifest), opts.paths);\n const parentMatchedPaths = filterPathsByGlobs(Object.keys(parentManifest), opts.paths);\n newTree = { ...parentManifest };\n\n for (const path of parentMatchedPaths) {\n if (!working.manifest[path]) {\n delete newTree[path];\n }\n }\n for (const path of matchedPaths) {\n newTree[path] = working.manifest[path]!;\n }\n\n const relevantBefore: TreeManifest = {};\n const relevantAfter: TreeManifest = {};\n const allRelevant = new Set([...matchedPaths, ...parentMatchedPaths]);\n for (const path of allRelevant) {\n if (parentManifest[path]) relevantBefore[path] = parentManifest[path]!;\n if (newTree[path]) relevantAfter[path] = newTree[path]!;\n }\n changes = await diffManifests(relevantBefore, relevantAfter, {\n rules: this.rules,\n objectStore: this.objectStore,\n beforeIndex: previousIndex,\n afterIndex: working.indexEntries,\n });\n } else {\n newTree = working.manifest;\n changes = await diffManifests(parentManifest, newTree, {\n rules: this.rules,\n objectStore: this.objectStore,\n beforeIndex: previousIndex,\n afterIndex: working.indexEntries,\n });\n }\n\n if (changes.length === 0) {\n throw new Error(\"nothing to commit\");\n }\n\n const id = await this.storage.nextRevisionId();\n const rev: Revision = {\n id,\n parent: parentId,\n branch: branch ?? \"detached\",\n message,\n timestamp: new Date().toISOString(),\n changes,\n tree: newTree,\n };\n\n await this.storage.writeRevision(rev);\n await this.storage.writeIndex(working.indexEntries);\n\n if (branch) {\n await this.storage.writeBranch(branch, { revision: id });\n } else {\n await this.storage.writeHead({ revision: id });\n }\n\n return rev;\n }\n\n /** Checkout a revision number or branch name. */\n async checkout(target: string | number, opts?: CheckoutOptions): Promise<void> {\n await this.ensureInit();\n\n const isPartial = opts?.paths && opts.paths.length > 0;\n\n let targetRevision: number;\n let targetBranch: string | null = null;\n\n if (typeof target === \"string\") {\n const branchRef = await this.storage.readBranch(target);\n if (branchRef) {\n targetBranch = target;\n targetRevision = branchRef.revision;\n } else {\n throw new Error(`unknown branch or revision: \"${target}\"`);\n }\n } else {\n targetRevision = target;\n }\n\n let rev: Revision;\n try {\n rev = await this.storage.readRevision(targetRevision);\n } catch {\n throw new Error(`revision ${targetRevision} not found`);\n }\n\n const currentManifest = await this.headManifest();\n\n if (isPartial) {\n await restoreTree(this.workFs, this.workPath, rev.tree, this.objectStore, {\n fullRestore: false,\n paths: opts!.paths!,\n rules: this.rules,\n trackedPaths: Object.keys(currentManifest),\n });\n\n const updatedIndex = await updateIndexForScopedPaths(\n this.workFs,\n this.workPath,\n rev.tree,\n this.objectStore,\n await this.currentIndex(),\n opts!.paths!,\n );\n await this.storage.writeIndex(updatedIndex);\n return;\n }\n\n if (!opts?.force) {\n const changes = await this.status();\n if (changes.length > 0) {\n throw new Error(\"working tree has uncommitted changes (use force to discard)\");\n }\n }\n\n await restoreTree(this.workFs, this.workPath, rev.tree, this.objectStore, {\n fullRestore: true,\n rules: this.rules,\n trackedPaths: Object.keys(currentManifest),\n });\n\n await this.storage.writeIndex(\n await rebuildIndexForManifest(this.workFs, this.workPath, rev.tree, this.objectStore),\n );\n\n if (targetBranch) {\n await this.storage.writeHead({ ref: `refs/heads/${targetBranch}` });\n } else {\n await this.storage.writeHead({ revision: targetRevision });\n }\n }\n\n /** Create a new branch at HEAD. */\n async branch(name: string): Promise<void> {\n await this.ensureInit();\n\n const existing = await this.storage.readBranch(name);\n if (existing) {\n throw new Error(`branch \"${name}\" already exists`);\n }\n\n const { revision } = await this.resolveHead();\n if (revision === null) {\n throw new Error(\"cannot create branch: no commits yet\");\n }\n\n await this.storage.writeBranch(name, { revision });\n }\n\n /** List all branches. */\n async branches(): Promise<BranchInfo[]> {\n await this.ensureInit();\n\n const names = await this.storage.listBranches();\n const head = await this.resolveHead();\n const result: BranchInfo[] = [];\n\n for (const name of names) {\n const ref = await this.storage.readBranch(name);\n if (ref) {\n result.push({\n name,\n revision: ref.revision,\n current: head.branch === name,\n });\n }\n }\n\n return result.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Get revision history. */\n async log(opts?: LogOptions): Promise<LogEntry[]> {\n await this.ensureInit();\n\n let startRevision: number | null;\n\n if (opts?.branch) {\n const branchRef = await this.storage.readBranch(opts.branch);\n if (!branchRef) throw new Error(`branch \"${opts.branch}\" not found`);\n startRevision = branchRef.revision;\n } else {\n const { revision } = await this.resolveHead();\n startRevision = revision;\n }\n\n if (startRevision === null) return [];\n\n const entries: LogEntry[] = [];\n let currentId: number | null = startRevision;\n\n while (currentId !== null) {\n if (opts?.limit && entries.length >= opts.limit) break;\n\n let rev: Revision;\n try {\n rev = await this.storage.readRevision(currentId);\n } catch {\n break;\n }\n\n const changedPaths = rev.changes.map((change) => change.path);\n\n if (opts?.path) {\n const matchesPath = changedPaths.some((path) => matchVCSPath(opts.path!, path));\n if (!matchesPath) {\n currentId = rev.parent;\n continue;\n }\n }\n\n entries.push({\n id: rev.id,\n parent: rev.parent,\n branch: rev.branch,\n message: rev.message,\n timestamp: rev.timestamp,\n paths: changedPaths,\n });\n\n currentId = rev.parent;\n }\n\n return entries;\n }\n\n /** Get uncommitted changes as DiffEntry[]. */\n async status(): Promise<DiffEntry[]> {\n await this.ensureInit();\n const manifest = await this.headManifest();\n const previousIndex = await this.currentIndex();\n const working = await buildTreeManifest(this.workFs, this.workPath, {\n objectStore: this.objectStore,\n rules: this.rules,\n trackedPaths: Object.keys(manifest),\n indexEntries: previousIndex,\n });\n await this.storage.writeIndex(working.indexEntries);\n return diffManifests(manifest, working.manifest, {\n rules: this.rules,\n objectStore: this.objectStore,\n beforeIndex: previousIndex,\n afterIndex: working.indexEntries,\n });\n }\n\n /** Diff between two revisions. */\n async diff(revA: number, revB: number): Promise<DiffEntry[]> {\n await this.ensureInit();\n const a = await this.storage.readRevision(revA);\n const b = await this.storage.readRevision(revB);\n return diffManifests(a.tree, b.tree, {\n rules: this.rules,\n objectStore: this.objectStore,\n });\n }\n\n async readBlob(blobId: string): Promise<Buffer>;\n async readBlob(blobId: string, encoding: BufferEncoding): Promise<string>;\n async readBlob(blobId: string, encoding?: BufferEncoding): Promise<Buffer | string> {\n const content = await this.objectStore.readBlob(blobId);\n return encoding ? content.toString(encoding) : content;\n }\n\n async readRevisionFile(revisionId: number, path: string): Promise<Buffer>;\n async readRevisionFile(\n revisionId: number,\n path: string,\n encoding: BufferEncoding,\n ): Promise<string>;\n async readRevisionFile(\n revisionId: number,\n path: string,\n encoding?: BufferEncoding,\n ): Promise<Buffer | string> {\n const revision = await this.storage.readRevision(revisionId);\n const normalizedPath = path.replace(/^\\/+/, \"\");\n const entry = revision.tree[normalizedPath];\n if (!entry || entry.kind === \"directory\") {\n throw new Error(`file \"${path}\" not found in revision ${revisionId}`);\n }\n return this.readBlob(entry.blobId, encoding as BufferEncoding);\n }\n\n /** Get current HEAD info. */\n async head(): Promise<{ branch: string | null; revision: number | null }> {\n await this.ensureInit();\n return this.resolveHead();\n }\n}\n\nfunction filterPathsByGlobs(paths: string[], patterns: string[]): string[] {\n return paths.filter((filePath) =>\n patterns.some((pattern) => matchVCSPath(pattern, filePath)),\n );\n}\n\nfunction resolveInternalPath(\n workFs: VirtualFS,\n metaFs: VirtualFS,\n workPath: string,\n metaPath: string,\n): string {\n if (workFs !== metaFs) return \"\";\n\n const normalizedWork = normalizeFsPath(workPath);\n const normalizedMeta = normalizeFsPath(metaFs.resolve(metaPath));\n\n if (normalizedMeta === normalizedWork) return \"\";\n if (!normalizedMeta.startsWith(`${normalizedWork}/`)) return \"\";\n\n return normalizedMeta.slice(normalizedWork.length + 1);\n}\n\nfunction normalizeFsPath(path: string): string {\n return path.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAaA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,MAAM,qBAAqB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,WAAW,CAAC,QAAmB;AAAA,IAC7B,KAAK,SAAS,OAAO;AAAA,IACrB,KAAK,WAAW,OAAO,GAAG,QAAQ,OAAO,IAAI;AAAA,IAE7C,MAAM,SAAS,OAAO,SAAS,MAAM,OAAO;AAAA,IAC5C,MAAM,WAAW,OAAO,SAAS,QAAQ,OAAO,QAAQ,OAAO,MAAM,MAAM;AAAA,IAC3E,KAAK,UAAU,IAAI,WAAW,QAAQ,QAAQ;AAAA,IAC9C,KAAK,cAAc,IAAI,eAAe,KAAK,QAAQ,YAAY,KAAK,QAAQ,QAAQ,CAAC;AAAA,IAErF,KAAK,kBAAkB,oBAAoB,OAAO,IAAI,QAAQ,KAAK,UAAU,QAAQ;AAAA,IAErF,KAAK,QAAQ,IAAI,SAAS;AAAA,MACxB,cAAc,KAAK;AAAA,MACnB,QAAQ,OAAO;AAAA,MACf,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA;AAAA,OAIG,KAAI,GAAkB;AAAA,IAC1B,IAAI,MAAM,KAAK,QAAQ,cAAc,GAAG;AAAA,MACtC,MAAM,KAAK,QAAQ,sBAAsB;AAAA,MACzC;AAAA,IACF;AAAA,IACA,MAAM,KAAK,QAAQ,WAAW;AAAA,IAC9B,MAAM,KAAK,YAAY,WAAW;AAAA;AAAA,OAGtB,WAAU,GAAkB;AAAA,IACxC,IAAI,CAAE,MAAM,KAAK,QAAQ,cAAc,GAAI;AAAA,MACzC,MAAM,KAAK,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,IACA,MAAM,KAAK,QAAQ,sBAAsB;AAAA;AAAA,OAI7B,YAAW,GAAgE;AAAA,IACvF,MAAM,OAAO,MAAM,KAAK,QAAQ,SAAS;AAAA,IACzC,IAAI,KAAK,aAAa,WAAW;AAAA,MAC/B,OAAO,EAAE,QAAQ,MAAM,UAAU,KAAK,SAAS;AAAA,IACjD;AAAA,IACA,IAAI,KAAK,KAAK;AAAA,MACZ,MAAM,aAAa,KAAK,IAAI,QAAQ,eAAe,EAAE;AAAA,MACrD,MAAM,YAAY,MAAM,KAAK,QAAQ,WAAW,UAAU;AAAA,MAC1D,OAAO,EAAE,QAAQ,YAAY,UAAU,WAAW,YAAY,KAAK;AAAA,IACrE;AAAA,IACA,OAAO,EAAE,QAAQ,MAAM,UAAU,KAAK;AAAA;AAAA,OAI1B,aAAY,GAA0B;AAAA,IAClD,QAAQ,aAAa,MAAM,KAAK,YAAY;AAAA,IAC5C,IAAI,aAAa;AAAA,MAAM,OAAO,CAAC;AAAA,IAC/B,MAAM,MAAM,MAAM,KAAK,QAAQ,aAAa,QAAQ;AAAA,IACpD,OAAO,IAAI;AAAA;AAAA,OAGC,aAAY,GAA2C;AAAA,IACnE,OAAO,KAAK,QAAQ,UAAU;AAAA;AAAA,OAI1B,OAAM,CAAC,SAAiB,MAAyC;AAAA,IACrE,MAAM,KAAK,WAAW;AAAA,IAEtB,QAAQ,QAAQ,UAAU,aAAa,MAAM,KAAK,YAAY;AAAA,IAC9D,MAAM,iBAAiB,aAAa,QAC/B,MAAM,KAAK,QAAQ,aAAa,QAAQ,GAAG,OAC5C,CAAC;AAAA,IACL,MAAM,gBAAgB,MAAM,KAAK,aAAa;AAAA,IAC9C,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,KAAK,UAAU;AAAA,MAClE,aAAa,KAAK;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,cAAc,OAAO,KAAK,cAAc;AAAA,MACxC,cAAc;AAAA,IAChB,CAAC;AAAA,IAED,IAAI;AAAA,IACJ,IAAI;AAAA,IAEJ,IAAI,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG;AAAA,MACxC,MAAM,eAAe,mBAAmB,OAAO,KAAK,QAAQ,QAAQ,GAAG,KAAK,KAAK;AAAA,MACjF,MAAM,qBAAqB,mBAAmB,OAAO,KAAK,cAAc,GAAG,KAAK,KAAK;AAAA,MACrF,UAAU,KAAK,eAAe;AAAA,MAE9B,WAAW,QAAQ,oBAAoB;AAAA,QACrC,IAAI,CAAC,QAAQ,SAAS,OAAO;AAAA,UAC3B,OAAO,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,MACA,WAAW,QAAQ,cAAc;AAAA,QAC/B,QAAQ,QAAQ,QAAQ,SAAS;AAAA,MACnC;AAAA,MAEA,MAAM,iBAA+B,CAAC;AAAA,MACtC,MAAM,gBAA8B,CAAC;AAAA,MACrC,MAAM,cAAc,IAAI,IAAI,CAAC,GAAG,cAAc,GAAG,kBAAkB,CAAC;AAAA,MACpE,WAAW,QAAQ,aAAa;AAAA,QAC9B,IAAI,eAAe;AAAA,UAAO,eAAe,QAAQ,eAAe;AAAA,QAChE,IAAI,QAAQ;AAAA,UAAO,cAAc,QAAQ,QAAQ;AAAA,MACnD;AAAA,MACA,UAAU,MAAM,cAAc,gBAAgB,eAAe;AAAA,QAC3D,OAAO,KAAK;AAAA,QACZ,aAAa,KAAK;AAAA,QAClB,aAAa;AAAA,QACb,YAAY,QAAQ;AAAA,MACtB,CAAC;AAAA,IACH,EAAO;AAAA,MACL,UAAU,QAAQ;AAAA,MAClB,UAAU,MAAM,cAAc,gBAAgB,SAAS;AAAA,QACrD,OAAO,KAAK;AAAA,QACZ,aAAa,KAAK;AAAA,QAClB,aAAa;AAAA,QACb,YAAY,QAAQ;AAAA,MACtB,CAAC;AAAA;AAAA,IAGH,IAAI,QAAQ,WAAW,GAAG;AAAA,MACxB,MAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAAA,IAEA,MAAM,KAAK,MAAM,KAAK,QAAQ,eAAe;AAAA,IAC7C,MAAM,MAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,WAAW,IAAI,KAAK,EAAE,YAAY;AAAA,MAClC;AAAA,MACA,MAAM;AAAA,IACR;AAAA,IAEA,MAAM,KAAK,QAAQ,cAAc,GAAG;AAAA,IACpC,MAAM,KAAK,QAAQ,WAAW,QAAQ,YAAY;AAAA,IAElD,IAAI,QAAQ;AAAA,MACV,MAAM,KAAK,QAAQ,YAAY,QAAQ,EAAE,UAAU,GAAG,CAAC;AAAA,IACzD,EAAO;AAAA,MACL,MAAM,KAAK,QAAQ,UAAU,EAAE,UAAU,GAAG,CAAC;AAAA;AAAA,IAG/C,OAAO;AAAA;AAAA,OAIH,SAAQ,CAAC,QAAyB,MAAuC;AAAA,IAC7E,MAAM,KAAK,WAAW;AAAA,IAEtB,MAAM,YAAY,MAAM,SAAS,KAAK,MAAM,SAAS;AAAA,IAErD,IAAI;AAAA,IACJ,IAAI,eAA8B;AAAA,IAElC,IAAI,OAAO,WAAW,UAAU;AAAA,MAC9B,MAAM,YAAY,MAAM,KAAK,QAAQ,WAAW,MAAM;AAAA,MACtD,IAAI,WAAW;AAAA,QACb,eAAe;AAAA,QACf,iBAAiB,UAAU;AAAA,MAC7B,EAAO;AAAA,QACL,MAAM,IAAI,MAAM,gCAAgC,SAAS;AAAA;AAAA,IAE7D,EAAO;AAAA,MACL,iBAAiB;AAAA;AAAA,IAGnB,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,MAAM,MAAM,KAAK,QAAQ,aAAa,cAAc;AAAA,MACpD,MAAM;AAAA,MACN,MAAM,IAAI,MAAM,YAAY,0BAA0B;AAAA;AAAA,IAGxD,MAAM,kBAAkB,MAAM,KAAK,aAAa;AAAA,IAEhD,IAAI,WAAW;AAAA,MACb,MAAM,YAAY,KAAK,QAAQ,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa;AAAA,QACxE,aAAa;AAAA,QACb,OAAO,KAAM;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,cAAc,OAAO,KAAK,eAAe;AAAA,MAC3C,CAAC;AAAA,MAED,MAAM,eAAe,MAAM,0BACzB,KAAK,QACL,KAAK,UACL,IAAI,MACJ,KAAK,aACL,MAAM,KAAK,aAAa,GACxB,KAAM,KACR;AAAA,MACA,MAAM,KAAK,QAAQ,WAAW,YAAY;AAAA,MAC1C;AAAA,IACF;AAAA,IAEA,IAAI,CAAC,MAAM,OAAO;AAAA,MAChB,MAAM,UAAU,MAAM,KAAK,OAAO;AAAA,MAClC,IAAI,QAAQ,SAAS,GAAG;AAAA,QACtB,MAAM,IAAI,MAAM,6DAA6D;AAAA,MAC/E;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,KAAK,QAAQ,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa;AAAA,MACxE,aAAa;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,cAAc,OAAO,KAAK,eAAe;AAAA,IAC3C,CAAC;AAAA,IAED,MAAM,KAAK,QAAQ,WACjB,MAAM,wBAAwB,KAAK,QAAQ,KAAK,UAAU,IAAI,MAAM,KAAK,WAAW,CACtF;AAAA,IAEA,IAAI,cAAc;AAAA,MAChB,MAAM,KAAK,QAAQ,UAAU,EAAE,KAAK,cAAc,eAAe,CAAC;AAAA,IACpE,EAAO;AAAA,MACL,MAAM,KAAK,QAAQ,UAAU,EAAE,UAAU,eAAe,CAAC;AAAA;AAAA;AAAA,OAKvD,OAAM,CAAC,MAA6B;AAAA,IACxC,MAAM,KAAK,WAAW;AAAA,IAEtB,MAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,IAAI;AAAA,IACnD,IAAI,UAAU;AAAA,MACZ,MAAM,IAAI,MAAM,WAAW,sBAAsB;AAAA,IACnD;AAAA,IAEA,QAAQ,aAAa,MAAM,KAAK,YAAY;AAAA,IAC5C,IAAI,aAAa,MAAM;AAAA,MACrB,MAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AAAA,IAEA,MAAM,KAAK,QAAQ,YAAY,MAAM,EAAE,SAAS,CAAC;AAAA;AAAA,OAI7C,SAAQ,GAA0B;AAAA,IACtC,MAAM,KAAK,WAAW;AAAA,IAEtB,MAAM,QAAQ,MAAM,KAAK,QAAQ,aAAa;AAAA,IAC9C,MAAM,OAAO,MAAM,KAAK,YAAY;AAAA,IACpC,MAAM,SAAuB,CAAC;AAAA,IAE9B,WAAW,QAAQ,OAAO;AAAA,MACxB,MAAM,MAAM,MAAM,KAAK,QAAQ,WAAW,IAAI;AAAA,MAC9C,IAAI,KAAK;AAAA,QACP,OAAO,KAAK;AAAA,UACV;AAAA,UACA,UAAU,IAAI;AAAA,UACd,SAAS,KAAK,WAAW;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,OAAO,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAAA,OAIrD,IAAG,CAAC,MAAwC;AAAA,IAChD,MAAM,KAAK,WAAW;AAAA,IAEtB,IAAI;AAAA,IAEJ,IAAI,MAAM,QAAQ;AAAA,MAChB,MAAM,YAAY,MAAM,KAAK,QAAQ,WAAW,KAAK,MAAM;AAAA,MAC3D,IAAI,CAAC;AAAA,QAAW,MAAM,IAAI,MAAM,WAAW,KAAK,mBAAmB;AAAA,MACnE,gBAAgB,UAAU;AAAA,IAC5B,EAAO;AAAA,MACL,QAAQ,aAAa,MAAM,KAAK,YAAY;AAAA,MAC5C,gBAAgB;AAAA;AAAA,IAGlB,IAAI,kBAAkB;AAAA,MAAM,OAAO,CAAC;AAAA,IAEpC,MAAM,UAAsB,CAAC;AAAA,IAC7B,IAAI,YAA2B;AAAA,IAE/B,OAAO,cAAc,MAAM;AAAA,MACzB,IAAI,MAAM,SAAS,QAAQ,UAAU,KAAK;AAAA,QAAO;AAAA,MAEjD,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,MAAM,MAAM,KAAK,QAAQ,aAAa,SAAS;AAAA,QAC/C,MAAM;AAAA,QACN;AAAA;AAAA,MAGF,MAAM,eAAe,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI;AAAA,MAE5D,IAAI,MAAM,MAAM;AAAA,QACd,MAAM,cAAc,aAAa,KAAK,CAAC,SAAS,aAAa,KAAK,MAAO,IAAI,CAAC;AAAA,QAC9E,IAAI,CAAC,aAAa;AAAA,UAChB,YAAY,IAAI;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,MAEA,QAAQ,KAAK;AAAA,QACX,IAAI,IAAI;AAAA,QACR,QAAQ,IAAI;AAAA,QACZ,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,WAAW,IAAI;AAAA,QACf,OAAO;AAAA,MACT,CAAC;AAAA,MAED,YAAY,IAAI;AAAA,IAClB;AAAA,IAEA,OAAO;AAAA;AAAA,OAIH,OAAM,GAAyB;AAAA,IACnC,MAAM,KAAK,WAAW;AAAA,IACtB,MAAM,WAAW,MAAM,KAAK,aAAa;AAAA,IACzC,MAAM,gBAAgB,MAAM,KAAK,aAAa;AAAA,IAC9C,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,KAAK,UAAU;AAAA,MAClE,aAAa,KAAK;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,cAAc,OAAO,KAAK,QAAQ;AAAA,MAClC,cAAc;AAAA,IAChB,CAAC;AAAA,IACD,MAAM,KAAK,QAAQ,WAAW,QAAQ,YAAY;AAAA,IAClD,OAAO,cAAc,UAAU,QAAQ,UAAU;AAAA,MAC/C,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,MAClB,aAAa;AAAA,MACb,YAAY,QAAQ;AAAA,IACtB,CAAC;AAAA;AAAA,OAIG,KAAI,CAAC,MAAc,MAAoC;AAAA,IAC3D,MAAM,KAAK,WAAW;AAAA,IACtB,MAAM,IAAI,MAAM,KAAK,QAAQ,aAAa,IAAI;AAAA,IAC9C,MAAM,IAAI,MAAM,KAAK,QAAQ,aAAa,IAAI;AAAA,IAC9C,OAAO,cAAc,EAAE,MAAM,EAAE,MAAM;AAAA,MACnC,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,IACpB,CAAC;AAAA;AAAA,OAKG,SAAQ,CAAC,QAAgB,UAAqD;AAAA,IAClF,MAAM,UAAU,MAAM,KAAK,YAAY,SAAS,MAAM;AAAA,IACtD,OAAO,WAAW,QAAQ,SAAS,QAAQ,IAAI;AAAA;AAAA,OAS3C,iBAAgB,CACpB,YACA,MACA,UAC0B;AAAA,IAC1B,MAAM,WAAW,MAAM,KAAK,QAAQ,aAAa,UAAU;AAAA,IAC3D,MAAM,iBAAiB,KAAK,QAAQ,QAAQ,EAAE;AAAA,IAC9C,MAAM,QAAQ,SAAS,KAAK;AAAA,IAC5B,IAAI,CAAC,SAAS,MAAM,SAAS,aAAa;AAAA,MACxC,MAAM,IAAI,MAAM,SAAS,+BAA+B,YAAY;AAAA,IACtE;AAAA,IACA,OAAO,KAAK,SAAS,MAAM,QAAQ,QAA0B;AAAA;AAAA,OAIzD,KAAI,GAAgE;AAAA,IACxE,MAAM,KAAK,WAAW;AAAA,IACtB,OAAO,KAAK,YAAY;AAAA;AAE5B;AAEA,SAAS,kBAAkB,CAAC,OAAiB,UAA8B;AAAA,EACzE,OAAO,MAAM,OAAO,CAAC,aACnB,SAAS,KAAK,CAAC,YAAY,aAAa,SAAS,QAAQ,CAAC,CAC5D;AAAA;AAGF,SAAS,mBAAmB,CAC1B,QACA,QACA,UACA,UACQ;AAAA,EACR,IAAI,WAAW;AAAA,IAAQ,OAAO;AAAA,EAE9B,MAAM,iBAAiB,gBAAgB,QAAQ;AAAA,EAC/C,MAAM,iBAAiB,gBAAgB,OAAO,QAAQ,QAAQ,CAAC;AAAA,EAE/D,IAAI,mBAAmB;AAAA,IAAgB,OAAO;AAAA,EAC9C,IAAI,CAAC,eAAe,WAAW,GAAG,iBAAiB;AAAA,IAAG,OAAO;AAAA,EAE7D,OAAO,eAAe,MAAM,eAAe,SAAS,CAAC;AAAA;AAGvD,SAAS,eAAe,CAAC,MAAsB;AAAA,EAC7C,OAAO,KAAK,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAAA;",
|
|
8
|
+
"debugId": "CA82B0F6ED31CC1264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { VirtualFS, FileStat } from "../types.ts";
|
|
1
|
+
import type { VirtualFS, VirtualFSWritable, FileStat } from "../types.ts";
|
|
2
2
|
export type Permission = "read-write" | "read-only" | "excluded";
|
|
3
3
|
export type PermissionRules = Record<string, Permission>;
|
|
4
4
|
export interface PathOps {
|
|
@@ -21,6 +21,7 @@ export interface UnderlyingFS {
|
|
|
21
21
|
isDirectory(): boolean;
|
|
22
22
|
size: number;
|
|
23
23
|
mtime: Date;
|
|
24
|
+
mtimeMs?: number;
|
|
24
25
|
}>;
|
|
25
26
|
writeFile(path: string, data: Buffer | string): Promise<void>;
|
|
26
27
|
appendFile(path: string, data: Buffer | string): Promise<void>;
|
|
@@ -32,6 +33,12 @@ export interface UnderlyingFS {
|
|
|
32
33
|
force?: boolean;
|
|
33
34
|
}): Promise<void>;
|
|
34
35
|
};
|
|
36
|
+
streams?: {
|
|
37
|
+
createReadStream?(path: string): AsyncIterable<Uint8Array>;
|
|
38
|
+
createWriteStream?(path: string, opts?: {
|
|
39
|
+
append?: boolean;
|
|
40
|
+
}): Promise<VirtualFSWritable> | VirtualFSWritable;
|
|
41
|
+
};
|
|
35
42
|
}
|
|
36
43
|
export declare class FileSystem implements VirtualFS {
|
|
37
44
|
private readonly mountBase;
|
|
@@ -47,11 +54,15 @@ export declare class FileSystem implements VirtualFS {
|
|
|
47
54
|
private resolveSafePath;
|
|
48
55
|
readFile(filePath: string): Promise<Buffer>;
|
|
49
56
|
readFile(filePath: string, encoding: BufferEncoding): Promise<string>;
|
|
57
|
+
readStream(filePath: string): AsyncIterable<Uint8Array>;
|
|
50
58
|
readdir(dirPath: string): Promise<string[]>;
|
|
51
59
|
stat(filePath: string): Promise<FileStat>;
|
|
52
60
|
exists(filePath: string): Promise<boolean>;
|
|
53
61
|
writeFile(filePath: string, data: Buffer | string): Promise<void>;
|
|
54
62
|
appendFile(filePath: string, data: Buffer | string): Promise<void>;
|
|
63
|
+
writeStream(filePath: string, opts?: {
|
|
64
|
+
append?: boolean;
|
|
65
|
+
}): Promise<VirtualFSWritable>;
|
|
55
66
|
mkdir(dirPath: string, opts?: {
|
|
56
67
|
recursive?: boolean;
|
|
57
68
|
}): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ShellDSL, createShellDSL, type Program } from "./shell-dsl.ts";
|
|
2
2
|
export { ShellPromise, type ShellPromiseOptions } from "./shell-promise.ts";
|
|
3
|
-
export type { VirtualFS, FileStat, Command, CommandContext, Stdin, Stdout, Stderr, OutputCollector, ExecResult, ShellConfig, RawValue, } from "./types.ts";
|
|
3
|
+
export type { VirtualFS, VirtualFSWritable, FileStat, Command, CommandContext, Stdin, Stdout, Stderr, OutputCollector, ExecResult, ShellConfig, RawValue, } from "./types.ts";
|
|
4
4
|
export { isRawValue } from "./types.ts";
|
|
5
5
|
export { ShellError, LexError, ParseError } from "./errors.ts";
|
|
6
6
|
export { Lexer, lex, tokenToString } from "./lexer/index.ts";
|
|
@@ -16,4 +16,4 @@ export { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer
|
|
|
16
16
|
export { escape, escapeForInterpolation, globVirtualFS } from "./utils/index.ts";
|
|
17
17
|
export type { GlobVirtualFS, GlobOptions } from "./utils/index.ts";
|
|
18
18
|
export { VersionControlSystem } from "./vcs/index.ts";
|
|
19
|
-
export type { VCSConfig, VCSAttributeRule, VCSResolvedAttributes, VCSDiffMode, Revision, DiffEntry, TreeManifest, TreeEntry, FileEntry, DirectoryEntry, CommitOptions, CheckoutOptions, LogOptions, LogEntry, BranchInfo, } from "./vcs/index.ts";
|
|
19
|
+
export type { VCSConfig, VCSAttributeRule, VCSResolvedAttributes, VCSDiffMode, VCSPatchSuppressionReason, Revision, DiffEntry, TreeManifest, TreeEntry, FileEntry, DirectoryEntry, VCSIndexEntry, VCSIndexFile, CommitOptions, CheckoutOptions, LogOptions, LogEntry, BranchInfo, } from "./vcs/index.ts";
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
export interface VirtualFSWritable {
|
|
2
|
+
write(chunk: Uint8Array): Promise<void>;
|
|
3
|
+
close(): Promise<void>;
|
|
4
|
+
abort?(reason?: unknown): Promise<void>;
|
|
5
|
+
}
|
|
1
6
|
export interface VirtualFS {
|
|
2
7
|
readFile(path: string): Promise<Buffer>;
|
|
3
8
|
readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
9
|
+
readStream(path: string): AsyncIterable<Uint8Array>;
|
|
4
10
|
readdir(path: string): Promise<string[]>;
|
|
5
11
|
stat(path: string): Promise<FileStat>;
|
|
6
12
|
exists(path: string): Promise<boolean>;
|
|
7
13
|
writeFile(path: string, data: Buffer | string): Promise<void>;
|
|
8
14
|
appendFile(path: string, data: Buffer | string): Promise<void>;
|
|
15
|
+
writeStream(path: string, opts?: {
|
|
16
|
+
append?: boolean;
|
|
17
|
+
}): Promise<VirtualFSWritable>;
|
|
9
18
|
mkdir(path: string, opts?: {
|
|
10
19
|
recursive?: boolean;
|
|
11
20
|
}): Promise<void>;
|
|
@@ -25,6 +34,7 @@ export interface FileStat {
|
|
|
25
34
|
isDirectory(): boolean;
|
|
26
35
|
size: number;
|
|
27
36
|
mtime: Date;
|
|
37
|
+
mtimeMs: number;
|
|
28
38
|
}
|
|
29
39
|
export type Command = (ctx: CommandContext) => Promise<number>;
|
|
30
40
|
export interface CommandContext {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const BINARY_SAMPLE_BYTES: number;
|
|
2
|
+
export declare const MAX_PATCH_BYTES: number;
|
|
3
|
+
export declare function detectBinaryFromSample(sample: Uint8Array<ArrayBufferLike>): boolean;
|
|
4
|
+
export declare function appendSample(sample: Uint8Array<ArrayBufferLike>, chunk: Uint8Array<ArrayBufferLike>, limit?: number): Uint8Array<ArrayBufferLike>;
|
|
5
|
+
export declare function readStreamSample(source: AsyncIterable<Uint8Array>, limit?: number): Promise<Uint8Array<ArrayBufferLike>>;
|
|
6
|
+
export declare function hashSample(sample: Uint8Array<ArrayBufferLike>): string;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
1
|
+
import type { TreeManifest, DiffEntry, VCSIndexEntry } from "./types.ts";
|
|
2
|
+
import { VCSObjectStore } from "./objects.ts";
|
|
3
3
|
import { VCSRules } from "./rules.ts";
|
|
4
|
+
interface DiffOptions {
|
|
5
|
+
rules?: VCSRules;
|
|
6
|
+
objectStore: VCSObjectStore;
|
|
7
|
+
beforeIndex?: Record<string, VCSIndexEntry>;
|
|
8
|
+
afterIndex?: Record<string, VCSIndexEntry>;
|
|
9
|
+
}
|
|
4
10
|
/**
|
|
5
11
|
* Compute diff entries between two tree manifests.
|
|
6
12
|
*/
|
|
7
|
-
export declare function diffManifests(before: TreeManifest, after: TreeManifest,
|
|
8
|
-
|
|
9
|
-
* Compute diff between a tree manifest and the current working tree.
|
|
10
|
-
*/
|
|
11
|
-
export declare function diffWorkingTree(fs: VirtualFS, rootPath: string, manifest: TreeManifest, rules?: VCSRules): Promise<DiffEntry[]>;
|
|
13
|
+
export declare function diffManifests(before: TreeManifest, after: TreeManifest, options: DiffOptions): Promise<DiffEntry[]>;
|
|
14
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { VersionControlSystem } from "./vcs.ts";
|
|
2
|
-
export type { VCSConfig, VCSAttributeRule, VCSResolvedAttributes, VCSDiffMode, Revision, DiffEntry, TreeManifest, TreeEntry, FileEntry, DirectoryEntry, CommitOptions, CheckoutOptions, LogOptions, LogEntry, BranchInfo, } from "./types.ts";
|
|
2
|
+
export type { VCSConfig, VCSAttributeRule, VCSResolvedAttributes, VCSDiffMode, VCSPatchSuppressionReason, Revision, DiffEntry, TreeManifest, TreeEntry, FileEntry, DirectoryEntry, VCSIndexEntry, VCSIndexFile, CommitOptions, CheckoutOptions, LogOptions, LogEntry, BranchInfo, } from "./types.ts";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { VirtualFS } from "../types.ts";
|
|
2
|
+
export interface StoredBlob {
|
|
3
|
+
blobId: string;
|
|
4
|
+
size: number;
|
|
5
|
+
binary: boolean;
|
|
6
|
+
sampleHash: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class VCSObjectStore {
|
|
9
|
+
private readonly fs;
|
|
10
|
+
private readonly basePath;
|
|
11
|
+
constructor(fs: VirtualFS, basePath: string);
|
|
12
|
+
initialize(): Promise<void>;
|
|
13
|
+
hasBlob(blobId: string): Promise<boolean>;
|
|
14
|
+
store(source: AsyncIterable<Uint8Array>): Promise<StoredBlob>;
|
|
15
|
+
readBlob(blobId: string): Promise<Buffer>;
|
|
16
|
+
readBlobText(blobId: string): Promise<string>;
|
|
17
|
+
readBlobStream(blobId: string): AsyncIterable<Uint8Array>;
|
|
18
|
+
isBinaryBlob(blobId: string): Promise<boolean>;
|
|
19
|
+
deleteTempFiles(): Promise<void>;
|
|
20
|
+
private blobPath;
|
|
21
|
+
private path;
|
|
22
|
+
}
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
import type { VirtualFS } from "../types.ts";
|
|
2
|
-
import type { TreeManifest } from "./types.ts";
|
|
2
|
+
import type { TreeManifest, VCSIndexEntry } from "./types.ts";
|
|
3
3
|
import { VCSRules } from "./rules.ts";
|
|
4
|
+
import { VCSObjectStore } from "./objects.ts";
|
|
5
|
+
export interface BuildTreeManifestResult {
|
|
6
|
+
manifest: TreeManifest;
|
|
7
|
+
indexEntries: Record<string, VCSIndexEntry>;
|
|
8
|
+
}
|
|
4
9
|
/**
|
|
5
10
|
* Build a TreeManifest from the current working tree.
|
|
6
11
|
*/
|
|
7
|
-
export declare function buildTreeManifest(fs: VirtualFS, rootPath: string, options
|
|
12
|
+
export declare function buildTreeManifest(fs: VirtualFS, rootPath: string, options: {
|
|
13
|
+
objectStore: VCSObjectStore;
|
|
8
14
|
rules?: VCSRules;
|
|
9
15
|
trackedPaths?: Iterable<string>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Build a TreeManifest for only the specified relative paths.
|
|
13
|
-
*/
|
|
14
|
-
export declare function buildPartialManifest(fs: VirtualFS, rootPath: string, paths: string[]): Promise<TreeManifest>;
|
|
16
|
+
indexEntries?: Record<string, VCSIndexEntry>;
|
|
17
|
+
}): Promise<BuildTreeManifestResult>;
|
|
15
18
|
/**
|
|
16
19
|
* Restore a working tree from a TreeManifest.
|
|
17
20
|
*
|
|
18
21
|
* If `fullRestore` is true, deletes working tree files not in the manifest.
|
|
19
22
|
* If `paths` is provided, only restores matching files.
|
|
20
23
|
*/
|
|
21
|
-
export declare function restoreTree(fs: VirtualFS, rootPath: string, manifest: TreeManifest, options?: {
|
|
24
|
+
export declare function restoreTree(fs: VirtualFS, rootPath: string, manifest: TreeManifest, objectStore: VCSObjectStore, options?: {
|
|
22
25
|
fullRestore?: boolean;
|
|
23
26
|
paths?: string[];
|
|
24
27
|
rules?: VCSRules;
|
|
25
28
|
trackedPaths?: Iterable<string>;
|
|
26
29
|
}): Promise<void>;
|
|
30
|
+
export declare function rebuildIndexForManifest(fs: VirtualFS, rootPath: string, manifest: TreeManifest, objectStore: VCSObjectStore): Promise<Record<string, VCSIndexEntry>>;
|
|
31
|
+
export declare function updateIndexForScopedPaths(fs: VirtualFS, rootPath: string, manifest: TreeManifest, objectStore: VCSObjectStore, existingIndex: Record<string, VCSIndexEntry>, patterns: string[]): Promise<Record<string, VCSIndexEntry>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VirtualFS } from "../types.ts";
|
|
2
|
-
import type { HeadRef, BranchRef, VCSConfigFile, Revision } from "./types.ts";
|
|
2
|
+
import type { HeadRef, BranchRef, VCSConfigFile, VCSIndexEntry, Revision } from "./types.ts";
|
|
3
3
|
export declare class VCSStorage {
|
|
4
4
|
private readonly fs;
|
|
5
5
|
private readonly basePath;
|
|
@@ -17,6 +17,12 @@ export declare class VCSStorage {
|
|
|
17
17
|
writeRevision(rev: Revision): Promise<void>;
|
|
18
18
|
nextRevisionId(): Promise<number>;
|
|
19
19
|
readConfig(): Promise<VCSConfigFile>;
|
|
20
|
+
assertSupportedFormat(): Promise<void>;
|
|
21
|
+
readIndex(): Promise<Record<string, VCSIndexEntry>>;
|
|
22
|
+
writeIndex(entries: Record<string, VCSIndexEntry>): Promise<void>;
|
|
23
|
+
resolve(...segments: string[]): string;
|
|
24
|
+
get fileSystem(): VirtualFS;
|
|
20
25
|
private readJSON;
|
|
21
26
|
private writeJSON;
|
|
27
|
+
private assertSupportedVersion;
|
|
22
28
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createUnifiedPatch(path: string, previousText: string, nextText: string): string | undefined;
|