expression-evaluation
Version:
Expression Evaluation
195 lines (194 loc) • 8.98 kB
JavaScript
import { FunctionDefinition } from '../FunctionDefinition.js';
import { typeBoolean, typeNumber, typeString, typeArray, typeOptionalBoolean, typeOptionalNumber, typeOptionalString, typeUnknown } from '../Type.js';
export const funcGreaterThan = new FunctionDefinition((value1, value2) => value1 > value2, typeBoolean, [typeNumber, typeNumber]);
export const funcLessThan = new FunctionDefinition((value1, value2) => value1 < value2, typeBoolean, [typeNumber, typeNumber]);
export const funcGreaterOrEqual = new FunctionDefinition((value1, value2) => value1 >= value2, typeBoolean, [typeNumber, typeNumber]);
export const funcLessOrEqual = new FunctionDefinition((value1, value2) => value1 <= value2, typeBoolean, [typeNumber, typeNumber]);
export const funcEqual = new FunctionDefinition((value1, value2) => equal(value1, value2), typeBoolean, [typeUnknown, typeUnknown]);
export const funcNotEqual = new FunctionDefinition((value1, value2) => !equal(value1, value2), typeBoolean, [typeUnknown, typeUnknown]);
export const funcLike = new FunctionDefinition((value1, value2) => equalStrings(value1, value2, true), typeBoolean, [typeString, typeString]);
export const funcUnlike = new FunctionDefinition((value1, value2) => !equalStrings(value1, value2, true), typeBoolean, [typeString, typeString]);
export const funcCoalesce = new FunctionDefinition((value, valueOtherwise) => value ?? valueOtherwise, typeUnknown, [typeUnknown, typeUnknown], 2, 2, 0);
export const funcSwitch = new FunctionDefinition((condition, value1, value2) => condition ? value1 : value2, typeUnknown, [typeBoolean, typeUnknown, typeUnknown], 3, 3, 1);
export const funcContains = new FunctionDefinition((value, search, start, ignoreCaseSpaceEtc) => containsString(value, search, start, ignoreCaseSpaceEtc), typeBoolean, [typeString, typeString, typeOptionalNumber, typeOptionalBoolean], 2, 4);
export const funcStartsWith = new FunctionDefinition((value, search, start, ignoreCaseSpaceEtc) => startsWithString(value, search, start, ignoreCaseSpaceEtc), typeBoolean, [typeString, typeString, typeOptionalNumber, typeOptionalBoolean], 2, 4);
export const funcEndsWith = new FunctionDefinition((value, search, end, ignoreCaseSpaceEtc) => endsWithString(value, search, end, ignoreCaseSpaceEtc), typeBoolean, [typeString, typeString, typeOptionalNumber, typeOptionalBoolean], 2, 4);
export const funcAlphanum = new FunctionDefinition((value) => {
const lowerCase = value.toLowerCase();
let result = '';
for (let i = 0; i < lowerCase.length; ++i) {
if (!isCaseSpaceEtc(value[i])) {
result += value[i];
}
}
return result;
}, typeString, [typeString]);
export const funcTrim = new FunctionDefinition((value) => value.trim(), typeString, [typeString]);
export const funcTrimStart = new FunctionDefinition((value) => value.trimStart(), typeString, [typeString]);
export const funcTrimEnd = new FunctionDefinition((value) => value.trimEnd(), typeString, [typeString]);
export const funcLowerCase = new FunctionDefinition((value) => value.toLowerCase(), typeString, [typeString]);
export const funcUpperCase = new FunctionDefinition((value) => value.toUpperCase(), typeString, [typeString]);
export const funcJoin = new FunctionDefinition((value, separator = ' ') => value.join(separator), typeString, [typeArray, typeOptionalString], 1, 2);
export const funcSplit = new FunctionDefinition((value, separator = ' ') => value.split(separator), typeArray, [typeString, typeOptionalString], 1, 2);
export const funcUnique = new FunctionDefinition((value) => {
const result = [];
value.forEach((i) => {
if (result.every((v) => !equal(v, i))) {
result.push(i);
}
});
return result;
}, typeArray, [typeArray]);
export const funcIntersection = new FunctionDefinition((value1, value2) => value1.filter((i) => value2.some((v) => equal(v, i))), typeArray, [typeArray, typeArray]);
export const funcDifference = new FunctionDefinition((value1, value2) => [...value1.filter((i) => value2.every((v) => !equal(v, i))), ...value2.filter((i) => value1.every((v) => !equal(v, i)))], typeArray, [typeArray, typeArray]);
function equal(value1, value2) {
if (value1 == null || value2 == null) {
return value1 == value2;
}
if (typeof value1 === 'boolean' || typeof value1 === 'number' || typeof value1 === 'string' || typeof value1 === 'function') {
return value1 === value2;
}
if (value1 instanceof ArrayBuffer && value2 instanceof ArrayBuffer) {
return equalBuffers(value1, value2);
}
if (Array.isArray(value1) && Array.isArray(value2)) {
if (value1.length === value2.length) {
for (let i = 0; i < value1.length; ++i) {
if (!equal(value1[i], value2[i])) {
return false;
}
}
return true;
}
return false;
}
const props = new Set([...Object.getOwnPropertyNames(value1), ...Object.getOwnPropertyNames(value2)]);
for (const prop of props) {
if (!equal(value1[prop], value2[prop])) {
return false;
}
}
return true;
}
function equalBuffers(value1, value2) {
if (value1.byteLength !== value2.byteLength) {
return false;
}
const dv1 = new DataView(value1);
const dv2 = new DataView(value2);
const length = dv1.byteLength;
for (let lfi = length - 3, i = 0; i < length;) {
if (i < lfi) {
if (dv1.getUint32(i) !== dv2.getUint32(i)) {
return false;
}
i += 4;
}
else {
if (dv1.getUint8(i) !== dv2.getUint8(i)) {
return false;
}
++i;
}
}
return true;
}
;
function isCaseSpaceEtc(c) {
return (c < 'a' || c > 'z') && (c < '0' || c > '9');
}
function equalStrings(value1, value2, ignoreCaseSpaceEtc) {
if (!ignoreCaseSpaceEtc) {
return value1 === value2;
}
const str1 = value1.toLowerCase();
const str2 = value2.toLowerCase();
for (let i1 = 0, i2 = 0; i1 < str1.length && i2 < str2.length; ++i1, ++i2) {
while (isCaseSpaceEtc(str1[i1]) && i1 < str1.length) {
++i1;
}
while (isCaseSpaceEtc(str2[i2]) && i2 < str2.length) {
++i2;
}
if (str1[i1] != str2[i2]) {
return false;
}
}
return true;
}
;
function containsString(value, search, startPos, ignoreCaseSpaceEtc) {
if (!ignoreCaseSpaceEtc) {
return value.includes(search, startPos);
}
const valueStr = value.toLowerCase();
const searchStr = search.toLowerCase();
if (valueStr.length < searchStr.length) {
return false;
}
const pos = startPos == null ? 0 : startPos < 0 ? value.length + startPos : startPos;
for (let i1 = pos, i2 = 0; i1 < valueStr.length && i2 < searchStr.length; ++i1, ++i2) {
while (isCaseSpaceEtc(valueStr[i1]) && i1 < valueStr.length) {
++i1;
}
while (isCaseSpaceEtc(searchStr[i2]) && i2 < searchStr.length) {
++i2;
}
while (valueStr[i1] != searchStr[i2] && i1 < valueStr.length) {
++i1;
}
if (valueStr[i1] != searchStr[i2] && i2 < searchStr.length) {
return false;
}
}
return true;
}
;
function startsWithString(value, search, startPos, ignoreCaseSpaceEtc) {
if (!ignoreCaseSpaceEtc) {
return value.startsWith(search, startPos);
}
const valueStr = value.toLowerCase();
const searchStr = search.toLowerCase();
if (valueStr.length < searchStr.length) {
return false;
}
const pos = startPos == null ? 0 : startPos < 0 ? value.length + startPos : startPos;
for (let i1 = pos, i2 = 0; i1 < valueStr.length && i2 < searchStr.length; ++i1, ++i2) {
while (isCaseSpaceEtc(valueStr[i1]) && i1 < valueStr.length) {
++i1;
}
while (isCaseSpaceEtc(searchStr[i2]) && i2 < searchStr.length) {
++i2;
}
if (valueStr[i1] != searchStr[i2] && i2 < searchStr.length) {
return false;
}
}
return true;
}
;
function endsWithString(value, search, endPos, ignoreCaseSpaceEtc) {
if (!ignoreCaseSpaceEtc) {
return value.endsWith(search, endPos);
}
const valueStr = value.toLowerCase();
const searchStr = search.toLowerCase();
if (valueStr.length < searchStr.length) {
return false;
}
const pos = endPos == null ? valueStr.length : endPos < 0 ? value.length + endPos : endPos;
for (let i1 = pos - 1, i2 = searchStr.length - 1; i1 > -1 && i2 > -1; --i1, --i2) {
while (isCaseSpaceEtc(valueStr[i1]) && i1 > -1) {
--i1;
}
while (isCaseSpaceEtc(searchStr[i2]) && i2 > -1) {
--i2;
}
if (valueStr[i1] != searchStr[i2] && i2 > -1) {
return false;
}
}
return true;
}
;