nano-git 0.3.3 → 0.3.4

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.
@@ -140,10 +140,23 @@ interface VirtualWorkdir {
140
140
  }): void;
141
141
  /** 写入符号链接(新建或覆盖) */
142
142
  writeLink(path: string, target: string): void;
143
- /** 创建目录(含必要父目录) */
144
- mkdir(path: string): void;
145
- /** 删除路径(文件、目录或符号链接) */
146
- delete(path: string): void;
143
+ /**
144
+ * 创建目录
145
+ *
146
+ * 默认要求各级父目录已存在;`recursive: true` 时自动创建缺失的父目录,
147
+ * 且目标路径已是目录时不报错。路径上任意段为文件(非目录)时抛出 `VirtualNotDirectoryError`。
148
+ */
149
+ mkdir(path: string, options?: {
150
+ readonly recursive?: boolean;
151
+ }): void;
152
+ /**
153
+ * 删除路径(文件、目录或符号链接)
154
+ *
155
+ * 默认要求路径已存在;`force: true` 时路径不存在则静默忽略(与 Node `fs.rm` 的 `force` 语义一致)。
156
+ */
157
+ delete(path: string, options?: {
158
+ readonly force?: boolean;
159
+ }): void;
147
160
  /**
148
161
  * 重命名路径
149
162
  *
@@ -2,7 +2,7 @@ import { VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError,
2
2
  import { createNodeId } from "./ids.mjs";
3
3
  import { modeToVirtualEntryKind, readRepoBlobContent } from "./origin.mjs";
4
4
  import { overlayBindEntry, overlayRenameEntry, overlayTombstoneEntry } from "./overlay.mjs";
5
- import { assertValidVirtualPath, normalizeDirectoryPath } from "./path.mjs";
5
+ import { assertValidVirtualPath, normalizeDirectoryPath, splitPathSegments } from "./path.mjs";
6
6
  import { getDirectoryChildrenView, getRootNode, requireExistingWriteTarget, requireMissingWriteTarget, resolveLeafWriteTarget, resolvePath, resolveWriteTransfer } from "./workdir-path.mjs";
7
7
  import { createChangeIndexPlanner } from "./change-index-plan.mjs";
8
8
  import { computeVirtualDiff, rebuildNormalizedChangeIndex, refreshChangeRecordForPath, replaceChangeRecords, rewriteChangeRecordForRename, writeChangeRecordForCopy } from "./change-index.mjs";
@@ -90,6 +90,35 @@ function openVirtualWorkdir(source, state) {
90
90
  });
91
91
  const dirtyDirPlanner = createDirtyDirPlanner(source, state);
92
92
  refreshChangeIndex();
93
+ const createDirectoryAtPath = (path) => {
94
+ const target = requireMissingWriteTarget(source, state, 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.setNode(newNode);
108
+ updateParentOverlay(state, target.parentNode.id, overlayBindEntry(target.parentNode.state.overlay, target.name, nodeId));
109
+ };
110
+ const mkdirRecursive = (path) => {
111
+ const segments = splitPathSegments(path);
112
+ for (let i = 0; i < segments.length; i++) {
113
+ const partialPath = segments.slice(0, i + 1).join("/");
114
+ const resolved = resolvePath(source, state, partialPath);
115
+ if (resolved.found && resolved.node !== null) {
116
+ if (resolved.node.state.kind !== "directory") throw new VirtualNotDirectoryError(partialPath);
117
+ continue;
118
+ }
119
+ createDirectoryAtPath(partialPath);
120
+ }
121
+ };
93
122
  return {
94
123
  get baseTree() {
95
124
  return state.readBaseTree();
@@ -141,23 +170,18 @@ function openVirtualWorkdir(source, state) {
141
170
  if (node.origin.kind === "repo-blob") return readRepoBlobContent(source, node.origin.hash, path).toString("utf-8");
142
171
  throw new VirtualPathNotFoundError(path);
143
172
  },
144
- mkdir(path) {
145
- runInWriteTransaction(state, () => dirtyDirPlanner.rebuild([path]), invalidateDiffCaches, () => {
146
- const target = requireMissingWriteTarget(source, state, path);
147
- const nodeId = createNodeId();
148
- const newNode = {
149
- id: nodeId,
150
- origin: { kind: "none" },
151
- state: {
152
- kind: "directory",
153
- overlay: {
154
- addedEntries: /* @__PURE__ */ new Map(),
155
- deletedNames: /* @__PURE__ */ new Set()
156
- }
157
- }
158
- };
159
- state.setNode(newNode);
160
- updateParentOverlay(state, target.parentNode.id, overlayBindEntry(target.parentNode.state.overlay, target.name, nodeId));
173
+ mkdir(path, options) {
174
+ const recursive = options?.recursive === true;
175
+ runInWriteTransaction(state, () => {
176
+ if (recursive) {
177
+ const segments = splitPathSegments(path);
178
+ const paths = [];
179
+ for (let i = 0; i < segments.length; i++) paths.push(segments.slice(0, i + 1).join("/"));
180
+ dirtyDirPlanner.rebuild(paths);
181
+ } else dirtyDirPlanner.rebuild([path]);
182
+ }, invalidateDiffCaches, () => {
183
+ if (recursive) mkdirRecursive(path);
184
+ else createDirectoryAtPath(path);
161
185
  });
162
186
  },
163
187
  writeFile(path, content, options) {
@@ -201,7 +225,10 @@ function openVirtualWorkdir(source, state) {
201
225
  if (writeTarget.existing === null || writeTarget.parentNode.state.overlay.addedEntries.has(writeTarget.name)) updateParentOverlay(state, writeTarget.parentNode.id, overlayBindEntry(writeTarget.parentNode.state.overlay, writeTarget.name, nodeId));
202
226
  });
203
227
  },
204
- delete(path) {
228
+ delete(path, options) {
229
+ if (options?.force === true) {
230
+ if (path !== "" && !resolvePath(source, state, path).found) return;
231
+ }
205
232
  runInWriteTransaction(state, () => {
206
233
  changeIndexPlanner.apply(changeIndexPlanner.planRefreshForPath(path, { treatMissingAsIncremental: true }));
207
234
  dirtyDirPlanner.rebuild([path]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-git",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "files": [
5
5
  "dist"
6
6
  ],