nano-git 0.1.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.
Files changed (227) hide show
  1. package/README.md +407 -0
  2. package/dist/backend/file-backend.d.mts +26 -0
  3. package/dist/backend/file-backend.mjs +83 -0
  4. package/dist/backend/file.d.mts +2 -0
  5. package/dist/backend/file.mjs +2 -0
  6. package/dist/backend/index.d.mts +2 -0
  7. package/dist/backend/index.mjs +1 -0
  8. package/dist/backend/memory-backend.d.mts +25 -0
  9. package/dist/backend/memory-backend.mjs +33 -0
  10. package/dist/backend/memory.d.mts +2 -0
  11. package/dist/backend/memory.mjs +2 -0
  12. package/dist/backend/types.d.mts +90 -0
  13. package/dist/core/errors.d.mts +124 -0
  14. package/dist/core/errors.mjs +168 -0
  15. package/dist/core/hash-digest.d.mts +35 -0
  16. package/dist/core/hash-digest.mjs +50 -0
  17. package/dist/core/hash-file.d.mts +20 -0
  18. package/dist/core/hash-file.mjs +27 -0
  19. package/dist/core/hash-path.d.mts +17 -0
  20. package/dist/core/hash-path.mjs +35 -0
  21. package/dist/core/types/odb.d.mts +63 -0
  22. package/dist/core/types/refs.d.mts +140 -0
  23. package/dist/core/types/refs.mjs +19 -0
  24. package/dist/core/types/shallow.d.mts +52 -0
  25. package/dist/core/types.d.mts +154 -0
  26. package/dist/core/types.mjs +43 -0
  27. package/dist/errors.d.mts +2 -0
  28. package/dist/errors.mjs +2 -0
  29. package/dist/hash-file.d.mts +2 -0
  30. package/dist/hash-file.mjs +2 -0
  31. package/dist/index.d.mts +16 -0
  32. package/dist/index.mjs +14 -0
  33. package/dist/objects/author.d.mts +25 -0
  34. package/dist/objects/author.mjs +45 -0
  35. package/dist/objects/blob.d.mts +15 -0
  36. package/dist/objects/blob.mjs +20 -0
  37. package/dist/objects/codec.d.mts +46 -0
  38. package/dist/objects/codec.mjs +84 -0
  39. package/dist/objects/commit.d.mts +26 -0
  40. package/dist/objects/commit.mjs +160 -0
  41. package/dist/objects/index.d.mts +8 -0
  42. package/dist/objects/index.mjs +8 -0
  43. package/dist/objects/raw.d.mts +85 -0
  44. package/dist/objects/raw.mjs +111 -0
  45. package/dist/objects/tag.d.mts +26 -0
  46. package/dist/objects/tag.mjs +148 -0
  47. package/dist/objects/tree.d.mts +22 -0
  48. package/dist/objects/tree.mjs +66 -0
  49. package/dist/odb/file-utils.mjs +136 -0
  50. package/dist/odb/file.d.mts +22 -0
  51. package/dist/odb/file.mjs +66 -0
  52. package/dist/odb/memory.d.mts +22 -0
  53. package/dist/odb/memory.mjs +54 -0
  54. package/dist/pack/composite-store.d.mts +76 -0
  55. package/dist/pack/composite-store.mjs +133 -0
  56. package/dist/pack/constants.mjs +48 -0
  57. package/dist/pack/crc32.mjs +38 -0
  58. package/dist/pack/delta-apply.d.mts +21 -0
  59. package/dist/pack/delta-apply.mjs +71 -0
  60. package/dist/pack/delta-create.d.mts +28 -0
  61. package/dist/pack/delta-create.mjs +151 -0
  62. package/dist/pack/index.d.mts +16 -0
  63. package/dist/pack/index.mjs +13 -0
  64. package/dist/pack/object-header.d.mts +36 -0
  65. package/dist/pack/object-header.mjs +72 -0
  66. package/dist/pack/ofs-delta-offset.d.mts +35 -0
  67. package/dist/pack/ofs-delta-offset.mjs +59 -0
  68. package/dist/pack/pack-builder-types.d.mts +19 -0
  69. package/dist/pack/pack-builder.d.mts +52 -0
  70. package/dist/pack/pack-builder.mjs +80 -0
  71. package/dist/pack/pack-encoding.mjs +76 -0
  72. package/dist/pack/pack-index-reader.d.mts +57 -0
  73. package/dist/pack/pack-index-reader.mjs +90 -0
  74. package/dist/pack/pack-index-types.d.mts +16 -0
  75. package/dist/pack/pack-index-writer.d.mts +45 -0
  76. package/dist/pack/pack-index-writer.mjs +106 -0
  77. package/dist/pack/pack-reader-resolver.mjs +104 -0
  78. package/dist/pack/pack-reader-types.d.mts +31 -0
  79. package/dist/pack/pack-reader-types.mjs +22 -0
  80. package/dist/pack/pack-reader-utils.mjs +61 -0
  81. package/dist/pack/pack-reader.d.mts +81 -0
  82. package/dist/pack/pack-reader.mjs +171 -0
  83. package/dist/pack/pack-store-loader.mjs +79 -0
  84. package/dist/pack/pack-store-types.d.mts +16 -0
  85. package/dist/pack/pack-store.d.mts +55 -0
  86. package/dist/pack/pack-store.mjs +114 -0
  87. package/dist/pack/pack-writer.mjs +96 -0
  88. package/dist/pack/varint.d.mts +34 -0
  89. package/dist/pack/varint.mjs +57 -0
  90. package/dist/refs/file.d.mts +6 -0
  91. package/dist/refs/file.mjs +222 -0
  92. package/dist/refs/fs-utils.mjs +30 -0
  93. package/dist/refs/memory.d.mts +14 -0
  94. package/dist/refs/memory.mjs +104 -0
  95. package/dist/refs/names.d.mts +57 -0
  96. package/dist/refs/names.mjs +80 -0
  97. package/dist/refs/resolve.d.mts +33 -0
  98. package/dist/refs/resolve.mjs +55 -0
  99. package/dist/refs/shallow/file.d.mts +17 -0
  100. package/dist/refs/shallow/file.mjs +61 -0
  101. package/dist/refs/shallow/memory.d.mts +18 -0
  102. package/dist/refs/shallow/memory.mjs +33 -0
  103. package/dist/repository/core.d.mts +3 -0
  104. package/dist/repository/core.mjs +2 -0
  105. package/dist/repository/create.d.mts +22 -0
  106. package/dist/repository/create.mjs +43 -0
  107. package/dist/repository/file.d.mts +43 -0
  108. package/dist/repository/file.mjs +82 -0
  109. package/dist/repository/import/import-glob.mjs +44 -0
  110. package/dist/repository/import/import-plan-builder.mjs +625 -0
  111. package/dist/repository/import/import-session-types.d.mts +280 -0
  112. package/dist/repository/import/import-session.mjs +96 -0
  113. package/dist/repository/import/import-view.mjs +133 -0
  114. package/dist/repository/memory.d.mts +17 -0
  115. package/dist/repository/memory.mjs +33 -0
  116. package/dist/repository/ops/fetch-operations.mjs +20 -0
  117. package/dist/repository/ops/fetch-types.d.mts +82 -0
  118. package/dist/repository/ops/fetch-url.mjs +82 -0
  119. package/dist/repository/ops/fs-object-operations.mjs +31 -0
  120. package/dist/repository/ops/maintenance-operations.mjs +62 -0
  121. package/dist/repository/ops/maintenance-types.d.mts +42 -0
  122. package/dist/repository/ops/object-operations.mjs +65 -0
  123. package/dist/repository/ops/object-types.d.mts +109 -0
  124. package/dist/repository/ops/push-operations.mjs +16 -0
  125. package/dist/repository/ops/push-resolution.mjs +17 -0
  126. package/dist/repository/ops/push-types.d.mts +72 -0
  127. package/dist/repository/ops/push-url.mjs +45 -0
  128. package/dist/repository/ops/reachability.mjs +60 -0
  129. package/dist/repository/ops/ref-operations.mjs +86 -0
  130. package/dist/repository/ops/ref-types.d.mts +70 -0
  131. package/dist/repository/tree/tree-patch.d.mts +64 -0
  132. package/dist/repository/tree/tree-patch.mjs +268 -0
  133. package/dist/repository/tree/tree-walk.d.mts +46 -0
  134. package/dist/repository/tree/tree-walk.mjs +65 -0
  135. package/dist/repository/tree/tree-writer.mjs +68 -0
  136. package/dist/repository/types.d.mts +36 -0
  137. package/dist/sha1.d.mts +4 -0
  138. package/dist/sha1.mjs +4 -0
  139. package/dist/transport/client/receive-pack/http.d.mts +33 -0
  140. package/dist/transport/client/receive-pack/http.mjs +99 -0
  141. package/dist/transport/client/receive-pack/push-error.d.mts +23 -0
  142. package/dist/transport/client/receive-pack/push-error.mjs +32 -0
  143. package/dist/transport/client/receive-pack/push-pack-plan.d.mts +28 -0
  144. package/dist/transport/client/receive-pack/push-pack-plan.mjs +60 -0
  145. package/dist/transport/client/receive-pack/push-policy.d.mts +19 -0
  146. package/dist/transport/client/receive-pack/push-policy.mjs +64 -0
  147. package/dist/transport/client/receive-pack/push-ref-plan.d.mts +45 -0
  148. package/dist/transport/client/receive-pack/push-ref-plan.mjs +108 -0
  149. package/dist/transport/client/receive-pack/push-report.d.mts +28 -0
  150. package/dist/transport/client/receive-pack/push-report.mjs +84 -0
  151. package/dist/transport/client/receive-pack/push-request-plan.mjs +52 -0
  152. package/dist/transport/client/receive-pack/push.d.mts +32 -0
  153. package/dist/transport/client/receive-pack/push.mjs +97 -0
  154. package/dist/transport/client/receive-pack/request.d.mts +39 -0
  155. package/dist/transport/client/receive-pack/request.mjs +46 -0
  156. package/dist/transport/client/receive-pack/response.d.mts +26 -0
  157. package/dist/transport/client/receive-pack/response.mjs +52 -0
  158. package/dist/transport/client/receive-pack/result.d.mts +34 -0
  159. package/dist/transport/client/receive-pack/result.mjs +100 -0
  160. package/dist/transport/client/upload-pack/capability-advertisement.d.mts +56 -0
  161. package/dist/transport/client/upload-pack/capability-advertisement.mjs +130 -0
  162. package/dist/transport/client/upload-pack/fetch.d.mts +109 -0
  163. package/dist/transport/client/upload-pack/fetch.mjs +392 -0
  164. package/dist/transport/client/upload-pack/http.d.mts +29 -0
  165. package/dist/transport/client/upload-pack/http.mjs +79 -0
  166. package/dist/transport/client/upload-pack/ls-refs.d.mts +75 -0
  167. package/dist/transport/client/upload-pack/ls-refs.mjs +150 -0
  168. package/dist/transport/client/upload-pack/object-info.d.mts +65 -0
  169. package/dist/transport/client/upload-pack/object-info.mjs +111 -0
  170. package/dist/transport/client/upload-pack/types.d.mts +153 -0
  171. package/dist/transport/http/index.d.mts +3 -0
  172. package/dist/transport/http/index.mjs +2 -0
  173. package/dist/transport/http/smart-http.d.mts +46 -0
  174. package/dist/transport/http/smart-http.mjs +176 -0
  175. package/dist/transport/http/types.d.mts +27 -0
  176. package/dist/transport/index.d.mts +9 -0
  177. package/dist/transport/index.mjs +8 -0
  178. package/dist/transport/protocol/object-graph.d.mts +63 -0
  179. package/dist/transport/protocol/object-graph.mjs +149 -0
  180. package/dist/transport/protocol/pkt-line.d.mts +109 -0
  181. package/dist/transport/protocol/pkt-line.mjs +195 -0
  182. package/dist/transport/protocol/ref-advertisement.mjs +185 -0
  183. package/dist/transport/protocol/ref-collection.d.mts +38 -0
  184. package/dist/transport/protocol/ref-collection.mjs +63 -0
  185. package/dist/transport/protocol/ref-match.d.mts +39 -0
  186. package/dist/transport/protocol/ref-match.mjs +42 -0
  187. package/dist/transport/protocol/refspec.d.mts +44 -0
  188. package/dist/transport/protocol/refspec.mjs +79 -0
  189. package/dist/transport/protocol/side-band.d.mts +65 -0
  190. package/dist/transport/protocol/side-band.mjs +142 -0
  191. package/dist/transport/protocol/transport-capabilities.mjs +46 -0
  192. package/dist/transport/protocol/types.d.mts +148 -0
  193. package/dist/transport/protocol/update-refs.d.mts +68 -0
  194. package/dist/transport/protocol/update-refs.mjs +126 -0
  195. package/dist/transport/receive-pack.d.mts +11 -0
  196. package/dist/transport/receive-pack.mjs +11 -0
  197. package/dist/transport/server/receive-pack/advertise.d.mts +28 -0
  198. package/dist/transport/server/receive-pack/advertise.mjs +88 -0
  199. package/dist/transport/server/receive-pack/handler.d.mts +30 -0
  200. package/dist/transport/server/receive-pack/handler.mjs +156 -0
  201. package/dist/transport/server/receive-pack/index.d.mts +6 -0
  202. package/dist/transport/server/receive-pack/index.mjs +6 -0
  203. package/dist/transport/server/receive-pack/parse.d.mts +17 -0
  204. package/dist/transport/server/receive-pack/parse.mjs +80 -0
  205. package/dist/transport/server/receive-pack/report-status.mjs +64 -0
  206. package/dist/transport/server/receive-pack/service.d.mts +41 -0
  207. package/dist/transport/server/receive-pack/service.mjs +39 -0
  208. package/dist/transport/server/receive-pack/types.d.mts +56 -0
  209. package/dist/transport/server/receive-pack/types.mjs +25 -0
  210. package/dist/transport/server/receive-pack/unpack.mjs +119 -0
  211. package/dist/transport/server/upload-pack/advertise.d.mts +20 -0
  212. package/dist/transport/server/upload-pack/advertise.mjs +30 -0
  213. package/dist/transport/server/upload-pack/command.d.mts +43 -0
  214. package/dist/transport/server/upload-pack/command.mjs +56 -0
  215. package/dist/transport/server/upload-pack/fetch.d.mts +43 -0
  216. package/dist/transport/server/upload-pack/fetch.mjs +217 -0
  217. package/dist/transport/server/upload-pack/index.d.mts +7 -0
  218. package/dist/transport/server/upload-pack/index.mjs +7 -0
  219. package/dist/transport/server/upload-pack/ls-refs.d.mts +38 -0
  220. package/dist/transport/server/upload-pack/ls-refs.mjs +113 -0
  221. package/dist/transport/server/upload-pack/service.d.mts +40 -0
  222. package/dist/transport/server/upload-pack/service.mjs +51 -0
  223. package/dist/transport/server/upload-pack/types.d.mts +11 -0
  224. package/dist/transport/server/upload-pack/types.mjs +21 -0
  225. package/dist/transport/upload-pack.d.mts +7 -0
  226. package/dist/transport/upload-pack.mjs +6 -0
  227. package/package.json +98 -0
@@ -0,0 +1,171 @@
1
+ import { InvalidPackError } from "../core/errors.mjs";
2
+ import { decodeObjectHeader } from "./object-header.mjs";
3
+ import { decodeOfsDeltaOffset } from "./ofs-delta-offset.mjs";
4
+ import { parsePackHeader } from "./pack-reader-utils.mjs";
5
+ import { resolveOfsDeltaPackObject, resolvePlainPackObject, resolveRefDeltaPackObject } from "./pack-reader-resolver.mjs";
6
+ import "./pack-reader-types.mjs";
7
+ //#region src/pack/pack-reader.ts
8
+ /**
9
+ * Packfile 读取
10
+ *
11
+ * Git Packfile 格式:
12
+ * - 头部:4 字节签名 "PACK" + 4 字节版本 + 4 字节对象数
13
+ * - 对象序列:每个对象包含头部 + zlib 压缩数据
14
+ * - 尾部:20 字节 SHA-1 校验和
15
+ *
16
+ * 对象类型:
17
+ * - 非 delta 对象:直接存储压缩后的对象数据
18
+ * - ofs_delta:基于偏移量的 delta,引用同一 packfile 中的其他对象
19
+ * - ref_delta:基于 SHA-1 的 delta,可引用任意对象
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const reader = createPackReader(packData);
24
+ * for (const obj of reader.objects()) {
25
+ * console.log(obj.type, obj.hash);
26
+ * }
27
+ * ```
28
+ *
29
+ * 拆分共享类型与底层辅助函数后,
30
+ * 当前文件只保留对象遍历与 delta 解析主流程。
31
+ */
32
+ /**
33
+ * 创建 Packfile 读取器
34
+ *
35
+ * @param data - 完整的 packfile 数据
36
+ * @returns Packfile 读取器实例
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const reader = createPackReader(packData);
41
+ * console.log(`Packfile 包含 ${reader.objectCount} 个对象`);
42
+ *
43
+ * // 遍历所有对象
44
+ * for (const obj of reader.objects()) {
45
+ * console.log(`${obj.type} ${obj.hash}`);
46
+ * }
47
+ * ```
48
+ */
49
+ function createPackReader(data) {
50
+ return new PackReader(data);
51
+ }
52
+ /**
53
+ * Packfile 读取器类
54
+ *
55
+ * 使用惰性解析策略:对象在首次被访问时才解析。
56
+ * - getByHash() / getByOffset() / has() 只解析到找到目标为止
57
+ * - objects() / listHashes() 解析全部对象
58
+ */
59
+ var PackReader = class {
60
+ data;
61
+ _objectCount;
62
+ objectsByOffset = /* @__PURE__ */ new Map();
63
+ objectsByHash = /* @__PURE__ */ new Map();
64
+ parseOffset;
65
+ parsedCount = 0;
66
+ fullyParsed = false;
67
+ constructor(data) {
68
+ this.data = data;
69
+ this._objectCount = parsePackHeader(data);
70
+ this.parseOffset = 12;
71
+ }
72
+ /** 对象数量 */
73
+ get objectCount() {
74
+ return this._objectCount;
75
+ }
76
+ /**
77
+ * 解析下一个对象
78
+ */
79
+ parseNext() {
80
+ if (this.fullyParsed) return;
81
+ const endOffset = this.data.length - 20;
82
+ if (this.parsedCount >= this._objectCount || this.parseOffset >= endOffset) {
83
+ this.fullyParsed = true;
84
+ if (this.parsedCount < this._objectCount) throw new InvalidPackError(`Unexpected end of packfile at object ${this.parsedCount}`);
85
+ return;
86
+ }
87
+ const objOffset = this.parseOffset;
88
+ const [typeNum, _size, headerBytes] = decodeObjectHeader(this.data, this.parseOffset);
89
+ this.parseOffset += headerBytes;
90
+ let obj;
91
+ if (typeNum === 6) {
92
+ const [negOffset, offsetBytes] = decodeOfsDeltaOffset(this.data, this.parseOffset);
93
+ this.parseOffset += offsetBytes;
94
+ const resolved = resolveOfsDeltaPackObject(this.data, this.parseOffset, objOffset, negOffset, this.objectsByOffset);
95
+ obj = resolved.object;
96
+ this.parseOffset = resolved.nextOffset;
97
+ } else if (typeNum === 7) {
98
+ const baseHash = this.data.subarray(this.parseOffset, this.parseOffset + 20).toString("hex");
99
+ this.parseOffset += 20;
100
+ const resolved = resolveRefDeltaPackObject(this.data, this.parseOffset, objOffset, baseHash, this.objectsByHash);
101
+ obj = resolved.object;
102
+ this.parseOffset = resolved.nextOffset;
103
+ } else {
104
+ const resolved = resolvePlainPackObject(this.data, this.parseOffset, objOffset, typeNum);
105
+ obj = resolved.object;
106
+ this.parseOffset = resolved.nextOffset;
107
+ }
108
+ this.objectsByOffset.set(objOffset, obj);
109
+ this.objectsByHash.set(obj.hash, obj);
110
+ this.parsedCount++;
111
+ if (this.parsedCount >= this._objectCount) this.fullyParsed = true;
112
+ }
113
+ /**
114
+ * 按需解析直到条件满足或解析全部
115
+ */
116
+ parseUntil(condition) {
117
+ while (!this.fullyParsed && !condition()) this.parseNext();
118
+ }
119
+ /**
120
+ * 解析所有剩余对象
121
+ */
122
+ parseAllRemaining() {
123
+ this.parseUntil(() => this.fullyParsed);
124
+ }
125
+ /**
126
+ * 遍历所有对象
127
+ *
128
+ * 按 offset 顺序解析并迭代所有对象。
129
+ */
130
+ *objects() {
131
+ this.parseAllRemaining();
132
+ yield* this.objectsByOffset.values();
133
+ }
134
+ /**
135
+ * 根据哈希获取对象(惰性解析)
136
+ *
137
+ * 只解析到找到目标对象为止,不解析全部。
138
+ */
139
+ getByHash(hash) {
140
+ if (this.objectsByHash.has(hash)) return this.objectsByHash.get(hash);
141
+ this.parseUntil(() => this.objectsByHash.has(hash));
142
+ return this.objectsByHash.get(hash);
143
+ }
144
+ /**
145
+ * 根据偏移量获取对象(惰性解析)
146
+ *
147
+ * 只解析到目标偏移位置为止。
148
+ */
149
+ getByOffset(offset) {
150
+ if (this.objectsByOffset.has(offset)) return this.objectsByOffset.get(offset);
151
+ this.parseUntil(() => this.objectsByOffset.has(offset) || this.fullyParsed);
152
+ return this.objectsByOffset.get(offset);
153
+ }
154
+ /**
155
+ * 检查对象是否存在(惰性查找)
156
+ */
157
+ has(hash) {
158
+ if (this.objectsByHash.has(hash)) return true;
159
+ this.parseUntil(() => this.objectsByHash.has(hash));
160
+ return this.objectsByHash.has(hash);
161
+ }
162
+ /**
163
+ * 获取所有对象的哈希列表(解析全部)
164
+ */
165
+ listHashes() {
166
+ this.parseAllRemaining();
167
+ return Array.from(this.objectsByHash.keys());
168
+ }
169
+ };
170
+ //#endregion
171
+ export { PackReader, createPackReader };
@@ -0,0 +1,79 @@
1
+ import { PackReader } from "./pack-reader.mjs";
2
+ import { createPackIndexReader } from "./pack-index-reader.mjs";
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ //#region src/pack/pack-store-loader.ts
6
+ /**
7
+ * Pack 对象存储加载辅助函数
8
+ */
9
+ /**
10
+ * 扫描 pack 目录并加载索引信息
11
+ *
12
+ * @param packDir - `.git/objects/pack` 目录
13
+ * @returns 已发现的 pack 文件对
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const pairs = loadPackPairs("/tmp/repo/.git/objects/pack");
18
+ * ```
19
+ */
20
+ function loadPackPairs(packDir) {
21
+ if (!existsSync(packDir)) return [];
22
+ const pairs = [];
23
+ const idxFiles = readdirSync(packDir).filter((file) => file.endsWith(".idx"));
24
+ for (const idxFile of idxFiles) {
25
+ const match = idxFile.match(/^pack-([0-9a-f]{40})\.idx$/);
26
+ if (!match) continue;
27
+ const checksum = match[1];
28
+ if (!existsSync(join(packDir, `pack-${checksum}.pack`))) continue;
29
+ const idxData = readFileSync(join(packDir, idxFile));
30
+ pairs.push({
31
+ checksum,
32
+ index: createPackIndexReader(idxData),
33
+ reader: null,
34
+ packData: null
35
+ });
36
+ }
37
+ return pairs;
38
+ }
39
+ /**
40
+ * 按需加载 packfile 读取器
41
+ *
42
+ * @param packDir - `.git/objects/pack` 目录
43
+ * @param pair - pack 文件对
44
+ * @returns PackReader 实例
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const reader = getPackReader(packDir, pair);
49
+ * ```
50
+ */
51
+ function getPackReader(packDir, pair) {
52
+ if (!pair.reader) {
53
+ pair.packData = readFileSync(join(packDir, `pack-${pair.checksum}.pack`));
54
+ pair.reader = new PackReader(pair.packData);
55
+ }
56
+ return pair.reader;
57
+ }
58
+ /**
59
+ * 将 pack 文件对转换为对外展示信息
60
+ *
61
+ * @param packDir - `.git/objects/pack` 目录
62
+ * @param pair - pack 文件对
63
+ * @returns pack 文件信息
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const info = toPackFileInfo(packDir, pair);
68
+ * ```
69
+ */
70
+ function toPackFileInfo(packDir, pair) {
71
+ return {
72
+ checksum: pair.checksum,
73
+ packPath: join(packDir, `pack-${pair.checksum}.pack`),
74
+ idxPath: join(packDir, `pack-${pair.checksum}.idx`),
75
+ objectCount: pair.index.objectCount
76
+ };
77
+ }
78
+ //#endregion
79
+ export { getPackReader, loadPackPairs, toPackFileInfo };
@@ -0,0 +1,16 @@
1
+ //#region src/pack/pack-store-types.d.ts
2
+ /**
3
+ * 一个已发现的 pack 文件对
4
+ */
5
+ interface PackFileInfo {
6
+ /** pack 文件校验和 */
7
+ checksum: string;
8
+ /** .pack 文件路径 */
9
+ packPath: string;
10
+ /** .idx 文件路径 */
11
+ idxPath: string;
12
+ /** 索引中的对象数量 */
13
+ objectCount: number;
14
+ }
15
+ //#endregion
16
+ export { PackFileInfo };
@@ -0,0 +1,55 @@
1
+ import { SHA1 } from "../core/types.mjs";
2
+ import { ObjectSource } from "../core/types/odb.mjs";
3
+ import { PackFileInfo } from "./pack-store-types.mjs";
4
+
5
+ //#region src/pack/pack-store.d.ts
6
+ /**
7
+ * 基于 Packfile 的对象源接口
8
+ */
9
+ interface PackObjectStore extends ObjectSource {
10
+ /**
11
+ * 刷新 pack 目录缓存
12
+ *
13
+ * 当外部新增或删除 packfile 后,需要调用此方法重新扫描。
14
+ */
15
+ refresh(): void;
16
+ /**
17
+ * 列出当前可见的 pack 文件对
18
+ */
19
+ listPacks(): PackFileInfo[];
20
+ /**
21
+ * 获取所有 packfile 中的对象哈希列表
22
+ *
23
+ * 保留此方法作为更明确的命名别名。
24
+ */
25
+ listHashes(): SHA1[];
26
+ /** 获取 packfile 数量 */
27
+ readonly packCount: number;
28
+ /** 获取所有对象数量 */
29
+ readonly objectCount: number;
30
+ }
31
+ /**
32
+ * 创建基于 Packfile 的对象源
33
+ *
34
+ * 扫描 .git/objects/pack/ 目录,加载所有 .idx 文件。
35
+ * packfile 数据按需加载(首次读取时才加载)。
36
+ *
37
+ * @param gitDir - .git 目录的路径
38
+ * @returns 基于 Packfile 的对象源
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const store = createPackObjectStore("/path/to/.git");
43
+ *
44
+ * // 读取原始对象
45
+ * const raw = store.read(hash);
46
+ *
47
+ * // 检查对象是否存在
48
+ * if (store.exists(hash)) {
49
+ * console.log("对象在 packfile 中");
50
+ * }
51
+ * ```
52
+ */
53
+ declare function createPackObjectStore(gitDir: string): PackObjectStore;
54
+ //#endregion
55
+ export { PackObjectStore, createPackObjectStore };
@@ -0,0 +1,114 @@
1
+ import { ObjectNotFoundError } from "../core/errors.mjs";
2
+ import { packObjectToRaw } from "./pack-reader-types.mjs";
3
+ import { getPackReader, loadPackPairs, toPackFileInfo } from "./pack-store-loader.mjs";
4
+ import { join } from "node:path";
5
+ //#region src/pack/pack-store.ts
6
+ /**
7
+ * 基于 Packfile 的对象源(raw-first)
8
+ *
9
+ * 从 .git/objects/pack/ 目录中读取 packfile 和索引文件,
10
+ * 提供只读的原始对象读取接口。
11
+ *
12
+ * Git 的 pack 目录结构:
13
+ * - pack-<checksum>.pack — 打包的对象数据
14
+ * - pack-<checksum>.idx — 对应的索引文件
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const store = createPackObjectStore("/path/to/.git");
19
+ * const raw = store.read(hash);
20
+ * ```
21
+ */
22
+ /**
23
+ * 创建基于 Packfile 的对象源
24
+ *
25
+ * 扫描 .git/objects/pack/ 目录,加载所有 .idx 文件。
26
+ * packfile 数据按需加载(首次读取时才加载)。
27
+ *
28
+ * @param gitDir - .git 目录的路径
29
+ * @returns 基于 Packfile 的对象源
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const store = createPackObjectStore("/path/to/.git");
34
+ *
35
+ * // 读取原始对象
36
+ * const raw = store.read(hash);
37
+ *
38
+ * // 检查对象是否存在
39
+ * if (store.exists(hash)) {
40
+ * console.log("对象在 packfile 中");
41
+ * }
42
+ * ```
43
+ */
44
+ function createPackObjectStore(gitDir) {
45
+ const packDir = join(gitDir, "objects", "pack");
46
+ const pairs = [];
47
+ let loaded = false;
48
+ /**
49
+ * 扫描 pack 目录并加载索引
50
+ */
51
+ function ensureLoaded() {
52
+ if (loaded) return;
53
+ loaded = true;
54
+ pairs.push(...loadPackPairs(packDir));
55
+ }
56
+ function read(hash) {
57
+ ensureLoaded();
58
+ for (const pair of pairs) if (pair.index.lookup(hash)) {
59
+ const obj = getPackReader(packDir, pair).getByHash(hash);
60
+ if (obj) return packObjectToRaw(obj);
61
+ }
62
+ throw new ObjectNotFoundError(hash);
63
+ }
64
+ function tryRead(hash) {
65
+ ensureLoaded();
66
+ for (const pair of pairs) if (pair.index.lookup(hash)) {
67
+ const obj = getPackReader(packDir, pair).getByHash(hash);
68
+ if (obj) return packObjectToRaw(obj);
69
+ }
70
+ }
71
+ function exists(hash) {
72
+ ensureLoaded();
73
+ for (const pair of pairs) if (pair.index.has(hash)) return true;
74
+ return false;
75
+ }
76
+ function list() {
77
+ ensureLoaded();
78
+ const hashes = [];
79
+ for (const pair of pairs) hashes.push(...pair.index.listHashes());
80
+ return hashes;
81
+ }
82
+ function listHashes() {
83
+ return list();
84
+ }
85
+ function listPacks() {
86
+ ensureLoaded();
87
+ return pairs.map((pair) => toPackFileInfo(packDir, pair));
88
+ }
89
+ function refresh() {
90
+ loaded = false;
91
+ pairs.length = 0;
92
+ }
93
+ return {
94
+ refresh,
95
+ read,
96
+ tryRead,
97
+ exists,
98
+ list,
99
+ listHashes,
100
+ listPacks,
101
+ get packCount() {
102
+ ensureLoaded();
103
+ return pairs.length;
104
+ },
105
+ get objectCount() {
106
+ ensureLoaded();
107
+ let count = 0;
108
+ for (const pair of pairs) count += pair.index.objectCount;
109
+ return count;
110
+ }
111
+ };
112
+ }
113
+ //#endregion
114
+ export { createPackObjectStore };
@@ -0,0 +1,96 @@
1
+ import { buildEncodedPack, toEncodedPackObject } from "./pack-encoding.mjs";
2
+ //#region src/pack/pack-writer.ts
3
+ /**
4
+ * Packfile 写入
5
+ *
6
+ * 将多个 Git 对象打包成一个 packfile。
7
+ *
8
+ * Packfile 格式:
9
+ * - 头部:4 字节签名 "PACK" + 4 字节版本 + 4 字节对象数
10
+ * - 对象序列:每个对象包含头部 + zlib 压缩数据
11
+ * - 尾部:20 字节 SHA-1 校验和(对整个 packfile 的哈希)
12
+ *
13
+ * 当前实现不生成 delta 对象,所有对象都以非 delta 形式存储。
14
+ * 这简化了实现,但牺牲了一些压缩效率。
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const writer = createPackWriter();
19
+ * writer.addObject({ type: "blob", content: Buffer.from("hello") });
20
+ * const packData = writer.build();
21
+ * ```
22
+ */
23
+ /**
24
+ * 创建 Packfile 写入器
25
+ *
26
+ * @returns Packfile 写入器实例
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const writer = createPackWriter();
31
+ *
32
+ * // 添加对象
33
+ * writer.addObject({ type: "blob", content: Buffer.from("hello") });
34
+ * writer.addObject({ type: "blob", content: Buffer.from("world") });
35
+ *
36
+ * // 构建 packfile
37
+ * const packData = writer.build();
38
+ * ```
39
+ */
40
+ function createPackWriter() {
41
+ return new PackWriter();
42
+ }
43
+ /**
44
+ * Packfile 写入器类
45
+ */
46
+ var PackWriter = class {
47
+ entries = [];
48
+ hashes = /* @__PURE__ */ new Set();
49
+ /**
50
+ * 添加一个原始对象到 packfile
51
+ *
52
+ * @param raw - 原始 Git 对象
53
+ * @returns 对象的 SHA-1 哈希
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const hash = writer.addRaw(raw);
58
+ * ```
59
+ */
60
+ addRaw(raw) {
61
+ const entry = toEncodedPackObject(raw);
62
+ const hash = entry.hash;
63
+ if (this.hashes.has(hash)) return hash;
64
+ this.entries.push(entry);
65
+ this.hashes.add(hash);
66
+ return hash;
67
+ }
68
+ /**
69
+ * 获取已添加的对象数量
70
+ */
71
+ get objectCount() {
72
+ return this.entries.length;
73
+ }
74
+ /**
75
+ * 构建 packfile 数据
76
+ *
77
+ * @returns 完整的 packfile 二进制数据
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const packData = writer.build();
82
+ * writeFileSync("objects/pack/pack-xxx.pack", packData);
83
+ * ```
84
+ */
85
+ build() {
86
+ return buildEncodedPack(this.entries).packData;
87
+ }
88
+ /**
89
+ * 获取所有已添加对象的哈希列表
90
+ */
91
+ listHashes() {
92
+ return this.entries.map((e) => e.hash);
93
+ }
94
+ };
95
+ //#endregion
96
+ export { createPackWriter };
@@ -0,0 +1,34 @@
1
+ //#region src/pack/varint.d.ts
2
+ /**
3
+ * Packfile 通用变长整数编码/解码
4
+ */
5
+ /**
6
+ * 解码变长整数(通用版本)
7
+ *
8
+ * 用于 delta 指令中的变长整数,每个字节高 1 位是继续标志,
9
+ * 低 7 位是数据,小端序。
10
+ *
11
+ * @param buf - 数据缓冲区
12
+ * @param offset - 起始偏移量
13
+ * @returns [值, 消耗的字节数]
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const [value, bytesRead] = decodeVarint(buf, 0);
18
+ * ```
19
+ */
20
+ declare function decodeVarint(buf: Buffer, offset: number): [value: number, bytesRead: number];
21
+ /**
22
+ * 编码变长整数(通用版本)
23
+ *
24
+ * @param value - 要编码的值
25
+ * @returns 编码后的字节缓冲区
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const encoded = encodeVarint(123);
30
+ * ```
31
+ */
32
+ declare function encodeVarint(value: number): Buffer;
33
+ //#endregion
34
+ export { decodeVarint, encodeVarint };
@@ -0,0 +1,57 @@
1
+ import { InvalidPackError } from "../core/errors.mjs";
2
+ //#region src/pack/varint.ts
3
+ /**
4
+ * Packfile 通用变长整数编码/解码
5
+ */
6
+ /**
7
+ * 解码变长整数(通用版本)
8
+ *
9
+ * 用于 delta 指令中的变长整数,每个字节高 1 位是继续标志,
10
+ * 低 7 位是数据,小端序。
11
+ *
12
+ * @param buf - 数据缓冲区
13
+ * @param offset - 起始偏移量
14
+ * @returns [值, 消耗的字节数]
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const [value, bytesRead] = decodeVarint(buf, 0);
19
+ * ```
20
+ */
21
+ function decodeVarint(buf, offset) {
22
+ let value = 0;
23
+ let shift = 0;
24
+ let bytesRead = 0;
25
+ let byte;
26
+ do {
27
+ if (offset + bytesRead >= buf.length) throw new InvalidPackError("Unexpected end of data in varint");
28
+ byte = buf[offset + bytesRead];
29
+ value |= (byte & 127) << shift;
30
+ shift += 7;
31
+ bytesRead++;
32
+ } while (byte & 128);
33
+ return [value, bytesRead];
34
+ }
35
+ /**
36
+ * 编码变长整数(通用版本)
37
+ *
38
+ * @param value - 要编码的值
39
+ * @returns 编码后的字节缓冲区
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const encoded = encodeVarint(123);
44
+ * ```
45
+ */
46
+ function encodeVarint(value) {
47
+ const bytes = [];
48
+ do {
49
+ let byte = value & 127;
50
+ value >>>= 7;
51
+ if (value > 0) byte |= 128;
52
+ bytes.push(byte);
53
+ } while (value > 0);
54
+ return Buffer.from(bytes);
55
+ }
56
+ //#endregion
57
+ export { decodeVarint, encodeVarint };
@@ -0,0 +1,6 @@
1
+ import { RefStore } from "../core/types/refs.mjs";
2
+
3
+ //#region src/refs/file.d.ts
4
+ declare function createFileRefStore(gitDir: string): RefStore;
5
+ //#endregion
6
+ export { createFileRefStore };