git-fs-s3 0.3.12 → 0.4.0

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.
@@ -0,0 +1,38 @@
1
+ // src/pack-files.ts
2
+ var PACK_FILE_KINDS = [
3
+ "pack",
4
+ "idx",
5
+ "keep",
6
+ "bitmap",
7
+ "rev"
8
+ ];
9
+ var READABLE_PACK_FILE_KINDS = /* @__PURE__ */ new Set([
10
+ "pack",
11
+ "idx"
12
+ ]);
13
+ var KNOWN_KINDS = new Set(PACK_FILE_KINDS);
14
+ function isPackFileKind(value) {
15
+ return KNOWN_KINDS.has(value);
16
+ }
17
+ function parsePackFileName(name) {
18
+ const dot = name.lastIndexOf(".");
19
+ if (dot <= 0) return null;
20
+ const kind = name.slice(dot + 1);
21
+ if (!isPackFileKind(kind)) return null;
22
+ return { base: name.slice(0, dot), kind, name };
23
+ }
24
+ function packFileName(base, kind) {
25
+ return `${base}.${kind}`;
26
+ }
27
+ function parsePackDirectory(entries) {
28
+ return entries.map(parsePackFileName).filter((file) => file !== null);
29
+ }
30
+
31
+ export {
32
+ PACK_FILE_KINDS,
33
+ READABLE_PACK_FILE_KINDS,
34
+ parsePackFileName,
35
+ packFileName,
36
+ parsePackDirectory
37
+ };
38
+ //# sourceMappingURL=chunk-RMAOPWHJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pack-files.ts"],"sourcesContent":["/**\n * Typed view of a git `objects/pack` directory listing.\n *\n * Every pack is a set of sibling files sharing one base name\n * (`pack-<hash>.pack`, `.idx`, and optionally `.keep`/`.bitmap`/`.rev`).\n * Parsing names once into {@link PackFileName} lets callers group, filter and\n * rename by kind instead of re-matching filename strings at each call site.\n *\n * Edge-compatible: no node: imports.\n */\n\n/** Every file kind git writes into `objects/pack`. */\nexport const PACK_FILE_KINDS = [\n\t\"pack\",\n\t\"idx\",\n\t\"keep\",\n\t\"bitmap\",\n\t\"rev\",\n] as const;\nexport type PackFileKind = (typeof PACK_FILE_KINDS)[number];\n\n/** Kinds isomorphic-git actually reads; the rest are git-CLI accelerators. */\nexport const READABLE_PACK_FILE_KINDS: ReadonlySet<PackFileKind> = new Set([\n\t\"pack\",\n\t\"idx\",\n]);\n\nexport interface PackFileName {\n\t/** Shared base of a pack's sibling files, e.g. `pack-1a2b…`. */\n\treadonly base: string;\n\treadonly kind: PackFileKind;\n\t/** The file name as listed, e.g. `pack-1a2b….idx`. */\n\treadonly name: string;\n}\n\nconst KNOWN_KINDS: ReadonlySet<string> = new Set(PACK_FILE_KINDS);\n\nfunction isPackFileKind(value: string): value is PackFileKind {\n\treturn KNOWN_KINDS.has(value);\n}\n\n/** Parse a pack-directory entry; `null` for anything git didn't put there. */\nexport function parsePackFileName(name: string): PackFileName | null {\n\tconst dot = name.lastIndexOf(\".\");\n\tif (dot <= 0) return null;\n\tconst kind = name.slice(dot + 1);\n\tif (!isPackFileKind(kind)) return null;\n\treturn { base: name.slice(0, dot), kind, name };\n}\n\n/** File name of the `kind` sibling of the pack with this base name. */\nexport function packFileName(base: string, kind: PackFileKind): string {\n\treturn `${base}.${kind}`;\n}\n\n/** Parse a directory listing, dropping entries that aren't pack files. */\nexport function parsePackDirectory(entries: readonly string[]): PackFileName[] {\n\treturn entries\n\t\t.map(parsePackFileName)\n\t\t.filter((file): file is PackFileName => file !== null);\n}\n"],"mappings":";AAYO,IAAM,kBAAkB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAIO,IAAM,2BAAsD,oBAAI,IAAI;AAAA,EAC1E;AAAA,EACA;AACD,CAAC;AAUD,IAAM,cAAmC,IAAI,IAAI,eAAe;AAEhE,SAAS,eAAe,OAAsC;AAC7D,SAAO,YAAY,IAAI,KAAK;AAC7B;AAGO,SAAS,kBAAkB,MAAmC;AACpE,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,OAAO,EAAG,QAAO;AACrB,QAAM,OAAO,KAAK,MAAM,MAAM,CAAC;AAC/B,MAAI,CAAC,eAAe,IAAI,EAAG,QAAO;AAClC,SAAO,EAAE,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,MAAM,KAAK;AAC/C;AAGO,SAAS,aAAa,MAAc,MAA4B;AACtE,SAAO,GAAG,IAAI,IAAI,IAAI;AACvB;AAGO,SAAS,mBAAmB,SAA4C;AAC9E,SAAO,QACL,IAAI,iBAAiB,EACrB,OAAO,CAAC,SAA+B,SAAS,IAAI;AACvD;","names":[]}
@@ -22,8 +22,11 @@ function decodeFileContent(content) {
22
22
  return typeof content === "string" ? content : new TextDecoder().decode(content);
23
23
  }
24
24
  async function listLooseBranches(repo) {
25
+ return listLooseRefNames(repo, "refs/heads");
26
+ }
27
+ async function listLooseRefNames(repo, dir) {
25
28
  if (!hasRecursiveFileLister(repo.fs)) return null;
26
- const names = await repo.fs.listFilesRecursively(`${repo.gitdir}/refs/heads`);
29
+ const names = await repo.fs.listFilesRecursively(`${repo.gitdir}/${dir}`);
27
30
  return names.filter(isSafeBranchName);
28
31
  }
29
32
  async function readPackedBranches(repo) {
@@ -116,10 +119,11 @@ async function assertBranchExists(repo, name) {
116
119
 
117
120
  export {
118
121
  assertSafeBranchName,
122
+ listLooseRefNames,
119
123
  resolveLooseRefFast,
120
124
  listBranches,
121
125
  createBranchFrom,
122
126
  deleteBranchByName,
123
127
  assertBranchExists
124
128
  };
125
- //# sourceMappingURL=chunk-3BDDEGAP.js.map
129
+ //# sourceMappingURL=chunk-Z4656PGE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ops/branch.ts"],"sourcesContent":["import git from \"isomorphic-git\";\nimport { GitInvalidRequestError } from \"../git-errors.js\";\nimport { isSafeBranchName } from \"../refs.js\";\nimport type { Repo } from \"./types.js\";\n\nexport interface Branch {\n\tname: string;\n\tcommit: string;\n\tisDefault: boolean;\n}\n\n/**\n * Defense in depth for every branch-name argument below: `git.deleteBranch`\n * and raw resolveRef/writeRef reads don't validate ref names internally the\n * way `git.branch` does (see refs.ts) — guard at the point the primitives are\n * actually called, not just at an API boundary far above.\n */\nexport function assertSafeBranchName(name: string): void {\n\tif (!isSafeBranchName(name)) {\n\t\tthrow new GitInvalidRequestError(`Invalid branch name: ${name}`);\n\t}\n}\n\nconst FULL_SHA_RE = /^[0-9a-f]{40}$/i;\n\ntype RecursiveFileLister = {\n\tlistFilesRecursively(dirpath: string): Promise<string[]>;\n};\n\nfunction hasRecursiveFileLister(\n\tfs: Repo[\"fs\"],\n): fs is Repo[\"fs\"] & RecursiveFileLister {\n\treturn (\n\t\ttypeof fs === \"object\" &&\n\t\tfs !== null &&\n\t\t\"listFilesRecursively\" in fs &&\n\t\ttypeof (fs as Partial<RecursiveFileLister>).listFilesRecursively ===\n\t\t\t\"function\"\n\t);\n}\n\ntype PromisesFs = {\n\treadFile(path: string, encoding: \"utf8\"): Promise<string | Uint8Array>;\n};\n\n// Repo.fs is typed as isomorphic-git's own fs union (promise- or\n// callback-based) since that's what git.readTree's signature allows, but\n// every fs this package actually constructs (git-fs.ts) is promise-based —\n// this just keeps the callback-style branch honest instead of crashing on\n// it. Shared by every loose-ref fast path below instead of each repeating\n// the same cast + presence check.\nfunction getPromisesFs(fs: Repo[\"fs\"]): PromisesFs | null {\n\tconst promises = (fs as { promises?: PromisesFs }).promises;\n\treturn promises ?? null;\n}\n\nfunction decodeFileContent(content: string | Uint8Array): string {\n\treturn typeof content === \"string\"\n\t\t? content\n\t\t: new TextDecoder().decode(content);\n}\n\n/**\n * Lists loose branch names without isomorphic-git's recursive readdir/stat\n * traversal. Object stores already return only leaf keys in a recursive LIST,\n * so this is one request regardless of branch-name nesting. Ordinary\n * filesystems retain isomorphic-git's implementation and packed refs remain\n * supported there.\n */\nasync function listLooseBranches(repo: Repo): Promise<string[] | null> {\n\treturn listLooseRefNames(repo, \"refs/heads\");\n}\n\n/**\n * Loose ref names under `dir` (e.g. `refs/tags`) in one recursive listing,\n * or `null` when the fs can't list recursively (use isomorphic-git's walk).\n */\nexport async function listLooseRefNames(\n\trepo: Repo,\n\tdir: \"refs/heads\" | \"refs/tags\",\n): Promise<string[] | null> {\n\tif (!hasRecursiveFileLister(repo.fs)) return null;\n\tconst names = await repo.fs.listFilesRecursively(`${repo.gitdir}/${dir}`);\n\treturn names.filter(isSafeBranchName);\n}\n\n/** Read packed branch refs so the object-store fast path preserves Git semantics. */\nasync function readPackedBranches(repo: Repo): Promise<Map<string, string>> {\n\tif (!hasRecursiveFileLister(repo.fs)) return new Map();\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (!promisesFs) return new Map();\n\ttry {\n\t\tconst content = await promisesFs.readFile(\n\t\t\t`${repo.gitdir}/packed-refs`,\n\t\t\t\"utf8\",\n\t\t);\n\t\tconst refs = new Map<string, string>();\n\t\tfor (const line of decodeFileContent(content).split(\"\\n\")) {\n\t\t\tconst match = /^([0-9a-f]{40}) refs\\/heads\\/(.+)$/i.exec(line);\n\t\t\tif (match?.[1] && match[2] && isSafeBranchName(match[2])) {\n\t\t\t\trefs.set(match[2], match[1]);\n\t\t\t}\n\t\t}\n\t\treturn refs;\n\t} catch {\n\t\treturn new Map();\n\t}\n}\n\n/** Read the symbolic HEAD directly when the object-store fs is available. */\nasync function getCurrentLooseBranch(repo: Repo): Promise<string | null> {\n\tif (!hasRecursiveFileLister(repo.fs)) return null;\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (!promisesFs) return null;\n\ttry {\n\t\tconst content = await promisesFs.readFile(`${repo.gitdir}/HEAD`, \"utf8\");\n\t\tconst head = decodeFileContent(content).trim();\n\t\tconst match = /^ref: refs\\/heads\\/(.+)$/.exec(head);\n\t\treturn match?.[1] && isSafeBranchName(match[1]) ? match[1] : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Resolve a fully-qualified ref's oid with one read instead of isomorphic-\n * git's own `resolveRef`, which does a stat *then* a read for a loose ref\n * (two round trips against object storage) — wasteful specifically here,\n * where the caller already knows the ref exists (it came from a directory\n * listing moments earlier). Reads the loose file directly and falls back to\n * `git.resolveRef` only when that doesn't pan out (packed-refs, or anything\n * else the plain-loose-file assumption doesn't cover), so correctness for\n * those cases is unchanged — this only removes the redundant round trip on\n * the common path.\n */\nexport async function resolveLooseRefFast(\n\trepo: Repo,\n\tref: string,\n): Promise<string> {\n\tconst promisesFs = getPromisesFs(repo.fs);\n\tif (promisesFs) {\n\t\ttry {\n\t\t\tconst content = await promisesFs.readFile(\n\t\t\t\t`${repo.gitdir}/${ref}`,\n\t\t\t\t\"utf8\",\n\t\t\t);\n\t\t\tconst oid = decodeFileContent(content).trim();\n\t\t\tif (FULL_SHA_RE.test(oid)) return oid;\n\t\t} catch {\n\t\t\t// Not a loose file (packed-refs, or genuinely absent) — fall through.\n\t\t}\n\t}\n\treturn git.resolveRef({ ...repo, ref });\n}\n\n/** All branches with their tip commits; [] for an empty repository. */\nexport async function listBranches(repo: Repo): Promise<Branch[]> {\n\ttry {\n\t\tconst [looseBranches, looseCurrentBranch, packedBranches] =\n\t\t\tawait Promise.all([\n\t\t\t\tlistLooseBranches(repo),\n\t\t\t\tgetCurrentLooseBranch(repo),\n\t\t\t\treadPackedBranches(repo),\n\t\t\t]);\n\t\tconst branches =\n\t\t\tlooseBranches === null\n\t\t\t\t? await git.listBranches(repo)\n\t\t\t\t: [...new Set([...looseBranches, ...packedBranches.keys()])].sort();\n\t\tconst currentBranch =\n\t\t\tlooseBranches === null\n\t\t\t\t? await git\n\t\t\t\t\t\t.currentBranch({ ...repo, fullname: false })\n\t\t\t\t\t\t.catch(() => null)\n\t\t\t\t: looseCurrentBranch;\n\n\t\treturn Promise.all(\n\t\t\tbranches.map(async (branch) => {\n\t\t\t\tconst packedCommit = packedBranches.get(branch);\n\t\t\t\treturn {\n\t\t\t\t\tname: branch,\n\t\t\t\t\tcommit:\n\t\t\t\t\t\tpackedCommit && !looseBranches?.includes(branch)\n\t\t\t\t\t\t\t? packedCommit\n\t\t\t\t\t\t\t: await resolveLooseRefFast(repo, `refs/heads/${branch}`),\n\t\t\t\t\tisDefault: branch === currentBranch,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\t} catch (err: unknown) {\n\t\tif ((err as { code?: string }).code === \"NotFoundError\") return [];\n\t\tthrow err;\n\t}\n}\n\n/** Create `name` pointing at the tip of `startPoint` (no checkout). */\nexport async function createBranchFrom(\n\trepo: Repo,\n\tname: string,\n\tstartPoint = \"main\",\n): Promise<void> {\n\tassertSafeBranchName(name);\n\tassertSafeBranchName(startPoint);\n\tconst object = await resolveLooseRefFast(repo, `refs/heads/${startPoint}`);\n\tawait git.branch({ ...repo, ref: name, checkout: false, object });\n}\n\n/** Delete a branch ref (validated — deleteBranch has no internal ref check). */\nexport async function deleteBranchByName(\n\trepo: Repo,\n\tname: string,\n): Promise<void> {\n\tassertSafeBranchName(name);\n\tawait git.deleteBranch({ ...repo, ref: name });\n}\n\n/** Throws (NotFoundError) unless the branch resolves. */\nexport async function assertBranchExists(\n\trepo: Repo,\n\tname: string,\n): Promise<void> {\n\tassertSafeBranchName(name);\n\tawait resolveLooseRefFast(repo, `refs/heads/${name}`);\n}\n"],"mappings":"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","names":[]}