UNPKG

amis-formula

Version:

负责 amis 里面的表达式实现,内置公式,编辑器等

789 lines (783 loc) 25.4 kB
/** * amis-formula v6.13.0 * Copyright 2021-2025 fex */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var lexer = require('./lexer.js'); var argListStates = { START: 0, COMMA: 1, SET: 2 }; var tempalteStates = { START: 0, SCRIPTING: 1 }; var objectStates = { START: 0, KEY: 1, COLON: 2, VALUE: 3, COMMA: 4 }; function parse(input, options) { var _a; var token; var lexer$1 = lexer.lexer(input, options); var tokens = []; var tokenChunk = []; // 允许的变量名字空间 var variableNamespaces = (_a = options === null || options === void 0 ? void 0 : options.variableNamespaces) !== null && _a !== void 0 ? _a : [ 'window', 'cookie', 'ls', 'ss' ]; if (!Array.isArray(variableNamespaces)) { variableNamespaces = []; } function next() { token = tokenChunk.length ? tokenChunk.shift() : lexer$1.next(); if (!token) { throw new TypeError('next token is undefined'); } tokens.push(token); } function back() { tokenChunk.unshift(tokens.pop()); token = tokens[tokens.length - 1]; } function matchPunctuator(operator) { return (token.type === lexer.TokenName[10 /* TokenEnum.Punctuator */] && (Array.isArray(operator) ? ~operator.indexOf(token.value) : token.value === operator)); } function fatal() { throw TypeError("Unexpected token ".concat(token.value || token.type, " in ").concat(token.start.line, ":").concat(token.start.column)); } function assert(result) { if (!result) { fatal(); } return result; } function expression() { return assignmentExpression(); } function skipWhiteSpaceChar() { while (token.type === lexer.TokenName[17 /* TokenEnum.Char */] && /^\s+$/m.test(token.value)) { next(); } } function collectFilterArg() { var arg = []; while (!matchPunctuator(':') && token.type !== lexer.TokenName[16 /* TokenEnum.OpenFilter */] && token.type !== lexer.TokenName[5 /* TokenEnum.CloseScript */]) { var item = literal() || numberLiteral() || stringLiteral() || template() || arrayLiteral() || rawScript() || objectLiteral(); if (item) { arg.push(item); } else { assert(~[ lexer.TokenName[7 /* TokenEnum.Identifier */], lexer.TokenName[10 /* TokenEnum.Punctuator */], lexer.TokenName[17 /* TokenEnum.Char */] ].indexOf(token.type)); // 其他的都当字符处理 if (arg.length && typeof arg[arg.length - 1] === 'string') { arg[arg.length - 1] += token.raw || token.value; } else { arg.push(token.raw || token.value); } next(); } } if (arg.length && typeof arg[arg.length - 1] === 'string') { arg[arg.length - 1] = arg[arg.length - 1].replace(/\s+$/, ''); if (!arg[arg.length - 1]) { arg.pop(); } } return arg; } function complexExpression() { var ast = expression(); var filters = []; while (token.type === lexer.TokenName[16 /* TokenEnum.OpenFilter */]) { next(); skipWhiteSpaceChar(); var name_1 = assert(identifier()); var fnName = name_1.name; var args = []; skipWhiteSpaceChar(); while (matchPunctuator(':')) { next(); skipWhiteSpaceChar(); var argContents = collectFilterArg(); if (argContents.length === 1) { argContents = argContents[0]; } else if (!argContents.length) { argContents = ''; } args.push(Array.isArray(argContents) ? { type: 'mixed', body: argContents } : argContents); } filters.push({ name: fnName, args: args }); } if (filters.length) { ast = { type: 'filter', input: ast, filters: filters, start: ast.start, end: filters[filters.length - 1].end }; } return ast; } function arrowFunction() { var ast = argList() || variable(); var args = []; var start; if ((ast === null || ast === void 0 ? void 0 : ast.type) === 'variable') { args = [ast]; start = ast.start; } else if ((ast === null || ast === void 0 ? void 0 : ast.type) === 'arg-list') { start = ast.start; args = ast.body; } if (Array.isArray(args) && matchPunctuator('=')) { next(); if (matchPunctuator('>')) { next(); var body = assert(expression()); return { type: 'anonymous_function', args: args, return: body, start: start, end: body.end }; } else { back(); } } return ast; } function conditionalExpression() { var ast = logicalOrExpression(); if (!ast) { return null; } if (matchPunctuator('?')) { next(); var consequent = assignmentExpression(); assert(consequent); assert(matchPunctuator(':')); next(); var alternate = assignmentExpression(); assert(alternate); return { type: 'conditional', test: ast, consequent: consequent, alternate: alternate, start: ast.start, end: alternate.end }; } return ast; } function binaryExpressionParser(type, operator, parseFunction, rightParseFunction, leftKey, rightKey) { var _a; if (rightParseFunction === void 0) { rightParseFunction = parseFunction; } if (leftKey === void 0) { leftKey = 'left'; } if (rightKey === void 0) { rightKey = 'right'; } var ast = parseFunction(); if (!ast) { return null; } if (matchPunctuator(operator)) { while (matchPunctuator(operator)) { next(); var right = assert(rightParseFunction()); ast = (_a = { type: type, op: operator }, _a[leftKey] = ast, _a[rightKey] = right, _a.start = ast.start, _a.end = right.end, _a); } } return ast; } function logicalOrExpression() { return binaryExpressionParser('or', '||', logicalAndExpression); } function logicalAndExpression() { return binaryExpressionParser('and', '&&', bitwiseOrExpression); } function bitwiseOrExpression() { return binaryExpressionParser('binary', '|', bitwiseXOrExpression); } function bitwiseXOrExpression() { return binaryExpressionParser('binary', '^', bitwiseAndExpression); } function bitwiseAndExpression() { return binaryExpressionParser('binary', '&', equalityExpression); } function equalityExpression() { return binaryExpressionParser('eq', '==', function () { return binaryExpressionParser('ne', '!=', function () { return binaryExpressionParser('streq', '===', function () { return binaryExpressionParser('strneq', '!==', relationalExpression); }); }); }); } function relationalExpression() { return binaryExpressionParser('lt', '<', function () { return binaryExpressionParser('gt', '>', function () { return binaryExpressionParser('le', '<=', function () { return binaryExpressionParser('ge', '>=', shiftExpression); }); }); }); } function shiftExpression() { return binaryExpressionParser('shift', '<<', function () { return binaryExpressionParser('shift', '>>', function () { return binaryExpressionParser('shift', '>>>', additiveExpression); }); }); } function additiveExpression() { return binaryExpressionParser('add', '+', function () { return binaryExpressionParser('minus', '-', multiplicativeExpression); }); } function multiplicativeExpression() { return binaryExpressionParser('multiply', '*', function () { return binaryExpressionParser('divide', '/', function () { return binaryExpressionParser('remainder', '%', powerExpression); }); }); } function powerExpression() { return binaryExpressionParser('power', '**', unaryExpression); } function unaryExpression() { var unaryOperators = ['+', '-', '~', '!']; var stack = []; while (matchPunctuator(unaryOperators)) { stack.push(token); next(); } var ast = postfixExpression(); assert(!stack.length || ast); while (stack.length) { var op = stack.pop(); ast = { type: 'unary', op: op.value, value: ast, start: op.start, end: op.end }; } return ast; } function postfixExpression(parseFunction) { if (parseFunction === void 0) { parseFunction = leftHandSideExpression; } var ast = parseFunction(); if (!ast) { return null; } while (matchPunctuator('[') || matchPunctuator('.')) { var isDot = matchPunctuator('.'); next(); var right = assert(isDot ? identifier() || numberLiteral() || rawScript() : expression()); if (!isDot) { assert(matchPunctuator(']')); next(); } ast = { type: 'getter', host: ast, key: right, start: ast.start, end: right.end }; } return ast; } function leftHandSideExpression() { return functionCall() || arrowFunction() || primaryExpression(); } function varibleKey(allowVariable, inObject) { if (allowVariable === void 0) { allowVariable = false; } if (inObject === void 0) { inObject = false; } return ((allowVariable ? variable() : identifier()) || stringLiteral() || numberLiteral() || (inObject ? objectTemplateKey() : template())); } function objectTemplateKey() { if (matchPunctuator('[')) { next(); var key = assert(template()); assert(matchPunctuator(']')); next(); return key; } return null; } function stringLiteral() { if (token.type === lexer.TokenName[11 /* TokenEnum.StringLiteral */]) { var cToken = token; next(); return { type: 'string', value: cToken.value, start: cToken.start, end: cToken.end }; } return null; } function numberLiteral() { if (token.type === lexer.TokenName[9 /* TokenEnum.NumericLiteral */]) { var value = token.value; var cToken = token; next(); return { type: 'literal', value: value, start: cToken.start, end: cToken.end }; } return null; } function template() { if (matchPunctuator('`')) { var start = token; var end = start; next(); var state = tempalteStates.START; var ast_1 = { type: 'template', body: [], start: start.start, end: start.end }; while (true) { if (state === tempalteStates.SCRIPTING) { var exp = assert(expression()); ast_1.body.push(exp); assert(token.type === lexer.TokenName[15 /* TokenEnum.TemplateRightBrace */]); next(); state = tempalteStates.START; } else { if (matchPunctuator('`')) { end = token; next(); break; } else if (token.type === lexer.TokenName[14 /* TokenEnum.TemplateLeftBrace */]) { next(); state = tempalteStates.SCRIPTING; } else if (token.type === lexer.TokenName[13 /* TokenEnum.TemplateRaw */]) { ast_1.body.push({ type: 'template_raw', value: token.value, start: token.start, end: token.end }); next(); } else { fatal(); } } } ast_1.end = end.end; return ast_1; } return null; } function identifier() { if (token.type === lexer.TokenName[7 /* TokenEnum.Identifier */]) { var cToken = token; next(); return { type: 'identifier', name: cToken.value, start: cToken.start, end: cToken.end }; } return null; } function primaryExpression() { return (variable() || literal() || numberLiteral() || stringLiteral() || template() || arrayLiteral() || objectLiteral() || (function () { var ast = expressionList(); if ((ast === null || ast === void 0 ? void 0 : ast.body.length) === 1) { return ast.body[0]; } return ast; })() || rawScript()); } function literal() { if (token.type === lexer.TokenName[8 /* TokenEnum.Literal */] || token.type === lexer.TokenName[1 /* TokenEnum.BooleanLiteral */]) { var value = token.value; var cToken = token; next(); return { type: 'literal', value: value, start: cToken.start, end: cToken.end }; } return null; } function functionCall() { if (token.type === lexer.TokenName[7 /* TokenEnum.Identifier */]) { var id = token; next(); if (matchPunctuator('(')) { var argList_1 = expressionList(); assert(argList_1); return { type: 'func_call', identifier: id.value, args: argList_1 === null || argList_1 === void 0 ? void 0 : argList_1.body, start: id.start, end: argList_1.end }; } else { back(); } } return null; } function arrayLiteral() { if (matchPunctuator('[')) { var argList_2 = expressionList('[', ']'); assert(argList_2); return { type: 'array', members: argList_2 === null || argList_2 === void 0 ? void 0 : argList_2.body, start: argList_2.start, end: argList_2.end }; } return null; } function expressionList(startOP, endOp) { if (startOP === void 0) { startOP = '('; } if (endOp === void 0) { endOp = ')'; } if (matchPunctuator(startOP)) { var start = token; var end = void 0; next(); var args = []; var state = argListStates.START; while (true) { if (state === argListStates.COMMA || !matchPunctuator(endOp)) { var arg = assert(expression()); args.push(arg); state = argListStates.START; if (matchPunctuator(',')) { next(); state = argListStates.COMMA; } } else if (matchPunctuator(endOp)) { end = token; next(); break; } } return { type: 'expression-list', body: args, start: start.start, end: end.end }; } return null; } function argList(startOP, endOp) { if (startOP === void 0) { startOP = '('; } if (endOp === void 0) { endOp = ')'; } var count = 0; var rollback = function () { while (count-- > 0) { back(); } return null; }; if (matchPunctuator(startOP)) { var start = token; var end = start; next(); count++; var args = []; var state = argListStates.START; while (!matchPunctuator(endOp)) { if (state === argListStates.COMMA || state === argListStates.START) { var arg = variable(false); if (!arg) { return rollback(); } count++; args.push(arg); state = argListStates.SET; } else if (state === argListStates.SET && matchPunctuator(',')) { next(); count++; state = argListStates.COMMA; } else { return rollback(); } } if (matchPunctuator(endOp)) { end = token; next(); return { type: 'arg-list', body: args, start: start.start, end: end.end }; } else { return rollback(); } } return null; } function objectLiteral() { if (matchPunctuator('{')) { var start = token; var end = start; next(); var ast_2 = { type: 'object', members: [], start: start.start, end: start.end }; var state = objectStates.START; var key = void 0, value = void 0; while (true) { if (state === objectStates.KEY) { assert(matchPunctuator(':')); next(); state = objectStates.COLON; } else if (state === objectStates.COLON) { value = assert(expression()); ast_2.members.push({ key: key, value: value }); state = objectStates.VALUE; } else if (state === objectStates.VALUE) { if (matchPunctuator(',')) { next(); state = objectStates.COMMA; } else if (matchPunctuator('}')) { end = token; next(); break; } else { fatal(); } } else { if (state != objectStates.COMMA && matchPunctuator('}')) { end = token; next(); break; } key = assert(varibleKey(false, true)); state = objectStates.KEY; } } ast_2.end = end.end; return ast_2; } return null; } function assignmentExpression() { return conditionalExpression(); } function contents() { var node = { type: 'document', body: [], start: token.start, end: token.end }; while (token.type !== lexer.TokenName[6 /* TokenEnum.EOF */]) { var ast_3 = raw() || rawScript() || oldVariable(); if (!ast_3) { break; } node.body.push(ast_3); } if (node.body.length) { node.end = node.body[node.body.length - 1].end; } return node; } function raw() { if (token.type !== lexer.TokenName[2 /* TokenEnum.RAW */]) { return null; } var cToken = token; next(); return { type: 'raw', value: cToken.value, start: cToken.start, end: cToken.end }; } function rawScript() { if (token.type !== lexer.TokenName[4 /* TokenEnum.OpenScript */]) { return null; } var start = token; var end = start; next(); var exp = assert(complexExpression()); assert(token.type === lexer.TokenName[5 /* TokenEnum.CloseScript */]); end = token; next(); return { type: 'script', body: exp, start: start.start, end: end.end }; } function variable(allowNameSpace) { if (allowNameSpace === void 0) { allowNameSpace = true; } if (token.type === lexer.TokenName[7 /* TokenEnum.Identifier */]) { var cToken = token; next(); if (allowNameSpace && matchPunctuator(':') && ~variableNamespaces.indexOf(cToken.value)) { next(); var body = assert(postfixExpression()); return { type: 'ns-variable', namespace: cToken.value, body: body, start: cToken.start, end: body.end }; } return { type: 'variable', name: cToken.value, start: cToken.start, end: cToken.end }; } else if (matchPunctuator('&')) { var v = token; next(); return { type: 'variable', name: '&', start: v.start, end: v.end }; } return null; } function oldVariable() { if (token.type !== lexer.TokenName[3 /* TokenEnum.Variable */]) { return null; } var prevToken = token; next(); return { type: 'script', body: prevToken.value.split('.').reduce(function (prev, key) { return prev ? { type: 'getter', host: prev, key: key, start: prevToken.start, end: prevToken.end } : { type: 'variable', name: key, start: prevToken.start, end: prevToken.end }; }, null), start: prevToken.start, end: prevToken.end }; } next(); var ast = (options === null || options === void 0 ? void 0 : options.variableMode) ? postfixExpression(variable) : (options === null || options === void 0 ? void 0 : options.evalMode) ? expression() : contents(); assert((token === null || token === void 0 ? void 0 : token.type) === lexer.TokenName[6 /* TokenEnum.EOF */]); return ast; } exports.parse = parse;