@feedloop/expression-parser
Advanced tools
Comparing version 0.1.1 to 0.1.2
@@ -1,7 +0,38 @@ | ||
export const evaluate = (expression, configs, stringify = false) => { | ||
const toString = (type, value) => { | ||
const toStringConfig = configs.functions.find((fn) => fn.name === "String" && | ||
fn.parameters.length === 1 && | ||
fn.parameters[0].type === type && | ||
fn.return.type === "string"); | ||
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.evaluate = void 0; | ||
var evaluate = function (expression, configs, stringify) { | ||
if (stringify === void 0) { stringify = false; } | ||
var toString = function (type, value) { | ||
var toStringConfig = configs.functions.find(function (fn) { | ||
return fn.name === "String" && | ||
fn.parameters.length === 1 && | ||
fn.parameters[0].type === type && | ||
fn.return.type === "string"; | ||
}); | ||
return toStringConfig | ||
@@ -11,32 +42,39 @@ ? toStringConfig.evaluate(value) | ||
}; | ||
const evaluate_ = (expression) => { | ||
var evaluate_ = function (expression) { | ||
var _a; | ||
switch (expression.kind) { | ||
case "function": { | ||
const functionConfigs = configs.functions.filter((config) => config.name === expression.name); | ||
const config = functionConfigs.find((config) => config.parameters.every((param, i) => expression.arguments[i].type === param.type)) || functionConfigs[0]; | ||
if (!config) { | ||
throw Error(`can't find config for function ${expression.name}`); | ||
var functionConfigs = configs.functions.filter(function (config) { return config.name === expression.name; }); | ||
var config_1 = functionConfigs.find(function (config) { | ||
return config.parameters.every(function (param, i) { return expression.arguments[i].type === param.type; }); | ||
}) || functionConfigs[0]; | ||
if (!config_1) { | ||
throw Error("can't find config for function ".concat(expression.name)); | ||
} | ||
return config.evaluate(...expression.arguments.map((arg, i) => evaluate(arg, configs, config.parameters[i].type === "string"))); | ||
return config_1.evaluate.apply(config_1, __spreadArray([], __read(expression.arguments.map(function (arg, i) { | ||
return (0, exports.evaluate)(arg, configs, config_1.parameters[i].type === "string"); | ||
})), false)); | ||
} | ||
case "operator": { | ||
const config = configs.operators.find((op) => op.name === expression.name); | ||
var config = configs.operators.find(function (op) { return op.name === expression.name; }); | ||
if (!config) { | ||
throw Error(`can't find config for operator ${expression.name}`); | ||
throw Error("can't find config for operator ".concat(expression.name)); | ||
} | ||
if (!expression.right) { | ||
throw Error(`ParseError: expected a term after the operator`); | ||
throw Error("ParseError: expected a term after the operator"); | ||
} | ||
return config.evaluate(...[ | ||
return config.evaluate.apply(config, __spreadArray([], __read([ | ||
[(_a = config.left) === null || _a === void 0 ? void 0 : _a.type, expression.left], | ||
[config.right.type, expression.right], | ||
] | ||
.filter((exp) => Boolean(exp[1])) | ||
.map(([type, exp]) => evaluate(exp, configs, type === "string"))); | ||
.filter(function (exp) { return Boolean(exp[1]); }) | ||
.map(function (_a) { | ||
var _b = __read(_a, 2), type = _b[0], exp = _b[1]; | ||
return (0, exports.evaluate)(exp, configs, type === "string"); | ||
})), false)); | ||
} | ||
case "variable": { | ||
const config = configs.variables.find((variable) => variable.name === expression.name); | ||
var config = configs.variables.find(function (variable) { return variable.name === expression.name; }); | ||
if (!config) { | ||
throw Error(`can't find config for operator ${expression.name}`); | ||
throw Error("can't find config for operator ".concat(expression.name)); | ||
} | ||
@@ -46,3 +84,3 @@ return config.evaluate(); | ||
case "expression": | ||
return evaluate(expression.expression, configs); | ||
return (0, exports.evaluate)(expression.expression, configs); | ||
case "boolean": | ||
@@ -54,6 +92,8 @@ case "number": | ||
.slice(1) | ||
.reduce((string, part, i) => string.concat(evaluate(expression.expressions[i], configs, true), part.value), expression.parts[0].value); | ||
.reduce(function (string, part, i) { | ||
return string.concat((0, exports.evaluate)(expression.expressions[i], configs, true), part.value); | ||
}, expression.parts[0].value); | ||
} | ||
}; | ||
const value = evaluate_(expression); | ||
var value = evaluate_(expression); | ||
return stringify && expression.type !== "string" | ||
@@ -63,1 +103,2 @@ ? toString(expression.type, value) | ||
}; | ||
exports.evaluate = evaluate; |
@@ -1,24 +0,56 @@ | ||
import { buildTypeChecker } from "./type-checker"; | ||
export const generate = (expression, configs) => { | ||
const checkType = buildTypeChecker(configs); | ||
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generate = void 0; | ||
var type_checker_1 = require("./type-checker"); | ||
var generate = function (expression, configs) { | ||
var checkType = (0, type_checker_1.buildTypeChecker)(configs); | ||
switch (expression.kind) { | ||
case "function": { | ||
const functionConfigs = configs.functions.filter((config) => config.name === expression.name); | ||
const fn = functionConfigs.find((config) => config.parameters.every((param, i) => checkType(expression.arguments[i], param.type)[1].length === 0)) || functionConfigs[0]; | ||
const argsString = expression.arguments.map((arg) => generate(arg, configs)); | ||
var functionConfigs = configs.functions.filter(function (config) { return config.name === expression.name; }); | ||
var fn = functionConfigs.find(function (config) { | ||
return config.parameters.every(function (param, i) { | ||
return checkType(expression.arguments[i], param.type)[1].length === 0; | ||
}); | ||
}) || functionConfigs[0]; | ||
var argsString = expression.arguments.map(function (arg) { | ||
return (0, exports.generate)(arg, configs); | ||
}); | ||
return (fn === null || fn === void 0 ? void 0 : fn.generate) | ||
? fn.generate(...argsString) | ||
: `${expression.name}(${argsString.join(",")})`; | ||
? fn.generate.apply(fn, __spreadArray([], __read(argsString), false)) : "".concat(expression.name, "(").concat(argsString.join(","), ")"); | ||
} | ||
case "operator": { | ||
const op = configs.operators.find((op) => op.name === expression.name); | ||
const argsString = [expression.left, expression.right] | ||
.filter((exp) => Boolean(exp)) | ||
.map((arg) => generate(arg, configs)); | ||
var op = configs.operators.find(function (op) { return op.name === expression.name; }); | ||
var argsString = [expression.left, expression.right] | ||
.filter(function (exp) { return Boolean(exp); }) | ||
.map(function (arg) { return (0, exports.generate)(arg, configs); }); | ||
return (op === null || op === void 0 ? void 0 : op.generate) | ||
? op.generate(...argsString) | ||
: argsString.join(` ${expression.name} `); | ||
? op.generate.apply(op, __spreadArray([], __read(argsString), false)) : argsString.join(" ".concat(expression.name, " ")); | ||
} | ||
case "variable": { | ||
const variable = configs.operators.find((variable) => variable.name === expression.name); | ||
var variable = configs.operators.find(function (variable) { return variable.name === expression.name; }); | ||
return (variable === null || variable === void 0 ? void 0 : variable.generate) ? variable.generate() : expression.name; | ||
@@ -28,9 +60,11 @@ } | ||
case "number": | ||
return `${expression.value}`; | ||
return "".concat(expression.value); | ||
case "string": | ||
return JSON.stringify(expression.parts | ||
.slice(1) | ||
.reduce((string, part, i) => string.concat(generate(expression.expressions[i], configs), part.value), expression.parts[0].value)); | ||
.reduce(function (string, part, i) { | ||
return string.concat((0, exports.generate)(expression.expressions[i], configs), part.value); | ||
}, expression.parts[0].value)); | ||
case "expression": | ||
return `(${generate(expression.expression, configs)})`; | ||
return "(".concat((0, exports.generate)(expression.expression, configs), ")"); | ||
case "placeholder": | ||
@@ -40,1 +74,2 @@ return ""; | ||
}; | ||
exports.generate = generate; |
@@ -1,3 +0,10 @@ | ||
export { buildExpressionSyntaxParser, buildExpressionParser, } from "./parser"; | ||
export { evaluate, } from "./evaluator"; | ||
export { generate, } from "./generator"; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generate = exports.evaluate = exports.buildExpressionParser = exports.buildExpressionSyntaxParser = void 0; | ||
var parser_1 = require("./parser"); | ||
Object.defineProperty(exports, "buildExpressionSyntaxParser", { enumerable: true, get: function () { return parser_1.buildExpressionSyntaxParser; } }); | ||
Object.defineProperty(exports, "buildExpressionParser", { enumerable: true, get: function () { return parser_1.buildExpressionParser; } }); | ||
var evaluator_1 = require("./evaluator"); | ||
Object.defineProperty(exports, "evaluate", { enumerable: true, get: function () { return evaluator_1.evaluate; } }); | ||
var generator_1 = require("./generator"); | ||
Object.defineProperty(exports, "generate", { enumerable: true, get: function () { return generator_1.generate; } }); |
@@ -1,54 +0,159 @@ | ||
export const ok = (parsed, input, position) => ({ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateErrorId = exports.spanned = exports.between = exports.sequence = exports.applySecond = exports.applyFirst = exports.map2 = exports.map = exports.oneOf = exports.alt = exports.sepBy = exports.many = exports.chainRec = exports.fold = exports.chain = exports.pureFail = exports.pure = exports.tryParse = exports.lookAhead = exports.lazy = exports.parse = exports.chainFail = exports.chainResult = exports.foldResult = exports.fail = exports.ok = void 0; | ||
var ok = function (parsed, input, position) { return ({ | ||
type: "ok", | ||
parsed, | ||
input, | ||
position, | ||
}); | ||
export const fail = (expected, input, position) => ({ | ||
parsed: parsed, | ||
input: input, | ||
position: position, | ||
}); }; | ||
exports.ok = ok; | ||
var fail = function (expected, input, position) { return ({ | ||
type: "fail", | ||
expected, | ||
input, | ||
position, | ||
}); | ||
const identity = (t) => t; | ||
export const foldResult = (result, onOk, onFail) => (result.type === "ok" ? onOk(result) : onFail(result)); | ||
export const chainResult = (result, fn) => foldResult(result, fn, identity); | ||
export const chainFail = (result, fn) => foldResult(result, identity, fn); | ||
export const parse = (parser, input, position) => | ||
// @ts-ignore | ||
parser.length === 0 ? parser()(input, position) : parser(input, position); | ||
export const lazy = (parser) => (input, position = 0) => parse(parser(), input, position); | ||
export const lookAhead = (parser) => (input, position = 0) => { | ||
const result = parse(parser, input, position); | ||
return result.type === "ok" ? ok(result.parsed, input, position) : result; | ||
expected: expected, | ||
input: input, | ||
position: position, | ||
}); }; | ||
exports.fail = fail; | ||
var identity = function (t) { return t; }; | ||
var foldResult = function (result, onOk, onFail) { return (result.type === "ok" ? onOk(result) : onFail(result)); }; | ||
exports.foldResult = foldResult; | ||
var chainResult = function (result, fn) { return (0, exports.foldResult)(result, fn, identity); }; | ||
exports.chainResult = chainResult; | ||
var chainFail = function (result, fn) { return (0, exports.foldResult)(result, identity, fn); }; | ||
exports.chainFail = chainFail; | ||
var parse = function (parser, input, position) { | ||
// @ts-ignore | ||
return parser.length === 0 ? parser()(input, position) : parser(input, position); | ||
}; | ||
export const tryParse = (parser) => (input, position = 0) => { | ||
const result = parse(parser, input, position); | ||
return result.type === "fail" | ||
? fail(result.expected, input, position) | ||
: result; | ||
exports.parse = parse; | ||
var lazy = function (parser) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return (0, exports.parse)(parser(), input, position); | ||
}; | ||
}; | ||
export const pure = (value) => (input, position = 0) => ok(value, input, position); | ||
export const pureFail = (expected) => (input, position = 0) => fail(expected, input, position); | ||
export const chain = (parser, fn) => fold(parser, fn, (fail) => pureFail(fail.expected)); | ||
export const fold = (parser, onOk, onFail) => (input, position = 0) => foldResult(parse(parser, input, position), (ok) => parse(onOk(ok.parsed), ok.input, ok.position), (fail) => parse(onFail(fail), fail.input, fail.position)); | ||
export const chainRec = (parser, rec, acc) => fold(parser, (parsed) => { | ||
const [nextParser, nextAcc] = rec(parsed, acc); | ||
return chainRec(nextParser, rec, nextAcc); | ||
}, (fail) => pure(acc)); | ||
export const many = (parser) => chainRec(parser, (parsed, acc) => [parser, acc.concat([parsed])], []); | ||
export const sepBy = (parser, sep) => chainRec(parser, (parsed, acc) => [applySecond(sep, parser), acc.concat(parsed)], []); | ||
export const alt = (parserA, parserB) => (input, position = 0) => chainFail(parse(parserA, input, position), () => parse(parserB, input, position)); | ||
export const oneOf = (parsers) => parsers.reduce((sum, parser) => alt(sum, parser), pureFail("one of parser")); | ||
export const map = (parser, fn) => chain(parser, (a) => pure(fn(a))); | ||
export const map2 = (parserA, parserB, fn) => chain(parserA, (a) => chain(parserB, (b) => pure(fn(a, b)))); | ||
export const applyFirst = (parserA, parserB) => map2(parserA, parserB, (a) => a); | ||
export const applySecond = (parserA, parserB) => map2(parserA, parserB, (a, b) => b); | ||
export const sequence = (parsers) => parsers.reduce((sum, parser) => chain(sum, (s) => chain(parser, (p) => pure(s.concat(p)))), pure([])); | ||
export const between = (left, middle, right) => applySecond(left, applyFirst(middle, right)); | ||
export const spanned = (parser) => (input, position = 0) => { | ||
const result = parse(parser, input, position); | ||
return chainResult(result, (ok) => (Object.assign(Object.assign({}, ok), { parsed: Object.assign(Object.assign({}, ok.parsed), { start: position, end: ok.position }) }))); | ||
exports.lazy = lazy; | ||
var lookAhead = function (parser) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
var result = (0, exports.parse)(parser, input, position); | ||
return result.type === "ok" ? (0, exports.ok)(result.parsed, input, position) : result; | ||
}; | ||
}; | ||
let id = 0; | ||
export const generateErrorId = () => id++; | ||
exports.lookAhead = lookAhead; | ||
var tryParse = function (parser) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
var result = (0, exports.parse)(parser, input, position); | ||
return result.type === "fail" | ||
? (0, exports.fail)(result.expected, input, position) | ||
: result; | ||
}; | ||
}; | ||
exports.tryParse = tryParse; | ||
var pure = function (value) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return (0, exports.ok)(value, input, position); | ||
}; | ||
}; | ||
exports.pure = pure; | ||
var pureFail = function (expected) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return (0, exports.fail)(expected, input, position); | ||
}; | ||
}; | ||
exports.pureFail = pureFail; | ||
var chain = function (parser, fn) { return (0, exports.fold)(parser, fn, function (fail) { return (0, exports.pureFail)(fail.expected); }); }; | ||
exports.chain = chain; | ||
var fold = function (parser, onOk, onFail) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return (0, exports.foldResult)((0, exports.parse)(parser, input, position), function (ok) { return (0, exports.parse)(onOk(ok.parsed), ok.input, ok.position); }, function (fail) { return (0, exports.parse)(onFail(fail), fail.input, fail.position); }); | ||
}; | ||
}; | ||
exports.fold = fold; | ||
var chainRec = function (parser, rec, acc) { | ||
return (0, exports.fold)(parser, function (parsed) { | ||
var _a = __read(rec(parsed, acc), 2), nextParser = _a[0], nextAcc = _a[1]; | ||
return (0, exports.chainRec)(nextParser, rec, nextAcc); | ||
}, function (fail) { return (0, exports.pure)(acc); }); | ||
}; | ||
exports.chainRec = chainRec; | ||
var many = function (parser) { | ||
return (0, exports.chainRec)(parser, function (parsed, acc) { return [parser, acc.concat([parsed])]; }, []); | ||
}; | ||
exports.many = many; | ||
var sepBy = function (parser, sep) { | ||
return (0, exports.chainRec)(parser, function (parsed, acc) { return [(0, exports.applySecond)(sep, parser), acc.concat(parsed)]; }, []); | ||
}; | ||
exports.sepBy = sepBy; | ||
var alt = function (parserA, parserB) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return (0, exports.chainFail)((0, exports.parse)(parserA, input, position), function () { | ||
return (0, exports.parse)(parserB, input, position); | ||
}); | ||
}; | ||
}; | ||
exports.alt = alt; | ||
var oneOf = function (parsers) { | ||
return parsers.reduce(function (sum, parser) { return (0, exports.alt)(sum, parser); }, (0, exports.pureFail)("one of parser")); | ||
}; | ||
exports.oneOf = oneOf; | ||
var map = function (parser, fn) { | ||
return (0, exports.chain)(parser, function (a) { return (0, exports.pure)(fn(a)); }); | ||
}; | ||
exports.map = map; | ||
var map2 = function (parserA, parserB, fn) { return (0, exports.chain)(parserA, function (a) { return (0, exports.chain)(parserB, function (b) { return (0, exports.pure)(fn(a, b)); }); }); }; | ||
exports.map2 = map2; | ||
var applyFirst = function (parserA, parserB) { return (0, exports.map2)(parserA, parserB, function (a) { return a; }); }; | ||
exports.applyFirst = applyFirst; | ||
var applySecond = function (parserA, parserB) { return (0, exports.map2)(parserA, parserB, function (a, b) { return b; }); }; | ||
exports.applySecond = applySecond; | ||
var sequence = function (parsers) { | ||
return parsers.reduce(function (sum, parser) { return (0, exports.chain)(sum, function (s) { return (0, exports.chain)(parser, function (p) { return (0, exports.pure)(s.concat(p)); }); }); }, (0, exports.pure)([])); | ||
}; | ||
exports.sequence = sequence; | ||
var between = function (left, middle, right) { return (0, exports.applySecond)(left, (0, exports.applyFirst)(middle, right)); }; | ||
exports.between = between; | ||
var spanned = function (parser) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
var result = (0, exports.parse)(parser, input, position); | ||
return (0, exports.chainResult)(result, function (ok) { return (__assign(__assign({}, ok), { parsed: __assign(__assign({}, ok.parsed), { start: position, end: ok.position }) })); }); | ||
}; | ||
}; | ||
exports.spanned = spanned; | ||
var id = 0; | ||
var generateErrorId = function () { return id++; }; | ||
exports.generateErrorId = generateErrorId; |
@@ -1,64 +0,129 @@ | ||
import { ok, fail, applyFirst, map, between, oneOf, pureFail, chain, parse, pure, sepBy, spanned, generateErrorId, map2, many, } from "./parser-utils"; | ||
import { getContextAtPosition, getSuggestionsAtPosition, } from "./suggestion"; | ||
import { buildTypeChecker } from "./type-checker"; | ||
export const regex = (regex) => { | ||
const anchoredRegex = new RegExp(`^${regex.source}`); | ||
return (input, position = 0) => { | ||
const match = anchoredRegex.exec(input.slice(position)); | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.buildExpressionParser = exports.buildExpressionSyntaxParser = exports.lexeme = exports.nonspaces = exports.spaces = exports.boolean = exports.number = exports.eof = exports.text = exports.regex = void 0; | ||
var parser_utils_1 = require("./parser-utils"); | ||
var suggestion_1 = require("./suggestion"); | ||
var type_checker_1 = require("./type-checker"); | ||
var regex = function (regex) { | ||
var anchoredRegex = new RegExp("^".concat(regex.source)); | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
var match = anchoredRegex.exec(input.slice(position)); | ||
if (match !== null) { | ||
const matchedText = match[0]; | ||
return ok(matchedText, input, position + matchedText.length); | ||
var matchedText = match[0]; | ||
return (0, parser_utils_1.ok)(matchedText, input, position + matchedText.length); | ||
} | ||
return fail(regex.toString(), input, position); | ||
return (0, parser_utils_1.fail)(regex.toString(), input, position); | ||
}; | ||
}; | ||
export const text = (text) => (input, position = 0) => input.slice(position).startsWith(text) | ||
? ok(text, input, position + text.length) | ||
: fail(`"${text}"`, input, position); | ||
export const eof = (input, position = 0) => input.slice(position).length === 0 | ||
? ok("", input, position) | ||
: fail(`"end of input"`, input, position); | ||
export const number = (input, position = 0) => { | ||
const match = /^\d+(\.\d+)?/.exec(input.slice(position)); | ||
exports.regex = regex; | ||
var text = function (text) { | ||
return function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return input.slice(position).startsWith(text) | ||
? (0, parser_utils_1.ok)(text, input, position + text.length) | ||
: (0, parser_utils_1.fail)("\"".concat(text, "\""), input, position); | ||
}; | ||
}; | ||
exports.text = text; | ||
var eof = function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
return input.slice(position).length === 0 | ||
? (0, parser_utils_1.ok)("", input, position) | ||
: (0, parser_utils_1.fail)("\"end of input\"", input, position); | ||
}; | ||
exports.eof = eof; | ||
var number = function (input, position) { | ||
if (position === void 0) { position = 0; } | ||
var match = /^\d+(\.\d+)?/.exec(input.slice(position)); | ||
if (match !== null) { | ||
const matchedText = match[0]; | ||
return ok(Number(matchedText), input, position + matchedText.length); | ||
var matchedText = match[0]; | ||
return (0, parser_utils_1.ok)(Number(matchedText), input, position + matchedText.length); | ||
} | ||
return fail("number", input, position); | ||
return (0, parser_utils_1.fail)("number", input, position); | ||
}; | ||
export const boolean = oneOf([ | ||
map(text("true"), () => true), | ||
map(text("false"), () => false), | ||
pureFail("boolean"), | ||
exports.number = number; | ||
exports.boolean = (0, parser_utils_1.oneOf)([ | ||
(0, parser_utils_1.map)((0, exports.text)("true"), function () { return true; }), | ||
(0, parser_utils_1.map)((0, exports.text)("false"), function () { return false; }), | ||
(0, parser_utils_1.pureFail)("boolean"), | ||
]); | ||
export const spaces = regex(/\s*/); | ||
export const nonspaces = regex(/[^\s"`,(){}/\\]+/); | ||
export const lexeme = (parser) => between(spaces, parser, spaces); | ||
export const buildExpressionSyntaxParser = (operatorConfigs) => { | ||
const operator = oneOf(operatorConfigs.map((config) => map(text(config.name), (name) => ({ | ||
kind: "operator", | ||
name, | ||
unary: !config.left, | ||
})))); | ||
const functionParser = chain(nonspaces, (name) => map(between(text("("), sepBy(lexeme(expression), text(",")), text(")")), (args) => ({ | ||
kind: "function", | ||
name, | ||
arguments: args, | ||
}))); | ||
const subExpression = map(between(text("("), lexeme(expression), text(")")), (expression) => ({ kind: "expression", expression })); | ||
const stringPart = spanned(map(regex(/.*?(?=\"|\{\{)/), (value) => ({ value }))); | ||
const string = between(text('"'), map2(stringPart, many(map2(between(text("{{"), lexeme(expression), text("}}")), stringPart, (expression, part) => [ | ||
exports.spaces = (0, exports.regex)(/\s*/); | ||
exports.nonspaces = (0, exports.regex)(/[^\s"`,(){}/\\]+/); | ||
var lexeme = function (parser) { | ||
return (0, parser_utils_1.between)(exports.spaces, parser, exports.spaces); | ||
}; | ||
exports.lexeme = lexeme; | ||
var buildExpressionSyntaxParser = function (operatorConfigs) { | ||
var operator = (0, parser_utils_1.oneOf)(operatorConfigs.map(function (config) { | ||
return (0, parser_utils_1.map)((0, exports.text)(config.name), function (name) { return ({ | ||
kind: "operator", | ||
name: name, | ||
unary: !config.left, | ||
}); }); | ||
})); | ||
var functionParser = (0, parser_utils_1.chain)(exports.nonspaces, function (name) { | ||
return (0, parser_utils_1.map)((0, parser_utils_1.between)((0, exports.text)("("), (0, parser_utils_1.sepBy)((0, exports.lexeme)(expression), (0, exports.text)(",")), (0, exports.text)(")")), function (args) { return ({ | ||
kind: "function", | ||
name: name, | ||
arguments: args, | ||
}); }); | ||
}); | ||
var subExpression = (0, parser_utils_1.map)((0, parser_utils_1.between)((0, exports.text)("("), (0, exports.lexeme)(expression), (0, exports.text)(")")), function (expression) { return ({ kind: "expression", expression: expression }); }); | ||
var stringPart = (0, parser_utils_1.spanned)((0, parser_utils_1.map)((0, exports.regex)(/.*?(?=\"|\{\{)/), function (value) { return ({ value: value }); })); | ||
var string = (0, parser_utils_1.between)((0, exports.text)('"'), (0, parser_utils_1.map2)(stringPart, (0, parser_utils_1.many)((0, parser_utils_1.map2)((0, parser_utils_1.between)((0, exports.text)("{{"), (0, exports.lexeme)(expression), (0, exports.text)("}}")), stringPart, function (expression, part) { return [ | ||
expression, | ||
part, | ||
])), (part, expressionAndParts) => expressionAndParts.reduce((string, [expression, part]) => ({ | ||
kind: "string", | ||
expressions: string.expressions.concat(expression), | ||
parts: string.parts.concat(part), | ||
}), { | ||
kind: "string", | ||
expressions: [], | ||
parts: [part], | ||
})), text('"')); | ||
]; })), function (part, expressionAndParts) { | ||
return expressionAndParts.reduce(function (string, _a) { | ||
var _b = __read(_a, 2), expression = _b[0], part = _b[1]; | ||
return ({ | ||
kind: "string", | ||
expressions: string.expressions.concat(expression), | ||
parts: string.parts.concat(part), | ||
}); | ||
}, { | ||
kind: "string", | ||
expressions: [], | ||
parts: [part], | ||
}); | ||
}), (0, exports.text)('"')); | ||
function termParser() { | ||
return spanned(oneOf([ | ||
return (0, parser_utils_1.spanned)((0, parser_utils_1.oneOf)([ | ||
functionParser, | ||
@@ -68,47 +133,54 @@ subExpression, | ||
string, | ||
map(number, (value) => ({ kind: "number", value })), | ||
map(boolean, (value) => ({ kind: "boolean", value })), | ||
map(nonspaces, (name) => ({ kind: "variable", name })), | ||
(0, parser_utils_1.map)(exports.number, function (value) { return ({ kind: "number", value: value }); }), | ||
(0, parser_utils_1.map)(exports.boolean, function (value) { return ({ kind: "boolean", value: value }); }), | ||
(0, parser_utils_1.map)(exports.nonspaces, function (name) { return ({ kind: "variable", name: name }); }), | ||
])); | ||
} | ||
const operatorPrecedenceGroup = [ | ||
...operatorConfigs | ||
.reduce((group, operatorConfig) => { | ||
var _a; | ||
return group.set(operatorConfig.precedence, ((_a = group.get(operatorConfig.precedence)) === null || _a === void 0 ? void 0 : _a.concat(operatorConfig)) || [ | ||
operatorConfig, | ||
]); | ||
}, new Map()) | ||
.entries(), | ||
].sort((a, b) => a[0] - b[0]); | ||
const reoderTerms = (termsAndOperators) => { | ||
const firstOpIndex = operatorPrecedenceGroup.reduce((operator, [, group]) => operator === -1 | ||
? termsAndOperators.findIndex((to) => to.kind === "operator" && | ||
group.map((op) => op.name).includes(to.name)) | ||
: operator, -1) || termsAndOperators.findIndex((to) => to.kind === "operator"); | ||
var operatorPrecedenceGroup = __spreadArray([], __read(operatorConfigs | ||
.reduce(function (group, operatorConfig) { | ||
var _a; | ||
return group.set(operatorConfig.precedence, ((_a = group.get(operatorConfig.precedence)) === null || _a === void 0 ? void 0 : _a.concat(operatorConfig)) || [ | ||
operatorConfig, | ||
]); | ||
}, new Map()) | ||
.entries()), false).sort(function (a, b) { return a[0] - b[0]; }); | ||
var reoderTerms = function (termsAndOperators) { | ||
var firstOpIndex = operatorPrecedenceGroup.reduce(function (operator, _a) { | ||
var _b = __read(_a, 2), group = _b[1]; | ||
return operator === -1 | ||
? termsAndOperators.findIndex(function (to) { | ||
return to.kind === "operator" && | ||
group.map(function (op) { return op.name; }).includes(to.name); | ||
}) | ||
: operator; | ||
}, -1) || termsAndOperators.findIndex(function (to) { return to.kind === "operator"; }); | ||
if (firstOpIndex === -1) { | ||
return termsAndOperators[0]; | ||
} | ||
const leftTermsAndOperators = termsAndOperators.slice(0, firstOpIndex); | ||
const [op, ...rightTermsAndOperators] = termsAndOperators.slice(firstOpIndex); | ||
var leftTermsAndOperators = termsAndOperators.slice(0, firstOpIndex); | ||
var _a = __read(termsAndOperators.slice(firstOpIndex)), op = _a[0], rightTermsAndOperators = _a.slice(1); | ||
if (op.kind !== "operator") { | ||
throw Error(`expecting an operator but got ${op.kind}`); | ||
throw Error("expecting an operator but got ".concat(op.kind)); | ||
} | ||
return firstOpIndex !== 0 && !op.unary | ||
? Object.assign(Object.assign({}, op), { left: reoderTerms(leftTermsAndOperators), right: reoderTerms(rightTermsAndOperators) }) : Object.assign(Object.assign({}, op), { right: reoderTerms(rightTermsAndOperators) }); | ||
? __assign(__assign({}, op), { left: reoderTerms(leftTermsAndOperators), right: reoderTerms(rightTermsAndOperators) }) : __assign(__assign({}, op), { right: reoderTerms(rightTermsAndOperators) }); | ||
}; | ||
function expression() { | ||
return map(chain(sepBy(termParser, spaces), (terms) => terms.length | ||
? pure(terms) | ||
: map(spanned(pure({ kind: "placeholder" })), (exp) => [exp])), reoderTerms); | ||
return (0, parser_utils_1.map)((0, parser_utils_1.chain)((0, parser_utils_1.sepBy)(termParser, exports.spaces), function (terms) { | ||
return terms.length | ||
? (0, parser_utils_1.pure)(terms) | ||
: (0, parser_utils_1.map)((0, parser_utils_1.spanned)((0, parser_utils_1.pure)({ kind: "placeholder" })), function (exp) { return [exp]; }); | ||
}), reoderTerms); | ||
} | ||
return (input) => parse(applyFirst(expression, eof), input, 0); | ||
return function (input) { return (0, parser_utils_1.parse)((0, parser_utils_1.applyFirst)(expression, exports.eof), input, 0); }; | ||
}; | ||
export const buildExpressionParser = (options) => { | ||
const syntaxParser = buildExpressionSyntaxParser(options.operators); | ||
const typeChecker = buildTypeChecker(options); | ||
return (input, cursorPosition = input.length) => { | ||
const parseResult = syntaxParser(input); | ||
exports.buildExpressionSyntaxParser = buildExpressionSyntaxParser; | ||
var buildExpressionParser = function (options) { | ||
var syntaxParser = (0, exports.buildExpressionSyntaxParser)(options.operators); | ||
var typeChecker = (0, type_checker_1.buildTypeChecker)(options); | ||
return function (input, cursorPosition) { | ||
if (cursorPosition === void 0) { cursorPosition = input.length; } | ||
var parseResult = syntaxParser(input); | ||
if (parseResult.type === "fail") { | ||
const id = generateErrorId(); | ||
var id = (0, parser_utils_1.generateErrorId)(); | ||
return { | ||
@@ -124,6 +196,6 @@ ast: { | ||
{ | ||
id, | ||
id: id, | ||
start: parseResult.position, | ||
end: parseResult.input.length - parseResult.position, | ||
message: `expecting ${parseResult.expected} but got ${parseResult.input.slice(parseResult.position)}`, | ||
message: "expecting ".concat(parseResult.expected, " but got ").concat(parseResult.input.slice(parseResult.position)), | ||
}, | ||
@@ -135,3 +207,3 @@ ], | ||
} | ||
const [typedAst, errors] = typeChecker(parseResult.parsed, options.type || "any"); | ||
var _a = __read(typeChecker(parseResult.parsed, options.type || "any"), 2), typedAst = _a[0], errors = _a[1]; | ||
return { | ||
@@ -142,13 +214,14 @@ ast: typedAst, | ||
{ | ||
id: generateErrorId(), | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: parseResult.position, | ||
end: parseResult.input.length - parseResult.position, | ||
message: `cannot parse ${parseResult.input.slice(parseResult.position)}`, | ||
message: "cannot parse ".concat(parseResult.input.slice(parseResult.position)), | ||
}, | ||
] | ||
: []), | ||
suggestions: getSuggestionsAtPosition(options, typedAst, cursorPosition), | ||
context: getContextAtPosition(options, typedAst, cursorPosition), | ||
suggestions: (0, suggestion_1.getSuggestionsAtPosition)(options, typedAst, cursorPosition), | ||
context: (0, suggestion_1.getContextAtPosition)(options, typedAst, cursorPosition), | ||
}; | ||
}; | ||
}; | ||
exports.buildExpressionParser = buildExpressionParser; |
@@ -1,64 +0,95 @@ | ||
export const getSuggestionsAtPosition = (parserOptions, expression, cursorPosition) => { | ||
const getFunctionSuggestions = (leftType = "any") => parserOptions.functions | ||
.filter((fn) => leftType === "any" || | ||
fn.return.type === "any" || | ||
fn.return.type === leftType) | ||
.map((config) => ({ | ||
kind: "function", | ||
name: config.name, | ||
description: config.description, | ||
parameters: config.parameters, | ||
value: `${config.name}(${config.parameters.map(() => "").join(",")})`, | ||
type: config.return.type, | ||
output: config.return.description, | ||
examples: config.examples, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
})); | ||
const getOperatorSuggestions = (leftType = "any", unary = false) => parserOptions.operators | ||
.filter((operator) => unary | ||
? !operator.left && operator.return.type === leftType | ||
: operator.left && | ||
(leftType === "any" || | ||
operator.left.type === "any" || | ||
operator.left.type === leftType)) | ||
.map((config) => ({ | ||
kind: "operator", | ||
name: config.name, | ||
arity: config.left ? "binary" : "unary", | ||
left: config.left, | ||
right: config.right, | ||
value: config.name, | ||
type: config.return.type, | ||
output: config.return.description, | ||
examples: config.examples, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
})); | ||
const getVariableSuggestions = (leftType = "any") => parserOptions.variables | ||
.filter((variable) => leftType === "any" || | ||
variable.type === "any" || | ||
variable.type === leftType) | ||
.map((config) => ({ | ||
kind: "variable", | ||
name: config.name, | ||
description: config.description, | ||
value: config.name, | ||
type: config.type, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
})); | ||
const getTermSuggestions = (leftType = "any", cursorPosition) => { | ||
const functionSuggestions = getFunctionSuggestions(leftType); | ||
const operatorSuggestions = getOperatorSuggestions(leftType, true); | ||
const variableSuggestions = getVariableSuggestions(leftType); | ||
const booleanSuggestions = leftType === "boolean" | ||
? ["true", "false"].map((value) => ({ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getContextAtPosition = exports.getSuggestionsAtPosition = void 0; | ||
var getSuggestionsAtPosition = function (parserOptions, expression, cursorPosition) { | ||
var getFunctionSuggestions = function (leftType) { | ||
if (leftType === void 0) { leftType = "any"; } | ||
return parserOptions.functions | ||
.filter(function (fn) { | ||
return leftType === "any" || | ||
fn.return.type === "any" || | ||
fn.return.type === leftType; | ||
}) | ||
.map(function (config) { return ({ | ||
kind: "function", | ||
name: config.name, | ||
description: config.description, | ||
parameters: config.parameters, | ||
value: "".concat(config.name, "(").concat(config.parameters.map(function () { return ""; }).join(","), ")"), | ||
type: config.return.type, | ||
output: config.return.description, | ||
examples: config.examples, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
}); }); | ||
}; | ||
var getOperatorSuggestions = function (leftType, unary) { | ||
if (leftType === void 0) { leftType = "any"; } | ||
if (unary === void 0) { unary = false; } | ||
return parserOptions.operators | ||
.filter(function (operator) { | ||
return unary | ||
? !operator.left && operator.return.type === leftType | ||
: operator.left && | ||
(leftType === "any" || | ||
operator.left.type === "any" || | ||
operator.left.type === leftType); | ||
}) | ||
.map(function (config) { return ({ | ||
kind: "operator", | ||
name: config.name, | ||
arity: config.left ? "binary" : "unary", | ||
left: config.left, | ||
right: config.right, | ||
value: config.name, | ||
type: config.return.type, | ||
output: config.return.description, | ||
examples: config.examples, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
}); }); | ||
}; | ||
var getVariableSuggestions = function (leftType) { | ||
if (leftType === void 0) { leftType = "any"; } | ||
return parserOptions.variables | ||
.filter(function (variable) { | ||
return leftType === "any" || | ||
variable.type === "any" || | ||
variable.type === leftType; | ||
}) | ||
.map(function (config) { return ({ | ||
kind: "variable", | ||
name: config.name, | ||
description: config.description, | ||
value: config.name, | ||
type: config.type, | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
}); }); | ||
}; | ||
var getTermSuggestions = function (leftType, cursorPosition) { | ||
if (leftType === void 0) { leftType = "any"; } | ||
var functionSuggestions = getFunctionSuggestions(leftType); | ||
var operatorSuggestions = getOperatorSuggestions(leftType, true); | ||
var variableSuggestions = getVariableSuggestions(leftType); | ||
var booleanSuggestions = leftType === "boolean" | ||
? ["true", "false"].map(function (value) { return ({ | ||
kind: "variable", | ||
name: value, | ||
value, | ||
value: value, | ||
type: "boolean", | ||
start: cursorPosition, | ||
end: cursorPosition, | ||
})) | ||
}); }) | ||
: []; | ||
@@ -70,6 +101,7 @@ return functionSuggestions | ||
}; | ||
const findSuggestions = (expression, lastSuggestion = []) => { | ||
var findSuggestions = function (expression, lastSuggestion) { | ||
if (lastSuggestion === void 0) { lastSuggestion = []; } | ||
switch (expression.kind) { | ||
case "function": { | ||
const config = parserOptions.functions.find((config) => config.name === expression.name); | ||
var config = parserOptions.functions.find(function (config) { return config.name === expression.name; }); | ||
return cursorPosition <= expression.start | ||
@@ -79,7 +111,7 @@ ? lastSuggestion | ||
? getOperatorSuggestions(config === null || config === void 0 ? void 0 : config.return.type) | ||
: expression.arguments.reduce((last, arg) => findSuggestions(arg, last), lastSuggestion); | ||
: expression.arguments.reduce(function (last, arg) { return findSuggestions(arg, last); }, lastSuggestion); | ||
} | ||
case "operator": { | ||
const config = parserOptions.operators.find((config) => config.name === expression.name); | ||
const operatorSuggestions = getTermSuggestions((config === null || config === void 0 ? void 0 : config.return.type) || "any", cursorPosition); | ||
var config = parserOptions.operators.find(function (config) { return config.name === expression.name; }); | ||
var operatorSuggestions = getTermSuggestions((config === null || config === void 0 ? void 0 : config.return.type) || "any", cursorPosition); | ||
return cursorPosition <= expression.start && expression.left | ||
@@ -98,7 +130,9 @@ ? findSuggestions(expression.left, lastSuggestion) | ||
return getTermSuggestions(expression.type, cursorPosition) | ||
.filter((suggestion) => suggestion.name !== expression.name && | ||
suggestion.name | ||
.toLowerCase() | ||
.startsWith(expression.name.toLowerCase())) | ||
.map((suggestion) => (Object.assign(Object.assign({}, suggestion), { start: expression.start }))); | ||
.filter(function (suggestion) { | ||
return suggestion.name !== expression.name && | ||
suggestion.name | ||
.toLowerCase() | ||
.startsWith(expression.name.toLowerCase()); | ||
}) | ||
.map(function (suggestion) { return (__assign(__assign({}, suggestion), { start: expression.start })); }); | ||
} | ||
@@ -115,3 +149,3 @@ case "boolean": | ||
? getOperatorSuggestions("string") | ||
: expression.expressions.reduce((last, expr) => findSuggestions(expr, last), lastSuggestion); | ||
: expression.expressions.reduce(function (last, expr) { return findSuggestions(expr, last); }, lastSuggestion); | ||
case "expression": { | ||
@@ -126,8 +160,9 @@ return cursorPosition <= expression.start | ||
// TODO: add option to show operator suggestions | ||
.filter((suggestion) => suggestion.kind !== "operator") | ||
.sort((a, b) => a.name.localeCompare(b.name)) | ||
.sort((a, b) => (a === b ? 0 : a.type === "any" ? 1 : -1))); | ||
.filter(function (suggestion) { return suggestion.kind !== "operator"; }) | ||
.sort(function (a, b) { return a.name.localeCompare(b.name); }) | ||
.sort(function (a, b) { return (a === b ? 0 : a.type === "any" ? 1 : -1); })); | ||
}; | ||
export const getContextAtPosition = (parserOptions, expression, cursorPosition) => { | ||
const getContext = (expression) => { | ||
exports.getSuggestionsAtPosition = getSuggestionsAtPosition; | ||
var getContextAtPosition = function (parserOptions, expression, cursorPosition) { | ||
var getContext = function (expression) { | ||
switch (expression.kind) { | ||
@@ -138,10 +173,12 @@ case "function": { | ||
return null; | ||
const context = expression.arguments.reduce((context, arg) => context || getContext(arg), null); | ||
var context = expression.arguments.reduce(function (context, arg) { return context || getContext(arg); }, null); | ||
if (context) | ||
return context; | ||
const index = expression.arguments.findIndex((arg) => arg.start <= cursorPosition && arg.end >= cursorPosition); | ||
const config = parserOptions.functions.find((fn) => fn.name === expression.name && | ||
fn.parameters.every((param, i) => param.type === expression.arguments[i].type)) || | ||
parserOptions.functions.find((fn) => fn.name === expression.name); | ||
const functionContext = config && { | ||
var index = expression.arguments.findIndex(function (arg) { return arg.start <= cursorPosition && arg.end >= cursorPosition; }); | ||
var config = parserOptions.functions.find(function (fn) { | ||
return fn.name === expression.name && | ||
fn.parameters.every(function (param, i) { return param.type === expression.arguments[i].type; }); | ||
}) || | ||
parserOptions.functions.find(function (fn) { return fn.name === expression.name; }); | ||
var functionContext = config && { | ||
kind: "function", | ||
@@ -157,3 +194,3 @@ name: config.name, | ||
? config.parameters[index] | ||
? Object.assign(Object.assign({}, functionContext), { kind: "parameter", description: config.parameters[index].description, index }) : functionContext | ||
? __assign(__assign({}, functionContext), { kind: "parameter", description: config.parameters[index].description, index: index }) : functionContext | ||
: null; | ||
@@ -169,3 +206,3 @@ } | ||
case "variable": { | ||
const config = parserOptions.variables.find((variable) => variable.name === expression.name); | ||
var config = parserOptions.variables.find(function (variable) { return variable.name === expression.name; }); | ||
return config | ||
@@ -183,3 +220,3 @@ ? { | ||
case "string": | ||
return expression.expressions.reduce((context, arg) => context || getContext(arg), null); | ||
return expression.expressions.reduce(function (context, arg) { return context || getContext(arg); }, null); | ||
default: | ||
@@ -191,1 +228,2 @@ return null; | ||
}; | ||
exports.getContextAtPosition = getContextAtPosition; |
@@ -1,16 +0,54 @@ | ||
import { generateErrorId } from "./parser-utils"; | ||
export const buildTypeChecker = (options) => { | ||
const castableToStringTypes = options.functions | ||
.filter((fn) => fn.name === "String" && | ||
fn.parameters.length === 1 && | ||
fn.return.type === "string") | ||
.map((fn) => fn.parameters[0].type); | ||
const checkType = (expression, type) => { | ||
const isCastableToString = (expressionType) => type === "string" && castableToStringTypes.includes(expressionType); | ||
const { start, end } = expression; | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.buildTypeChecker = void 0; | ||
var parser_utils_1 = require("./parser-utils"); | ||
var buildTypeChecker = function (options) { | ||
var castableToStringTypes = options.functions | ||
.filter(function (fn) { | ||
return fn.name === "String" && | ||
fn.parameters.length === 1 && | ||
fn.return.type === "string"; | ||
}) | ||
.map(function (fn) { return fn.parameters[0].type; }); | ||
var checkType = function (expression, type) { | ||
var isCastableToString = function (expressionType) { | ||
return type === "string" && castableToStringTypes.includes(expressionType); | ||
}; | ||
var start = expression.start, end = expression.end; | ||
switch (expression.kind) { | ||
case "function": { | ||
const configs = options.functions.filter((config) => config.name === expression.name); | ||
const config = configs.find((config) => config.parameters.find((param, i) => checkType(expression.arguments[i], param.type)[1].length === 0)) || configs[0]; | ||
const functionErrors = config | ||
var configs = options.functions.filter(function (config) { return config.name === expression.name; }); | ||
var config = configs.find(function (config) { | ||
return config.parameters.find(function (param, i) { | ||
return checkType(expression.arguments[i], param.type)[1].length === 0; | ||
}); | ||
}) || configs[0]; | ||
var functionErrors = config | ||
? type === "any" || | ||
@@ -23,6 +61,6 @@ config.return.type === "any" || | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected return type of ${type} but got ${config.return.type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected return type of ".concat(type, " but got ").concat(config.return.type), | ||
}, | ||
@@ -32,14 +70,15 @@ ] | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: start + expression.name.length, | ||
message: `function ${expression.name} is not defined`, | ||
message: "function ".concat(expression.name, " is not defined"), | ||
}, | ||
]; | ||
const [args, argumentErrors] = ((config === null || config === void 0 ? void 0 : config.parameters) || []).reduce(([sumArgs, sumErrs], param, i) => { | ||
const [typedArg, errors] = checkType(expression.arguments[i], param.type); | ||
var _a = __read(((config === null || config === void 0 ? void 0 : config.parameters) || []).reduce(function (_a, param, i) { | ||
var _b = __read(_a, 2), sumArgs = _b[0], sumErrs = _b[1]; | ||
var _c = __read(checkType(expression.arguments[i], param.type), 2), typedArg = _c[0], errors = _c[1]; | ||
return [sumArgs.concat(typedArg), sumErrs.concat(errors)]; | ||
}, [[], []]); | ||
}, [[], []]), 2), args = _a[0], argumentErrors = _a[1]; | ||
return [ | ||
Object.assign(Object.assign({}, expression), { arguments: args, type: (config === null || config === void 0 ? void 0 : config.return.type) || type }), | ||
__assign(__assign({}, expression), { arguments: args, type: (config === null || config === void 0 ? void 0 : config.return.type) || type }), | ||
functionErrors.concat(argumentErrors.flat()), | ||
@@ -49,4 +88,4 @@ ]; | ||
case "operator": { | ||
const config = options.operators.find((config) => config.name === expression.name); | ||
const operatorErrors = config | ||
var config = options.operators.find(function (config) { return config.name === expression.name; }); | ||
var operatorErrors = config | ||
? type === "any" || | ||
@@ -59,6 +98,6 @@ config.return.type === "any" || | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected operator type of ${type} but got ${config.return.type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected operator type of ".concat(type, " but got ").concat(config.return.type), | ||
}, | ||
@@ -68,9 +107,9 @@ ] | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: start + expression.name.length, | ||
message: `operator ${expression.name} is not defined`, | ||
message: "operator ".concat(expression.name, " is not defined"), | ||
}, | ||
]; | ||
const [left, leftErrors] = (config === null || config === void 0 ? void 0 : config.left) | ||
var _b = __read((config === null || config === void 0 ? void 0 : config.left) | ||
? expression.left | ||
@@ -81,10 +120,10 @@ ? checkType(expression.left, config.left.type) | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected a term before the operator`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected a term before the operator", | ||
}, | ||
] | ||
: [undefined, []]; | ||
const [right, rightErrors] = config | ||
: [undefined, []], 2), left = _b[0], leftErrors = _b[1]; | ||
var _c = __read(config | ||
? expression.right | ||
@@ -95,11 +134,11 @@ ? checkType(expression.right, config.right.type) | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected a term after the operator`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected a term after the operator", | ||
}, | ||
] | ||
: [undefined, []]; | ||
: [undefined, []], 2), right = _c[0], rightErrors = _c[1]; | ||
return [ | ||
Object.assign(Object.assign({}, expression), { left, right, type: (config === null || config === void 0 ? void 0 : config.return.type) || type }), | ||
__assign(__assign({}, expression), { left: left, right: right, type: (config === null || config === void 0 ? void 0 : config.return.type) || type }), | ||
operatorErrors.concat(leftErrors, rightErrors), | ||
@@ -109,3 +148,3 @@ ]; | ||
case "variable": { | ||
const config = options.variables.find((config) => config.name === expression.name); | ||
var config = options.variables.find(function (config) { return config.name === expression.name; }); | ||
return config | ||
@@ -116,11 +155,11 @@ ? type === "any" || | ||
isCastableToString(config.type) | ||
? [Object.assign(Object.assign({}, expression), { type: config.type }), []] | ||
? [__assign(__assign({}, expression), { type: config.type }), []] | ||
: [ | ||
Object.assign(Object.assign({}, expression), { type: config.type }), | ||
__assign(__assign({}, expression), { type: config.type }), | ||
[ | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected type of ${type} but got ${config.type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected type of ".concat(type, " but got ").concat(config.type), | ||
}, | ||
@@ -130,9 +169,9 @@ ], | ||
: [ | ||
Object.assign(Object.assign({}, expression), { type }), | ||
__assign(__assign({}, expression), { type: type }), | ||
[ | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: start + expression.name.length, | ||
message: `variable ${expression.name} is not defined`, | ||
message: "variable ".concat(expression.name, " is not defined"), | ||
}, | ||
@@ -144,9 +183,9 @@ ], | ||
return [ | ||
Object.assign(Object.assign({}, expression), { errorID: generateErrorId(), type }), | ||
__assign(__assign({}, expression), { errorID: (0, parser_utils_1.generateErrorId)(), type: type }), | ||
[ | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected type of ${type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected type of ".concat(type), | ||
}, | ||
@@ -156,4 +195,4 @@ ], | ||
case "expression": { | ||
const [typedExpression, errors] = checkType(expression.expression, type); | ||
return [Object.assign(Object.assign({}, expression), { expression: typedExpression, type }), errors]; | ||
var _d = __read(checkType(expression.expression, type), 2), typedExpression = _d[0], errors_1 = _d[1]; | ||
return [__assign(__assign({}, expression), { expression: typedExpression, type: type }), errors_1]; | ||
} | ||
@@ -163,3 +202,3 @@ case "boolean": | ||
return [ | ||
Object.assign(Object.assign({}, expression), { type: expression.kind }), | ||
__assign(__assign({}, expression), { type: expression.kind }), | ||
type === "any" || | ||
@@ -171,6 +210,6 @@ type === expression.kind || | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected type of ${type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected type of ".concat(type), | ||
}, | ||
@@ -180,4 +219,5 @@ ], | ||
case "string": | ||
const [typedExpressions, errors] = expression.expressions.reduce(([typedExpressions, errors], expression) => { | ||
const [typedExpression, error] = checkType(expression, "string"); | ||
var _e = __read(expression.expressions.reduce(function (_a, expression) { | ||
var _b = __read(_a, 2), typedExpressions = _b[0], errors = _b[1]; | ||
var _c = __read(checkType(expression, "string"), 2), typedExpression = _c[0], error = _c[1]; | ||
return [ | ||
@@ -187,5 +227,5 @@ typedExpressions.concat(typedExpression), | ||
]; | ||
}, [[], []]); | ||
}, [[], []]), 2), typedExpressions = _e[0], errors = _e[1]; | ||
return [ | ||
Object.assign(Object.assign({}, expression), { expressions: typedExpressions, type: "string" }), | ||
__assign(__assign({}, expression), { expressions: typedExpressions, type: "string" }), | ||
type === "any" || type === "string" | ||
@@ -195,6 +235,6 @@ ? errors | ||
{ | ||
id: generateErrorId(), | ||
start, | ||
end, | ||
message: `expected type of ${type}`, | ||
id: (0, parser_utils_1.generateErrorId)(), | ||
start: start, | ||
end: end, | ||
message: "expected type of ".concat(type), | ||
}, | ||
@@ -207,1 +247,2 @@ ].concat(errors), | ||
}; | ||
exports.buildTypeChecker = buildTypeChecker; |
{ | ||
"name": "@feedloop/expression-parser", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"main": "lib/index.js", | ||
@@ -15,3 +15,3 @@ "types": "lib/index.d.ts", | ||
}, | ||
"gitHead": "73e4e754b82fb46a38f303db3bfe61b029ec3eac" | ||
"gitHead": "567b097877ecd08e83033c47486016c5145534d1" | ||
} |
@@ -9,7 +9,8 @@ { | ||
"strict": true, | ||
"module": "es6", | ||
"module": "CommonJS", | ||
"moduleResolution": "node", | ||
"target": "es6" | ||
"target": "ES5", | ||
"downlevelIteration": true | ||
}, | ||
"include": ["src/**/*.ts"] | ||
} |
133222
4168