wkt-parse-and-geojson 1.0.6 → 1.0.8

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/dist/index.cjs.js CHANGED
@@ -4,7 +4,6 @@ var types = /*#__PURE__*/Object.freeze({
4
4
  __proto__: null
5
5
  });
6
6
 
7
- // Precompiled regex for better performance
8
7
  const RE_WHITESPACE = /\s/;
9
8
  const RE_NUMBER_START = /[0-9\-]/;
10
9
  const RE_NUMBER_BODY = /[0-9\.\-eE\+]/;
@@ -30,7 +29,6 @@ class Lexer {
30
29
  return RE_NUMBER_BODY.test(c);
31
30
  }
32
31
  nextToken() {
33
- // skip whitespace
34
32
  while (this.pos < this.input.length && this.isWhitespace(this.peek())) {
35
33
  this.advance();
36
34
  }
@@ -50,7 +48,6 @@ class Lexer {
50
48
  this.advance();
51
49
  return { type: 'COMMA', value: ',' };
52
50
  }
53
- // Number: starts with digit or minus
54
51
  if (this.isNumberStart(c)) {
55
52
  const start = this.pos;
56
53
  while (this.pos < this.input.length && this.isNumberBody(this.peek())) {
@@ -58,7 +55,6 @@ class Lexer {
58
55
  }
59
56
  return { type: 'NUMBER', value: this.input.slice(start, this.pos) };
60
57
  }
61
- // Word (geometry type or EMPTY/Z/M keyword)
62
58
  const start = this.pos;
63
59
  while (this.pos < this.input.length && RE_WORD_CHAR.test(this.peek())) {
64
60
  this.pos++;
@@ -82,7 +78,6 @@ class WKTParser {
82
78
  }
83
79
  this.tokens.push({ type: 'EOF', value: '' });
84
80
  const geometry = this.parseGeometry();
85
- // 校验尾部无多余字符(防止静默忽略垃圾输入)
86
81
  if (this.peek().type !== 'EOF') {
87
82
  throw new Error(`Unexpected trailing token after geometry: "${this.peek().value}"`);
88
83
  }
@@ -94,7 +89,6 @@ class WKTParser {
94
89
  advance() {
95
90
  return this.tokens[this.pos++];
96
91
  }
97
- /** 消费当前 token 并返回,若类型不匹配则抛出错误 */
98
92
  consume(type) {
99
93
  const token = this.peek();
100
94
  if (token.type !== type) {
@@ -135,14 +129,12 @@ class WKTParser {
135
129
  throw new Error(`Unknown geometry type: ${token.value}`);
136
130
  }
137
131
  }
138
- // ── 消费可选的维度修饰符(Z / M / ZM)
139
132
  skipDimensionKeyword() {
140
133
  const t = this.peek();
141
134
  if (t.type === 'WORD' && (t.value === 'Z' || t.value === 'M' || t.value === 'ZM')) {
142
135
  this.advance();
143
136
  }
144
137
  }
145
- // ── 判断并消费 EMPTY 关键字
146
138
  isEmptyGeometry() {
147
139
  const t = this.peek();
148
140
  if (t.type === 'WORD' && t.value === 'EMPTY') {
@@ -151,13 +143,10 @@ class WKTParser {
151
143
  }
152
144
  return false;
153
145
  }
154
- // ── POINT ────────────────────────────────────────────────────────
155
146
  parsePoint() {
156
- this.advance(); // consume POINT
147
+ this.advance();
157
148
  this.skipDimensionKeyword();
158
149
  if (this.isEmptyGeometry()) {
159
- // GeoJSON 无法表示空点:POINT EMPTY 在 GeoJSON 中应用 null geometry Feature,
160
- // 此处直接抛出,由调用方决定如何处理。
161
150
  throw new Error('POINT EMPTY cannot be represented as a GeoJSON Point. ' +
162
151
  'Consider using wktToFeature() and checking Feature.geometry === null.');
163
152
  }
@@ -166,9 +155,8 @@ class WKTParser {
166
155
  this.consume('RPAREN');
167
156
  return { type: 'Point', coordinates: coords };
168
157
  }
169
- // ── LINESTRING ───────────────────────────────────────────────────
170
158
  parseLineString() {
171
- this.advance(); // consume LINESTRING
159
+ this.advance();
172
160
  this.skipDimensionKeyword();
173
161
  if (this.isEmptyGeometry()) {
174
162
  return { type: 'LineString', coordinates: [] };
@@ -176,9 +164,8 @@ class WKTParser {
176
164
  const coords = this.parseCoordinatesList();
177
165
  return { type: 'LineString', coordinates: coords };
178
166
  }
179
- // ── POLYGON ──────────────────────────────────────────────────────
180
167
  parsePolygon() {
181
- this.advance(); // consume POLYGON
168
+ this.advance();
182
169
  this.skipDimensionKeyword();
183
170
  if (this.isEmptyGeometry()) {
184
171
  return { type: 'Polygon', coordinates: [] };
@@ -192,24 +179,21 @@ class WKTParser {
192
179
  this.consume('RPAREN');
193
180
  return { type: 'Polygon', coordinates: rings };
194
181
  }
195
- // ── MULTIPOINT ───────────────────────────────────────────────────
196
182
  parseMultiPoint() {
197
- this.advance(); // consume MULTIPOINT
183
+ this.advance();
198
184
  this.skipDimensionKeyword();
199
185
  if (this.isEmptyGeometry() || this.peek().type !== 'LPAREN') {
200
186
  return { type: 'MultiPoint', coordinates: [] };
201
187
  }
202
- this.advance(); // consume outer (
188
+ this.advance();
203
189
  const coords = [];
204
190
  while (!this.isDone()) {
205
191
  if (this.peek().type === 'LPAREN') {
206
- // 标准写法: MULTIPOINT ((x y), (x y))
207
- this.advance(); // consume (
192
+ this.advance();
208
193
  coords.push(this.parseCoordinates());
209
194
  this.consume('RPAREN');
210
195
  }
211
196
  else {
212
- // 非标准写法: MULTIPOINT (x y, x y)
213
197
  coords.push(this.parseCoordinates());
214
198
  }
215
199
  this.skipComma();
@@ -217,14 +201,13 @@ class WKTParser {
217
201
  this.consume('RPAREN');
218
202
  return { type: 'MultiPoint', coordinates: coords };
219
203
  }
220
- // ── MULTILINESTRING ──────────────────────────────────────────────
221
204
  parseMultiLineString() {
222
- this.advance(); // consume MULTILINESTRING
205
+ this.advance();
223
206
  this.skipDimensionKeyword();
224
207
  if (this.isEmptyGeometry() || this.peek().type !== 'LPAREN') {
225
208
  return { type: 'MultiLineString', coordinates: [] };
226
209
  }
227
- this.advance(); // consume outer (
210
+ this.advance();
228
211
  const lines = [];
229
212
  while (!this.isDone()) {
230
213
  lines.push(this.parseCoordinatesList());
@@ -233,9 +216,8 @@ class WKTParser {
233
216
  this.consume('RPAREN');
234
217
  return { type: 'MultiLineString', coordinates: lines };
235
218
  }
236
- // ── MULTIPOLYGON ─────────────────────────────────────────────────
237
219
  parseMultiPolygon() {
238
- this.advance(); // consume MULTIPOLYGON
220
+ this.advance();
239
221
  this.skipDimensionKeyword();
240
222
  if (this.isEmptyGeometry()) {
241
223
  return { type: 'MultiPolygon', coordinates: [] };
@@ -249,14 +231,13 @@ class WKTParser {
249
231
  this.consume('RPAREN');
250
232
  return { type: 'MultiPolygon', coordinates: polys };
251
233
  }
252
- // ── GEOMETRYCOLLECTION ───────────────────────────────────────────
253
234
  parseGeometryCollection() {
254
- this.advance(); // consume GEOMETRYCOLLECTION
235
+ this.advance();
255
236
  this.skipDimensionKeyword();
256
237
  if (this.isEmptyGeometry() || this.peek().type !== 'LPAREN') {
257
238
  return { type: 'GeometryCollection', geometries: [] };
258
239
  }
259
- this.advance(); // consume (
240
+ this.advance();
260
241
  const geometries = [];
261
242
  while (!this.isDone()) {
262
243
  geometries.push(this.parseGeometry());
@@ -265,11 +246,6 @@ class WKTParser {
265
246
  this.consume('RPAREN');
266
247
  return { type: 'GeometryCollection', geometries };
267
248
  }
268
- // ── 坐标解析辅助方法 ──────────────────────────────────────────────
269
- /**
270
- * 读取一个坐标点(自动检测维度:X Y 或 X Y Z)
271
- * 读完 X、Y 后,若下一个 token 仍是 NUMBER,则继续读 Z
272
- */
273
249
  parseCoordinates() {
274
250
  const xStr = this.consume('NUMBER').value;
275
251
  const yStr = this.consume('NUMBER').value;
@@ -279,7 +255,6 @@ class WKTParser {
279
255
  throw new Error(`Invalid coordinate value: "${xStr}"`);
280
256
  if (isNaN(y))
281
257
  throw new Error(`Invalid coordinate value: "${yStr}"`);
282
- // 动态检测 Z 坐标
283
258
  if (this.peek().type === 'NUMBER') {
284
259
  const zStr = this.advance().value;
285
260
  const z = parseFloat(zStr);
@@ -289,7 +264,6 @@ class WKTParser {
289
264
  }
290
265
  return [x, y];
291
266
  }
292
- /** 解析带括号的坐标序列:( x y, x y, ... ) */
293
267
  parseCoordinatesList() {
294
268
  this.consume('LPAREN');
295
269
  const coords = [];
@@ -300,11 +274,10 @@ class WKTParser {
300
274
  this.consume('RPAREN');
301
275
  return coords;
302
276
  }
303
- /** 解析环列表(Polygon 级别):( (...), (...) ) */
304
277
  parseCoordinateListList() {
305
278
  if (this.peek().type !== 'LPAREN')
306
279
  return [];
307
- this.advance(); // consume outer (
280
+ this.advance();
308
281
  const lists = [];
309
282
  while (!this.isDone()) {
310
283
  lists.push(this.parseCoordinatesList());
@@ -314,11 +287,10 @@ class WKTParser {
314
287
  return lists;
315
288
  }
316
289
  }
317
- /** 将 WKT 字符串解析为 GeoJSON Geometry 对象 */
318
290
  function parse(wkt) {
319
- const parser = new WKTParser();
320
- return parser.parse(wkt);
291
+ return WKT_PARSER.parse(wkt);
321
292
  }
293
+ const WKT_PARSER = new WKTParser();
322
294
 
323
295
  var wktParser = /*#__PURE__*/Object.freeze({
324
296
  __proto__: null,
@@ -326,10 +298,6 @@ var wktParser = /*#__PURE__*/Object.freeze({
326
298
  parse: parse
327
299
  });
328
300
 
329
- /**
330
- * 将坐标数值格式化为字符串,避免科学计数法(WKT 不支持)。
331
- * 例:1e-7 → "0.0000001",1.50000 → "1.5",1.0 → "1"
332
- */
333
301
  function formatNumber(v) {
334
302
  if (v % 1 !== 0) {
335
303
  return Number(v.toFixed(15)).toString();
@@ -342,25 +310,24 @@ function positionToWkt(pos) {
342
310
  function coordsToWkt(coords) {
343
311
  return coords.map(positionToWkt).join(', ');
344
312
  }
345
- // 检查坐标是否包含 Z(3个分量)
346
313
  function hasZ(coordinates) {
347
314
  if (!Array.isArray(coordinates))
348
315
  return false;
349
316
  if (coordinates.length === 0)
350
317
  return false;
351
318
  const first = coordinates[0];
352
- if (Array.isArray(first)) {
353
- if (typeof first[0] === 'number') {
354
- return first.length === 3;
355
- }
356
- if (Array.isArray(first[0])) {
357
- const firstRing = first;
358
- return firstRing.length > 0 && firstRing[0].length === 3;
359
- }
319
+ if (typeof first === 'number') {
320
+ return coordinates.length === 3;
321
+ }
322
+ if (Array.isArray(first) && typeof first[0] === 'number') {
323
+ return first.length === 3;
324
+ }
325
+ if (Array.isArray(first) && Array.isArray(first[0])) {
326
+ const firstRing = first;
327
+ return firstRing.length > 0 && firstRing[0].length === 3;
360
328
  }
361
329
  return false;
362
330
  }
363
- // 获取 Z 后缀字符串
364
331
  function zSuffix(coordinates) {
365
332
  return hasZ(coordinates) ? ' Z' : '';
366
333
  }
@@ -399,10 +366,6 @@ class WKTBuilder {
399
366
  const ringStr = geom.coordinates.map(ring => `(${coordsToWkt(ring)})`).join(', ');
400
367
  return `POLYGON${zSuffix(geom.coordinates)} (${ringStr})`;
401
368
  }
402
- /**
403
- * 按 OGC/ISO WKT 标准,MULTIPOINT 每个点用括号包裹:
404
- * MULTIPOINT ((0 0), (1 1), (2 2))
405
- */
406
369
  buildMultiPoint(geom) {
407
370
  if (geom.coordinates.length === 0)
408
371
  return 'MULTIPOINT EMPTY';
@@ -431,11 +394,9 @@ class WKTBuilder {
431
394
  return `GEOMETRYCOLLECTION (${geoms})`;
432
395
  }
433
396
  }
434
- /** 将 GeoJSON Geometry 对象转换为 WKT 字符串 */
435
397
  function build(geometry) {
436
398
  return WKT_BUILDER.build(geometry);
437
399
  }
438
- // 单例实例,避免重复创建
439
400
  const WKT_BUILDER = new WKTBuilder();
440
401
 
441
402
  var wktBuilder = /*#__PURE__*/Object.freeze({
@@ -444,15 +405,11 @@ var wktBuilder = /*#__PURE__*/Object.freeze({
444
405
  build: build
445
406
  });
446
407
 
447
- // ─── 内部工具:判断是否为 Position([number, number] 或 [number, number, number])
448
408
  function isPosition(v) {
449
409
  return (Array.isArray(v) &&
450
410
  (v.length === 2 || v.length === 3) &&
451
411
  v.every((n) => typeof n === 'number'));
452
412
  }
453
- /**
454
- * GeoJSON 几何对象构建器(类形式,方便组合使用)
455
- */
456
413
  class GeoJSONBuilder {
457
414
  createPoint(x, y, z) {
458
415
  return z !== undefined
@@ -462,130 +419,56 @@ class GeoJSONBuilder {
462
419
  createLineString(coordinates) {
463
420
  return { type: 'LineString', coordinates };
464
421
  }
465
- /**
466
- * 创建 Polygon。
467
- * - 传入 `Position[]`:视为单个外环,自动包装为 `[ring]`
468
- * - 传入 `Position[][]`:视为完整的环列表(外环 + 内环/空洞)
469
- */
470
422
  createPolygon(coordinates) {
471
423
  const rings = isPosition(coordinates[0])
472
- ? [coordinates] // 单环:Position[] → Position[][]
473
- : coordinates; // 多环:已是 Position[][]
424
+ ? [coordinates]
425
+ : coordinates;
474
426
  return { type: 'Polygon', coordinates: rings };
475
427
  }
476
- /**
477
- * 创建 MultiPoint。
478
- * - 传入 `Position`:视为单个点,自动包装为 `[point]`
479
- * - 传入 `Position[]`:视为多个点
480
- */
481
428
  createMultiPoint(coordinates) {
482
429
  const pts = isPosition(coordinates)
483
- ? [coordinates] // 单点:Position → Position[]
484
- : coordinates; // 多点:已是 Position[]
430
+ ? [coordinates]
431
+ : coordinates;
485
432
  return { type: 'MultiPoint', coordinates: pts };
486
433
  }
487
- /**
488
- * 创建 MultiLineString。
489
- * - 传入 `Position[]`:视为单条线,自动包装为 `[line]`
490
- * - 传入 `Position[][]`:视为多条线
491
- */
492
434
  createMultiLineString(coordinates) {
493
435
  const lines = isPosition(coordinates[0])
494
- ? [coordinates] // 单线:Position[] → Position[][]
495
- : coordinates; // 多线:已是 Position[][]
436
+ ? [coordinates]
437
+ : coordinates;
496
438
  return { type: 'MultiLineString', coordinates: lines };
497
439
  }
498
- /**
499
- * 创建 MultiPolygon。
500
- * - 传入 `Position[][]`:视为单个多边形(环列表),自动包装为 `[polygon]`
501
- * - 传入 `Position[][][]`:视为多个多边形
502
- */
503
440
  createMultiPolygon(coordinates) {
504
- // 判断:若第一个元素是 Position[](环),则整体是单个 polygon
505
441
  const firstElem = coordinates[0];
506
442
  const isSinglePolygon = Array.isArray(firstElem) && Array.isArray(firstElem[0]) && isPosition(firstElem[0]);
507
443
  const polys = isSinglePolygon
508
- ? [coordinates] // 单多边形:Position[][] → Position[][][]
509
- : coordinates; // 多多边形:已是 Position[][][]
444
+ ? [coordinates]
445
+ : coordinates;
510
446
  return { type: 'MultiPolygon', coordinates: polys };
511
447
  }
512
- /**
513
- * 创建 GeometryCollection。
514
- * - 传入单个 `Geometry`:自动包装为 `[geometry]`
515
- * - 传入 `Geometry[]`:直接使用
516
- */
517
448
  createGeometryCollection(geometries) {
518
449
  const geoms = Array.isArray(geometries) ? geometries : [geometries];
519
450
  return { type: 'GeometryCollection', geometries: geoms };
520
451
  }
521
452
  }
522
- // 单例,避免重复实例化
523
453
  const _builder = new GeoJSONBuilder();
524
- /** 创建 Point */
525
454
  function createPoint(x, y, z) {
526
455
  return _builder.createPoint(x, y, z);
527
456
  }
528
- /** 创建 LineString */
529
457
  function createLineString(coordinates) {
530
458
  return _builder.createLineString(coordinates);
531
459
  }
532
- /**
533
- * 创建 Polygon。
534
- * - 传入 `Position[]`:单个外环,自动包装
535
- * - 传入 `Position[][]`:外环 + 内环(空洞)
536
- *
537
- * @example
538
- * createPolygon([[0,0],[1,0],[1,1],[0,1],[0,0]])
539
- * createPolygon([[[0,0],[10,0],[10,10],[0,10],[0,0]], [[2,2],[4,2],[4,4],[2,4],[2,2]]])
540
- */
541
460
  function createPolygon(coordinates) {
542
461
  return _builder.createPolygon(coordinates);
543
462
  }
544
- /**
545
- * 创建 MultiPoint。
546
- * - 传入 `Position`:单个点
547
- * - 传入 `Position[]`:多个点
548
- *
549
- * @example
550
- * createMultiPoint([0, 0])
551
- * createMultiPoint([[0,0],[1,1],[2,2]])
552
- */
553
463
  function createMultiPoint(coordinates) {
554
464
  return _builder.createMultiPoint(coordinates);
555
465
  }
556
- /**
557
- * 创建 MultiLineString。
558
- * - 传入 `Position[]`:单条线
559
- * - 传入 `Position[][]`:多条线
560
- *
561
- * @example
562
- * createMultiLineString([[0,0],[1,1]])
563
- * createMultiLineString([[[0,0],[1,1]], [[2,2],[3,3]]])
564
- */
565
466
  function createMultiLineString(coordinates) {
566
467
  return _builder.createMultiLineString(coordinates);
567
468
  }
568
- /**
569
- * 创建 MultiPolygon。
570
- * - 传入 `Position[][]`:单个多边形(环列表)
571
- * - 传入 `Position[][][]`:多个多边形
572
- *
573
- * @example
574
- * createMultiPolygon([[[0,0],[1,0],[1,1],[0,1],[0,0]]])
575
- * createMultiPolygon([[[[0,0],[1,0],[1,1],[0,1],[0,0]]], [[[2,2],[3,2],[3,3],[2,3],[2,2]]]])
576
- */
577
469
  function createMultiPolygon(coordinates) {
578
470
  return _builder.createMultiPolygon(coordinates);
579
471
  }
580
- /**
581
- * 创建 GeometryCollection。
582
- * - 传入单个 `Geometry`:自动包装
583
- * - 传入 `Geometry[]`:直接使用
584
- *
585
- * @example
586
- * createGeometryCollection(createPoint(0, 0))
587
- * createGeometryCollection([createPoint(0,0), createLineString([[0,0],[1,1]])])
588
- */
589
472
  function createGeometryCollection(geometries) {
590
473
  return _builder.createGeometryCollection(geometries);
591
474
  }
@@ -602,30 +485,9 @@ var geojsonBuilder = /*#__PURE__*/Object.freeze({
602
485
  createPolygon: createPolygon
603
486
  });
604
487
 
605
- /**
606
- * 将 WKT 字符串转换为 GeoJSON Geometry 对象。
607
- *
608
- * @example
609
- * wktToGeoJSON('POINT (30.5 40.5)')
610
- * // → { type: 'Point', coordinates: [30.5, 40.5] }
611
- *
612
- * wktToGeoJSON('POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))')
613
- * // → { type: 'Polygon', coordinates: [[[0,0],[1,0],[1,1],[0,1],[0,0]]] }
614
- */
615
488
  function wktToGeoJSON(wkt) {
616
489
  return parse(wkt);
617
490
  }
618
- /**
619
- * 将 WKT 字符串转换为 GeoJSON Feature 对象。
620
- *
621
- * @param wkt WKT 字符串
622
- * @param properties 可选的 Feature 属性对象
623
- * @param id 可选的 Feature ID
624
- *
625
- * @example
626
- * wktToFeature('POINT (30.5 40.5)', { name: '北京' })
627
- * // → { type: 'Feature', geometry: { type: 'Point', ... }, properties: { name: '北京' } }
628
- */
629
491
  function wktToFeature(wkt, properties = null, id) {
630
492
  const geometry = parse(wkt);
631
493
  const feature = {
@@ -638,16 +500,6 @@ function wktToFeature(wkt, properties = null, id) {
638
500
  }
639
501
  return feature;
640
502
  }
641
- /**
642
- * 将多个 WKT 字符串批量转换为 GeoJSON FeatureCollection。
643
- *
644
- * @param wkts WKT 字符串数组
645
- * @param properties 可选,每个 Feature 的属性数组(长度应与 wkts 一致)
646
- *
647
- * @example
648
- * wktToFeatureCollection(['POINT (0 0)', 'POINT (1 1)'])
649
- * // → { type: 'FeatureCollection', features: [...] }
650
- */
651
503
  function wktToFeatureCollection(wkts, properties) {
652
504
  const features = wkts.map((wkt, i) => wktToFeature(wkt, properties ? (properties[i] ?? null) : null));
653
505
  return { type: 'FeatureCollection', features };
@@ -660,43 +512,15 @@ var wktToGeojson = /*#__PURE__*/Object.freeze({
660
512
  wktToGeoJSON: wktToGeoJSON
661
513
  });
662
514
 
663
- /**
664
- * 将 GeoJSON Geometry 对象转换为 WKT 字符串。
665
- *
666
- * @example
667
- * geojsonToWkt({ type: 'Point', coordinates: [30.5, 40.5] })
668
- * // → 'POINT (30.5 40.5)'
669
- *
670
- * geojsonToWkt({ type: 'Polygon', coordinates: [[[0,0],[1,0],[1,1],[0,1],[0,0]]] })
671
- * // → 'POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))'
672
- */
673
515
  function geojsonToWkt(geojson) {
674
516
  return build(geojson);
675
517
  }
676
- /**
677
- * 将 GeoJSON Feature 对象转换为 WKT 字符串(取 geometry 部分)。
678
- *
679
- * @throws 若 Feature.geometry 为 null,则抛出错误
680
- *
681
- * @example
682
- * featureToWkt({ type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: null })
683
- * // → 'POINT (0 0)'
684
- */
685
518
  function featureToWkt(feature) {
686
519
  if (!feature.geometry) {
687
520
  throw new Error('Feature.geometry is null, cannot convert to WKT');
688
521
  }
689
522
  return build(feature.geometry);
690
523
  }
691
- /**
692
- * 将 GeoJSON FeatureCollection 中所有 Feature 转换为 WKT 字符串数组。
693
- *
694
- * geometry 为 null 的 Feature 会被跳过(返回数组中对应位置为 null)。
695
- *
696
- * @example
697
- * featureCollectionToWkt({ type: 'FeatureCollection', features: [...] })
698
- * // → ['POINT (0 0)', 'LINESTRING (0 0, 1 1)', ...]
699
- */
700
524
  function featureCollectionToWkt(fc) {
701
525
  return fc.features.map((f) => {
702
526
  if (!f.geometry)
@@ -712,15 +536,12 @@ var geojsonToWkt$1 = /*#__PURE__*/Object.freeze({
712
536
  geojsonToWkt: geojsonToWkt
713
537
  });
714
538
 
715
- // 预定义常量,避免重复创建
716
539
  const VALID_GEOMETRY_TYPES = [
717
540
  'Point', 'LineString', 'Polygon',
718
541
  'MultiPoint', 'MultiLineString', 'MultiPolygon',
719
542
  'GeometryCollection'
720
543
  ];
721
- /**
722
- * 校验 WKT 字符串格式是否合法
723
- */
544
+ const VALID_TYPES_MESSAGE = `Invalid geometry type. Must be one of: ${VALID_GEOMETRY_TYPES.join(', ')}`;
724
545
  function validateWKT(wkt) {
725
546
  if (!wkt || typeof wkt !== 'string') {
726
547
  return { valid: false, error: 'WKT must be a non-empty string' };
@@ -737,23 +558,18 @@ function validateWKT(wkt) {
737
558
  return { valid: false, error: e.message };
738
559
  }
739
560
  }
740
- /**
741
- * 校验 GeoJSON Geometry 对象是否合法
742
- */
743
561
  function validateGeoJSON(geojson) {
744
562
  if (!geojson || typeof geojson !== 'object') {
745
563
  return { valid: false, error: 'GeoJSON must be an object' };
746
564
  }
747
565
  const obj = geojson;
748
- // 检查 type 字段
749
566
  if (!obj.type || typeof obj.type !== 'string') {
750
567
  return { valid: false, error: 'GeoJSON must have a "type" property' };
751
568
  }
752
569
  const type = obj.type;
753
570
  if (!VALID_GEOMETRY_TYPES.includes(type)) {
754
- return { valid: false, error: `Invalid geometry type: "${type}". Must be one of: ${VALID_GEOMETRY_TYPES.join(', ')}` };
571
+ return { valid: false, error: VALID_TYPES_MESSAGE };
755
572
  }
756
- // GeometryCollection 特殊处理
757
573
  if (type === 'GeometryCollection') {
758
574
  if (!obj.geometries || !Array.isArray(obj.geometries)) {
759
575
  return { valid: false, error: 'GeometryCollection must have a "geometries" array' };
@@ -766,11 +582,9 @@ function validateGeoJSON(geojson) {
766
582
  }
767
583
  return { valid: true };
768
584
  }
769
- // 其他几何类型必须要有 coordinates
770
585
  if (obj.coordinates === undefined) {
771
586
  return { valid: false, error: `${type} must have "coordinates"` };
772
587
  }
773
- // 校验坐标格式
774
588
  return validateCoordinates(type, obj.coordinates);
775
589
  }
776
590
  function validateCoordinates(type, coords) {
@@ -839,34 +653,27 @@ function validatePosition(pos) {
839
653
  return { valid: false, error: `Position must have 2 or 3 coordinates, got ${pos.length}` };
840
654
  }
841
655
  for (let i = 0; i < pos.length; i++) {
842
- if (typeof pos[i] !== 'number' || isNaN(pos[i])) {
656
+ if (typeof pos[i] !== 'number' || !Number.isFinite(pos[i])) {
843
657
  return { valid: false, error: `Position[${i}] must be a valid number` };
844
658
  }
845
659
  }
846
660
  return { valid: true };
847
661
  }
848
- /**
849
- * 尝试从可能不规范的 WKT 中恢复出有效结果
850
- * 主要处理尾部多余字符的情况
851
- */
852
662
  function tryFixWKT(wkt) {
853
663
  const trimmed = wkt.trim();
854
664
  if (!trimmed) {
855
665
  return { fixed: wkt, changed: false };
856
666
  }
857
- // 先尝试直接解析,如果成功则不需要修复
858
667
  try {
859
668
  parse(trimmed);
860
669
  return { fixed: trimmed, changed: false };
861
670
  }
862
671
  catch {
863
- // 解析失败,尝试修复
864
672
  }
865
- // 尝试找到最后一个有效的 geometry 结束位置
866
673
  const patterns = [
867
- /\)\s*[A-Z]/i, // 括号后跟字母 (如 POLYGON ((...)) POINT )
868
- /EMPTY\s+[A-Z]/i, // EMPTY 后跟字母
869
- /\)\s*$/, // 括号结尾后有多余内容
674
+ /\)\s*[A-Z]/i,
675
+ /EMPTY\s+[A-Z]/i,
676
+ /\)\s*$/,
870
677
  ];
871
678
  for (const pattern of patterns) {
872
679
  const match = trimmed.match(pattern);
@@ -877,11 +684,9 @@ function tryFixWKT(wkt) {
877
684
  return { fixed, changed: true };
878
685
  }
879
686
  catch {
880
- // 这个修复方案不行,尝试下一个
881
687
  }
882
688
  }
883
689
  }
884
- // 尝试去除尾部垃圾字符
885
690
  const lastValidIndex = findLastValidPosition(trimmed);
886
691
  if (lastValidIndex > 0) {
887
692
  const fixed = trimmed.slice(0, lastValidIndex + 1);
@@ -890,7 +695,6 @@ function tryFixWKT(wkt) {
890
695
  return { fixed, changed: true };
891
696
  }
892
697
  catch {
893
- // 修复失败
894
698
  }
895
699
  }
896
700
  return { fixed: wkt, changed: false };
@@ -904,7 +708,6 @@ function findLastValidPosition(wkt) {
904
708
  else if (c === '(')
905
709
  depth--;
906
710
  else if (c === ' ' && depth === 0 && /[A-Z]/.test(wkt.slice(i + 1))) {
907
- // 如果空格后面是字母开头,可能是垃圾字符的起点
908
711
  if (wkt.slice(0, i).trimEnd().match(/[A-Z]\s*$/)) {
909
712
  return i - 1;
910
713
  }
@@ -912,19 +715,12 @@ function findLastValidPosition(wkt) {
912
715
  }
913
716
  return wkt.length - 1;
914
717
  }
915
- /**
916
- * 深度克隆 GeoJSON 对象(用于避免意外修改原对象)
917
- */
918
718
  function cloneGeometry(geometry) {
919
719
  return JSON.parse(JSON.stringify(geometry));
920
720
  }
921
- /**
922
- * 判断两个几何对象是否相等(坐标对比)
923
- */
924
721
  function geometryEquals(a, b) {
925
722
  if (a.type !== b.type)
926
723
  return false;
927
- // Point 比较最常见,单独优化
928
724
  if (a.type === 'Point') {
929
725
  const aCoords = a.coordinates;
930
726
  const bCoords = b.coordinates;
@@ -933,7 +729,6 @@ function geometryEquals(a, b) {
933
729
  aCoords[1] === bCoords[1] &&
934
730
  (aCoords.length === 2 || aCoords[2] === bCoords[2]);
935
731
  }
936
- // 其他类型使用 JSON.stringify 比较
937
732
  return JSON.stringify(a) === JSON.stringify(b);
938
733
  }
939
734
 
@@ -946,9 +741,6 @@ var validate = /*#__PURE__*/Object.freeze({
946
741
  validateWKT: validateWKT
947
742
  });
948
743
 
949
- // 命名空间导出 - 所有公共 API 汇总
950
- // 使用方式: import WKT from 'wkt-parse-and-geojson';
951
- // WKT.parse(...), WKT.build(...), etc.
952
744
  const WKT = {
953
745
  ...types,
954
746
  ...wktParser,