enterprise-loyalty-components
Version:
企业版忠诚度组件库
1,503 lines (1,459 loc) • 86.3 kB
JavaScript
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var CodeMirror = _interopDefault(require('codemirror'));
require('codemirror/lib/codemirror.css');
require('codemirror/addon/dialog/dialog.css');
require('codemirror/addon/scroll/simplescrollbars.css');
require('codemirror/addon/hint/show-hint.css');
var moment = _interopDefault(require('moment'));
var injectSheet = _interopDefault(require('react-jss'));
var antd = require('antd');
var ReactDOM = require('react-dom');
var EventListener = _interopDefault(require('react-event-listener'));
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(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);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css = ".cm-property,\n.cm-custom-property-id {\n color: #05a;\n}\n\n.cm-function,\n.cm-declaration {\n color: #30a;\n}\n\n.cm-operator {\n color: #ec8a3c;\n}\n\n.cm-time,\n.cm-date,\n.cm-datetime {\n color: #9e6cef;\n}\n\n.CodeMirror {\n line-height: 20px;\n border: 1px solid #d9d9d9;\n transition: all 0.3s;\n border-radius: 2px;\n height: 150px !important;\n}\n\n.CodeMirror.CodeMirror-focused {\n border-color: #3dad91;\n box-shadow: 0 0 0 2px rgba(30, 160, 132, 0.2);\n}\n\n.CodeMirror .CodeMirror-placeholder {\n color: #999;\n}\n\n.CodeMirror-hints {\n z-index: 10000 !important;\n}\n\n.WrongExpression .CodeMirror {\n border-color: #f5222d;\n box-shadow: 0 0 0 2px rgba(241, 7, 7, 0.2);\n}\n\n.EditorDisabled .CodeMirror {\n border-color: #d9d9d9;\n box-shadow: none;\n background-color: #f5f5f5;\n cursor: not-allowed;\n}\n\n.EditorDisabled .CodeMirror-lines {\n cursor: not-allowed;\n}\n\n.EditorDisabled .CodeMirror-cursors {\n display: none;\n}\n";
styleInject(css);
function fullMatchTypes(type, targets) {
if (type === null) {
return false;
}
var types = type.split(' ');
var matched = true;
while (matched && targets.length) {
var target = targets.shift();
matched = types.indexOf(target) > -1;
}
return matched;
}
// 判断 obj 对象是否有 key 属性,obj 可使用全大小写
function includesIgnoreCase(arr, key) {
return !!arr.find(function (item) {
return item === key || item.toLowerCase() === key || item.toUpperCase() === key;
});
}
// 创建用以替换 token 的 Element
function createSpanReplacementNode(context, className) {
var $span = document.createElement('span');
$span.innerText = context;
if (className) {
$span.classList.add(className);
}
return $span;
}
// 创建日期类型的Maker,点击可弹出日期选择控件
function createDateReplacementNode(context, className, onMarkerClick) {
var $span = document.createElement('span');
$span.innerText = context;
if (className) {
$span.classList.add(className);
}
$span.addEventListener('click', onMarkerClick, false);
// 设置清除事件监听的函数,marker在清除的时候需要调用该函数
$span.removeMarkerListener = function () {
$span.removeEventListener('click', onMarkerClick, false);
};
return $span;
}
function defineMode(config) {
CodeMirror.defineMode('expression', function () {
var atoms = ['false', 'true', 'null'];
var fqn = config.fqn;
var operators = config.operators;
var functions = config.functions;
var declarations = config.declarations;
var operatorChars = /^[\/*+\-%<>!=&|~^]/;
var brackets = /^[\{}\(\)]/;
// const brackets = config.brackets || /^[\{}\(\)\[\]]/;
var specialOperatorWords = operators.reduce(function (o, n) {
return o.concat(n.split(' '));
}, []);
var paths = [];
function tokenBase(stream, state) {
var ch = stream.next();
if (ch === null) {
return null;
}
if (ch === ',') {
paths.length = 0;
return 'comma';
}
// {-1000}和{1000}表示为属性ID
if (ch === '{' && stream.match(/-?\d+\}/)) {
return 'custom-property-id';
}
if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
// numbers
stream.match(/^[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?/);
stream.match(/^\.(?!\.)/);
paths.length = 0;
return 'number';
}
else if (ch === "'" || ch === '"') {
// strings
state.tokenize = tokenLiteral(ch);
return state.tokenize(stream, state);
}
else if (brackets.test(ch)) {
// brackets
paths.length = 0;
return 'bracket';
}
else if (ch === '.') {
// .1 for 0.1
if (stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
paths.length = 0;
return 'number';
}
if (stream.match(/^\.+/)) {
return null;
}
return 'dot';
}
else if (operatorChars.test(ch)) {
// operators
stream.eatWhile(operatorChars);
paths.length = 0;
return 'operator';
}
else {
// 此处只匹配了中文,其他文字暂未处理
stream.eatWhile(/^[_\w\d\[\]\u4e00-\u9fa5]/);
var word = stream.current();
if (word === 'this') {
paths.length = 0;
paths.push('this');
return 'fqn root property';
}
if (paths[0] === 'this') {
paths.push(word);
}
if (paths.length > 0 && isInRightFqnPath(fqn, paths)) {
return 'fqn property';
}
paths.length = 0;
if (includesIgnoreCase(specialOperatorWords, word)) {
return 'operator';
}
if (includesIgnoreCase(atoms, word)) {
return 'atom';
}
if (includesIgnoreCase(functions, word)) {
return 'function';
}
if (declarations.includes(word)) {
return 'declaration';
}
return null;
}
}
// 'string', with char specified in quote escaped by '\'
function tokenLiteral(quote) {
return function (stream, state) {
var escaped = false;
var ch = stream.next();
while (ch) {
if (ch === quote && !escaped) {
state.tokenize = tokenBase;
break;
}
escaped = !escaped && ch === '\\';
ch = stream.next();
}
return 'string';
};
}
function pushContext(stream, state, type) {
state.context = {
prev: state.context,
indent: stream.indentation(),
col: stream.column(),
type: type
};
}
function popContext(state) {
state.indent = state.context.indent;
state.context = state.context.prev;
}
return {
startState: function () {
return { tokenize: tokenBase, context: null };
},
token: function (stream, state) {
if (stream.sol()) {
if (state.context && state.context.align === null) {
state.context.align = false;
}
}
if (state.tokenize === tokenBase && stream.eatSpace()) {
return null;
}
var style = state.tokenize(stream, state);
if (state.context && state.context.align === null) {
state.context.align = true;
}
var tok = stream.current();
if (tok === '(') {
pushContext(stream, state, ')');
}
else if (tok === '[') {
pushContext(stream, state, ']');
}
else if (state.context && state.context.type === tok) {
popContext(state);
}
return style;
},
// indent(state, textAfter) {
// const cx = state.context;
// if (!cx) {
// return CodeMirror.Pass;
// }
// const closing = textAfter.charAt(0) === cx.type;
// if (cx.align) {
// return cx.col + (closing ? 0 : 1);
// } else {
// return cx.indent + (closing ? 0 : config.indentUnit);
// }
// },
// closeBrackets: "()[]{}''\"\"``"
closeBrackets: "(){}''\"\"``"
};
});
}
// 判断 leefPath 是否在 fqn 的路径上
function isInRightFqnPath(fqn, paths) {
var cPaths = paths.slice();
var matchedObj = fqn;
while (cPaths.length > 0) {
var path = cPaths.shift();
if (path === 'this') {
matchedObj = fqn;
}
else if (matchedObj.hasOwnProperty(path)) {
if (matchedObj[path].$type) {
matchedObj = matchedObj[path].$type;
}
else {
matchedObj = matchedObj[path];
}
}
else {
return false;
}
}
return matchedObj;
}
function isObject(data) {
return Object.prototype.toString.call(data) === '[object Object]';
}
var Pos = CodeMirror.Pos;
function scriptHint(editor, getToken, options) {
// Find the token at the cursor
var cur = editor.getCursor();
var token = getToken(editor, cur);
if (/\b(?:string|comment)\b/.test(token.type)) {
return;
}
var innerMode = CodeMirror.innerMode(editor.getMode(), token.state);
token.state = innerMode.state;
// If it's not a 'word-style' token, ignore the token.
var isWordStyle = /^[\S]*$/.test(token.string) && token.string !== '.';
if (!isWordStyle) {
token = {
start: cur.ch, end: cur.ch,
string: '',
state: token.state,
type: token.string === '.' ? 'property' : null
};
}
else if (token.end > cur.ch) {
token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start);
}
else if (isWordStyle) {
var start = cur.ch - token.string.length;
var preToken = getToken(editor, { line: cur.line, ch: start });
if (preToken.string === '.') {
token = {
start: start,
end: start,
string: token.string,
state: token.state,
type: 'property'
};
}
}
var tprop = token;
var context;
// If it is a property, find out what it is a property of.
while (fullMatchTypes(tprop.type, ['property'])) {
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.string === '.') {
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (!context) {
context = [];
}
context.push(tprop);
}
}
return {
list: getCompletions(token, context, options),
from: Pos(cur.line, token.start),
to: Pos(cur.line, token.start + token.string.length)
};
}
function forAllProps(obj, callback) {
if (isObject(obj)) {
Object.keys(obj).forEach(function (item) {
callback(item);
});
}
}
function getCompletions(token, context, options) {
var found = [];
var start = token.string.toLowerCase();
var global = options && options.globalScope || {};
function maybeAdd(str) {
if (str.toLowerCase().lastIndexOf(start, 0) === 0 && found.indexOf(str) === -1) {
found.push(str);
}
}
function maybeAddCustomProperty(property) {
var text = "{" + property.id + "}";
if (property.name.startsWith(start) && !found.find(function (item) { return item.text === text; })) {
found.push({
text: text,
displayText: property.name
});
}
}
function maybeAddDeclaration(declaration) {
if (declaration.toLowerCase().lastIndexOf(start, 0) === 0 && found.indexOf(declaration) === -1) {
found.push({
text: generateDefaultDeclarationValue(declaration),
displayText: declaration
});
}
}
if (context && context.length) {
// If this is a property, see if it belongs to some object we can
// find in the current environment.
var obj = context.pop();
var base = void 0;
if (fullMatchTypes(obj.type, ['fqn', 'property'])) {
base = base || getFqnObjWithPath(global, obj.string);
}
while (base !== null && context.length) {
var children = base[context.pop().string];
// 存在$type属性,表示路径到终点了
if (children.$type) {
base = null;
}
else {
base = children;
}
}
if (base !== null) {
forAllProps(base, maybeAdd);
}
}
else {
options.operators.forEach(maybeAdd);
options.declarations.forEach(maybeAddDeclaration);
options.functions.forEach(maybeAdd);
options.customProperties.forEach(maybeAddCustomProperty);
}
return found;
}
function getFqnObjWithPath(global, path) {
var pathArr = path.split('.');
var obj = global;
while (pathArr.length) {
var p = pathArr.shift();
if (p === 'this') {
continue;
}
obj = obj[p];
}
return obj;
}
function generateHint(config) {
return function (editor, options) {
options.globalScope = config.fqn;
options.operators = config.operators || [];
options.functions = config.functions || [];
options.declarations = config.declarations || [];
options.customProperties = config.customProperties || [];
return scriptHint(editor, function (e, cur) {
return e.getTokenAt(cur);
}, options);
};
}
function registerHint(config) {
CodeMirror.registerHelper('hint', 'expression', generateHint(config));
}
// 生成默认的类型声明值
function generateDefaultDeclarationValue(declaration) {
var declarationValue = '';
if (declaration === 'DateTime') {
declarationValue = "\"" + moment().toISOString() + "\"";
}
else if (declaration === 'Date') {
declarationValue = "\"" + moment().format('YYYY-MM-DD') + "\"";
}
else if (declaration === 'Time') {
declarationValue = "\"" + moment().format('HH:mm:ss') + "\"";
}
return declaration + "(" + declarationValue + ")";
}
var TypeEnum;
(function (TypeEnum) {
TypeEnum["Number"] = "Number";
TypeEnum["Integer"] = "Integer";
TypeEnum["String"] = "String";
TypeEnum["Date"] = "Date";
TypeEnum["Time"] = "Time";
TypeEnum["DateTime"] = "DateTime";
TypeEnum["Arithmetic"] = "Arithmetic";
TypeEnum["Comparison"] = "Comparison";
TypeEnum["LogicOperator"] = "LogicOperator";
TypeEnum["IdentiferComparison"] = "IdentiferComparison";
TypeEnum["BracketStart"] = "BracketStart";
TypeEnum["BracketEnd"] = "BracketEnd";
TypeEnum["Comma"] = "Comma";
TypeEnum["Semicolon"] = "Semicolon";
TypeEnum["Function"] = "Function";
TypeEnum["FunctionCall"] = "FunctionCall";
TypeEnum["FqnProperty"] = "FqnProperty";
TypeEnum["CustomProperty"] = "CustomProperty";
TypeEnum["Identifier"] = "Identifier";
TypeEnum["Boolean"] = "Boolean";
TypeEnum["Null"] = "Null";
TypeEnum["LogicNot"] = "LogicNot";
})(TypeEnum || (TypeEnum = {}));
function isScalaType(t) {
return [
TypeEnum.CustomProperty,
TypeEnum.FqnProperty,
TypeEnum.Boolean,
TypeEnum.Integer,
TypeEnum.Number,
TypeEnum.String,
TypeEnum.Null
].includes(t);
}
function isOperatorType(t) {
return [
TypeEnum.Comparison,
TypeEnum.Arithmetic,
TypeEnum.LogicOperator,
TypeEnum.IdentiferComparison
].includes(t);
}
/**
* 判断路径path是否在target中存在
* @param path 路径,必须以this开头
* @param fqn 目标对象
*/
function matchFqnPath(path, fqn, pos) {
var paths = path.split('.');
paths.shift();
var obj = fqn;
while (paths.length > 0) {
var subPath = paths.shift();
if (obj.hasOwnProperty && obj.hasOwnProperty(subPath)) {
obj = obj[subPath];
}
else {
throw { code: 'InvalidFqnPath', pos: pos };
}
}
return obj;
}
/**
* 获取括号结束位置,即左括号对应的右括号的位置
* start 为左括号的位置
*/
function getBracketEndTokenPosition(start, tokens) {
var i = start;
var bracketCount = 0;
while ((i < tokens.length && bracketCount > 0) || i === start) {
var itoken = tokens[i++];
if (itoken.type === TypeEnum.BracketStart) {
bracketCount++;
}
else if (itoken.type === TypeEnum.BracketEnd) {
bracketCount--;
}
}
if (bracketCount > 0) {
throw FunctionError(tokens[start], 'Function Arguments must end with `)`.');
}
return i - 1;
}
function FunctionError(token, message) {
return { code: 'InvalidFunction', pos: token.pos, message: message };
}
function getFuncArgs(tokens) {
var args = [];
var i = 0;
var brackCount = 0;
while (i < tokens.length) {
var token = tokens[i++];
if (token.type === TypeEnum.Comma) {
if (brackCount === 0) {
args.push(tokens.splice(0, i - 1));
tokens.shift();
i = 0;
}
// 防止出现`SUM(1,2,)`参数最后为逗号的情况
if (!tokens.length) {
throw { message: 'Function arguments error' };
}
continue;
}
if (token.type === TypeEnum.BracketStart) {
brackCount++;
}
else if (token.type === TypeEnum.BracketEnd) {
brackCount--;
}
if (i === tokens.length) {
if (brackCount !== 0) {
throw { message: 'Function arguments error' };
}
args.push(tokens);
}
}
return args;
}
function macthOperatorType(valve) {
if ([','].includes(valve)) {
return TypeEnum.Comma;
}
if (['==', '!=', '>', '>=', '<', '<='].includes(valve)) {
return TypeEnum.Comparison;
}
if (['&&', '||', '!'].includes(valve)) {
return TypeEnum.LogicOperator;
}
if (['+', '-', '*', '/', '%'].includes(valve)) {
return TypeEnum.Arithmetic;
}
throw { code: 'invalid-operator', message: '无效的比较符' };
}
// 判断是否为正确的日期格式
function isAcceptableDate(v) {
return /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/.test(v);
}
// 判断是否为正确的时间格式
function isAcceptableTime(v) {
// return /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$/.test(v);
return /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])$/.test(v);
}
// 判断是否为正确的ISO时间格式
function isAcceptableDateTime(v) {
// tslint:disable-next-line
return /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/.test(v);
}
var ArithmeticOperators = ['+', '-', '*', '/', '%'];
var ComparisonOperators = ['>', '<', '='];
var SingleCharOperators = ['(', ')', ';'];
var LogicOperators = ['&', '|', '!'];
function Position(start, end, line) {
return { start: start, end: end, line: line };
}
function generateTokens(input, options) {
var fqn = options.fqn;
var functions = options.functions;
var declarations = options.declarations;
var customProperties = options.customProperties;
var tokens = [];
var len = input.length;
var i = 0;
var line = 0;
while (i < len) {
var ch = input[i++];
if (ch === ';') {
break;
}
if (ch === ' ' || ch === '\t') {
continue;
}
if (ch === '\n') {
line++;
continue;
}
// 特殊字符串
if (SingleCharOperators.includes(ch)) {
tokens.push({
type: {
'(': TypeEnum.BracketStart,
')': TypeEnum.BracketEnd
}[ch],
value: ch,
pos: Position(i - 1, i - 1, line)
});
continue;
}
var doubleOperators = eatSpecialDoubleOperators(input.slice(i - 1));
if (doubleOperators) {
tokens.push({
type: TypeEnum.IdentiferComparison,
value: doubleOperators.replace(/\s+/g, ' ').toUpperCase(),
pos: Position(i - 1, i - 1 + doubleOperators.length, line)
});
i = i + doubleOperators.length;
continue;
}
var singleOperators = eatSpecialSingleOperators(input.slice(i - 1));
if (singleOperators) {
tokens.push({
type: TypeEnum.IdentiferComparison,
value: singleOperators.toUpperCase(),
pos: Position(i - 1, i - 1 + singleOperators.length, line)
});
i = i + singleOperators.length;
continue;
}
var commaToken = eatContinuousOperators([','], i - 1);
if (commaToken) {
tokens.push(__assign({}, commaToken, { type: macthOperatorType(commaToken.value) }));
i = commaToken.pos.end + 1;
continue;
}
var continueToken = eatContinuousOperators(LogicOperators.concat(ArithmeticOperators, ComparisonOperators), i - 1);
if (continueToken) {
tokens.push(__assign({}, continueToken, { type: macthOperatorType(continueToken.value) }));
i = continueToken.pos.end + 1;
continue;
}
var customProperty = eatCustomProperties(i - 1);
if (customProperty) {
tokens.push(customProperty);
i = customProperty.pos.end + 1;
continue;
}
// fqn
if (ch === 't') {
var start = i - 1;
var firstWord = input.slice(start, start + 4);
var nextOfThis = input[start + 4];
if (firstWord === 'this' && ['.', ' ', '\t', undefined].includes(nextOfThis)) {
i = start + 4;
while (i < len && /[A-Za-z_0-9\.\[\]]/.test(input[i])) {
i++;
}
var word = input.slice(start, i);
var pos = Position(start, i - 1, line);
var fqnPathType = matchFqnPath(word, fqn, pos);
if (word) {
tokens.push({
vType: fqnPathType,
type: TypeEnum.FqnProperty,
value: word,
pos: pos
});
}
continue;
}
}
// 内置函数
if (/[A-Za-z_]/.test(ch)) {
var start = i - 1;
while (i < len && /[A-Za-z_0-9]/.test(input[i])) {
i++;
}
var word = input.slice(start, i);
if ((functions.includes(word.toLowerCase()) || functions.includes(word.toUpperCase()))
&& input[i] === '(') {
tokens.push({
type: TypeEnum.Function,
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
else if (declarations.includes(word) && input[i] === '(') {
tokens.push({
type: TypeEnum.Function,
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
else if (['TRUE', 'true', 'FALSE', 'false'].includes(word)) {
tokens.push({
type: TypeEnum.Boolean,
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
else if (['NULL', 'null'].includes(word)) {
tokens.push({
type: TypeEnum.Null,
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
else {
throw { code: 'InvalidIdentifier', pos: Position(start, i - 1, line) };
}
}
// 数字(整数&浮点数)
if (/[0-9]/.test(ch)) {
var start = i - 1;
var isDot = false;
while (i < len) {
var char = input[i];
if (char === '.') {
if (isDot) {
throw {
code: 'InvalidNumberFormatter',
message: 'Too many dot in a number.',
pos: Position(i, i, line)
};
}
isDot = true;
i++;
}
else if (/[0-9]/.test(char)) {
i++;
}
else {
break;
}
}
var word = input.slice(start, i);
var type = word.includes('.') ? TypeEnum.Number : TypeEnum.Integer;
tokens.push({
type: type,
vType: { $type: type },
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
// 字符串字面量
if (ch === '\'' || ch === '"') {
var start = i - 1;
var escaped = false;
while (i < len) {
var char = input[i];
if (char === ch && !escaped) {
break;
}
escaped = !escaped && char === '\\';
i++;
}
if (input[i] !== ch) {
throw {
code: 'StringEndLost',
message: '字符串缺少结束符',
pos: Position(start, i - 1, line)
};
}
var word = input.slice(start + 1, i);
i++;
tokens.push({
type: TypeEnum.String,
vType: { $type: TypeEnum.String },
value: word,
pos: Position(start, i - 1, line)
});
continue;
}
throw { code: 'InvalidIdentifier', pos: Position(i - 1, i - 1, line) };
}
return tokens;
// 连续的操作符
function eatContinuousOperators(opers, start) {
var index = start;
var word = input[index];
var leftSpace = input[index - 1] ? [' ', '\t'].includes(input[index - 1]) : false;
var rightSpace = input[index + 1] ? [' ', '\t'].includes(input[index + 1]) : false;
if (opers.includes(word)) {
while (opers.includes(input[index + 1])) {
word += input[index + 1];
index++;
}
return {
value: word,
pos: Position(start, index, line),
leftSpace: leftSpace,
rightSpace: rightSpace
};
}
return false;
}
// 自定义属性ID=> {12345}
function eatCustomProperties(start) {
var matched = input.slice(start).match(/^-?\{\d+\}/);
if (matched) {
var value = matched[0];
var pos = Position(start, start + value.length - 1, line);
var propertyId_1 = Number(value.slice(1, value.length - 1));
var customProperty = customProperties.find(function (item) { return item.id === propertyId_1; });
if (!customProperty) {
throw { code: 'invalid-custom-property', pos: pos };
}
return {
value: value,
pos: pos,
type: TypeEnum.CustomProperty,
vType: { $type: customProperty.dataType }
};
}
return false;
}
}
var specialSingleOperators = ['in', 'contain', 'between', 'and'];
function eatSpecialSingleOperators(input) {
var i = 0;
var word = input[i];
while (i <= input.length && ![' ', '\t', undefined].includes(input[i + 1])) {
word += input[++i];
}
if (specialSingleOperators.find(function (item) {
return item.toLowerCase() === word || item.toUpperCase() === word;
})) {
return word;
}
return false;
}
function eatSpecialDoubleOperators(input) {
var matched = matchRegExpList(input, [
/^(begin\s+with)\s+/, /^(BEGIN\s+WITH)\s+/,
/^(end\s+with)\s+/, /^(END\s+WITH)\s+/,
/^(include\s+any)\s+/, /^(INCLUDE\s+ANY)\s+/,
/^(include\s+all)\s+/, /^(INCLUDE\s+ALL)\s+/,
/^(exclude\s+any)\s+/, /^(EXCLUDE\s+ANY)\s+/,
/^(exclude\s+all)\s+/, /^(EXCLUDE\s+ALL)\s+/,
/^(not\s+in)\s+/, /^(NOT\s+IN)\s+/,
/^(not\s+contain)\s+/, /^(NOT\s+CONTAIN)\s+/
]);
if (matched) {
return matched;
}
return false;
}
function matchRegExpList(input, regexpList) {
var i = 0;
while (i < regexpList.length) {
var matched = input.match(regexpList[i]);
if (matched) {
return matched[1];
}
i++;
}
return false;
}
function matchBrackets(tokens) {
var start = tokens.findIndex(function (item) { return item.type === TypeEnum.BracketStart; });
if (start === -1) {
return;
}
var end = getBracketEndTokenPosition(start, tokens);
var eatTokens = tokens.slice(start, end + 1);
if (eatTokens.length <= 2) {
throw {
code: 'BracketsContentEmpty',
message: '括号内内容不能为空',
pos: {
start: tokens[start].pos.start,
end: tokens[end].pos.end,
line: tokens[start].pos.line
}
};
}
tokens.splice(start, eatTokens.length, match(eatTokens.slice(1, eatTokens.length - 1)));
matchBrackets(tokens);
}
function matchFunctions(tokens) {
var index = tokens.findIndex(function (item) { return item.type === TypeEnum.Function; });
if (index === -1) {
return;
}
var start = index + 1;
var end = getBracketEndTokenPosition(start, tokens);
var eatTokens = tokens.slice(index, end + 1);
var argsTokens = tokens.slice(index + 2, end);
var args = getFuncArgs(argsTokens);
args.forEach(function (arg) {
if (!arg.length) {
throw { code: 'invalid-function-arg', message: '函数参数值不能为空' };
}
});
tokens.splice(index, eatTokens.length, {
type: TypeEnum.FunctionCall,
value: tokens[index].value,
tokens: eatTokens,
args: args.map(function (arg) { return match(arg); })
});
matchFunctions(tokens);
}
function matchCommonOperator(tokens, type, operators) {
var i = tokens.findIndex(function (item) { return item.type === type && operators.includes(item.value); });
if (i === -1) {
return;
}
var token = tokens[i];
var left = tokens[i - 1];
var right = tokens[i + 1];
if (!left || !right) {
throw { code: 'E1' };
}
tokens.splice(i - 1, 3, {
tokens: [left, token, right],
operator: token,
left: match([left]),
right: match([right])
});
matchCommonOperator(tokens, type, operators);
}
function matchArithmetic(tokens, operators) {
matchCommonOperator(tokens, TypeEnum.Arithmetic, operators);
}
function matchLogicOperator(tokens) {
matchCommonOperator(tokens, TypeEnum.LogicOperator, ['&&', '||']);
}
function matchComparison(tokens) {
matchCommonOperator(tokens, TypeEnum.Comparison, ['>', '>=', '<', '<=', '==', '!=']);
matchCommonOperator(tokens, TypeEnum.IdentiferComparison, [
'CONTAIN', 'NOT CONTAIN', 'IN', 'NOT IN', 'BEGIN WITH', 'END WITH',
'INCLUDE ANY', 'INCLUDE ALL', 'EXCLUDE ANY', 'EXCLUDE ALL', 'BETWEEN'
]);
}
function matchLogicNot(tokens) {
var i = tokens.findIndex(function (vtoken) {
return vtoken.type === TypeEnum.LogicOperator
&& vtoken.value.includes('!');
});
if (i === -1) {
return;
}
var token = tokens[i];
var right = tokens[i + 1];
if (!right) {
throw { code: 'E1' };
}
tokens.splice(i, 2, {
tokens: [token, right],
operator: token,
right: match([right])
});
matchLogicNot(tokens);
}
function matchIdentiferComparison(tokens) {
var i = tokens.findIndex(function (vtoken) { return (vtoken.type === TypeEnum.IdentiferComparison); });
if (i === -1) {
return '';
}
var token = tokens[i];
if (['BEGIN WITH', 'END WITH', 'INCLUDE ANY', 'INCLUDE ALL', 'EXCLUDE ANY', 'EXCLUDE ALL'].includes(token.value)) {
var left = tokens[i - 1];
var right = tokens[i + 1];
if (!left || !right) {
throw { code: 'E1' };
}
tokens.splice(i - 1, 3, {
tokens: [left, token, right],
operator: token,
left: match([left]),
right: match([right])
});
}
else if (token.value === 'BETWEEN') {
var left = tokens[i - 1];
if (!left) {
throw { code: 'BetweenLeftComparsionTokenError' };
}
var endIndex = matchBetweenAnd(tokens, i);
var firstComparsionTokens = tokens.slice(i + 1, endIndex);
if (firstComparsionTokens.length !== 1) {
throw { code: 'AndLeftComparsionTokenError' };
}
var secondComparsionToken = tokens[endIndex + 1];
if (!secondComparsionToken) {
throw { code: 'AndRightComparsionTokenError' };
}
tokens.splice(i - 1, 5, {
tokens: [left, token, firstComparsionTokens[0], tokens[endIndex], secondComparsionToken],
operator: token,
left: match([left]),
andLeft: match([firstComparsionTokens[0]]),
andRight: match([secondComparsionToken])
});
}
}
// function matchNegativeDigit(tokens: IToken[]) {
// const i = tokens.findIndex(token => {
// return token.type === TypeEnum.Arithmetic && token.value === '-';
// });
// const leftToken = tokens[i-1];
// const rightToken = tokens[i+1];
// }
function match(tokens) {
if (tokens.length === 0) {
return;
}
if (tokens.length === 1) {
var token = tokens[0];
if (!token.type) {
return token;
}
if (!isScalaType(token.type) && token.type !== TypeEnum.FunctionCall) {
throw { code: 'invalid-token-start' };
}
return tokens[0];
}
if (tokens.length === 2) {
var token = tokens[0];
if (token.type === TypeEnum.LogicOperator && token.value.includes('!')) {
var right = tokens[1];
return {
tokens: [token, right],
operator: token,
right: match([right])
};
}
else if (token.type === TypeEnum.Arithmetic) {
if (token.value === '-') {
if (!token.rightSpace) {
var right = tokens[1];
return {
tokens: [token, right],
operator: token,
right: match([right])
};
}
}
}
throw { code: 'invalid-token-size' };
}
if (tokens.length === 3) {
if (tokens[0].type === 'Function') {
matchFunctions(tokens);
return match(tokens);
}
if (!isOperatorType(tokens[1].type)) {
throw { code: 'invalid-operator' };
}
if (!isScalaType(tokens[0].type)) {
if (!tokens[0].left) {
throw { code: 'invalid-expression' };
}
}
if (!isScalaType(tokens[2].type)) {
if (!tokens[2].left) {
throw { code: 'invalid-expression' };
}
}
return {
left: tokens[0],
operator: tokens[1],
right: tokens[2]
};
}
// 函数
matchFunctions(tokens);
// 括号
matchBrackets(tokens);
// 逻辑非
matchLogicNot(tokens);
// 四则运算乘除取余
matchArithmetic(tokens, ['*', '/', '%']);
// 四则运算加减
matchArithmetic(tokens, ['+', '-']);
// 比较 BEGIN WITH/END WITH...
matchIdentiferComparison(tokens);
// 比较符运算
matchComparison(tokens);
// 逻辑与、逻辑或
matchLogicOperator(tokens);
return match(tokens);
}
function matchBetweenAnd(tokens, betweenIndex) {
var i = betweenIndex + 1;
var matched = false;
while (i < tokens.length) {
if (tokens[i].type === TypeEnum.IdentiferComparison && tokens[i].value === 'AND') {
matched = true;
return i;
}
i++;
}
if (!matched) {
throw { code: 'BetweenNotMatchedAnd' };
}
return i;
}
function generateType($type) {
return { $type: $type };
}
// 是否为数字类型
function isDigit(v) {
return ['Number', 'Integer'].includes(v);
}
// 是否存在非数字类型
function hasNotDigitArgs(args) {
return args.find(function (arg) { return !isDigit(arg.vType.$type); });
}
// 是否存在Number类型
function hasNumberArgs(args) {
return args.find(function (arg) { return 'Number' === arg.vType.$type; });
}
// 是否存在非布尔类型
function hasNotBooleanArgs(args) {
return args.find(function (arg) { return 'Boolean' !== arg.vType.$type; });
}
// 是否为字符串类型
function isString(v) {
return ['String'].includes(v);
}
// 是否存在非类字符串类型
function hasNotStringArgs(args) {
return args.find(function (arg) { return !isString(arg.vType.$type); });
}
function AND(later) {
var args = later.args;
if (hasNotBooleanArgs(args)) {
throw { message: 'AND 函数的参数只能为布尔类型' };
}
later.vType = generateType('Boolean');
return later.vType;
}
function AVG(later) {
var args = later.args;
var firstArgType = args[0].vType.$type;
if (['IntegerArray', 'NumberArray'].includes(firstArgType)) {
if (args.length > 1) {
throw { message: 'AVG 函数的第一个参数如果为数组,则只接受一个参数' };
}
later.vType = generateType('Number');
return later.vType;
}
if (hasNotDigitArgs(args)) {
throw { message: 'AVG 函数的参数不能为非数字类型' };
}
later.vType = generateType('Number');
return later.vType;
}
function COUNT(later) {
var args = later.args;
var firstArgType = args[0].vType.$type;
if (['IntegerArray', 'NumberArray'].includes(firstArgType)) {
if (args.length > 1) {
throw { message: 'COUNT 函数的第一个参数如果为数组,则只接受一个参数' };
}
later.vType = generateType(firstArgType === 'IntegerArray' ? 'Integer' : 'Number');
return later.vType;
}
if (args.length === 1) {
later.vType = generateType('Integer');
return later.vType;
}
if (isObject$2(args[0].vType.$type) && args.length > 1) {
throw { message: '当 COUNT 函数第一个参数为数组时,只接受一个参数' };
}
later.vType = generateType(TypeEnum.Integer);
return later.vType;
}
function isObject$2(v) {
return Object.prototype.toString.call(v) === '[object Object]';
}
// 在日期上添加指定 秒/分/小时/日/月/年
function DATE_ADD(later, name) {
var args = later.args;
if (args.length !== 2) {
throw { message: name + " \u51FD\u6570\u7684\u53EA\u63A5\u53D7\u4E24\u4E2A\u53C2\u6570" };
}
if ('DateTime' !== args[0].vType.$type) {
throw { message: name + " \u51FD\u6570\u7684\u7B2C\u4E00\u4E2A\u53C2\u6570\u5FC5\u987B\u4E3A DateTime \u7C7B\u578B" };
}
if ('Integer' !== args[1].vType.$type) {
throw { message: name + " \u51FD\u6570\u7684\u7B2C\u4E8C\u4E2A\u53C2\u6570\u5FC5\u987B\u4E3A\u6574\u6570\u7C7B\u578B" };
}
later.vType = generateType('DateTime');
return later.vType;
}
// 日期上指定的值
function DATE_FETCH(later, name) {
var args = later.args;
if (args.length !== 1) {
throw { message: name + " \u51FD\u6570\u7684\u53EA\u63A5\u53D7\u4E00\u4E2A\u53C2\u6570" };
}
if ('DateTime' !== args[0].vType.$type) {
throw { message: name + " \u51FD\u6570\u7684\u53C2\u6570\u5FC5\u987B\u4E3A DateTime \u7C7B\u578B" };
}
later.vType = generateType('Integer');
return later.vType;
}
// 生成日期对象
function DATE(later) {
var args = later.args;
if (args.length !== 1) {
throw { message: "Date \u51FD\u6570\u7684\u53EA\u63A5\u53D7\u4E00\u4E2A\u53C2\u6570" };
}
var arg = args[0];
if (arg.vType.$type !== 'String' || !arg.value) {
throw { message: 'Date 函数的参数必须为字符串类型' };
}
if (!isAcceptableDate(arg.value)) {
throw { message: 'Date 函数参数必须为 yyyy-dd-mm' };
}
later.vType = generateType('Date');
return later.vType;
}
// 生成日期时间对象
function DATETIME(later) {
var args = later.args;
if (args.length !== 1) {
throw { message: "DateTime \u51FD\u6570\u7684\u53EA\u63A5\u53D7\u4E00\u4E2A\u53C2\u6570" };
}
var arg = args[0];
if (arg.vType.$type !== 'String' || !arg.value) {
throw { message: 'DateTime 函数的参数必须为字符串类型' };
}
// tslint:disable-next-line
if (!isAcceptableDateTime(arg.value)) {
throw { message: 'DateTime 函数参数必须为ISO时间格式 2019-01-01T00:00:00.000Z' };
}
later.vType = generateType('DateTime');
return later.vType;
}
// 比较两个日期在指定单位上的偏移量
function DURATION_DIFF(later) {
var name = 'DURATION_DIFF';
var args = later.args;
if (args.length !== 3) {
throw { message: name + " \u51FD\u6570\u7684\u63A5\u53D7\u4E09\u4E2A\u53C2\u6570" };
}
if ('DateTime' !== args[0].vType.$type) {
throw { message: name + " \u51FD\u6570\u7684\u7B2C\u4E00\u4E2A\u53C2\u6570\u5FC5\u987B\u4E3A DateTime \u7C7B\u578B" };
}
if ('DateTime' !== args[1].vType.$type) {
throw { message: name + " \u51FD\u6570\u7684\u7B2C\u4E8C\u4E2A\u53C2\u6570\u5FC5\u987B\u4E3A DateTime \u7C7B\u578B" };
}
if (!['DAY', 'HOUR', 'MINUTE', 'SECOND'].includes(args[2].value)) {
throw { message: name + " \u51FD\u6570\u7684\u7B2C\u4E09\u4E2A\u53C2\u6570\u5FC5\u987B\u4E3A DAY\u3001HOUR\u3001MINUTE\u3001SECOND \u4E2D\u7684\u4E00\u4E2A" };
}
later.vType = generateType('Integer');
return later.vType;
}
// import { generateType } from '@/ast/functions/utils';
// 条件格式固定为:目标对象,比较符和参考值,目标对象/变量可以为变量、常量或函数返回值,不支持混合加减乘除运算,返回值为满足条件的参考值集合。
function FILTER(later) {
var args = later.args;
if (args.length < 2) {
throw { message: 'FILTER 函数至少需要两个参数' };
}
var conditionArgs = args.slice(1);
for (var _i = 0, conditionArgs_1 = conditionArgs; _i < conditionArgs_1.length; _i++) {
var arg = conditionArgs_1[_i];
if (arg.vType.$type !== TypeEnum.Boolean) {
throw { message: 'FILTER 函数第一个之后的参数返回类型都必须为布尔类型' };
}
if (!arg.operator) {
throw { message: 'FILTER 函数条件参数必须为条件表达式' };
}
}
later.vType = args[0].vType;
return later.vType;
}
// 生成ID对象
function ID(later) {
var args = later.args;
if (args.length !== 1) {
throw { message: "ID \u51FD\u6570\u7684\u53EA\u63A5\u53D7\u4E00\u4E2A\u53C2\u6570" };
}
var arg = args[0];
if ((arg.vType.$type !== 'String' && arg.vType.$type !== 'Integer') || !arg.value) {
throw { message: 'ID 函数的参数必须为字符串或整数类型' };
}
later.vType = generateType('Id');
return later.vType;
}
// 合并字符串
function JOINER(later) {
var args = later.args;
if (hasNotStringArgs(args)) {
throw { message: 'JOINER 函数的参数不能为非 字符串、邮件地址、URL、手机号 等类型' };
}
later.vType = generateType('String');
return later.vType;
}
// 获取字符串函数的长度
// 函数需要为一个参数
// 参数1:目标字符串
function LENGTH(later) {
var args = later.args;
if (args.length !== 1) {
throw { message: 'LENGTH 函数的只接受一个参数' };
}
if (!isString(args[0].vType.$type)) {
throw { message: 'LENGTH 函数的参数必须为 字符串、邮件地址、URL、手机号 等类型' };
}
later.vType = generateType('Integer');
return later.vType;
}
function MAX(later) {
var args = later.args;
var firstArgType = args[0].vType.$type;
if (['IntegerArray', 'NumberArray'].includes(firstArgType)) {
if (args.length > 1) {
throw { message: 'MAX 函数的第一个参数如果为数组,则只接受一个参数' };
}
later.vType = generateType(firstArgType === 'IntegerArray' ? 'Integer' : 'Number');
return later.vType;
}
if (hasNotDigitArgs(args)) {
throw { message: 'MAX 函数的参数不能为非数字类型' };
}
later.vType = generateType(hasNumberArgs(args) ? 'Number' : 'Integer');
return later.vType;
}
function MIN(later) {
var args = later.args;
var firstArgType = args[0].vType.$type;
if (['IntegerArray', 'NumberArray'].includes(firstArgType)) {
if (args.length > 1) {
throw { message: 'MIN 函数的第一个参数如果为数组,则只接受一个参数' };
}
later.vType = generateType(firstArgType === 'IntegerArray' ? 'Integer' : 'Number');
return later.vType;
}
if (hasNotDigitArgs(args)) {
throw { message: 'MIN 函数的参数不能为非数字类型' };
}
later.vType = generateType(hasNumberArgs(args) ? 'Number' : 'Integer');
return later.vType;
}
// 取余,与 / 相同
function MOD(later) {
var args = later.args;
if (args.length !== 2) {
throw { message: 'MOD 函数只接受两个参数' };
}
if (hasNotDigitArgs(args)) {
throw { message: 'MOD 函数的参数不能为非数字类型' };
}
later.vType = generateType('Number');
return later.vType;
}
function NEGATIVE(later) {
var args = later.args;
if (args.length > 1) {
throw { message: 'NEGATIVE 函数只接受一个参数,且参数类型为布尔类型' };
}
if (args[0].vType.$type !== 'Boolean') {
throw { message: 'NEGATIVE 函数只接受一个参数,且参数类型为布尔类型' };
}
later.vType = generateType('Boolean');
return later.vType;
}
// 生成当前日期时间对象
function NOW(later) {
var args = later.args;
if (args.length !== 0) {
throw { message: "NOW \u51FD\u6570\u7684\u4E0D\u63A5\u53D7\u4EFB\u4F55\u53C2\u6570" };
}
later.vType = generateType('DateTime');
return later.vType;
}
// 判断字符串在目标字符串中出现的次数
// 函数需要为两个参数
// 参数1: 指定字符串
// 参数2: 目标字符串
function OCCURRENCE_TIMES(later) {
var args = later.args;
if (args.length !== 2) {
throw { message: 'OCCURRENCE_TIMES 函数的参数必须为两个' };
}
if (!isString(args[0].vType.$type)) {
throw { message: 'OCCURRENCE_TIMES 函数的第一个参数必须为字符串类型' };
}
if (!isString(args[1].vType.$type)) {
throw { message: 'OCCURRENCE_TIMES 函数的第二个参数必须为字符串类型' };
}
later.vType = generateType(TypeEnum.Integer);
return later.vType;
}
function OR(later) {
var args = later.args;
if (hasNotBooleanArgs(args)) {
throw { message: 'OR 函数的参数只能为布尔类型' };
}
later.vType = generateType('Boolean');
return later.vType;
}
// 向后截取字符串函数
// 函数需要为两个参数
/