ansuko 1.3.1 → 1.3.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.
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
@@ -142,6 +142,8 @@ const value = _.equalsOr(a, b, defaultValue) // null == undefined
142
142
  - **`toMultiLineStringGeoJson`** - 将多条线转换为 MultiLineString
143
143
  - **`unionPolygon`** - 将多个 Polygon/MultiPolygon 合并为单个几何
144
144
  - **`parseToTerraDraw`** - 将 GeoJSON 转换为 Terra Draw 兼容的要素
145
+ - **`mZoomInterpolate`** - 将缩放对象转换为 MapBox 插值表达式
146
+ - **`mProps`** - 将 camelCase 属性转换为 MapBox 兼容格式(处理 minzoom、visibility 等特殊情况)
145
147
 
146
148
  ### 原型扩展(插件:`ansuko/plugins/prototype`)
147
149
 
@@ -243,6 +245,17 @@ extended.toPointGeoJson({ lat: 35.6895, lng: 139.6917 })
243
245
 
244
246
  // 合并多个多边形
245
247
  const unified = extended.unionPolygon([polygon1, polygon2])
248
+
249
+ // MapBox 工具
250
+ extended.mZoomInterpolate({ 10: 1, 15: 5, 20: 10 })
251
+ // => ["interpolate", ["linear"], ["zoom"], 10, 1, 15, 5, 20, 10]
252
+
253
+ extended.mProps({
254
+ fillColor: "#ff0000",
255
+ sourceLayer: "buildings",
256
+ visibility: true
257
+ })
258
+ // => { "fill-color": "#ff0000", "source-layer": "buildings", "visibility": "visible" }
246
259
  ```
247
260
 
248
261
  #### 原型插件
package/dist/index.d.ts CHANGED
@@ -22,6 +22,18 @@ type MaybePromise<T> = T | Promise<T>;
22
22
  type MaybeFunction<T> = T | (() => MaybePromise<T>);
23
23
  declare const valueOr: <T, E>(value: MaybeFunction<MaybePromise<T | null | undefined>>, els?: E | (() => MaybePromise<E>)) => MaybePromise<T | E | undefined | null>;
24
24
  declare const emptyOr: <T, E>(value: MaybeFunction<MaybePromise<T | null | undefined>>, els?: E | ((val: T | null | undefined) => MaybePromise<E>)) => MaybePromise<T | E | undefined | null>;
25
+ /**
26
+ * Ensures that all given paths exist on the resolved value; otherwise returns a default.
27
+ * Supports functions and Promises.
28
+ * @param value - Object or thunk
29
+ * @param paths - Paths to check
30
+ * @param els - Default value or thunk receiving the resolved value
31
+ * @returns Value or default
32
+ * @example await hasOr(fetchUser(), ['profile.name','id'], null)
33
+ * @example hasOr({a:{b:1}}, 'a.b', {}) // returns original object
34
+ * @category Promise Utilities
35
+ */
36
+ declare const hasOr: <T, E>(value: MaybeFunction<MaybePromise<T | null | undefined>>, paths: string | string[], els?: E | ((val: T | null | undefined) => MaybePromise<E>)) => MaybePromise<T | E | undefined | null>;
25
37
  /**
26
38
  * Checks emptiness with intuitive rules: numbers and booleans are NOT empty.
27
39
  * @param value - Value to check
@@ -206,40 +218,329 @@ export type ChangesOptions = {
206
218
  };
207
219
  type ChangesAfterCallback<T> = (value: T) => any | Promise<any>;
208
220
  type ChangesAfterFinallyCallback<T> = (value: T, res: any) => any | Promise<any>;
209
- export interface AnsukoType extends Omit<_.LoDashStatic, "castArray" | "isEmpty" | "toNumber"> {
221
+ export interface AnsukoType {
210
222
  extend: typeof extend;
211
223
  isValidStr: typeof isValidStr;
212
224
  valueOr: typeof valueOr;
213
225
  emptyOr: typeof emptyOr;
214
- isEmpty: typeof isEmpty;
215
- toNumber: typeof toNumber;
226
+ hasOr: typeof hasOr;
216
227
  toBool: typeof toBool;
217
228
  boolIf: typeof boolIf;
218
229
  waited: typeof waited;
219
230
  equalsOr: typeof equalsOr;
220
231
  parseJSON: typeof parseJSON;
221
232
  jsonStringify: typeof jsonStringify;
222
- castArray: typeof castArray;
223
233
  changes: typeof changes;
224
234
  swallow: typeof swallow;
225
235
  swallowMap: typeof swallowMap;
226
- size: typeof _.size;
227
- isNil: typeof _.isNil;
236
+ arrayDepth: typeof arrayDepth;
237
+ isEmpty: typeof isEmpty;
238
+ toNumber: typeof toNumber;
239
+ castArray: typeof castArray;
240
+ isEmptyOrg: typeof _.isEmpty;
241
+ toNumberOrg: typeof _.toNumber;
242
+ castArrayOrg: typeof _.castArray;
243
+ add: typeof _.add;
244
+ after: typeof _.after;
245
+ ary: typeof _.ary;
246
+ assign: typeof _.assign;
247
+ assignIn: typeof _.assignIn;
248
+ assignInWith: typeof _.assignInWith;
249
+ assignWith: typeof _.assignWith;
250
+ at: typeof _.at;
251
+ attempt: typeof _.attempt;
252
+ before: typeof _.before;
253
+ bind: typeof _.bind;
254
+ bindAll: typeof _.bindAll;
255
+ bindKey: typeof _.bindKey;
256
+ camelCase: typeof _.camelCase;
257
+ capitalize: typeof _.capitalize;
258
+ ceil: typeof _.ceil;
259
+ chain: typeof _.chain;
260
+ chunk: typeof _.chunk;
261
+ clamp: typeof _.clamp;
262
+ clone: typeof _.clone;
263
+ cloneDeep: typeof _.cloneDeep;
264
+ cloneDeepWith: typeof _.cloneDeepWith;
265
+ cloneWith: typeof _.cloneWith;
266
+ compact: typeof _.compact;
267
+ concat: typeof _.concat;
268
+ cond: typeof _.cond;
269
+ conforms: typeof _.conforms;
270
+ conformsTo: typeof _.conformsTo;
271
+ constant: typeof _.constant;
272
+ countBy: typeof _.countBy;
273
+ create: typeof _.create;
274
+ curry: typeof _.curry;
275
+ curryRight: typeof _.curryRight;
228
276
  debounce: typeof _.debounce;
229
- isEqual: typeof _.isEqual;
277
+ deburr: typeof _.deburr;
278
+ defaultTo: typeof _.defaultTo;
279
+ defaults: typeof _.defaults;
280
+ defaultsDeep: typeof _.defaultsDeep;
281
+ defer: typeof _.defer;
282
+ delay: typeof _.delay;
283
+ difference: typeof _.difference;
284
+ differenceBy: typeof _.differenceBy;
285
+ differenceWith: typeof _.differenceWith;
286
+ divide: typeof _.divide;
287
+ drop: typeof _.drop;
288
+ dropRight: typeof _.dropRight;
289
+ dropRightWhile: typeof _.dropRightWhile;
290
+ dropWhile: typeof _.dropWhile;
291
+ each: typeof _.each;
292
+ eachRight: typeof _.eachRight;
293
+ endsWith: typeof _.endsWith;
294
+ entries: typeof _.entries;
295
+ entriesIn: typeof _.entriesIn;
296
+ eq: typeof _.eq;
297
+ escape: typeof _.escape;
298
+ escapeRegExp: typeof _.escapeRegExp;
299
+ every: typeof _.every;
300
+ extendWith: typeof _.extendWith;
301
+ fill: typeof _.fill;
302
+ filter: typeof _.filter;
303
+ find: typeof _.find;
304
+ findIndex: typeof _.findIndex;
305
+ findKey: typeof _.findKey;
306
+ findLast: typeof _.findLast;
307
+ findLastIndex: typeof _.findLastIndex;
308
+ findLastKey: typeof _.findLastKey;
309
+ first: typeof _.first;
310
+ flatMap: typeof _.flatMap;
311
+ flatMapDeep: typeof _.flatMapDeep;
312
+ flatMapDepth: typeof _.flatMapDepth;
313
+ flatten: typeof _.flatten;
314
+ flattenDeep: typeof _.flattenDeep;
315
+ flattenDepth: typeof _.flattenDepth;
316
+ flip: typeof _.flip;
317
+ floor: typeof _.floor;
318
+ flow: typeof _.flow;
319
+ flowRight: typeof _.flowRight;
320
+ forEach: typeof _.forEach;
321
+ forEachRight: typeof _.forEachRight;
322
+ forIn: typeof _.forIn;
323
+ forInRight: typeof _.forInRight;
324
+ forOwn: typeof _.forOwn;
325
+ forOwnRight: typeof _.forOwnRight;
326
+ fromPairs: typeof _.fromPairs;
327
+ functions: typeof _.functions;
328
+ functionsIn: typeof _.functionsIn;
329
+ get: typeof _.get;
330
+ groupBy: typeof _.groupBy;
331
+ gt: typeof _.gt;
332
+ gte: typeof _.gte;
333
+ has: typeof _.has;
334
+ hasIn: typeof _.hasIn;
335
+ head: typeof _.head;
336
+ identity: typeof _.identity;
337
+ inRange: typeof _.inRange;
338
+ includes: typeof _.includes;
339
+ indexOf: typeof _.indexOf;
340
+ initial: typeof _.initial;
341
+ intersection: typeof _.intersection;
342
+ intersectionBy: typeof _.intersectionBy;
343
+ intersectionWith: typeof _.intersectionWith;
344
+ invert: typeof _.invert;
345
+ invertBy: typeof _.invertBy;
346
+ invoke: typeof _.invoke;
347
+ invokeMap: typeof _.invokeMap;
348
+ isArguments: typeof _.isArguments;
349
+ isArray: typeof _.isArray;
350
+ isArrayBuffer: typeof _.isArrayBuffer;
351
+ isArrayLike: typeof _.isArrayLike;
352
+ isArrayLikeObject: typeof _.isArrayLikeObject;
230
353
  isBoolean: typeof _.isBoolean;
354
+ isBuffer: typeof _.isBuffer;
355
+ isDate: typeof _.isDate;
356
+ isElement: typeof _.isElement;
357
+ isEqual: typeof _.isEqual;
358
+ isEqualWith: typeof _.isEqualWith;
359
+ isError: typeof _.isError;
360
+ isFinite: typeof _.isFinite;
361
+ isFunction: typeof _.isFunction;
362
+ isInteger: typeof _.isInteger;
363
+ isLength: typeof _.isLength;
364
+ isMap: typeof _.isMap;
365
+ isMatch: typeof _.isMatch;
366
+ isMatchWith: typeof _.isMatchWith;
367
+ isNaN: typeof _.isNaN;
368
+ isNative: typeof _.isNative;
369
+ isNil: typeof _.isNil;
370
+ isNull: typeof _.isNull;
371
+ isNumber: typeof _.isNumber;
372
+ isObject: typeof _.isObject;
373
+ isObjectLike: typeof _.isObjectLike;
374
+ isPlainObject: typeof _.isPlainObject;
375
+ isRegExp: typeof _.isRegExp;
376
+ isSafeInteger: typeof _.isSafeInteger;
377
+ isSet: typeof _.isSet;
231
378
  isString: typeof _.isString;
232
- first: typeof _.first;
379
+ isSymbol: typeof _.isSymbol;
380
+ isTypedArray: typeof _.isTypedArray;
381
+ isUndefined: typeof _.isUndefined;
382
+ isWeakMap: typeof _.isWeakMap;
383
+ isWeakSet: typeof _.isWeakSet;
384
+ iteratee: typeof _.iteratee;
385
+ join: typeof _.join;
386
+ kebabCase: typeof _.kebabCase;
387
+ keyBy: typeof _.keyBy;
388
+ keys: typeof _.keys;
389
+ keysIn: typeof _.keysIn;
233
390
  last: typeof _.last;
391
+ lastIndexOf: typeof _.lastIndexOf;
392
+ lowerCase: typeof _.lowerCase;
393
+ lowerFirst: typeof _.lowerFirst;
394
+ lt: typeof _.lt;
395
+ lte: typeof _.lte;
396
+ map: typeof _.map;
397
+ mapKeys: typeof _.mapKeys;
398
+ mapValues: typeof _.mapValues;
399
+ matches: typeof _.matches;
400
+ matchesProperty: typeof _.matchesProperty;
401
+ max: typeof _.max;
402
+ maxBy: typeof _.maxBy;
403
+ mean: typeof _.mean;
404
+ meanBy: typeof _.meanBy;
405
+ memoize: typeof _.memoize;
406
+ merge: typeof _.merge;
407
+ mergeWith: typeof _.mergeWith;
408
+ method: typeof _.method;
409
+ methodOf: typeof _.methodOf;
410
+ min: typeof _.min;
411
+ minBy: typeof _.minBy;
412
+ mixin: typeof _.mixin;
413
+ multiply: typeof _.multiply;
414
+ negate: typeof _.negate;
415
+ noConflict: typeof _.noConflict;
416
+ noop: typeof _.noop;
417
+ now: typeof _.now;
418
+ nth: typeof _.nth;
419
+ nthArg: typeof _.nthArg;
420
+ omit: typeof _.omit;
421
+ omitBy: typeof _.omitBy;
422
+ once: typeof _.once;
423
+ orderBy: typeof _.orderBy;
424
+ over: typeof _.over;
425
+ overArgs: typeof _.overArgs;
426
+ overEvery: typeof _.overEvery;
427
+ overSome: typeof _.overSome;
428
+ pad: typeof _.pad;
429
+ padEnd: typeof _.padEnd;
430
+ padStart: typeof _.padStart;
431
+ parseInt: typeof _.parseInt;
432
+ partial: typeof _.partial;
433
+ partialRight: typeof _.partialRight;
434
+ partition: typeof _.partition;
435
+ pick: typeof _.pick;
436
+ pickBy: typeof _.pickBy;
437
+ property: typeof _.property;
438
+ propertyOf: typeof _.propertyOf;
439
+ pull: typeof _.pull;
440
+ pullAll: typeof _.pullAll;
441
+ pullAllBy: typeof _.pullAllBy;
442
+ pullAllWith: typeof _.pullAllWith;
443
+ pullAt: typeof _.pullAt;
444
+ random: typeof _.random;
445
+ range: typeof _.range;
446
+ rangeRight: typeof _.rangeRight;
447
+ rearg: typeof _.rearg;
448
+ reduce: typeof _.reduce;
449
+ reduceRight: typeof _.reduceRight;
450
+ reject: typeof _.reject;
451
+ remove: typeof _.remove;
452
+ repeat: typeof _.repeat;
453
+ replace: typeof _.replace;
454
+ rest: typeof _.rest;
455
+ result: typeof _.result;
456
+ reverse: typeof _.reverse;
457
+ round: typeof _.round;
458
+ runInContext: typeof _.runInContext;
459
+ sample: typeof _.sample;
460
+ sampleSize: typeof _.sampleSize;
461
+ set: typeof _.set;
462
+ setWith: typeof _.setWith;
463
+ shuffle: typeof _.shuffle;
464
+ size: typeof _.size;
465
+ slice: typeof _.slice;
466
+ snakeCase: typeof _.snakeCase;
467
+ some: typeof _.some;
468
+ sortBy: typeof _.sortBy;
469
+ sortedIndex: typeof _.sortedIndex;
470
+ sortedIndexBy: typeof _.sortedIndexBy;
471
+ sortedIndexOf: typeof _.sortedIndexOf;
472
+ sortedLastIndex: typeof _.sortedLastIndex;
473
+ sortedLastIndexBy: typeof _.sortedLastIndexBy;
474
+ sortedLastIndexOf: typeof _.sortedLastIndexOf;
475
+ sortedUniq: typeof _.sortedUniq;
476
+ sortedUniqBy: typeof _.sortedUniqBy;
477
+ split: typeof _.split;
478
+ spread: typeof _.spread;
479
+ startCase: typeof _.startCase;
480
+ startsWith: typeof _.startsWith;
481
+ stubArray: typeof _.stubArray;
482
+ stubFalse: typeof _.stubFalse;
483
+ stubObject: typeof _.stubObject;
484
+ stubString: typeof _.stubString;
485
+ stubTrue: typeof _.stubTrue;
486
+ subtract: typeof _.subtract;
487
+ sum: typeof _.sum;
488
+ sumBy: typeof _.sumBy;
489
+ tail: typeof _.tail;
490
+ take: typeof _.take;
491
+ takeRight: typeof _.takeRight;
492
+ takeRightWhile: typeof _.takeRightWhile;
493
+ takeWhile: typeof _.takeWhile;
494
+ tap: typeof _.tap;
495
+ template: typeof _.template;
496
+ throttle: typeof _.throttle;
497
+ thru: typeof _.thru;
498
+ times: typeof _.times;
499
+ toArray: typeof _.toArray;
500
+ toFinite: typeof _.toFinite;
501
+ toInteger: typeof _.toInteger;
502
+ toLength: typeof _.toLength;
503
+ toLower: typeof _.toLower;
504
+ toPairs: typeof _.toPairs;
505
+ toPairsIn: typeof _.toPairsIn;
506
+ toPath: typeof _.toPath;
507
+ toPlainObject: typeof _.toPlainObject;
508
+ toSafeInteger: typeof _.toSafeInteger;
509
+ toString: typeof _.toString;
510
+ toUpper: typeof _.toUpper;
511
+ transform: typeof _.transform;
512
+ trim: typeof _.trim;
513
+ trimEnd: typeof _.trimEnd;
514
+ trimStart: typeof _.trimStart;
515
+ truncate: typeof _.truncate;
516
+ unary: typeof _.unary;
517
+ unescape: typeof _.unescape;
518
+ union: typeof _.union;
519
+ unionBy: typeof _.unionBy;
520
+ unionWith: typeof _.unionWith;
234
521
  uniq: typeof _.uniq;
235
- has: typeof _.has;
236
- keys: typeof _.keys;
522
+ uniqBy: typeof _.uniqBy;
523
+ uniqWith: typeof _.uniqWith;
524
+ uniqueId: typeof _.uniqueId;
525
+ unset: typeof _.unset;
526
+ unzip: typeof _.unzip;
527
+ unzipWith: typeof _.unzipWith;
528
+ update: typeof _.update;
529
+ updateWith: typeof _.updateWith;
530
+ upperCase: typeof _.upperCase;
531
+ upperFirst: typeof _.upperFirst;
237
532
  values: typeof _.values;
238
- some: typeof _.some;
239
- arrayDepth: typeof arrayDepth;
240
- isEmptyOrg: typeof _.isEmpty;
241
- toNumberOrg: typeof _.toNumber;
242
- castArrayOrg: typeof _.castArray;
533
+ valuesIn: typeof _.valuesIn;
534
+ without: typeof _.without;
535
+ words: typeof _.words;
536
+ wrap: typeof _.wrap;
537
+ xor: typeof _.xor;
538
+ xorBy: typeof _.xorBy;
539
+ xorWith: typeof _.xorWith;
540
+ zip: typeof _.zip;
541
+ zipObject: typeof _.zipObject;
542
+ zipObjectDeep: typeof _.zipObjectDeep;
543
+ zipWith: typeof _.zipWith;
243
544
  }
244
545
  declare const _default: AnsukoType;
245
546
  export default _default;
@@ -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.1",
3
+ "version": "1.3.3",
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",