nano-git 0.1.0 → 0.2.1

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 (45) hide show
  1. package/README.md +58 -1
  2. package/dist/backend/sqlite.d.mts +44 -0
  3. package/dist/backend/sqlite.mjs +59 -0
  4. package/dist/core/errors.d.mts +71 -1
  5. package/dist/core/errors.mjs +99 -1
  6. package/dist/errors.d.mts +2 -2
  7. package/dist/errors.mjs +2 -2
  8. package/dist/index.d.mts +2 -1
  9. package/dist/log/index.d.mts +3 -0
  10. package/dist/log/index.mjs +2 -0
  11. package/dist/log/types.d.mts +71 -0
  12. package/dist/log/walk.d.mts +37 -0
  13. package/dist/log/walk.mjs +274 -0
  14. package/dist/odb/sqlite.d.mts +23 -0
  15. package/dist/odb/sqlite.mjs +83 -0
  16. package/dist/refs/shallow/sqlite.d.mts +23 -0
  17. package/dist/refs/shallow/sqlite.mjs +61 -0
  18. package/dist/refs/sqlite.d.mts +23 -0
  19. package/dist/refs/sqlite.mjs +135 -0
  20. package/dist/remote/http.d.mts +51 -0
  21. package/dist/remote/http.mjs +74 -0
  22. package/dist/remote/types.d.mts +20 -0
  23. package/dist/repository/import/import-session-types.d.mts +3 -16
  24. package/dist/repository/ops/object-operations.mjs +0 -5
  25. package/dist/repository/ops/object-types.d.mts +0 -21
  26. package/dist/repository/sqlite.d.mts +28 -0
  27. package/dist/repository/sqlite.mjs +45 -0
  28. package/dist/transport/upload-pack.d.mts +1 -1
  29. package/dist/transport/upload-pack.mjs +1 -1
  30. package/dist/workdir/change-log.mjs +63 -0
  31. package/dist/workdir/core.d.mts +166 -0
  32. package/dist/workdir/core.mjs +2 -0
  33. package/dist/workdir/ids.mjs +20 -0
  34. package/dist/workdir/memory-backend.mjs +21 -0
  35. package/dist/workdir/memory.d.mts +2 -0
  36. package/dist/workdir/memory.mjs +2 -0
  37. package/dist/workdir/nodes.mjs +112 -0
  38. package/dist/workdir/origin.mjs +55 -0
  39. package/dist/workdir/overlay.mjs +95 -0
  40. package/dist/workdir/path.mjs +70 -0
  41. package/dist/workdir/session-internal.mjs +141 -0
  42. package/dist/workdir/session.d.mts +18 -0
  43. package/dist/workdir/session.mjs +380 -0
  44. package/dist/workdir/write-tree.mjs +97 -0
  45. package/package.json +21 -3
@@ -0,0 +1,380 @@
1
+ import { VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError } from "../core/errors.mjs";
2
+ import { VIRTUAL_ROOT_NODE_ID, createNodeId } from "./ids.mjs";
3
+ import { overlayBindEntry, overlayRenameEntry, overlayTombstoneEntry } from "./overlay.mjs";
4
+ import { cloneSessionNodeForCopy, createRootDirectoryNode, revertNodeState } from "./nodes.mjs";
5
+ import { createVirtualWorkdirMemoryState } from "./memory-backend.mjs";
6
+ import { modeToVirtualEntryKind, readRepoBlobContent } from "./origin.mjs";
7
+ import { assertValidVirtualPath, baseName, normalizeDirectoryPath, parentPath } from "./path.mjs";
8
+ import { listDirectoryChildren, resolveChild, resolvePath } from "./session-internal.mjs";
9
+ import { writeTreeFromSession } from "./write-tree.mjs";
10
+ //#region src/workdir/session.ts
11
+ /**
12
+ * VirtualWorkdirSession 行为编排
13
+ *
14
+ * Phase 5:完整文件/目录 rename 与 copy 语义。
15
+ */
16
+ /**
17
+ * 基于 ObjectDatabase 创建 VirtualWorkdirSession
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const repo = createMemoryRepository();
22
+ * const tree = repo.createTree([]);
23
+ * const session = createVirtualWorkdirSession(repo.objects, { baseTree: tree });
24
+ * expect(session.readdir()).toEqual([]);
25
+ * ```
26
+ */
27
+ function createVirtualWorkdirSession(source, options) {
28
+ return buildSessionApi(source, createVirtualWorkdirMemoryState(options.baseTree));
29
+ }
30
+ function buildSessionApi(source, state) {
31
+ return {
32
+ get baseTree() {
33
+ return state.baseTree;
34
+ },
35
+ exists(path) {
36
+ if (path === "") return true;
37
+ return resolvePath(source, state, path).found;
38
+ },
39
+ stat(path) {
40
+ if (path === "") return statDirectoryNode(getRootNode(state));
41
+ const resolved = resolvePath(source, state, path);
42
+ if (!resolved.found || resolved.node === null) return null;
43
+ return statNode(source, resolved.node, path);
44
+ },
45
+ readdir(dirPath) {
46
+ const normalized = normalizeDirectoryPath(dirPath);
47
+ const resolved = normalized === "" ? {
48
+ found: true,
49
+ node: getRootNode(state)
50
+ } : resolvePath(source, state, normalized);
51
+ if (!resolved.found || resolved.node === null) throw new VirtualPathNotFoundError(normalized);
52
+ if (resolved.node.state.kind !== "directory") throw new VirtualNotDirectoryError(normalized);
53
+ return listDirectoryChildren(source, state, resolved.node, normalized).map((child) => ({
54
+ name: child.name,
55
+ kind: modeToVirtualEntryKind(child.mode),
56
+ mode: child.mode
57
+ }));
58
+ },
59
+ readFile(path) {
60
+ assertValidVirtualPath(path);
61
+ const resolved = resolvePath(source, state, path);
62
+ if (!resolved.found || resolved.node === null) throw new VirtualPathNotFoundError(path);
63
+ const node = resolved.node;
64
+ if (node.state.kind === "file") {
65
+ if (node.state.content !== void 0) return node.state.content;
66
+ if (node.origin.kind === "repo-blob") return readRepoBlobContent(source, node.origin.hash, path);
67
+ throw new VirtualPathNotFoundError(path);
68
+ }
69
+ if (node.state.kind === "symlink") throw new VirtualNotFileError(path);
70
+ throw new VirtualNotFileError(path);
71
+ },
72
+ readLink(path) {
73
+ assertValidVirtualPath(path);
74
+ const resolved = resolvePath(source, state, path);
75
+ if (!resolved.found || resolved.node === null) throw new VirtualPathNotFoundError(path);
76
+ const node = resolved.node;
77
+ if (node.state.kind !== "symlink") throw new VirtualNotSymlinkError(path);
78
+ if (node.state.target !== void 0) return node.state.target.toString("utf-8");
79
+ if (node.origin.kind === "repo-blob") return readRepoBlobContent(source, node.origin.hash, path).toString("utf-8");
80
+ throw new VirtualPathNotFoundError(path);
81
+ },
82
+ mkdir(path) {
83
+ assertValidVirtualPath(path);
84
+ const parent = parentPath(path);
85
+ const name = baseName(path);
86
+ const parentResolved = parent !== null ? resolvePath(source, state, parent) : {
87
+ found: true,
88
+ node: getRootNode(state)
89
+ };
90
+ if (!parentResolved.found || parentResolved.node === null) throw new VirtualPathNotFoundError(parent ?? path);
91
+ const parentNode = parentResolved.node;
92
+ if (parentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(parent ?? path);
93
+ const existing = resolveChild(source, state, parentNode, parent ?? "", name);
94
+ if (existing.found && existing.node !== null) throw new VirtualPathAlreadyExistsError(path);
95
+ const nodeId = createNodeId();
96
+ const newNode = {
97
+ id: nodeId,
98
+ origin: { kind: "none" },
99
+ state: {
100
+ kind: "directory",
101
+ overlay: {
102
+ addedEntries: /* @__PURE__ */ new Map(),
103
+ deletedNames: /* @__PURE__ */ new Set()
104
+ }
105
+ }
106
+ };
107
+ state.nodes.set(nodeId, newNode);
108
+ updateParentOverlay(state, parentNode.id, overlayBindEntry(parentNode.state.overlay, name, nodeId));
109
+ state.changeLog.append({
110
+ op: "add",
111
+ path
112
+ });
113
+ },
114
+ writeFile(path, content, options) {
115
+ assertValidVirtualPath(path);
116
+ const mode = options?.mode ?? "100644";
117
+ const parent = parentPath(path);
118
+ const name = baseName(path);
119
+ const parentResolved = parent !== null ? resolvePath(source, state, parent) : {
120
+ found: true,
121
+ node: getRootNode(state)
122
+ };
123
+ if (!parentResolved.found || parentResolved.node === null) throw new VirtualPathNotFoundError(parent ?? path);
124
+ const parentNode = parentResolved.node;
125
+ if (parentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(parent ?? path);
126
+ const existing = resolveChild(source, state, parentNode, parent ?? "", name);
127
+ if (existing.found && existing.node !== null) {
128
+ if (existing.node.state.kind === "directory") throw new VirtualNotFileError(path);
129
+ }
130
+ const isNew = !existing.found || existing.node === null;
131
+ const nodeId = existing.found ? existing.node.id : createNodeId();
132
+ const fileNode = {
133
+ id: nodeId,
134
+ origin: existing.found ? existing.node.origin : { kind: "none" },
135
+ state: {
136
+ kind: "file",
137
+ mode,
138
+ content
139
+ }
140
+ };
141
+ state.nodes.set(nodeId, fileNode);
142
+ updateParentOverlay(state, parentNode.id, overlayBindEntry(parentNode.state.overlay, name, nodeId));
143
+ state.changeLog.append({
144
+ op: isNew ? "add" : "modify",
145
+ path
146
+ });
147
+ },
148
+ writeLink(path, target) {
149
+ assertValidVirtualPath(path);
150
+ const parent = parentPath(path);
151
+ const name = baseName(path);
152
+ const parentResolved = parent !== null ? resolvePath(source, state, parent) : {
153
+ found: true,
154
+ node: getRootNode(state)
155
+ };
156
+ if (!parentResolved.found || parentResolved.node === null) throw new VirtualPathNotFoundError(parent ?? path);
157
+ const parentNode = parentResolved.node;
158
+ if (parentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(parent ?? path);
159
+ const existing = resolveChild(source, state, parentNode, parent ?? "", name);
160
+ if (existing.found && existing.node !== null) {
161
+ if (existing.node.state.kind === "directory") throw new VirtualNotFileError(path);
162
+ }
163
+ const isNew = !existing.found || existing.node === null;
164
+ const nodeId = existing.found ? existing.node.id : createNodeId();
165
+ const linkNode = {
166
+ id: nodeId,
167
+ origin: existing.found ? existing.node.origin : { kind: "none" },
168
+ state: {
169
+ kind: "symlink",
170
+ mode: "120000",
171
+ target: Buffer.from(target)
172
+ }
173
+ };
174
+ state.nodes.set(nodeId, linkNode);
175
+ updateParentOverlay(state, parentNode.id, overlayBindEntry(parentNode.state.overlay, name, nodeId));
176
+ state.changeLog.append({
177
+ op: isNew ? "add" : "modify",
178
+ path
179
+ });
180
+ },
181
+ delete(path) {
182
+ assertValidVirtualPath(path);
183
+ const parent = parentPath(path);
184
+ const name = baseName(path);
185
+ const parentResolved = parent !== null ? resolvePath(source, state, parent) : {
186
+ found: true,
187
+ node: getRootNode(state)
188
+ };
189
+ if (!parentResolved.found || parentResolved.node === null) throw new VirtualPathNotFoundError(parent ?? path);
190
+ const parentNode = parentResolved.node;
191
+ if (parentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(parent ?? path);
192
+ const existing = resolveChild(source, state, parentNode, parent ?? "", name);
193
+ if (!existing.found || existing.node === null) throw new VirtualPathNotFoundError(path);
194
+ updateParentOverlay(state, parentNode.id, overlayTombstoneEntry(parentNode.state.overlay, name));
195
+ state.changeLog.append({
196
+ op: "delete",
197
+ path
198
+ });
199
+ },
200
+ rename(from, to) {
201
+ assertValidVirtualPath(from);
202
+ assertValidVirtualPath(to);
203
+ if (from === to) return;
204
+ const fromParent = parentPath(from);
205
+ const fromName = baseName(from);
206
+ const fromParentResolved = fromParent !== null ? resolvePath(source, state, fromParent) : {
207
+ found: true,
208
+ node: getRootNode(state)
209
+ };
210
+ if (!fromParentResolved.found || fromParentResolved.node === null) throw new VirtualPathNotFoundError(from);
211
+ const fromParentNode = fromParentResolved.node;
212
+ if (fromParentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(from);
213
+ const fromChild = resolveChild(source, state, fromParentNode, fromParent ?? "", fromName);
214
+ if (!fromChild.found || fromChild.node === null) throw new VirtualPathNotFoundError(from);
215
+ const sourceNode = fromChild.node;
216
+ const toParent = parentPath(to);
217
+ const toName = baseName(to);
218
+ const toParentResolved = toParent !== null ? resolvePath(source, state, toParent) : {
219
+ found: true,
220
+ node: getRootNode(state)
221
+ };
222
+ if (!toParentResolved.found || toParentResolved.node === null) throw new VirtualPathNotFoundError(to);
223
+ const toParentNode = toParentResolved.node;
224
+ if (toParentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(to);
225
+ const toExisting = resolveChild(source, state, toParentNode, toParent ?? "", toName);
226
+ if (toExisting.found && toExisting.node !== null) throw new VirtualPathAlreadyExistsError(to);
227
+ if (sourceNode.state.kind === "directory") {
228
+ const toPath = to;
229
+ const fromPath = from;
230
+ if (toPath.startsWith(fromPath + "/") || toPath === fromPath) throw new Error(`Cannot rename '${from}' to '${to}': destination is a subdirectory of source`);
231
+ }
232
+ if (fromParentNode.id === toParentNode.id) updateParentOverlay(state, fromParentNode.id, overlayRenameEntry(fromParentNode.state.overlay, fromName, toName, sourceNode.id));
233
+ else {
234
+ updateParentOverlay(state, fromParentNode.id, overlayTombstoneEntry(fromParentNode.state.overlay, fromName));
235
+ updateParentOverlay(state, toParentNode.id, overlayBindEntry(toParentNode.state.overlay, toName, sourceNode.id));
236
+ }
237
+ state.changeLog.append({
238
+ op: "rename",
239
+ from,
240
+ to
241
+ });
242
+ },
243
+ copy(from, to) {
244
+ assertValidVirtualPath(from);
245
+ assertValidVirtualPath(to);
246
+ if (from === to) throw new VirtualPathAlreadyExistsError(to);
247
+ const fromParent = parentPath(from);
248
+ const fromName = baseName(from);
249
+ const fromParentResolved = fromParent !== null ? resolvePath(source, state, fromParent) : {
250
+ found: true,
251
+ node: getRootNode(state)
252
+ };
253
+ if (!fromParentResolved.found || fromParentResolved.node === null) throw new VirtualPathNotFoundError(from);
254
+ const fromParentNode = fromParentResolved.node;
255
+ if (fromParentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(from);
256
+ const fromChild = resolveChild(source, state, fromParentNode, fromParent ?? "", fromName);
257
+ if (!fromChild.found || fromChild.node === null) throw new VirtualPathNotFoundError(from);
258
+ const sourceNode = fromChild.node;
259
+ const toParent = parentPath(to);
260
+ const toName = baseName(to);
261
+ const toParentResolved = toParent !== null ? resolvePath(source, state, toParent) : {
262
+ found: true,
263
+ node: getRootNode(state)
264
+ };
265
+ if (!toParentResolved.found || toParentResolved.node === null) throw new VirtualPathNotFoundError(to);
266
+ const toParentNode = toParentResolved.node;
267
+ if (toParentNode.state.kind !== "directory") throw new VirtualNotDirectoryError(to);
268
+ const toExisting = resolveChild(source, state, toParentNode, toParent ?? "", toName);
269
+ if (toExisting.found && toExisting.node !== null) throw new VirtualPathAlreadyExistsError(to);
270
+ const newNodeId = cloneNodeGraphForCopy(source, state, sourceNode, from);
271
+ updateParentOverlay(state, toParentNode.id, overlayBindEntry(toParentNode.state.overlay, toName, newNodeId));
272
+ state.changeLog.append({
273
+ op: "copy",
274
+ from,
275
+ to
276
+ });
277
+ },
278
+ revert(path) {
279
+ assertValidVirtualPath(path);
280
+ const resolved = resolvePath(source, state, path);
281
+ if (!resolved.found || resolved.node === null) throw new VirtualPathNotFoundError(path);
282
+ const node = resolved.node;
283
+ const reverted = revertNodeState(node);
284
+ if (reverted === node) throw new VirtualRevertNotSupportedError(path);
285
+ state.nodes.set(node.id, reverted);
286
+ state.changeLog.append({
287
+ op: "revert",
288
+ path
289
+ });
290
+ },
291
+ writeTree() {
292
+ return writeTreeFromSession(source, state);
293
+ },
294
+ reset(baseTree) {
295
+ state.baseTree = baseTree;
296
+ state.nodes.clear();
297
+ state.nodes.set(VIRTUAL_ROOT_NODE_ID, createRootDirectoryNode(baseTree));
298
+ state.changeLog.clear();
299
+ },
300
+ listChanges() {
301
+ return state.changeLog.toVirtualChanges();
302
+ }
303
+ };
304
+ }
305
+ function getRootNode(state) {
306
+ const root = state.nodes.get(VIRTUAL_ROOT_NODE_ID);
307
+ if (root === void 0) throw new Error("Virtual workdir session is missing root node");
308
+ return root;
309
+ }
310
+ /**
311
+ * 更新父节点的 overlay(创建新节点对象替代 Map 中的旧引用)
312
+ */
313
+ function updateParentOverlay(state, parentId, newOverlay) {
314
+ const parentNode = state.nodes.get(parentId);
315
+ if (!parentNode || parentNode.state.kind !== "directory") throw new Error("updateParentOverlay: parent is not a directory");
316
+ state.nodes.set(parentId, {
317
+ ...parentNode,
318
+ state: {
319
+ ...parentNode.state,
320
+ overlay: newOverlay
321
+ }
322
+ });
323
+ }
324
+ function statNode(source, node, path) {
325
+ if (node.state.kind === "directory") return statDirectoryNode(node);
326
+ if (node.state.kind === "symlink") {
327
+ const hash = node.origin.kind === "repo-blob" ? node.origin.hash : null;
328
+ let size = 0;
329
+ if (node.state.target !== void 0) size = node.state.target.length;
330
+ else if (hash !== null) size = readRepoBlobContent(source, hash, path).length;
331
+ return {
332
+ kind: "symlink",
333
+ mode: "120000",
334
+ size,
335
+ hash
336
+ };
337
+ }
338
+ const hash = node.origin.kind === "repo-blob" ? node.origin.hash : null;
339
+ let size = 0;
340
+ if (node.state.content !== void 0) size = node.state.content.length;
341
+ else if (hash !== null) size = readRepoBlobContent(source, hash, path).length;
342
+ return {
343
+ kind: "blob",
344
+ mode: node.state.mode,
345
+ size,
346
+ hash
347
+ };
348
+ }
349
+ function statDirectoryNode(node) {
350
+ return {
351
+ kind: "tree",
352
+ mode: "40000",
353
+ size: 0,
354
+ hash: node.origin.kind === "repo-tree" ? node.origin.hash : null
355
+ };
356
+ }
357
+ function cloneNodeGraphForCopy(source, state, node, path) {
358
+ const newNodeId = createNodeId();
359
+ const cloned = cloneSessionNodeForCopy(node, newNodeId);
360
+ state.nodes.set(newNodeId, cloned);
361
+ if (node.state.kind !== "directory" || cloned.state.kind !== "directory") return newNodeId;
362
+ let overlay = cloned.state.overlay;
363
+ const children = listDirectoryChildren(source, state, node, path);
364
+ for (const child of children) {
365
+ const childNode = state.nodes.get(child.nodeId);
366
+ if (childNode === void 0) continue;
367
+ const clonedChildId = cloneNodeGraphForCopy(source, state, childNode, path === "" ? child.name : `${path}/${child.name}`);
368
+ overlay = overlayBindEntry(overlay, child.name, clonedChildId);
369
+ }
370
+ state.nodes.set(newNodeId, {
371
+ ...cloned,
372
+ state: {
373
+ kind: "directory",
374
+ overlay
375
+ }
376
+ });
377
+ return newNodeId;
378
+ }
379
+ //#endregion
380
+ export { createVirtualWorkdirSession };
@@ -0,0 +1,97 @@
1
+ import { writeObject } from "../objects/raw.mjs";
2
+ import { isDirectoryOverlayDirty } from "./nodes.mjs";
3
+ import { listDirectoryChildren } from "./session-internal.mjs";
4
+ //#region src/workdir/write-tree.ts
5
+ /**
6
+ * Virtual Workdir overlay -> tree 最小化编译
7
+ *
8
+ * 遍历 session 的目录 overlay,将受影响的目录重写为新 tree,
9
+ * 未修改的 repo-backed 子树/文件尽量复用原对象哈希。
10
+ *
11
+ * writeTree() 成功后不清空 overlay,不推进 baseTree。
12
+ */
13
+ /**
14
+ * 将当前 session 状态编译为新的根 tree
15
+ *
16
+ * 只重写受 overlay 影响的目录;文件/符号链接仅在 materialized 时写新 blob。
17
+ * 未修改的 repo-backed 条目直接复用 origin hash。
18
+ *
19
+ * @param source - 可写对象数据库(用于写入新 blob/tree)
20
+ * @param state - session 内存状态
21
+ * @returns 新根 tree 的 SHA-1
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const rootHash = writeTreeFromSession(repo.objects, state);
26
+ * ```
27
+ */
28
+ function writeTreeFromSession(source, state) {
29
+ const root = state.nodes.get("root");
30
+ if (!root || root.state.kind !== "directory") throw new Error("Virtual workdir: root node is missing or not a directory");
31
+ return compileDirectory(source, source, state, root);
32
+ }
33
+ /**
34
+ * 递归编译目录 overlay -> 新 tree
35
+ *
36
+ * 返回新 tree 的 SHA-1(若目录无任何变化则直接复用 origin hash)。
37
+ */
38
+ function compileDirectory(writeSource, readSource, state, dirNode) {
39
+ if (dirNode.state.kind !== "directory") throw new Error("compileDirectory called on non-directory node");
40
+ const children = listDirectoryChildren(readSource, state, dirNode, "");
41
+ let anyChanged = false;
42
+ const newEntries = [];
43
+ for (const child of children) {
44
+ const node = state.nodes.get(child.nodeId);
45
+ if (!node) continue;
46
+ if (node.state.kind === "directory") {
47
+ const newHash = compileDirectory(writeSource, readSource, state, node);
48
+ if (newHash !== (node.origin.kind === "repo-tree" ? node.origin.hash : null)) anyChanged = true;
49
+ newEntries.push({
50
+ mode: "40000",
51
+ name: child.name,
52
+ hash: newHash
53
+ });
54
+ } else if (node.state.kind === "file") {
55
+ if (node.state.content !== void 0) {
56
+ const hash = writeObject(writeSource, {
57
+ type: "blob",
58
+ content: node.state.content
59
+ });
60
+ anyChanged = true;
61
+ newEntries.push({
62
+ mode: node.state.mode,
63
+ name: child.name,
64
+ hash
65
+ });
66
+ } else if (node.origin.kind === "repo-blob") newEntries.push({
67
+ mode: node.state.mode,
68
+ name: child.name,
69
+ hash: node.origin.hash
70
+ });
71
+ } else if (node.state.target !== void 0) {
72
+ const hash = writeObject(writeSource, {
73
+ type: "blob",
74
+ content: node.state.target
75
+ });
76
+ anyChanged = true;
77
+ newEntries.push({
78
+ mode: "120000",
79
+ name: child.name,
80
+ hash
81
+ });
82
+ } else if (node.origin.kind === "repo-blob") newEntries.push({
83
+ mode: "120000",
84
+ name: child.name,
85
+ hash: node.origin.hash
86
+ });
87
+ }
88
+ if (isDirectoryOverlayDirty(dirNode.state.overlay)) anyChanged = true;
89
+ if (!anyChanged && dirNode.origin.kind === "repo-tree") return dirNode.origin.hash;
90
+ newEntries.sort((a, b) => a.name.localeCompare(b.name));
91
+ return writeObject(writeSource, {
92
+ type: "tree",
93
+ entries: newEntries
94
+ });
95
+ }
96
+ //#endregion
97
+ export { writeTreeFromSession };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-git",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -11,11 +11,14 @@
11
11
  "./backend": "./src/backend/index.ts",
12
12
  "./backend/file": "./src/backend/file.ts",
13
13
  "./backend/memory": "./src/backend/memory.ts",
14
+ "./backend/sqlite": "./src/backend/sqlite.ts",
14
15
  "./errors": "./src/errors.ts",
15
16
  "./hash-file": "./src/hash-file.ts",
17
+ "./log": "./src/log/index.ts",
16
18
  "./objects": "./src/objects/index.ts",
17
19
  "./odb/file": "./src/odb/file.ts",
18
20
  "./odb/memory": "./src/odb/memory.ts",
21
+ "./odb/sqlite": "./src/odb/sqlite.ts",
19
22
  "./pack": "./src/pack/index.ts",
20
23
  "./refs/file": "./src/refs/file.ts",
21
24
  "./refs/memory": "./src/refs/memory.ts",
@@ -23,9 +26,13 @@
23
26
  "./refs/resolve": "./src/refs/resolve.ts",
24
27
  "./refs/shallow/file": "./src/refs/shallow/file.ts",
25
28
  "./refs/shallow/memory": "./src/refs/shallow/memory.ts",
29
+ "./refs/shallow/sqlite": "./src/refs/shallow/sqlite.ts",
30
+ "./refs/sqlite": "./src/refs/sqlite.ts",
31
+ "./remote/http": "./src/remote/http.ts",
26
32
  "./repository/core": "./src/repository/core.ts",
27
33
  "./repository/file": "./src/repository/file.ts",
28
34
  "./repository/memory": "./src/repository/memory.ts",
35
+ "./repository/sqlite": "./src/repository/sqlite.ts",
29
36
  "./repository/tree/tree-patch": "./src/repository/tree/tree-patch.ts",
30
37
  "./repository/tree/tree-walk": "./src/repository/tree/tree-walk.ts",
31
38
  "./sha1": "./src/sha1.ts",
@@ -34,7 +41,9 @@
34
41
  "./transport/receive-pack": "./src/transport/receive-pack.ts",
35
42
  "./transport/server/receive-pack": "./src/transport/server/receive-pack/index.ts",
36
43
  "./transport/server/upload-pack": "./src/transport/server/upload-pack/index.ts",
37
- "./transport/upload-pack": "./src/transport/upload-pack.ts"
44
+ "./transport/upload-pack": "./src/transport/upload-pack.ts",
45
+ "./workdir/core": "./src/workdir/core.ts",
46
+ "./workdir/memory": "./src/workdir/memory.ts"
38
47
  },
39
48
  "publishConfig": {
40
49
  "exports": {
@@ -42,11 +51,14 @@
42
51
  "./backend": "./dist/backend/index.mjs",
43
52
  "./backend/file": "./dist/backend/file.mjs",
44
53
  "./backend/memory": "./dist/backend/memory.mjs",
54
+ "./backend/sqlite": "./dist/backend/sqlite.mjs",
45
55
  "./errors": "./dist/errors.mjs",
46
56
  "./hash-file": "./dist/hash-file.mjs",
57
+ "./log": "./dist/log/index.mjs",
47
58
  "./objects": "./dist/objects/index.mjs",
48
59
  "./odb/file": "./dist/odb/file.mjs",
49
60
  "./odb/memory": "./dist/odb/memory.mjs",
61
+ "./odb/sqlite": "./dist/odb/sqlite.mjs",
50
62
  "./pack": "./dist/pack/index.mjs",
51
63
  "./refs/file": "./dist/refs/file.mjs",
52
64
  "./refs/memory": "./dist/refs/memory.mjs",
@@ -54,9 +66,13 @@
54
66
  "./refs/resolve": "./dist/refs/resolve.mjs",
55
67
  "./refs/shallow/file": "./dist/refs/shallow/file.mjs",
56
68
  "./refs/shallow/memory": "./dist/refs/shallow/memory.mjs",
69
+ "./refs/shallow/sqlite": "./dist/refs/shallow/sqlite.mjs",
70
+ "./refs/sqlite": "./dist/refs/sqlite.mjs",
71
+ "./remote/http": "./dist/remote/http.mjs",
57
72
  "./repository/core": "./dist/repository/core.mjs",
58
73
  "./repository/file": "./dist/repository/file.mjs",
59
74
  "./repository/memory": "./dist/repository/memory.mjs",
75
+ "./repository/sqlite": "./dist/repository/sqlite.mjs",
60
76
  "./repository/tree/tree-patch": "./dist/repository/tree/tree-patch.mjs",
61
77
  "./repository/tree/tree-walk": "./dist/repository/tree/tree-walk.mjs",
62
78
  "./sha1": "./dist/sha1.mjs",
@@ -65,7 +81,9 @@
65
81
  "./transport/receive-pack": "./dist/transport/receive-pack.mjs",
66
82
  "./transport/server/receive-pack": "./dist/transport/server/receive-pack/index.mjs",
67
83
  "./transport/server/upload-pack": "./dist/transport/server/upload-pack/index.mjs",
68
- "./transport/upload-pack": "./dist/transport/upload-pack.mjs"
84
+ "./transport/upload-pack": "./dist/transport/upload-pack.mjs",
85
+ "./workdir/core": "./dist/workdir/core.mjs",
86
+ "./workdir/memory": "./dist/workdir/memory.mjs"
69
87
  }
70
88
  },
71
89
  "scripts": {