@fast-china/utils 1.0.37 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/CONTRIBUTING.md +87 -0
  3. package/README.md +111 -50
  4. package/README.zh.md +111 -50
  5. package/SECURITY.md +46 -0
  6. package/dist/array/index.d.mts +87 -0
  7. package/dist/array/index.d.mts.map +1 -0
  8. package/dist/array/index.mjs +161 -0
  9. package/dist/array/index.mjs.map +1 -0
  10. package/dist/async/index.d.mts +146 -0
  11. package/dist/async/index.d.mts.map +1 -0
  12. package/dist/async/index.mjs +336 -0
  13. package/dist/async/index.mjs.map +1 -0
  14. package/dist/base64/index.d.mts +105 -0
  15. package/dist/base64/index.d.mts.map +1 -0
  16. package/dist/base64/index.mjs +427 -0
  17. package/dist/base64/index.mjs.map +1 -0
  18. package/dist/color/index.d.mts +90 -0
  19. package/dist/color/index.d.mts.map +1 -0
  20. package/dist/color/index.mjs +178 -0
  21. package/dist/color/index.mjs.map +1 -0
  22. package/dist/crypto/index.d.mts +157 -0
  23. package/dist/crypto/index.d.mts.map +1 -0
  24. package/dist/crypto/index.mjs +541 -0
  25. package/dist/crypto/index.mjs.map +1 -0
  26. package/dist/date/index.d.mts +191 -0
  27. package/dist/date/index.d.mts.map +1 -0
  28. package/dist/date/index.mjs +383 -0
  29. package/dist/date/index.mjs.map +1 -0
  30. package/dist/dom/style.d.mts +30 -0
  31. package/dist/dom/style.d.mts.map +1 -0
  32. package/dist/dom/style.mjs +74 -0
  33. package/dist/dom/style.mjs.map +1 -0
  34. package/dist/env/index.d.mts +63 -0
  35. package/dist/env/index.d.mts.map +1 -0
  36. package/dist/env/index.mjs +97 -0
  37. package/dist/env/index.mjs.map +1 -0
  38. package/dist/identity/index.d.mts +78 -0
  39. package/dist/identity/index.d.mts.map +1 -0
  40. package/dist/identity/index.mjs +87 -0
  41. package/dist/identity/index.mjs.map +1 -0
  42. package/dist/index.d.mts +24 -0
  43. package/dist/index.mjs +23 -0
  44. package/dist/internal/text.mjs +36 -0
  45. package/dist/internal/text.mjs.map +1 -0
  46. package/dist/logger/index.d.mts +87 -0
  47. package/dist/logger/index.d.mts.map +1 -0
  48. package/dist/logger/index.mjs +124 -0
  49. package/dist/logger/index.mjs.map +1 -0
  50. package/dist/number/index.d.mts +89 -0
  51. package/dist/number/index.d.mts.map +1 -0
  52. package/dist/number/index.mjs +215 -0
  53. package/dist/number/index.mjs.map +1 -0
  54. package/dist/object/index.d.mts +76 -0
  55. package/dist/object/index.d.mts.map +1 -0
  56. package/dist/object/index.mjs +134 -0
  57. package/dist/object/index.mjs.map +1 -0
  58. package/dist/storage/index.d.mts +104 -0
  59. package/dist/storage/index.d.mts.map +1 -0
  60. package/dist/storage/index.mjs +324 -0
  61. package/dist/storage/index.mjs.map +1 -0
  62. package/dist/string/index.d.mts +130 -0
  63. package/dist/string/index.d.mts.map +1 -0
  64. package/dist/string/index.mjs +275 -0
  65. package/dist/string/index.mjs.map +1 -0
  66. package/dist/vue/emits.d.mts +24 -0
  67. package/dist/vue/emits.d.mts.map +1 -0
  68. package/dist/vue/emits.mjs +47 -0
  69. package/dist/vue/emits.mjs.map +1 -0
  70. package/dist/vue/expose.d.mts +12 -0
  71. package/dist/vue/expose.d.mts.map +1 -0
  72. package/dist/vue/expose.mjs +16 -0
  73. package/dist/vue/expose.mjs.map +1 -0
  74. package/dist/vue/func.d.mts +14 -0
  75. package/dist/vue/func.d.mts.map +1 -0
  76. package/dist/vue/func.mjs +16 -0
  77. package/dist/vue/func.mjs.map +1 -0
  78. package/dist/vue/index.d.mts +9 -0
  79. package/dist/vue/install.d.mts +69 -0
  80. package/dist/vue/install.d.mts.map +1 -0
  81. package/dist/vue/install.mjs +123 -0
  82. package/dist/vue/install.mjs.map +1 -0
  83. package/dist/vue/props.d.mts +23 -0
  84. package/dist/vue/props.d.mts.map +1 -0
  85. package/dist/vue/props.mjs +41 -0
  86. package/dist/vue/props.mjs.map +1 -0
  87. package/dist/vue/render.d.mts +13 -0
  88. package/dist/vue/render.d.mts.map +1 -0
  89. package/dist/vue/render.mjs +23 -0
  90. package/dist/vue/render.mjs.map +1 -0
  91. package/dist/vue/slots.d.mts +19 -0
  92. package/dist/vue/slots.d.mts.map +1 -0
  93. package/dist/vue/slots.mjs +13 -0
  94. package/dist/vue/slots.mjs.map +1 -0
  95. package/dist/vue/with.d.mts +12 -0
  96. package/dist/vue/with.d.mts.map +1 -0
  97. package/dist/vue/with.mjs +15 -0
  98. package/dist/vue/with.mjs.map +1 -0
  99. package/docs/API.md +96 -0
  100. package/docs/API.zh-CN.md +96 -0
  101. package/docs/DEVELOPMENT_RELEASE.zh-CN.md +65 -0
  102. package/docs/RUNTIME_CONTRACT.md +37 -0
  103. package/package.json +65 -73
  104. package/src/array/index.ts +173 -0
  105. package/src/async/index.ts +475 -0
  106. package/src/base64/index.ts +374 -0
  107. package/src/color/index.ts +208 -0
  108. package/src/crypto/index.ts +670 -0
  109. package/src/date/index.ts +451 -0
  110. package/src/dom/index.ts +6 -0
  111. package/src/dom/style.ts +92 -0
  112. package/src/env/index.ts +169 -0
  113. package/src/identity/index.ts +144 -0
  114. package/src/index.ts +20 -0
  115. package/src/internal/text.ts +46 -0
  116. package/src/logger/index.ts +219 -0
  117. package/src/number/index.ts +235 -0
  118. package/src/object/index.ts +160 -0
  119. package/src/storage/index.ts +524 -0
  120. package/src/string/index.ts +328 -0
  121. package/src/vue/emits.ts +71 -0
  122. package/src/vue/expose.ts +11 -0
  123. package/src/vue/func.ts +17 -0
  124. package/src/vue/index.ts +13 -0
  125. package/src/vue/install.ts +185 -0
  126. package/src/vue/props.ts +39 -0
  127. package/src/vue/render.ts +41 -0
  128. package/src/vue/slots.ts +23 -0
  129. package/src/vue/with.ts +10 -0
  130. package/Fast.png +0 -0
  131. package/dist/index.global.js +0 -14500
  132. package/dist/index.global.js.map +0 -1
  133. package/dist/index.global.min.js +0 -2
  134. package/dist/index.global.min.js.map +0 -1
  135. package/es/array/index.d.ts +0 -19
  136. package/es/array/index.mjs +0 -2
  137. package/es/array/index.mjs.map +0 -1
  138. package/es/base64/index.d.ts +0 -21
  139. package/es/base64/index.mjs +0 -2
  140. package/es/base64/index.mjs.map +0 -1
  141. package/es/click/index.d.ts +0 -33
  142. package/es/click/index.mjs +0 -2
  143. package/es/click/index.mjs.map +0 -1
  144. package/es/color/index.d.ts +0 -33
  145. package/es/color/index.mjs +0 -2
  146. package/es/color/index.mjs.map +0 -1
  147. package/es/console/index.d.ts +0 -31
  148. package/es/console/index.mjs +0 -2
  149. package/es/console/index.mjs.map +0 -1
  150. package/es/crypto/index.d.ts +0 -46
  151. package/es/crypto/index.mjs +0 -2
  152. package/es/crypto/index.mjs.map +0 -1
  153. package/es/date/index.d.ts +0 -44
  154. package/es/date/index.mjs +0 -2
  155. package/es/date/index.mjs.map +0 -1
  156. package/es/dom/index.d.ts +0 -1
  157. package/es/dom/index.mjs +0 -2
  158. package/es/dom/index.mjs.map +0 -1
  159. package/es/dom/style.d.ts +0 -12
  160. package/es/dom/style.mjs +0 -2
  161. package/es/dom/style.mjs.map +0 -1
  162. package/es/env/index.d.ts +0 -25
  163. package/es/env/index.mjs +0 -2
  164. package/es/env/index.mjs.map +0 -1
  165. package/es/error/index.d.ts +0 -3
  166. package/es/error/index.mjs +0 -2
  167. package/es/error/index.mjs.map +0 -1
  168. package/es/identity/index.d.ts +0 -14
  169. package/es/identity/index.mjs +0 -2
  170. package/es/identity/index.mjs.map +0 -1
  171. package/es/index.d.ts +0 -15
  172. package/es/index.es.d.ts +0 -2
  173. package/es/index.mjs +0 -2
  174. package/es/index.mjs.map +0 -1
  175. package/es/object/index.d.ts +0 -13
  176. package/es/object/index.mjs +0 -2
  177. package/es/object/index.mjs.map +0 -1
  178. package/es/storage/index.d.ts +0 -96
  179. package/es/storage/index.mjs +0 -2
  180. package/es/storage/index.mjs.map +0 -1
  181. package/es/string/index.d.ts +0 -114
  182. package/es/string/index.mjs +0 -2
  183. package/es/string/index.mjs.map +0 -1
  184. package/es/vue/emits.d.ts +0 -8
  185. package/es/vue/emits.mjs +0 -2
  186. package/es/vue/emits.mjs.map +0 -1
  187. package/es/vue/expose.d.ts +0 -4
  188. package/es/vue/expose.mjs +0 -2
  189. package/es/vue/expose.mjs.map +0 -1
  190. package/es/vue/func.d.ts +0 -6
  191. package/es/vue/func.mjs +0 -2
  192. package/es/vue/func.mjs.map +0 -1
  193. package/es/vue/index.d.ts +0 -8
  194. package/es/vue/index.mjs +0 -2
  195. package/es/vue/index.mjs.map +0 -1
  196. package/es/vue/install.d.ts +0 -5
  197. package/es/vue/install.mjs +0 -2
  198. package/es/vue/install.mjs.map +0 -1
  199. package/es/vue/props.d.ts +0 -9
  200. package/es/vue/props.mjs +0 -2
  201. package/es/vue/props.mjs.map +0 -1
  202. package/es/vue/slots.d.ts +0 -11
  203. package/es/vue/slots.mjs +0 -2
  204. package/es/vue/slots.mjs.map +0 -1
  205. package/es/vue/useRender.d.ts +0 -6
  206. package/es/vue/useRender.mjs +0 -2
  207. package/es/vue/useRender.mjs.map +0 -1
  208. package/es/vue/with.d.ts +0 -5
  209. package/es/vue/with.mjs +0 -2
  210. package/es/vue/with.mjs.map +0 -1
  211. package/lib/array/index.d.ts +0 -19
  212. package/lib/array/index.js +0 -2
  213. package/lib/array/index.js.map +0 -1
  214. package/lib/base64/index.d.ts +0 -21
  215. package/lib/base64/index.js +0 -2
  216. package/lib/base64/index.js.map +0 -1
  217. package/lib/click/index.d.ts +0 -33
  218. package/lib/click/index.js +0 -2
  219. package/lib/click/index.js.map +0 -1
  220. package/lib/color/index.d.ts +0 -33
  221. package/lib/color/index.js +0 -2
  222. package/lib/color/index.js.map +0 -1
  223. package/lib/console/index.d.ts +0 -31
  224. package/lib/console/index.js +0 -2
  225. package/lib/console/index.js.map +0 -1
  226. package/lib/crypto/index.d.ts +0 -46
  227. package/lib/crypto/index.js +0 -2
  228. package/lib/crypto/index.js.map +0 -1
  229. package/lib/date/index.d.ts +0 -44
  230. package/lib/date/index.js +0 -2
  231. package/lib/date/index.js.map +0 -1
  232. package/lib/dom/index.d.ts +0 -1
  233. package/lib/dom/index.js +0 -2
  234. package/lib/dom/index.js.map +0 -1
  235. package/lib/dom/style.d.ts +0 -12
  236. package/lib/dom/style.js +0 -2
  237. package/lib/dom/style.js.map +0 -1
  238. package/lib/env/index.d.ts +0 -25
  239. package/lib/env/index.js +0 -2
  240. package/lib/env/index.js.map +0 -1
  241. package/lib/error/index.d.ts +0 -3
  242. package/lib/error/index.js +0 -2
  243. package/lib/error/index.js.map +0 -1
  244. package/lib/identity/index.d.ts +0 -14
  245. package/lib/identity/index.js +0 -2
  246. package/lib/identity/index.js.map +0 -1
  247. package/lib/index.d.ts +0 -15
  248. package/lib/index.es.d.ts +0 -2
  249. package/lib/index.js +0 -2
  250. package/lib/index.js.map +0 -1
  251. package/lib/object/index.d.ts +0 -13
  252. package/lib/object/index.js +0 -2
  253. package/lib/object/index.js.map +0 -1
  254. package/lib/storage/index.d.ts +0 -96
  255. package/lib/storage/index.js +0 -2
  256. package/lib/storage/index.js.map +0 -1
  257. package/lib/string/index.d.ts +0 -114
  258. package/lib/string/index.js +0 -2
  259. package/lib/string/index.js.map +0 -1
  260. package/lib/vue/emits.d.ts +0 -8
  261. package/lib/vue/emits.js +0 -2
  262. package/lib/vue/emits.js.map +0 -1
  263. package/lib/vue/expose.d.ts +0 -4
  264. package/lib/vue/expose.js +0 -2
  265. package/lib/vue/expose.js.map +0 -1
  266. package/lib/vue/func.d.ts +0 -6
  267. package/lib/vue/func.js +0 -2
  268. package/lib/vue/func.js.map +0 -1
  269. package/lib/vue/index.d.ts +0 -8
  270. package/lib/vue/index.js +0 -2
  271. package/lib/vue/index.js.map +0 -1
  272. package/lib/vue/install.d.ts +0 -5
  273. package/lib/vue/install.js +0 -2
  274. package/lib/vue/install.js.map +0 -1
  275. package/lib/vue/props.d.ts +0 -9
  276. package/lib/vue/props.js +0 -2
  277. package/lib/vue/props.js.map +0 -1
  278. package/lib/vue/slots.d.ts +0 -11
  279. package/lib/vue/slots.js +0 -2
  280. package/lib/vue/slots.js.map +0 -1
  281. package/lib/vue/useRender.d.ts +0 -6
  282. package/lib/vue/useRender.js +0 -2
  283. package/lib/vue/useRender.js.map +0 -1
  284. package/lib/vue/with.d.ts +0 -5
  285. package/lib/vue/with.js +0 -2
  286. package/lib/vue/with.js.map +0 -1
@@ -0,0 +1,65 @@
1
+ # Fast.Utils 开发与发布
2
+
3
+ ## 基线
4
+
5
+ - Node.js:`^22.18.0 || ^24.18.0`。
6
+ - pnpm:`^11.0.0`,不固定补丁版本。
7
+ - TypeScript 6、tsdown、ESLint 10 Flat Config、Prettier 3。
8
+ - 发布格式:纯 ESM、ES2022、`.mjs`、`.d.mts` 和 Source Map。
9
+ - 根目录是唯一 npm 发布单元,根 `dist/` 是唯一产物目录。
10
+
11
+ 应用环境包括现代浏览器、WebView、Vue 2.7/3 和 uni-app。
12
+
13
+ ## 安装与命令
14
+
15
+ ```bash
16
+ corepack enable
17
+ pnpm install --frozen-lockfile
18
+ ```
19
+
20
+ | 命令 | 用途 |
21
+ | ------------------- | ---------------------------------------------------------------------- |
22
+ | `pnpm dev` | 使用 tsdown 监听源码并增量构建 |
23
+ | `pnpm build` | 使用 tsdown 构建统一公开入口与内部模块 |
24
+ | `pnpm typecheck` | 检查源码与构建配置类型 |
25
+ | `pnpm lint` | 运行零警告 ESLint |
26
+ | `pnpm format:check` | 检查 Prettier |
27
+ | `pnpm test:types` | 验证公开消费者类型 |
28
+ | `pnpm test:runtime` | 运行单元、平台与 Vue Runtime 测试 |
29
+ | `pnpm test:package` | 验证 Tarball、公开入口、声明、Source Map、Tree Shaking、体积与 Publint |
30
+ | `pnpm check` | 运行统一质量门禁 |
31
+
32
+ ## 修改公共模块
33
+
34
+ 新增公共模块时必须同步:
35
+
36
+ 1. 在 `src/<module>/index.ts` 定义具名 API 和 TSDoc。
37
+ 2. 在 `src/index.ts` 统一重新导出公共 API。
38
+ 3. 不为模块增加 `package.json#exports` 子路径或独立构建入口。
39
+ 4. 增加源码类型、消费者类型、单元和真实包测试。
40
+ 5. 更新双语 README、API 和 Changelog。
41
+
42
+ 禁止在导入阶段访问浏览器或 uni-app 全局对象。平台能力应在调用阶段解析;`configureStorage` 在调用时自动检测全局 `uni`。
43
+
44
+ ## 依赖与锁文件
45
+
46
+ - Runtime Dependency 必须证明无法由平台能力或小型实现替代。
47
+ - Vue 保持 Optional Peer Dependency,不得打包进发布产物。
48
+ - 依赖升级后使用当前 pnpm 11 更新 Lockfile,并通过 Frozen Lockfile 安装验证。
49
+ - 不混用 npm、Yarn 或不同 pnpm 主版本改写 Lockfile。
50
+
51
+ ## CI
52
+
53
+ CI 在 Node 22 与 24 上运行,使用 Frozen Lockfile,并执行 `pnpm check` 与 Pack Dry Run。不得通过关闭类型、Lint、测试或包验证来修复门禁。
54
+
55
+ ## 发布
56
+
57
+ 仓库只采用人工发布流程,不声明或配置 OIDC Trusted Publishing:
58
+
59
+ 1. 更新 SemVer 与 `CHANGELOG.md` 日期。
60
+ 2. 执行 `pnpm install --frozen-lockfile`。
61
+ 3. 执行 `pnpm check`。
62
+ 4. 人工检查 `pnpm --config.ignore-scripts=true pack --dry-run` 清单。
63
+ 5. 由维护者在可信环境执行 npm Publish,并创建对应 `v<version>` Tag。
64
+
65
+ 未经明确授权,不执行 Publish、Push、Tag 或 Release。npm 已发布版本不可覆盖;发布后缺陷必须通过新 Patch 或 Pre-release 修复。
@@ -0,0 +1,37 @@
1
+ # Fast.Utils runtime contract / 运行时契约
2
+
3
+ ## Runtime and package contract
4
+
5
+ - Runtime platforms: ES2022 modern browsers, WebViews, Vue 2.7/3 applications, and uni-app.
6
+ - Package format: pure ESM with one public named-export entry; CommonJS, UMD, and IIFE are not shipped.
7
+ - Framework boundary: Vue remains external to the package build and is an optional peer in `^2.7.0 || ^3.3.0`.
8
+ - uni-app boundary: `configureStorage({ prefix })` detects global `uni` at call time and uses its synchronous Storage API.
9
+ - Browser storage: applications call `configureStorage()` once, then import `Local` and `Session` directly from the package.
10
+ - Stateful browser defaults: Storage and Identity configuration are page-global by design. Conflicting reconfiguration throws.
11
+ - Security: secure random APIs require Web Crypto and never fall back to `Math.random()`.
12
+ - Publishing: the repository root is the only package, `dist/` is the only build output, and `package.json#exports` is the complete public path whitelist.
13
+
14
+ Importing a module does not itself read `window`, browser Storage, or `uni`, so unsupported platform capabilities fail only when the corresponding API is called.
15
+
16
+ ## Public API policy
17
+
18
+ - Stateless Array, Date, String, Number, Object, Base64, Color, DOM, Env, Async, and Crypto capabilities use named exports.
19
+ - The public API uses named functions instead of mutable aggregate utility objects.
20
+ - Stateful browser capabilities use cohesive package-owned objects: `Local`, `Session`, `installationIdentity`, and logger instances. Logger scope is supplied to each severity method rather than stored in child instances.
21
+ - Internal adapters and client factories are implementation details and are not public export paths.
22
+ - Removing a named function, changing Storage/ciphertext formats, raising the browser syntax target, or changing the Vue peer range requires an explicit major-version Breaking Change.
23
+
24
+ ## 运行时与包契约
25
+
26
+ - 运行平台:ES2022 现代浏览器、WebView、Vue 2.7/3 应用和 uni-app。
27
+ - 包格式:仅纯 ESM 和单一公开具名导出入口,不发布 CommonJS、UMD 或 IIFE。
28
+ - Vue 边界:Vue 不会打进本包产物,是 `^2.7.0 || ^3.3.0` 的可选 Peer。
29
+ - uni-app:`configureStorage({ prefix })` 在调用阶段自动检测全局 `uni` 并使用其同步 Storage API。
30
+ - Storage:程序入口配置一次,其他文件直接从包导入 `Local` 和 `Session`。
31
+ - 状态:Storage 与 Identity 配置按浏览器页面全局共享;冲突配置明确抛错。
32
+ - 安全随机:要求 Web Crypto,禁止回退 `Math.random()`。
33
+ - 发布:根目录是唯一 npm 包,`dist/` 是唯一构建输出,`exports` 是完整公共路径白名单。
34
+
35
+ 模块导入本身不读取 `window`、浏览器 Storage 或 `uni`,不具备对应平台能力时只在调用相关 API 时明确失败。
36
+
37
+ 无状态能力统一使用具名导出。有状态浏览器能力使用 `Local`、`Session`、`installationIdentity` 和 Logger 实例;Logger 作用域随每次级别方法调用传入,不创建 Child Logger。
package/package.json CHANGED
@@ -1,104 +1,96 @@
1
1
  {
2
2
  "name": "@fast-china/utils",
3
- "version": "1.0.37",
4
- "description": "Fast 工具库.",
3
+ "version": "2.0.0",
4
+ "description": "Typed utilities for modern browsers, WebViews, Vue 2.7/3, and uni-app applications.",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "fast-china",
8
- "fast",
9
8
  "typescript",
10
9
  "utils"
11
10
  ],
12
11
  "license": "Apache-2.0",
13
12
  "homepage": "https://fastdotnet.com",
14
13
  "bugs": {
15
- "url": "https://gitee.com/FastDotnet/Fast.Utils/issues"
14
+ "url": "https://gitee.com/FastDotnet/fast.utils/issues"
16
15
  },
17
16
  "repository": {
18
17
  "type": "git",
19
- "url": "https://gitee.com/FastDotnet/Fast.Utils"
18
+ "url": "https://gitee.com/FastDotnet/fast.utils"
20
19
  },
21
20
  "author": "小方",
22
21
  "files": [
23
- "./Fast.png",
24
- "./LICENSE",
25
- "./README.md",
26
- "./README.zh.md",
27
- "./dist",
28
- "./es",
29
- "./lib"
22
+ "CHANGELOG.md",
23
+ "CONTRIBUTING.md",
24
+ "LICENSE",
25
+ "README.md",
26
+ "README.zh.md",
27
+ "SECURITY.md",
28
+ "dist",
29
+ "docs",
30
+ "src"
30
31
  ],
31
- "main": "lib/index.js",
32
- "module": "es/index.mjs",
33
- "types": "es/index.d.ts",
32
+ "main": "./dist/index.mjs",
33
+ "module": "./dist/index.mjs",
34
+ "types": "./dist/index.d.mts",
34
35
  "exports": {
35
36
  ".": {
36
- "types": "./es/index.d.ts",
37
- "require": "./lib/index.js",
38
- "import": "./es/index.mjs"
39
- },
40
- "./es": {
41
- "types": "./es/index.d.ts",
42
- "import": "./es/index.mjs"
43
- },
44
- "./lib": {
45
- "types": "./lib/index.d.ts",
46
- "require": "./lib/index.js"
47
- },
48
- "./es/*.mjs": {
49
- "types": "./es/*.d.ts",
50
- "import": "./es/*.mjs"
51
- },
52
- "./es/*": {
53
- "types": [
54
- "./es/*.d.ts",
55
- "./es/*/index.d.ts"
56
- ],
57
- "import": "./es/*.mjs"
58
- },
59
- "./lib/*.js": {
60
- "types": "./lib/*.d.ts",
61
- "require": "./lib/*.js"
62
- },
63
- "./lib/*": {
64
- "types": [
65
- "./lib/*.d.ts",
66
- "./lib/*/index.d.ts"
67
- ],
68
- "require": "./lib/*.js"
69
- },
70
- "./*": "./*"
37
+ "types": "./dist/index.d.mts",
38
+ "import": "./dist/index.mjs",
39
+ "default": "./dist/index.mjs"
40
+ }
71
41
  },
72
- "unpkg": "dist/index.global.min.js",
73
- "jsdelivr": "dist/index.global.min.js",
42
+ "sideEffects": false,
74
43
  "publishConfig": {
75
44
  "access": "public"
76
45
  },
46
+ "scripts": {
47
+ "dev": "tsdown --watch",
48
+ "build": "tsdown",
49
+ "typecheck": "tsc --noEmit",
50
+ "lint": "eslint . --max-warnings 0",
51
+ "lint:fix": "eslint . --fix",
52
+ "format": "prettier --write .",
53
+ "format:check": "prettier --check .",
54
+ "test": "pnpm run build && pnpm run test:types && pnpm run test:runtime && pnpm run test:package",
55
+ "test:types": "tsc --noEmit --project tests/tsconfig.json",
56
+ "test:runtime": "node --import tsx --test tests/async.test.ts tests/core.test.ts tests/storage-crypto.test.ts tests/storage-uni.test.ts tests/vue.test.ts",
57
+ "test:package": "node --test tests/package.test.mjs && publint --strict --pack npm",
58
+ "check": "pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run format:check",
59
+ "prepack": "pnpm run check"
60
+ },
77
61
  "peerDependencies": {
78
- "vue": "^2 || ^3"
62
+ "vue": "^2.7.0 || ^3.3.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "vue": {
66
+ "optional": true
67
+ }
79
68
  },
80
69
  "dependencies": {
81
- "@types/crypto-js": "^4.2",
82
- "@types/lodash": "^4.17",
83
- "@types/lodash-es": "^4.17",
84
- "crypto-js": "^4.2",
85
- "lodash": "^4.17",
86
- "lodash-es": "^4.17",
87
- "lodash-unified": "^1"
70
+ "crypto-js": "^4.2.0"
88
71
  },
89
72
  "devDependencies": {
90
- "@dcloudio/types": "^3",
91
- "@fast-china/eslint-config": "^1",
92
- "@rollup/plugin-terser": "^0.4",
93
- "@types/node": "^24",
94
- "@vue/tsconfig": "^0.8",
95
- "eslint": "^9",
96
- "prettier": "^3",
97
- "terser": "^5",
98
- "typescript": "^5",
99
- "vite": "^7",
100
- "vite-plugin-dts": "^4",
101
- "vue": "^2 || ^3",
102
- "vue-tsc": "^3"
73
+ "@eslint/js": "^10.0.1",
74
+ "@eslint/markdown": "^8.0.3",
75
+ "@types/crypto-js": "^4.2.2",
76
+ "@types/node": "^24.13.3",
77
+ "eslint": "^10.8.0",
78
+ "eslint-config-flat-gitignore": "^2.3.0",
79
+ "eslint-config-prettier": "^10.1.8",
80
+ "eslint-plugin-import-x": "^4.17.1",
81
+ "eslint-plugin-jsonc": "^3.3.0",
82
+ "eslint-plugin-regexp": "^3.1.1",
83
+ "globals": "^17.8.0",
84
+ "prettier": "^3.9.6",
85
+ "publint": "^0.3.22",
86
+ "tsdown": "^0.22.14",
87
+ "tsx": "^4.23.1",
88
+ "typescript": "^6.0.3",
89
+ "typescript-eslint": "^8.65.0",
90
+ "vue": "^3.5.40"
91
+ },
92
+ "engines": {
93
+ "node": "^22.18.0 || ^24.18.0",
94
+ "pnpm": "^11.0.0"
103
95
  }
104
96
  }
@@ -0,0 +1,173 @@
1
+ /** 从数组项中提取可比较键的函数。 */
2
+ export type KeySelector<Item, Key> = (item: Item, index: number) => Key;
3
+
4
+ /**
5
+ * 将只读数组按固定大小分组。
6
+ *
7
+ * @typeParam Item - 数组项类型。
8
+ * @param items - 不会被修改的输入数组。
9
+ * @param size - 每组最多包含的项目数,必须是正安全整数。
10
+ * @returns 新建的二维数组;最后一组可能小于 `size`。
11
+ * @throws `RangeError` 当 `size` 不是正安全整数。
12
+ */
13
+ export function chunk<Item>(items: readonly Item[], size: number): Item[][] {
14
+ if (!Number.isSafeInteger(size) || size <= 0) {
15
+ throw new RangeError("size must be a positive safe integer.");
16
+ }
17
+
18
+ const result: Item[][] = [];
19
+ for (let index = 0; index < items.length; index += size) {
20
+ result.push(items.slice(index, index + size));
21
+ }
22
+ return result;
23
+ }
24
+
25
+ /**
26
+ * 删除数组中的 `null` 与 `undefined`,保留 `false`、`0` 和空字符串。
27
+ *
28
+ * @param items - 可包含空值的只读数组。
29
+ * @returns 保持原顺序的新数组。
30
+ */
31
+ export function removeNullishValues<Item>(items: readonly (Item | null | undefined)[]): Item[] {
32
+ return items.filter((item): item is Item => item !== null && item !== undefined);
33
+ }
34
+
35
+ /**
36
+ * 使用 JavaScript `Set` 的 SameValueZero 语义去重。
37
+ *
38
+ * @param items - 不会被修改的输入数组。
39
+ * @returns 保留每个值首次出现顺序的新数组;稀疏数组空位被忽略。
40
+ */
41
+ export function unique<Item>(items: readonly Item[]): Item[] {
42
+ const result: Item[] = [];
43
+ const seen = new Set<Item>();
44
+ for (let index = 0; index < items.length; index += 1) {
45
+ if (!(index in items)) continue;
46
+ const item = items[index] as Item;
47
+ if (seen.has(item)) continue;
48
+ seen.add(item);
49
+ result.push(item);
50
+ }
51
+ return result;
52
+ }
53
+
54
+ /**
55
+ * 按选择器返回的键去重。
56
+ *
57
+ * @param items - 不会被修改的输入数组。
58
+ * @param selectKey - 接收项目与索引并返回去重键的函数。
59
+ * @returns 保留每个键首次出现项目的新数组;稀疏数组空位被忽略。
60
+ */
61
+ export function uniqueBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Item[] {
62
+ const seen = new Set<Key>();
63
+ const result: Item[] = [];
64
+ for (let index = 0; index < items.length; index += 1) {
65
+ const item = items[index];
66
+ if (item === undefined && !(index in items)) continue;
67
+ const key = selectKey(item as Item, index);
68
+ if (seen.has(key)) continue;
69
+ seen.add(key);
70
+ result.push(item as Item);
71
+ }
72
+ return result;
73
+ }
74
+
75
+ /**
76
+ * 按选择器结果分组。
77
+ *
78
+ * @param items - 不会被修改的输入数组。
79
+ * @param selectKey - 返回任意 `Map` 键的函数。
80
+ * @returns 按键首次出现顺序排列的 `Map`;每个分组保持输入顺序,稀疏空位被忽略。
81
+ */
82
+ export function groupBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Map<Key, Item[]> {
83
+ const groups = new Map<Key, Item[]>();
84
+ items.forEach((item, index) => {
85
+ const key = selectKey(item, index);
86
+ const group = groups.get(key);
87
+ if (group === undefined) groups.set(key, [item]);
88
+ else group.push(item);
89
+ });
90
+ return groups;
91
+ }
92
+
93
+ /**
94
+ * 按谓词把数组拆分为匹配项和非匹配项。
95
+ *
96
+ * @param items - 不会被修改的输入数组。
97
+ * @param predicate - 接收项目与索引的判断函数。
98
+ * @returns 二元组:第一项匹配谓词,第二项不匹配;两组都保持原顺序并忽略稀疏空位。
99
+ */
100
+ export function partition<Item>(items: readonly Item[], predicate: (item: Item, index: number) => boolean): [matched: Item[], unmatched: Item[]] {
101
+ const matched: Item[] = [];
102
+ const unmatched: Item[] = [];
103
+ items.forEach((item, index) => (predicate(item, index) ? matched : unmatched).push(item));
104
+ return [matched, unmatched];
105
+ }
106
+
107
+ /**
108
+ * 返回只出现在左侧数组中的不同值。
109
+ *
110
+ * @param left - 主输入数组。
111
+ * @param right - 需要排除的值。
112
+ * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。
113
+ */
114
+ export function difference<Item>(left: readonly Item[], right: readonly Item[]): Item[] {
115
+ const excluded = new Set(unique(right));
116
+ return unique(left).filter((item) => !excluded.has(item));
117
+ }
118
+
119
+ /**
120
+ * 返回两个数组共有的不同值。
121
+ *
122
+ * @param left - 决定结果顺序的数组。
123
+ * @param right - 用于成员判断的数组。
124
+ * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。
125
+ */
126
+ export function intersection<Item>(left: readonly Item[], right: readonly Item[]): Item[] {
127
+ const included = new Set(unique(right));
128
+ return unique(left).filter((item) => included.has(item));
129
+ }
130
+
131
+ /**
132
+ * 判断选择器产生的键是否重复。
133
+ *
134
+ * @param items - 不会被修改的输入数组。
135
+ * @param selectKey - 返回比较键的函数;键使用 SameValueZero 语义比较。
136
+ * @returns 存在至少一个重复键时返回 `true`。
137
+ */
138
+ export function hasDuplicatesBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {
139
+ const seen = new Set<Key>();
140
+ for (let index = 0; index < items.length; index += 1) {
141
+ const item = items[index];
142
+ if (item === undefined && !(index in items)) continue;
143
+ const key = selectKey(item as Item, index);
144
+ if (seen.has(key)) return true;
145
+ seen.add(key);
146
+ }
147
+ return false;
148
+ }
149
+
150
+ /**
151
+ * 判断所有项目是否具有相同的选择器结果。
152
+ *
153
+ * @remarks 空数组、只有稀疏空位的数组和单项数组按数学惯例返回 `true`;空位不会调用选择器。
154
+ * @param items - 不会被修改的输入数组。
155
+ * @param selectKey - 返回比较键的函数。
156
+ * @returns 所有键都满足 SameValueZero 相等时返回 `true`。
157
+ */
158
+ export function allEqualBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {
159
+ let first: Key | undefined;
160
+ let hasFirst = false;
161
+ for (let index = 0; index < items.length; index += 1) {
162
+ const item = items[index];
163
+ if (item === undefined && !(index in items)) continue;
164
+ const current = selectKey(item as Item, index);
165
+ if (!hasFirst) {
166
+ first = current;
167
+ hasFirst = true;
168
+ continue;
169
+ }
170
+ if (!(first === current || (Number.isNaN(first) && Number.isNaN(current)))) return false;
171
+ }
172
+ return true;
173
+ }