ansuko 1.2.10 → 1.2.12
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 +1 -1
- package/README.md +1 -1
- package/README.zh.md +355 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -3
- package/package.json +1 -1
package/README.ja.md
CHANGED
package/README.md
CHANGED
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
|
@@ -96,12 +96,14 @@ declare const parseJSON: <T = any>(str: string | object) => T | null;
|
|
|
96
96
|
/**
|
|
97
97
|
* Stringifies objects/arrays; returns null for strings or numbers.
|
|
98
98
|
* @param obj - Target object
|
|
99
|
+
* @param replacer — A function that transforms the results.
|
|
100
|
+
* @param space - Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
|
99
101
|
* @returns JSON string or null
|
|
100
102
|
* @example jsonStringify({a:1}) // '{"a":1}'
|
|
101
103
|
* @example jsonStringify('{a:1}') // '{"a":1}' (normalize)
|
|
102
104
|
* @category Conversion
|
|
103
105
|
*/
|
|
104
|
-
declare const jsonStringify: <T = any>(obj: T) => string | null;
|
|
106
|
+
declare const jsonStringify: <T = any>(obj: T, replacer?: ((this: any, key: string, value: any) => any) | undefined, space?: string | number | undefined) => string | null;
|
|
105
107
|
/**
|
|
106
108
|
* Casts value to array; null/undefined become [] (not [null]).
|
|
107
109
|
* @param value - Value
|
package/dist/index.js
CHANGED
|
@@ -329,19 +329,21 @@ const parseJSON = (str) => {
|
|
|
329
329
|
/**
|
|
330
330
|
* Stringifies objects/arrays; returns null for strings or numbers.
|
|
331
331
|
* @param obj - Target object
|
|
332
|
+
* @param replacer — A function that transforms the results.
|
|
333
|
+
* @param space - Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
|
332
334
|
* @returns JSON string or null
|
|
333
335
|
* @example jsonStringify({a:1}) // '{"a":1}'
|
|
334
336
|
* @example jsonStringify('{a:1}') // '{"a":1}' (normalize)
|
|
335
337
|
* @category Conversion
|
|
336
338
|
*/
|
|
337
|
-
const jsonStringify = (obj) => {
|
|
339
|
+
const jsonStringify = (obj, replacer, space) => {
|
|
338
340
|
if (_.isNil(obj)) {
|
|
339
341
|
return null;
|
|
340
342
|
}
|
|
341
343
|
if (typeof obj === "string") {
|
|
342
344
|
try {
|
|
343
345
|
const j = JSON5.parse(obj);
|
|
344
|
-
return JSON.stringify(j);
|
|
346
|
+
return JSON.stringify(j, replacer, space);
|
|
345
347
|
}
|
|
346
348
|
catch {
|
|
347
349
|
return null;
|
|
@@ -349,7 +351,7 @@ const jsonStringify = (obj) => {
|
|
|
349
351
|
}
|
|
350
352
|
if (typeof obj === "object") {
|
|
351
353
|
try {
|
|
352
|
-
return JSON.stringify(obj);
|
|
354
|
+
return JSON.stringify(obj, replacer, space);
|
|
353
355
|
}
|
|
354
356
|
catch {
|
|
355
357
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ansuko",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.12",
|
|
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",
|