ansuko 1.3.2 → 1.3.4

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
@@ -167,6 +167,17 @@ extended.toPointGeoJson({ lat: 35.6895, lng: 139.6917 })
167
167
 
168
168
  // 複数のポリゴンを結合
169
169
  const unified = extended.unionPolygon([polygon1, polygon2])
170
+
171
+ // MapBoxユーティリティ
172
+ extended.mZoomInterpolate({ 10: 1, 15: 5, 20: 10 })
173
+ // => ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 5, 20, 10]
174
+
175
+ extended.mProps({
176
+ fillColor: "#ff0000",
177
+ sourceLayer: "buildings",
178
+ visibility: true
179
+ })
180
+ // => { "fill-color": "#ff0000", "source-layer": "buildings", "visibility": "visible" }
170
181
  ```
171
182
 
172
183
  #### Prototypeプラグイン
@@ -254,6 +265,8 @@ extended.toPointGeoJson([139.7, 35.6])
254
265
  - **`toMultiLineStringGeoJson`** - 複数の線をMultiLineStringに変換
255
266
  - **`unionPolygon`** - 複数のPolygon/MultiPolygonを単一のジオメトリに結合
256
267
  - **`parseToTerraDraw`** - GeoJSONをTerra Draw互換のフィーチャーに変換
268
+ - **`mZoomInterpolate`** - ズームオブジェクトをMapBox補間式に変換
269
+ - **`mProps`** - camelCaseプロパティをMapBox互換形式に変換(minzoom、visibilityなどの特殊ケースに対応)
257
270
 
258
271
  ### Prototype拡張(プラグイン: `ansuko/plugins/prototype`)
259
272
 
package/README.md CHANGED
@@ -143,6 +143,8 @@ const value = _.equalsOr(a, b, defaultValue) // null == undefined
143
143
  - **`toMultiLineStringGeoJson`** - Convert multiple lines to MultiLineString
144
144
  - **`unionPolygon`** - Union multiple Polygon/MultiPolygon into single geometry
145
145
  - **`parseToTerraDraw`** - Convert GeoJSON to Terra Draw compatible features
146
+ - **`mZoomInterpolate`** - Convert zoom object to MapBox interpolation expression
147
+ - **`mProps`** - Convert camelCase properties to MapBox-compatible format (handles special cases like minzoom, visibility)
146
148
 
147
149
  ### Prototype Extensions (plugin: `ansuko/plugins/prototype`)
148
150
 
@@ -244,6 +246,17 @@ extended.toPointGeoJson({ lat: 35.6895, lng: 139.6917 })
244
246
 
245
247
  // Union multiple polygons
246
248
  const unified = extended.unionPolygon([polygon1, polygon2])
249
+
250
+ // MapBox utilities
251
+ extended.mZoomInterpolate({ 10: 1, 15: 5, 20: 10 })
252
+ // => ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 5, 20, 10]
253
+
254
+ extended.mProps({
255
+ fillColor: "#ff0000",
256
+ sourceLayer: "buildings",
257
+ visibility: true
258
+ })
259
+ // => { "fill-color": "#ff0000", "source-layer": "buildings", "visibility": "visible" }
247
260
  ```
248
261
 
249
262
  #### Prototype Plugin
package/README.zh.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ansuko
2
2
 
3
- 一个现代化的 JavaScript/TypeScript 实用工具库,以实用、直观的行为扩展 lodash。
3
+ 在lodash基础上扩展、提供实用且直观易懂的现代JavaScript/TypeScript工具库。
4
4
 
5
5
  [English](./README.md) | [日本語](./README.ja.md) | [简体中文](./README.zh.md)
6
6
 
@@ -12,8 +12,6 @@
12
12
  - **ansuko = underscore → low dash → lodash** - 延续这个系列
13
13
  - **スコ (suko)** - 日文俚语,意为"喜欢"或"最爱"
14
14
 
15
- 这个库修复了 lodash 的不直观行为,并添加了强大的工具来消除常见的 JavaScript 困扰。
16
-
17
15
  ## 安装
18
16
 
19
17
  ```bash
@@ -32,40 +30,40 @@ npm install ansuko
32
30
 
33
31
  ## 核心理念
34
32
 
35
- ansuko 通过直观的行为消除常见的 JavaScript 困扰:
33
+ ansuko以直观的语法,解决了JavaScript中常见的痛点。
36
34
 
37
- ### 修复 lodash 的怪异行为
35
+ ### 修正 lodash 的非常规行为
38
36
 
39
37
  ```typescript
40
38
  // ❌ lodash(不直观)
41
- _.isEmpty(0) // true - 0 真的"空"吗?
42
- _.isEmpty(true) // true - true "空"吗?
43
- _.castArray(null) // [null] - 为什么保留 null?
39
+ _.isEmpty(0) // true - 0真的为「空」吗?
40
+ _.isEmpty(true) // true - true算「空」吗?
41
+ _.castArray(null) // [null] - 为何保留null?
44
42
 
45
43
  // ✅ ansuko(直观)
46
- _.isEmpty(0) // false - 数字不为空
44
+ _.isEmpty(0) // false - 数值不为空
47
45
  _.isEmpty(true) // false - 布尔值不为空
48
- _.castArray(null) // [] - 干净的空数组
46
+ _.castArray(null) // [] - 得到空数组
49
47
  ```
50
48
 
51
49
  ### 安全的 JSON 处理
52
50
 
53
51
  ```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!
52
+ // ❌ 标准 JSON(繁琐)
53
+ JSON.stringify('hello') // '"hello"' - 多余的引号
54
+ JSON.parse(badJson) // throws - 必须用try-catch
55
+
56
+ // ✅ ansuko(简洁直观)
57
+ _.jsonStringify('hello') // null - 非对象不序列化
58
+ _.jsonStringify({ a: 1 }) // '{"a":1}' - 结构简洁
59
+ _.parseJSON(badJson) // null - 不抛异常
60
+ _.parseJSON('{ a: 1, }') // {a:1} - 支持JSON5!
63
61
  ```
64
62
 
65
- ### Promise 感知的后备
63
+ ### 支持Promise的回滚
66
64
 
67
65
  ```typescript
68
- // ❌ 冗长的模式
66
+ // ❌ 冗长写法
69
67
  const data = await fetchData()
70
68
  const result = data ? data : await fetchBackup()
71
69
 
@@ -79,7 +77,7 @@ const result = await _.valueOr(
79
77
  ### 智能比较
80
78
 
81
79
  ```typescript
82
- // ❌ 冗长的三元表达式地狱
80
+ // ❌ 三元运算符地狱
83
81
  const value = a === b ? a : (a == null && b == null ? a : defaultValue)
84
82
 
85
83
  // ✅ ansuko(可读)
@@ -88,40 +86,40 @@ const value = _.equalsOr(a, b, defaultValue) // null == undefined
88
86
 
89
87
  ## 主要特性
90
88
 
91
- ### 增强的 lodash 函数
89
+ ### 增强型lodash函数
92
90
 
93
- - **`isEmpty`** - 检查是否为空(数字和布尔值不为空)
94
- - **`castArray`** - 转换为数组,null/undefined 返回 `[]`
95
- - 所有 lodash 函数仍然可用:`size`、`isNil`、`debounce`、`isEqual`、`keys`、`values`、`has` 等
91
+ - **`isEmpty`** - 检查是否为空(数字和布尔值不视为空)
92
+ - **`castArray`** - 转换为数组,若为null/undefined 则返回 `[]`
93
+ - 支持所有lodash函数:`size`、`isNil`、`debounce`、`isEqual`、`keys`、`values`、`has` 等
96
94
 
97
- ### 值处理与控制流
95
+ ### 数值处理与流控制
98
96
 
99
- - **`valueOr`** - 获取值或默认值,支持 Promise/函数
100
- - **`emptyOr`** - 如果为空返回 null,否则应用回调或返回值
101
- - **`hasOr`** - 检查路径是否存在,如果缺失则返回默认值(支持深度路径和 Promise)
102
- - **`equalsOr`** - 比较并后备,具有直观的 nil 处理(支持 Promise
103
- - **`changes`** - 跟踪对象差异用于数据库更新(支持深度路径如 `profile.tags[1]` 和排除模式)
104
- - **`swallow`** - 执行函数,出错时返回 undefined(同步/异步支持)
105
- - **`swallowMap`** - 映射数组,将错误视为 undefined(可选紧凑模式过滤错误)
97
+ - **`valueOr`** - 支持Promise和函数,获取目标值或默认值
98
+ - **`emptyOr`** - 若为空则返回null,否则应用回调或返回值
99
+ - **`hasOr`** - 检查路径是否存在,不存在则返回默认值(支持深层路径及 Promise)
100
+ - **`equalsOr`** - 支持Promise的比较与回退,具备直观的Nil处理机制
101
+ - **`changes`** - 用于数据库更新的对象差分追踪(支持 profile.tags[1]等深层路径及排除模式)`和排除模式)
102
+ - **`swallow`** - 执行函数并在报错时返回undefined(支持同步/异步)
103
+ - **`swallowMap`** - 将错误处理为undefined的数组map(支持compact模式排除错误项)
106
104
 
107
105
  ### 类型转换与验证
108
106
 
109
- - **`toNumber`** - 解析数字,支持逗号/全角,无效时返回 `null`
110
- - **`toBool`** - 智能布尔值转换("yes"/"no"/"true"/"false"/数字),可配置未检测处理
111
- - **`boolIf`** - 带后备的安全布尔值转换
107
+ - **`toNumber`** - 解析包含逗号、全角字符的数字,无效时返回null
108
+ - **`toBool`** - 智能布尔值转换(支持 "yes"/"no"/"true"/"false"/数字),可配置未检测到时的行为检测处理
109
+ - **`boolIf`** - 带有回退机制的安全布尔值转换
112
110
  - **`isValidStr`** - 非空字符串验证
113
111
 
114
112
  ### JSON 处理
115
113
 
116
- - **`parseJSON`** - 无需 try-catch 的安全 JSON/JSON5 解析(支持注释和尾随逗号)
117
- - **`jsonStringify`** - 仅字符串化有效对象,防止意外的字符串包装
114
+ - **`parseJSON`** - 无需try-catch的安全JSON/JSON5解析(支持注释及末尾逗号)
115
+ - **`jsonStringify`** - 仅字符串化有效对象,防止字符串被重复包裹
118
116
 
119
117
  ### 数组工具
120
118
 
121
119
  - **`arrayDepth`** - 返回数组的嵌套深度(非数组:0,空数组:1)
122
120
  - **`castArray`** - 转换为数组,nil 变为 `[]`(而非 `[null]`)
123
121
 
124
- ### 日文文本(插件:`ansuko/plugins/ja`)
122
+ ### 日语文本处理(插件:`ansuko/plugins/ja`)
125
123
 
126
124
  - **`kanaToFull`** - 半角片假名 → 全角(例如 `ガギ` → `ガギ`)
127
125
  - **`kanaToHalf`** - 全角 → 半角片假名(浊音拆分:`ガギ` → `ガギ`)
@@ -129,51 +127,51 @@ const value = _.equalsOr(a, b, defaultValue) // null == undefined
129
127
  - **`hiraToKana`** - 平假名 → 片假名
130
128
  - **`toHalfWidth`** - 全角 → 半角,可选连字符标准化
131
129
  - **`toFullWidth`** - 半角 → 全角,可选连字符标准化
132
- - **`haifun`** - 将各种连字符标准化为单一字符
130
+ - **`haifun`** - 将各种形式的连字符统一正规化
133
131
 
134
- ### 地理工具(插件:`ansuko/plugins/geo`)
132
+ ### Geo地理空间工具(插件:`ansuko/plugins/geo`)
135
133
 
136
- - **`toGeoJson`** - 通用 GeoJSON 转换器,具有自动检测功能(从高维度到低维度尝试)
137
- - **`toPointGeoJson`** - 将坐标/对象转换为 Point GeoJSON
138
- - **`toPolygonGeoJson`** - 将外环转换为 Polygon(验证闭合环)
139
- - **`toLineStringGeoJson`** - 将坐标转换为 LineString(检查自相交)
140
- - **`toMultiPointGeoJson`** - 将多个点转换为 MultiPoint
141
- - **`toMultiPolygonGeoJson`** - 将多个多边形转换为 MultiPolygon
142
- - **`toMultiLineStringGeoJson`** - 将多条线转换为 MultiLineString
143
- - **`unionPolygon`** - 将多个 Polygon/MultiPolygon 合并为单个几何
144
- - **`parseToTerraDraw`** - 将 GeoJSON 转换为 Terra Draw 兼容的要素
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的Feature
143
+ - **`mZoomInterpolate`** - 将缩放对象转换为MapBox插值表达式
144
+ - **`mProps`** - 将(camelCase)属性转换为MapBox兼容格式(处理minzoom、visibility等特殊情况)
145
145
 
146
- ### 原型扩展(插件:`ansuko/plugins/prototype`)
146
+ ### Prototype原型扩展(插件:`ansuko/plugins/prototype`)
147
147
 
148
- - **`Array.prototype.notMap`** - 使用否定谓词映射 → 布尔数组
149
- - **`Array.prototype.notFilter`** - 通过否定谓词过滤(不匹配的项)
148
+ - **`Array.prototype.notMap`** - 使用谓词取反进行map,返回布尔数组
149
+ - **`Array.prototype.notFilter`** - 使用谓词取反进行filter(筛选不匹配的项)
150
150
 
151
151
  ### 时间工具
152
152
 
153
- - **`waited`** - 通过 N 个动画帧延迟执行(比 `setTimeout` 更适合 React/DOM
153
+ - **`waited`** - 延迟N个动画帧后执行(在 React/DOM 環境下比`setTimeout`更优)
154
154
 
155
155
  ## 插件架构
156
156
 
157
- ansuko 使用最小核心 + 插件架构来保持你的包大小小:
158
-
159
- - **核心**(~20KB):改进 lodash 的基本工具
160
- - **日文插件**(~5KB):仅在需要日文文本处理时加载
161
- - **地理插件**(~100KB 含 @turf/turf):仅为 GIS 应用加载
162
- - **原型插件**(~1KB):仅在需要数组原型扩展时加载
157
+ ansuko使用最小核心 + 插件架构来保持你的包大小小:
163
158
 
164
- 这意味着你只为使用的功能付费!
159
+ - **核心**(约 20KB):在 lodash 上增强的必备工具
160
+ - **日文插件**(约 5KB):仅在需要日文文本处理时引入
161
+ - **Geo 插件**(约 100KB,含 @turf/turf):面向 GIS 应用
162
+ - **Prototype 插件**(约 1KB):仅在需要扩展 Array.prototype 时引入
165
163
 
166
164
  ```typescript
167
- // 最小包 - 仅核心
165
+ // 最小打包:仅核心
168
166
  import _ from 'ansuko' // ~20KB
169
167
 
170
- // 需要时添加日文支持
168
+ // 按需加入日文支持
171
169
  import jaPlugin from 'ansuko/plugins/ja'
172
- _.extend(jaPlugin) // +5KB
170
+ const extended = _.extend(jaPlugin) // +5KB
173
171
 
174
- // 为地图应用添加 GIS 功能
172
+ // 地图类应用再挂载 GIS
175
173
  import geoPlugin from 'ansuko/plugins/geo'
176
- _.extend(geoPlugin) // +100KB
174
+ const full = extended.extend(geoPlugin) // +100KB
177
175
  ```
178
176
 
179
177
  ## 快速开始
@@ -243,6 +241,17 @@ extended.toPointGeoJson({ lat: 35.6895, lng: 139.6917 })
243
241
 
244
242
  // 合并多个多边形
245
243
  const unified = extended.unionPolygon([polygon1, polygon2])
244
+
245
+ // MapBox 工具
246
+ extended.mZoomInterpolate({ 10: 1, 15: 5, 20: 10 })
247
+ // => ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 5, 20, 10]
248
+
249
+ extended.mProps({
250
+ fillColor: "#ff0000",
251
+ sourceLayer: "buildings",
252
+ visibility: true
253
+ })
254
+ // => { "fill-color": "#ff0000", "source-layer": "buildings", "visibility": "visible" }
246
255
  ```
247
256
 
248
257
  #### 原型插件
@@ -276,37 +285,37 @@ extended.toPointGeoJson([139.7, 35.6])
276
285
 
277
286
  ## 文档
278
287
 
279
- 详细信息请参阅:
288
+ 更多详细信息,请参阅:
280
289
 
281
- - **[API 参考](./docs/API.zh.md)** - 带示例的完整 API 文档
282
- - **[使用指南](./docs/Guide.zh.md)** - 实际示例和模式
290
+ - **[API 参考](./docs/API.zh.md)** - 包含示例的完整API文档
291
+ - **[使用指南](./docs/Guide.zh.md)** - 实际使用案例与设计模式
283
292
 
284
- ## TypeScript 支持
293
+ ## 支持TypeScript
285
294
 
286
- 完整的 TypeScript 支持,包含类型定义。所有函数都完全类型化,支持泛型。
295
+ 完美支持TypeScript,包含完整的类型定义。所有函数均支持泛型,并经过严格的类型标注。
287
296
 
288
- ## 为什么不只使用 lodash
297
+ ## 为什么仅有lodash还不够?
289
298
 
290
- lodash 很优秀,但有一些[社区批评](https://github.com/lodash/lodash/issues)的怪异行为:
299
+ lodash很优秀,但存在一些[被社区广为诟病](https://github.com/lodash/lodash/issues)的怪癖:
291
300
 
292
- ### 修复的行为
301
+ ### 已修正的部分
293
302
 
294
- 1. **`_.isEmpty(true)` 返回 `true`** - 布尔值真的"空"吗?
295
- 2. **`_.isEmpty(1)` 返回 `true`** - 数字 1 "空"吗?
296
- 3. **`_.castArray(null)` 返回 `[null]`** - 为什么在数组中包含 null
303
+ 1. **`_.isEmpty(true)` 返回 `true`** - 布尔值真的为"空"吗?
304
+ 2. **`_.isEmpty(1)` 返回 `true`** - 数字1怎么能为"空"呢?
305
+ 3. **`_.castArray(null)` 返回 `[null]`** - 为什么要把null包含在数组里?
297
306
 
298
- ### lodash 中缺少的添加工具
307
+ ### lodash中没有的工具函数
299
308
 
300
- 4. **无安全的 JSON 解析** - 总是需要 try-catch
301
- 5. **无内置的比较与后备** - 到处都是冗长的三元表达式模式
302
- 6. **无 Promise 感知的值解析** - 手动 Promise 处理变得混乱
303
- 7. **无对象差异跟踪** - 需要外部库进行数据库更新
304
- 8. **`JSON.stringify("hello")` 添加引号** - 那些 `'"hello"'` 引号很烦人
309
+ 4. **无安全的 JSON 解析** - 总是需要写重复的try-catch代码块
310
+ 5. **无内置的比较与后备** - 代码中到处充斥着冗余的三元运算符
311
+ 6. **无 Promise 感知的值解析** - 手动处理Promise逻辑非常繁琐
312
+ 7. **无对象差异跟踪** - 进行数据库更新操作时往往需要引入额外库
313
+ 8. **`JSON.stringify("hello")` 会添加多余引号 —— 生成 `'"hello"'`这种带引号的繁琐字符串
305
314
 
306
- ### 实际示例
315
+ ### 实际使用案例
307
316
 
308
317
  ```typescript
309
- // lodash 的常见模式(冗长且容易出错)
318
+ // lodash的常见写法(冗长且易错)
310
319
  let data
311
320
  try {
312
321
  const cached = cache.get(id)
@@ -320,7 +329,7 @@ try {
320
329
  data = defaultValue
321
330
  }
322
331
 
323
- // ansuko 的相同逻辑(简洁且安全)
332
+ // ansuko的实现逻辑(简洁且安全)
324
333
  const data = await _.valueOr(
325
334
  () => cache.get(id),
326
335
  () => api.fetch(id),
@@ -328,13 +337,13 @@ const data = await _.valueOr(
328
337
  )
329
338
  ```
330
339
 
331
- ansuko 保持与 lodash **100% 兼容性**,同时修复这些问题并为现代 JavaScript 开发添加强大的工具。
340
+ ansuko在修正上述问题的同时,为现代JavaScript开发增添了强大的工具函数,并保持了与Lodash的100%兼容性。
332
341
 
333
342
  ## 依赖项
334
343
 
335
344
  - **`lodash`** - 核心工具函数
336
- - **`json5`** - 增强的 JSON 解析,支持注释和尾随逗号
337
- - **`@turf/turf`** - 地理空间分析(由地理插件使用)
345
+ - **`json5`** - 支持注释和末尾逗号的扩展JSON解析
346
+ - **`@turf/turf`** - 地理空间分析(用于geo插件)
338
347
 
339
348
  ## 从源代码构建
340
349
 
@@ -343,10 +352,10 @@ npm install
343
352
  npm run build
344
353
  ```
345
354
 
346
- 这将在 `dist` 目录中生成编译后的 JavaScript 和类型定义。
355
+ 执行后将在`dist`目录下生成编译后的JavaScript文件和类型定义。
347
356
 
348
- ## 开发
349
- 由 Sera 开发,Claude(Anthropic)协助文档编写、代码审查和技术讨论。
357
+ ## 开发相关
358
+ 因为不太擅长写测试和文档,所以一直在使用Claude进行头脑风暴并辅助编写文档。
350
359
 
351
360
  ## 许可证
352
361
 
@@ -358,4 +367,4 @@ Naoto Sera
358
367
 
359
368
  ---
360
369
 
361
- 无论中日国际形势如何,我认为开源软件(OSS)应始终保持和平。也衷心希望您能有同样的想法。
370
+ 技术无国界,开源即和平。无论世界如何变迁,愿代码始终纯粹。
@@ -21,6 +21,8 @@ export interface AnsukoGeoPluginExtension {
21
21
  toMultiPolygonGeoJson: (geo: any, digit?: number) => GeoJSON.MultiPolygon | null;
22
22
  toMultiLineStringGeoJson: (geo: any, digit?: number) => GeoJSON.MultiLineString | null;
23
23
  unionPolygon: (geo: any, digit?: number) => GeoJSON.Polygon | GeoJSON.MultiPolygon | null;
24
+ mZoomInterpolate: (zoomValues: Record<number, number>, type?: string) => any;
25
+ mProps: (properties: Record<string, any>, excludeKeys?: string[]) => Record<string, any>;
24
26
  }
25
27
  declare const ansukoGeoPlugin: <T extends AnsukoType>(ansuko: T) => T & AnsukoGeoPluginExtension;
26
28
  export default ansukoGeoPlugin;
@@ -551,6 +551,108 @@ const ansukoGeoPlugin = (ansuko) => {
551
551
  }
552
552
  return features;
553
553
  };
554
+ /**
555
+ * Creates a MapBox zoom interpolation expression from a simple object mapping.
556
+ * Converts `{10: 1, 15: 5, 20: 10}` into MapBox's interpolation array format.
557
+ *
558
+ * @param zoomValues - Object mapping zoom levels to values
559
+ * @param type - Interpolation type: "linear", "exponential", or "cubic-bezier" (default: "linear")
560
+ * @returns MapBox interpolation expression array
561
+ * @example
562
+ * _.mZoomInterpolate({ 10: 1, 15: 5, 20: 10 })
563
+ * // Returns: ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 5, 20, 10]
564
+ * @example
565
+ * _.mZoomInterpolate({ 12: 0.5, 18: 2 }, "exponential")
566
+ * @category Geo Utilities
567
+ */
568
+ const mZoomInterpolate = (zoomValues, type = "linear") => {
569
+ let vals = [];
570
+ Object.entries(zoomValues).sort((v1, v2) => {
571
+ return parseFloat(v1[0]) - parseFloat(v2[0]);
572
+ }).map(([zoom, val]) => {
573
+ vals.push(parseFloat(zoom));
574
+ vals.push(val);
575
+ });
576
+ return [
577
+ "interpolate",
578
+ [type],
579
+ ["zoom"],
580
+ ...vals,
581
+ ];
582
+ };
583
+ /**
584
+ * Converts camelCase properties to MapBox-compatible format.
585
+ * Handles special cases like minzoom, maxzoom, tileSize, cluster properties, and converts
586
+ * visibility boolean to "visible"/"none". Recursively processes nested objects and arrays.
587
+ *
588
+ * @param properties - Object with camelCase properties
589
+ * @param excludeKeys - Keys to exclude from conversion (keeps original key and value)
590
+ * @returns Converted properties object compatible with MapBox
591
+ * @example
592
+ * _.mProps({
593
+ * fillColor: "#ff0000",
594
+ * fillOpacity: 0.5,
595
+ * sourceLayer: "buildings"
596
+ * })
597
+ * // Returns: { "fill-color": "#ff0000", "fill-opacity": 0.5, "source-layer": "buildings" }
598
+ * @example
599
+ * _.mProps({ visibility: true }) // Returns: { visibility: "visible" }
600
+ * @example
601
+ * _.mProps({ minZoom: 10, maxZoom: 20 }) // Returns: { minzoom: 10, maxzoom: 20 }
602
+ * @category Geo Utilities
603
+ */
604
+ const mProps = (properties, excludeKeys = []) => {
605
+ if (_.isEmpty(properties)) {
606
+ return properties;
607
+ }
608
+ if (Array.isArray(properties)) {
609
+ return properties.map(p => mProps(p, excludeKeys));
610
+ }
611
+ if (typeof properties === "object") {
612
+ return Object.fromEntries(Object.entries(properties).map(([key, value]) => {
613
+ let newKey = key;
614
+ const lKey = key.toLowerCase();
615
+ if (lKey === "minzoom") {
616
+ newKey = "minzoom";
617
+ }
618
+ else if (lKey === "maxzoom") {
619
+ newKey = "maxzoom";
620
+ }
621
+ else if (lKey === "tilesize") {
622
+ newKey = "tileSize";
623
+ }
624
+ else if (lKey === "clusterradius") {
625
+ newKey = "clusterRadius";
626
+ }
627
+ else if (lKey === "clustermaxzoom") {
628
+ newKey = "clusterMaxZoom";
629
+ }
630
+ else if (lKey === "clusterminpoints") {
631
+ newKey = "clusterMinPoints";
632
+ }
633
+ else if (lKey === "clusterproperties") {
634
+ newKey = "clusterProperties";
635
+ }
636
+ else if (lKey === "linemetrics") {
637
+ newKey = "lineMetrics";
638
+ }
639
+ else {
640
+ newKey = _.kebabCase(newKey).toLowerCase();
641
+ }
642
+ if (key === "visibility" && _.isBoolean(value)) {
643
+ return ["visibility", value ? "visible" : "none"];
644
+ }
645
+ if (excludeKeys.includes(key) || excludeKeys.includes(newKey)) {
646
+ return [key, value];
647
+ }
648
+ if (Array.isArray(value) || typeof value === "object") {
649
+ value = mProps(value, excludeKeys);
650
+ }
651
+ return [newKey, value];
652
+ }));
653
+ }
654
+ return properties;
655
+ };
554
656
  const a = ansuko;
555
657
  a.toLngLatArray = toLngLatArray;
556
658
  a.toGeoJson = toGeoJson;
@@ -562,6 +664,8 @@ const ansukoGeoPlugin = (ansuko) => {
562
664
  a.toMultiPolygonGeoJson = toMultiPolygonGeoJson;
563
665
  a.unionPolygon = unionPolygon;
564
666
  a.parseToTerraDraw = parseToTerraDraw;
667
+ a.mZoomInterpolate = mZoomInterpolate;
668
+ a.mProps = mProps;
565
669
  return ansuko;
566
670
  };
567
671
  export default ansukoGeoPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ansuko",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
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",