wkt-parse-and-geojson 1.0.4 → 1.0.5

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.md CHANGED
@@ -83,8 +83,12 @@ npm install wkt-parse-and-geojson
83
83
  // CommonJS
84
84
  const { parse, build, wktToFeature } = require('wkt-parse-and-geojson');
85
85
 
86
- // ES Module
86
+ // ES Module - 按需导入
87
87
  import { parse, build, wktToFeature } from 'wkt-parse-and-geojson';
88
+
89
+ // ES Module - 命名空间导入(避免命名冲突)
90
+ import WKT from 'wkt-parse-and-geojson';
91
+ const geom = WKT.parse('POINT (116.39 39.91)');
88
92
  ```
89
93
 
90
94
  ### 浏览器 (script 标签)
@@ -93,13 +97,13 @@ import { parse, build, wktToFeature } from 'wkt-parse-and-geojson';
93
97
  <!-- UMD 方式:通过 script 标签直接引入,全局变量 WKTGeoJSON -->
94
98
  <script src="https://unpkg.com/wkt-parse-and-geojson/dist/index.umd.js"></script>
95
99
  <script>
100
+ // 方式一:使用命名空间(推荐,避免命名冲突)
96
101
  const geom = WKTGeoJSON.parse('POINT (116.39 39.91)');
97
102
  console.log(geom);
98
- // → { type: 'Point', coordinates: [116.39, 39.91] }
99
103
 
100
- const wkt = WKTGeoJSON.build(geom);
101
- console.log(wkt);
102
- // "POINT (116.39 39.91)"
104
+ // 方式二:解构赋值(需注意命名冲突)
105
+ const { parse, build } = WKTGeoJSON;
106
+ const wkt = build(geom);
103
107
  </script>
104
108
  ```
105
109
 
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var types = /*#__PURE__*/Object.freeze({
4
+ __proto__: null
5
+ });
6
+
3
7
  // Precompiled regex for better performance
4
8
  const RE_WHITESPACE = /\s/;
5
9
  const RE_NUMBER_START = /[0-9\-]/;
@@ -316,16 +320,21 @@ function parse(wkt) {
316
320
  return parser.parse(wkt);
317
321
  }
318
322
 
323
+ var wktParser = /*#__PURE__*/Object.freeze({
324
+ __proto__: null,
325
+ WKTParser: WKTParser,
326
+ parse: parse
327
+ });
328
+
319
329
  /**
320
330
  * 将坐标数值格式化为字符串,避免科学计数法(WKT 不支持)。
321
331
  * 例:1e-7 → "0.0000001",1.50000 → "1.5",1.0 → "1"
322
332
  */
323
333
  function formatNumber(v) {
324
- // 有小数则最多保留 15 位有效位,再去掉尾零
325
334
  if (v % 1 !== 0) {
326
- return parseFloat(v.toFixed(15)).toString();
335
+ return Number(v.toFixed(15)).toString();
327
336
  }
328
- return v.toFixed(0);
337
+ return String(v);
329
338
  }
330
339
  function positionToWkt(pos) {
331
340
  return pos.map(formatNumber).join(' ');
@@ -333,6 +342,28 @@ function positionToWkt(pos) {
333
342
  function coordsToWkt(coords) {
334
343
  return coords.map(positionToWkt).join(', ');
335
344
  }
345
+ // 检查坐标是否包含 Z(3个分量)
346
+ function hasZ(coordinates) {
347
+ if (!Array.isArray(coordinates))
348
+ return false;
349
+ if (coordinates.length === 0)
350
+ return false;
351
+ 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
+ }
360
+ }
361
+ return false;
362
+ }
363
+ // 获取 Z 后缀字符串
364
+ function zSuffix(coordinates) {
365
+ return hasZ(coordinates) ? ' Z' : '';
366
+ }
336
367
  class WKTBuilder {
337
368
  build(geometry) {
338
369
  switch (geometry.type) {
@@ -355,21 +386,18 @@ class WKTBuilder {
355
386
  }
356
387
  }
357
388
  buildPoint(geom) {
358
- const hasZ = geom.coordinates.length === 3;
359
- return `POINT${hasZ ? ' Z' : ''} (${positionToWkt(geom.coordinates)})`;
389
+ return `POINT${zSuffix(geom.coordinates)} (${positionToWkt(geom.coordinates)})`;
360
390
  }
361
391
  buildLineString(geom) {
362
392
  if (geom.coordinates.length === 0)
363
393
  return 'LINESTRING EMPTY';
364
- const hasZ = geom.coordinates[0].length === 3;
365
- return `LINESTRING${hasZ ? ' Z' : ''} (${coordsToWkt(geom.coordinates)})`;
394
+ return `LINESTRING${zSuffix(geom.coordinates)} (${coordsToWkt(geom.coordinates)})`;
366
395
  }
367
396
  buildPolygon(geom) {
368
397
  if (geom.coordinates.length === 0)
369
398
  return 'POLYGON EMPTY';
370
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
371
399
  const ringStr = geom.coordinates.map(ring => `(${coordsToWkt(ring)})`).join(', ');
372
- return `POLYGON${hasZ ? ' Z' : ''} (${ringStr})`;
400
+ return `POLYGON${zSuffix(geom.coordinates)} (${ringStr})`;
373
401
  }
374
402
  /**
375
403
  * 按 OGC/ISO WKT 标准,MULTIPOINT 每个点用括号包裹:
@@ -378,26 +406,23 @@ class WKTBuilder {
378
406
  buildMultiPoint(geom) {
379
407
  if (geom.coordinates.length === 0)
380
408
  return 'MULTIPOINT EMPTY';
381
- const hasZ = geom.coordinates[0].length === 3;
382
409
  const pts = geom.coordinates.map(p => `(${positionToWkt(p)})`).join(', ');
383
- return `MULTIPOINT${hasZ ? ' Z' : ''} (${pts})`;
410
+ return `MULTIPOINT${zSuffix(geom.coordinates)} (${pts})`;
384
411
  }
385
412
  buildMultiLineString(geom) {
386
413
  if (geom.coordinates.length === 0)
387
414
  return 'MULTILINESTRING EMPTY';
388
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
389
415
  const lines = geom.coordinates.map(line => `(${coordsToWkt(line)})`).join(', ');
390
- return `MULTILINESTRING${hasZ ? ' Z' : ''} (${lines})`;
416
+ return `MULTILINESTRING${zSuffix(geom.coordinates)} (${lines})`;
391
417
  }
392
418
  buildMultiPolygon(geom) {
393
419
  if (geom.coordinates.length === 0)
394
420
  return 'MULTIPOLYGON EMPTY';
395
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length > 0 && geom.coordinates[0][0][0].length === 3;
396
421
  const polys = geom.coordinates.map(poly => {
397
422
  const rings = poly.map(ring => `(${coordsToWkt(ring)})`).join(', ');
398
423
  return `(${rings})`;
399
424
  }).join(', ');
400
- return `MULTIPOLYGON${hasZ ? ' Z' : ''} (${polys})`;
425
+ return `MULTIPOLYGON${zSuffix(geom.coordinates)} (${polys})`;
401
426
  }
402
427
  buildGeometryCollection(geom) {
403
428
  if (geom.geometries.length === 0)
@@ -411,6 +436,12 @@ function build(geometry) {
411
436
  return new WKTBuilder().build(geometry);
412
437
  }
413
438
 
439
+ var wktBuilder = /*#__PURE__*/Object.freeze({
440
+ __proto__: null,
441
+ WKTBuilder: WKTBuilder,
442
+ build: build
443
+ });
444
+
414
445
  // ─── 内部工具:判断是否为 Position([number, number] 或 [number, number, number])
415
446
  function isPosition(v) {
416
447
  return (Array.isArray(v) &&
@@ -557,6 +588,18 @@ function createGeometryCollection(geometries) {
557
588
  return _builder.createGeometryCollection(geometries);
558
589
  }
559
590
 
591
+ var geojsonBuilder = /*#__PURE__*/Object.freeze({
592
+ __proto__: null,
593
+ GeoJSONBuilder: GeoJSONBuilder,
594
+ createGeometryCollection: createGeometryCollection,
595
+ createLineString: createLineString,
596
+ createMultiLineString: createMultiLineString,
597
+ createMultiPoint: createMultiPoint,
598
+ createMultiPolygon: createMultiPolygon,
599
+ createPoint: createPoint,
600
+ createPolygon: createPolygon
601
+ });
602
+
560
603
  /**
561
604
  * 将 WKT 字符串转换为 GeoJSON Geometry 对象。
562
605
  *
@@ -608,6 +651,13 @@ function wktToFeatureCollection(wkts, properties) {
608
651
  return { type: 'FeatureCollection', features };
609
652
  }
610
653
 
654
+ var wktToGeojson = /*#__PURE__*/Object.freeze({
655
+ __proto__: null,
656
+ wktToFeature: wktToFeature,
657
+ wktToFeatureCollection: wktToFeatureCollection,
658
+ wktToGeoJSON: wktToGeoJSON
659
+ });
660
+
611
661
  /**
612
662
  * 将 GeoJSON Geometry 对象转换为 WKT 字符串。
613
663
  *
@@ -653,6 +703,13 @@ function featureCollectionToWkt(fc) {
653
703
  });
654
704
  }
655
705
 
706
+ var geojsonToWkt$1 = /*#__PURE__*/Object.freeze({
707
+ __proto__: null,
708
+ featureCollectionToWkt: featureCollectionToWkt,
709
+ featureToWkt: featureToWkt,
710
+ geojsonToWkt: geojsonToWkt
711
+ });
712
+
656
713
  /**
657
714
  * 校验 WKT 字符串格式是否合法
658
715
  */
@@ -794,11 +851,14 @@ function tryFixWKT(wkt) {
794
851
  if (!trimmed) {
795
852
  return { fixed: wkt, changed: false };
796
853
  }
797
- // 检查是否有尾部多余字符
798
- const result = validateWKT(trimmed);
799
- if (result.valid) {
854
+ // 先尝试直接解析,如果成功则不需要修复
855
+ try {
856
+ parse(trimmed);
800
857
  return { fixed: trimmed, changed: false };
801
858
  }
859
+ catch {
860
+ // 解析失败,尝试修复
861
+ }
802
862
  // 尝试找到最后一个有效的 geometry 结束位置
803
863
  const patterns = [
804
864
  /\)\s*[A-Z]/i, // 括号后跟字母 (如 POLYGON ((...)) POINT )
@@ -809,18 +869,26 @@ function tryFixWKT(wkt) {
809
869
  const match = trimmed.match(pattern);
810
870
  if (match) {
811
871
  const fixed = trimmed.slice(0, match.index + (match[0].match(/\)/)?.[0].length || 0));
812
- if (validateWKT(fixed).valid) {
872
+ try {
873
+ parse(fixed);
813
874
  return { fixed, changed: true };
814
875
  }
876
+ catch {
877
+ // 这个修复方案不行,尝试下一个
878
+ }
815
879
  }
816
880
  }
817
881
  // 尝试去除尾部垃圾字符
818
882
  const lastValidIndex = findLastValidPosition(trimmed);
819
883
  if (lastValidIndex > 0) {
820
884
  const fixed = trimmed.slice(0, lastValidIndex + 1);
821
- if (validateWKT(fixed).valid) {
885
+ try {
886
+ parse(fixed);
822
887
  return { fixed, changed: true };
823
888
  }
889
+ catch {
890
+ // 修复失败
891
+ }
824
892
  }
825
893
  return { fixed: wkt, changed: false };
826
894
  }
@@ -860,10 +928,43 @@ function cloneGeometry(geometry) {
860
928
  function geometryEquals(a, b) {
861
929
  if (a.type !== b.type)
862
930
  return false;
931
+ // Point 比较最常见,单独优化
932
+ if (a.type === 'Point') {
933
+ const aCoords = a.coordinates;
934
+ const bCoords = b.coordinates;
935
+ return aCoords.length === bCoords.length &&
936
+ aCoords[0] === bCoords[0] &&
937
+ aCoords[1] === bCoords[1] &&
938
+ (aCoords.length === 2 || aCoords[2] === bCoords[2]);
939
+ }
940
+ // 其他类型使用 JSON.stringify(缓存 key 优化可后续添加)
863
941
  return JSON.stringify(a) === JSON.stringify(b);
864
942
  }
865
943
 
944
+ var validate = /*#__PURE__*/Object.freeze({
945
+ __proto__: null,
946
+ cloneGeometry: cloneGeometry,
947
+ geometryEquals: geometryEquals,
948
+ tryFixWKT: tryFixWKT,
949
+ validateGeoJSON: validateGeoJSON,
950
+ validateWKT: validateWKT
951
+ });
952
+
953
+ // 命名空间导出 - 所有公共 API 汇总
954
+ // 使用方式: import WKT from 'wkt-parse-and-geojson';
955
+ // WKT.parse(...), WKT.build(...), etc.
956
+ const WKT = {
957
+ ...types,
958
+ ...wktParser,
959
+ ...wktBuilder,
960
+ ...geojsonBuilder,
961
+ ...wktToGeojson,
962
+ ...geojsonToWkt$1,
963
+ ...validate,
964
+ };
965
+
866
966
  exports.GeoJSONBuilder = GeoJSONBuilder;
967
+ exports.WKT = WKT;
867
968
  exports.WKTBuilder = WKTBuilder;
868
969
  exports.WKTParser = WKTParser;
869
970
  exports.build = build;
package/dist/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export { createPoint, createLineString, createPolygon, createMultiPoint, createM
5
5
  export { wktToGeoJSON, wktToFeature, wktToFeatureCollection } from './wkt-to-geojson';
6
6
  export { geojsonToWkt, featureToWkt, featureCollectionToWkt } from './geojson-to-wkt';
7
7
  export { validateWKT, validateGeoJSON, tryFixWKT, cloneGeometry, geometryEquals, type ValidationResult, } from './validate';
8
+ export { default as WKT } from './namespace';
package/dist/index.esm.js CHANGED
@@ -1,3 +1,7 @@
1
+ var types = /*#__PURE__*/Object.freeze({
2
+ __proto__: null
3
+ });
4
+
1
5
  // Precompiled regex for better performance
2
6
  const RE_WHITESPACE = /\s/;
3
7
  const RE_NUMBER_START = /[0-9\-]/;
@@ -314,16 +318,21 @@ function parse(wkt) {
314
318
  return parser.parse(wkt);
315
319
  }
316
320
 
321
+ var wktParser = /*#__PURE__*/Object.freeze({
322
+ __proto__: null,
323
+ WKTParser: WKTParser,
324
+ parse: parse
325
+ });
326
+
317
327
  /**
318
328
  * 将坐标数值格式化为字符串,避免科学计数法(WKT 不支持)。
319
329
  * 例:1e-7 → "0.0000001",1.50000 → "1.5",1.0 → "1"
320
330
  */
321
331
  function formatNumber(v) {
322
- // 有小数则最多保留 15 位有效位,再去掉尾零
323
332
  if (v % 1 !== 0) {
324
- return parseFloat(v.toFixed(15)).toString();
333
+ return Number(v.toFixed(15)).toString();
325
334
  }
326
- return v.toFixed(0);
335
+ return String(v);
327
336
  }
328
337
  function positionToWkt(pos) {
329
338
  return pos.map(formatNumber).join(' ');
@@ -331,6 +340,28 @@ function positionToWkt(pos) {
331
340
  function coordsToWkt(coords) {
332
341
  return coords.map(positionToWkt).join(', ');
333
342
  }
343
+ // 检查坐标是否包含 Z(3个分量)
344
+ function hasZ(coordinates) {
345
+ if (!Array.isArray(coordinates))
346
+ return false;
347
+ if (coordinates.length === 0)
348
+ return false;
349
+ const first = coordinates[0];
350
+ if (Array.isArray(first)) {
351
+ if (typeof first[0] === 'number') {
352
+ return first.length === 3;
353
+ }
354
+ if (Array.isArray(first[0])) {
355
+ const firstRing = first;
356
+ return firstRing.length > 0 && firstRing[0].length === 3;
357
+ }
358
+ }
359
+ return false;
360
+ }
361
+ // 获取 Z 后缀字符串
362
+ function zSuffix(coordinates) {
363
+ return hasZ(coordinates) ? ' Z' : '';
364
+ }
334
365
  class WKTBuilder {
335
366
  build(geometry) {
336
367
  switch (geometry.type) {
@@ -353,21 +384,18 @@ class WKTBuilder {
353
384
  }
354
385
  }
355
386
  buildPoint(geom) {
356
- const hasZ = geom.coordinates.length === 3;
357
- return `POINT${hasZ ? ' Z' : ''} (${positionToWkt(geom.coordinates)})`;
387
+ return `POINT${zSuffix(geom.coordinates)} (${positionToWkt(geom.coordinates)})`;
358
388
  }
359
389
  buildLineString(geom) {
360
390
  if (geom.coordinates.length === 0)
361
391
  return 'LINESTRING EMPTY';
362
- const hasZ = geom.coordinates[0].length === 3;
363
- return `LINESTRING${hasZ ? ' Z' : ''} (${coordsToWkt(geom.coordinates)})`;
392
+ return `LINESTRING${zSuffix(geom.coordinates)} (${coordsToWkt(geom.coordinates)})`;
364
393
  }
365
394
  buildPolygon(geom) {
366
395
  if (geom.coordinates.length === 0)
367
396
  return 'POLYGON EMPTY';
368
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
369
397
  const ringStr = geom.coordinates.map(ring => `(${coordsToWkt(ring)})`).join(', ');
370
- return `POLYGON${hasZ ? ' Z' : ''} (${ringStr})`;
398
+ return `POLYGON${zSuffix(geom.coordinates)} (${ringStr})`;
371
399
  }
372
400
  /**
373
401
  * 按 OGC/ISO WKT 标准,MULTIPOINT 每个点用括号包裹:
@@ -376,26 +404,23 @@ class WKTBuilder {
376
404
  buildMultiPoint(geom) {
377
405
  if (geom.coordinates.length === 0)
378
406
  return 'MULTIPOINT EMPTY';
379
- const hasZ = geom.coordinates[0].length === 3;
380
407
  const pts = geom.coordinates.map(p => `(${positionToWkt(p)})`).join(', ');
381
- return `MULTIPOINT${hasZ ? ' Z' : ''} (${pts})`;
408
+ return `MULTIPOINT${zSuffix(geom.coordinates)} (${pts})`;
382
409
  }
383
410
  buildMultiLineString(geom) {
384
411
  if (geom.coordinates.length === 0)
385
412
  return 'MULTILINESTRING EMPTY';
386
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
387
413
  const lines = geom.coordinates.map(line => `(${coordsToWkt(line)})`).join(', ');
388
- return `MULTILINESTRING${hasZ ? ' Z' : ''} (${lines})`;
414
+ return `MULTILINESTRING${zSuffix(geom.coordinates)} (${lines})`;
389
415
  }
390
416
  buildMultiPolygon(geom) {
391
417
  if (geom.coordinates.length === 0)
392
418
  return 'MULTIPOLYGON EMPTY';
393
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length > 0 && geom.coordinates[0][0][0].length === 3;
394
419
  const polys = geom.coordinates.map(poly => {
395
420
  const rings = poly.map(ring => `(${coordsToWkt(ring)})`).join(', ');
396
421
  return `(${rings})`;
397
422
  }).join(', ');
398
- return `MULTIPOLYGON${hasZ ? ' Z' : ''} (${polys})`;
423
+ return `MULTIPOLYGON${zSuffix(geom.coordinates)} (${polys})`;
399
424
  }
400
425
  buildGeometryCollection(geom) {
401
426
  if (geom.geometries.length === 0)
@@ -409,6 +434,12 @@ function build(geometry) {
409
434
  return new WKTBuilder().build(geometry);
410
435
  }
411
436
 
437
+ var wktBuilder = /*#__PURE__*/Object.freeze({
438
+ __proto__: null,
439
+ WKTBuilder: WKTBuilder,
440
+ build: build
441
+ });
442
+
412
443
  // ─── 内部工具:判断是否为 Position([number, number] 或 [number, number, number])
413
444
  function isPosition(v) {
414
445
  return (Array.isArray(v) &&
@@ -555,6 +586,18 @@ function createGeometryCollection(geometries) {
555
586
  return _builder.createGeometryCollection(geometries);
556
587
  }
557
588
 
589
+ var geojsonBuilder = /*#__PURE__*/Object.freeze({
590
+ __proto__: null,
591
+ GeoJSONBuilder: GeoJSONBuilder,
592
+ createGeometryCollection: createGeometryCollection,
593
+ createLineString: createLineString,
594
+ createMultiLineString: createMultiLineString,
595
+ createMultiPoint: createMultiPoint,
596
+ createMultiPolygon: createMultiPolygon,
597
+ createPoint: createPoint,
598
+ createPolygon: createPolygon
599
+ });
600
+
558
601
  /**
559
602
  * 将 WKT 字符串转换为 GeoJSON Geometry 对象。
560
603
  *
@@ -606,6 +649,13 @@ function wktToFeatureCollection(wkts, properties) {
606
649
  return { type: 'FeatureCollection', features };
607
650
  }
608
651
 
652
+ var wktToGeojson = /*#__PURE__*/Object.freeze({
653
+ __proto__: null,
654
+ wktToFeature: wktToFeature,
655
+ wktToFeatureCollection: wktToFeatureCollection,
656
+ wktToGeoJSON: wktToGeoJSON
657
+ });
658
+
609
659
  /**
610
660
  * 将 GeoJSON Geometry 对象转换为 WKT 字符串。
611
661
  *
@@ -651,6 +701,13 @@ function featureCollectionToWkt(fc) {
651
701
  });
652
702
  }
653
703
 
704
+ var geojsonToWkt$1 = /*#__PURE__*/Object.freeze({
705
+ __proto__: null,
706
+ featureCollectionToWkt: featureCollectionToWkt,
707
+ featureToWkt: featureToWkt,
708
+ geojsonToWkt: geojsonToWkt
709
+ });
710
+
654
711
  /**
655
712
  * 校验 WKT 字符串格式是否合法
656
713
  */
@@ -792,11 +849,14 @@ function tryFixWKT(wkt) {
792
849
  if (!trimmed) {
793
850
  return { fixed: wkt, changed: false };
794
851
  }
795
- // 检查是否有尾部多余字符
796
- const result = validateWKT(trimmed);
797
- if (result.valid) {
852
+ // 先尝试直接解析,如果成功则不需要修复
853
+ try {
854
+ parse(trimmed);
798
855
  return { fixed: trimmed, changed: false };
799
856
  }
857
+ catch {
858
+ // 解析失败,尝试修复
859
+ }
800
860
  // 尝试找到最后一个有效的 geometry 结束位置
801
861
  const patterns = [
802
862
  /\)\s*[A-Z]/i, // 括号后跟字母 (如 POLYGON ((...)) POINT )
@@ -807,18 +867,26 @@ function tryFixWKT(wkt) {
807
867
  const match = trimmed.match(pattern);
808
868
  if (match) {
809
869
  const fixed = trimmed.slice(0, match.index + (match[0].match(/\)/)?.[0].length || 0));
810
- if (validateWKT(fixed).valid) {
870
+ try {
871
+ parse(fixed);
811
872
  return { fixed, changed: true };
812
873
  }
874
+ catch {
875
+ // 这个修复方案不行,尝试下一个
876
+ }
813
877
  }
814
878
  }
815
879
  // 尝试去除尾部垃圾字符
816
880
  const lastValidIndex = findLastValidPosition(trimmed);
817
881
  if (lastValidIndex > 0) {
818
882
  const fixed = trimmed.slice(0, lastValidIndex + 1);
819
- if (validateWKT(fixed).valid) {
883
+ try {
884
+ parse(fixed);
820
885
  return { fixed, changed: true };
821
886
  }
887
+ catch {
888
+ // 修复失败
889
+ }
822
890
  }
823
891
  return { fixed: wkt, changed: false };
824
892
  }
@@ -858,7 +926,39 @@ function cloneGeometry(geometry) {
858
926
  function geometryEquals(a, b) {
859
927
  if (a.type !== b.type)
860
928
  return false;
929
+ // Point 比较最常见,单独优化
930
+ if (a.type === 'Point') {
931
+ const aCoords = a.coordinates;
932
+ const bCoords = b.coordinates;
933
+ return aCoords.length === bCoords.length &&
934
+ aCoords[0] === bCoords[0] &&
935
+ aCoords[1] === bCoords[1] &&
936
+ (aCoords.length === 2 || aCoords[2] === bCoords[2]);
937
+ }
938
+ // 其他类型使用 JSON.stringify(缓存 key 优化可后续添加)
861
939
  return JSON.stringify(a) === JSON.stringify(b);
862
940
  }
863
941
 
864
- export { GeoJSONBuilder, WKTBuilder, WKTParser, build, cloneGeometry, createGeometryCollection, createLineString, createMultiLineString, createMultiPoint, createMultiPolygon, createPoint, createPolygon, featureCollectionToWkt, featureToWkt, geojsonToWkt, geometryEquals, parse, tryFixWKT, validateGeoJSON, validateWKT, wktToFeature, wktToFeatureCollection, wktToGeoJSON };
942
+ var validate = /*#__PURE__*/Object.freeze({
943
+ __proto__: null,
944
+ cloneGeometry: cloneGeometry,
945
+ geometryEquals: geometryEquals,
946
+ tryFixWKT: tryFixWKT,
947
+ validateGeoJSON: validateGeoJSON,
948
+ validateWKT: validateWKT
949
+ });
950
+
951
+ // 命名空间导出 - 所有公共 API 汇总
952
+ // 使用方式: import WKT from 'wkt-parse-and-geojson';
953
+ // WKT.parse(...), WKT.build(...), etc.
954
+ const WKT = {
955
+ ...types,
956
+ ...wktParser,
957
+ ...wktBuilder,
958
+ ...geojsonBuilder,
959
+ ...wktToGeojson,
960
+ ...geojsonToWkt$1,
961
+ ...validate,
962
+ };
963
+
964
+ export { GeoJSONBuilder, WKT, WKTBuilder, WKTParser, build, cloneGeometry, createGeometryCollection, createLineString, createMultiLineString, createMultiPoint, createMultiPolygon, createPoint, createPolygon, featureCollectionToWkt, featureToWkt, geojsonToWkt, geometryEquals, parse, tryFixWKT, validateGeoJSON, validateWKT, wktToFeature, wktToFeatureCollection, wktToGeoJSON };
package/dist/index.umd.js CHANGED
@@ -4,6 +4,10 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.WKTGeoJSON = {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
+ var types = /*#__PURE__*/Object.freeze({
8
+ __proto__: null
9
+ });
10
+
7
11
  // Precompiled regex for better performance
8
12
  const RE_WHITESPACE = /\s/;
9
13
  const RE_NUMBER_START = /[0-9\-]/;
@@ -320,16 +324,21 @@
320
324
  return parser.parse(wkt);
321
325
  }
322
326
 
327
+ var wktParser = /*#__PURE__*/Object.freeze({
328
+ __proto__: null,
329
+ WKTParser: WKTParser,
330
+ parse: parse
331
+ });
332
+
323
333
  /**
324
334
  * 将坐标数值格式化为字符串,避免科学计数法(WKT 不支持)。
325
335
  * 例:1e-7 → "0.0000001",1.50000 → "1.5",1.0 → "1"
326
336
  */
327
337
  function formatNumber(v) {
328
- // 有小数则最多保留 15 位有效位,再去掉尾零
329
338
  if (v % 1 !== 0) {
330
- return parseFloat(v.toFixed(15)).toString();
339
+ return Number(v.toFixed(15)).toString();
331
340
  }
332
- return v.toFixed(0);
341
+ return String(v);
333
342
  }
334
343
  function positionToWkt(pos) {
335
344
  return pos.map(formatNumber).join(' ');
@@ -337,6 +346,28 @@
337
346
  function coordsToWkt(coords) {
338
347
  return coords.map(positionToWkt).join(', ');
339
348
  }
349
+ // 检查坐标是否包含 Z(3个分量)
350
+ function hasZ(coordinates) {
351
+ if (!Array.isArray(coordinates))
352
+ return false;
353
+ if (coordinates.length === 0)
354
+ return false;
355
+ const first = coordinates[0];
356
+ if (Array.isArray(first)) {
357
+ if (typeof first[0] === 'number') {
358
+ return first.length === 3;
359
+ }
360
+ if (Array.isArray(first[0])) {
361
+ const firstRing = first;
362
+ return firstRing.length > 0 && firstRing[0].length === 3;
363
+ }
364
+ }
365
+ return false;
366
+ }
367
+ // 获取 Z 后缀字符串
368
+ function zSuffix(coordinates) {
369
+ return hasZ(coordinates) ? ' Z' : '';
370
+ }
340
371
  class WKTBuilder {
341
372
  build(geometry) {
342
373
  switch (geometry.type) {
@@ -359,21 +390,18 @@
359
390
  }
360
391
  }
361
392
  buildPoint(geom) {
362
- const hasZ = geom.coordinates.length === 3;
363
- return `POINT${hasZ ? ' Z' : ''} (${positionToWkt(geom.coordinates)})`;
393
+ return `POINT${zSuffix(geom.coordinates)} (${positionToWkt(geom.coordinates)})`;
364
394
  }
365
395
  buildLineString(geom) {
366
396
  if (geom.coordinates.length === 0)
367
397
  return 'LINESTRING EMPTY';
368
- const hasZ = geom.coordinates[0].length === 3;
369
- return `LINESTRING${hasZ ? ' Z' : ''} (${coordsToWkt(geom.coordinates)})`;
398
+ return `LINESTRING${zSuffix(geom.coordinates)} (${coordsToWkt(geom.coordinates)})`;
370
399
  }
371
400
  buildPolygon(geom) {
372
401
  if (geom.coordinates.length === 0)
373
402
  return 'POLYGON EMPTY';
374
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
375
403
  const ringStr = geom.coordinates.map(ring => `(${coordsToWkt(ring)})`).join(', ');
376
- return `POLYGON${hasZ ? ' Z' : ''} (${ringStr})`;
404
+ return `POLYGON${zSuffix(geom.coordinates)} (${ringStr})`;
377
405
  }
378
406
  /**
379
407
  * 按 OGC/ISO WKT 标准,MULTIPOINT 每个点用括号包裹:
@@ -382,26 +410,23 @@
382
410
  buildMultiPoint(geom) {
383
411
  if (geom.coordinates.length === 0)
384
412
  return 'MULTIPOINT EMPTY';
385
- const hasZ = geom.coordinates[0].length === 3;
386
413
  const pts = geom.coordinates.map(p => `(${positionToWkt(p)})`).join(', ');
387
- return `MULTIPOINT${hasZ ? ' Z' : ''} (${pts})`;
414
+ return `MULTIPOINT${zSuffix(geom.coordinates)} (${pts})`;
388
415
  }
389
416
  buildMultiLineString(geom) {
390
417
  if (geom.coordinates.length === 0)
391
418
  return 'MULTILINESTRING EMPTY';
392
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length === 3;
393
419
  const lines = geom.coordinates.map(line => `(${coordsToWkt(line)})`).join(', ');
394
- return `MULTILINESTRING${hasZ ? ' Z' : ''} (${lines})`;
420
+ return `MULTILINESTRING${zSuffix(geom.coordinates)} (${lines})`;
395
421
  }
396
422
  buildMultiPolygon(geom) {
397
423
  if (geom.coordinates.length === 0)
398
424
  return 'MULTIPOLYGON EMPTY';
399
- const hasZ = geom.coordinates[0].length > 0 && geom.coordinates[0][0].length > 0 && geom.coordinates[0][0][0].length === 3;
400
425
  const polys = geom.coordinates.map(poly => {
401
426
  const rings = poly.map(ring => `(${coordsToWkt(ring)})`).join(', ');
402
427
  return `(${rings})`;
403
428
  }).join(', ');
404
- return `MULTIPOLYGON${hasZ ? ' Z' : ''} (${polys})`;
429
+ return `MULTIPOLYGON${zSuffix(geom.coordinates)} (${polys})`;
405
430
  }
406
431
  buildGeometryCollection(geom) {
407
432
  if (geom.geometries.length === 0)
@@ -415,6 +440,12 @@
415
440
  return new WKTBuilder().build(geometry);
416
441
  }
417
442
 
443
+ var wktBuilder = /*#__PURE__*/Object.freeze({
444
+ __proto__: null,
445
+ WKTBuilder: WKTBuilder,
446
+ build: build
447
+ });
448
+
418
449
  // ─── 内部工具:判断是否为 Position([number, number] 或 [number, number, number])
419
450
  function isPosition(v) {
420
451
  return (Array.isArray(v) &&
@@ -561,6 +592,18 @@
561
592
  return _builder.createGeometryCollection(geometries);
562
593
  }
563
594
 
595
+ var geojsonBuilder = /*#__PURE__*/Object.freeze({
596
+ __proto__: null,
597
+ GeoJSONBuilder: GeoJSONBuilder,
598
+ createGeometryCollection: createGeometryCollection,
599
+ createLineString: createLineString,
600
+ createMultiLineString: createMultiLineString,
601
+ createMultiPoint: createMultiPoint,
602
+ createMultiPolygon: createMultiPolygon,
603
+ createPoint: createPoint,
604
+ createPolygon: createPolygon
605
+ });
606
+
564
607
  /**
565
608
  * 将 WKT 字符串转换为 GeoJSON Geometry 对象。
566
609
  *
@@ -612,6 +655,13 @@
612
655
  return { type: 'FeatureCollection', features };
613
656
  }
614
657
 
658
+ var wktToGeojson = /*#__PURE__*/Object.freeze({
659
+ __proto__: null,
660
+ wktToFeature: wktToFeature,
661
+ wktToFeatureCollection: wktToFeatureCollection,
662
+ wktToGeoJSON: wktToGeoJSON
663
+ });
664
+
615
665
  /**
616
666
  * 将 GeoJSON Geometry 对象转换为 WKT 字符串。
617
667
  *
@@ -657,6 +707,13 @@
657
707
  });
658
708
  }
659
709
 
710
+ var geojsonToWkt$1 = /*#__PURE__*/Object.freeze({
711
+ __proto__: null,
712
+ featureCollectionToWkt: featureCollectionToWkt,
713
+ featureToWkt: featureToWkt,
714
+ geojsonToWkt: geojsonToWkt
715
+ });
716
+
660
717
  /**
661
718
  * 校验 WKT 字符串格式是否合法
662
719
  */
@@ -798,11 +855,14 @@
798
855
  if (!trimmed) {
799
856
  return { fixed: wkt, changed: false };
800
857
  }
801
- // 检查是否有尾部多余字符
802
- const result = validateWKT(trimmed);
803
- if (result.valid) {
858
+ // 先尝试直接解析,如果成功则不需要修复
859
+ try {
860
+ parse(trimmed);
804
861
  return { fixed: trimmed, changed: false };
805
862
  }
863
+ catch {
864
+ // 解析失败,尝试修复
865
+ }
806
866
  // 尝试找到最后一个有效的 geometry 结束位置
807
867
  const patterns = [
808
868
  /\)\s*[A-Z]/i, // 括号后跟字母 (如 POLYGON ((...)) POINT )
@@ -813,18 +873,26 @@
813
873
  const match = trimmed.match(pattern);
814
874
  if (match) {
815
875
  const fixed = trimmed.slice(0, match.index + (match[0].match(/\)/)?.[0].length || 0));
816
- if (validateWKT(fixed).valid) {
876
+ try {
877
+ parse(fixed);
817
878
  return { fixed, changed: true };
818
879
  }
880
+ catch {
881
+ // 这个修复方案不行,尝试下一个
882
+ }
819
883
  }
820
884
  }
821
885
  // 尝试去除尾部垃圾字符
822
886
  const lastValidIndex = findLastValidPosition(trimmed);
823
887
  if (lastValidIndex > 0) {
824
888
  const fixed = trimmed.slice(0, lastValidIndex + 1);
825
- if (validateWKT(fixed).valid) {
889
+ try {
890
+ parse(fixed);
826
891
  return { fixed, changed: true };
827
892
  }
893
+ catch {
894
+ // 修复失败
895
+ }
828
896
  }
829
897
  return { fixed: wkt, changed: false };
830
898
  }
@@ -864,10 +932,43 @@
864
932
  function geometryEquals(a, b) {
865
933
  if (a.type !== b.type)
866
934
  return false;
935
+ // Point 比较最常见,单独优化
936
+ if (a.type === 'Point') {
937
+ const aCoords = a.coordinates;
938
+ const bCoords = b.coordinates;
939
+ return aCoords.length === bCoords.length &&
940
+ aCoords[0] === bCoords[0] &&
941
+ aCoords[1] === bCoords[1] &&
942
+ (aCoords.length === 2 || aCoords[2] === bCoords[2]);
943
+ }
944
+ // 其他类型使用 JSON.stringify(缓存 key 优化可后续添加)
867
945
  return JSON.stringify(a) === JSON.stringify(b);
868
946
  }
869
947
 
948
+ var validate = /*#__PURE__*/Object.freeze({
949
+ __proto__: null,
950
+ cloneGeometry: cloneGeometry,
951
+ geometryEquals: geometryEquals,
952
+ tryFixWKT: tryFixWKT,
953
+ validateGeoJSON: validateGeoJSON,
954
+ validateWKT: validateWKT
955
+ });
956
+
957
+ // 命名空间导出 - 所有公共 API 汇总
958
+ // 使用方式: import WKT from 'wkt-parse-and-geojson';
959
+ // WKT.parse(...), WKT.build(...), etc.
960
+ const WKT = {
961
+ ...types,
962
+ ...wktParser,
963
+ ...wktBuilder,
964
+ ...geojsonBuilder,
965
+ ...wktToGeojson,
966
+ ...geojsonToWkt$1,
967
+ ...validate,
968
+ };
969
+
870
970
  exports.GeoJSONBuilder = GeoJSONBuilder;
971
+ exports.WKT = WKT;
871
972
  exports.WKTBuilder = WKTBuilder;
872
973
  exports.WKTParser = WKTParser;
873
974
  exports.build = build;
@@ -0,0 +1,34 @@
1
+ import * as types from './types';
2
+ import * as wktParser from './wkt-parser';
3
+ import * as wktBuilder from './wkt-builder';
4
+ import * as geojsonBuilder from './geojson-builder';
5
+ import * as validate from './validate';
6
+ declare const WKT: {
7
+ validateWKT(wkt: string): validate.ValidationResult;
8
+ validateGeoJSON(geojson: unknown): validate.ValidationResult;
9
+ tryFixWKT(wkt: string): {
10
+ fixed: string;
11
+ changed: boolean;
12
+ };
13
+ cloneGeometry<G extends types.Geometry>(geometry: G): G;
14
+ geometryEquals(a: types.Geometry, b: types.Geometry): boolean;
15
+ geojsonToWkt(geojson: types.Geometry): string;
16
+ featureToWkt(feature: types.Feature): string;
17
+ featureCollectionToWkt(fc: types.FeatureCollection): Array<string | null>;
18
+ wktToGeoJSON(wkt: string): types.Geometry;
19
+ wktToFeature(wkt: string, properties?: Record<string, unknown> | null, id?: string | number): types.Feature;
20
+ wktToFeatureCollection(wkts: string[], properties?: Array<Record<string, unknown> | null>): types.FeatureCollection;
21
+ createPoint(x: number, y: number, z?: number): types.Point;
22
+ createLineString(coordinates: types.Position[]): types.LineString;
23
+ createPolygon(coordinates: types.Position[] | types.Position[][]): types.Polygon;
24
+ createMultiPoint(coordinates: types.Position | types.Position[]): types.MultiPoint;
25
+ createMultiLineString(coordinates: types.Position[] | types.Position[][]): types.MultiLineString;
26
+ createMultiPolygon(coordinates: types.Position[][] | types.Position[][][]): types.MultiPolygon;
27
+ createGeometryCollection(geometries: types.Geometry | types.Geometry[]): types.GeometryCollection;
28
+ GeoJSONBuilder: typeof geojsonBuilder.GeoJSONBuilder;
29
+ build(geometry: types.Geometry): string;
30
+ WKTBuilder: typeof wktBuilder.WKTBuilder;
31
+ parse(wkt: string): types.Geometry;
32
+ WKTParser: typeof wktParser.WKTParser;
33
+ };
34
+ export default WKT;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wkt-parse-and-geojson",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "Zero-dependency WKT parser/builder and WKT↔GeoJSON converter",
6
6
  "main": "dist/index.cjs.js",