From 9df6d42cafb0e8896deef9b5f45d184d1b702417 Mon Sep 17 00:00:00 2001 From: john gravois Date: Thu, 4 Apr 2019 00:12:01 -0700 Subject: [PATCH] add @terraformer/wkt module --- .gitignore | 5 +- .travis.yml | 19 +- README.md | 2 +- package-lock.json | 598 +++++++++-------------------- package.json | 6 +- packages/arcgis/README.md | 2 +- packages/wkt/README.md | 63 ++++ packages/wkt/build-esm.js | 14 + packages/wkt/package-lock.json | 126 +++++++ packages/wkt/package.json | 47 +++ packages/wkt/test/geojson.test.js | 452 ++++++++++++++++++++++ packages/wkt/test/wkt.test.js | 606 ++++++++++++++++++++++++++++++ packages/wkt/wkt.js | 334 ++++++++++++++++ packages/wkt/wkt.yy | 178 +++++++++ 14 files changed, 2025 insertions(+), 427 deletions(-) create mode 100644 packages/wkt/README.md create mode 100644 packages/wkt/build-esm.js create mode 100644 packages/wkt/package-lock.json create mode 100644 packages/wkt/package.json create mode 100644 packages/wkt/test/geojson.test.js create mode 100644 packages/wkt/test/wkt.test.js create mode 100644 packages/wkt/wkt.js create mode 100644 packages/wkt/wkt.yy diff --git a/.gitignore b/.gitignore index e4b8ec3..c1fb7cc 100644 --- a/.gitignore +++ b/.gitignore @@ -94,4 +94,7 @@ demos/test/* packages/**/.source.**.html # jsdoc -out/* \ No newline at end of file +out/* + +# created by jison +packages/wkt/index.js \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 2c67e4c..c04d576 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,14 @@ node_js: - 'node' - 'lts/*' sudo: false -cache: - directories: - - node_modules -install: - - export DISPLAY=':99.0' - - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & +cache: npm before_script: -- npm install tape-run -- npm run bootstrap + - npm install tape-run + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + - sleep 3 # give xvfb some time to start script: -- npm run test:ci + - npm run test:ci before_deploy: - npm run jsdoc deploy: @@ -31,8 +28,8 @@ branches: only: - master addons: + chrome: stable + firefox: latest apt: packages: - xvfb - chrome: stable - firefox: latest diff --git a/README.md b/README.md index aed82b4..ad81bb4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ See the [@terraformer](https://terraformer-js.github.io/terraformer/module-@terr * **[`@terraformer/spatial`](./packages/spatial/)** - Spatial predicates for [GeoJSON](https://tools.ietf.org/html/rfc7946). * **[`@terraformer/arcgis`](./packages/arcgis/)** - Convert ArcGIS JSON geometries to GeoJSON geometries and vice versa. -* **`@terraformer/wkt`** - coming soon +* **[`@terraformer/wkt`](./packages/wkt/)** - Convert WKT geometries to GeoJSON geometries and vice versa. ## Contributing diff --git a/package-lock.json b/package-lock.json index ec28d50..e4dea15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3332,9 +3332,9 @@ "dev": true }, "estree-walker": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", - "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.0.tgz", + "integrity": "sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==", "dev": true }, "esutils": { @@ -3409,57 +3409,6 @@ } } }, - "expand-range": { - "version": "1.8.2", - "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3692,12 +3641,6 @@ "object-assign": "^4.0.1" } }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -3774,15 +3717,6 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3845,24 +3779,29 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, "requires": { @@ -3872,13 +3811,17 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3886,34 +3829,43 @@ }, "chownr": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": false, + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, "requires": { @@ -3922,25 +3874,29 @@ }, "deep-extend": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, "requires": { @@ -3949,13 +3905,15 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, "requires": { @@ -3971,7 +3929,8 @@ }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, "requires": { @@ -3985,13 +3944,15 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "bundled": true, + "resolved": false, + "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, "requires": { @@ -4000,7 +3961,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, "requires": { @@ -4009,7 +3971,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, "requires": { @@ -4019,46 +3982,58 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4066,7 +4041,8 @@ }, "minizlib": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, "requires": { @@ -4075,21 +4051,25 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, "requires": { @@ -4100,7 +4080,8 @@ }, "node-pre-gyp": { "version": "0.10.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, "requires": { @@ -4118,7 +4099,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, "requires": { @@ -4128,13 +4110,15 @@ }, "npm-bundled": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "bundled": true, + "resolved": false, + "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, "requires": { @@ -4144,7 +4128,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, "requires": { @@ -4156,38 +4141,46 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, "requires": { @@ -4197,19 +4190,22 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "bundled": true, + "resolved": false, + "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, "requires": { @@ -4221,7 +4217,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -4229,7 +4226,8 @@ }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, "requires": { @@ -4244,7 +4242,8 @@ }, "rimraf": { "version": "2.6.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, "requires": { @@ -4253,43 +4252,52 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4298,7 +4306,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, "requires": { @@ -4307,21 +4316,25 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, "requires": { @@ -4336,13 +4349,15 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, "requires": { @@ -4351,13 +4366,17 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", - "bundled": true, - "dev": true + "resolved": false, + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", + "dev": true, + "optional": true } } }, @@ -4676,42 +4695,6 @@ "path-is-absolute": "^1.0.0" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", @@ -4795,26 +4778,17 @@ "dev": true }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" }, "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5337,21 +5311,6 @@ } } }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -5463,18 +5422,6 @@ "isobject": "^3.0.1" } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -5599,9 +5546,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -6179,12 +6126,6 @@ "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", - "dev": true - }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -6444,6 +6385,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -6577,16 +6524,6 @@ "isobject": "^3.0.0" } }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -6792,35 +6729,6 @@ "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", "dev": true }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -7003,12 +6911,6 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -7115,25 +7017,6 @@ "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", "dev": true }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -7367,15 +7250,6 @@ "private": "^0.1.6" } }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -7653,104 +7527,13 @@ } }, "rollup-pluginutils": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.3.tgz", - "integrity": "sha512-2XZwja7b6P5q4RZ5FhyX1+f46xi1Z3qBKigLRZ6VTZjwbN0K1IFGMlwm06Uu0Emcre2Z63l77nq/pzn+KxIEoA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.5.0.tgz", + "integrity": "sha512-9Muh1H+XB5f5ONmKMayUoTYR1EZwHbwJJ9oZLrKT5yuTf/RLIQ5mYIGsrERquVucJmjmaAW0Y7+6Qo1Ep+5w3Q==", "dev": true, "requires": { - "estree-walker": "^0.5.2", - "micromatch": "^2.3.11" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - } + "estree-walker": "^0.6.0", + "micromatch": "^3.1.10" } }, "run-async": { @@ -8853,23 +8636,16 @@ "dev": true }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.3.tgz", + "integrity": "sha512-rIQPT2UMDnk4jRX+w4WO84/pebU2jiLsjgIyrCktYgSvx28enOE3iYQMr+BD1rHiitWnDmpu0cY/LfIEpKcjcw==", "dev": true, "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.19.0", "source-map": "~0.6.1" }, "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index fd3f441..679b6f7 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "test:electron": "browserify packages/**/test/*.js -t [ babelify --presets [ @babel/preset-env ] ] --debug | tape-run | faucet", "test:chrome": "browserify packages/**/test/*.js -t [ babelify --presets [ @babel/preset-env ] ] --debug | tape-run --browser chrome | faucet", "test:firefox": "browserify packages/**/test/*.js -t [ babelify --presets [ @babel/preset-env ] ] --debug | tape-run --browser firefox | faucet", + "pretest:ci": "npm run build", "test": "npm run lint && npm run test:node", - "test:ci": "npm run lint && npm run test:node && npm run test:chrome && npm run test:firefox", - "release": "./release.sh" + "test:ci": "npm run lint && npm run test:node && npm run test:electron", + "release": "./release.sh", + "postinstall": "npm run bootstrap" }, "repository": { "type": "git", diff --git a/packages/arcgis/README.md b/packages/arcgis/README.md index aedcec5..4123d47 100644 --- a/packages/arcgis/README.md +++ b/packages/arcgis/README.md @@ -15,7 +15,7 @@ ## Install -``` +```shell npm install @terraformer/arcgis ``` diff --git a/packages/wkt/README.md b/packages/wkt/README.md new file mode 100644 index 0000000..2a0b409 --- /dev/null +++ b/packages/wkt/README.md @@ -0,0 +1,63 @@ +# @terraformer/wkt + +[![npm][npm-image]][npm-url] +[![travis][travis-image]][travis-url] +[![standard][standard-image]][standard-url] + +[npm-image]: https://img.shields.io/npm/v/@terraformer/wkt.svg?style=flat-square +[npm-url]: https://www.npmjs.com/package/@terraformer/wkt +[travis-image]: https://img.shields.io/travis/terraformer-js/terraformer/master.svg?style=flat-square +[travis-url]: https://travis-ci.org/terraformer-js/terraformer +[standard-image]: https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square +[standard-url]: http://npm.im/semistandard + +> Tools to convert WKT geometries to GeoJSON geometries and vice versa. + +## Install + +```shell +npm install @terraformer/wkt +``` + +## Usage + +### ES Module + +```js +import { wktToGeoJSON, geojsonToWKT } from '@terraformer/wkt'; + +// parse WKT and convert to GeoJSON +const geojson = wktToGeoJSON("POINT (-122.6764, 45.5165)"); + +>> { "type": "Point", "coordinates": [ -122.6764, 45.5165 ] } + +// parse GeoJSON and convert it to ArcGIS JSON +const wkt = geojsonToWKT({ + "type": "Point", + "coordinates": [ -122.6764, 45.5165 ] +}); + +>> "POINT (-122.6764, 45.5165)" +``` + +### Browser (from CDN) + +This package is distributed as a [UMD](https://github.com/umdjs/umd) module and can also be used in AMD based systems or as a global under the `Terraformer` namespace. + +```html + +``` +```js +Terraformer.wktToGeoJSON("POINT (-122.6764, 45.5165)"); +``` + +### Node.js + +```js +const Terraformer = require('@terraformer/wkt'); + +Terraformer.geojsonToWKT(/* ... */); +Terraformer.wktToGeoJSON(/* ... */); +``` + +## [Contributing](./CONTRIBUTING.md) diff --git a/packages/wkt/build-esm.js b/packages/wkt/build-esm.js new file mode 100644 index 0000000..1344d3c --- /dev/null +++ b/packages/wkt/build-esm.js @@ -0,0 +1,14 @@ +var fs = require('fs'); +var jison = require('jison'); + +var grammar = fs.readFileSync('./wkt.yy', 'utf8'); +var wrapper = fs.readFileSync('./wkt.js', 'utf8'); + +var Parser = jison.Parser; +var parser = new Parser(grammar); + +// generate source, ready to be written to disk using a jison fork to get a es module output: https://github.com/zaach/jison/pull/326 +var parserSource = parser.generate({ moduleType: 'es' }); + +wrapper = wrapper.replace('\'SOURCE\';', parserSource); +fs.writeFileSync('./index.js', wrapper, 'utf8'); diff --git a/packages/wkt/package-lock.json b/packages/wkt/package-lock.json new file mode 100644 index 0000000..ac4f834 --- /dev/null +++ b/packages/wkt/package-lock.json @@ -0,0 +1,126 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "JSONSelect": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz", + "integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40=" + }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "optional": true + }, + "cjson": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz", + "integrity": "sha1-5kObkHA9MS/24iJAl76pLOPQKhQ=", + "requires": { + "jsonlint": "1.6.0" + } + }, + "colors": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=" + }, + "ebnf-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz", + "integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=" + }, + "escodegen": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz", + "integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=", + "requires": { + "esprima": "~1.1.1", + "estraverse": "~1.5.0", + "esutils": "~1.0.0", + "source-map": "~0.1.33" + } + }, + "esprima": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz", + "integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk=" + }, + "estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=" + }, + "esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=" + }, + "jison": { + "version": "github:GabrielRatener/jison#2668d7efbb628c763dc7cce41ab24a4632528942", + "from": "github:GabrielRatener/jison", + "requires": { + "JSONSelect": "0.4.0", + "cjson": "0.3.0", + "ebnf-parser": "0.1.10", + "escodegen": "1.3.x", + "esprima": "1.1.x", + "jison-lex": "0.3.x", + "lex-parser": "~0.1.3", + "nomnom": "1.5.2" + } + }, + "jison-lex": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/jison-lex/-/jison-lex-0.3.4.tgz", + "integrity": "sha1-gcoo2E+ESZ36jFlNzePYo/Jux6U=", + "requires": { + "lex-parser": "0.1.x", + "nomnom": "1.5.2" + } + }, + "jsonlint": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz", + "integrity": "sha1-iKpGvCiaesk7tGyuLVihh6m7SUo=", + "requires": { + "JSV": ">= 4.0.x", + "nomnom": ">= 1.5.x" + } + }, + "lex-parser": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz", + "integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA=" + }, + "nomnom": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz", + "integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=", + "requires": { + "colors": "0.5.x", + "underscore": "1.1.x" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "underscore": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz", + "integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA=" + } + } +} diff --git a/packages/wkt/package.json b/packages/wkt/package.json new file mode 100644 index 0000000..f44aa8f --- /dev/null +++ b/packages/wkt/package.json @@ -0,0 +1,47 @@ +{ + "name": "@terraformer/wkt", + "description": "Tools to convert WKT geometries to GeoJSON geometries and vica-versa.", + "version": "2.0.0", + "author": "Jerry Sievert (http://legitimatesounding.com)", + "bugs": { + "url": "https://github.com/terraformer-js/terraformer/issues" + }, + "contributors": [ + "John Gravois " + ], + "dependencies": {}, + "devDependencies": { + "jison": "GabrielRatener/jison" + }, + "files": [ + "index.js", + "dist/wkt.umd.js.map" + ], + "homepage": "https://github.com/terraformer-js/terraformer", + "keywords": [ + "wkt", + "convert", + "geo", + "geojson", + "geometry" + ], + "license": "MIT", + "main": "dist/wkt.umd.js", + "unpkg": "dist/wkt.umd.js", + "module": "index.js", + "jspm": { + "main": "index.js", + "registry": "npm", + "format": "es6" + }, + "repository": { + "type": "git", + "url": "https://github.com/terraformer-js/terraformer" + }, + "scripts": { + "build:module": "node build-esm.js", + "prebuild": "npm run build:module", + "build": "npm run build:module && rollup -c ../../rollup.config.js", + "prepare": "npm run build" + } +} diff --git a/packages/wkt/test/geojson.test.js b/packages/wkt/test/geojson.test.js new file mode 100644 index 0000000..4948e51 --- /dev/null +++ b/packages/wkt/test/geojson.test.js @@ -0,0 +1,452 @@ + +import test from 'tape'; +import { geojsonToWKT } from '../index.js'; + +test('should exist', function (t) { + t.plan(1); + t.ok(geojsonToWKT); +}); + +test('should turn a GeoJSON Point into WKT', function (t) { + t.plan(1); + + const input = { + type: 'Point', + coordinates: [ 30, 10 ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POINT (30 10)'); +}); + +test('should convert a POINT with Z', function (t) { + t.plan(1); + + const input = { + type: 'Point', + coordinates: [ 30, 10, 10 ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POINT Z (30 10 10)'); +}); + +test('should convert a POINT with M (nonstandard)', function (t) { + t.plan(1); + + const input = { + properties: { m: true }, + type: 'Point', + coordinates: [ 30, 10, 10 ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POINT M (30 10 10)'); +}); + +test('should convert a POINT with Z and M', function (t) { + t.plan(1); + + const input = { + type: 'Point', + coordinates: [ 30, 10, 10, 12 ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POINT ZM (30 10 10 12)'); +}); + +test('should convert an empty POINT', function (t) { + t.plan(1); + + const input = { + type: 'Point', + coordinates: [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POINT EMPTY'); +}); + +test('should convert a POLYGON', function (t) { + t.plan(1); + + const input = { + type: 'Polygon', + coordinates: [ [ [ 30, 10 ], [ 20, 20 ], [ 30, 20 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POLYGON ((30 10, 20 20, 30 20))'); +}); + +test('should convert a POLYGON with Z', function (t) { + t.plan(1); + + const input = { + type: 'Polygon', + coordinates: [ [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POLYGON Z ((30 10 1, 20 20 2, 30 20 3))'); +}); + +test('should convert a POLYGON with ZM', function (t) { + t.plan(1); + + const input = { + type: 'Polygon', + coordinates: [ [ [ 30, 10, 1, 3 ], [ 20, 20, 2, 2 ], [ 30, 20, 3, 1 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POLYGON ZM ((30 10 1 3, 20 20 2 2, 30 20 3 1))'); +}); + +test('should convert a POLYGON with M (nonstandard)', function (t) { + t.plan(1); + + const input = { + properties: { m: true }, + type: 'Polygon', + coordinates: [ [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POLYGON M ((30 10 1, 20 20 2, 30 20 3))'); +}); + +test('should convert an EMPTY POLYGON', function (t) { + t.plan(1); + + const input = { + type: 'Polygon', + coordinates: [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'POLYGON EMPTY'); +}); + +test('should convert a MULTIPOINT', function (t) { + t.plan(1); + + const input = { + type: 'MultiPoint', + coordinates: [ [ 30, 10 ], [ 20, 20 ], [ 30, 20 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOINT (30 10, 20 20, 30 20)'); +}); + +test('should convert a MULTIPOINT with Z', function (t) { + t.plan(1); + + const input = { + type: 'MultiPoint', + coordinates: [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOINT Z (30 10 1, 20 20 2, 30 20 3)'); +}); + +test('should convert a MULTIPOINT with ZM', function (t) { + t.plan(1); + + const input = { + type: 'MultiPoint', + coordinates: [ [ 30, 10, 1, 2 ], [ 20, 20, 3, 4 ], [ 30, 20, 5, 6 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOINT ZM (30 10 1 2, 20 20 3 4, 30 20 5 6)'); +}); + +test('should convert a MULTIPOINT with M (nonstandard)', function (t) { + t.plan(1); + + const input = { + properties: { m: true }, + type: 'MultiPoint', + coordinates: [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOINT M (30 10 1, 20 20 2, 30 20 3)'); +}); + +test('should convert an EMPTY MULTIPOINT', function (t) { + t.plan(1); + + const input = { + type: 'MultiPoint', + coordinates: [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOINT EMPTY'); +}); + +test('should convert a LINESTRING with Z', function (t) { + t.plan(1); + + const input = { + type: 'LineString', + coordinates: [ [ 30, 10, 2 ], [ 20, 20, 1 ], [ 30, 20, 0 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'LINESTRING Z (30 10 2, 20 20 1, 30 20 0)'); +}); + +test('should convert a LINESTRING with ZM', function (t) { + t.plan(1); + + const input = { + type: 'LineString', + coordinates: [ [ 30, 10, 1, 2 ], [ 20, 20, 3, 4 ], [ 30, 20, 5, 6 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'LINESTRING ZM (30 10 1 2, 20 20 3 4, 30 20 5 6)'); +}); + +test('should convert a LINESTRING with M (nonstandard)', function (t) { + t.plan(1); + + const input = { + properties: { m: true }, + type: 'LineString', + coordinates: [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'LINESTRING M (30 10 1, 20 20 2, 30 20 3)'); +}); + +test('should convert an empty LINESTRING', function (t) { + t.plan(1); + + const input = { + type: 'LineString', + coordinates: [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'LINESTRING EMPTY'); +}); + +test('should convert a LINESTRING', function (t) { + t.plan(1); + + const input = { + type: 'LineString', + coordinates: [ [ 30, 10 ], [ 20, 20 ], [ 30, 20 ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'LINESTRING (30 10, 20 20, 30 20)'); +}); + +test('should convert a MULTILINESTRING', function (t) { + t.plan(1); + + const input = { + type: 'MultiLineString', + coordinates: [ [ [ 30, 10 ], [ 20, 20 ], [ 30, 20 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTILINESTRING ((30 10, 20 20, 30 20))'); +}); + +test('should convert a MULTILINESTRING with Z', function (t) { + t.plan(1); + + const input = { + type: 'MultiLineString', + coordinates: [ [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTILINESTRING Z ((30 10 1, 20 20 2, 30 20 3))'); +}); + +test('should convert a MULTILINESTRING with Z and M', function (t) { + t.plan(1); + + const input = { + type: 'MultiLineString', + coordinates: [ [ [ 30, 10, 1, 2 ], [ 20, 20, 3, 4 ], [ 30, 20, 5, 6 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTILINESTRING ZM ((30 10 1 2, 20 20 3 4, 30 20 5 6))'); +}); + +test('should convert a MULTILINESTRING with M (nonstandard)', function (t) { + t.plan(1); + + const input = { + properties: { m: true }, + type: 'MultiLineString', + coordinates: [ [ [ 30, 10, 1 ], [ 20, 20, 2 ], [ 30, 20, 3 ] ] ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTILINESTRING M ((30 10 1, 20 20 2, 30 20 3))'); +}); + +test('should convert an empty MULTILINESTRING', function (t) { + t.plan(1); + + const input = { + type: 'MultiLineString', + coordinates: [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTILINESTRING EMPTY'); +}); + +test('should convert a MULTIPOLYGON', function (t) { + t.plan(1); + + const input = { 'type': 'MultiPolygon', + 'coordinates': [ + [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]], + [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] + ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOLYGON (((102 2, 103 2, 103 3, 102 3, 102 2)), ((100 0, 101 0, 101 1, 100 1, 100 0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))'); +}); + +test('should convert a MULTIPOLYGON with Z', function (t) { + t.plan(1); + + const input = { 'type': 'MultiPolygon', + 'coordinates': [ + [[[102.0, 2.0, 1], [103.0, 2.0, 2], [103.0, 3.0, 3], [102.0, 3.0, 4], [102.0, 2.0, 5]]], + [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] + ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOLYGON Z (((102 2 1, 103 2 2, 103 3 3, 102 3 4, 102 2 5)), ((100 0, 101 0, 101 1, 100 1, 100 0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))'); +}); + +test('should convert a MULTIPOLYGON with Z and M', function (t) { + t.plan(1); + + const input = { 'type': 'MultiPolygon', + 'coordinates': [ + [[[102.0, 2.0, 1, 2], [103.0, 2.0, 3, 4], [103.0, 3.0, 5, 6], [102.0, 3.0, 7, 8], [102.0, 2.0, 9, 10]]], + [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] + ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOLYGON ZM (((102 2 1 2, 103 2 3 4, 103 3 5 6, 102 3 7 8, 102 2 9 10)), ((100 0, 101 0, 101 1, 100 1, 100 0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))'); +}); + +test('should convert a MULTIPOLYGON with M (non standard)', function (t) { + t.plan(1); + + const input = { 'type': 'MultiPolygon', + properties: { m: true }, + 'coordinates': [ + [[[102.0, 2.0, 1], [103.0, 2.0, 2], [103.0, 3.0, 3], [102.0, 3.0, 4], [102.0, 2.0, 5]]], + [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], + [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] + ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOLYGON M (((102 2 1, 103 2 2, 103 3 3, 102 3 4, 102 2 5)), ((100 0, 101 0, 101 1, 100 1, 100 0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))'); +}); + +test('should convert an EMPTY MULTIPOLYGON', function (t) { + t.plan(1); + + const input = { + 'type': 'MultiPolygon', + 'coordinates': [ ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'MULTIPOLYGON EMPTY'); +}); + +test('should convert a Geometry Collection', function (t) { + t.plan(1); + + const input = { + 'type': 'GeometryCollection', + 'geometries': [ + { 'type': 'Point', + 'coordinates': [100.0, 0.0] + }, + { 'type': 'LineString', + 'coordinates': [ [101.0, 0.0], [102.0, 1.0] ] + } + ] + }; + + const output = geojsonToWKT(input); + + t.deepEqual(output, 'GEOMETRYCOLLECTION(POINT (100 0), LINESTRING (101 0, 102 1))'); +}); + +test('should fail a conversion on an unknown type', function (t) { + t.plan(1); + + const input = { + 'type': 'MultiPolygonLikeThingy', + 'coordinates': [ ] + }; + + try { + geojsonToWKT(input); + } catch (err) { + const error = err.toString(); + t.deepEqual(error, 'Error: Unknown Type: MultiPolygonLikeThingy'); + } +}); diff --git a/packages/wkt/test/wkt.test.js b/packages/wkt/test/wkt.test.js new file mode 100644 index 0000000..e06ba03 --- /dev/null +++ b/packages/wkt/test/wkt.test.js @@ -0,0 +1,606 @@ + +import test from 'tape'; +import { wktToGeoJSON } from '../index.js'; + +test('should exist', function (t) { + t.plan(1); + t.ok(wktToGeoJSON); +}); + +test('should parse a WKT POINT', function (t) { + t.plan(1); + + const input = 'POINT (30 10)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Point', + coordinates: [ 30, 10 ] + }); +}); + +test('should parse an empty WKT POINT', function (t) { + t.plan(1); + + const input = 'POINT EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Point', + coordinates: [ ] + }); +}); + +test('should parse a POINT with a Z coordinate', function (t) { + t.plan(1); + + const input = 'POINT Z (30 10 20)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + properties: { z: true }, + type: 'Point', + coordinates: [ 30, 10, 20 ] + }); +}); + +test('should parse a POINT with a M coordinate', function (t) { + t.plan(1); + + const input = 'POINT M (30 10 20)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + properties: { m: true }, + type: 'Point', + coordinates: [ 30, 10, 20 ] + }); +}); + +test('should parse a POINT with a Z and M coordinate', function (t) { + t.plan(1); + + const input = 'POINT ZM (30 10 20 15)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + properties: { + m: true, + z: true + }, + type: 'Point', + coordinates: [ 30, 10, 20, 15 ] + }); +}); + +test('should parse a POINT with scientific notation coordinates', function (t) { + t.plan(1); + + const input = 'POINT (30e0 10 2.0E+001 15)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Point', + coordinates: [ 30, 10, 20, 15 ] + }); +}); + +test('should parse a LINESTRING', function (t) { + t.plan(1); + + const input = 'LINESTRING (30 10, 10 30, 40 40)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'LineString', + coordinates: [ [30, 10], [10, 30], [40, 40] ] + }); +}); + +test('should parse an EMPTY LINESTRING', function (t) { + t.plan(1); + + const input = 'LINESTRING EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'LineString', + coordinates: [ ] + }); +}); + +test('should parse a LINESTRING with a Z coordinate', function (t) { + t.plan(1); + + const input = 'LINESTRING Z (30 10 5, 10 30 15, 40 40 25)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'LineString', + properties: { + z: true + }, + coordinates: [ [30, 10, 5], [10, 30, 15], [40, 40, 25] ] + }); +}); + +test('should parse a LINESTRING with an M coordinate', function (t) { + t.plan(1); + + const input = 'LINESTRING M (30 10 5, 10 30 15, 40 40 25)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'LineString', + properties: { + m: true + }, + coordinates: [ [30, 10, 5], [10, 30, 15], [40, 40, 25] ] + }); +}); + +test('should parse a LINESTRING with Z and M coordinates', function (t) { + t.plan(1); + + const input = 'LINESTRING ZM (30 10 5 2, 10 30 15 8, 40 40 25 16)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'LineString', + properties: { + z: true, + m: true + }, + coordinates: [ [30, 10, 5, 2], [10, 30, 15, 8], [40, 40, 25, 16] ] + }); +}); + +test('should parse a POLYGON', function (t) { + t.plan(1); + + const input = 'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + coordinates: [ [ [30, 10], [10, 20], [20, 40], [40, 40], [30, 10] ] ] + }); +}); + +test('should parse an empty POLYGON', function (t) { + t.plan(1); + + const input = 'POLYGON EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + coordinates: [ ] + }); +}); + +test('should parse a POLYGON with a Z coordinate', function (t) { + t.plan(1); + + const input = 'POLYGON Z ((30 10 4, 10 20 6, 20 40 8, 40 40 1, 30 10 3))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + properties: { + z: true + }, + coordinates: [ [ [30, 10, 4], [10, 20, 6], [20, 40, 8], [40, 40, 1], [30, 10, 3] ] ] + }); +}); + +test('should parse a POLYGON with an M coordinate', function (t) { + t.plan(1); + + const input = 'POLYGON M ((30 10 4, 10 20 6, 20 40 8, 40 40 1, 30 10 3))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + properties: { + m: true + }, + coordinates: [ [ [30, 10, 4], [10, 20, 6], [20, 40, 8], [40, 40, 1], [30, 10, 3] ] ] + }); +}); + +test('should parse a POLYGON with a Z and M coordinate', function (t) { + t.plan(1); + + const input = 'POLYGON ZM ((30 10 4 1, 10 20 6 3, 20 40 8 5, 40 40 1 7, 30 10 3 9))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + properties: { + m: true, + z: true + }, + coordinates: [ [ [30, 10, 4, 1], [10, 20, 6, 3], [20, 40, 8, 5], [40, 40, 1, 7], [30, 10, 3, 9] ] ] + }); +}); + +test('should parse a POLYGON with a hole', function (t) { + t.plan(1); + + const input = 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'Polygon', + coordinates: [ + [ [35, 10], [10, 20], [15, 40], [45, 45], [35, 10] ], + [ [20, 30], [35, 35], [30, 20], [20, 30] ] + ] + }); +}); + +test('should parse a MULTIPOINT', function (t) { + t.plan(1); + + const input = 'MULTIPOINT ((10 40), (40 30), (20 20), (30 10))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + coordinates: [ + [10, 40], [40, 30], [20, 20], [30, 10] + ] + }); +}); + +test('should parse an EMPTY MULTIPOINT', function (t) { + t.plan(1); + + const input = 'MULTIPOINT EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + coordinates: [ ] + }); +}); + +test('should parse a MULTIPOINT with a Z coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOINT Z ((10 40 1), (40 30 2), (20 20 3), (30 10 4))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + z: true + }, + coordinates: [ [10, 40, 1], [40, 30, 2], [20, 20, 3], [30, 10, 4] ] + }); +}); + +test('should parse a MULTIPOINT with an M coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOINT M ((10 40 1), (40 30 2), (20 20 3), (30 10 4))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + m: true + }, + coordinates: [ [10, 40, 1], [40, 30, 2], [20, 20, 3], [30, 10, 4] ] + }); +}); + +test('should parse a MULTIPOINT with a Z and M coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOINT ZM ((10 40 1 8), (40 30 2 9), (20 20 3 8), (30 10 4 9))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + m: true, + z: true + }, + coordinates: [ [10, 40, 1, 8], [40, 30, 2, 9], [20, 20, 3, 8], [30, 10, 4, 9] ] + }); +}); + +test('should parse a MULTIPOINT with alternate syntax', function (t) { + t.plan(1); + + const input = 'MULTIPOINT (10 40, 40 30, 20 20, 30 10)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + coordinates: [ [10, 40], [40, 30], [20, 20], [30, 10] ] + }); +}); + +test('should parse a MULTIPOINT with alternate syntax and Z coordinates', function (t) { + t.plan(1); + + const input = 'MULTIPOINT Z (10 40 1, 40 30 2, 20 20 3, 30 10 4)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + z: true + }, + coordinates: [ [10, 40, 1], [40, 30, 2], [20, 20, 3], [30, 10, 4] ] + }); +}); + +test('should parse a MULTIPOINT with alternate syntax and M coordinates', function (t) { + t.plan(1); + + const input = 'MULTIPOINT M (10 40 1, 40 30 2, 20 20 3, 30 10 4)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + m: true + }, + coordinates: [ [10, 40, 1], [40, 30, 2], [20, 20, 3], [30, 10, 4] ] + }); +}); + +test('should parse a MULTIPOINT with alternate syntax and Z and M coordinates', function (t) { + t.plan(1); + + const input = 'MULTIPOINT ZM (10 40 1 2, 40 30 2 3, 20 20 3 4, 30 10 4 5)'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPoint', + properties: { + m: true, + z: true + }, + coordinates: [ [10, 40, 1, 2], [40, 30, 2, 3], [20, 20, 3, 4], [30, 10, 4, 5] ] + }); +}); + +test('should parse a MULTILINESTRING with alternate syntax', function (t) { + t.plan(1); + + const input = 'MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiLineString', + coordinates: [ [ [10, 10], [20, 20], [10, 40] ], + [ [40, 40], [30, 30], [40, 20], [30, 10] ] ] + }); +}); + +test('should parse a MULTILINESTRING with alternate syntax', function (t) { + t.plan(1); + + const input = 'MULTILINESTRING EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiLineString', + coordinates: [ ] + }); +}); + +test('should parse a MULTILINESTRING with alternate syntax and Z coordinates', function (t) { + t.plan(1); + + const input = 'MULTILINESTRING Z ((10 10 10, 20 20 20, 10 40 30),(40 40 30, 30 30 20, 40 20 10, 30 10 10))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiLineString', + properties: { + z: true + }, + coordinates: [ + [ [10, 10, 10], [20, 20, 20], [10, 40, 30] ], + [ [40, 40, 30], [30, 30, 20], [40, 20, 10], [30, 10, 10] ] + ] + }); +}); + +test('should parse a MULTILINESTRING with alternate syntax and M coordinates', function (t) { + t.plan(1); + + const input = 'MULTILINESTRING M ((10 10 10, 20 20 20, 10 40 30),(40 40 30, 30 30 20, 40 20 10, 30 10 10))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiLineString', + properties: { + m: true + }, + coordinates: [ + [ [10, 10, 10], [20, 20, 20], [10, 40, 30] ], + [ [40, 40, 30], [30, 30, 20], [40, 20, 10], [30, 10, 10] ] + ] + }); +}); + +test('should parse a MULTILINESTRING with alternate syntax and Z and M coordinates', function (t) { + t.plan(1); + + const input = 'MULTILINESTRING ZM ((10 10 10 5, 20 20 20 4, 10 40 30 3),(40 40 30 2, 30 30 20 1, 40 20 10 2, 30 10 10 3))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiLineString', + properties: { + z: true, + m: true + }, + coordinates: [ + [ [10, 10, 10, 5], [20, 20, 20, 4], [10, 40, 30, 3] ], + [ [40, 40, 30, 2], [30, 30, 20, 1], [40, 20, 10, 2], [30, 10, 10, 3] ] + ] + }); +}); + +test('should parse a MULTIPOLYGON', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + coordinates: [ + [ + [ [30, 20], [10, 40], [45, 40], [30, 20] ] + ], + [ + [ [15, 5], [40, 10], [10, 20], [5, 10], [15, 5] ] + ] + ] + }); +}); + +test('should parse an empty MULTIPOLYGON', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON EMPTY'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + coordinates: [ ] + }); +}); + +test('should parse a MULTIPOLYGON with a Z coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON Z (((30 20 1, 10 40 2, 45 40 3, 30 20 4)),((15 5, 40 10, 10 20, 5 10, 15 5)))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + properties: { + z: true + }, + coordinates: [ + [ + [ [30, 20, 1], [10, 40, 2], [45, 40, 3], [30, 20, 4] ] + ], + [ + [ [15, 5], [40, 10], [10, 20], [5, 10], [15, 5] ] + ] + ] + }); +}); + +test('should parse a MULTIPOLYGON with a M coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON M (((30 20 1, 10 40 2, 45 40 3, 30 20 4)),((15 5, 40 10, 10 20, 5 10, 15 5)))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + properties: { + m: true + }, + coordinates: [ + [ + [ [30, 20, 1], [10, 40, 2], [45, 40, 3], [30, 20, 4] ] + ], + [ + [ [15, 5], [40, 10], [10, 20], [5, 10], [15, 5] ] + ] + ] + }); +}); + +test('should parse a MULTIPOLYGON with a Z and M coordinate', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON ZM (((30 20 1 0, 10 40 2 1, 45 40 3 2, 30 20 4 3)),((15 5, 40 10, 10 20, 5 10, 15 5)))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + properties: { + m: true, + z: true + }, + coordinates: [ + [ + [ [30, 20, 1, 0], [10, 40, 2, 1], [45, 40, 3, 2], [30, 20, 4, 3] ] + ], + [ + [ [15, 5], [40, 10], [10, 20], [5, 10], [15, 5] ] + ] + ] + }); +}); + +test('should parse a MULTIPOLYGON with a hole', function (t) { + t.plan(1); + + const input = 'MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20)))'; + + const output = wktToGeoJSON(input); + + t.deepEqual(output, { + type: 'MultiPolygon', + coordinates: [ + [ + [ [40, 40], [20, 45], [45, 30], [40, 40] ] + ], + [ + [ [20, 35], [45, 20], [30, 5], [10, 10], [10, 30], [20, 35] ], + [ [30, 20], [20, 25], [20, 15], [30, 20] ] + ] + ] + }); +}); diff --git a/packages/wkt/wkt.js b/packages/wkt/wkt.js new file mode 100644 index 0000000..b7cee6b --- /dev/null +++ b/packages/wkt/wkt.js @@ -0,0 +1,334 @@ +/* global parser */ // via jison + +/* Copyright (c) 2012-2019 Environmental Systems Research Institute, Inc. + * MIT */ + +/** @module @terraformer/wkt */ + +'SOURCE'; + +function PointArray (point) { + this.data = [ point ]; + this.type = 'PointArray'; +} + +PointArray.prototype.addPoint = function (point) { + if (point.type === 'PointArray') { + this.data = this.data.concat(point.data); + } else { + this.data.push(point); + } + + return this; +}; + +PointArray.prototype.toJSON = function () { + return this.data; +}; + +function Ring (point) { + this.data = point; + this.type = 'Ring'; +} + +Ring.prototype.toJSON = function () { + var data = [ ]; + + for (var i = 0; i < this.data.data.length; i++) { + data.push(this.data.data[i]); + } + + return data; +}; + +function RingList (ring) { + this.data = [ ring ]; + this.type = 'RingList'; +} + +RingList.prototype.addRing = function (ring) { + this.data.push(ring); + + return this; +}; + +RingList.prototype.toJSON = function () { + var data = [ ]; + + for (var i = 0; i < this.data.length; i++) { + data.push(this.data[i].toJSON()); + } + + if (data.length === 1) { + return data; + } else { + return data; + } +}; + +function PolygonList (polygon) { + this.data = [ polygon ]; + this.type = 'PolygonList'; +} + +PolygonList.prototype.addPolygon = function (polygon) { + this.data.push(polygon); + + return this; +}; + +PolygonList.prototype.toJSON = function () { + var data = [ ]; + + for (var i = 0; i < this.data.length; i++) { + data = data.concat([ this.data[i].toJSON() ]); + } + + return data; +}; + +/** + * Converts a [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) geometry into a GeoJSON geometry. + * @function + * @param {string} WKT - The input WKT geometry. + * @return {object} GeoJSON. + * + * ```js + * import { wktToGeoJSON } from "@terraformer/wkt" + * + * wktToGeoJSON("POINT (-122.6764, 45.5165)"); + * + * >> { "type": "Point", "coordinates": [ -122.6764, 45.5165 ] } + * ``` + */ +export const wktToGeoJSON = (element) => { + let res; + + try { + res = parser.parse(element); + } catch (err) { + throw Error('Unable to parse: ' + err); + } + + return res; +}; + +const arrayToRing = (arr) => { + let parts = [ ]; + let ret = ''; + + for (var i = 0; i < arr.length; i++) { + parts.push(arr[i].join(' ')); + } + + ret += '(' + parts.join(', ') + ')'; + + return ret; +}; + +const pointToWKTPoint = (geojson) => { + let ret = 'POINT '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates.length === 3) { + // 3d or time? default to 3d + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates.length === 4) { + // 3d and time + ret += 'ZM '; + } + + // include coordinates + ret += '(' + geojson.coordinates.join(' ') + ')'; + + return ret; +}; + +const lineStringToWKTLineString = (geojson) => { + let ret = 'LINESTRING '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0 || geojson.coordinates[0].length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates[0].length === 3) { + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates[0].length === 4) { + ret += 'ZM '; + } + + ret += arrayToRing(geojson.coordinates); + + return ret; +}; + +const polygonToWKTPolygon = (geojson) => { + let ret = 'POLYGON '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0 || geojson.coordinates[0].length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates[0][0].length === 3) { + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates[0][0].length === 4) { + ret += 'ZM '; + } + + ret += '('; + var parts = [ ]; + for (var i = 0; i < geojson.coordinates.length; i++) { + parts.push(arrayToRing(geojson.coordinates[i])); + } + + ret += parts.join(', '); + ret += ')'; + + return ret; +}; + +const multiPointToWKTMultiPoint = (geojson) => { + var ret = 'MULTIPOINT '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0 || geojson.coordinates[0].length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates[0].length === 3) { + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates[0].length === 4) { + ret += 'ZM '; + } + + ret += arrayToRing(geojson.coordinates); + + return ret; +}; + +const multiLineStringToWKTMultiLineString = (geojson) => { + let ret = 'MULTILINESTRING '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0 || geojson.coordinates[0].length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates[0][0].length === 3) { + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates[0][0].length === 4) { + ret += 'ZM '; + } + + ret += '('; + let parts = [ ]; + for (var i = 0; i < geojson.coordinates.length; i++) { + parts.push(arrayToRing(geojson.coordinates[i])); + } + + ret += parts.join(', '); + ret += ')'; + + return ret; +}; + +const multiPolygonToWKTMultiPolygon = (geojson) => { + var ret = 'MULTIPOLYGON '; + + if (geojson.coordinates === undefined || geojson.coordinates.length === 0 || geojson.coordinates[0].length === 0) { + ret += 'EMPTY'; + + return ret; + } else if (geojson.coordinates[0][0][0].length === 3) { + if (geojson.properties && geojson.properties.m === true) { + ret += 'M '; + } else { + ret += 'Z '; + } + } else if (geojson.coordinates[0][0][0].length === 4) { + ret += 'ZM '; + } + + ret += '('; + var inner = [ ]; + for (var c = 0; c < geojson.coordinates.length; c++) { + var it = '('; + var parts = [ ]; + for (var i = 0; i < geojson.coordinates[c].length; i++) { + parts.push(arrayToRing(geojson.coordinates[c][i])); + } + + it += parts.join(', '); + it += ')'; + + inner.push(it); + } + + ret += inner.join(', '); + ret += ')'; + + return ret; +}; + +/** + * Converts a GeoJSON geometry or GeometryCollection into a [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) string. + * @function + * @param {object} GeoJSON - The input GeoJSON geometry or GeometryCollection. + * @return {string} WKT. + * ```js + * import { geojsonToWKT } from "@terraformer/wkt" + * + * geojsonToWKT({ + * "type": "Point", + * "coordinates": [-122.6764, 45.5165] + * }) + * + * >> "POINT (-122.6764, 45.5165)" + * ``` + */ +export const geojsonToWKT = (geojson) => { + switch (geojson.type) { + case 'Point': + return pointToWKTPoint(geojson); + case 'LineString': + return lineStringToWKTLineString(geojson); + case 'Polygon': + return polygonToWKTPolygon(geojson); + case 'MultiPoint': + return multiPointToWKTMultiPoint(geojson); + case 'MultiLineString': + return multiLineStringToWKTMultiLineString(geojson); + case 'MultiPolygon': + return multiPolygonToWKTMultiPolygon(geojson); + case 'GeometryCollection': + var ret = 'GEOMETRYCOLLECTION'; + var parts = [ ]; + for (let i = 0; i < geojson.geometries.length; i++) { + parts.push(geojsonToWKT(geojson.geometries[i])); + } + return ret + '(' + parts.join(', ') + ')'; + default: + throw Error('Unknown Type: ' + geojson.type); + } +}; diff --git a/packages/wkt/wkt.yy b/packages/wkt/wkt.yy new file mode 100644 index 0000000..cc58897 --- /dev/null +++ b/packages/wkt/wkt.yy @@ -0,0 +1,178 @@ + + +%lex + +%% + +\s+ // ignore +"(" return '(' +")" return ')' +"-"?[0-9]+("."[0-9]+)?([eE][\-\+]?[0-9]+)? return 'DOUBLE_TOK' +"POINT" return 'POINT' +"LINESTRING" return 'LINESTRING' +"POLYGON" return 'POLYGON' +"MULTIPOINT" return 'MULTIPOINT' +"MULTILINESTRING" return 'MULTILINESTRING' +"MULTIPOLYGON" return 'MULTIPOLYGON' +"," return 'COMMA' +"EMPTY" return 'EMPTY' +"M" return 'M' +"Z" return 'Z' +"ZM" return 'ZM' +<> return 'EOF' +. return "INVALID" + +/lex + + +%start expressions + +%% /* language grammar */ + +expressions + : point EOF + { return $1; } + | linestring EOF + { return $1; } + | polygon EOF + { return $1; } + | multipoint EOF + { return $1; } + | multilinestring EOF + { return $1; } + | multipolygon EOF + { return $1; } + ; + +coordinate + : DOUBLE_TOK DOUBLE_TOK + { $$ = new PointArray([ Number($1), Number($2) ]); } + | DOUBLE_TOK DOUBLE_TOK DOUBLE_TOK + { $$ = new PointArray([ Number($1), Number($2), Number($3) ]); } + | DOUBLE_TOK DOUBLE_TOK DOUBLE_TOK DOUBLE_TOK + { $$ = new PointArray([ Number($1), Number($2), Number($3), Number($4) ]); } + ; + +ptarray + : ptarray COMMA coordinate + { $$ = $1.addPoint($3); } + | coordinate + { $$ = $1; } + ; + +ring_list + : ring_list COMMA ring + { $$ = $1.addRing($3); } + | ring + { $$ = new RingList($1); } + ; + +ring + : '(' ptarray ')' + { $$ = new Ring($2); } + ; + +point + : POINT '(' ptarray ')' + { $$ = { "type": "Point", "coordinates": $3.data[0] }; } + | POINT Z '(' ptarray ')' + { $$ = { "type": "Point", "coordinates": $4.data[0], "properties": { z: true } }; } + | POINT ZM '(' ptarray ')' + { $$ = { "type": "Point", "coordinates": $4.data[0], "properties": { z: true, m: true } }; } + | POINT M '(' ptarray ')' + { $$ = { "type": "Point", "coordinates": $4.data[0], "properties": { m: true } }; } + | POINT EMPTY + { $$ = { "type": "Point", "coordinates": [ ] }; } + ; + +point_untagged + : coordinate + { $$ = $1; } + | '(' coordinate ')' + { $$ = $2; } + ; + +polygon_list + : polygon_list COMMA polygon_untagged + { $$ = $1.addPolygon($3); } + | polygon_untagged + { $$ = new PolygonList($1); } + ; + +polygon_untagged + : '(' ring_list ')' + { $$ = $2; } + ; + + +point_list + : point_list COMMA point_untagged + { $$ = $1.addPoint($3); } + | point_untagged + { $$ = $1; } + ; + +linestring + : LINESTRING '(' point_list ')' + { $$ = { "type": "LineString", "coordinates": $3.data }; } + | LINESTRING Z '(' point_list ')' + { $$ = { "type": "LineString", "coordinates": $4.data, "properties": { z: true } }; } + | LINESTRING M '(' point_list ')' + { $$ = { "type": "LineString", "coordinates": $4.data, "properties": { m: true } }; } + | LINESTRING ZM '(' point_list ')' + { $$ = { "type": "LineString", "coordinates": $4.data, "properties": { z: true, m: true } }; } + | LINESTRING EMPTY + { $$ = { "type": "LineString", "coordinates": [ ] }; } + ; + +polygon + : POLYGON '(' ring_list ')' + { $$ = { "type": "Polygon", "coordinates": $3.toJSON() }; } + | POLYGON Z '(' ring_list ')' + { $$ = { "type": "Polygon", "coordinates": $4.toJSON(), "properties": { z: true } }; } + | POLYGON M '(' ring_list ')' + { $$ = { "type": "Polygon", "coordinates": $4.toJSON(), "properties": { m: true } }; } + | POLYGON ZM '(' ring_list ')' + { $$ = { "type": "Polygon", "coordinates": $4.toJSON(), "properties": { z: true, m: true } }; } + | POLYGON EMPTY + { $$ = { "type": "Polygon", "coordinates": [ ] }; } + ; + +multipoint + : MULTIPOINT '(' point_list ')' + { $$ = { "type": "MultiPoint", "coordinates": $3.data }; } + | MULTIPOINT Z '(' point_list ')' + { $$ = { "type": "MultiPoint", "coordinates": $4.data, "properties": { z: true } }; } + | MULTIPOINT M '(' point_list ')' + { $$ = { "type": "MultiPoint", "coordinates": $4.data, "properties": { m: true } }; } + | MULTIPOINT ZM '(' point_list ')' + { $$ = { "type": "MultiPoint", "coordinates": $4.data, "properties": { z: true, m: true } }; } + | MULTIPOINT EMPTY + { $$ = { "type": "MultiPoint", "coordinates": [ ] } } + ; + +multilinestring + : MULTILINESTRING '(' ring_list ')' + { $$ = { "type": "MultiLineString", "coordinates": $3.toJSON() }; } + | MULTILINESTRING Z '(' ring_list ')' + { $$ = { "type": "MultiLineString", "coordinates": $4.toJSON(), "properties": { z: true } }; } + | MULTILINESTRING M '(' ring_list ')' + { $$ = { "type": "MultiLineString", "coordinates": $4.toJSON(), "properties": { m: true } }; } + | MULTILINESTRING ZM '(' ring_list ')' + { $$ = { "type": "MultiLineString", "coordinates": $4.toJSON(), "properties": { z: true, m: true } }; } + | MULTILINESTRING EMPTY + { $$ = { "type": "MultiLineString", "coordinates": [ ] }; } + ; + +multipolygon + : MULTIPOLYGON '(' polygon_list ')' + { $$ = { "type": "MultiPolygon", "coordinates": $3.toJSON() }; } + | MULTIPOLYGON Z '(' polygon_list ')' + { $$ = { "type": "MultiPolygon", "coordinates": $4.toJSON(), "properties": { z: true } }; } + | MULTIPOLYGON M '(' polygon_list ')' + { $$ = { "type": "MultiPolygon", "coordinates": $4.toJSON(), "properties": { m: true } }; } + | MULTIPOLYGON ZM '(' polygon_list ')' + { $$ = { "type": "MultiPolygon", "coordinates": $4.toJSON(), "properties": { z: true, m: true } }; } + | MULTIPOLYGON EMPTY + { $$ = { "type": "MultiPolygon", "coordinates": [ ] }; } + ; \ No newline at end of file