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
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/snapshot.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.cjs\";\nimport type { TreeManifest, FileEntry } from \"./types.cjs\";\nimport {
|
|
5
|
+
"import type { VirtualFS } from \"../types.cjs\";\nimport type { TreeManifest, FileEntry, TreeEntry } from \"./types.cjs\";\nimport { matchVCSPath, VCSRules } from \"./rules.cjs\";\nimport { walkTreeEntries } from \"./walk.cjs\";\n\n/**\n * Build a TreeManifest from the current working tree.\n */\nexport async function buildTreeManifest(\n fs: VirtualFS,\n rootPath: string,\n options?: {\n rules?: VCSRules;\n trackedPaths?: Iterable<string>;\n },\n): Promise<TreeManifest> {\n const manifest: TreeManifest = {};\n const rules = options?.rules ?? new VCSRules({ internalDirName: \".vcs\" });\n const trackedPaths = new Set(options?.trackedPaths ?? []);\n const entries = await walkTreeEntries(fs, rootPath, {\n enterDirectory: (relPath) => rules.shouldEnterDirectory(relPath, trackedPaths),\n includeFile: (relPath) => rules.shouldIncludeWorkingFile(relPath, trackedPaths),\n includeDirectory: (relPath, info) =>\n info.empty && rules.shouldIncludeEmptyDirectory(relPath, trackedPaths),\n });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n manifest[entry.path] = { kind: \"directory\", size: 0 };\n continue;\n }\n\n const fullPath = fs.resolve(rootPath, entry.path);\n const content = await fs.readFile(fullPath);\n const buf = Buffer.from(content);\n manifest[entry.path] = {\n kind: \"file\",\n content: buf.toString(\"base64\"),\n size: buf.length,\n };\n }\n\n return manifest;\n}\n\n/**\n * Build a TreeManifest for only the specified relative paths.\n */\nexport async function buildPartialManifest(\n fs: VirtualFS,\n rootPath: string,\n paths: string[],\n): Promise<TreeManifest> {\n const manifest: TreeManifest = {};\n\n for (const relPath of paths) {\n const fullPath = fs.resolve(rootPath, relPath);\n if (!(await fs.exists(fullPath))) continue;\n const stat = await fs.stat(fullPath);\n if (stat.isDirectory()) {\n const entries = await fs.readdir(fullPath);\n if (entries.length === 0) {\n manifest[relPath] = { kind: \"directory\", size: 0 };\n }\n continue;\n }\n if (!stat.isFile()) continue;\n\n const content = await fs.readFile(fullPath);\n const buf = Buffer.from(content);\n manifest[relPath] = {\n kind: \"file\",\n content: buf.toString(\"base64\"),\n size: buf.length,\n };\n }\n\n return manifest;\n}\n\n/**\n * Restore a working tree from a TreeManifest.\n *\n * If `fullRestore` is true, deletes working tree files not in the manifest.\n * If `paths` is provided, only restores matching files.\n */\nexport async function restoreTree(\n fs: VirtualFS,\n rootPath: string,\n manifest: TreeManifest,\n options?: {\n fullRestore?: boolean;\n paths?: string[];\n rules?: VCSRules;\n trackedPaths?: Iterable<string>;\n },\n): Promise<void> {\n const fullRestore = options?.fullRestore ?? false;\n const rules = options?.rules ?? new VCSRules({ internalDirName: \".vcs\" });\n const trackedPaths = new Set(options?.trackedPaths ?? []);\n const scopePatterns = options?.paths ?? null;\n const scopedEntries = Object.entries(manifest)\n .filter(([relPath]) => isPathInScope(relPath, scopePatterns))\n .sort(([a], [b]) => a.localeCompare(b));\n const targetPaths = new Set(scopedEntries.map(([relPath]) => relPath));\n const requiredDirectories = collectRequiredDirectories(scopedEntries);\n const shouldDeleteExtras = fullRestore || scopePatterns !== null;\n\n if (shouldDeleteExtras) {\n const currentEntries = await walkTreeEntries(fs, rootPath, {\n enterDirectory: (relPath) => !rules.isInternalPath(relPath),\n includeFile: (relPath) => rules.shouldIncludeRestoreScanFile(relPath),\n includeDirectory: () => true,\n });\n\n for (const current of currentEntries) {\n if (current.kind !== \"file\") continue;\n if (!isPathInScope(current.path, scopePatterns)) continue;\n if (targetPaths.has(current.path)) continue;\n if (rules.shouldPreserveUntrackedIgnored(current.path, trackedPaths)) continue;\n await fs.rm(fs.resolve(rootPath, current.path));\n }\n }\n\n for (const directory of [...requiredDirectories].sort(comparePathDepth)) {\n await ensureDirectoryExists(fs, fs.resolve(rootPath, directory));\n }\n\n for (const [relPath, entry] of scopedEntries) {\n if (isDirectoryEntry(entry)) {\n await ensureDirectoryExists(fs, fs.resolve(rootPath, relPath));\n continue;\n }\n await writeFileFromEntry(fs, rootPath, relPath, entry);\n }\n\n if (shouldDeleteExtras) {\n const currentEntries = await walkTreeEntries(fs, rootPath, {\n enterDirectory: (relPath) => !rules.isInternalPath(relPath),\n includeFile: () => true,\n includeDirectory: () => true,\n });\n\n const directories = currentEntries\n .filter((entry) => entry.kind === \"directory\")\n .map((entry) => entry.path)\n .filter((relPath) => isPathInScope(relPath, scopePatterns))\n .sort((a, b) => comparePathDepth(b, a));\n\n for (const relPath of directories) {\n if (requiredDirectories.has(relPath)) continue;\n if (rules.shouldPreserveUntrackedIgnored(relPath, trackedPaths)) continue;\n const fullPath = fs.resolve(rootPath, relPath);\n if (await isEmptyDirectory(fs, fullPath)) {\n await fs.rm(fullPath);\n }\n }\n }\n}\n\nasync function writeFileFromEntry(\n fs: VirtualFS,\n rootPath: string,\n relPath: string,\n entry: FileEntry,\n): Promise<void> {\n const fullPath = fs.resolve(rootPath, relPath);\n await ensureDirectoryExists(fs, fs.dirname(fullPath));\n await removeDirectoryAtPath(fs, fullPath);\n\n const buf = Buffer.from(entry.content, \"base64\");\n await fs.writeFile(fullPath, buf);\n}\n\nfunction isDirectoryEntry(entry: TreeEntry): entry is Extract<TreeEntry, { kind: \"directory\" }> {\n return entry.kind === \"directory\";\n}\n\nfunction isPathInScope(relPath: string, patterns: string[] | null): boolean {\n if (!patterns || patterns.length === 0) return true;\n return patterns.some((pattern) => matchVCSPath(pattern, relPath));\n}\n\nfunction collectRequiredDirectories(entries: Array<[string, TreeEntry]>): Set<string> {\n const directories = new Set<string>();\n\n for (const [relPath, entry] of entries) {\n if (isDirectoryEntry(entry)) {\n directories.add(relPath);\n }\n for (const parent of parentDirectories(relPath)) {\n directories.add(parent);\n }\n }\n\n return directories;\n}\n\nfunction parentDirectories(relPath: string): string[] {\n const parts = relPath.split(\"/\").filter(Boolean);\n const parents: string[] = [];\n\n for (let i = 1; i < parts.length; i++) {\n parents.push(parts.slice(0, i).join(\"/\"));\n }\n\n return parents;\n}\n\nfunction comparePathDepth(a: string, b: string): number {\n const depthA = a.split(\"/\").filter(Boolean).length;\n const depthB = b.split(\"/\").filter(Boolean).length;\n if (depthA !== depthB) return depthA - depthB;\n return a.localeCompare(b);\n}\n\nasync function ensureDirectoryExists(fs: VirtualFS, dirPath: string): Promise<void> {\n const parent = fs.dirname(dirPath);\n if (parent !== dirPath) {\n await ensureDirectoryExists(fs, parent);\n }\n\n if (await fs.exists(dirPath)) {\n const stat = await fs.stat(dirPath);\n if (stat.isDirectory()) return;\n await fs.rm(dirPath, { recursive: true, force: true });\n }\n\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nasync function removeDirectoryAtPath(fs: VirtualFS, path: string): Promise<void> {\n if (!(await fs.exists(path))) return;\n const stat = await fs.stat(path);\n if (stat.isDirectory()) {\n await fs.rm(path, { recursive: true, force: true });\n }\n}\n\nasync function isEmptyDirectory(fs: VirtualFS, dirPath: string): Promise<boolean> {\n try {\n const entries = await fs.readdir(dirPath);\n return entries.length === 0;\n } catch {\n return false;\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "7E15F1F035E56CC164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/cjs/src/vcs/vcs.cjs
CHANGED
|
@@ -44,31 +44,27 @@ __export(exports_vcs, {
|
|
|
44
44
|
module.exports = __toCommonJS(exports_vcs);
|
|
45
45
|
var import_storage = require("./storage.cjs");
|
|
46
46
|
var import_diff = require("./diff.cjs");
|
|
47
|
+
var import_rules = require("./rules.cjs");
|
|
47
48
|
var import_snapshot = require("./snapshot.cjs");
|
|
48
|
-
var import_match = require("./match.cjs");
|
|
49
49
|
|
|
50
50
|
class VersionControlSystem {
|
|
51
51
|
workFs;
|
|
52
52
|
workPath;
|
|
53
53
|
storage;
|
|
54
|
-
|
|
54
|
+
vcsInternalPath;
|
|
55
|
+
rules;
|
|
55
56
|
constructor(config) {
|
|
56
57
|
this.workFs = config.fs;
|
|
57
58
|
this.workPath = config.fs.resolve(config.path);
|
|
58
59
|
const metaFs = config.vcsPath?.fs ?? config.fs;
|
|
59
60
|
const metaPath = config.vcsPath?.path ?? metaFs.resolve(config.path, ".vcs");
|
|
60
61
|
this.storage = new import_storage.VCSStorage(metaFs, metaPath);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
this.vcsDirName = "";
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
get excludeDirs() {
|
|
71
|
-
return this.vcsDirName ? [this.vcsDirName] : [];
|
|
62
|
+
this.vcsInternalPath = resolveInternalPath(config.fs, metaFs, this.workPath, metaPath);
|
|
63
|
+
this.rules = new import_rules.VCSRules({
|
|
64
|
+
internalPath: this.vcsInternalPath,
|
|
65
|
+
ignore: config.ignore,
|
|
66
|
+
attributes: config.attributes
|
|
67
|
+
});
|
|
72
68
|
}
|
|
73
69
|
async init() {
|
|
74
70
|
if (await this.storage.isInitialized())
|
|
@@ -106,7 +102,10 @@ class VersionControlSystem {
|
|
|
106
102
|
let newTree;
|
|
107
103
|
let changes;
|
|
108
104
|
if (opts?.paths && opts.paths.length > 0) {
|
|
109
|
-
const fullManifest = await import_snapshot.buildTreeManifest(this.workFs, this.workPath,
|
|
105
|
+
const fullManifest = await import_snapshot.buildTreeManifest(this.workFs, this.workPath, {
|
|
106
|
+
rules: this.rules,
|
|
107
|
+
trackedPaths: Object.keys(parentManifest)
|
|
108
|
+
});
|
|
110
109
|
const matchedPaths = filterPathsByGlobs(Object.keys(fullManifest), opts.paths);
|
|
111
110
|
newTree = { ...parentManifest };
|
|
112
111
|
const parentMatchedPaths = filterPathsByGlobs(Object.keys(parentManifest), opts.paths);
|
|
@@ -127,10 +126,13 @@ class VersionControlSystem {
|
|
|
127
126
|
if (newTree[p])
|
|
128
127
|
relevantAfter[p] = newTree[p];
|
|
129
128
|
}
|
|
130
|
-
changes = import_diff.diffManifests(relevantBefore, relevantAfter);
|
|
129
|
+
changes = import_diff.diffManifests(relevantBefore, relevantAfter, this.rules);
|
|
131
130
|
} else {
|
|
132
|
-
newTree = await import_snapshot.buildTreeManifest(this.workFs, this.workPath,
|
|
133
|
-
|
|
131
|
+
newTree = await import_snapshot.buildTreeManifest(this.workFs, this.workPath, {
|
|
132
|
+
rules: this.rules,
|
|
133
|
+
trackedPaths: Object.keys(parentManifest)
|
|
134
|
+
});
|
|
135
|
+
changes = import_diff.diffManifests(parentManifest, newTree, this.rules);
|
|
134
136
|
}
|
|
135
137
|
if (changes.length === 0) {
|
|
136
138
|
throw new Error("nothing to commit");
|
|
@@ -175,15 +177,13 @@ class VersionControlSystem {
|
|
|
175
177
|
} catch {
|
|
176
178
|
throw new Error(`revision ${targetRevision} not found`);
|
|
177
179
|
}
|
|
180
|
+
const currentManifest = await this.headManifest();
|
|
178
181
|
if (isPartial) {
|
|
179
|
-
|
|
180
|
-
const filteredManifest = {};
|
|
181
|
-
for (const p of matchedPaths) {
|
|
182
|
-
filteredManifest[p] = rev.tree[p];
|
|
183
|
-
}
|
|
184
|
-
await import_snapshot.restoreTree(this.workFs, this.workPath, filteredManifest, {
|
|
182
|
+
await import_snapshot.restoreTree(this.workFs, this.workPath, rev.tree, {
|
|
185
183
|
fullRestore: false,
|
|
186
|
-
paths:
|
|
184
|
+
paths: opts.paths,
|
|
185
|
+
rules: this.rules,
|
|
186
|
+
trackedPaths: Object.keys(currentManifest)
|
|
187
187
|
});
|
|
188
188
|
} else {
|
|
189
189
|
if (!opts?.force) {
|
|
@@ -192,7 +192,11 @@ class VersionControlSystem {
|
|
|
192
192
|
throw new Error("working tree has uncommitted changes (use force to discard)");
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
-
await import_snapshot.restoreTree(this.workFs, this.workPath, rev.tree, {
|
|
195
|
+
await import_snapshot.restoreTree(this.workFs, this.workPath, rev.tree, {
|
|
196
|
+
fullRestore: true,
|
|
197
|
+
rules: this.rules,
|
|
198
|
+
trackedPaths: Object.keys(currentManifest)
|
|
199
|
+
});
|
|
196
200
|
if (targetBranch) {
|
|
197
201
|
await this.storage.writeHead({ ref: `refs/heads/${targetBranch}` });
|
|
198
202
|
} else {
|
|
@@ -256,7 +260,7 @@ class VersionControlSystem {
|
|
|
256
260
|
}
|
|
257
261
|
const changedPaths = rev.changes.map((c) => c.path);
|
|
258
262
|
if (opts?.path) {
|
|
259
|
-
const matchesPath = changedPaths.some((p) =>
|
|
263
|
+
const matchesPath = changedPaths.some((p) => import_rules.matchVCSPath(opts.path, p));
|
|
260
264
|
if (matchesPath) {
|
|
261
265
|
entries.push({
|
|
262
266
|
id: rev.id,
|
|
@@ -284,13 +288,13 @@ class VersionControlSystem {
|
|
|
284
288
|
async status() {
|
|
285
289
|
await this.ensureInit();
|
|
286
290
|
const manifest = await this.headManifest();
|
|
287
|
-
return import_diff.diffWorkingTree(this.workFs, this.workPath, manifest, this.
|
|
291
|
+
return import_diff.diffWorkingTree(this.workFs, this.workPath, manifest, this.rules);
|
|
288
292
|
}
|
|
289
293
|
async diff(revA, revB) {
|
|
290
294
|
await this.ensureInit();
|
|
291
295
|
const a = await this.storage.readRevision(revA);
|
|
292
296
|
const b = await this.storage.readRevision(revB);
|
|
293
|
-
return import_diff.diffManifests(a.tree, b.tree);
|
|
297
|
+
return import_diff.diffManifests(a.tree, b.tree, this.rules);
|
|
294
298
|
}
|
|
295
299
|
async head() {
|
|
296
300
|
await this.ensureInit();
|
|
@@ -298,8 +302,21 @@ class VersionControlSystem {
|
|
|
298
302
|
}
|
|
299
303
|
}
|
|
300
304
|
function filterPathsByGlobs(paths, patterns) {
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
return paths.filter((filePath) => patterns.some((pattern) => import_rules.matchVCSPath(pattern, filePath)));
|
|
306
|
+
}
|
|
307
|
+
function resolveInternalPath(workFs, metaFs, workPath, metaPath) {
|
|
308
|
+
if (workFs !== metaFs)
|
|
309
|
+
return "";
|
|
310
|
+
const normalizedWork = normalizeFsPath(workPath);
|
|
311
|
+
const normalizedMeta = normalizeFsPath(metaFs.resolve(metaPath));
|
|
312
|
+
if (normalizedMeta === normalizedWork)
|
|
313
|
+
return "";
|
|
314
|
+
if (!normalizedMeta.startsWith(`${normalizedWork}/`))
|
|
315
|
+
return "";
|
|
316
|
+
return normalizedMeta.slice(normalizedWork.length + 1);
|
|
317
|
+
}
|
|
318
|
+
function normalizeFsPath(path) {
|
|
319
|
+
return path.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
303
320
|
}
|
|
304
321
|
|
|
305
|
-
//# debugId=
|
|
322
|
+
//# debugId=B3A44192C38E782A64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/vcs.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.cjs\";\nimport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\nimport { VCSStorage } from \"./storage.cjs\";\nimport { diffManifests, diffWorkingTree } from \"./diff.cjs\";\nimport { buildTreeManifest, restoreTree } from \"./snapshot.cjs\";\nimport { matchGlobPath } from \"./match.cjs\";\n\nexport class VersionControlSystem {\n private readonly workFs: VirtualFS;\n private readonly workPath: string;\n private readonly storage: VCSStorage;\n private readonly vcsDirName: string;\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 // Determine the vcs directory name relative to workPath for exclusion\n const resolvedMeta = metaFs.resolve(metaPath);\n const resolvedWork = this.workPath;\n if (resolvedMeta.startsWith(resolvedWork + \"/\") || resolvedMeta.startsWith(resolvedWork + \"\\\\\")) {\n const rel = resolvedMeta.slice(resolvedWork.length + 1);\n this.vcsDirName = rel.split(\"/\")[0] ?? \".vcs\";\n } else {\n // VCS dir is outside the work tree, no exclusion needed\n this.vcsDirName = \"\";\n }\n }\n\n private get excludeDirs(): string[] {\n return this.vcsDirName ? [this.vcsDirName] : [];\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, this.excludeDirs);\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);\n } else {\n // Full commit\n newTree = await buildTreeManifest(this.workFs, this.workPath, this.excludeDirs);\n changes = diffManifests(parentManifest, newTree);\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 if (isPartial) {\n // Partial checkout: restore specific files, don't update HEAD\n const matchedPaths = filterPathsByGlobs(Object.keys(rev.tree), opts!.paths!);\n const filteredManifest: TreeManifest = {};\n for (const p of matchedPaths) {\n filteredManifest[p] = rev.tree[p]!;\n }\n await restoreTree(this.workFs, this.workPath, filteredManifest, {\n fullRestore: false,\n paths: matchedPaths,\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, { fullRestore: true });\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) => matchGlobPath(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.excludeDirs);\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 }\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 const normalizedPatterns = patterns.map((p) => (p.startsWith(\"/\") ? p.slice(1) : p));\n return paths.filter((filePath) =>\n normalizedPatterns.some((pattern) => matchGlobPath(pattern, filePath)),\n );\n}\n"
|
|
5
|
+
"import type { VirtualFS } from \"../types.cjs\";\nimport type {\n VCSConfig,\n Revision,\n DiffEntry,\n TreeManifest,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./types.cjs\";\nimport { VCSStorage } from \"./storage.cjs\";\nimport { diffManifests, diffWorkingTree } from \"./diff.cjs\";\nimport { matchVCSPath, VCSRules } from \"./rules.cjs\";\nimport { buildTreeManifest, restoreTree } from \"./snapshot.cjs\";\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"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAY2B,IAA3B;AAC+C,IAA/C;AAC+C,IAA/C;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "B3A44192C38E782A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -39,24 +39,27 @@ var __export = (target, all) => {
|
|
|
39
39
|
// src/vcs/walk.ts
|
|
40
40
|
var exports_walk = {};
|
|
41
41
|
__export(exports_walk, {
|
|
42
|
+
walkTreeEntries: () => walkTreeEntries,
|
|
42
43
|
walkTree: () => walkTree
|
|
43
44
|
});
|
|
44
45
|
module.exports = __toCommonJS(exports_walk);
|
|
45
|
-
async function walkTree(fs, root,
|
|
46
|
+
async function walkTree(fs, root, options = {}) {
|
|
47
|
+
const results = await walkTreeEntries(fs, root, options);
|
|
48
|
+
return results.filter((entry) => entry.kind === "file").map((entry) => entry.path);
|
|
49
|
+
}
|
|
50
|
+
async function walkTreeEntries(fs, root, options = {}) {
|
|
46
51
|
const results = [];
|
|
47
|
-
await walkDir(fs, root,
|
|
48
|
-
return results.sort();
|
|
52
|
+
await walkDir(fs, root, "", options, results);
|
|
53
|
+
return results.sort((a, b) => a.path.localeCompare(b.path));
|
|
49
54
|
}
|
|
50
|
-
async function walkDir(fs,
|
|
55
|
+
async function walkDir(fs, dir, relativeDir, options, results) {
|
|
51
56
|
let entries;
|
|
52
57
|
try {
|
|
53
58
|
entries = await fs.readdir(dir);
|
|
54
59
|
} catch {
|
|
55
|
-
return;
|
|
60
|
+
return false;
|
|
56
61
|
}
|
|
57
62
|
for (const entry of entries) {
|
|
58
|
-
if (exclude.includes(entry))
|
|
59
|
-
continue;
|
|
60
63
|
const fullPath = fs.resolve(dir, entry);
|
|
61
64
|
let stat;
|
|
62
65
|
try {
|
|
@@ -64,20 +67,23 @@ async function walkDir(fs, base, dir, exclude, results) {
|
|
|
64
67
|
} catch {
|
|
65
68
|
continue;
|
|
66
69
|
}
|
|
70
|
+
const relative = relativeDir ? `${relativeDir}/${entry}` : entry;
|
|
67
71
|
if (stat.isDirectory()) {
|
|
68
|
-
|
|
72
|
+
if (options.enterDirectory && !await options.enterDirectory(relative)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const empty = await walkDir(fs, fullPath, relative, options, results);
|
|
76
|
+
if (options.includeDirectory && await options.includeDirectory(relative, { empty })) {
|
|
77
|
+
results.push({ path: relative, kind: "directory" });
|
|
78
|
+
}
|
|
69
79
|
} else if (stat.isFile()) {
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
if (options.includeFile && !await options.includeFile(relative)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
results.push({ path: relative, kind: "file" });
|
|
72
84
|
}
|
|
73
85
|
}
|
|
74
|
-
|
|
75
|
-
function relativePath(base, full) {
|
|
76
|
-
const normalizedBase = base.endsWith("/") ? base : base + "/";
|
|
77
|
-
if (full.startsWith(normalizedBase)) {
|
|
78
|
-
return full.slice(normalizedBase.length);
|
|
79
|
-
}
|
|
80
|
-
return full;
|
|
86
|
+
return entries.length === 0;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
//# debugId=
|
|
89
|
+
//# debugId=25C7BCDB4757CEFB64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/walk.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.cjs\";\n\n/**\n * Recursively walk a directory tree and return all file paths\n * relative to the given root
|
|
5
|
+
"import type { VirtualFS } from \"../types.cjs\";\n\ninterface WalkTreeOptions {\n enterDirectory?: (relPath: string) => boolean | Promise<boolean>;\n includeFile?: (relPath: string) => boolean | Promise<boolean>;\n includeDirectory?: (\n relPath: string,\n info: { empty: boolean },\n ) => boolean | Promise<boolean>;\n}\n\nexport interface WalkTreeEntry {\n path: string;\n kind: \"file\" | \"directory\";\n}\n\n/**\n * Recursively walk a directory tree and return all file paths\n * relative to the given root.\n */\nexport async function walkTree(\n fs: VirtualFS,\n root: string,\n options: WalkTreeOptions = {},\n): Promise<string[]> {\n const results = await walkTreeEntries(fs, root, options);\n return results\n .filter((entry) => entry.kind === \"file\")\n .map((entry) => entry.path);\n}\n\nexport async function walkTreeEntries(\n fs: VirtualFS,\n root: string,\n options: WalkTreeOptions = {},\n): Promise<WalkTreeEntry[]> {\n const results: WalkTreeEntry[] = [];\n await walkDir(fs, root, \"\", options, results);\n return results.sort((a, b) => a.path.localeCompare(b.path));\n}\n\nasync function walkDir(\n fs: VirtualFS,\n dir: string,\n relativeDir: string,\n options: WalkTreeOptions,\n results: WalkTreeEntry[],\n): Promise<boolean> {\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch {\n return false;\n }\n\n for (const entry of entries) {\n const fullPath = fs.resolve(dir, entry);\n let stat;\n try {\n stat = await fs.stat(fullPath);\n } catch {\n continue;\n }\n\n const relative = relativeDir ? `${relativeDir}/${entry}` : entry;\n\n if (stat.isDirectory()) {\n if (options.enterDirectory && !(await options.enterDirectory(relative))) {\n continue;\n }\n const empty = await walkDir(fs, fullPath, relative, options, results);\n if (options.includeDirectory && (await options.includeDirectory(relative, { empty }))) {\n results.push({ path: relative, kind: \"directory\" });\n }\n } else if (stat.isFile()) {\n if (options.includeFile && !(await options.includeFile(relative))) {\n continue;\n }\n results.push({ path: relative, kind: \"file\" });\n }\n }\n\n return entries.length === 0;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,eAAsB,QAAQ,CAC5B,IACA,MACA,UAA2B,CAAC,GACT;AAAA,EACnB,MAAM,UAAU,MAAM,gBAAgB,IAAI,MAAM,OAAO;AAAA,EACvD,OAAO,QACJ,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,EACvC,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA;AAG9B,eAAsB,eAAe,CACnC,IACA,MACA,UAA2B,CAAC,GACF;AAAA,EAC1B,MAAM,UAA2B,CAAC;AAAA,EAClC,MAAM,QAAQ,IAAI,MAAM,IAAI,SAAS,OAAO;AAAA,EAC5C,OAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA;AAG5D,eAAe,OAAO,CACpB,IACA,KACA,aACA,SACA,SACkB;AAAA,EAClB,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,UAAU,MAAM,GAAG,QAAQ,GAAG;AAAA,IAC9B,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAGT,WAAW,SAAS,SAAS;AAAA,IAC3B,MAAM,WAAW,GAAG,QAAQ,KAAK,KAAK;AAAA,IACtC,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,OAAO,MAAM,GAAG,KAAK,QAAQ;AAAA,MAC7B,MAAM;AAAA,MACN;AAAA;AAAA,IAGF,MAAM,WAAW,cAAc,GAAG,eAAe,UAAU;AAAA,IAE3D,IAAI,KAAK,YAAY,GAAG;AAAA,MACtB,IAAI,QAAQ,kBAAkB,CAAE,MAAM,QAAQ,eAAe,QAAQ,GAAI;AAAA,QACvE;AAAA,MACF;AAAA,MACA,MAAM,QAAQ,MAAM,QAAQ,IAAI,UAAU,UAAU,SAAS,OAAO;AAAA,MACpE,IAAI,QAAQ,oBAAqB,MAAM,QAAQ,iBAAiB,UAAU,EAAE,MAAM,CAAC,GAAI;AAAA,QACrF,QAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,YAAY,CAAC;AAAA,MACpD;AAAA,IACF,EAAO,SAAI,KAAK,OAAO,GAAG;AAAA,MACxB,IAAI,QAAQ,eAAe,CAAE,MAAM,QAAQ,YAAY,QAAQ,GAAI;AAAA,QACjE;AAAA,MACF;AAAA,MACA,QAAQ,KAAK,EAAE,MAAM,UAAU,MAAM,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,OAAO,QAAQ,WAAW;AAAA;",
|
|
8
|
+
"debugId": "25C7BCDB4757CEFB64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/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.mjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.mjs\";\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.mjs\";\nexport { isRawValue } from \"./types.mjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.mjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.mjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.mjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.mjs\";\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.mjs\";\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.mjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.mjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.mjs\";\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.mjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.mjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.mjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.mjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.mjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.mjs\";\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.mjs\";\n"
|
|
5
|
+
"// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.mjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.mjs\";\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.mjs\";\nexport { isRawValue } from \"./types.mjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.mjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.mjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.mjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.mjs\";\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.mjs\";\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.mjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.mjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.mjs\";\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.mjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.mjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.mjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.mjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.mjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.mjs\";\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.mjs\";\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": ";AACA;AACA;AAgBA;AAGA;AAGA;AAIA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AAGA;AAIA;",
|
|
8
8
|
"debugId": "A64F16175D95758364756E2164756E21",
|
|
@@ -1,62 +1,67 @@
|
|
|
1
1
|
// src/vcs/diff.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { VCSRules } from "./rules.mjs";
|
|
3
|
+
import { buildTreeManifest } from "./snapshot.mjs";
|
|
4
|
+
function diffManifests(before, after, rules = new VCSRules) {
|
|
4
5
|
const entries = [];
|
|
5
6
|
const allPaths = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
6
7
|
for (const path of allPaths) {
|
|
7
8
|
const prev = before[path];
|
|
8
9
|
const curr = after[path];
|
|
9
10
|
if (!prev && curr) {
|
|
10
|
-
entries.push(
|
|
11
|
+
entries.push(createDiffEntry("add", path, curr, undefined, rules));
|
|
11
12
|
} else if (prev && !curr) {
|
|
12
|
-
entries.push(
|
|
13
|
-
} else if (prev && curr && prev
|
|
14
|
-
entries.push(
|
|
15
|
-
type: "modify",
|
|
16
|
-
path,
|
|
17
|
-
content: curr.content,
|
|
18
|
-
previousContent: prev.content
|
|
19
|
-
});
|
|
13
|
+
entries.push(createDiffEntry("delete", path, undefined, prev, rules));
|
|
14
|
+
} else if (prev && curr && !entriesEqual(prev, curr)) {
|
|
15
|
+
entries.push(createDiffEntry("modify", path, curr, prev, rules));
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
return entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
23
19
|
}
|
|
24
|
-
async function diffWorkingTree(fs, rootPath, manifest,
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
async function diffWorkingTree(fs, rootPath, manifest, rules = new VCSRules({ internalDirName: ".vcs" })) {
|
|
21
|
+
const workingManifest = await buildTreeManifest(fs, rootPath, {
|
|
22
|
+
rules,
|
|
23
|
+
trackedPaths: Object.keys(manifest)
|
|
24
|
+
});
|
|
25
|
+
return diffManifests(manifest, workingManifest, rules);
|
|
26
|
+
}
|
|
27
|
+
function createDiffEntry(type, path, current, previous, rules) {
|
|
28
|
+
const attributes = rules.resolveAttributes(path);
|
|
29
|
+
const entryKind = getEntryKind(current ?? previous);
|
|
30
|
+
const previousEntryKind = previous ? getEntryKind(previous) : undefined;
|
|
31
|
+
const entry = {
|
|
32
|
+
type,
|
|
33
|
+
path,
|
|
34
|
+
binary: attributes.binary,
|
|
35
|
+
diff: attributes.diff,
|
|
36
|
+
entryKind,
|
|
37
|
+
previousEntryKind
|
|
38
|
+
};
|
|
39
|
+
if (attributes.diff !== "none") {
|
|
40
|
+
if (isFileEntry(current)) {
|
|
41
|
+
entry.content = current.content;
|
|
44
42
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!seenPaths.has(manifestPath)) {
|
|
48
|
-
entries.push({
|
|
49
|
-
type: "delete",
|
|
50
|
-
path: manifestPath,
|
|
51
|
-
previousContent: manifest[manifestPath].content
|
|
52
|
-
});
|
|
43
|
+
if (isFileEntry(previous)) {
|
|
44
|
+
entry.previousContent = previous.content;
|
|
53
45
|
}
|
|
54
46
|
}
|
|
55
|
-
return
|
|
47
|
+
return entry;
|
|
48
|
+
}
|
|
49
|
+
function entriesEqual(a, b) {
|
|
50
|
+
if (getEntryKind(a) !== getEntryKind(b))
|
|
51
|
+
return false;
|
|
52
|
+
if (!isFileEntry(a) || !isFileEntry(b))
|
|
53
|
+
return true;
|
|
54
|
+
return a.content === b.content;
|
|
55
|
+
}
|
|
56
|
+
function getEntryKind(entry) {
|
|
57
|
+
return entry?.kind === "directory" ? "directory" : "file";
|
|
58
|
+
}
|
|
59
|
+
function isFileEntry(entry) {
|
|
60
|
+
return !!entry && entry.kind !== "directory";
|
|
56
61
|
}
|
|
57
62
|
export {
|
|
58
63
|
diffWorkingTree,
|
|
59
64
|
diffManifests
|
|
60
65
|
};
|
|
61
66
|
|
|
62
|
-
//# debugId=
|
|
67
|
+
//# debugId=E1AC85757DDF65ED64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/vcs/diff.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { VirtualFS } from \"../types.mjs\";\nimport type { TreeManifest, DiffEntry } from \"./types.mjs\";\nimport {
|
|
5
|
+
"import type { VirtualFS } from \"../types.mjs\";\nimport type { TreeManifest, DiffEntry, TreeEntry } from \"./types.mjs\";\nimport { VCSRules } from \"./rules.mjs\";\nimport { buildTreeManifest } from \"./snapshot.mjs\";\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": ";AAEA;AAKO,SAAS,aAAa,CAC3B,QACA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAEA;AACA;AAKO,SAAS,aAAa,CAC3B,QACA,OACA,QAAkB,IAAI,UACT;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,SAAS,EAAE,iBAAiB,OAAO,CAAC,GACpC;AAAA,EACtB,MAAM,kBAAkB,MAAM,kBAAkB,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": "E1AC85757DDF65ED64756E2164756E21",
|
|
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.mjs\";\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.mjs\";\n"
|
|
5
|
+
"export { VersionControlSystem } from \"./vcs.mjs\";\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.mjs\";\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": ";AAAA;",
|
|
8
8
|
"debugId": "D3267E53BCD7103264756E2164756E21",
|