UNPKG

wael-lib

Version:

Well-Known Text Arithmetic Expression Language

1,438 lines (1,384 loc) 74.3 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // package.json var require_package = __commonJS({ "package.json"(exports2, module2) { module2.exports = { name: "wael-lib", version: "0.0.14", description: "Well-Known Text Arithmetic Expression Language", repository: { type: "git", url: "git+https://github.com/anthonydgj/wael.git" }, files: [ "dist", "examples" ], browser: { fs: false, path: false, os: false }, type: "commonjs", main: "dist/cjs/index.cjs", module: "dist/esm/index.mjs", types: "dist/cjs/index.d.ts", exports: { "./package.json": "./package.json", ".": { import: { types: "./dist/esm/index.d.mts", default: "./dist/esm/index.mjs" }, require: { types: "./dist/cjs/index.d.ts", default: "./dist/cjs/index.cjs" } } }, scripts: { build: "tsup --config ./tsup.config.ts", "build-all": "npm run build-binary && npm run build-release-binaries", "build-binary": 'npm run build && pkg ./dist/wael/wael.cjs -t=latest --no-bytecode --public-packages "*" --public --out-path dist/bin/', "build-release-binaries": 'pkg ./dist/wael/wael.cjs -t=latest,latest-macos-arm64,latest-linuxstatic-x64,latest-win-x64 --no-bytecode --public-packages "*" --public --out-path dist/bin/release/', test: "jest", "publish-lib": "npm run build && npm test && npm publish" }, author: "AnthonyDGJ", license: "MIT", devDependencies: { "@types/geojson": "^7946.0.16", "@types/jest": "^29.5.14", "@types/sync-fetch": "^0.4.3", "@types/wellknown": "^0.5.8", jest: "^29.7.0", pkg: "^5.8.1", "ts-jest": "^29.3.2", "ts-node": "^10.9.2", tsup: "^8.4.0", typescript: "^5.8.3" }, dependencies: { "@turf/turf": "^7.2.0", chalk: "^4.1.2", fs: "^0.0.1-security", "ohm-js": "^17.1.0", "sync-fetch": "^0.6.0-2", tslib: "^2.8.1", wellknown: "^0.5.0", yargs: "^17.7.2" }, keywords: [ "wkt", "well-known text", "ohm", "dsl", "domain-specific language", "geospatial" ] }; } }); // scripts/wael.ts var fs = __toESM(require("fs")); // src/main.ts var turf4 = __toESM(require("@turf/turf")); var wellknown = __toESM(require("wellknown")); // src/interpreter/interpreter.ts var ohm = __toESM(require("ohm-js")); var turf3 = __toESM(require("@turf/turf")); // src/interpreter/types.ts var GeometryType = /* @__PURE__ */ ((GeometryType2) => { GeometryType2["Point"] = "Point"; GeometryType2["LineString"] = "LineString"; GeometryType2["Polygon"] = "Polygon"; GeometryType2["MultiPoint"] = "MultiPoint"; GeometryType2["MultiLineString"] = "MultiLineString"; GeometryType2["MultiPolygon"] = "MultiPolygon"; GeometryType2["GeometryCollection"] = "GeometryCollection"; return GeometryType2; })(GeometryType || {}); var UNIT = null; // src/interpreter/helpers.ts var turf = __toESM(require("@turf/turf")); var isAnyGeometryType = /* @__PURE__ */ __name((value) => { const types = Object.values(GeometryType); for (const type of types) { if (isGeometryType(type, value)) { return true; } } return false; }, "isAnyGeometryType"); var isGeometryType = /* @__PURE__ */ __name((type, ...values) => { var _a2; for (const value of values) { const isType2 = typeof value === "object" && (value == null ? void 0 : value.type) === type || ((_a2 = value == null ? void 0 : value.geometry) == null ? void 0 : _a2.type) === type; if (!isType2) { return false; } } return true; }, "isGeometryType"); var getGeometryType = /* @__PURE__ */ __name((value, isForDisplay = false) => { var _a2; if (typeof value === "object") { const type = ((_a2 = value == null ? void 0 : value.geometry) == null ? void 0 : _a2.type) || (value == null ? void 0 : value.type); if (isForDisplay && type === "GeometryCollection" /* GeometryCollection */) { return "GeometryCollection" /* GeometryCollection */; } return type; } return void 0; }, "getGeometryType"); var getArrayLikeItems = /* @__PURE__ */ __name((value) => { if (isGeometryType("LineString" /* LineString */, value) || isGeometryType("MultiPoint" /* MultiPoint */, value)) { return value.coordinates; } else if (isGeometryType("GeometryCollection" /* GeometryCollection */, value)) { return value.geometries; } return void 0; }, "getArrayLikeItems"); var isNumber = /* @__PURE__ */ __name((...values) => { return isType("number", ...values); }, "isNumber"); var isType = /* @__PURE__ */ __name((type, ...values) => { for (const value of values) { const isType2 = typeof value === type; if (!isType2) { return false; } } return true; }, "isType"); var arithmeticOperationExp = /* @__PURE__ */ __name((a, b, op) => { return arithmeticOperation(a.eval(), b.eval(), op); }, "arithmeticOperationExp"); var arithmeticOperation = /* @__PURE__ */ __name((A, B, op) => { if (isNumber(A, B)) { return op(A, B); } if (isNumber(A) && isAnyGeometryType(B)) { return arithmeticOperation(turf.point([A, A]).geometry, B, op); } if (isNumber(B) && isAnyGeometryType(A)) { return arithmeticOperation(A, turf.point([B, B]).geometry, op); } if (isGeometryType("Point" /* Point */, A, B)) { return pointOperation(A, B, op); } if (isGeometryType("LineString" /* LineString */, A, B)) { return lineStringOperation(A, B, op); } if (isGeometryType("MultiPoint" /* MultiPoint */, A, B)) { return multiPointOperation(A, B, op); } if (isGeometryType("Point" /* Point */, A)) { return transform(B, (b) => pointOperation(A, b, op)); } if (isGeometryType("Point" /* Point */, B)) { return transform(A, (a) => pointOperation(a, B, op)); } return void 0; }, "arithmeticOperation"); var pointOperation = /* @__PURE__ */ __name((A, B, computeFn) => { return turf.point([ computeFn(A.coordinates[0], B.coordinates[0]), computeFn(A.coordinates[1], B.coordinates[1]) ]).geometry; }, "pointOperation"); var lineStringOperation = /* @__PURE__ */ __name((A, B, computeFn) => { return turf.lineString(A.coordinates.map((p, index) => { return [ computeFn(p[0], B.coordinates[index][0]), computeFn(p[1], B.coordinates[index][1]) ]; })).geometry; }, "lineStringOperation"); var multiPointOperation = /* @__PURE__ */ __name((A, B, computeFn) => { return turf.multiPoint(A.coordinates.map((p, index) => { return [ computeFn(p[0], B.coordinates[index][0]), computeFn(p[1], B.coordinates[index][1]) ]; })).geometry; }, "multiPointOperation"); var _OperationNotSupported = class _OperationNotSupported extends Error { constructor(message) { super(`Operation not supported: ${message}`); } }; __name(_OperationNotSupported, "OperationNotSupported"); var OperationNotSupported = _OperationNotSupported; function toString(value) { try { return `${JSON.stringify(value)}`; } catch (err) { return `${value}`; } } __name(toString, "toString"); function transformPoints(coords, coordsMapFn) { if (!!coords) { if (Array.isArray(coords)) { if (coords.length > 0) { const firstElement = coords[0]; if (Array.isArray(firstElement)) { return coords.map((c) => transformPoints(c, coordsMapFn)); } else { const point4 = turf.point(coords).geometry; return coordsMapFn(point4).coordinates; } } } } return coords; } __name(transformPoints, "transformPoints"); function transform(geoJson, coordsMapFn) { if (!!geoJson) { if (!!geoJson.features) { return __spreadProps(__spreadValues({}, geoJson), { features: geoJson.features.map((feature3) => transform(feature3, coordsMapFn)) }); } if (!!geoJson.geometries) { return __spreadProps(__spreadValues({}, geoJson), { geometries: geoJson.geometries.map((geometry2) => transform(geometry2, coordsMapFn)) }); } const geometry = geoJson.geometry; if (!!geometry) { if (geoJson.coordinates) { return __spreadProps(__spreadValues({}, geoJson), { geometry: __spreadProps(__spreadValues({}, geometry), { coordinates: transformPoints(geometry.coordinates, coordsMapFn) }) }); } } const coordinates = geoJson.coordinates; if (!!coordinates) { return __spreadProps(__spreadValues({}, geoJson), { coordinates: transformPoints(coordinates, coordsMapFn) }); } } return geoJson; } __name(transform, "transform"); function convertToGeometry(json) { if (json.type === "Feature") { return json.geometry; } else if (json.type === "FeatureCollection") { return { type: "GeometryCollection", geometries: json.features.map((f) => convertToGeometry(f)) }; } else if (Array.isArray(json)) { return { type: "GeometryCollection", geometries: json.map((f) => convertToGeometry(f)) }; } return json; } __name(convertToGeometry, "convertToGeometry"); function geometryAccessor(v, p, params) { const value = v.eval(); const property = p.sourceString; if (!isAnyGeometryType(value)) { throw new Error(`Expected a geometry type for value "${v.sourceString}" but got: ${toString(value)}`); } switch (property.toLocaleLowerCase()) { case "type": if ((params == null ? void 0 : params.length) > 1) { throw new Error(`Expected no parameters for "${property}" for ${v.sourceString}`); } return getGeometryType(value, true); } if (isGeometryType("Point" /* Point */, value)) { switch (property.toLocaleLowerCase()) { case "x": if ((params == null ? void 0 : params.length) > 0) { if (params.length === 1) { return turf.point([ params[0], value.coordinates[1] ]).geometry; } throw Error(`Expected one value in "${property}" setter for "${v.sourceString}" but got: ${toString(params)}`); } return value.coordinates[0]; case "y": if ((params == null ? void 0 : params.length) > 0) { if (params.length === 1) { return turf.point([ value.coordinates[0], params[0] ]).geometry; } throw Error(`Expected one value in "${property}" setter for "${v.sourceString}" but got: ${toString(params)}`); } return value.coordinates[1]; } } else if (isGeometryType("GeometryCollection" /* GeometryCollection */, value)) { switch (property.toLocaleLowerCase()) { case "geometryn": if (params.length === 1) { const index = parseInt(params[0]); return value.geometries[index]; } throw Error(`Expected one value in "${property}" setter for "${v.sourceString}" but got: ${toString(params)}`); case "numgeometries": return value.geometries.length; } } else if (isGeometryType("LineString" /* LineString */, value)) { switch (property.toLocaleLowerCase()) { case "pointn": if (params.length === 1) { const index = parseInt(params[0]); return turf.point(value.coordinates[index]).geometry; } throw Error(`Expected one value in "${property}" setter for "${v.sourceString}" but got: ${toString(params)}`); case "numpoints": return value.coordinates.length; } } throw new Error(`Property "${property}" not accessible on object: ${toString(value)}`); } __name(geometryAccessor, "geometryAccessor"); // src/interpreter/scope.ts var _Scope = class _Scope { constructor(parent, level = 0, defaultBindings = {}) { this.parent = parent; this.level = level; this.bindings = {}; this.availableBindings = {}; this.metadata = {}; for (const identifier in defaultBindings) { if (defaultBindings.hasOwnProperty(identifier)) { this.store(identifier, defaultBindings[identifier]); } } } store(identifier, value, metadata, searchParentChain = true) { let scope = this; if (searchParentChain) { const resolvedScope = this.resolveScope(identifier); if (resolvedScope) { scope = resolvedScope; } scope.store(identifier, value, metadata, false); return; } this.bindings[identifier] = value; if (metadata) { this.metadata[identifier] = metadata; } } resolveScope(identifier) { if (this.bindings.hasOwnProperty(identifier)) { return this; } if (this.parent) { return this.parent.resolveScope(identifier); } return void 0; } resolve(identifier) { var _a2; const scope = (_a2 = this.resolveScope(identifier)) != null ? _a2 : this; return scope.bindings[identifier]; } push(extraBindings) { return new _Scope(this, this.level + 1, extraBindings); } pop(additionalBindings) { var _a2; const exportedBindings = __spreadValues({}, additionalBindings); for (const identifier in this.metadata) { const metadata = this.metadata[identifier]; if (metadata && metadata.public) { exportedBindings[identifier] = this.bindings[identifier]; } } (_a2 = this.parent) == null ? void 0 : _a2.import(exportedBindings); return this.parent; } import(scopeBindings) { this.availableBindings = __spreadValues(__spreadValues({}, this.availableBindings), scopeBindings); } useImports(selectedIdentifiers) { let selectedBindings = {}; if (selectedIdentifiers) { selectedIdentifiers.forEach((selectedIdentifier) => { selectedBindings[selectedIdentifier] = this.availableBindings[selectedIdentifier]; }); } else { selectedBindings = this.availableBindings; } this.availableBindings = {}; return selectedBindings; } useNamedImports(selectedIdentifiers) { let selectedBindings = {}; if (selectedIdentifiers) { selectedIdentifiers.forEach((selectedIdentifier) => { selectedBindings[selectedIdentifier] = this.availableBindings[selectedIdentifier]; }); } this.bindings = __spreadValues(__spreadValues({}, this.bindings), selectedBindings); return selectedBindings; } }; __name(_Scope, "Scope"); var Scope = _Scope; // src/interpreter/built-in-functions.ts var turf2 = __toESM(require("@turf/turf")); // node_modules/geojson-equality-ts/dist/esm/index.js var __defProp2 = Object.defineProperty; var __name2 = /* @__PURE__ */ __name((target, value) => __defProp2(target, "name", { value, configurable: true }), "__name"); var _a; var _GeojsonEquality = (_a = class { constructor(opts) { this.direction = false; this.compareProperties = true; var _a2, _b, _c; this.precision = 10 ** -((_a2 = opts == null ? void 0 : opts.precision) != null ? _a2 : 17); this.direction = (_b = opts == null ? void 0 : opts.direction) != null ? _b : false; this.compareProperties = (_c = opts == null ? void 0 : opts.compareProperties) != null ? _c : true; } compare(g1, g2) { if (g1.type !== g2.type) { return false; } if (!sameLength(g1, g2)) { return false; } switch (g1.type) { case "Point": return this.compareCoord(g1.coordinates, g2.coordinates); case "LineString": return this.compareLine(g1.coordinates, g2.coordinates); case "Polygon": return this.comparePolygon(g1, g2); case "GeometryCollection": return this.compareGeometryCollection(g1, g2); case "Feature": return this.compareFeature(g1, g2); case "FeatureCollection": return this.compareFeatureCollection(g1, g2); default: if (g1.type.startsWith("Multi")) { const g1s = explode(g1); const g2s = explode( g2 ); return g1s.every( (g1part) => g2s.some((g2part) => this.compare(g1part, g2part)) ); } } return false; } compareCoord(c1, c2) { return c1.length === c2.length && c1.every((c, i) => Math.abs(c - c2[i]) < this.precision); } compareLine(path1, path2, ind = 0, isPoly = false) { if (!sameLength(path1, path2)) { return false; } const p1 = path1; let p2 = path2; if (isPoly && !this.compareCoord(p1[0], p2[0])) { const startIndex = this.fixStartIndex(p2, p1); if (!startIndex) { return false; } else { p2 = startIndex; } } const sameDirection = this.compareCoord(p1[ind], p2[ind]); if (this.direction || sameDirection) { return this.comparePath(p1, p2); } else { if (this.compareCoord(p1[ind], p2[p2.length - (1 + ind)])) { return this.comparePath(p1.slice().reverse(), p2); } return false; } } fixStartIndex(sourcePath, targetPath) { let correctPath, ind = -1; for (let i = 0; i < sourcePath.length; i++) { if (this.compareCoord(sourcePath[i], targetPath[0])) { ind = i; break; } } if (ind >= 0) { correctPath = [].concat( sourcePath.slice(ind, sourcePath.length), sourcePath.slice(1, ind + 1) ); } return correctPath; } comparePath(p1, p2) { return p1.every((c, i) => this.compareCoord(c, p2[i])); } comparePolygon(g1, g2) { if (this.compareLine(g1.coordinates[0], g2.coordinates[0], 1, true)) { const holes1 = g1.coordinates.slice(1, g1.coordinates.length); const holes2 = g2.coordinates.slice(1, g2.coordinates.length); return holes1.every( (h1) => holes2.some((h2) => this.compareLine(h1, h2, 1, true)) ); } return false; } compareGeometryCollection(g1, g2) { return sameLength(g1.geometries, g2.geometries) && this.compareBBox(g1, g2) && g1.geometries.every((g, i) => this.compare(g, g2.geometries[i])); } compareFeature(g1, g2) { return g1.id === g2.id && (this.compareProperties ? equal(g1.properties, g2.properties) : true) && this.compareBBox(g1, g2) && this.compare(g1.geometry, g2.geometry); } compareFeatureCollection(g1, g2) { return sameLength(g1.features, g2.features) && this.compareBBox(g1, g2) && g1.features.every((f, i) => this.compare(f, g2.features[i])); } compareBBox(g1, g2) { return Boolean(!g1.bbox && !g2.bbox) || (g1.bbox && g2.bbox ? this.compareCoord(g1.bbox, g2.bbox) : false); } }, __name(_a, "_GeojsonEquality"), _a); __name2(_GeojsonEquality, "GeojsonEquality"); var GeojsonEquality = _GeojsonEquality; function sameLength(g1, g2) { return g1.coordinates ? g1.coordinates.length === g2.coordinates.length : g1.length === g2.length; } __name(sameLength, "sameLength"); __name2(sameLength, "sameLength"); function explode(g) { return g.coordinates.map((part) => ({ type: g.type.replace("Multi", ""), coordinates: part })); } __name(explode, "explode"); __name2(explode, "explode"); function geojsonEquality(g1, g2, opts) { const eq = new GeojsonEquality(opts); return eq.compare(g1, g2); } __name(geojsonEquality, "geojsonEquality"); __name2(geojsonEquality, "geojsonEquality"); function equal(object1, object2) { if (object1 === null && object2 === null) { return true; } if (object1 === null || object2 === null) { return false; } const objKeys1 = Object.keys(object1); const objKeys2 = Object.keys(object2); if (objKeys1.length !== objKeys2.length) return false; for (var key of objKeys1) { const value1 = object1[key]; const value2 = object2[key]; const isObjects = isObject(value1) && isObject(value2); if (isObjects && !equal(value1, value2) || !isObjects && value1 !== value2) { return false; } } return true; } __name(equal, "equal"); __name2(equal, "equal"); var isObject = /* @__PURE__ */ __name2((object) => { return object != null && typeof object === "object"; }, "isObject"); // node_modules/@turf/helpers/dist/esm/index.js var earthRadius = 63710088e-1; var factors = { centimeters: earthRadius * 100, centimetres: earthRadius * 100, degrees: 360 / (2 * Math.PI), feet: earthRadius * 3.28084, inches: earthRadius * 39.37, kilometers: earthRadius / 1e3, kilometres: earthRadius / 1e3, meters: earthRadius, metres: earthRadius, miles: earthRadius / 1609.344, millimeters: earthRadius * 1e3, millimetres: earthRadius * 1e3, nauticalmiles: earthRadius / 1852, radians: 1, yards: earthRadius * 1.0936 }; function feature(geom, properties, options2 = {}) { const feat = { type: "Feature" }; if (options2.id === 0 || options2.id) { feat.id = options2.id; } if (options2.bbox) { feat.bbox = options2.bbox; } feat.properties = properties || {}; feat.geometry = geom; return feat; } __name(feature, "feature"); // node_modules/@turf/invariant/dist/esm/index.js function getCoords(coords) { if (Array.isArray(coords)) { return coords; } if (coords.type === "Feature") { if (coords.geometry !== null) { return coords.geometry.coordinates; } } else { if (coords.coordinates) { return coords.coordinates; } } throw new Error( "coords must be GeoJSON Feature, Geometry Object or an Array" ); } __name(getCoords, "getCoords"); function getGeom(geojson) { if (geojson.type === "Feature") { return geojson.geometry; } return geojson; } __name(getGeom, "getGeom"); function getType(geojson, _name) { if (geojson.type === "FeatureCollection") { return "FeatureCollection"; } if (geojson.type === "GeometryCollection") { return "GeometryCollection"; } if (geojson.type === "Feature" && geojson.geometry !== null) { return geojson.geometry.type; } return geojson.type; } __name(getType, "getType"); // node_modules/@turf/clean-coords/dist/esm/index.js function cleanCoords(geojson, options2 = {}) { var mutate = typeof options2 === "object" ? options2.mutate : options2; if (!geojson) throw new Error("geojson is required"); var type = getType(geojson); var newCoords = []; switch (type) { case "LineString": newCoords = cleanLine(geojson, type); break; case "MultiLineString": case "Polygon": getCoords(geojson).forEach(function(line) { newCoords.push(cleanLine(line, type)); }); break; case "MultiPolygon": getCoords(geojson).forEach(function(polygons) { var polyPoints = []; polygons.forEach(function(ring) { polyPoints.push(cleanLine(ring, type)); }); newCoords.push(polyPoints); }); break; case "Point": return geojson; case "MultiPoint": var existing = {}; getCoords(geojson).forEach(function(coord) { var key = coord.join("-"); if (!Object.prototype.hasOwnProperty.call(existing, key)) { newCoords.push(coord); existing[key] = true; } }); break; default: throw new Error(type + " geometry not supported"); } if (geojson.coordinates) { if (mutate === true) { geojson.coordinates = newCoords; return geojson; } return { type, coordinates: newCoords }; } else { if (mutate === true) { geojson.geometry.coordinates = newCoords; return geojson; } return feature({ type, coordinates: newCoords }, geojson.properties, { bbox: geojson.bbox, id: geojson.id }); } } __name(cleanCoords, "cleanCoords"); function cleanLine(line, type) { var points = getCoords(line); if (points.length === 2 && !equals(points[0], points[1])) return points; var newPoints = []; var secondToLast = points.length - 1; var newPointsLength = newPoints.length; newPoints.push(points[0]); for (var i = 1; i < secondToLast; i++) { var prevAddedPoint = newPoints[newPoints.length - 1]; if (points[i][0] === prevAddedPoint[0] && points[i][1] === prevAddedPoint[1]) continue; else { newPoints.push(points[i]); newPointsLength = newPoints.length; if (newPointsLength > 2) { if (isPointOnLineSegment( newPoints[newPointsLength - 3], newPoints[newPointsLength - 1], newPoints[newPointsLength - 2] )) newPoints.splice(newPoints.length - 2, 1); } } } newPoints.push(points[points.length - 1]); newPointsLength = newPoints.length; if ((type === "Polygon" || type === "MultiPolygon") && equals(points[0], points[points.length - 1]) && newPointsLength < 4) { throw new Error("invalid polygon"); } if (type === "LineString" && newPointsLength < 3) { return newPoints; } if (isPointOnLineSegment( newPoints[newPointsLength - 3], newPoints[newPointsLength - 1], newPoints[newPointsLength - 2] )) newPoints.splice(newPoints.length - 2, 1); return newPoints; } __name(cleanLine, "cleanLine"); function equals(pt1, pt2) { return pt1[0] === pt2[0] && pt1[1] === pt2[1]; } __name(equals, "equals"); function isPointOnLineSegment(start, end, point4) { var x = point4[0], y = point4[1]; var startX = start[0], startY = start[1]; var endX = end[0], endY = end[1]; var dxc = x - startX; var dyc = y - startY; var dxl = endX - startX; var dyl = endY - startY; var cross = dxc * dyl - dyc * dxl; if (cross !== 0) return false; else if (Math.abs(dxl) >= Math.abs(dyl)) return dxl > 0 ? startX <= x && x <= endX : endX <= x && x <= startX; else return dyl > 0 ? startY <= y && y <= endY : endY <= y && y <= startY; } __name(isPointOnLineSegment, "isPointOnLineSegment"); // node_modules/@turf/boolean-equal/dist/esm/index.js function booleanEqual(feature1, feature22, options2 = {}) { let precision = options2.precision; precision = precision === void 0 || precision === null || isNaN(precision) ? 6 : precision; if (typeof precision !== "number" || !(precision >= 0)) { throw new Error("precision must be a positive number"); } const type1 = getGeom(feature1).type; const type2 = getGeom(feature22).type; if (type1 !== type2) return false; return geojsonEquality(cleanCoords(feature1), cleanCoords(feature22), { precision }); } __name(booleanEqual, "booleanEqual"); var turf_boolean_equal_default = booleanEqual; // src/interpreter/built-in-functions.ts var BuiltInFunctions; ((BuiltInFunctions2) => { const FlattenHelper = /* @__PURE__ */ __name((value) => { const flattenedValues = []; if (!!value) { if ((value == null ? void 0 : value.type) === "GeometryCollection" /* GeometryCollection */) { for (const item of value.geometries) { flattenedValues.push(...FlattenHelper(item)); } } else { flattenedValues.push(value); } } return flattenedValues; }, "FlattenHelper"); BuiltInFunctions2.Flatten = /* @__PURE__ */ __name((value) => { if ((value == null ? void 0 : value.type) === "GeometryCollection" /* GeometryCollection */) { return turf2.geometryCollection(FlattenHelper(value)).geometry; } return value; }, "Flatten"); BuiltInFunctions2.PointCircle = /* @__PURE__ */ __name((radius, count) => { const circlePoints = []; const angleIncrement = 2 * Math.PI / count; for (let i = 0; i < count; i++) { const angle = i * angleIncrement; const x = radius * Math.cos(angle); const y = radius * Math.sin(angle); circlePoints.push(turf2.point([x, y]).geometry); } return turf2.geometryCollection(circlePoints).geometry; }, "PointCircle"); BuiltInFunctions2.PointGrid = /* @__PURE__ */ __name((x, y, spacing = 1) => { const points = []; for (let i = 0; i < x; i++) { for (let j = 0; j < y; j++) { const point4 = turf2.point([i * spacing, j * spacing]).geometry; points.push(point4); } } return turf2.geometryCollection(points).geometry; }, "PointGrid"); const getPointsList = /* @__PURE__ */ __name((value) => { let points; if (isGeometryType("GeometryCollection" /* GeometryCollection */, value)) { points = value == null ? void 0 : value.geometries.map((f) => f.coordinates); } else if (isGeometryType("LineString" /* LineString */, value) || isGeometryType("MultiPoint" /* MultiPoint */, value)) { points = value == null ? void 0 : value.coordinates; } if (points) { return points; } throw new Error("Expected geometry with points list"); }, "getPointsList"); BuiltInFunctions2.ToLineString = /* @__PURE__ */ __name((value) => { const pointsList = getPointsList(value); return turf2.lineString(pointsList).geometry; }, "ToLineString"); BuiltInFunctions2.ToMultiPoint = /* @__PURE__ */ __name((value) => { const pointsList = getPointsList(value); return turf2.multiPoint(pointsList).geometry; }, "ToMultiPoint"); BuiltInFunctions2.ToPolygon = /* @__PURE__ */ __name((value) => { const pointsList = getPointsList(value); if (pointsList.length > 0) { if (!turf_boolean_equal_default( turf2.point(pointsList[0]).geometry, turf2.point(pointsList[pointsList.length - 1]).geometry )) { pointsList.push(pointsList[0]); } } return turf2.polygon([pointsList]).geometry; }, "ToPolygon"); BuiltInFunctions2.ToGeometryCollection = /* @__PURE__ */ __name((value) => { const pointsList = getPointsList(value); return turf2.geometryCollection(pointsList.map((p) => turf2.point(p).geometry)).geometry; }, "ToGeometryCollection"); BuiltInFunctions2.Rotate = /* @__PURE__ */ __name((angleDegrees, origin = turf2.point([0, 0]).geometry, geometry) => { return transform(geometry, (p) => { const angleRadians = angleDegrees * Math.PI / -180; const originX = origin.coordinates[0]; const originY = origin.coordinates[1]; const x = p.coordinates[0]; const y = p.coordinates[1]; const dx = x - originX; const dy = y - originY; const newX = originX + dx * Math.cos(angleRadians) - dy * Math.sin(angleRadians); const newY = originY + dx * Math.sin(angleRadians) + dy * Math.cos(angleRadians); return turf2.point([newX, newY]).geometry; }); }, "Rotate"); BuiltInFunctions2.Round = /* @__PURE__ */ __name((precision = 0, val) => { if (typeof val === "number") { return +val.toFixed(precision); } if (isGeometryType("Point" /* Point */, val)) { const coords = val.coordinates; return turf2.point([ (0, BuiltInFunctions2.Round)(precision, coords[0]), (0, BuiltInFunctions2.Round)(precision, coords[1]) ]).geometry; } throw new OperationNotSupported(`Unable to round value: ${toString(val)}`); }, "Round"); })(BuiltInFunctions || (BuiltInFunctions = {})); // src/interpreter/grammar.ts var GRAMMAR = String.raw` WAEL { /*************** * WAEL syntax * ***************/ // Top-level expressions TopLevel = ScopedExpressions TopLevelEnd TopLevelEnd = ExpressionDelimiter | end // Comments comment = "#" commentSpace* commentText* commentSpace* commentEnd commentText = ~commentEnd any commentEnd = "\n" | end commentSpace = " " // Expression structure ScopedExpressions = ListOf<GeneralExpression, ExpressionDelimiter> --list | GeneralExpression GeneralExpression = GeneralExpression comment --rightComment | comment GeneralExpression --leftComment | AssignmentExp | AssignableExpression | comment ExpressionDelimiter = expressionDelimiter expressionDelimiter = ";" // Imports ImportExpression = AccessibleExp<ImportExpressionType> ImportExpressionType = ImportUsingExpression | ImportAllExpression ImportUsingExpression = ImportEitherExpression usingKeyword ImportUsingParameters ImportUsingParameters = FunctionParameters | ImportUsingAllParams ImportUsingAllParams = Paren<"*"> ImportAllExpression = ImportEitherExpression ImportEitherExpression = ImportExternalExp | ImportFunctionExp ImportExternalExp = importKeyword Paren<ImportExternalParamExp> ImportExternalParamExp = stringLiteralExp | Identifier ImportFunctionExp = importKeyword Paren<FunctionCallExp> importKeyword = caseInsensitive<"import"> usingKeyword = caseInsensitive<"using"> // Exports exportKeyword = caseInsensitive<"export"> // Variables letKeyword = caseInsensitive<"let"> AssignmentExp = exportKeyword? letKeyword? Identifier assignmentOperator AssignableExpression AssignableExpression = | ImportExpression | NonArithmeticAssignableExpression | ArithmeticAssignableExpression NonArithmeticAssignableExpression = | OperationExp | stringLiteralExp ArithmeticAssignableExpression = Arithmetic<AssignableExpressionForArithmetic> AssignableExpressionForArithmetic = | BooleanResultExp | IfThenElseExp | ComputedExp | FunctionTextExp | NumberExp | AccessibleExp<GeometryExp> | BooleanValue | Paren<OperationExp> assignmentOperator = "=" ComputedValue<Type> = Type | ComputedExp ComputedExp = AccessibleExp<ComputedPrimitive> ComputedPrimitive = FunctionCallExp | Identifier AccessibleExp<Type> = | Type accessorOperator Identifier Invocation? --method | Type // Additional operation expressions OperationExp = PipeExp | GenerateExp | ConcatExp PipeExp = MappableValue anyPipeOperator Pipeable //Callable Pipeable = FunctionCallExp | Callable GenerateExp = generateKeyword GenerateCountExpr ComputedValue<GenerateValue> GenerateCountExpr = ComputedValue<NumberExp> | FunctionTextExp ConcatExp = MappableValue concatOperator MappableValue GenerateValue = GeometryExp | FunctionTextExp generateKeyword = caseInsensitive<"Generate"> MappableValue = AssignableExpression // Helpers Paren<type> = LeftParen type RightParen OptionallyParen<type> = LeftParen type RightParen --paren | type --noParen OptionallyBraced<type> = LeftBrace type RightBrace --brace | type // Arithmetic expressions Arithmetic<Type> = ArithmeticAdd<Type> ArithmeticAdd<Type> = | ArithmeticAdd<Type> plusOperator ArithmeticMul<Type> -- plus | ArithmeticAdd<Type> minusOperator ArithmeticMul<Type> -- minus | ArithmeticMul<Type> ArithmeticMul<Type> = | ArithmeticMul<Type> timesOperator ArithmeticExp<Type> -- times | ArithmeticMul<Type> divideOperator ArithmeticExp<Type> -- divide | ArithmeticMul<Type> modOperator ArithmeticExp<Type> -- mod | ArithmeticExp<Type> ArithmeticExp<Type> = | ArithmeticPri<Type> powerOperator ArithmeticExp<Type> -- power | ArithmeticPri<Type> ArithmeticPri<Type> = | Type | leftParen Arithmetic<Type> rightParen -- paren // Operators operator = | expressionDelimiter | anyPipeOperator | plusOperator | minusOperator | timesOperator | divideOperator | powerOperator | modOperator | accessorOperator | conditionalOperator | assignmentOperator | notOperator anyPipeOperator = doublePipeOperator | coordinatesPipeOperator | filterOperator | reduceOperator | pipeOperator pipeOperator = "|" coordinatesPipeOperator = "|*" doublePipeOperator = "||" filterOperator = "|~" reduceOperator = "|>" concatOperator = "++" plusOperator = "+" minusOperator = "-" timesOperator = "*" divideOperator = "/" powerOperator = "^" modOperator = "%" accessorOperator = ":" // Function expressions FunctionTextExp = functionKeyword LeftParen FunctionExp RightParen --keyword | OptionallyParen<FunctionExp> FunctionExp = FunctionParameters "=>" OptionallyParen<FunctionBody> FunctionParameters = LeftParen ListOf<Identifier, Comma> RightParen --multipleParams | Identifier --single FunctionBody = OptionallyParen<ScopedExpressions> | AssignableExpression FunctionCallExp = FunctionCallExp Invocation | Callable Invocation Invocation = LeftParen ListOf<GeneralExpression, Comma> RightParen functionKeyword = caseInsensitive<"Function"> Callable = | FunctionTextExp | FunctionCallExp | AccessibleExp<Callable> | Identifier // If-Then-Else expressions IfThenElseExp = ifKeyword Paren<BooleanResultExp> thenKeyword Paren<ScopedExpressions> elseKeyword Paren<ScopedExpressions> ifKeyword = caseInsensitive<"if"> thenKeyword = caseInsensitive<"then"> elseKeyword = caseInsensitive<"else"> // Conditional expressions BooleanResultExp = EqualityExp | CompareExp | NotExp | booleanValue EqualityExp = ComparePrimitive equalityOperatorPrimitive ComparePrimitive NotExp = notOperator ComparePrimitive ConditionalValue = CompareExp | EqualityExp | BooleanValue | NumberExp CompareExp = ComparePrimitive compareOperatorPrimitive ComparePrimitive ComparePrimitive = BooleanResultExp | ComputedValue<NumberExp> | AccessibleExp<GeometryExp> | geometryKeyword conditionalOperator = compareOperatorPrimitive | equalityOperatorPrimitive compareOperatorPrimitive = "<=" | ">=" | "<" | ">" equalityOperatorPrimitive = "==" | "!=" | logicalOperator logicalOperator = caseInsensitive<"And"> | caseInsensitive<"Or"> notOperator = "!" // Identifiers Identifier = basicIdentifier basicIdentifier = ~nonAllowedIdentifiers id id = firstIdCharacter idCharacter* firstIdCharacter = simpleLatinLetter | "$" | "_" idCharacter = simpleLatinLetter | digit | "_" | "?" | "'" nonAllowedIdentifiers = keyword identifierEnd identifierEnd = end | comma | leftParen | rightParen | operator | wktSpace /************************************* * OGC Well-Known Text (WKT) Grammar * *************************************/ // Based on WKT Syntax: https://www.ogc.org/standard/sfa/ GeometrySyntaxExp<GeometryTypeExp, geometryKeyword> = Arithmetic<GeometryArithmetic<GeometryTypeExp, geometryKeyword>> GeometryArithmetic<GeometryTypeExp, geometryKeyword> = GeometryPrimitive<GeometryTypeExp, geometryKeyword> GeometryPrimitive<GeometryTypeExp, geometryKeyword> = GeometryTaggedText<GeometryTypeExp, geometryKeyword> GeometryTaggedText<GeometryTypeExp, geometryKeyword> = geometryKeyword GeometryTypeExp GeometryCollectionExp = GeometrySyntaxExp<GeometryCollectionText, geometryCollectionKeyword> GeometryCollectionText = emptySet --empty | LeftParen ListOf<GeometryExp, Comma> RightParen --present geometryCollectionKeyword = caseInsensitive<"GEOMETRYCOLLECTION"> GeometryExp = | PointExp | MultiPointExp | LineStringExp | MultiLineStringExp | PolygonExp | MultiPolygonExp | GeometryCollectionExp // TODO -- support POLYHEDRALSURFACE geometry //PolyhedralSurfaceExp = GeometrySyntaxExp<PolyhedralSurfaceText, polyhedralSurfaceKeyword> //PolyhedralSurfaceText = emptySet --empty // | LeftParen NonemptyListOf<PolygonText, Comma> RightParen --present //polyhedralSurfaceKeyword = caseInsensitive<"PolyhedralSurface"> MultiPolygonExp = GeometrySyntaxExp<MultiPolygonText, multiPolygonKeyword> MultiPolygonText = emptySet --empty | LeftParen NonemptyListOf<PolygonText, Comma> RightParen --present multiPolygonKeyword = caseInsensitive<"MULTIPOLYGON"> PolygonExp = GeometrySyntaxExp<PolygonText, polygonKeyword> PolygonText = emptySet --empty | LeftParen NonemptyListOf<LineStringText, Comma> RightParen --present polygonKeyword = caseInsensitive<"POLYGON"> MultiLineStringExp = GeometrySyntaxExp<MultiLineStringText, multiLineStringKeyword> MultiLineStringText = emptySet --empty | LeftParen NonemptyListOf<LineStringText, Comma> RightParen --present multiLineStringKeyword = caseInsensitive<"MULTILINESTRING"> LineStringExp = GeometrySyntaxExp<LineStringText, lineStringKeyword> LineStringText = emptySet --empty | LeftParen PointList RightParen --present lineStringKeyword = caseInsensitive<"LINESTRING"> MultiPointExp = GeometrySyntaxExp<MultiPointText, multiPointKeyword> MultiPointText = emptySet --empty | LeftParen PointList RightParen --present multiPointKeyword = caseInsensitive<"MULTIPOINT"> // Base point type helpers PointList = NonemptyListOf<PointListArgument, Comma> PointListArgument = Point | ComputedValue<PointExp> PointExp = Arithmetic<PointArithmetic> PointArithmetic = PointPrimitive | ComputedExp PointPrimitive = PointTaggedText | PointText | Point PointTaggedText = pointKeyword PointText PointText = emptySet --empty | LeftParen Point RightParen --present Point = X Y pointKeyword = caseInsensitive<"POINT"> // Keywords keyword = geometryKeyword | functionKeyword | generateKeyword | booleanValue | ifKeyword | thenKeyword | elseKeyword | importKeyword | exportKeyword | letKeyword geometryKeyword = pointKeyword | multiPointKeyword | lineStringKeyword | multiLineStringKeyword | polygonKeyword | multiPolygonKeyword | geometryCollectionKeyword // Coordinate values X = PointNumberValue Y = PointNumberValue Z = PointNumberValue M = PointNumberValue // Numeric value PointNumberValue = signedNumericLiteral | OptionallyParen<ComputedValue<NumberExp>> | ComputedPrimitive NumberExp = Arithmetic<ComputedValue<signedNumericLiteral>> // Boolean value BooleanValue = ComputedValue<booleanValue> booleanValue = caseInsensitive<"true"> | caseInsensitive<"false"> // String literals stringLiteralExp = stringLiteral<"'"> | stringLiteral<"\""> stringLiteral<quoteChar> = quoteChar stringLiteralValue<quoteChar>* quoteChar stringLiteralValue<quoteChar> = ~quoteChar any // OGC specification primitives quotedName = doubleQuote name doubleQuote name = letters letters = wktLetter+ wktLetter = simpleLatinLetter | digit | special simpleLatinLetter = simpleLatinUpperCaseLetter | simpleLatinLowerCaseLetter signedNumericLiteral = sign unsignedNumericLiteral --signPresent | unsignedNumericLiteral --signMissing unsignedNumericLiteral = exactNumericLiteral | approximateNumericLiteral approximateNumericLiteral = mantissa "E" exponent // TODO -- handle this notation at higher level expressions mantissa = exactNumericLiteral exponent = signedInteger exactNumericLiteral = unsignedInteger decimalPoint unsignedInteger --decimalWithWholeNumber | decimalPoint unsignedInteger --decimalWithoutWholeNumber | unsignedInteger --wholeNumber signedInteger = sign unsignedInteger --signedInteger | unsignedInteger --unsignedInteger unsignedInteger = digit+ leftDelimiter = leftParen | leftBracket rightDelimiter = rightParen | rightBracket special = rightParen | leftParen | minusSign | underscore | period | quote | wktSpace sign = plusSign | minusSign decimalPoint = period // comma // TODO -- comma causes parsing issues emptySet = "EMPTY" minusSign = "-" LeftParen = leftParen leftParen = "(" RightParen = rightParen rightParen = ")" leftBracket = "[" rightBracket = "]" LeftBrace = leftBrace leftBrace = "{" RightBrace = rightBrace rightBrace = "}" period = "." plusSign = "+" doubleQuote = "\"" quote = "'" Comma = comma comma = "," underscore = "_" // digit = 0|1|2|3|4|5|6|7|8|9 // provided by default simpleLatinLowerCaseLetter = lower // a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z simpleLatinUpperCaseLetter = upper // A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z wktSpace = " " // unicode "U+0020" (space) // provided by default } `; // src/interpreter/interpreter.ts var import_fs = require("fs"); var import_sync_fetch = __toESM(require("sync-fetch")); var grammarString = GRAMMAR; var Interpreter; ((Interpreter2) => { Interpreter2.IMPORT_DEFAULT_IDENTIFIER = "Default"; Interpreter2.IMPORT_USING_ALL = "*"; Interpreter2.STANDARD_LIBRARY = {}; const math = {}; Object.getOwnPropertyNames(Math).forEach((prop) => { math[prop] = Math[prop]; }); Interpreter2.STANDARD_LIBRARY["Math"] = math; Interpreter2.STANDARD_LIBRARY["Flatten"] = BuiltInFunctions.Flatten; Interpreter2.STANDARD_LIBRARY["PointCircle"] = BuiltInFunctions.PointCircle; Interpreter2.STANDARD_LIBRARY["PointGrid"] = BuiltInFunctions.PointGrid; Interpreter2.STANDARD_LIBRARY["ToLineString"] = BuiltInFunctions.ToLineString; Interpreter2.STANDARD_LIBRARY["ToMultiPoint"] = BuiltInFunctions.ToMultiPoint; Interpreter2.STANDARD_LIBRARY["ToPolygon"] = BuiltInFunctions.ToPolygon; Interpreter2.STANDARD_LIBRARY["ToGeometryCollection"] = BuiltInFunctions.ToGeometryCollection; Interpreter2.STANDARD_LIBRARY["_Rotate"] = BuiltInFunctions.Rotate; Interpreter2.STANDARD_LIBRARY["_Round"] = BuiltInFunctions.Round; Interpreter2.createGlobalScope = /* @__PURE__ */ __name(() => new Scope(void 0, void 0, Interpreter2.STANDARD_LIBRARY), "createGlobalScope"); function evaluateInput(input, initialScope) { const GLOBAL_SCOPE = (0, Interpreter2.createGlobalScope)(); let currentScope = initialScope || GLOBAL_SCOPE; const grammar2 = ohm.grammar(grammarString); const semantics = grammar2.createSemantics(); semantics.addOperation("eval", { stringLiteral(_leftQuote, str, _rightQuote) { return str.sourceString; }, ImportAllExpression(exp) { const ret = exp.eval(); if (ret) { return ret; } const importObj = currentScope.useImports(); return importObj; }, ImportUsingExpression(importAllExp, _keyword, identifierList) { importAllExp.eval(); const identifiers = identifierList.eval(); let importObj; if (identifiers === Interpreter2.IMPORT_USING_ALL) { importObj = currentScope.useNamedImports(Object.keys(currentScope.availableBindings)); } else { importObj = currentScope.useNamedImports(identifiers); } return importObj; }, ImportUsingAllParams(_) { return Interpreter2.IMPORT_USING_ALL; }, ImportExternalExp(_keyword, importUri) { const uri = importUri.eval(); let data; if (uri.startsWith("http://") || uri.startsWith("https://")) { data = (0, import_sync_fetch.default)(uri).text(); } else { data = (0, import_fs.readFileSync)(uri, "utf8"); } currentScope = currentScope.push(); let ret = void 0; let bindings = void 0; try { ret = convertToGeometry(JSON.parse(data)); } catch (e) { try { const libRet = evaluateInput(data, currentScope); bindings = {}; bindings[Interpreter2.IMPORT_DEFAULT_IDENTIFIER] = libRet; } catch (e2) { throw new Error(`Unable to import file: ${uri}`); } } currentScope = currentScope.pop(bindings) || GLOBAL_SCOPE; return ret; }, ImportFunctionExp(_keyword, importFn) { importFn.eval(); }, IfThenElseExp(_if, c, _then, exp1, _else, exp2) { const condition = c.eval(); if (condition) { return exp1.eval(); } return exp2.eval(); }, booleanValue(val) { const value = val.sourceString.toLocaleLowerCase(); if (value === "true") { return true; } if (value === "false") { return false; } throw new Error(`Invalid boolean value: ${val.sourceString}`); }, EqualityExp(v1, op, v2) { const value1 = v1.eval(); const operator = op.sourceString; const value2 = v2.eval(); switch (operator.trim().toLocaleLowerCase()) { case "==": return value1 === value2; case "!=": return value1 !== value2; case "and": return value1 && value2; case "or": return value1 || value2; } throw new Error(`Operator not supported: ${operator}`); }, NotExp(_, exp) { return !exp.eval(); }, geometryKeyword(keyword) { return keyword.sourceString;