wael-lib
Version:
Well-Known Text Arithmetic Expression Language
1,325 lines (1,277 loc) • 53.9 kB
JavaScript
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
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 });
// src/main.ts
var _turf = require('@turf/turf'); var turf4 = _interopRequireWildcard(_turf); var turf3 = _interopRequireWildcard(_turf); var turf = _interopRequireWildcard(_turf); var turf2 = _interopRequireWildcard(_turf);
var _wellknown = require('wellknown'); var wellknown = _interopRequireWildcard(_wellknown);
// src/interpreter/interpreter.ts
var _ohmjs = require('ohm-js'); var ohm = _interopRequireWildcard(_ohmjs);
// 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 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 _a;
for (const value of values) {
const isType2 = typeof value === "object" && (value == null ? void 0 : value.type) === type || ((_a = value == null ? void 0 : value.geometry) == null ? void 0 : _a.type) === type;
if (!isType2) {
return false;
}
}
return true;
}, "isGeometryType");
var getGeometryType = /* @__PURE__ */ __name((value, isForDisplay = false) => {
var _a;
if (typeof value === "object") {
const type = ((_a = value == null ? void 0 : value.geometry) == null ? void 0 : _a.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((feature2) => transform(feature2, 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 _a;
const scope = (_a = this.resolveScope(identifier)) != null ? _a : this;
return scope.bindings[identifier];
}
push(extraBindings) {
return new _Scope(this, this.level + 1, extraBindings);
}
pop(additionalBindings) {
var _a;
const exportedBindings = __spreadValues({}, additionalBindings);
for (const identifier in this.metadata) {
const metadata = this.metadata[identifier];
if (metadata && metadata.public) {
exportedBindings[identifier] = this.bindings[identifier];
}
}
(_a = this.parent) == null ? void 0 : _a.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 _booleanequal = require('@turf/boolean-equal'); var _booleanequal2 = _interopRequireDefault(_booleanequal);
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 (!_booleanequal2.default.call(void 0,
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 = exports.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 _fs = require('fs');
var _syncfetch = require('sync-fetch'); var _syncfetch2 = _interopRequireDefault(_syncfetch);
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 = _syncfetch2.default.call(void 0, uri).text();
} else {
data = _fs.readFileSync.call(void 0, 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;
},
CompareExp(v1, op, v2) {
const value1 = v1.eval();
if (!isNumber(value1)) {
throw new Error(`Expected a number for ${v1.sourceString} but got: ${toString(value1)}`);
}
const operator = op.sourceString;
const value2 = v2.eval();
if (!isNumber(value2)) {
throw new Error(`Expected a number for ${v2.sourceString} but got: ${toString(value2)}`);
}
switch (operator.trim()) {
case "<":
return value1 < value2;
case "<=":
return value1 <= value2;
case ">":
return value1 > value2;
case ">=":
return value1 >= value2;
}
throw new Error(`Operator not supported: ${operator}`);
},
ConcatExp(g1, _op, g2) {
const geom1 = g1.eval();
const geom2 = g2.eval();
const type1 = getGeometryType(geom1);
const type2 = getGeometryType(geom2);
if (!type1 || !type2) {
throw new Error(`Expected geometry types for concatenation but found geom1: ${toString(geom1)} and geom2: ${toString(geom2)}`);
}
if (type1 === type2) {
const list1 = getArrayLikeItems(geom1);
const list2 = getArrayLikeItems(geom2);
if (type1 === "LineString" /* LineString */ || type1 === "MultiPoint" /* MultiPoint */ || type1 === "GeometryCollection" /* GeometryCollection */) {
const combined = list1.concat(list2);
if (type1 === "LineString" /* LineString */) {
return turf3.lineString(combined).geometry;
}
if (type1 === "MultiPoint" /* MultiPoint */) {
return turf3.multiPoint(combined).geometry;
}
if (type1 === "GeometryCollection" /* GeometryCollection */) {
return turf3.geometryCollection(combined).geometry;
}
}
}
if (type1 === "LineString" /* LineString */ || type1 === "MultiPoint" /* MultiPoint */) {
const list1 = getArrayLikeItems(geom1);
let list2;
if (type2 === "LineString" /* LineString */ || type2 === "MultiPoint" /* MultiPoint */) {
list2 = getArrayLikeItems(geom2);
} else {
if (type2 === "Point" /* Point */) {
list2 = [geom2.coordinates];
}
}
if (list2) {
const combined = list1.concat(list2);
if (type1 === "LineString" /* LineString */) {
return turf3.lineString(combined).geometry;
}
if (type1 === "MultiPoint" /* MultiPoint */) {
return turf3.multiPoint(combined).geometry;
}
if (type1 === "GeometryCollection" /* GeometryCollection */) {
return turf3.geometryCollection(combined).geometry;
}
}
}
if (type1 === "GeometryCollection" /* GeometryCollection */) {
return turf3.geometryCollection(geom1.geometries.concat([geom2])).geometry;
}
if (type2 === "GeometryCollection" /* GeometryCollection */) {
return turf3.geometryCollection([geom1].concat(...geom2.geometries)).geometry;
}
return turf3.geometryCollection([geom1, geom2]).geometry;
},
PipeExp(a, op, f) {
const operator = op.sourceString;
const val = a.eval();
const fn = f.eval();
if (operator === "|") {
return fn(val);
}
if (operator === "|*") {
return transform(val, fn);
}
const list = getArrayLikeItems(val);
let listFn;
switch (operator) {
case "||":
listFn = Array.prototype.map;
break;
case "|~":
listFn = Array.prototype.filter;
break;
case "|>":
listFn = Array.prototype.reduce;
break;
default:
throw new Error(`Operator ${operator} not supported`);
}
if (isGeometryType("GeometryCollection" /* GeometryCollection */, val)) {
const mappedList = listFn.call(list, fn);
if (isAnyGeometryType(mappedList)) {
return mappedList;
}
return turf3.geometryCollection(mappedList).geometry;
}
if (isGeometryType("LineString" /* LineString */, val)) {
let mappedList = listFn.call(
list.map((coords) => turf3.point(coords).geometry),
fn
);
if (isAnyGeometryType(mappedList)) {
return mappedList;
}
mappedList = mappedList.map((v) => v.coordinates);
return turf3.lineString(mappedList).geometry;
}
if (isGeometryType("MultiPoint" /* MultiPoint */, val)) {
let mappedList = listFn.call(
list.map((coords) => turf3.point(coords).geometry),
fn
);
if (isAnyGeometryType(mappedList)) {
return mappedList;
}
mappedList = mappedList.map((v) => v.coordinates);
return turf3.multiPoint(mappedList).geometry;
}
throw Error(`Error mapping values to geometries`);
},
TopLevel(scopedExpressions, _end) {
let lastValue = scopedExpressions.eval();
return lastValue;
},
GenerateExp(_keyword, numExp, valueExp) {
const num = numExp.eval();
if (!Number.isInteger(num) && typeof num !== "function") {
throw new Error(`Expected integer but got: ${toString(num)}`);
}
let value = valueExp.eval();
let mapFn;
if (typeof value === "function") {
mapFn = value;
} else if (isAnyGeometryType(value)) {
mapFn = /* @__PURE__ */ __name(() => value, "mapFn");
} else {
throw new Error(`Expected geometry type or function but got: ${toString(value)}`);
}
const items = [];
if (typeof num === "function") {
let i = 0;
let condition = num(i);
while (condition) {
const result2 = mapFn(i);
if (!isAnyGeometryType(result2)) {
throw new Error(`Expected geometry type return value but got: ${toString(result2)}`);
}
items.push(result2);
condition = num(++i);
}
} else {
for (let i = 0; i < num; i++) {
const result2 = mapFn(i);
if (!isAnyGeometryType(result2)) {
throw new Error(`Expected geometry type return value but got: ${toString(result2)}`);
}
items.push(result2);
}
}
return turf3.geometryCollection(items).geometry;
},
FunctionCallExp(callable, p) {
const fn = callable.eval();
const params = p.eval();
if (!fn) {
throw new Error(`${callable.sourceString} is: ${fn}`);
}
const value = fn(...params);
return value;
},
AccessibleExp_method(val, _accessOp, prop, optionalParams) {
const value = val.eval();
const identifier = prop.sourceString;
const isInvocation = optionalParams.children.length > 0;
const parameters = isInvocation ? optionalParams.children.map((c) => c.eval())[0] : [];
if (typeof value === "function") {
if (identifier === "bind") {
return value.bind(void 0, ...parameters);
}
throw new OperationNotSupported(`Method ${identifier} not supported on function type`);
}
if (isAnyGeometryType(value)) {
return geometryAccessor(val, prop, parameters);
}
const resolvedValue = value[identifier];
if (typeof resolvedValue === "function" && isInvocation) {
return resolvedValue(...parameters);
}
return resolvedValue;
},
Invocation(_leftParen, list, _rightParen) {
return list.asIteration().children.map((c) => c.eval());
},
FunctionExp(p, _, body) {
let params = p.eval();
params = Array.isArray(params) ? params : [params];
let fnScope = currentScope;
const fn = /* @__PURE__ */ __name(function(...values) {
currentScope = currentScope.push(__spreadValues({}, fnScope.bindings));
params.forEach((paramName, index) => {
currentScope.store(paramName, values[index], void 0, false);
});
const ret = body.eval();
const defaultBindings = {};
defaultBindings[Interpreter2.IMPORT_DEFAULT_IDENTIFIER] = ret;
currentScope = currentScope.pop(defaultBindings) || GLOBAL_SCOPE;
return ret;
}, "fn");
const boundFn = fn.bind(currentScope);
boundFn.toString = function() {
return `Function(${p.sourceString} => ${body.sourceString})`;
};
return boundFn;
},
FunctionParameters_multipleParams(_leftParen, identifierList, _rightParen) {
const params = identifierList.asIteration().children.map((c) => c.sourceString);
return params;
},
FunctionParameters_single(identifier) {
return [identifier.sourceString];
},
FunctionTextExp_keyword(_keyword, _leftParen, exp, _rightParen) {
return exp.eval();
},
id(first, rest) {
const key = first.sourceString + rest.sourceString;
return currentScope.resolve(key);
},
AssignmentExp(exportKeyword, letKeyword, identifier, _operator, value) {
var _a, _b;
const isPublic = !!((_a = exportKeyword == null ? void 0 : exportKeyword.children) == null ? void 0 : _a.length);
const isLet = !!((_b = letKeyword == null ? void 0 : letKeyword.children) == null ? void 0 : _b.length);
const variableName = identifier.sourceString;
const variableValue = value.eval();
currentScope.store(variableName, variableValue, { public: isPublic }, !isLet);
return variableValue;
},
ScopedExpressions_list(list) {
const expressions = list.asIteration().children.map((c) => c.eval());
return expressions[expressions.length - 1];
},
GeneralExpression_rightComment(exp, _) {
return exp.eval();
},
GeneralExpression_leftComment(_, exp) {
return exp.eval();
},
Paren(_leftParen, exp, _rightParen) {
return exp.eval();
},
OptionallyParen_paren(_leftParen, exp, _rightParen) {
return exp.eval();
},
OptionallyBraced_brace(_leftBrace, exp, _rightBrace) {
return exp.eval();
},
GeometryTaggedText(_keyword, exp) {
return exp.eval();
},
GeometryCollectionText_present(_leftParen, list, _rightParen) {
const geometries = (list || []).asIteration().children.map((c) => c.eval());
return turf3.geometryCollection(geometries).geometry;
},
MultiPolygonText_present(_leftParen, list, _rightParen) {
const polygons = list.asIteration().children.map((c) => c.eval());
return turf3.multiPolygon(polygons.map((p) => p.coordinates)).geometry;
},
MultiLineStringText_present(_leftParen, list, _rightParen) {
const lineStrings = list.asIteration().children.map((c) => c.eval());
return turf3.multiLineString(lineStrings.map((p) => p.coordinates)).geometry;
},
MultiPointText_present(_leftParen, list, _rightParen) {
const points = list.eval();
return turf3.multiPoint(points.map((p) => p.coordinates)).geometry;
},
PolygonText_present(_leftParen, list, _rightParen) {
const points = list.asIteration().children.map((c) => c.eval());
return turf3.polygon(points.map((p) => p.coordinates)).geometry;
},
LineStringText_present(_leftParen, list, _rightParen) {
const points = list.eval();
return turf3.lineString(points.map((p) => p.coordinates)).geometry;
},
PointList(list) {
return list.asIteration().children.map((c) => c.eval());
},
PointTaggedText(_, point4) {
return point4.eval();
},
PointText_present(_leftParen, point4, _rightParen) {
return point4.eval();
},
Point(x, y) {
return turf3.point([x.eval(), y.eval()]).geometry;
},
ArithmeticAdd_plus(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => a2 + b2);
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} + ${toString(b.eval())}`);
},
ArithmeticAdd_minus(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => a2 - b2);
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} - ${toString(b.eval())}`);
},
ArithmeticMul_times(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => a2 * b2);
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} * ${toString(b.eval())}`);
},
ArithmeticMul_divide(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => a2 / b2);
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} / ${toString(b.eval())}`);
},
ArithmeticMul_mod(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => a2 % b2);
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} % ${toString(b.eval())}`);
},
ArithmeticExp_power(a, _, b) {
const result2 = arithmeticOperationExp(a, b, (a2, b2) => Math.pow(a2, b2));
if (result2 !== void 0) {
return result2;
}
throw new OperationNotSupported(`${toString(a.eval())} ^ ${toString(b.eval())}`);
},
ArithmeticPri_paren(_l, exp, _r) {
return exp.eval();
},
exactNumericLiteral_decimalWithWholeNumber(whole, _, decimal) {
return parseFloat(`${whole.sourceString}.${decimal.sourceString}`);
},
exactNumericLiteral_decimalWithoutWholeNumber(_, decimal) {
return parseFloat(`.${decimal.sourceString}`);
},
exactNumericLiteral_wholeNumber(whole) {
return parseInt(`${whole.sourceString}`);
},
approximateNumericLiteral(mantissa, e, exponent) {
return parseFloat(`${mantissa.eval()}${e}${exponent.eval()}`);
},
signedNumericLiteral_signPresent(sign, numericLiteral) {
return parseFloat(`${sign.sourceString}${numericLiteral.eva