amis-formula
Version:
负责 amis 里面的表达式实现,内置公式,编辑器等
789 lines (783 loc) • 25.4 kB
JavaScript
/**
* 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;