ansuko 1.1.1

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.
@@ -0,0 +1,25 @@
1
+ import GeoJSON from "geojson";
2
+ import { type AnsukoType } from "../index.js";
3
+ /**
4
+ * Geometry type selector for conversions. Use `auto` to try higher dimensions first.
5
+ */
6
+ export declare enum GeomType {
7
+ point = 0,
8
+ polygon = 1,
9
+ lineString = 2,
10
+ multiPoint = 3,
11
+ multiPolygon = 4,
12
+ multiLineString = 5,
13
+ auto = "auto"
14
+ }
15
+ export interface AnsukoGeoPluginExtension {
16
+ toPointGeoJson: (geo: any, digit?: number) => GeoJSON.Point | null;
17
+ toPolygonGeoJson: (geo: any, digit?: number) => GeoJSON.Polygon | null;
18
+ toLineStringGeoJson: (geo: any, digit?: number) => GeoJSON.LineString | null;
19
+ toMultiPointGeoJson: (geo: any, digit?: number) => GeoJSON.MultiPoint | null;
20
+ toMultiPolygonGeoJson: (geo: any, digit?: number) => GeoJSON.MultiPolygon | null;
21
+ toMultiLineStringGeoJson: (geo: any, digit?: number) => GeoJSON.MultiLineString | null;
22
+ unionPolygon: (geo: any, digit?: number) => GeoJSON.Polygon | GeoJSON.MultiPolygon | null;
23
+ }
24
+ declare const ansukoGeoPlugin: <T extends AnsukoType>(ansuko: T) => T & AnsukoGeoPluginExtension;
25
+ export default ansukoGeoPlugin;
@@ -0,0 +1,566 @@
1
+ import * as turf from "@turf/turf";
2
+ /**
3
+ * Geometry type selector for conversions. Use `auto` to try higher dimensions first.
4
+ */
5
+ export var GeomType;
6
+ (function (GeomType) {
7
+ GeomType[GeomType["point"] = 0] = "point";
8
+ GeomType[GeomType["polygon"] = 1] = "polygon";
9
+ GeomType[GeomType["lineString"] = 2] = "lineString";
10
+ GeomType[GeomType["multiPoint"] = 3] = "multiPoint";
11
+ GeomType[GeomType["multiPolygon"] = 4] = "multiPolygon";
12
+ GeomType[GeomType["multiLineString"] = 5] = "multiLineString";
13
+ GeomType["auto"] = "auto";
14
+ })(GeomType || (GeomType = {}));
15
+ const ansukoGeoPlugin = (ansuko) => {
16
+ const _ = ansuko;
17
+ /**
18
+ * Converts a coordinate-like value to a [lng, lat] tuple, optionally rounding digits.
19
+ * Swaps order if lat/lng appear to be inverted. Returns null when invalid.
20
+ * @internal
21
+ */
22
+ const toLngLatToArray = (coord, digit) => {
23
+ if (_.isNil(coord)) {
24
+ return null;
25
+ }
26
+ let tLat = null;
27
+ let tLng = null;
28
+ if (Array.isArray(coord) && _.isNumber(coord[0]) && _.isNumber(coord[1])) {
29
+ tLng = _.toNumber(coord[0]);
30
+ tLat = _.toNumber(coord[1]);
31
+ }
32
+ else {
33
+ if (typeof coord !== "object") {
34
+ return null;
35
+ }
36
+ tLng = _.toNumber(coord.lng ?? coord.lon ?? coord.longitude);
37
+ tLat = _.toNumber(coord.lat ?? coord.latitude);
38
+ }
39
+ if (!tLat || !tLng) {
40
+ return null;
41
+ }
42
+ if (((tLat < -90 || tLat > 90) && (tLng > -90 && tLng < 90)) ||
43
+ ((tLng < -180 || tLng > 180) && (tLat > -180 && tLat < 180))) {
44
+ const t = tLat;
45
+ tLat = tLng;
46
+ tLat = t;
47
+ }
48
+ return [
49
+ (_.isNumber(digit) ? _.toNumber(tLng.toFixed(digit)) : tLng),
50
+ (_.isNumber(digit) ? _.toNumber(tLat.toFixed(digit)) : tLat)
51
+ ];
52
+ };
53
+ /**
54
+ * Converts coordinates or an object to a Point GeoJSON.
55
+ * @param geo - [lng,lat] or {lat,lng}
56
+ * @param digit - Rounding digits
57
+ * @returns Point or null
58
+ * @example toPointGeoJson([139.7671,35.6812])
59
+ * @example toPointGeoJson({ lat:35.6895, lng:139.6917 })
60
+ * @category Geo Utilities
61
+ */
62
+ const toPointGeoJson = (geo, digit) => {
63
+ let lngLat = null;
64
+ if (_.isEmpty(geo)) {
65
+ return null;
66
+ }
67
+ if (Array.isArray(geo)) {
68
+ if (_.size(geo) === 1) {
69
+ lngLat = toLngLatToArray(geo[0], digit);
70
+ }
71
+ else {
72
+ lngLat = toLngLatToArray(geo, digit);
73
+ }
74
+ }
75
+ else if (_.has(geo, "lat") || _.has(geo, "latitude")) {
76
+ lngLat = toLngLatToArray(geo, digit);
77
+ }
78
+ else if (_.has(geo, "type")) {
79
+ switch (geo.type.toLowerCase()) {
80
+ case "featurecollection":
81
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "point") {
82
+ return null;
83
+ }
84
+ if (_.size(geo.features) !== 1) {
85
+ return null;
86
+ }
87
+ lngLat = toLngLatToArray(_.get(geo, "features[0].geometry.coordinates"), digit);
88
+ break;
89
+ case "feature":
90
+ if (geo.geometry?.type?.toLowerCase() !== "point") {
91
+ return null;
92
+ }
93
+ lngLat = toLngLatToArray(geo.geometry?.coordinates, digit);
94
+ break;
95
+ case "point":
96
+ lngLat = toLngLatToArray(geo.coordinates, digit);
97
+ break;
98
+ default:
99
+ return null;
100
+ }
101
+ }
102
+ else {
103
+ return null;
104
+ }
105
+ if (!lngLat) {
106
+ return null;
107
+ } // null チェック追加
108
+ try {
109
+ return turf.point(lngLat)?.geometry;
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ };
115
+ /**
116
+ * Converts an outer ring to Polygon GeoJSON (ring must be closed).
117
+ * @param geo - [[lng,lat], ...] or Polygon-like GeoJSON
118
+ * @param digit - Rounding digits
119
+ * @returns Polygon or null
120
+ * @example toPolygonGeoJson([
121
+ * [139.70,35.68],[139.78,35.68],[139.78,35.75],[139.70,35.75],[139.70,35.68]
122
+ * ])
123
+ * @category Geo Utilities
124
+ */
125
+ const toPolygonGeoJson = (geo, digit) => {
126
+ let ll = null;
127
+ if (_.arrayDepth(geo) === 3 && _.size(geo) === 1) { // [[外周リング]]
128
+ ll = _.first(geo).map((coord) => toLngLatToArray(coord, digit));
129
+ }
130
+ else if (_.arrayDepth(geo) === 2) { // [外周リング]
131
+ ll = geo.map((coord) => toLngLatToArray(coord, digit));
132
+ }
133
+ else if (_.has(geo, "type")) {
134
+ switch (_.get(geo, "type")?.toLowerCase()) {
135
+ case "featurecollection":
136
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "polygon") {
137
+ return null;
138
+ }
139
+ if (_.size(geo.features) !== 1) {
140
+ return null;
141
+ }
142
+ // 最初のリング(外周)だけ取得
143
+ ll = _.first(_.first(geo.features)?.geometry.coordinates)
144
+ ?.map((coord) => toLngLatToArray(coord, digit));
145
+ break;
146
+ case "feature":
147
+ if (geo.geometry?.type?.toLowerCase() !== "polygon") {
148
+ return null;
149
+ }
150
+ ll = _.first(geo.geometry.coordinates)?.map((coord) => toLngLatToArray(coord, digit));
151
+ break;
152
+ case "polygon":
153
+ ll = _.first(geo.coordinates)?.map((coord) => toLngLatToArray(coord, digit));
154
+ break;
155
+ default:
156
+ return null;
157
+ }
158
+ }
159
+ else {
160
+ return null;
161
+ }
162
+ if (!ll || ll.find(_.isEmpty)) {
163
+ return null;
164
+ }
165
+ if (!_.isEqual(_.first(ll), _.last(ll))) {
166
+ return null;
167
+ } // 閉じてるかチェック
168
+ try {
169
+ return turf.polygon([ll])?.geometry; // [ll] で囲む(外周リングの配列にする)
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ };
175
+ /**
176
+ * Converts coordinate sequence to LineString GeoJSON; returns null if self-intersecting.
177
+ * @param geo - [[lng,lat], ...] or LineString-like GeoJSON
178
+ * @param digit - Rounding digits
179
+ * @returns LineString or null
180
+ * @example toLineStringGeoJson([[139.70,35.68],[139.75,35.70],[139.80,35.72]])
181
+ * @category Geo Utilities
182
+ */
183
+ const toLineStringGeoJson = (geo, digit) => {
184
+ let ll = null;
185
+ if (_.arrayDepth(geo) === 3 && _.size(geo) === 1) {
186
+ ll = _.first(geo).map((l) => toLngLatToArray(l, digit));
187
+ }
188
+ else if (_.arrayDepth(geo) === 2) {
189
+ ll = geo.map((l) => toLngLatToArray(l, digit));
190
+ }
191
+ else if (_.has(geo, "type")) {
192
+ switch (_.get(geo, "type")?.toLowerCase()) {
193
+ case "featurecollection":
194
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "linestring") {
195
+ return null;
196
+ }
197
+ if (_.size(geo.features) !== 1) {
198
+ return null;
199
+ }
200
+ ll = _.first(geo.features)?.geometry.coordinates?.map((l) => toLngLatToArray(l, digit));
201
+ break;
202
+ case "feature":
203
+ if (geo.geometry?.type?.toLowerCase() !== "linestring") {
204
+ return null;
205
+ }
206
+ ll = geo.geometry?.coordinates?.map((l) => toLngLatToArray(l, digit));
207
+ break;
208
+ case "linestring":
209
+ ll = geo.coordinates?.map((l) => toLngLatToArray(l, digit));
210
+ break;
211
+ default:
212
+ return null;
213
+ }
214
+ }
215
+ else {
216
+ return null;
217
+ }
218
+ if (!ll || ll.find(_.isEmpty)) {
219
+ return null;
220
+ }
221
+ try {
222
+ const feature = turf.lineString(ll); // Feature を取得
223
+ if (!_.isEmpty(turf.kinks(feature)?.features)) {
224
+ return null;
225
+ } // 交差チェック
226
+ return feature.geometry; // Geometry を返す
227
+ }
228
+ catch {
229
+ return null;
230
+ }
231
+ };
232
+ /**
233
+ * Converts multiple points to MultiPoint GeoJSON.
234
+ * @param geo - [[lng,lat], ...] or MultiPoint-like GeoJSON
235
+ * @param digit - Rounding digits
236
+ * @returns MultiPoint or null
237
+ * @example toMultiPointGeoJson([[139.70,35.68],[139.71,35.69],[139.72,35.70]])
238
+ * @category Geo Utilities
239
+ */
240
+ const toMultiPointGeoJson = (geo, digit) => {
241
+ let ll = null;
242
+ if (_.arrayDepth(geo) === 2) { // MultiPointは2次元
243
+ ll = geo.map((coord) => toLngLatToArray(coord, digit));
244
+ }
245
+ else if (_.has(geo, "type")) {
246
+ switch (_.get(geo, "type")?.toLowerCase()) {
247
+ case "featurecollection":
248
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "multipoint") {
249
+ return null;
250
+ }
251
+ if (_.size(geo.features) !== 1) {
252
+ return null;
253
+ }
254
+ ll = _.first(geo.features).geometry?.coordinates
255
+ ?.map((coord) => toLngLatToArray(coord, digit));
256
+ break;
257
+ case "feature":
258
+ if (geo.geometry?.type?.toLowerCase() !== "multipoint") {
259
+ return null;
260
+ }
261
+ ll = geo.geometry?.coordinates?.map((coord) => toLngLatToArray(coord, digit));
262
+ break;
263
+ case "multipoint":
264
+ ll = geo.coordinates?.map((coord) => toLngLatToArray(coord, digit));
265
+ break;
266
+ default:
267
+ return null;
268
+ }
269
+ }
270
+ else {
271
+ return null;
272
+ }
273
+ if (!ll || ll.find(_.isEmpty)) {
274
+ return null;
275
+ }
276
+ try {
277
+ return turf.multiPoint(ll)?.geometry;
278
+ }
279
+ catch {
280
+ return null;
281
+ }
282
+ };
283
+ /**
284
+ * Converts polygons (outer rings) to MultiPolygon GeoJSON.
285
+ * @param geo - Polygons
286
+ * @param digit - Rounding digits
287
+ * @returns MultiPolygon or null
288
+ * @example toMultiPolygonGeoJson([
289
+ * [[[139.7,35.6],[139.8,35.6],[139.8,35.7],[139.7,35.7],[139.7,35.6]]],
290
+ * [[[139.75,35.65],[139.85,35.65],[139.85,35.75],[139.75,35.75],[139.75,35.65]]]
291
+ * ])
292
+ * @category Geo Utilities
293
+ */
294
+ const toMultiPolygonGeoJson = (geo, digit) => {
295
+ let ll = null;
296
+ if (_.arrayDepth(geo) === 4) {
297
+ ll = geo.map((polygon) => _.first(polygon).map((l) => toLngLatToArray(l, digit)));
298
+ }
299
+ else if (_.has(geo, "type")) {
300
+ switch (geo.type.toLowerCase()) {
301
+ case "featurecollection":
302
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "multipolygon") {
303
+ return null;
304
+ }
305
+ if (_.size(geo.features) !== 1) {
306
+ return null;
307
+ }
308
+ ll = _.first(geo.features).geometry?.coordinates?.map((polygon) => _.first(polygon).map((l) => toLngLatToArray(l, digit)));
309
+ break;
310
+ case "feature":
311
+ if (geo.geometry?.type?.toLowerCase() !== "multipolygon") {
312
+ return null;
313
+ }
314
+ ll = geo.geometry?.coordinates?.map((polygon) => _.first(polygon).map((l) => toLngLatToArray(l, digit)));
315
+ break;
316
+ case "multipolygon":
317
+ ll = geo.coordinates?.map((polygon) => _.first(polygon).map((l) => toLngLatToArray(l, digit)));
318
+ break;
319
+ default:
320
+ return null;
321
+ }
322
+ }
323
+ else {
324
+ return null;
325
+ }
326
+ if (!ll || ll.find((polygon) => !polygon || polygon.find((ring) => !ring || ring.find(_.isEmpty)) || !_.isEqual(_.first(polygon), _.last(polygon)))) {
327
+ return null;
328
+ }
329
+ try {
330
+ return turf.multiPolygon(ll)?.geometry;
331
+ }
332
+ catch {
333
+ return null;
334
+ }
335
+ };
336
+ /**
337
+ * Converts lines to MultiLineString GeoJSON, rejecting self-intersections.
338
+ * @param geo - Lines
339
+ * @param digit - Rounding digits
340
+ * @returns MultiLineString or null
341
+ * @example toMultiLineStringGeoJson([
342
+ * [[139.7,35.6],[139.8,35.65]],
343
+ * [[139.75,35.62],[139.85,35.68]]
344
+ * ])
345
+ * @category Geo Utilities
346
+ */
347
+ const toMultiLineStringGeoJson = (geo, digit) => {
348
+ let ll = null;
349
+ if (_.arrayDepth(geo) === 3) {
350
+ ll = geo.map((line) => line.map((l) => toLngLatToArray(l, digit)));
351
+ }
352
+ else if (_.has(geo, "type")) {
353
+ switch (_.get(geo, "type").toLowerCase()) {
354
+ case "featurecollection":
355
+ if (_.get(geo, "features[0].geometry.type")?.toLowerCase() !== "multilinestring") {
356
+ return null;
357
+ }
358
+ if (_.size(geo.features) !== 1) {
359
+ return null;
360
+ }
361
+ ll = _.first(geo.features).geometry?.coordinates?.map((line) => line.map((l) => toLngLatToArray(l, digit)));
362
+ break;
363
+ case "feature":
364
+ if (geo.geometry?.type?.toLowerCase() !== "multilinestring") {
365
+ return null;
366
+ } // 修正
367
+ ll = geo.geometry?.coordinates?.map((line) => line.map((l) => toLngLatToArray(l, digit)));
368
+ break;
369
+ case "multilinestring":
370
+ ll = geo.coordinates?.map((line) => line.map((l) => toLngLatToArray(l, digit)));
371
+ break;
372
+ default:
373
+ return null;
374
+ }
375
+ }
376
+ if (!ll || ll.find((g) => !g || g.find(_.isEmpty))) {
377
+ return null;
378
+ }
379
+ try {
380
+ // 一旦linestringでチェック
381
+ if (ll.find((l) => {
382
+ const r = turf.lineString(l);
383
+ if (!r)
384
+ return true;
385
+ const kinks = turf.kinks(r);
386
+ return !_.isEmpty(kinks.features);
387
+ })) {
388
+ return null;
389
+ }
390
+ return turf.multiLineString(ll)?.geometry;
391
+ }
392
+ catch {
393
+ return null;
394
+ }
395
+ };
396
+ /**
397
+ * Unions polygons into a single Polygon/MultiPolygon.
398
+ * @param geo - Polygon/MultiPolygon/FeatureCollection, etc.
399
+ * @param digit - Rounding digits
400
+ * @returns Unified geometry or null
401
+ * @example unionPolygon([
402
+ * [[139.7,35.6],[139.8,35.6],[139.8,35.7],[139.7,35.7],[139.7,35.6]],
403
+ * [[139.75,35.65],[139.85,35.65],[139.85,35.75],[139.75,35.75],[139.75,35.65]]
404
+ * ])
405
+ * @category Geo Utilities
406
+ */
407
+ const unionPolygon = (geo, digit) => {
408
+ let list = null;
409
+ const g = geo;
410
+ if (_.arrayDepth(geo) === 4) {
411
+ geo = _.first(geo);
412
+ }
413
+ if (Array.isArray(geo)) {
414
+ list = geo.map(g => {
415
+ const p = toPolygonGeoJson(g, digit);
416
+ return p ? turf.polygon(p.coordinates) : null;
417
+ }).filter(Boolean);
418
+ }
419
+ else if (_.has(geo, "type")) {
420
+ switch (_.get(g, "type")?.toLowerCase()) {
421
+ case "featurecollection":
422
+ list = g.features?.map((f) => {
423
+ const p = toPolygonGeoJson(f, digit);
424
+ return p ? turf.polygon(p.coordinates) : null;
425
+ }).filter(Boolean);
426
+ break;
427
+ case "feature":
428
+ if (g.geometry?.type !== "polygon") {
429
+ return g;
430
+ }
431
+ else if (g.geometry?.type === "multipolygon") {
432
+ list = g.geometry?.coordinates.map((c) => {
433
+ const p = toPolygonGeoJson(c, digit);
434
+ return p ? turf.polygon(p.coordinates) : null;
435
+ }).filter(Boolean);
436
+ }
437
+ break;
438
+ case "polygon":
439
+ return g;
440
+ case "multipolygon":
441
+ list = g.coordinates.map((c) => {
442
+ const p = toPolygonGeoJson(c, digit);
443
+ return p ? turf.polygon(p.coordinates) : null;
444
+ }).filter(Boolean);
445
+ break;
446
+ default:
447
+ return null;
448
+ }
449
+ }
450
+ else {
451
+ return null;
452
+ }
453
+ if (_.isEmpty(list)) {
454
+ return null;
455
+ }
456
+ if (_.size(list) === 1) {
457
+ return _.first(list).geometry;
458
+ }
459
+ return turf.union(turf.featureCollection(list))?.geometry ?? null;
460
+ };
461
+ /**
462
+ * Converts input to GeoJSON geometry of the given type. `auto` tries higher dimensions first.
463
+ * @param geo - Input
464
+ * @param type - GeomType
465
+ * @param digit - Rounding digits
466
+ * @returns Geometry or null
467
+ * @example toGeoJson([139.7,35.6], GeomType.point)
468
+ * @example toGeoJson([[139.7,35.6],[139.8,35.7]], GeomType.lineString)
469
+ * @example toGeoJson(
470
+ * [[[139.7,35.6],[139.8,35.6],[139.8,35.7],[139.7,35.7],[139.7,35.6]]],
471
+ * GeomType.polygon
472
+ * )
473
+ * @category Geo Utilities
474
+ */
475
+ const toGeoJson = (geo, type = GeomType.auto, digit) => {
476
+ if (_.isEmpty(geo)) {
477
+ return null;
478
+ }
479
+ if (typeof geo === "string") {
480
+ geo = _.parseJSON(geo);
481
+ }
482
+ switch (type) {
483
+ case GeomType.point:
484
+ return toPointGeoJson(geo, digit);
485
+ case GeomType.polygon:
486
+ return toPolygonGeoJson(geo, digit);
487
+ case GeomType.lineString:
488
+ return toLineStringGeoJson(geo, digit);
489
+ case GeomType.multiLineString:
490
+ return toMultiLineStringGeoJson(geo, digit);
491
+ case GeomType.multiPoint:
492
+ return toMultiPointGeoJson(geo, digit);
493
+ case GeomType.multiPolygon:
494
+ return toMultiPolygonGeoJson(geo, digit);
495
+ default:
496
+ break;
497
+ }
498
+ // auto: 次元の高い順に試す
499
+ return toMultiPolygonGeoJson(geo, digit)
500
+ ?? toMultiLineStringGeoJson(geo, digit)
501
+ ?? toPolygonGeoJson(geo, digit)
502
+ ?? toLineStringGeoJson(geo, digit)
503
+ ?? toMultiPointGeoJson(geo, digit)
504
+ ?? toPointGeoJson(geo, digit);
505
+ };
506
+ /**
507
+ * Converts inputs into a list of GeoJSON.Features suitable for TerraDraw.
508
+ * Multi-geometries are exploded into individual features and assigned UUIDs.
509
+ * @param geo - Geometry/Feature/FeatureCollection or nested arrays
510
+ * @returns Feature array (may be empty when input is invalid)
511
+ */
512
+ const parseToTerraDraw = (geo) => {
513
+ let feature = toGeoJson(geo, GeomType.auto);
514
+ if (_.isEmpty(feature) && Array.isArray(geo)) {
515
+ return geo.flatMap(parseToTerraDraw);
516
+ }
517
+ if (!feature)
518
+ return [];
519
+ const features = [];
520
+ const geom = feature.geometry; // 一度だけ
521
+ switch (geom.type) {
522
+ case "MultiPoint":
523
+ geom.coordinates.forEach((coord) => {
524
+ const f = turf.point(coord, { mode: "point" });
525
+ f.id = crypto.randomUUID();
526
+ features.push(f);
527
+ });
528
+ break;
529
+ case "MultiLineString":
530
+ geom.coordinates.forEach((coords) => {
531
+ const f = turf.lineString(coords, { mode: "linestring" });
532
+ f.id = crypto.randomUUID();
533
+ features.push(f);
534
+ });
535
+ break;
536
+ case "MultiPolygon":
537
+ geom.coordinates.forEach((coords) => {
538
+ const f = turf.polygon(coords, { mode: "polygon" });
539
+ f.id = crypto.randomUUID();
540
+ features.push(f);
541
+ });
542
+ break;
543
+ default:
544
+ const f = { ...feature };
545
+ f.id = crypto.randomUUID();
546
+ f.properties = {
547
+ ...f.properties,
548
+ mode: geom.type.toLowerCase()
549
+ };
550
+ features.push(f);
551
+ }
552
+ return features;
553
+ };
554
+ const a = ansuko;
555
+ a.toGeoJson = toGeoJson;
556
+ a.toPointGeoJson = toPointGeoJson;
557
+ a.toPolygonGeoJson = toPolygonGeoJson;
558
+ a.toLineStringGeoJson = toLineStringGeoJson;
559
+ a.toMultiPointGeoJson = toMultiPointGeoJson;
560
+ a.toMultiLineStringGeoJson = toMultiLineStringGeoJson;
561
+ a.toMultiPolygonGeoJson = toMultiPolygonGeoJson;
562
+ a.unionPolygon = unionPolygon;
563
+ a.parseToTerraDraw = parseToTerraDraw;
564
+ return ansuko;
565
+ };
566
+ export default ansukoGeoPlugin;
@@ -0,0 +1,13 @@
1
+ import { type AnsukoType } from "../index.js";
2
+ import { toHalfWidth, haifun } from "../util.js";
3
+ export interface AnsukoJaExtension {
4
+ kanaToFull: (str: unknown) => string | null;
5
+ kanaToHalf: (str: unknown) => string | null;
6
+ kanaToHira: (str: unknown) => string | null;
7
+ hiraToKana: (str: unknown) => string | null;
8
+ toHalfWidth: typeof toHalfWidth;
9
+ toFullWidth: (value: unknown, withHaifun?: string) => string | null;
10
+ haifun: typeof haifun;
11
+ }
12
+ declare const ansukoJaPlugin: <T extends AnsukoType>(ansuko: T) => T & AnsukoJaExtension;
13
+ export default ansukoJaPlugin;