@wener/common 2.0.2 → 2.0.3

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 (351) hide show
  1. package/lib/ai/qwen3vl/index.js +2 -0
  2. package/lib/ai/qwen3vl/index.js.map +1 -0
  3. package/lib/ai/qwen3vl/utils.js +31 -0
  4. package/lib/ai/qwen3vl/utils.js.map +1 -0
  5. package/lib/ai/vision/DocLayoutElementTypeSchema.js +28 -0
  6. package/lib/ai/vision/DocLayoutElementTypeSchema.js.map +1 -0
  7. package/lib/ai/vision/ImageAnnotationSchema.js +50 -0
  8. package/lib/ai/vision/ImageAnnotationSchema.js.map +1 -0
  9. package/lib/ai/vision/index.js +3 -0
  10. package/lib/ai/vision/index.js.map +1 -0
  11. package/lib/ai/vision/resolveImageAnnotation.js +105 -0
  12. package/lib/ai/vision/resolveImageAnnotation.js.map +1 -0
  13. package/lib/cn/ChineseResidentIdNo.js +21 -14
  14. package/lib/cn/ChineseResidentIdNo.js.map +1 -0
  15. package/lib/cn/ChineseResidentIdNo.test.js +1 -1
  16. package/lib/cn/DivisionCode.js +30 -25
  17. package/lib/cn/DivisionCode.js.map +1 -0
  18. package/lib/cn/DivisionCode.test.js +1 -1
  19. package/lib/cn/Mod11.js +38 -81
  20. package/lib/cn/Mod11.js.map +1 -0
  21. package/lib/cn/Mod31.js +41 -90
  22. package/lib/cn/Mod31.js.map +1 -0
  23. package/lib/cn/UnifiedSocialCreditCode.js +43 -34
  24. package/lib/cn/UnifiedSocialCreditCode.js.map +1 -0
  25. package/lib/cn/UnifiedSocialCreditCode.test.js +1 -1
  26. package/lib/cn/formatChineseAmount.js +77 -0
  27. package/lib/cn/formatChineseAmount.js.map +1 -0
  28. package/lib/cn/index.js +7 -1
  29. package/lib/cn/index.js.map +1 -0
  30. package/lib/cn/parseChineseNumber.js +94 -0
  31. package/lib/cn/parseChineseNumber.js.map +1 -0
  32. package/lib/cn/parseChineseNumber.test.js +278 -0
  33. package/lib/cn/pinyin/cartesianProduct.js +22 -0
  34. package/lib/cn/pinyin/cartesianProduct.js.map +1 -0
  35. package/lib/cn/pinyin/cartesianProduct.test.js +179 -0
  36. package/lib/cn/pinyin/data.json +23573 -0
  37. package/lib/cn/pinyin/loader.js +14 -0
  38. package/lib/cn/pinyin/loader.js.map +1 -0
  39. package/lib/cn/pinyin/preload.js +3 -0
  40. package/lib/cn/pinyin/preload.js.map +1 -0
  41. package/lib/cn/pinyin/toPinyin.test.js +167 -0
  42. package/lib/cn/pinyin/toPinyinPure.js +33 -0
  43. package/lib/cn/pinyin/toPinyinPure.js.map +1 -0
  44. package/lib/cn/pinyin/transform.js +14 -0
  45. package/lib/cn/pinyin/transform.js.map +1 -0
  46. package/lib/cn/types.d.js +2 -0
  47. package/lib/cn/types.d.js.map +1 -0
  48. package/lib/consola/createStandardConsolaReporter.js +6 -6
  49. package/lib/consola/createStandardConsolaReporter.js.map +1 -0
  50. package/lib/consola/formatLogObject.js +65 -145
  51. package/lib/consola/formatLogObject.js.map +1 -0
  52. package/lib/consola/formatLogObject.test.js +184 -0
  53. package/lib/consola/index.js +1 -0
  54. package/lib/consola/index.js.map +1 -0
  55. package/lib/data/formatSort.js +6 -5
  56. package/lib/data/formatSort.js.map +1 -0
  57. package/lib/data/index.js +1 -0
  58. package/lib/data/index.js.map +1 -0
  59. package/lib/data/maybeNumber.js +5 -7
  60. package/lib/data/maybeNumber.js.map +1 -0
  61. package/lib/data/parseSort.js +22 -28
  62. package/lib/data/parseSort.js.map +1 -0
  63. package/lib/data/resolvePagination.js +13 -17
  64. package/lib/data/resolvePagination.js.map +1 -0
  65. package/lib/data/types.d.js +2 -0
  66. package/lib/data/types.d.js.map +1 -0
  67. package/lib/dayjs/dayjs.js +21 -19
  68. package/lib/dayjs/dayjs.js.map +1 -0
  69. package/lib/dayjs/formatDuration.js +15 -14
  70. package/lib/dayjs/formatDuration.js.map +1 -0
  71. package/lib/dayjs/index.js +2 -0
  72. package/lib/dayjs/index.js.map +1 -0
  73. package/lib/dayjs/parseDuration.js +5 -8
  74. package/lib/dayjs/parseDuration.js.map +1 -0
  75. package/lib/dayjs/parseRelativeTime.js +90 -0
  76. package/lib/dayjs/parseRelativeTime.js.map +1 -0
  77. package/lib/dayjs/parseRelativeTime.test.js +247 -0
  78. package/lib/dayjs/resolveRelativeTime.js +158 -0
  79. package/lib/dayjs/resolveRelativeTime.js.map +1 -0
  80. package/lib/dayjs/resolveRelativeTime.test.js +310 -0
  81. package/lib/decimal/index.js +1 -0
  82. package/lib/decimal/index.js.map +1 -0
  83. package/lib/decimal/parseDecimal.js +3 -1
  84. package/lib/decimal/parseDecimal.js.map +1 -0
  85. package/lib/emittery/emitter.js +10 -0
  86. package/lib/emittery/emitter.js.map +1 -0
  87. package/lib/emittery/index.js +2 -0
  88. package/lib/emittery/index.js.map +1 -0
  89. package/lib/foundation/schema/SexType.js +5 -3
  90. package/lib/foundation/schema/SexType.js.map +1 -0
  91. package/lib/foundation/schema/index.js +1 -0
  92. package/lib/foundation/schema/index.js.map +1 -0
  93. package/lib/foundation/schema/parseSexType.js +1 -0
  94. package/lib/foundation/schema/parseSexType.js.map +1 -0
  95. package/lib/foundation/schema/types.js +4 -2
  96. package/lib/foundation/schema/types.js.map +1 -0
  97. package/lib/fs/FileSystemError.js +23 -0
  98. package/lib/fs/FileSystemError.js.map +1 -0
  99. package/lib/fs/IFileSystem.d.js +3 -0
  100. package/lib/fs/IFileSystem.d.js.map +1 -0
  101. package/lib/fs/MemoryFileSystem.test.js +188 -0
  102. package/lib/fs/createBrowserFileSystem.js +248 -0
  103. package/lib/fs/createBrowserFileSystem.js.map +1 -0
  104. package/lib/fs/createMemoryFileSystem.js +516 -0
  105. package/lib/fs/createMemoryFileSystem.js.map +1 -0
  106. package/lib/fs/createSandboxFileSystem.js +108 -0
  107. package/lib/fs/createSandboxFileSystem.js.map +1 -0
  108. package/lib/fs/createWebDavFileSystem.js +137 -0
  109. package/lib/fs/createWebDavFileSystem.js.map +1 -0
  110. package/lib/fs/findMimeType.js +17 -0
  111. package/lib/fs/findMimeType.js.map +1 -0
  112. package/lib/fs/index.js +8 -0
  113. package/lib/fs/index.js.map +1 -0
  114. package/lib/fs/orpc/FileSystemContract.js +93 -0
  115. package/lib/fs/orpc/FileSystemContract.js.map +1 -0
  116. package/lib/fs/orpc/createContractClientFileSystem.js +93 -0
  117. package/lib/fs/orpc/createContractClientFileSystem.js.map +1 -0
  118. package/lib/fs/orpc/index.js +3 -0
  119. package/lib/fs/orpc/index.js.map +1 -0
  120. package/lib/fs/orpc/server/createFileSystemContractImpl.js +63 -0
  121. package/lib/fs/orpc/server/createFileSystemContractImpl.js.map +1 -0
  122. package/lib/fs/orpc/server/index.js +2 -0
  123. package/lib/fs/orpc/server/index.js.map +1 -0
  124. package/lib/fs/s3/createS3MiniFileSystem.js +705 -0
  125. package/lib/fs/s3/createS3MiniFileSystem.js.map +1 -0
  126. package/lib/fs/s3/index.js +2 -0
  127. package/lib/fs/s3/index.js.map +1 -0
  128. package/lib/fs/s3/s3mini.test.js +584 -0
  129. package/lib/fs/scandir.js +59 -0
  130. package/lib/fs/scandir.js.map +1 -0
  131. package/lib/fs/server/createDatabaseFileSystem.js +750 -0
  132. package/lib/fs/server/createDatabaseFileSystem.js.map +1 -0
  133. package/lib/fs/server/createNodeFileSystem.js +401 -0
  134. package/lib/fs/server/createNodeFileSystem.js.map +1 -0
  135. package/lib/fs/server/dbfs.test.js +221 -0
  136. package/lib/fs/server/index.js +2 -0
  137. package/lib/fs/server/index.js.map +1 -0
  138. package/lib/fs/server/loadTestDatabase.js +127 -0
  139. package/lib/fs/server/loadTestDatabase.js.map +1 -0
  140. package/lib/fs/tests/runFileSystemTest.js +318 -0
  141. package/lib/fs/tests/runFileSystemTest.js.map +1 -0
  142. package/lib/fs/types.js +27 -0
  143. package/lib/fs/types.js.map +1 -0
  144. package/lib/fs/utils/getFileUrl.js +35 -0
  145. package/lib/fs/utils/getFileUrl.js.map +1 -0
  146. package/lib/fs/utils.js +22 -0
  147. package/lib/fs/utils.js.map +1 -0
  148. package/lib/index.js +1 -0
  149. package/lib/index.js.map +1 -0
  150. package/lib/jsonschema/JsonSchema.js +146 -172
  151. package/lib/jsonschema/JsonSchema.js.map +1 -0
  152. package/lib/jsonschema/forEachJsonSchema.js +44 -0
  153. package/lib/jsonschema/forEachJsonSchema.js.map +1 -0
  154. package/lib/jsonschema/index.js +2 -0
  155. package/lib/jsonschema/index.js.map +1 -0
  156. package/lib/jsonschema/types.d.js +2 -0
  157. package/lib/jsonschema/types.d.js.map +1 -0
  158. package/lib/meta/defineFileType.js +20 -103
  159. package/lib/meta/defineFileType.js.map +1 -0
  160. package/lib/meta/defineInit.js +31 -250
  161. package/lib/meta/defineInit.js.map +1 -0
  162. package/lib/meta/defineMetadata.js +24 -140
  163. package/lib/meta/defineMetadata.js.map +1 -0
  164. package/lib/meta/index.js +1 -0
  165. package/lib/meta/index.js.map +1 -0
  166. package/lib/orpc/createOpenApiContractClient.js +27 -0
  167. package/lib/orpc/createOpenApiContractClient.js.map +1 -0
  168. package/lib/orpc/createRpcContractClient.js +34 -0
  169. package/lib/orpc/createRpcContractClient.js.map +1 -0
  170. package/lib/orpc/index.js +3 -0
  171. package/lib/orpc/index.js.map +1 -0
  172. package/lib/orpc/resolveLinkPlugins.js +28 -0
  173. package/lib/orpc/resolveLinkPlugins.js.map +1 -0
  174. package/lib/password/PHC.js +63 -87
  175. package/lib/password/PHC.js.map +1 -0
  176. package/lib/password/PHC.test.js +11 -3
  177. package/lib/password/Password.js +29 -294
  178. package/lib/password/Password.js.map +1 -0
  179. package/lib/password/Password.test.js +35 -22
  180. package/lib/password/createArgon2PasswordAlgorithm.js +35 -191
  181. package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -0
  182. package/lib/password/createBase64PasswordAlgorithm.js +8 -141
  183. package/lib/password/createBase64PasswordAlgorithm.js.map +1 -0
  184. package/lib/password/createBcryptPasswordAlgorithm.js +13 -168
  185. package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -0
  186. package/lib/password/createPBKDF2PasswordAlgorithm.js +46 -228
  187. package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -0
  188. package/lib/password/createScryptPasswordAlgorithm.js +55 -211
  189. package/lib/password/createScryptPasswordAlgorithm.js.map +1 -0
  190. package/lib/password/index.js +1 -0
  191. package/lib/password/index.js.map +1 -0
  192. package/lib/password/server/index.js +1 -0
  193. package/lib/password/server/index.js.map +1 -0
  194. package/lib/resource/Identifiable.js +2 -0
  195. package/lib/resource/Identifiable.js.map +1 -0
  196. package/lib/resource/ListQuery.js +21 -93
  197. package/lib/resource/ListQuery.js.map +1 -0
  198. package/lib/resource/getTitleOfResource.js +3 -5
  199. package/lib/resource/getTitleOfResource.js.map +1 -0
  200. package/lib/resource/index.js +1 -0
  201. package/lib/resource/index.js.map +1 -0
  202. package/lib/resource/schema/AnyResourceSchema.js +2 -1
  203. package/lib/resource/schema/AnyResourceSchema.js.map +1 -0
  204. package/lib/resource/schema/BaseResourceSchema.js +2 -1
  205. package/lib/resource/schema/BaseResourceSchema.js.map +1 -0
  206. package/lib/resource/schema/ResourceActionType.js +6 -4
  207. package/lib/resource/schema/ResourceActionType.js.map +1 -0
  208. package/lib/resource/schema/ResourceStatus.js +5 -3
  209. package/lib/resource/schema/ResourceStatus.js.map +1 -0
  210. package/lib/resource/schema/ResourceType.js +5 -3
  211. package/lib/resource/schema/ResourceType.js.map +1 -0
  212. package/lib/resource/schema/index.js +1 -0
  213. package/lib/resource/schema/index.js.map +1 -0
  214. package/lib/resource/schema/types.js +16 -20
  215. package/lib/resource/schema/types.js.map +1 -0
  216. package/lib/s3/formatS3Url.js +65 -0
  217. package/lib/s3/formatS3Url.js.map +1 -0
  218. package/lib/s3/formatS3Url.test.js +262 -0
  219. package/lib/s3/index.js +3 -0
  220. package/lib/s3/index.js.map +1 -0
  221. package/lib/s3/parseS3Url.js +65 -0
  222. package/lib/s3/parseS3Url.js.map +1 -0
  223. package/lib/s3/parseS3Url.test.js +270 -0
  224. package/lib/schema/SchemaRegistry.js +38 -38
  225. package/lib/schema/SchemaRegistry.js.map +1 -0
  226. package/lib/schema/TypeSchema.d.js +2 -0
  227. package/lib/schema/TypeSchema.d.js.map +1 -0
  228. package/lib/schema/createSchemaData.js +26 -125
  229. package/lib/schema/createSchemaData.js.map +1 -0
  230. package/lib/schema/findJsonSchemaByPath.js +13 -36
  231. package/lib/schema/findJsonSchemaByPath.js.map +1 -0
  232. package/lib/schema/formatZodError.js +140 -0
  233. package/lib/schema/formatZodError.js.map +1 -0
  234. package/lib/schema/formatZodError.test.js +196 -0
  235. package/lib/schema/getSchemaCache.js +5 -5
  236. package/lib/schema/getSchemaCache.js.map +1 -0
  237. package/lib/schema/getSchemaOptions.js +8 -11
  238. package/lib/schema/getSchemaOptions.js.map +1 -0
  239. package/lib/schema/index.js +2 -1
  240. package/lib/schema/index.js.map +1 -0
  241. package/lib/schema/toJsonSchema.js +47 -290
  242. package/lib/schema/toJsonSchema.js.map +1 -0
  243. package/lib/schema/validate.js +33 -45
  244. package/lib/schema/validate.js.map +1 -0
  245. package/lib/tools/generateSchema.js +39 -197
  246. package/lib/tools/generateSchema.js.map +1 -0
  247. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +55 -143
  248. package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +1 -0
  249. package/lib/utils/buildBaseUrl.js +13 -0
  250. package/lib/utils/buildBaseUrl.js.map +1 -0
  251. package/lib/utils/buildRedactorFormSchema.js +59 -0
  252. package/lib/utils/buildRedactorFormSchema.js.map +1 -0
  253. package/lib/utils/getEstimateProcessTime.js +12 -11
  254. package/lib/utils/getEstimateProcessTime.js.map +1 -0
  255. package/lib/utils/index.js +3 -0
  256. package/lib/utils/index.js.map +1 -0
  257. package/lib/utils/resolveFeatureOptions.js +12 -0
  258. package/lib/utils/resolveFeatureOptions.js.map +1 -0
  259. package/package.json +61 -13
  260. package/src/ai/qwen3vl/index.ts +1 -0
  261. package/src/ai/qwen3vl/utils.ts +36 -0
  262. package/src/ai/vision/DocLayoutElementTypeSchema.ts +30 -0
  263. package/src/ai/vision/ImageAnnotationSchema.ts +60 -0
  264. package/src/ai/vision/index.ts +2 -0
  265. package/src/ai/vision/resolveImageAnnotation.ts +135 -0
  266. package/src/cn/ChineseResidentIdNo.test.ts +1 -1
  267. package/src/cn/ChineseResidentIdNo.ts +8 -0
  268. package/src/cn/DivisionCode.test.ts +1 -1
  269. package/src/cn/DivisionCode.ts +8 -0
  270. package/src/cn/UnifiedSocialCreditCode.test.ts +1 -1
  271. package/src/cn/UnifiedSocialCreditCode.ts +15 -0
  272. package/src/cn/__snapshots__/UnifiedSocialCreditCode.test.ts.snap +23 -0
  273. package/src/cn/formatChineseAmount.ts +61 -0
  274. package/src/cn/index.ts +7 -1
  275. package/src/cn/parseChineseNumber.test.ts +159 -0
  276. package/src/cn/parseChineseNumber.ts +97 -0
  277. package/src/cn/pinyin/cartesianProduct.test.ts +64 -0
  278. package/src/cn/pinyin/cartesianProduct.ts +24 -0
  279. package/src/cn/pinyin/data.json +23573 -0
  280. package/src/cn/pinyin/loader.ts +12 -0
  281. package/src/cn/pinyin/preload.ts +3 -0
  282. package/src/cn/pinyin/toPinyin.test.ts +12 -0
  283. package/src/cn/pinyin/toPinyinPure.ts +43 -0
  284. package/src/cn/pinyin/transform.ts +12 -0
  285. package/src/consola/formatLogObject.test.ts +27 -0
  286. package/src/consola/formatLogObject.ts +34 -6
  287. package/src/dayjs/dayjs.ts +18 -18
  288. package/src/dayjs/index.ts +3 -1
  289. package/src/dayjs/parseRelativeTime.test.ts +185 -0
  290. package/src/dayjs/parseRelativeTime.ts +115 -0
  291. package/src/dayjs/resolveRelativeTime.test.ts +357 -0
  292. package/src/dayjs/resolveRelativeTime.ts +167 -0
  293. package/src/emittery/emitter.ts +9 -0
  294. package/src/emittery/index.ts +1 -0
  295. package/src/fs/FileSystemError.ts +26 -0
  296. package/src/fs/IFileSystem.d.ts +102 -0
  297. package/src/fs/MemoryFileSystem.test.ts +37 -0
  298. package/src/fs/createBrowserFileSystem.ts +291 -0
  299. package/src/fs/createMemoryFileSystem.ts +604 -0
  300. package/src/fs/createSandboxFileSystem.ts +136 -0
  301. package/src/fs/createWebDavFileSystem.ts +172 -0
  302. package/src/fs/findMimeType.ts +23 -0
  303. package/src/fs/index.ts +8 -0
  304. package/src/fs/orpc/FileSystemContract.ts +92 -0
  305. package/src/fs/orpc/createContractClientFileSystem.ts +115 -0
  306. package/src/fs/orpc/index.ts +2 -0
  307. package/src/fs/orpc/server/createFileSystemContractImpl.ts +64 -0
  308. package/src/fs/orpc/server/index.ts +1 -0
  309. package/src/fs/s3/createS3MiniFileSystem.ts +830 -0
  310. package/src/fs/s3/index.ts +1 -0
  311. package/src/fs/s3/s3mini.test.ts +264 -0
  312. package/src/fs/scandir.ts +75 -0
  313. package/src/fs/server/createDatabaseFileSystem.ts +668 -0
  314. package/src/fs/server/createNodeFileSystem.ts +499 -0
  315. package/src/fs/server/dbfs.test.ts +47 -0
  316. package/src/fs/server/index.ts +1 -0
  317. package/src/fs/server/loadTestDatabase.ts +131 -0
  318. package/src/fs/tests/runFileSystemTest.ts +288 -0
  319. package/src/fs/types.ts +29 -0
  320. package/src/fs/utils/getFileUrl.ts +44 -0
  321. package/src/fs/utils.ts +23 -0
  322. package/src/jsonschema/JsonSchema.ts +118 -110
  323. package/src/jsonschema/forEachJsonSchema.ts +50 -0
  324. package/src/jsonschema/index.ts +1 -0
  325. package/src/orpc/createOpenApiContractClient.ts +52 -0
  326. package/src/orpc/createRpcContractClient.ts +50 -0
  327. package/src/orpc/index.ts +2 -0
  328. package/src/orpc/resolveLinkPlugins.ts +29 -0
  329. package/src/password/PHC.ts +3 -3
  330. package/src/password/Password.test.ts +1 -1
  331. package/src/password/createPBKDF2PasswordAlgorithm.ts +2 -2
  332. package/src/resource/schema/AnyResourceSchema.ts +16 -2
  333. package/src/s3/formatS3Url.test.ts +254 -0
  334. package/src/s3/formatS3Url.ts +84 -0
  335. package/src/s3/index.ts +2 -0
  336. package/src/s3/parseS3Url.test.ts +258 -0
  337. package/src/s3/parseS3Url.ts +88 -0
  338. package/src/schema/SchemaRegistry.ts +35 -33
  339. package/src/schema/formatZodError.test.ts +196 -0
  340. package/src/schema/formatZodError.ts +151 -0
  341. package/src/schema/getSchemaOptions.ts +2 -2
  342. package/src/schema/index.ts +1 -1
  343. package/src/utils/buildBaseUrl.ts +12 -0
  344. package/src/utils/buildRedactorFormSchema.ts +85 -0
  345. package/src/utils/index.ts +4 -0
  346. package/src/utils/resolveFeatureOptions.ts +14 -0
  347. package/src/cn/ChineseResidentIdNo.mod.ts +0 -7
  348. package/src/cn/DivisionCode.mod.ts +0 -7
  349. package/src/cn/UnifiedSocialCreditCode.mod.ts +0 -7
  350. package/src/cn/mod.ts +0 -3
  351. package/src/schema/SchemaRegistry.mod.ts +0 -1
@@ -0,0 +1,288 @@
1
+ import { expect } from 'vitest';
2
+ import { FileSystemError, FileSystemErrorCode } from '../FileSystemError';
3
+ import type { IFileSystem } from '../IFileSystem';
4
+
5
+ export type RunFileSystemTestOptions = {
6
+ writableStream?: boolean;
7
+ readableStream?: boolean;
8
+ readStream?: boolean;
9
+ writeStream?: boolean;
10
+ abort?: boolean;
11
+ };
12
+
13
+ export async function runFileSystemTest(fs: IFileSystem, options: RunFileSystemTestOptions = {}) {
14
+ const { writableStream = true, readableStream = true, readStream = true, writeStream = true, abort = true } = options;
15
+ // should be implemented
16
+ const stat = await fs.stat('/README.txt');
17
+ expect(stat).toMatchObject({
18
+ path: '/README.txt',
19
+ directory: '/',
20
+ name: 'README.txt',
21
+ kind: 'file',
22
+ size: 5,
23
+ });
24
+ await fs.mkdir('/');
25
+ const entries = await fs.readdir('/');
26
+ expect(entries.some((e) => e.name === 'README.txt')).toBe(true);
27
+ await fs.mkdir('/test');
28
+
29
+ if (fs.getUrl) {
30
+ expect(fs.getUrl(await fs.stat('/README.txt'))).toBeTypeOf('string');
31
+ }
32
+
33
+ // should handle AbortSignal
34
+ if (abort) {
35
+ const controller = new AbortController();
36
+ controller.abort();
37
+
38
+ await expect(fs.stat('/README.txt', { signal: controller.signal })).rejects.toThrow(Error);
39
+ await expect(fs.readdir('/', { signal: controller.signal })).rejects.toThrow(Error);
40
+ await expect(fs.mkdir('/test', { signal: controller.signal })).rejects.toThrow(Error);
41
+ await expect(fs.readFile('/README.txt', { signal: controller.signal })).rejects.toThrow(Error);
42
+ await expect(fs.writeFile('/test.txt', 'test', { signal: controller.signal })).rejects.toThrow(Error);
43
+ await expect(fs.rm('/README.txt', { signal: controller.signal })).rejects.toThrow(Error);
44
+ await expect(fs.rename('/README.txt', '/new.txt', { signal: controller.signal })).rejects.toThrow(Error);
45
+ await expect(fs.copy('/README.txt', '/copy.txt', { signal: controller.signal })).rejects.toThrow(Error);
46
+ }
47
+
48
+ // should validate input parameters
49
+ await expect(fs.stat('')).rejects.toThrow(FileSystemError);
50
+ await expect(fs.stat('')).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
51
+ await expect(fs.stat(null as any)).rejects.toThrow(FileSystemError);
52
+ await expect(fs.stat(null as any)).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
53
+ await expect(fs.stat(undefined as any)).rejects.toThrow(FileSystemError);
54
+ await expect(fs.stat(undefined as any)).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
55
+ await expect(fs.stat(123 as any)).rejects.toThrow(FileSystemError);
56
+ await expect(fs.stat(123 as any)).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
57
+
58
+ await expect(fs.writeFile('', 'test')).rejects.toThrow(FileSystemError);
59
+ await expect(fs.writeFile('', 'test')).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
60
+ await expect(fs.writeFile('/test', null as any)).rejects.toThrow(FileSystemError);
61
+ await expect(fs.writeFile('/test', null as any)).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
62
+ await expect(fs.writeFile('/test', undefined as any)).rejects.toThrow(FileSystemError);
63
+ await expect(fs.writeFile('/test', undefined as any)).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
64
+ await expect(fs.writeFile('/', 'test')).rejects.toThrow(FileSystemError);
65
+ await expect(fs.writeFile('/', 'test')).rejects.toMatchObject({ code: FileSystemErrorCode.EINVAL });
66
+
67
+ // should support streaming operations
68
+ if (readStream && fs.createReadStream) {
69
+ await fs.writeFile('/stream.txt', 'Hello, World!');
70
+
71
+ // Test createReadStream
72
+ const readStream = fs.createReadStream('/stream.txt');
73
+ expect(readStream).toBeDefined();
74
+
75
+ const chunks: Buffer[] = [];
76
+ for await (const chunk of readStream) {
77
+ chunks.push(chunk);
78
+ }
79
+ expect(Buffer.concat(chunks).toString()).toBe('Hello, World!');
80
+
81
+ // Test createReadStream with range
82
+ const rangeStream = fs.createReadStream('/stream.txt', { range: { start: 0, end: 4 } });
83
+ const rangeChunks: Buffer[] = [];
84
+ for await (const chunk of rangeStream) {
85
+ rangeChunks.push(chunk);
86
+ }
87
+ expect(Buffer.concat(rangeChunks).toString()).toBe('Hello');
88
+ }
89
+
90
+ if (writeStream && fs.createWriteStream) {
91
+ // Test createWriteStream
92
+ const writeStream = fs.createWriteStream('/write-test.txt');
93
+ expect(writeStream).toBeDefined();
94
+
95
+ writeStream.write('Test content');
96
+ writeStream.end();
97
+
98
+ await new Promise((resolve) => writeStream.on('finish', resolve));
99
+ expect(await fs.readFile('/write-test.txt', { encoding: 'text' })).toBe('Test content');
100
+ }
101
+
102
+ // should support Web Streams API
103
+ if (readableStream) {
104
+ await fs.writeFile('/webstream.txt', 'Web Stream Test');
105
+
106
+ // Test createReadableStream
107
+ const readableStream = fs.createReadableStream('/webstream.txt');
108
+ expect(readableStream).toBeDefined();
109
+
110
+ const reader = readableStream.getReader();
111
+ const { value } = await reader.read();
112
+ expect(value?.toString()).toBe('Web Stream Test');
113
+ }
114
+
115
+ if (writableStream) {
116
+ // Test createWritableStream
117
+ const writableStream = fs.createWritableStream('/web-write-test.txt');
118
+ expect(writableStream).toBeDefined();
119
+
120
+ const writer = writableStream.getWriter();
121
+ await writer.write(Buffer.from('Web Stream Write Test'));
122
+ await writer.close();
123
+
124
+ expect(await fs.readFile('/web-write-test.txt', { encoding: 'text' })).toBe('Web Stream Write Test');
125
+ }
126
+
127
+ // should handle streaming errors
128
+ if (abort && readStream && fs.createReadStream) {
129
+ const controller2 = new AbortController();
130
+
131
+ // Test read stream with abort
132
+ const readStream = fs.createReadStream('/README.txt', { signal: controller2.signal });
133
+ controller2.abort();
134
+
135
+ await expect(
136
+ new Promise((_, reject) => {
137
+ readStream.on('error', reject);
138
+ }),
139
+ ).rejects.toThrow(Error);
140
+ }
141
+
142
+ if (abort && writeStream && fs.createWriteStream) {
143
+ // Test write stream with abort
144
+ const controller3 = new AbortController();
145
+ const writeStream = fs.createWriteStream('/abort-test.txt', { signal: controller3.signal });
146
+ controller3.abort();
147
+
148
+ await expect(
149
+ new Promise((_, reject) => {
150
+ writeStream.on('error', reject);
151
+ writeStream.write('test');
152
+ }),
153
+ ).rejects.toThrow(Error);
154
+ }
155
+
156
+ // should handle file operations correctly
157
+ // Test file creation
158
+ await fs.writeFile('/newfile.txt', 'New content');
159
+ expect(await fs.exists('/newfile.txt')).toBe(true);
160
+
161
+ const stat2 = await fs.stat('/newfile.txt');
162
+ expect(stat2.kind).toBe('file');
163
+ expect(stat2.size).toBe(11); // "New content" is 11 bytes
164
+
165
+ // Test file reading
166
+ const content = await fs.readFile('/newfile.txt', { encoding: 'text' });
167
+ expect(content).toBe('New content');
168
+
169
+ // Test file reading as binary
170
+ const binary = await fs.readFile('/newfile.txt');
171
+ expect(Buffer.from(binary).toString()).toBe('New content');
172
+
173
+ // Test file overwrite
174
+ await fs.writeFile('/newfile.txt', 'Updated content');
175
+ expect(await fs.readFile('/newfile.txt', { encoding: 'text' })).toBe('Updated content');
176
+
177
+ // Test file overwrite protection
178
+ await expect(fs.writeFile('/newfile.txt', 'Should fail', { overwrite: false })).rejects.toThrow(FileSystemError);
179
+ await expect(fs.writeFile('/newfile.txt', 'Should fail', { overwrite: false })).rejects.toMatchObject({
180
+ code: FileSystemErrorCode.EEXIST,
181
+ });
182
+
183
+ // Test large file write (should use file_node_content table)
184
+ // Create ~1KB data to test large file handling
185
+ const largeData = 'x'.repeat(1024); // 1KB of data
186
+ await fs.writeFile('/largefile.txt', largeData);
187
+ const largeFileStat = await fs.stat('/largefile.txt');
188
+ expect(largeFileStat.size).toBe(1024);
189
+ const largeFileContent = await fs.readFile('/largefile.txt', { encoding: 'text' });
190
+ expect(largeFileContent).toBe(largeData);
191
+ expect(largeFileContent.length).toBe(1024);
192
+
193
+ // should handle directory operations correctly
194
+ // Test directory creation
195
+ await fs.mkdir('/newdir');
196
+ expect(await fs.exists('/newdir')).toBe(true);
197
+
198
+ const stat3 = await fs.stat('/newdir');
199
+ expect(stat3.kind).toBe('directory');
200
+
201
+ // Test recursive directory creation
202
+ await fs.mkdir('/deep/nested/dir', { recursive: true });
203
+ expect(await fs.exists('/deep/nested/dir')).toBe(true);
204
+
205
+ // Test non-recursive directory creation failure
206
+ await expect(fs.mkdir('/another/deep/dir')).rejects.toThrow(FileSystemError);
207
+ await expect(fs.mkdir('/another/deep/dir')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
208
+
209
+ // Test directory listing
210
+ await fs.writeFile('/newdir/file1.txt', 'File 1');
211
+ await fs.writeFile('/newdir/file2.txt', 'File 2');
212
+
213
+ const contents = await fs.readdir('/newdir');
214
+ expect(contents).toHaveLength(2);
215
+ expect(contents.map((f) => f.name)).toContain('file1.txt');
216
+ expect(contents.map((f) => f.name)).toContain('file2.txt');
217
+
218
+ // should handle file removal correctly
219
+ await fs.writeFile('/toremove.txt', 'Remove me');
220
+ expect(await fs.exists('/toremove.txt')).toBe(true);
221
+
222
+ await fs.rm('/toremove.txt');
223
+ expect(await fs.exists('/toremove.txt')).toBe(false);
224
+
225
+ // Test force removal
226
+ await expect(fs.rm('/nonexistent.txt')).rejects.toThrow(FileSystemError);
227
+ await expect(fs.rm('/nonexistent.txt')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
228
+ await fs.rm('/nonexistent.txt', { force: true }); // Should not throw
229
+
230
+ // Test recursive removal
231
+ await fs.mkdir('/dirwithfiles', { recursive: true });
232
+ await fs.writeFile('/dirwithfiles/file.txt', 'content');
233
+ await expect(fs.rm('/dirwithfiles')).rejects.toThrow(FileSystemError);
234
+ await expect(fs.rm('/dirwithfiles')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOTEMPTY });
235
+ await fs.rm('/dirwithfiles', { recursive: true });
236
+ expect(await fs.exists('/dirwithfiles')).toBe(false);
237
+
238
+ // should handle file rename correctly
239
+ await fs.writeFile('/rename.txt', 'Original content');
240
+ expect(await fs.exists('/rename.txt')).toBe(true);
241
+
242
+ await fs.rename('/rename.txt', '/renamed.txt');
243
+ expect(await fs.exists('/rename.txt')).toBe(false);
244
+ expect(await fs.exists('/renamed.txt')).toBe(true);
245
+ expect(await fs.readFile('/renamed.txt', { encoding: 'text' })).toBe('Original content');
246
+
247
+ // should handle file copy correctly
248
+ await fs.writeFile('/copy.txt', 'Copy me');
249
+ expect(await fs.exists('/copy.txt')).toBe(true);
250
+
251
+ await fs.copy('/copy.txt', '/copied.txt');
252
+ expect(await fs.exists('/copy.txt')).toBe(true);
253
+ expect(await fs.exists('/copied.txt')).toBe(true);
254
+ expect(await fs.readFile('/copied.txt', { encoding: 'text' })).toBe('Copy me');
255
+
256
+ // Test copy overwrite
257
+ await fs.writeFile('/target2.txt', 'Target content');
258
+ await expect(fs.copy('/copy.txt', '/target2.txt')).rejects.toThrow(FileSystemError);
259
+ await expect(fs.copy('/copy.txt', '/target2.txt')).rejects.toMatchObject({ code: FileSystemErrorCode.EEXIST });
260
+ await fs.copy('/copy.txt', '/target2.txt', { overwrite: true });
261
+ expect(await fs.readFile('/target2.txt', { encoding: 'text' })).toBe('Copy me');
262
+
263
+ // should handle edge cases correctly
264
+ // Test root directory operations
265
+ await expect(fs.stat('/')).resolves.toBeDefined();
266
+ await expect(fs.readdir('/')).resolves.toBeDefined();
267
+ await fs.mkdir('/'); // Should not throw
268
+
269
+ // Test path normalization
270
+ await fs.writeFile('/normalize.txt', 'test');
271
+ expect(await fs.exists('/normalize.txt')).toBe(true);
272
+ expect(await fs.exists('/./normalize.txt')).toBe(true);
273
+ // Note: the exists method may return true for files with trailing slashes due to normalization
274
+
275
+ // Test error cases
276
+ await expect(fs.stat('/nonexistent')).rejects.toThrow(FileSystemError);
277
+ await expect(fs.stat('/nonexistent')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
278
+ await expect(fs.readdir('/nonexistent')).rejects.toThrow(FileSystemError);
279
+ await expect(fs.readdir('/nonexistent')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
280
+ await expect(fs.readFile('/nonexistent')).rejects.toThrow(FileSystemError);
281
+ await expect(fs.readFile('/nonexistent')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
282
+ await expect(fs.rm('/nonexistent')).rejects.toThrow(FileSystemError);
283
+ await expect(fs.rm('/nonexistent')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
284
+ await expect(fs.rename('/nonexistent', '/new')).rejects.toThrow(FileSystemError);
285
+ await expect(fs.rename('/nonexistent', '/new')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
286
+ await expect(fs.copy('/nonexistent', '/new')).rejects.toThrow(FileSystemError);
287
+ await expect(fs.copy('/nonexistent', '/new')).rejects.toMatchObject({ code: FileSystemErrorCode.ENOENT });
288
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod/v4';
2
+
3
+ type EnumValues<T> = T[Exclude<keyof T, '__proto__'>];
4
+ export const FileKind = Object.freeze({
5
+ __proto__: null,
6
+ directory: 'directory',
7
+ file: 'file',
8
+ });
9
+ export type FileKind = EnumValues<typeof FileKind>;
10
+ export const FileKindSchema = z.enum(['directory', 'file']);
11
+
12
+ export type ReaddirOptions = z.infer<typeof ReaddirOptionsSchema>;
13
+ export const ReaddirOptionsSchema = z.object({
14
+ recursive: z.boolean().optional(),
15
+ depth: z.number().optional(),
16
+ glob: z.string().optional(),
17
+ kind: FileKindSchema.optional(),
18
+ cursor: z.string().optional(),
19
+ hidden: z.boolean().default(false),
20
+ });
21
+
22
+ export type FileUrlOptions = z.infer<typeof FileUrlOptionsSchema>;
23
+ export const FileUrlOptionsSchema = z.object({
24
+ size: z.coerce.number().optional(),
25
+ width: z.number().optional(),
26
+ height: z.number().optional(),
27
+ quality: z.number().optional(),
28
+ thumbnail: z.boolean().optional(),
29
+ });
@@ -0,0 +1,44 @@
1
+ import type { IFileStat, IFileSystem } from '../IFileSystem';
2
+ import type { FileUrlOptions } from '../types';
3
+
4
+ export function getFileUrl(
5
+ fs: IFileSystem,
6
+ needle?: IFileStat | string,
7
+ {
8
+ ...options
9
+ }: FileUrlOptions & {
10
+ fs?: IFileSystem;
11
+ } = {},
12
+ ) {
13
+ const [file, path] = resolveFilePath(needle);
14
+ if (!path || !needle) return;
15
+
16
+ let out: string | undefined;
17
+ if (fs?.getUrl) {
18
+ try {
19
+ out = fs.getUrl(needle, options);
20
+ } catch (e) {
21
+ console.error(`failed to get file url`, needle, e);
22
+ }
23
+ }
24
+ if (!out && file) {
25
+ out = file.meta?.url || (file as any).url;
26
+ }
27
+ return out;
28
+ }
29
+
30
+ export function resolveFilePath(needle: IFileStat): [IFileStat, string];
31
+ export function resolveFilePath(needle: string): [undefined, string];
32
+ export function resolveFilePath(needle?: IFileStat | string): [IFileStat | undefined, string | undefined];
33
+ export function resolveFilePath(needle?: IFileStat | string): [IFileStat | undefined, string | undefined] {
34
+ if (!needle) {
35
+ return [undefined, undefined];
36
+ }
37
+ let file = typeof needle === 'string' ? undefined : needle;
38
+ let path = typeof needle === 'string' ? needle : needle.path;
39
+
40
+ if (file && !path) {
41
+ path = file.path;
42
+ }
43
+ return [file, path];
44
+ }
@@ -0,0 +1,23 @@
1
+ import { ArrayBuffers, classOf } from '@wener/utils';
2
+ import type { IFileStat, WritableData } from './IFileSystem';
3
+
4
+ export function resolveData(data: WritableData) {
5
+ let buf: Uint8Array;
6
+ if (typeof data === 'string') {
7
+ buf = ArrayBuffers.toUint8Array(ArrayBuffers.from(data, 'utf8'));
8
+ } else if (data instanceof ArrayBuffer) {
9
+ buf = new Uint8Array(data);
10
+ } else if (data instanceof Uint8Array) {
11
+ buf = data;
12
+ } else {
13
+ throw new Error(`unable to resolve data: ${typeof data} ${classOf(data)}`);
14
+ }
15
+ return buf;
16
+ }
17
+
18
+ export function getPath(f: IFileStat | string) {
19
+ if (typeof f === 'string') {
20
+ return f;
21
+ }
22
+ return f.path;
23
+ }
@@ -1,26 +1,25 @@
1
1
  import type { Static, TSchema } from '@sinclair/typebox';
2
+ import { isNil } from '@wener/utils';
2
3
  import Ajv, { type ErrorObject, type Options } from 'ajv';
3
4
  import addFormats from 'ajv-formats';
4
- // import localize from 'ajv-i18n/localize/zh';
5
5
  import addKeywords from 'ajv-keywords';
6
- import { isNil } from 'es-toolkit';
7
6
  import { match, P } from 'ts-pattern';
8
7
  import type { JsonSchemaDef } from './types';
9
8
 
10
- function _createAjv(opt: Options) {
9
+ function _createValidator(opt: Options) {
11
10
  const ajv = new Ajv(opt);
12
11
  addKeywords(ajv);
13
12
  addFormats(ajv);
14
13
  return ajv;
15
14
  }
16
15
 
17
- type ValidateOptions = { mutate?: boolean; clone?: boolean; ajv?: Ajv };
16
+ type ValidateOptions = { mutate?: boolean; clone?: boolean; validator?: Ajv };
18
17
 
19
18
  type ValidateResult<T> =
20
19
  | { data: T; success: true; message: undefined }
21
20
  | { data: undefined; success: false; message: string; errors: ErrorObject[] };
22
21
 
23
- function validate({ schema, data, mutate, clone, ajv }: ValidateOptions & { schema: any; data: any }) {
22
+ function validate({ schema, data, mutate, clone, validator }: ValidateOptions & { schema: any; data: any }) {
24
23
  let opts: Options = {
25
24
  // strict: 'log',
26
25
  strict: true,
@@ -35,11 +34,11 @@ function validate({ schema, data, mutate, clone, ajv }: ValidateOptions & { sche
35
34
  data = structuredClone(data);
36
35
  }
37
36
 
38
- if (!ajv) {
39
- ajv = JsonSchema.createAjv(opts);
37
+ if (!validator) {
38
+ validator = JsonSchema.createValidator(opts);
40
39
  }
41
40
 
42
- const validate = ajv.compile(schema);
41
+ const validate = validator.compile(schema);
43
42
 
44
43
  // consider reusing validate instance
45
44
 
@@ -47,119 +46,128 @@ function validate({ schema, data, mutate, clone, ajv }: ValidateOptions & { sche
47
46
  const errors = validate.errors;
48
47
  // localize(errors);
49
48
 
50
- return { data, success: valid, message: ajv.errorsText(errors), errors: errors };
49
+ return { data, success: valid, message: validator.errorsText(errors), errors: errors };
51
50
  }
52
51
 
53
52
  type TypeOfSchema<S> = S extends TSchema ? Static<S> : any;
54
53
 
55
- export namespace JsonSchema {
56
- export let schemas: JsonSchemaDef[] = [];
57
-
58
- export let createAjv = _createAjv;
59
-
60
- export function addSchema(
61
- schema: JsonSchemaDef,
62
- {
63
- onConflict = 'throw',
64
- }: {
65
- onConflict?: 'throw' | 'ignore' | 'replace' | ((old: JsonSchemaDef, neo: JsonSchemaDef) => JsonSchemaDef);
66
- } = {},
67
- ) {
68
- if (!schema.$id) throw new Error('Schema must have $id');
69
- switch (onConflict) {
70
- case 'ignore':
71
- onConflict = (old) => old;
72
- break;
73
- case 'replace':
74
- onConflict = (_, neo) => neo;
75
- break;
76
- case 'throw':
77
- onConflict = (old, neo) => {
78
- throw new Error(`Schema ${neo.$id} already exists`);
79
- };
80
- break;
81
- }
82
- let idx = schemas.findIndex((s) => s.$id === schema.$id);
83
- if (idx >= 0) {
84
- schemas[idx] = onConflict(schemas[idx], schema);
85
- } else {
86
- schemas.push(schema);
87
- }
54
+ let schemas: JsonSchemaDef[] = [];
55
+
56
+ let createValidator = _createValidator;
57
+
58
+ function addSchema(
59
+ schema: JsonSchemaDef,
60
+ {
61
+ onConflict = 'throw',
62
+ }: {
63
+ onConflict?: 'throw' | 'ignore' | 'replace' | ((old: JsonSchemaDef, neo: JsonSchemaDef) => JsonSchemaDef);
64
+ } = {},
65
+ ) {
66
+ if (!schema.$id) throw new Error('Schema must have $id');
67
+ switch (onConflict) {
68
+ case 'ignore':
69
+ onConflict = (old) => old;
70
+ break;
71
+ case 'replace':
72
+ onConflict = (_, neo) => neo;
73
+ break;
74
+ case 'throw':
75
+ onConflict = (old, neo) => {
76
+ throw new Error(`Schema ${neo.$id} already exists`);
77
+ };
78
+ break;
88
79
  }
89
-
90
- /**
91
- * Check data is valid, will not use default
92
- */
93
- export function check<S>(schema: S, data: any): ValidateResult<TypeOfSchema<S>> {
94
- return validate({ schema, data, mutate: false, clone: true }) as any;
80
+ let idx = schemas.findIndex((s) => s.$id === schema.$id);
81
+ if (idx >= 0) {
82
+ schemas[idx] = onConflict(schemas[idx], schema);
83
+ } else {
84
+ schemas.push(schema);
95
85
  }
86
+ }
96
87
 
97
- /**
98
- * Parse data with default value and coerceTypes
99
- */
100
- export function safeParse<S>(schema: S, data: any): ValidateResult<TypeOfSchema<S>> {
101
- return validate({ schema, data, mutate: true, clone: true }) as any;
102
- }
88
+ /**
89
+ * Check data is valid, will not use default
90
+ */
91
+ function check<S>(schema: S, data: any): ValidateResult<TypeOfSchema<S>> {
92
+ return validate({ schema, data, mutate: false, clone: true }) as any;
93
+ }
103
94
 
104
- export function parse<S>(schema: S, data: any): TypeOfSchema<S> {
105
- const { data: out, message, errors } = validate({ schema, data, mutate: true, clone: true });
106
- if (errors) {
107
- throw new Error(message);
108
- }
109
- return out;
95
+ /**
96
+ * Parse data with default value and coerceTypes
97
+ */
98
+ function safeParse<S>(schema: S, data: any): ValidateResult<TypeOfSchema<S>> {
99
+ return validate({ schema, data, mutate: true, clone: true }) as any;
100
+ }
101
+
102
+ function parse<S>(schema: S, data: any): TypeOfSchema<S> {
103
+ const { data: out, message, errors } = validate({ schema, data, mutate: true, clone: true });
104
+ if (errors) {
105
+ throw new Error(message);
110
106
  }
107
+ return out;
108
+ }
111
109
 
112
- export function create<S>(schema: S, data?: any): TypeOfSchema<S> {
113
- // will not ensure value match the rule
114
- return match(schema as JsonSchemaDef)
115
- .returnType<any>()
116
- .with({ const: P.nonNullable }, (v) => v)
117
- .with({ default: P.select() }, (v) => v)
118
- .with({ anyOf: P.nonNullable }, (schema) => {
119
- return create(schema.anyOf[0]);
120
- })
121
- .with({ oneOf: P.nonNullable }, (schema) => {
122
- return create(schema.oneOf[0]);
123
- })
124
- .with({ type: 'string' }, (schema) => '')
125
- .with({ type: P.union('number', 'integer') }, (schema) => 0)
126
- .with({ type: 'object' }, (schema) => {
127
- let out = validate({ schema, data: data ?? {}, mutate: true });
128
- if (!out.success) {
129
- // fallback
130
- let obj = data || {};
131
- schema.required?.forEach((key) => {
132
- if (!(key in obj)) {
133
- let last = obj[key];
134
- let prop = schema.properties?.[key];
135
- if (prop && isNil(last)) obj[key] = JsonSchema.create(prop, last);
136
- }
137
- });
138
- out = validate({ schema, data: obj, mutate: true });
139
- if (!out.success) {
140
- console.warn(`Failed to create object with schema: ${out.message}`);
110
+ function create<S>(schema: S, data?: any): TypeOfSchema<S> {
111
+ // will not ensure value match the rule
112
+ return match(schema as JsonSchemaDef)
113
+ .returnType<any>()
114
+ .with({ const: P.nonNullable }, (v) => v)
115
+ .with({ default: P.select() }, (v) => v)
116
+ .with({ anyOf: P.nonNullable }, (schema) => {
117
+ return create(schema.anyOf[0]);
118
+ })
119
+ .with({ oneOf: P.nonNullable }, (schema) => {
120
+ return create(schema.oneOf[0]);
121
+ })
122
+ .with({ type: 'string' }, (schema) => '')
123
+ .with({ type: P.union('number', 'integer') }, (schema) => 0)
124
+ .with({ type: 'object' }, (schema: JsonSchemaDef) => {
125
+ let out = validate({ schema, data: data ?? {}, mutate: true });
126
+ if (!out.success) {
127
+ // fallback
128
+ let obj = data || {};
129
+ schema.required?.forEach((key) => {
130
+ if (!(key in obj)) {
131
+ let last = obj[key];
132
+ let prop = schema.properties?.[key];
133
+ if (prop && isNil(last)) obj[key] = JsonSchema.create(prop, last);
141
134
  }
135
+ });
136
+ out = validate({ schema, data: obj, mutate: true });
137
+ if (!out.success) {
138
+ console.warn(`Failed to create object with schema: ${out.message}`);
142
139
  }
143
- return out.data;
144
- })
145
- .with({ type: 'null' }, () => null)
146
- .with({ type: 'boolean' }, (schema) => false)
147
- .with({ type: 'array' }, (schema) => [])
148
- .otherwise(() => {
149
- return undefined;
150
- });
151
- }
140
+ }
141
+ return out.data;
142
+ })
143
+ .with({ type: 'null' }, () => null)
144
+ .with({ type: 'boolean' }, (schema) => false)
145
+ .with({ type: 'array' }, (schema) => [])
146
+ .otherwise(() => {
147
+ return undefined;
148
+ });
149
+ }
152
150
 
153
- export function isPrimitiveType(schema: any): boolean {
154
- return match(schema as JsonSchemaDef)
155
- .returnType<boolean>()
156
- .with({ type: P.union('number', 'integer', 'string', 'boolean') }, () => true)
157
- .with({ anyOf: P.nonNullable }, (schema) => {
158
- return isPrimitiveType(schema.anyOf[0]);
159
- })
160
- .with({ oneOf: P.nonNullable }, (schema) => {
161
- return isPrimitiveType(schema.oneOf[0]);
162
- })
163
- .otherwise(() => false);
164
- }
151
+ function isPrimitiveType(schema: any): boolean {
152
+ return match(schema as JsonSchemaDef)
153
+ .returnType<boolean>()
154
+ .with({ type: P.union('number', 'integer', 'string', 'boolean') }, () => true)
155
+ .with({ anyOf: P.nonNullable }, (schema) => {
156
+ return isPrimitiveType(schema.anyOf[0]);
157
+ })
158
+ .with({ oneOf: P.nonNullable }, (schema) => {
159
+ return isPrimitiveType(schema.oneOf[0]);
160
+ })
161
+ .otherwise(() => false);
165
162
  }
163
+
164
+ export const JsonSchema = {
165
+ createValidator,
166
+ addSchema,
167
+ schemas,
168
+ check,
169
+ safeParse,
170
+ parse,
171
+ create,
172
+ isPrimitiveType,
173
+ } as const;