ansuko 1.2.11 → 1.2.13

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.
package/README.ja.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  lodashを拡張した、実用的で直感的な動作を提供するモダンなJavaScript/TypeScriptユーティリティライブラリ。
5
5
 
6
- [English](./README.md) | [日本語](./README.ja.md)
6
+ [English](./README.md) | [日本語](./README.ja.md) | [简体中文](./README.zh.md)
7
7
 
8
8
  ## インストール
9
9
 
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  A modern JavaScript/TypeScript utility library that extends lodash with practical, intuitive behaviors.
5
5
 
6
- [English](./README.md) | [日本語](./README.ja.md)
6
+ [English](./README.md) | [日本語](./README.ja.md) | [简体中文](./README.zh.md)
7
7
 
8
8
  ## Why ansuko?
9
9
 
package/README.zh.md ADDED
@@ -0,0 +1,355 @@
1
+ # ansuko
2
+
3
+ 一个现代化的 JavaScript/TypeScript 实用工具库,以实用、直观的行为扩展 lodash。
4
+
5
+ [English](./README.md) | [日本語](./README.ja.md) | [简体中文](./README.zh.md)
6
+
7
+ ## 为什么选择 ansuko?
8
+
9
+ "ansuko"这个名字有多重含义:
10
+
11
+ - **アンスコ (ansuko)** - 日文中"underscore"(下划线)的缩写(アンダースコア)
12
+ - **ansuko = underscore → low dash → lodash** - 延续这个系列
13
+ - **スコ (suko)** - 日文俚语,意为"喜欢"或"最爱"
14
+
15
+ 这个库修复了 lodash 的不直观行为,并添加了强大的工具来消除常见的 JavaScript 困扰。
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ npm install ansuko
21
+ ```
22
+
23
+ 或添加到你的 `package.json`:
24
+
25
+ ```json
26
+ {
27
+ "dependencies": {
28
+ "ansuko"
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## 核心理念
34
+
35
+ ansuko 通过直观的行为消除常见的 JavaScript 困扰:
36
+
37
+ ### 修复 lodash 的怪异行为
38
+
39
+ ```typescript
40
+ // ❌ lodash(不直观)
41
+ _.isEmpty(0) // true - 0 真的"空"吗?
42
+ _.isEmpty(true) // true - true "空"吗?
43
+ _.castArray(null) // [null] - 为什么保留 null?
44
+
45
+ // ✅ ansuko(直观)
46
+ _.isEmpty(0) // false - 数字不为空
47
+ _.isEmpty(true) // false - 布尔值不为空
48
+ _.castArray(null) // [] - 干净的空数组
49
+ ```
50
+
51
+ ### 安全的 JSON 处理
52
+
53
+ ```typescript
54
+ // ❌ 标准 JSON(烦人)
55
+ JSON.stringify('hello') // '"hello"' - 额外的引号!
56
+ JSON.parse(badJson) // 抛出错误 - 需要 try-catch
57
+
58
+ // ✅ ansuko(流畅)
59
+ _.jsonStringify('hello') // null - 不是对象
60
+ _.jsonStringify({ a: 1 }) // '{"a":1}' - 干净
61
+ _.parseJSON(badJson) // null - 无异常
62
+ _.parseJSON('{ a: 1, }') // {a:1} - 支持 JSON5!
63
+ ```
64
+
65
+ ### Promise 感知的后备
66
+
67
+ ```typescript
68
+ // ❌ 冗长的模式
69
+ const data = await fetchData()
70
+ const result = data ? data : await fetchBackup()
71
+
72
+ // ✅ ansuko(简洁)
73
+ const result = await _.valueOr(
74
+ () => fetchData(),
75
+ () => fetchBackup()
76
+ )
77
+ ```
78
+
79
+ ### 智能比较
80
+
81
+ ```typescript
82
+ // ❌ 冗长的三元表达式地狱
83
+ const value = a === b ? a : (a == null && b == null ? a : defaultValue)
84
+
85
+ // ✅ ansuko(可读)
86
+ const value = _.equalsOr(a, b, defaultValue) // null == undefined
87
+ ```
88
+
89
+ ## 主要特性
90
+
91
+ ### 增强的 lodash 函数
92
+
93
+ - **`isEmpty`** - 检查是否为空(数字和布尔值不为空)
94
+ - **`castArray`** - 转换为数组,null/undefined 返回 `[]`
95
+ - 所有 lodash 函数仍然可用:`size`、`isNil`、`debounce`、`isEqual`、`keys`、`values`、`has` 等
96
+
97
+ ### 值处理与控制流
98
+
99
+ - **`valueOr`** - 获取值或默认值,支持 Promise/函数
100
+ - **`emptyOr`** - 如果为空返回 null,否则应用回调或返回值
101
+ - **`hasOr`** - 检查路径是否存在,如果缺失则返回默认值(支持深度路径和 Promise)
102
+ - **`equalsOr`** - 比较并后备,具有直观的 nil 处理(支持 Promise)
103
+ - **`changes`** - 跟踪对象差异用于数据库更新(支持深度路径如 `profile.tags[1]` 和排除模式)
104
+
105
+ ### 类型转换与验证
106
+
107
+ - **`toNumber`** - 解析数字,支持逗号/全角,无效时返回 `null`
108
+ - **`toBool`** - 智能布尔值转换("yes"/"no"/"true"/"false"/数字),可配置未检测处理
109
+ - **`boolIf`** - 带后备的安全布尔值转换
110
+ - **`isValidStr`** - 非空字符串验证
111
+
112
+ ### JSON 处理
113
+
114
+ - **`parseJSON`** - 无需 try-catch 的安全 JSON/JSON5 解析(支持注释和尾随逗号)
115
+ - **`jsonStringify`** - 仅字符串化有效对象,防止意外的字符串包装
116
+
117
+ ### 数组工具
118
+
119
+ - **`arrayDepth`** - 返回数组的嵌套深度(非数组:0,空数组:1)
120
+ - **`castArray`** - 转换为数组,nil 变为 `[]`(而非 `[null]`)
121
+
122
+ ### 日文文本(插件:`ansuko/plugins/ja`)
123
+
124
+ - **`kanaToFull`** - 半角片假名 → 全角(例如 `ガギ` → `ガギ`)
125
+ - **`kanaToHalf`** - 全角 → 半角片假名(浊音拆分:`ガギ` → `ガギ`)
126
+ - **`kanaToHira`** - 片假名 → 平假名(自动先转换半角)
127
+ - **`hiraToKana`** - 平假名 → 片假名
128
+ - **`toHalfWidth`** - 全角 → 半角,可选连字符标准化
129
+ - **`toFullWidth`** - 半角 → 全角,可选连字符标准化
130
+ - **`haifun`** - 将各种连字符标准化为单一字符
131
+
132
+ ### 地理工具(插件:`ansuko/plugins/geo`)
133
+
134
+ - **`toGeoJson`** - 通用 GeoJSON 转换器,具有自动检测功能(从高维度到低维度尝试)
135
+ - **`toPointGeoJson`** - 将坐标/对象转换为 Point GeoJSON
136
+ - **`toPolygonGeoJson`** - 将外环转换为 Polygon(验证闭合环)
137
+ - **`toLineStringGeoJson`** - 将坐标转换为 LineString(检查自相交)
138
+ - **`toMultiPointGeoJson`** - 将多个点转换为 MultiPoint
139
+ - **`toMultiPolygonGeoJson`** - 将多个多边形转换为 MultiPolygon
140
+ - **`toMultiLineStringGeoJson`** - 将多条线转换为 MultiLineString
141
+ - **`unionPolygon`** - 将多个 Polygon/MultiPolygon 合并为单个几何
142
+ - **`parseToTerraDraw`** - 将 GeoJSON 转换为 Terra Draw 兼容的要素
143
+
144
+ ### 原型扩展(插件:`ansuko/plugins/prototype`)
145
+
146
+ - **`Array.prototype.notMap`** - 使用否定谓词映射 → 布尔数组
147
+ - **`Array.prototype.notFilter`** - 通过否定谓词过滤(不匹配的项)
148
+
149
+ ### 时间工具
150
+
151
+ - **`waited`** - 通过 N 个动画帧延迟执行(比 `setTimeout` 更适合 React/DOM)
152
+
153
+ ## 插件架构
154
+
155
+ ansuko 使用最小核心 + 插件架构来保持你的包大小小:
156
+
157
+ - **核心**(~20KB):改进 lodash 的基本工具
158
+ - **日文插件**(~5KB):仅在需要日文文本处理时加载
159
+ - **地理插件**(~100KB 含 @turf/turf):仅为 GIS 应用加载
160
+ - **原型插件**(~1KB):仅在需要数组原型扩展时加载
161
+
162
+ 这意味着你只为使用的功能付费!
163
+
164
+ ```typescript
165
+ // 最小包 - 仅核心
166
+ import _ from 'ansuko' // ~20KB
167
+
168
+ // 需要时添加日文支持
169
+ import jaPlugin from 'ansuko/plugins/ja'
170
+ _.extend(jaPlugin) // +5KB
171
+
172
+ // 为地图应用添加 GIS 功能
173
+ import geoPlugin from 'ansuko/plugins/geo'
174
+ _.extend(geoPlugin) // +100KB
175
+ ```
176
+
177
+ ## 快速开始
178
+
179
+ ### 基本用法
180
+
181
+ ```typescript
182
+ import _ from 'ansuko'
183
+
184
+ // 增强的 lodash 函数
185
+ _.isEmpty(0) // false(不像 lodash 那样是 true!)
186
+ _.isEmpty([]) // true
187
+ _.castArray(null) // [](不是 [null]!)
188
+ _.toNumber('1,234.5') // 1234.5
189
+
190
+ // 支持 Promise 的值处理
191
+ const value = await _.valueOr(
192
+ () => cache.get(id),
193
+ () => api.fetch(id)
194
+ )
195
+
196
+ // 安全的 JSON 解析
197
+ const data = _.parseJSON('{ "a": 1, /* 注释 */ }') // 支持 JSON5!
198
+
199
+ // 跟踪对象更改以进行数据库更新
200
+ const diff = _.changes(
201
+ original,
202
+ updated,
203
+ ['name', 'email', 'profile.bio']
204
+ )
205
+ ```
206
+
207
+ ### 使用插件
208
+
209
+ #### 日文文本插件
210
+
211
+ ```typescript
212
+ import _ from 'ansuko'
213
+ import jaPlugin from 'ansuko/plugins/ja'
214
+
215
+ _.extend(jaPlugin)
216
+
217
+ _.kanaToFull('ガギ') // 'ガギ'
218
+ _.kanaToHira('アイウ') // 'あいう'
219
+ _.toHalfWidth('ABCー123', '-') // 'ABC-123'
220
+ _.haifun('test‐data', '-') // 'test-data'
221
+ ```
222
+
223
+ #### 地理插件
224
+
225
+ ```typescript
226
+ import _ from 'ansuko'
227
+ import geoPlugin from 'ansuko/plugins/geo'
228
+
229
+ const extended = _.extend(geoPlugin)
230
+
231
+ // 将各种格式转换为 GeoJSON
232
+ extended.toPointGeoJson([139.7671, 35.6812])
233
+ // => { type: 'Point', coordinates: [139.7671, 35.6812] }
234
+
235
+ extended.toPointGeoJson({ lat: 35.6895, lng: 139.6917 })
236
+ // => { type: 'Point', coordinates: [139.6917, 35.6895] }
237
+
238
+ // 合并多个多边形
239
+ const unified = extended.unionPolygon([polygon1, polygon2])
240
+ ```
241
+
242
+ #### 原型插件
243
+
244
+ ```typescript
245
+ import _ from 'ansuko'
246
+ import prototypePlugin from 'ansuko/plugins/prototype'
247
+
248
+ _.extend(prototypePlugin)
249
+
250
+ // 现在 Array.prototype 已扩展
251
+ [1, 2, 3].notMap(n => n > 1) // [true, false, false]
252
+ [1, 2, 3].notFilter(n => n % 2) // [2](偶数)
253
+ ```
254
+
255
+ ### 链式插件
256
+
257
+ ```typescript
258
+ import _ from 'ansuko'
259
+ import jaPlugin from 'ansuko/plugins/ja'
260
+ import geoPlugin from 'ansuko/plugins/geo'
261
+
262
+ const extended = _
263
+ .extend(jaPlugin)
264
+ .extend(geoPlugin)
265
+
266
+ // 现在你同时拥有日文和地理工具!
267
+ extended.kanaToHira('アイウ')
268
+ extended.toPointGeoJson([139.7, 35.6])
269
+ ```
270
+
271
+ ## 文档
272
+
273
+ 详细信息请参阅:
274
+
275
+ - **[API 参考](./docs/API.zh.md)** - 带示例的完整 API 文档
276
+ - **[使用指南](./docs/Guide.zh.md)** - 实际示例和模式
277
+
278
+ ## TypeScript 支持
279
+
280
+ 完整的 TypeScript 支持,包含类型定义。所有函数都完全类型化,支持泛型。
281
+
282
+ ## 为什么不只使用 lodash?
283
+
284
+ lodash 很优秀,但有一些[社区批评](https://github.com/lodash/lodash/issues)的怪异行为:
285
+
286
+ ### 修复的行为
287
+
288
+ 1. **`_.isEmpty(true)` 返回 `true`** - 布尔值真的"空"吗?
289
+ 2. **`_.isEmpty(1)` 返回 `true`** - 数字 1 "空"吗?
290
+ 3. **`_.castArray(null)` 返回 `[null]`** - 为什么在数组中包含 null?
291
+
292
+ ### lodash 中缺少的添加工具
293
+
294
+ 4. **无安全的 JSON 解析** - 总是需要 try-catch 块
295
+ 5. **无内置的比较与后备** - 到处都是冗长的三元表达式模式
296
+ 6. **无 Promise 感知的值解析** - 手动 Promise 处理变得混乱
297
+ 7. **无对象差异跟踪** - 需要外部库进行数据库更新
298
+ 8. **`JSON.stringify("hello")` 添加引号** - 那些 `'"hello"'` 引号很烦人
299
+
300
+ ### 实际示例
301
+
302
+ ```typescript
303
+ // lodash 的常见模式(冗长且容易出错)
304
+ let data
305
+ try {
306
+ const cached = cache.get(id)
307
+ if (cached && !_.isEmpty(cached)) {
308
+ data = cached
309
+ } else {
310
+ const fetched = await api.fetch(id)
311
+ data = fetched || defaultValue
312
+ }
313
+ } catch (e) {
314
+ data = defaultValue
315
+ }
316
+
317
+ // ansuko 的相同逻辑(简洁且安全)
318
+ const data = await _.valueOr(
319
+ () => cache.get(id),
320
+ () => api.fetch(id),
321
+ defaultValue
322
+ )
323
+ ```
324
+
325
+ ansuko 保持与 lodash 的 **100% 兼容性**,同时修复这些问题并为现代 JavaScript 开发添加强大的工具。
326
+
327
+ ## 依赖项
328
+
329
+ - **`lodash`** - 核心工具函数
330
+ - **`json5`** - 增强的 JSON 解析,支持注释和尾随逗号
331
+ - **`@turf/turf`** - 地理空间分析(由地理插件使用)
332
+
333
+ ## 从源代码构建
334
+
335
+ ```bash
336
+ npm install
337
+ npm run build
338
+ ```
339
+
340
+ 这将在 `dist` 目录中生成编译后的 JavaScript 和类型定义。
341
+
342
+ ## 开发
343
+ 由 Sera 开发,Claude(Anthropic)协助文档编写、代码审查和技术讨论。
344
+
345
+ ## 许可证
346
+
347
+ MIT
348
+
349
+ ## 作者
350
+
351
+ Naoto Sera
352
+
353
+ ---
354
+
355
+ 无论中日国际形势如何,我认为开源软件(OSS)应始终保持和平。也衷心希望您能有同样的想法。
package/dist/index.d.ts CHANGED
@@ -154,7 +154,7 @@ declare const arrayDepth: (ary: unknown) => number;
154
154
  * @example const extended = _.extend(jaPlugin)
155
155
  * @category Core Functions
156
156
  */
157
- declare const extend: <T>(this: any, plugin: (a: any) => T) => any & T;
157
+ declare const extend: <T extends AnsukoType, E>(this: T, plugin: (a: T) => T & E) => T & E;
158
158
  export type ChangesOptions = {
159
159
  keyExcludes?: boolean;
160
160
  };
package/dist/index.js CHANGED
@@ -477,7 +477,7 @@ const arrayDepth = (ary) => {
477
477
  */
478
478
  const extend = function (plugin) {
479
479
  if (typeof plugin === 'function') {
480
- plugin(this); // ← this が undefined になってる?
480
+ return plugin(this); // プラグインの戻り値をそのまま返す
481
481
  }
482
482
  return this;
483
483
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ansuko",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "description": "A modern JavaScript/TypeScript utility library that extends lodash with practical, intuitive behaviors. Fixes lodash quirks, adds Promise support, Japanese text processing, and GeoJSON utilities.",
5
5
  "keywords": [
6
6
  "lodash",