@wener/common 2.0.3 → 2.0.6

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 (312) hide show
  1. package/lib/ai/qwen3vl/index.js +1 -1
  2. package/lib/ai/qwen3vl/utils.js +15 -15
  3. package/lib/ai/qwen3vl/utils.js.map +1 -1
  4. package/lib/ai/vision/DocLayoutElementTypeSchema.js +22 -22
  5. package/lib/ai/vision/ImageAnnotationSchema.js +63 -47
  6. package/lib/ai/vision/index.js +2 -2
  7. package/lib/ai/vision/resolveImageAnnotation.js +81 -95
  8. package/lib/cn/ChineseResidentIdNo.js +55 -41
  9. package/lib/cn/ChineseResidentIdNo.js.map +1 -1
  10. package/lib/cn/ChineseResidentIdNo.mod.js +6 -1
  11. package/lib/cn/ChineseResidentIdNo.test.js +22 -21
  12. package/lib/cn/DivisionCode.js +220 -235
  13. package/lib/cn/DivisionCode.mod.js +6 -1
  14. package/lib/cn/DivisionCode.test.js +92 -121
  15. package/lib/cn/Mod11.js +18 -37
  16. package/lib/cn/Mod11.js.map +1 -1
  17. package/lib/cn/Mod31.js +23 -41
  18. package/lib/cn/UnifiedSocialCreditCode.js +143 -137
  19. package/lib/cn/UnifiedSocialCreditCode.mod.js +6 -1
  20. package/lib/cn/UnifiedSocialCreditCode.test.js +21 -15
  21. package/lib/cn/formatChineseAmount.js +46 -71
  22. package/lib/cn/index.js +6 -6
  23. package/lib/cn/mod.js +5 -3
  24. package/lib/cn/parseChineseNumber.js +81 -85
  25. package/lib/cn/parseChineseNumber.test.js +183 -261
  26. package/lib/cn/pinyin/cartesianProduct.js +19 -19
  27. package/lib/cn/pinyin/cartesianProduct.test.js +78 -178
  28. package/lib/cn/pinyin/loader.js +13 -11
  29. package/lib/cn/pinyin/preload.js +2 -1
  30. package/lib/cn/pinyin/toPinyin.test.js +149 -161
  31. package/lib/cn/pinyin/toPinyinPure.js +28 -23
  32. package/lib/cn/pinyin/transform.js +11 -11
  33. package/lib/cn/types.d.js +2 -2
  34. package/lib/consola/createStandardConsolaReporter.js +14 -15
  35. package/lib/consola/formatLogObject.js +149 -133
  36. package/lib/consola/formatLogObject.js.map +1 -1
  37. package/lib/consola/formatLogObject.test.js +167 -178
  38. package/lib/consola/index.js +2 -2
  39. package/lib/data/formatSort.js +14 -12
  40. package/lib/data/formatSort.test.js +33 -33
  41. package/lib/data/index.js +3 -3
  42. package/lib/data/maybeNumber.js +23 -23
  43. package/lib/data/maybeNumber.js.map +1 -1
  44. package/lib/data/parseSort.js +75 -68
  45. package/lib/data/parseSort.test.js +196 -187
  46. package/lib/data/resolvePagination.js +38 -39
  47. package/lib/data/resolvePagination.test.js +228 -218
  48. package/lib/data/types.d.js +2 -2
  49. package/lib/data/types.d.js.map +1 -1
  50. package/lib/dayjs/dayjs.js +20 -20
  51. package/lib/dayjs/formatDuration.js +56 -56
  52. package/lib/dayjs/formatDuration.js.map +1 -1
  53. package/lib/dayjs/formatDuration.test.js +63 -77
  54. package/lib/dayjs/index.js +4 -4
  55. package/lib/dayjs/parseDuration.js +21 -26
  56. package/lib/dayjs/parseRelativeTime.js +65 -66
  57. package/lib/dayjs/parseRelativeTime.test.js +227 -243
  58. package/lib/dayjs/resolveRelativeTime.js +74 -144
  59. package/lib/dayjs/resolveRelativeTime.js.map +1 -1
  60. package/lib/dayjs/resolveRelativeTime.test.js +296 -307
  61. package/lib/decimal/index.js +1 -1
  62. package/lib/decimal/parseDecimal.js +12 -12
  63. package/lib/drain3/Drain.js +321 -0
  64. package/lib/drain3/Drain.js.map +1 -0
  65. package/lib/drain3/LogCluster.js +38 -0
  66. package/lib/drain3/LogCluster.js.map +1 -0
  67. package/lib/drain3/Node.js +39 -0
  68. package/lib/drain3/Node.js.map +1 -0
  69. package/lib/drain3/TemplateMiner.js +205 -0
  70. package/lib/drain3/TemplateMiner.js.map +1 -0
  71. package/lib/drain3/index.js +31 -0
  72. package/lib/drain3/index.js.map +1 -0
  73. package/lib/drain3/persistence/FilePersistence.js +24 -0
  74. package/lib/drain3/persistence/FilePersistence.js.map +1 -0
  75. package/lib/drain3/persistence/MemoryPersistence.js +18 -0
  76. package/lib/drain3/persistence/MemoryPersistence.js.map +1 -0
  77. package/lib/drain3/persistence/PersistenceHandler.js +5 -0
  78. package/lib/drain3/persistence/PersistenceHandler.js.map +1 -0
  79. package/lib/drain3/types.js +7 -0
  80. package/lib/drain3/types.js.map +1 -0
  81. package/lib/emittery/emitter.js +7 -7
  82. package/lib/emittery/index.js +1 -1
  83. package/lib/foundation/schema/SexType.js +15 -12
  84. package/lib/foundation/schema/index.js +1 -1
  85. package/lib/foundation/schema/parseSexType.js +15 -16
  86. package/lib/foundation/schema/types.js +8 -6
  87. package/lib/fs/FileSystemError.js +18 -18
  88. package/lib/fs/IFileSystem.d.js +2 -2
  89. package/lib/fs/IFileSystem.d.js.map +1 -1
  90. package/lib/fs/MemoryFileSystem.test.js +172 -181
  91. package/lib/fs/createBrowserFileSystem.js +222 -233
  92. package/lib/fs/createBrowserFileSystem.js.map +1 -1
  93. package/lib/fs/createMemoryFileSystem.js +473 -510
  94. package/lib/fs/createMemoryFileSystem.js.map +1 -1
  95. package/lib/fs/createSandboxFileSystem.js +102 -101
  96. package/lib/fs/createSandboxFileSystem.js.map +1 -1
  97. package/lib/fs/createWebDavFileSystem.js +162 -132
  98. package/lib/fs/createWebDavFileSystem.js.map +1 -1
  99. package/lib/fs/createWebFileSystem.js +202 -0
  100. package/lib/fs/createWebFileSystem.js.map +1 -0
  101. package/lib/fs/findMimeType.js +14 -14
  102. package/lib/fs/findMimeType.js.map +1 -1
  103. package/lib/fs/index.js +7 -7
  104. package/lib/fs/index.js.map +1 -1
  105. package/lib/fs/minio/createMinioFileSystem.js +977 -0
  106. package/lib/fs/minio/createMinioFileSystem.js.map +1 -0
  107. package/lib/fs/minio/index.js +2 -0
  108. package/lib/fs/minio/index.js.map +1 -0
  109. package/lib/fs/orpc/FileSystemContract.js +57 -57
  110. package/lib/fs/orpc/createContractClientFileSystem.js +88 -88
  111. package/lib/fs/orpc/createContractClientFileSystem.js.map +1 -1
  112. package/lib/fs/orpc/index.js +2 -2
  113. package/lib/fs/orpc/server/createFileSystemContractImpl.js +62 -60
  114. package/lib/fs/orpc/server/createFileSystemContractImpl.js.map +1 -1
  115. package/lib/fs/orpc/server/index.js +1 -1
  116. package/lib/fs/s3/createS3MiniFileSystem.js +756 -689
  117. package/lib/fs/s3/createS3MiniFileSystem.js.map +1 -1
  118. package/lib/fs/s3/index.js +1 -1
  119. package/lib/fs/s3/s3mini.test.js +524 -553
  120. package/lib/fs/scandir.js +56 -56
  121. package/lib/fs/server/createDatabaseFileSystem.js +834 -741
  122. package/lib/fs/server/createDatabaseFileSystem.js.map +1 -1
  123. package/lib/fs/server/createNodeFileSystem.js +407 -380
  124. package/lib/fs/server/createNodeFileSystem.js.map +1 -1
  125. package/lib/fs/server/dbfs.test.js +201 -214
  126. package/lib/fs/server/index.js +1 -1
  127. package/lib/fs/server/loadTestDatabase.js +40 -43
  128. package/lib/fs/tests/runFileSystemTest.js +352 -315
  129. package/lib/fs/tests/runFileSystemTest.js.map +1 -1
  130. package/lib/fs/types.js +17 -20
  131. package/lib/fs/utils/getFileUrl.js +24 -30
  132. package/lib/fs/utils.js +17 -17
  133. package/lib/fs/utils.js.map +1 -1
  134. package/lib/fs/webdav/index.js +2 -0
  135. package/lib/fs/webdav/index.js.map +1 -0
  136. package/lib/index.js +2 -2
  137. package/lib/jsonschema/JsonSchema.js +216 -155
  138. package/lib/jsonschema/JsonSchema.js.map +1 -1
  139. package/lib/jsonschema/JsonSchema.test.js +123 -124
  140. package/lib/jsonschema/forEachJsonSchema.js +41 -41
  141. package/lib/jsonschema/forEachJsonSchema.js.map +1 -1
  142. package/lib/jsonschema/index.js +2 -2
  143. package/lib/jsonschema/types.d.js +2 -2
  144. package/lib/jsonschema/types.d.js.map +1 -1
  145. package/lib/meta/defineFileType.js +32 -38
  146. package/lib/meta/defineInit.js +39 -35
  147. package/lib/meta/defineMetadata.js +37 -34
  148. package/lib/meta/defineMetadata.js.map +1 -1
  149. package/lib/meta/defineMetadata.test.js +13 -12
  150. package/lib/meta/index.js +3 -3
  151. package/lib/orpc/createOpenApiContractClient.js +26 -24
  152. package/lib/orpc/createOpenApiContractClient.js.map +1 -1
  153. package/lib/orpc/createRpcContractClient.js +37 -31
  154. package/lib/orpc/index.js +2 -2
  155. package/lib/orpc/resolveLinkPlugins.js +25 -25
  156. package/lib/password/PHC.js +187 -189
  157. package/lib/password/PHC.js.map +1 -1
  158. package/lib/password/PHC.test.js +517 -535
  159. package/lib/password/Password.js +85 -80
  160. package/lib/password/Password.test.js +330 -364
  161. package/lib/password/createArgon2PasswordAlgorithm.js +50 -51
  162. package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -1
  163. package/lib/password/createBase64PasswordAlgorithm.js +11 -11
  164. package/lib/password/createBase64PasswordAlgorithm.js.map +1 -1
  165. package/lib/password/createBcryptPasswordAlgorithm.js +20 -18
  166. package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -1
  167. package/lib/password/createPBKDF2PasswordAlgorithm.js +65 -52
  168. package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -1
  169. package/lib/password/createScryptPasswordAlgorithm.js +74 -63
  170. package/lib/password/createScryptPasswordAlgorithm.js.map +1 -1
  171. package/lib/password/index.js +5 -5
  172. package/lib/password/server/index.js +1 -1
  173. package/lib/resource/Identifiable.js +2 -2
  174. package/lib/resource/ListQuery.js +42 -42
  175. package/lib/resource/ListQuery.js.map +1 -1
  176. package/lib/resource/getTitleOfResource.js +5 -5
  177. package/lib/resource/index.js +2 -2
  178. package/lib/resource/index.js.map +1 -1
  179. package/lib/resource/schema/AnyResourceSchema.js +91 -89
  180. package/lib/resource/schema/BaseResourceSchema.js +26 -26
  181. package/lib/resource/schema/ResourceActionType.js +117 -115
  182. package/lib/resource/schema/ResourceStatus.js +94 -92
  183. package/lib/resource/schema/ResourceType.js +25 -23
  184. package/lib/resource/schema/index.js +5 -5
  185. package/lib/resource/schema/types.js +86 -55
  186. package/lib/resource/schema/types.test.js +16 -13
  187. package/lib/s3/formatS3Url.js +60 -60
  188. package/lib/s3/formatS3Url.js.map +1 -1
  189. package/lib/s3/formatS3Url.test.js +238 -261
  190. package/lib/s3/index.js +2 -2
  191. package/lib/s3/parseS3Url.js +61 -60
  192. package/lib/s3/parseS3Url.js.map +1 -1
  193. package/lib/s3/parseS3Url.test.js +270 -269
  194. package/lib/schema/SchemaRegistry.js +41 -42
  195. package/lib/schema/SchemaRegistry.js.map +1 -1
  196. package/lib/schema/SchemaRegistry.mod.js +1 -1
  197. package/lib/schema/TypeSchema.d.js +2 -2
  198. package/lib/schema/TypeSchema.d.js.map +1 -1
  199. package/lib/schema/createSchemaData.js +113 -67
  200. package/lib/schema/createSchemaData.js.map +1 -1
  201. package/lib/schema/findJsonSchemaByPath.js +28 -23
  202. package/lib/schema/findJsonSchemaByPath.js.map +1 -1
  203. package/lib/schema/formatZodError.js +113 -134
  204. package/lib/schema/formatZodError.js.map +1 -1
  205. package/lib/schema/formatZodError.test.js +192 -195
  206. package/lib/schema/getSchemaCache.js +7 -7
  207. package/lib/schema/getSchemaOptions.js +17 -16
  208. package/lib/schema/index.js +6 -6
  209. package/lib/schema/toJsonSchema.js +196 -190
  210. package/lib/schema/toJsonSchema.js.map +1 -1
  211. package/lib/schema/toJsonSchema.test.js +34 -26
  212. package/lib/schema/validate.js +106 -97
  213. package/lib/schema/validate.js.map +1 -1
  214. package/lib/tools/generateSchema.js +40 -40
  215. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +74 -74
  216. package/lib/utils/buildBaseUrl.js +8 -8
  217. package/lib/utils/buildRedactorFormSchema.js +55 -54
  218. package/lib/utils/buildRedactorFormSchema.js.map +1 -1
  219. package/lib/utils/getEstimateProcessTime.js +24 -19
  220. package/lib/utils/index.js +3 -3
  221. package/lib/utils/resolveFeatureOptions.js +9 -9
  222. package/package.json +37 -18
  223. package/src/ai/qwen3vl/utils.ts +1 -1
  224. package/src/ai/vision/index.ts +2 -2
  225. package/src/cn/ChineseResidentIdNo.ts +1 -1
  226. package/src/cn/Mod11.ts +1 -1
  227. package/src/cn/__snapshots__/ChineseResidentIdNo.test.ts.snap +1 -1
  228. package/src/cn/__snapshots__/UnifiedSocialCreditCode.test.ts.snap +0 -23
  229. package/src/cn/index.ts +1 -2
  230. package/src/cn/parseChineseNumber.test.ts +4 -4
  231. package/src/consola/formatLogObject.ts +6 -6
  232. package/src/consola/index.ts +1 -1
  233. package/src/data/index.ts +3 -4
  234. package/src/data/maybeNumber.ts +1 -1
  235. package/src/data/parseSort.test.ts +0 -1
  236. package/src/data/resolvePagination.ts +2 -2
  237. package/src/data/types.d.ts +2 -2
  238. package/src/dayjs/formatDuration.ts +10 -11
  239. package/src/dayjs/index.ts +1 -1
  240. package/src/dayjs/parseRelativeTime.ts +1 -1
  241. package/src/dayjs/resolveRelativeTime.ts +11 -14
  242. package/src/drain3/Drain.test.ts +378 -0
  243. package/src/drain3/Drain.ts +394 -0
  244. package/src/drain3/LogCluster.ts +46 -0
  245. package/src/drain3/Node.ts +53 -0
  246. package/src/drain3/TemplateMiner.ts +246 -0
  247. package/src/drain3/index.ts +34 -0
  248. package/src/drain3/persistence/FilePersistence.ts +24 -0
  249. package/src/drain3/persistence/MemoryPersistence.ts +23 -0
  250. package/src/drain3/persistence/PersistenceHandler.ts +19 -0
  251. package/src/drain3/types.ts +75 -0
  252. package/src/fs/IFileSystem.d.ts +1 -2
  253. package/src/fs/createBrowserFileSystem.ts +7 -5
  254. package/src/fs/createMemoryFileSystem.ts +9 -13
  255. package/src/fs/createSandboxFileSystem.ts +1 -1
  256. package/src/fs/createWebDavFileSystem.ts +30 -17
  257. package/src/fs/createWebFileSystem.ts +242 -0
  258. package/src/fs/findMimeType.ts +1 -4
  259. package/src/fs/index.ts +5 -5
  260. package/src/fs/minio/createMinioFileSystem.ts +1148 -0
  261. package/src/fs/minio/index.ts +1 -0
  262. package/src/fs/orpc/createContractClientFileSystem.ts +5 -5
  263. package/src/fs/orpc/server/createFileSystemContractImpl.ts +1 -1
  264. package/src/fs/s3/createS3MiniFileSystem.ts +120 -79
  265. package/src/fs/s3/s3fs.test.ts +441 -0
  266. package/src/fs/s3/s3mini.test.ts +2 -2
  267. package/src/fs/server/createDatabaseFileSystem.ts +78 -114
  268. package/src/fs/server/createNodeFileSystem.ts +32 -13
  269. package/src/fs/server/dbfs.test.ts +13 -8
  270. package/src/fs/server/index.ts +1 -0
  271. package/src/fs/server/loadTestDatabase.ts +8 -119
  272. package/src/fs/tests/runFileSystemTest.ts +29 -28
  273. package/src/fs/utils.ts +1 -1
  274. package/src/fs/webdav/index.ts +1 -0
  275. package/src/jsonschema/JsonSchema.ts +5 -5
  276. package/src/jsonschema/forEachJsonSchema.ts +1 -1
  277. package/src/jsonschema/index.ts +1 -1
  278. package/src/jsonschema/types.d.ts +1 -1
  279. package/src/meta/defineMetadata.ts +1 -1
  280. package/src/meta/index.ts +2 -3
  281. package/src/orm/createSqliteDialect.ts +17 -0
  282. package/src/orm/index.ts +1 -0
  283. package/src/orpc/createOpenApiContractClient.ts +3 -3
  284. package/src/orpc/index.ts +1 -1
  285. package/src/password/PHC.ts +3 -3
  286. package/src/password/createArgon2PasswordAlgorithm.ts +2 -2
  287. package/src/password/createBase64PasswordAlgorithm.ts +2 -2
  288. package/src/password/createBcryptPasswordAlgorithm.ts +4 -2
  289. package/src/password/createPBKDF2PasswordAlgorithm.ts +2 -2
  290. package/src/password/createScryptPasswordAlgorithm.ts +4 -4
  291. package/src/password/index.ts +2 -2
  292. package/src/resource/ListQuery.ts +4 -1
  293. package/src/resource/index.ts +3 -3
  294. package/src/resource/schema/index.ts +4 -4
  295. package/src/s3/formatS3Url.test.ts +1 -1
  296. package/src/s3/formatS3Url.ts +2 -2
  297. package/src/s3/index.ts +1 -1
  298. package/src/s3/parseS3Url.ts +1 -1
  299. package/src/schema/SchemaRegistry.ts +2 -2
  300. package/src/schema/TypeSchema.d.ts +6 -6
  301. package/src/schema/createSchemaData.ts +5 -5
  302. package/src/schema/findJsonSchemaByPath.ts +5 -5
  303. package/src/schema/formatZodError.test.ts +2 -1
  304. package/src/schema/formatZodError.ts +50 -62
  305. package/src/schema/index.ts +5 -5
  306. package/src/schema/toJsonSchema.ts +6 -6
  307. package/src/schema/validate.ts +2 -2
  308. package/src/utils/buildRedactorFormSchema.ts +4 -4
  309. package/src/utils/formatNumber.ts +18 -0
  310. package/src/utils/formatPercent.ts +17 -0
  311. package/src/utils/index.ts +3 -3
  312. package/src/utils/resolveFeatureOptions.ts +1 -1
@@ -1,516 +1,479 @@
1
- import { computeIfAbsent } from "@wener/utils";
2
- import { basename, dirname, normalize } from "pathe";
3
- import { findMimeType } from "./findMimeType.js";
1
+ import { computeIfAbsent } from '@wener/utils';
2
+ import { basename, dirname, normalize } from 'pathe';
3
+ import { FileSystemError } from './FileSystemError.js';
4
+ import { findMimeType } from './findMimeType.js';
4
5
  export function createMemoryFileSystem(options = {}) {
5
- return new MemFS(options);
6
+ return new MemFS(options);
6
7
  }
7
- let MemoryFileSystemError = class MemoryFileSystemError extends Error {
8
- code;
9
- constructor(message, code) {
10
- super(message);
11
- this.name = "MemoryFileSystemError";
12
- this.code = code;
13
- }
8
+ let MemoryFileSystemError = class MemoryFileSystemError extends FileSystemError {
9
+ constructor(message, code) {
10
+ super(message, code);
11
+ this.name = 'MemoryFileSystemError';
12
+ }
14
13
  };
15
14
  let MemFS = class MemFS {
16
- root;
17
- cache = new WeakMap();
18
- constructor({ root } = {}) {
19
- this.root = root || {
20
- name: "",
21
- kind: "directory",
22
- path: "/",
23
- directory: "",
24
- children: [],
25
- size: 0,
26
- mtime: Date.now(),
27
- meta: {}
28
- };
29
- }
30
- /**
31
- * 核心辅助方法:通过路径查找节点
32
- * @returns A tuple: [foundNode, parentNode, finalName]
33
- */ _getNodeByPath(path) {
34
- if (!path || typeof path !== "string") {
35
- throw new MemoryFileSystemError("Invalid path: path must be a non-empty string", "EINVAL");
36
- }
37
- const normalized = normalize(path);
38
- if (normalized === "/") {
39
- // the parent of root is itself
40
- return [
41
- this.root,
42
- this.root,
43
- ""
44
- ];
45
- }
46
- const parts = normalized.split("/").filter((p) => p);
47
- if (parts.length === 0) {
48
- return [
49
- this.root,
50
- this.root,
51
- ""
52
- ];
53
- }
54
- const finalName = parts.pop();
55
- let current = this.root;
56
- for (const part of parts) {
57
- if (!part)
58
- continue; // skip empty parts
59
- const found = current.children.find((child) => child.name === part);
60
- if (!found || found.kind !== "directory") {
61
- return [
62
- null,
63
- null,
64
- finalName
65
- ];
66
- }
67
- current = found;
68
- }
69
- const node = current.children.find((child) => child.name === finalName) ?? null;
70
- return [
71
- node,
72
- current,
73
- finalName
74
- ];
75
- }
76
- /**
77
- * 核心辅助方法:查找或创建目录
78
- */ _findOrCreateDirectory(path) {
79
- if (!path || typeof path !== "string") {
80
- throw new MemoryFileSystemError("Invalid path: path must be a non-empty string", "EINVAL");
81
- }
82
- const normalized = normalize(path);
83
- if (normalized === "/")
84
- return this.root;
85
- const parts = normalized.split("/").filter((p) => p);
86
- if (parts.length === 0)
87
- return this.root;
88
- let current = this.root;
89
- let currentPath = "";
90
- for (const part of parts) {
91
- if (!part)
92
- continue; // skip empty parts
93
- currentPath = `${currentPath}/${part}`;
94
- let found = current.children.find((child) => child.name === part);
95
- if (!found) {
96
- const now = Date.now();
97
- const newDir = {
98
- name: part,
99
- kind: "directory",
100
- path: currentPath,
101
- directory: dirname(currentPath),
102
- children: [],
103
- size: 0,
104
- mtime: now,
105
- meta: {}
106
- };
107
- current.children.push(newDir);
108
- current = newDir;
109
- }
110
- else if (found.kind !== "directory") {
111
- throw new MemoryFileSystemError(`Path conflict: ${currentPath} is a file`, "ENOTDIR");
112
- }
113
- else {
114
- current = found;
115
- }
116
- }
117
- return current;
118
- }
119
- async stat(path, options) {
120
- if (options?.signal?.aborted) {
121
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
122
- }
123
- const [node] = this._getNodeByPath(path);
124
- if (!node) {
125
- throw new MemoryFileSystemError(`File not found: ${path}`, "ENOENT");
126
- }
127
- return {
128
- ...node
129
- };
130
- }
131
- async exists(path) {
132
- const [node] = this._getNodeByPath(path);
133
- return !!node;
134
- }
135
- async readdir(path, options) {
136
- if (options?.signal?.aborted) {
137
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
138
- }
139
- const [node] = this._getNodeByPath(path);
140
- if (!node) {
141
- throw new MemoryFileSystemError(`Directory not found: ${path}`, "ENOENT");
142
- }
143
- if (node.kind !== "directory") {
144
- throw new MemoryFileSystemError(`Not a directory: ${path}`, "ENOTDIR");
145
- }
146
- // 返回副本
147
- return node.children.map((child) => ({
148
- ...child
149
- }));
150
- }
151
- async mkdir(path, options) {
152
- if (options?.signal?.aborted) {
153
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
154
- }
155
- const [node] = this._getNodeByPath(path);
156
- if (node) {
157
- if (node.kind === "file")
158
- throw new MemoryFileSystemError(`File already exists: ${path}`, "EEXIST");
159
- return; // 目录已存在
160
- }
161
- if (options?.recursive) {
162
- this._findOrCreateDirectory(path);
163
- }
164
- else {
165
- const parentPath = dirname(path);
166
- const [, parent] = this._getNodeByPath(parentPath);
167
- if (!parent) {
168
- throw new MemoryFileSystemError(`Parent directory does not exist: ${parentPath}`, "ENOENT");
169
- }
170
- this._findOrCreateDirectory(path);
171
- }
172
- }
173
- async readFile(path, options) {
174
- if (options?.signal?.aborted) {
175
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
176
- }
177
- const [node] = this._getNodeByPath(path);
178
- if (!node) {
179
- throw new MemoryFileSystemError(`File not found: ${path}`, "ENOENT");
180
- }
181
- if (node.kind !== "file") {
182
- throw new MemoryFileSystemError(`Is a directory: ${path}`, "EISDIR");
183
- }
184
- const content = "content" in node ? node.content : "";
185
- return options?.encoding === "text" ? content.toString() : Buffer.from(content);
186
- }
187
- async writeFile(path, data, options = {}) {
188
- if (options?.signal?.aborted) {
189
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
190
- }
191
- if (!path || typeof path !== "string") {
192
- throw new MemoryFileSystemError("Invalid path: path must be a non-empty string", "EINVAL");
193
- }
194
- if (data === null || data === undefined) {
195
- throw new MemoryFileSystemError("Invalid data: data cannot be null or undefined", "EINVAL");
196
- }
197
- const { overwrite = true } = options;
198
- const parentPath = dirname(path);
199
- const filename = basename(path);
200
- if (!filename) {
201
- throw new MemoryFileSystemError("Invalid path: filename cannot be empty", "EINVAL");
202
- }
203
- const parent = this._findOrCreateDirectory(parentPath);
204
- const nodeIndex = parent.children.findIndex((child) => child.name === filename);
205
- const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
206
- if (existingNode) {
207
- if (!overwrite)
208
- throw new MemoryFileSystemError(`File already exists: ${path}`, "EEXIST");
209
- if (existingNode.kind === "directory")
210
- throw new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, "EISDIR");
211
- // 更新文件
212
- existingNode.content = data;
213
- existingNode.size = data.length;
214
- existingNode.mtime = Date.now();
215
- }
216
- else {
217
- // 创建新文件
218
- const now = Date.now();
219
- const newFile = {
220
- name: filename,
221
- kind: "file",
222
- path: path,
223
- directory: parentPath,
224
- content: data,
225
- size: data.length,
226
- mtime: now,
227
- meta: {}
228
- };
229
- parent.children.push(newFile);
230
- }
231
- }
232
- async rm(path, options = {}) {
233
- if (options?.signal?.aborted) {
234
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
235
- }
236
- const { recursive = false, force = false } = options;
237
- const [node, parent] = this._getNodeByPath(path);
238
- if (!node) {
239
- if (force)
240
- return;
241
- throw new MemoryFileSystemError(`File not found: ${path}`, "ENOENT");
242
- }
243
- if (node.kind === "directory" && node.children.length > 0 && !recursive) {
244
- throw new MemoryFileSystemError(`Directory not empty: ${path}`, "ENOTEMPTY");
245
- }
246
- if (parent) {
247
- const index = parent.children.findIndex((child) => child.name === node.name);
248
- if (index !== -1) {
249
- parent.children.splice(index, 1);
250
- }
251
- }
252
- }
253
- async rename(oldPath, newPath, options) {
254
- if (options?.signal?.aborted) {
255
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
256
- }
257
- const [oldNode, oldParent, oldName] = this._getNodeByPath(oldPath);
258
- if (!oldNode || !oldParent)
259
- throw new MemoryFileSystemError(`Source not found: ${oldPath}`, "ENOENT");
260
- const oldNodeIndex = oldParent.children.findIndex((c) => c.name === oldName);
261
- oldParent.children.splice(oldNodeIndex, 1);
262
- const newParentPath = dirname(newPath);
263
- const newName = basename(newPath);
264
- const newParent = this._findOrCreateDirectory(newParentPath);
265
- const existingNodeIndex = newParent.children.findIndex((c) => c.name === newName);
266
- if (existingNodeIndex !== -1) {
267
- if (!options?.overwrite)
268
- throw new MemoryFileSystemError(`Destination exists: ${newPath}`, "EEXIST");
269
- newParent.children.splice(existingNodeIndex, 1);
270
- }
271
- oldNode.name = newName;
272
- oldNode.path = newPath;
273
- oldNode.directory = newParentPath;
274
- oldNode.mtime = Date.now();
275
- newParent.children.push(oldNode);
276
- }
277
- async copy(srcPath, destPath, options) {
278
- if (options?.signal?.aborted) {
279
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
280
- }
281
- const [srcNode] = this._getNodeByPath(srcPath);
282
- if (!srcNode)
283
- throw new MemoryFileSystemError(`Source not found: ${srcPath}`, "ENOENT");
284
- const deepClone = (node) => JSON.parse(JSON.stringify(node));
285
- const newNode = deepClone(srcNode);
286
- const newParentPath = dirname(destPath);
287
- const newName = basename(destPath);
288
- const newParent = this._findOrCreateDirectory(newParentPath);
289
- newNode.name = newName;
290
- newNode.path = destPath;
291
- newNode.directory = newParentPath;
292
- const existingNodeIndex = newParent.children.findIndex((c) => c.name === newName);
293
- if (existingNodeIndex !== -1) {
294
- if (!options?.overwrite)
295
- throw new MemoryFileSystemError(`Destination exists: ${destPath}`, "EEXIST");
296
- newParent.children[existingNodeIndex] = newNode;
297
- }
298
- else {
299
- newParent.children.push(newNode);
300
- }
301
- }
302
- createReadStream(path, options) {
303
- const { signal, range } = options || {};
304
- if (signal?.aborted) {
305
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
306
- }
307
- const [node] = this._getNodeByPath(path);
308
- if (!node) {
309
- throw new MemoryFileSystemError(`File not found: ${path}`, "ENOENT");
310
- }
311
- if (node.kind !== "file") {
312
- throw new MemoryFileSystemError(`Is a directory: ${path}`, "EISDIR");
313
- }
314
- const content = Buffer.from("content" in node ? node.content : "");
315
- const { Readable } = require("node:stream");
316
- let data = content;
317
- if (range) {
318
- const start = range.start || 0;
319
- const end = range.end || content.length - 1;
320
- data = content.subarray(start, end + 1);
321
- }
322
- const stream = Readable.from([
323
- data
324
- ]);
325
- if (signal) {
326
- signal.addEventListener("abort", () => {
327
- stream.destroy(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
328
- });
329
- }
330
- return stream;
331
- }
332
- createWriteStream(path, options) {
333
- const { signal, overwrite = true } = options || {};
334
- if (signal?.aborted) {
335
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
336
- }
337
- const { Writable } = require("node:stream");
338
- const chunks = [];
339
- const self = this;
340
- const stream = new Writable({
341
- write(chunk, encoding, callback) {
342
- if (signal?.aborted) {
343
- callback(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
344
- return;
345
- }
346
- chunks.push(chunk);
347
- callback();
348
- },
349
- final(callback) {
350
- if (signal?.aborted) {
351
- callback(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
352
- return;
353
- }
354
- try {
355
- const content = Buffer.concat(chunks);
356
- const parentPath = dirname(path);
357
- const filename = basename(path);
358
- const parent = self._findOrCreateDirectory(parentPath);
359
- const nodeIndex = parent.children.findIndex((child) => child.name === filename);
360
- const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
361
- if (existingNode) {
362
- if (!overwrite) {
363
- callback(new MemoryFileSystemError(`File already exists: ${path}`, "EEXIST"));
364
- return;
365
- }
366
- if (existingNode.kind === "directory") {
367
- callback(new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, "EISDIR"));
368
- return;
369
- }
370
- existingNode.content = content;
371
- existingNode.size = content.length;
372
- existingNode.mtime = Date.now();
373
- }
374
- else {
375
- const now = Date.now();
376
- const newFile = {
377
- name: filename,
378
- kind: "file",
379
- path: path,
380
- directory: parentPath,
381
- content: content,
382
- size: content.length,
383
- mtime: now,
384
- meta: {}
385
- };
386
- parent.children.push(newFile);
387
- }
388
- callback();
389
- }
390
- catch (error) {
391
- callback(error instanceof Error ? error : new MemoryFileSystemError("Unknown error", "UNKNOWN"));
392
- }
393
- }
394
- });
395
- if (signal) {
396
- signal.addEventListener("abort", () => {
397
- stream.destroy(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
398
- });
399
- }
400
- return stream;
401
- }
402
- getUrl(file) {
403
- let node;
404
- if (typeof file === "string") {
405
- [node] = this._getNodeByPath(file);
406
- }
407
- else {
408
- node = file;
409
- }
410
- let mf = node;
411
- if (mf.content) {
412
- let c = computeIfAbsent(this.cache, mf, () => ({}));
413
- if (!c.url) {
414
- let mime = findMimeType(mf.name) || "application/octet-stream";
415
- c.url = URL.createObjectURL(new Blob([
416
- mf.content
417
- ], {
418
- type: mime
419
- }));
420
- }
421
- return c.url;
422
- }
423
- return;
424
- }
425
- createReadableStream(path, options) {
426
- const { signal, range } = options || {};
427
- if (signal?.aborted) {
428
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
429
- }
430
- const [node] = this._getNodeByPath(path);
431
- if (!node) {
432
- throw new MemoryFileSystemError(`File not found: ${path}`, "ENOENT");
433
- }
434
- if (node.kind !== "file") {
435
- throw new MemoryFileSystemError(`Is a directory: ${path}`, "EISDIR");
436
- }
437
- const content = Buffer.from("content" in node ? node.content : "");
438
- let data = content;
439
- if (range) {
440
- const start = range.start || 0;
441
- const end = range.end || content.length - 1;
442
- data = content.subarray(start, end + 1);
443
- }
444
- const stream = new ReadableStream({
445
- start(controller) {
446
- controller.enqueue(data);
447
- controller.close();
448
- }
449
- });
450
- if (signal) {
451
- signal.addEventListener("abort", () => {
452
- stream.cancel(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
453
- });
454
- }
455
- return stream;
456
- }
457
- createWritableStream(path, options) {
458
- const { signal, overwrite = true } = options || {};
459
- if (signal?.aborted) {
460
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
461
- }
462
- const chunks = [];
463
- const self = this;
464
- const stream = new WritableStream({
465
- write(chunk) {
466
- if (signal?.aborted) {
467
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
468
- }
469
- chunks.push(chunk);
470
- },
471
- close() {
472
- if (signal?.aborted) {
473
- throw new MemoryFileSystemError("Operation aborted", "ABORT_ERR");
474
- }
475
- const content = Buffer.concat(chunks);
476
- const parentPath = dirname(path);
477
- const filename = basename(path);
478
- const parent = self._findOrCreateDirectory(parentPath);
479
- const nodeIndex = parent.children.findIndex((child) => child.name === filename);
480
- const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
481
- if (existingNode) {
482
- if (!overwrite) {
483
- throw new MemoryFileSystemError(`File already exists: ${path}`, "EEXIST");
484
- }
485
- if (existingNode.kind === "directory") {
486
- throw new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, "EISDIR");
487
- }
488
- existingNode.content = content;
489
- existingNode.size = content.length;
490
- existingNode.mtime = Date.now();
491
- }
492
- else {
493
- const now = Date.now();
494
- const newFile = {
495
- name: filename,
496
- kind: "file",
497
- path: path,
498
- directory: parentPath,
499
- content: content,
500
- size: content.length,
501
- mtime: now,
502
- meta: {}
503
- };
504
- parent.children.push(newFile);
505
- }
506
- }
507
- });
508
- if (signal) {
509
- signal.addEventListener("abort", () => {
510
- stream.abort(new MemoryFileSystemError("Operation aborted", "ABORT_ERR"));
511
- });
512
- }
513
- return stream;
514
- }
15
+ root;
16
+ cache = new WeakMap();
17
+ constructor({ root } = {}) {
18
+ this.root = root || {
19
+ name: '',
20
+ kind: 'directory',
21
+ path: '/',
22
+ directory: '',
23
+ children: [],
24
+ size: 0,
25
+ mtime: Date.now(),
26
+ meta: {},
27
+ };
28
+ }
29
+ /**
30
+ * 核心辅助方法:通过路径查找节点
31
+ * @returns A tuple: [foundNode, parentNode, finalName]
32
+ */ _getNodeByPath(path) {
33
+ if (!path || typeof path !== 'string') {
34
+ throw new MemoryFileSystemError('Invalid path: path must be a non-empty string', 'EINVAL');
35
+ }
36
+ const normalized = normalize(path);
37
+ if (normalized === '/') {
38
+ // the parent of root is itself
39
+ return [this.root, this.root, ''];
40
+ }
41
+ const parts = normalized.split('/').filter((p) => p);
42
+ if (parts.length === 0) {
43
+ return [this.root, this.root, ''];
44
+ }
45
+ const finalName = parts.pop();
46
+ let current = this.root;
47
+ for (const part of parts) {
48
+ if (!part) continue; // skip empty parts
49
+ const found = current.children.find((child) => child.name === part);
50
+ if (!found || found.kind !== 'directory') {
51
+ return [null, null, finalName];
52
+ }
53
+ current = found;
54
+ }
55
+ const node = current.children.find((child) => child.name === finalName) ?? null;
56
+ return [node, current, finalName];
57
+ }
58
+ /**
59
+ * 核心辅助方法:查找或创建目录
60
+ */ _findOrCreateDirectory(path) {
61
+ if (!path || typeof path !== 'string') {
62
+ throw new MemoryFileSystemError('Invalid path: path must be a non-empty string', 'EINVAL');
63
+ }
64
+ const normalized = normalize(path);
65
+ if (normalized === '/') return this.root;
66
+ const parts = normalized.split('/').filter((p) => p);
67
+ if (parts.length === 0) return this.root;
68
+ let current = this.root;
69
+ let currentPath = '';
70
+ for (const part of parts) {
71
+ if (!part) continue; // skip empty parts
72
+ currentPath = `${currentPath}/${part}`;
73
+ let found = current.children.find((child) => child.name === part);
74
+ if (!found) {
75
+ const now = Date.now();
76
+ const newDir = {
77
+ name: part,
78
+ kind: 'directory',
79
+ path: currentPath,
80
+ directory: dirname(currentPath),
81
+ children: [],
82
+ size: 0,
83
+ mtime: now,
84
+ meta: {},
85
+ };
86
+ current.children.push(newDir);
87
+ current = newDir;
88
+ } else if (found.kind !== 'directory') {
89
+ throw new MemoryFileSystemError(`Path conflict: ${currentPath} is a file`, 'ENOTDIR');
90
+ } else {
91
+ current = found;
92
+ }
93
+ }
94
+ return current;
95
+ }
96
+ async stat(path, options) {
97
+ if (options?.signal?.aborted) {
98
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
99
+ }
100
+ const [node] = this._getNodeByPath(path);
101
+ if (!node) {
102
+ throw new MemoryFileSystemError(`File not found: ${path}`, 'ENOENT');
103
+ }
104
+ return {
105
+ ...node,
106
+ };
107
+ }
108
+ async exists(path) {
109
+ const [node] = this._getNodeByPath(path);
110
+ return !!node;
111
+ }
112
+ async readdir(path, options) {
113
+ if (options?.signal?.aborted) {
114
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
115
+ }
116
+ const [node] = this._getNodeByPath(path);
117
+ if (!node) {
118
+ throw new MemoryFileSystemError(`Directory not found: ${path}`, 'ENOENT');
119
+ }
120
+ if (node.kind !== 'directory') {
121
+ throw new MemoryFileSystemError(`Not a directory: ${path}`, 'ENOTDIR');
122
+ }
123
+ // 返回副本
124
+ return node.children.map((child) => ({
125
+ ...child,
126
+ }));
127
+ }
128
+ async mkdir(path, options) {
129
+ if (options?.signal?.aborted) {
130
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
131
+ }
132
+ const [node] = this._getNodeByPath(path);
133
+ if (node) {
134
+ if (node.kind === 'file') throw new MemoryFileSystemError(`File already exists: ${path}`, 'EEXIST');
135
+ return; // 目录已存在
136
+ }
137
+ if (options?.recursive) {
138
+ this._findOrCreateDirectory(path);
139
+ } else {
140
+ const parentPath = dirname(path);
141
+ const [, parent] = this._getNodeByPath(parentPath);
142
+ if (!parent) {
143
+ throw new MemoryFileSystemError(`Parent directory does not exist: ${parentPath}`, 'ENOENT');
144
+ }
145
+ this._findOrCreateDirectory(path);
146
+ }
147
+ }
148
+ async readFile(path, options) {
149
+ if (options?.signal?.aborted) {
150
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
151
+ }
152
+ const [node] = this._getNodeByPath(path);
153
+ if (!node) {
154
+ throw new MemoryFileSystemError(`File not found: ${path}`, 'ENOENT');
155
+ }
156
+ if (node.kind !== 'file') {
157
+ throw new MemoryFileSystemError(`Is a directory: ${path}`, 'EISDIR');
158
+ }
159
+ const content = 'content' in node ? node.content : '';
160
+ return options?.encoding === 'text' ? content.toString() : Buffer.from(content);
161
+ }
162
+ async writeFile(path, data, options = {}) {
163
+ if (options?.signal?.aborted) {
164
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
165
+ }
166
+ if (!path || typeof path !== 'string') {
167
+ throw new MemoryFileSystemError('Invalid path: path must be a non-empty string', 'EINVAL');
168
+ }
169
+ if (data === null || data === undefined) {
170
+ throw new MemoryFileSystemError('Invalid data: data cannot be null or undefined', 'EINVAL');
171
+ }
172
+ const { overwrite = true } = options;
173
+ const parentPath = dirname(path);
174
+ const filename = basename(path);
175
+ if (!filename) {
176
+ throw new MemoryFileSystemError('Invalid path: filename cannot be empty', 'EINVAL');
177
+ }
178
+ const parent = this._findOrCreateDirectory(parentPath);
179
+ const nodeIndex = parent.children.findIndex((child) => child.name === filename);
180
+ const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
181
+ if (existingNode) {
182
+ if (!overwrite) throw new MemoryFileSystemError(`File already exists: ${path}`, 'EEXIST');
183
+ if (existingNode.kind === 'directory')
184
+ throw new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, 'EISDIR');
185
+ // 更新文件
186
+ existingNode.content = data;
187
+ existingNode.size = data.length;
188
+ existingNode.mtime = Date.now();
189
+ } else {
190
+ // 创建新文件
191
+ const now = Date.now();
192
+ const newFile = {
193
+ name: filename,
194
+ kind: 'file',
195
+ path: path,
196
+ directory: parentPath,
197
+ content: data,
198
+ size: data.length,
199
+ mtime: now,
200
+ meta: {},
201
+ };
202
+ parent.children.push(newFile);
203
+ }
204
+ }
205
+ async rm(path, options = {}) {
206
+ if (options?.signal?.aborted) {
207
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
208
+ }
209
+ const { recursive = false, force = false } = options;
210
+ const [node, parent] = this._getNodeByPath(path);
211
+ if (!node) {
212
+ if (force) return;
213
+ throw new MemoryFileSystemError(`File not found: ${path}`, 'ENOENT');
214
+ }
215
+ if (node.kind === 'directory' && node.children.length > 0 && !recursive) {
216
+ throw new MemoryFileSystemError(`Directory not empty: ${path}`, 'ENOTEMPTY');
217
+ }
218
+ if (parent) {
219
+ const index = parent.children.findIndex((child) => child.name === node.name);
220
+ if (index !== -1) {
221
+ parent.children.splice(index, 1);
222
+ }
223
+ }
224
+ }
225
+ async rename(oldPath, newPath, options) {
226
+ if (options?.signal?.aborted) {
227
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
228
+ }
229
+ const [oldNode, oldParent, oldName] = this._getNodeByPath(oldPath);
230
+ if (!oldNode || !oldParent) throw new MemoryFileSystemError(`Source not found: ${oldPath}`, 'ENOENT');
231
+ const oldNodeIndex = oldParent.children.findIndex((c) => c.name === oldName);
232
+ oldParent.children.splice(oldNodeIndex, 1);
233
+ const newParentPath = dirname(newPath);
234
+ const newName = basename(newPath);
235
+ const newParent = this._findOrCreateDirectory(newParentPath);
236
+ const existingNodeIndex = newParent.children.findIndex((c) => c.name === newName);
237
+ if (existingNodeIndex !== -1) {
238
+ if (!options?.overwrite) throw new MemoryFileSystemError(`Destination exists: ${newPath}`, 'EEXIST');
239
+ newParent.children.splice(existingNodeIndex, 1);
240
+ }
241
+ oldNode.name = newName;
242
+ oldNode.path = newPath;
243
+ oldNode.directory = newParentPath;
244
+ oldNode.mtime = Date.now();
245
+ newParent.children.push(oldNode);
246
+ }
247
+ async copy(srcPath, destPath, options) {
248
+ if (options?.signal?.aborted) {
249
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
250
+ }
251
+ const [srcNode] = this._getNodeByPath(srcPath);
252
+ if (!srcNode) throw new MemoryFileSystemError(`Source not found: ${srcPath}`, 'ENOENT');
253
+ const deepClone = (node) => JSON.parse(JSON.stringify(node));
254
+ const newNode = deepClone(srcNode);
255
+ const newParentPath = dirname(destPath);
256
+ const newName = basename(destPath);
257
+ const newParent = this._findOrCreateDirectory(newParentPath);
258
+ newNode.name = newName;
259
+ newNode.path = destPath;
260
+ newNode.directory = newParentPath;
261
+ const existingNodeIndex = newParent.children.findIndex((c) => c.name === newName);
262
+ if (existingNodeIndex !== -1) {
263
+ if (!options?.overwrite) throw new MemoryFileSystemError(`Destination exists: ${destPath}`, 'EEXIST');
264
+ newParent.children[existingNodeIndex] = newNode;
265
+ } else {
266
+ newParent.children.push(newNode);
267
+ }
268
+ }
269
+ createReadStream(path, options) {
270
+ const { signal, range } = options || {};
271
+ if (signal?.aborted) {
272
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
273
+ }
274
+ const [node] = this._getNodeByPath(path);
275
+ if (!node) {
276
+ throw new MemoryFileSystemError(`File not found: ${path}`, 'ENOENT');
277
+ }
278
+ if (node.kind !== 'file') {
279
+ throw new MemoryFileSystemError(`Is a directory: ${path}`, 'EISDIR');
280
+ }
281
+ const content = Buffer.from('content' in node ? node.content : '');
282
+ const { Readable } = require('node:stream');
283
+ let data = content;
284
+ if (range) {
285
+ const start = range.start || 0;
286
+ const end = range.end || content.length - 1;
287
+ data = content.subarray(start, end + 1);
288
+ }
289
+ const stream = Readable.from([data]);
290
+ if (signal) {
291
+ signal.addEventListener('abort', () => {
292
+ stream.destroy(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
293
+ });
294
+ }
295
+ return stream;
296
+ }
297
+ createWriteStream(path, options) {
298
+ const { signal, overwrite = true } = options || {};
299
+ if (signal?.aborted) {
300
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
301
+ }
302
+ const { Writable } = require('node:stream');
303
+ const chunks = [];
304
+ const self = this;
305
+ const stream = new Writable({
306
+ write(chunk, _encoding, callback) {
307
+ if (signal?.aborted) {
308
+ callback(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
309
+ return;
310
+ }
311
+ chunks.push(chunk);
312
+ callback();
313
+ },
314
+ final(callback) {
315
+ if (signal?.aborted) {
316
+ callback(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
317
+ return;
318
+ }
319
+ try {
320
+ const content = Buffer.concat(chunks);
321
+ const parentPath = dirname(path);
322
+ const filename = basename(path);
323
+ const parent = self._findOrCreateDirectory(parentPath);
324
+ const nodeIndex = parent.children.findIndex((child) => child.name === filename);
325
+ const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
326
+ if (existingNode) {
327
+ if (!overwrite) {
328
+ callback(new MemoryFileSystemError(`File already exists: ${path}`, 'EEXIST'));
329
+ return;
330
+ }
331
+ if (existingNode.kind === 'directory') {
332
+ callback(new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, 'EISDIR'));
333
+ return;
334
+ }
335
+ existingNode.content = content;
336
+ existingNode.size = content.length;
337
+ existingNode.mtime = Date.now();
338
+ } else {
339
+ const now = Date.now();
340
+ const newFile = {
341
+ name: filename,
342
+ kind: 'file',
343
+ path: path,
344
+ directory: parentPath,
345
+ content: content,
346
+ size: content.length,
347
+ mtime: now,
348
+ meta: {},
349
+ };
350
+ parent.children.push(newFile);
351
+ }
352
+ callback();
353
+ } catch (error) {
354
+ callback(error instanceof Error ? error : new MemoryFileSystemError('Unknown error', 'UNKNOWN'));
355
+ }
356
+ },
357
+ });
358
+ if (signal) {
359
+ signal.addEventListener('abort', () => {
360
+ stream.destroy(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
361
+ });
362
+ }
363
+ return stream;
364
+ }
365
+ getUrl(file) {
366
+ let node;
367
+ if (typeof file === 'string') {
368
+ [node] = this._getNodeByPath(file);
369
+ } else {
370
+ node = file;
371
+ }
372
+ let mf = node;
373
+ if (mf.content) {
374
+ let c = computeIfAbsent(this.cache, mf, () => ({}));
375
+ if (!c.url) {
376
+ let mime = findMimeType(mf.name) || 'application/octet-stream';
377
+ // Convert Buffer to Uint8Array for Blob compatibility with TypeScript 5.x strict typing
378
+ const blobPart = typeof mf.content === 'string' ? mf.content : new Uint8Array(mf.content);
379
+ c.url = URL.createObjectURL(
380
+ new Blob([blobPart], {
381
+ type: mime,
382
+ }),
383
+ );
384
+ }
385
+ return c.url;
386
+ }
387
+ return;
388
+ }
389
+ createReadableStream(path, options) {
390
+ const { signal, range } = options || {};
391
+ if (signal?.aborted) {
392
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
393
+ }
394
+ const [node] = this._getNodeByPath(path);
395
+ if (!node) {
396
+ throw new MemoryFileSystemError(`File not found: ${path}`, 'ENOENT');
397
+ }
398
+ if (node.kind !== 'file') {
399
+ throw new MemoryFileSystemError(`Is a directory: ${path}`, 'EISDIR');
400
+ }
401
+ const content = Buffer.from('content' in node ? node.content : '');
402
+ let data = content;
403
+ if (range) {
404
+ const start = range.start || 0;
405
+ const end = range.end || content.length - 1;
406
+ data = content.subarray(start, end + 1);
407
+ }
408
+ const stream = new ReadableStream({
409
+ start(controller) {
410
+ controller.enqueue(data);
411
+ controller.close();
412
+ },
413
+ });
414
+ if (signal) {
415
+ signal.addEventListener('abort', () => {
416
+ stream.cancel(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
417
+ });
418
+ }
419
+ return stream;
420
+ }
421
+ createWritableStream(path, options) {
422
+ const { signal, overwrite = true } = options || {};
423
+ if (signal?.aborted) {
424
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
425
+ }
426
+ const chunks = [];
427
+ const self = this;
428
+ const stream = new WritableStream({
429
+ write(chunk) {
430
+ if (signal?.aborted) {
431
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
432
+ }
433
+ chunks.push(chunk);
434
+ },
435
+ close() {
436
+ if (signal?.aborted) {
437
+ throw new MemoryFileSystemError('Operation aborted', 'ABORT_ERR');
438
+ }
439
+ const content = Buffer.concat(chunks);
440
+ const parentPath = dirname(path);
441
+ const filename = basename(path);
442
+ const parent = self._findOrCreateDirectory(parentPath);
443
+ const nodeIndex = parent.children.findIndex((child) => child.name === filename);
444
+ const existingNode = nodeIndex !== -1 ? parent.children[nodeIndex] : null;
445
+ if (existingNode) {
446
+ if (!overwrite) {
447
+ throw new MemoryFileSystemError(`File already exists: ${path}`, 'EEXIST');
448
+ }
449
+ if (existingNode.kind === 'directory') {
450
+ throw new MemoryFileSystemError(`Cannot overwrite a directory: ${path}`, 'EISDIR');
451
+ }
452
+ existingNode.content = content;
453
+ existingNode.size = content.length;
454
+ existingNode.mtime = Date.now();
455
+ } else {
456
+ const now = Date.now();
457
+ const newFile = {
458
+ name: filename,
459
+ kind: 'file',
460
+ path: path,
461
+ directory: parentPath,
462
+ content: content,
463
+ size: content.length,
464
+ mtime: now,
465
+ meta: {},
466
+ };
467
+ parent.children.push(newFile);
468
+ }
469
+ },
470
+ });
471
+ if (signal) {
472
+ signal.addEventListener('abort', () => {
473
+ stream.abort(new MemoryFileSystemError('Operation aborted', 'ABORT_ERR'));
474
+ });
475
+ }
476
+ return stream;
477
+ }
515
478
  };
516
479
  //# sourceMappingURL=createMemoryFileSystem.js.map