survey-expression 4.4.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -1
- package/dist/index.js +67 -61
- package/package.json +12 -11
package/dist/index.d.ts
CHANGED
|
@@ -194,6 +194,7 @@ export declare const parseSequenceItems: (state: SurveyExpressionParserState, cl
|
|
|
194
194
|
export declare const parseSurveyExpression: (source: string) => Result<SurveyExpressionNode, SurveyLogicError>;
|
|
195
195
|
export declare const runSurveyExpression: (source: string, context: SurveyLogicContext) => Result<SurveyLogicValue, SurveyLogicError>;
|
|
196
196
|
export declare const addSurveyLogicMonths: (wallClock: Date, months: number) => void;
|
|
197
|
+
export declare const averageSurveyNumbers: (numbers: number[]) => number | undefined;
|
|
197
198
|
export declare const checkIsCalendarDay: (year: number, month: number, day: number) => boolean;
|
|
198
199
|
export declare const checkIsSurveyFieldName: (text: string) => boolean;
|
|
199
200
|
export declare const checkIsSurveyLogicAllOf: (left: SurveyLogicValue, right: SurveyLogicValue) => boolean;
|
|
@@ -204,6 +205,7 @@ export declare const checkIsSurveyLogicLess: (left: SurveyLogicValue, right: Sur
|
|
|
204
205
|
export declare const checkIsSurveyLogicPrimitiveEqual: (left: SurveyLogicValue, right: SurveyLogicValue) => boolean;
|
|
205
206
|
export declare const checkIsSurveyLogicValueEmpty: (value: SurveyLogicValue) => boolean;
|
|
206
207
|
export declare const checkIsSurveyLogicValueEqual: (left: SurveyLogicValue, right: SurveyLogicValue) => boolean;
|
|
208
|
+
export declare const checkIsSurveyReturnField: (value: unknown) => value is string;
|
|
207
209
|
export declare const compareSurveyLogicTexts: (first: string, second: string) => number;
|
|
208
210
|
export declare const countSurveyLogicDecimals: (number: number) => number;
|
|
209
211
|
export declare const createSurveyLogicWallClock: (year: number, monthIndex: number, day: number, { hour, millisecond, minute, second }?: {
|
|
@@ -225,13 +227,14 @@ export declare const getSurveyLogicDayNumber: (wallClock: Date) => number;
|
|
|
225
227
|
export declare const getSurveyNumberWithPrecision: (args: SurveyLogicValue[]) => [number, number] | undefined;
|
|
226
228
|
export declare const getSurveyOptionalArgument: <T>(value: SurveyLogicValue, defaultValue: T, readArgument: (value: SurveyLogicValue) => T | undefined) => T | undefined;
|
|
227
229
|
export declare const getSurveyTextIndex: (index: number, length: number) => number;
|
|
230
|
+
export declare const mapSurveyLogicValues: <T, U>(record: Record<string, T>, mapValue: (value: T) => U) => Record<string, U>;
|
|
228
231
|
export declare const parseSurveyLogicDate: (value: SurveyLogicValue) => Date | undefined;
|
|
229
232
|
export declare const roundSurveyLogicProduct: (left: number, right: number, product: number) => number;
|
|
230
233
|
export declare const roundSurveyLogicResult: (result: number, digits: number) => number;
|
|
231
234
|
export declare const roundSurveyLogicSum: (left: number, right: number, sum: number) => number;
|
|
232
235
|
export declare const sumSurveyNumbers: (numbers: number[]) => number | undefined;
|
|
233
|
-
export declare const toSurveyLogicAnswers: (record: Record<string, SurveyLogicStoredValue>) => SurveyLogicRecord;
|
|
234
236
|
export declare const toSurveyLogicAnswer: (value: SurveyLogicStoredValue) => SurveyLogicValue;
|
|
237
|
+
export declare const toSurveyLogicAnswers: (record: Record<string, SurveyLogicStoredValue>) => SurveyLogicRecord;
|
|
235
238
|
export declare const toSurveyLogicDate: (wallClock: Date) => string | undefined;
|
|
236
239
|
export declare const toSurveyLogicNumber: (value: SurveyLogicValue) => number | undefined;
|
|
237
240
|
export declare const toSurveyLogicPrimitive: (value: SurveyLogicValue) => SurveyLogicValue;
|
package/dist/index.js
CHANGED
|
@@ -52,47 +52,6 @@ let SurveyExpressionUnaryOperator = /* @__PURE__ */ function(SurveyExpressionUna
|
|
|
52
52
|
SurveyExpressionUnaryOperator["NotEmpty"] = "notEmpty";
|
|
53
53
|
return SurveyExpressionUnaryOperator;
|
|
54
54
|
}({});
|
|
55
|
-
// src/services/shared/checkIsSurveyFieldName.ts
|
|
56
|
-
const checkIsSurveyFieldName = (text) => !/[{}><=!]/u.test(text);
|
|
57
|
-
// src/services/shared/getOwnValue.ts
|
|
58
|
-
const getOwnValue = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
59
|
-
// src/services/shared/getSurveyArrayItems.ts
|
|
60
|
-
const getSurveyArrayItems = (data) => {
|
|
61
|
-
if (Array.isArray(data)) return data;
|
|
62
|
-
if (typeof data === "object") return Object.values(data);
|
|
63
|
-
return [];
|
|
64
|
-
};
|
|
65
|
-
// src/services/shared/toSurveyLogicNumber.ts
|
|
66
|
-
const NUMBER_TEXT_REGEX = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/iu;
|
|
67
|
-
const toSurveyLogicNumber = (value) => {
|
|
68
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
69
|
-
if (typeof value !== "string") return void 0;
|
|
70
|
-
const text = value.trim();
|
|
71
|
-
if (!NUMBER_TEXT_REGEX.test(text)) return void 0;
|
|
72
|
-
const number = Number(text);
|
|
73
|
-
return Number.isFinite(number) ? number : void 0;
|
|
74
|
-
};
|
|
75
|
-
// src/services/shared/getSurveyArrayParams.ts
|
|
76
|
-
const getSurveyArrayParams = (args) => {
|
|
77
|
-
const [data, name, returnCandidate] = args;
|
|
78
|
-
if (args.length < 2 || args.length > 4 || typeof name !== "string") return void 0;
|
|
79
|
-
const hasReturnField = args.length > 2 && typeof returnCandidate === "string" && checkIsSurveyFieldName(returnCandidate);
|
|
80
|
-
const filterIndex = hasReturnField ? 3 : 2;
|
|
81
|
-
if (args.length > filterIndex) return void 0;
|
|
82
|
-
const rows = [];
|
|
83
|
-
for (const item of getSurveyArrayItems(data)) {
|
|
84
|
-
if (typeof item !== "object" || Array.isArray(item)) continue;
|
|
85
|
-
const field = toSurveyLogicNumber(getOwnValue(item, name));
|
|
86
|
-
if (field !== void 0) rows.push({
|
|
87
|
-
field,
|
|
88
|
-
item
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
returnField: hasReturnField && returnCandidate !== name ? returnCandidate : void 0,
|
|
93
|
-
rows
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
55
|
// src/services/shared/countSurveyLogicDecimals.ts
|
|
97
56
|
const countSurveyLogicDecimals = (number) => {
|
|
98
57
|
const [mantissa = "", exponent = "0"] = number.toExponential().split("e");
|
|
@@ -213,12 +172,59 @@ const sumSurveyNumbers = (numbers) => {
|
|
|
213
172
|
for (const number of numbers) total = roundSurveyLogicSum(total, number, total + number);
|
|
214
173
|
return toSurveyLogicResult(total);
|
|
215
174
|
};
|
|
175
|
+
// src/services/shared/averageSurveyNumbers.ts
|
|
176
|
+
const averageSurveyNumbers = (numbers) => {
|
|
177
|
+
if (numbers.length === 0) return void 0;
|
|
178
|
+
const total = sumSurveyNumbers(numbers);
|
|
179
|
+
return total === void 0 ? void 0 : total / numbers.length;
|
|
180
|
+
};
|
|
181
|
+
// src/services/shared/checkIsSurveyFieldName.ts
|
|
182
|
+
const checkIsSurveyFieldName = (text) => !/[{}><=!]/u.test(text);
|
|
183
|
+
// src/services/shared/checkIsSurveyReturnField.ts
|
|
184
|
+
const checkIsSurveyReturnField = (value) => typeof value === "string" && checkIsSurveyFieldName(value);
|
|
185
|
+
// src/services/shared/getOwnValue.ts
|
|
186
|
+
const getOwnValue = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
187
|
+
// src/services/shared/getSurveyArrayItems.ts
|
|
188
|
+
const getSurveyArrayItems = (data) => {
|
|
189
|
+
if (Array.isArray(data)) return data;
|
|
190
|
+
if (typeof data === "object") return Object.values(data);
|
|
191
|
+
return [];
|
|
192
|
+
};
|
|
193
|
+
// src/services/shared/toSurveyLogicNumber.ts
|
|
194
|
+
const NUMBER_TEXT_REGEX = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/iu;
|
|
195
|
+
const toSurveyLogicNumber = (value) => {
|
|
196
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
197
|
+
if (typeof value !== "string") return void 0;
|
|
198
|
+
const text = value.trim();
|
|
199
|
+
if (!NUMBER_TEXT_REGEX.test(text)) return void 0;
|
|
200
|
+
const number = Number(text);
|
|
201
|
+
return Number.isFinite(number) ? number : void 0;
|
|
202
|
+
};
|
|
203
|
+
// src/services/shared/getSurveyArrayParams.ts
|
|
204
|
+
const getSurveyArrayParams = (args) => {
|
|
205
|
+
const [data, name, returnCandidate] = args;
|
|
206
|
+
if (args.length < 2 || args.length > 4 || typeof name !== "string") return void 0;
|
|
207
|
+
const hasReturnField = args.length > 2 && checkIsSurveyReturnField(returnCandidate);
|
|
208
|
+
const filterIndex = hasReturnField ? 3 : 2;
|
|
209
|
+
if (args.length > filterIndex) return void 0;
|
|
210
|
+
const rows = [];
|
|
211
|
+
for (const item of getSurveyArrayItems(data)) {
|
|
212
|
+
if (typeof item !== "object" || Array.isArray(item)) continue;
|
|
213
|
+
const field = toSurveyLogicNumber(getOwnValue(item, name));
|
|
214
|
+
if (field !== void 0) rows.push({
|
|
215
|
+
field,
|
|
216
|
+
item
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
returnField: hasReturnField && returnCandidate !== name ? returnCandidate : void 0,
|
|
221
|
+
rows
|
|
222
|
+
};
|
|
223
|
+
};
|
|
216
224
|
// src/services/functions/avgInArrayFunction.ts
|
|
217
225
|
const avgInArrayFunction = (args) => {
|
|
218
226
|
const params = getSurveyArrayParams(args);
|
|
219
|
-
|
|
220
|
-
const total = sumSurveyNumbers(params.rows.map((row) => row.field));
|
|
221
|
-
return total === void 0 ? void 0 : total / params.rows.length;
|
|
227
|
+
return params === void 0 ? void 0 : averageSurveyNumbers(params.rows.map((row) => row.field));
|
|
222
228
|
};
|
|
223
229
|
// src/services/functions/countInArrayFunction.ts
|
|
224
230
|
const countInArrayFunction = (args) => {
|
|
@@ -475,12 +481,7 @@ const flattenSurveyNumbers = (values) => values.flatMap((value) => {
|
|
|
475
481
|
return number === void 0 ? [] : [number];
|
|
476
482
|
});
|
|
477
483
|
// src/services/functions/avgFunction.ts
|
|
478
|
-
const avgFunction = (args) =>
|
|
479
|
-
const numbers = flattenSurveyNumbers(args);
|
|
480
|
-
if (numbers.length === 0) return void 0;
|
|
481
|
-
const total = sumSurveyNumbers(numbers);
|
|
482
|
-
return total === void 0 ? void 0 : total / numbers.length;
|
|
483
|
-
};
|
|
484
|
+
const avgFunction = (args) => averageSurveyNumbers(flattenSurveyNumbers(args));
|
|
484
485
|
// src/services/functions/countFunction.ts
|
|
485
486
|
const countFunction = (args) => {
|
|
486
487
|
return flattenSurveyNumbers(args).length;
|
|
@@ -540,7 +541,7 @@ const getCallRefusal = (node) => {
|
|
|
540
541
|
if (getOwnValue(SurveyLogicFunctionMap, name) === void 0) return `Unknown function "${node.name}"`;
|
|
541
542
|
if (getOwnValue(ArrayFunctionMap, name) === void 0 || node.args.length < 3) return void 0;
|
|
542
543
|
const third = node.args.at(2);
|
|
543
|
-
return node.args.length === 3 && third?.type === "literal" &&
|
|
544
|
+
return node.args.length === 3 && third?.type === "literal" && checkIsSurveyReturnField(third.value) ? void 0 : `The filter form of "${node.name}" is not supported`;
|
|
544
545
|
};
|
|
545
546
|
// src/services/getSurveyExpressionChildren.ts
|
|
546
547
|
const getSurveyExpressionChildren = (node) => {
|
|
@@ -1086,8 +1087,6 @@ const evaluateCall = (node, context, evaluate) => {
|
|
|
1086
1087
|
};
|
|
1087
1088
|
// src/services/evaluator/evaluateList.ts
|
|
1088
1089
|
const evaluateList = (node, context, evaluate) => node.items.map((item) => evaluate(item, context));
|
|
1089
|
-
// src/services/evaluator/readSurveyLogicLength.ts
|
|
1090
|
-
const readSurveyLogicLength = (value) => Array.isArray(value) || typeof value === "string" ? value.length : 0;
|
|
1091
1090
|
// src/services/evaluator/readSurveyLogicKey.ts
|
|
1092
1091
|
const DIGITS_ONLY_REGEX = /^\d+$/u;
|
|
1093
1092
|
const readSurveyLogicKey = (container, key) => {
|
|
@@ -1109,11 +1108,8 @@ const readSurveyLogicPathUncached = (container, name, readTail) => {
|
|
|
1109
1108
|
const whole = readSurveyLogicPart(container, name);
|
|
1110
1109
|
if (whole !== void 0) return whole;
|
|
1111
1110
|
for (let separatorIndex = name.indexOf("."); separatorIndex !== -1; separatorIndex = name.indexOf(".", separatorIndex + 1)) {
|
|
1112
|
-
const
|
|
1113
|
-
const tail = name.slice(separatorIndex + 1);
|
|
1114
|
-
const value = readTail(head, tail);
|
|
1111
|
+
const value = readTail(readSurveyLogicPart(container, name.slice(0, separatorIndex)), name.slice(separatorIndex + 1));
|
|
1115
1112
|
if (value !== void 0) return value;
|
|
1116
|
-
if (tail === "length") return readSurveyLogicLength(head);
|
|
1117
1113
|
}
|
|
1118
1114
|
};
|
|
1119
1115
|
// src/services/evaluator/readMemoizedSurveyLogicPath.ts
|
|
@@ -1124,8 +1120,15 @@ const readMemoizedSurveyLogicPath = (container, name, memo) => {
|
|
|
1124
1120
|
namesRead.set(name, value);
|
|
1125
1121
|
return value;
|
|
1126
1122
|
};
|
|
1123
|
+
// src/services/evaluator/readSurveyLogicLength.ts
|
|
1124
|
+
const readSurveyLogicLength = (value) => Array.isArray(value) || typeof value === "string" ? value.length : 0;
|
|
1127
1125
|
// src/services/evaluator/readSurveyLogicPath.ts
|
|
1128
|
-
const
|
|
1126
|
+
const LENGTH_SUFFIX = ".length";
|
|
1127
|
+
const readSurveyLogicPath = (container, name) => {
|
|
1128
|
+
const value = readMemoizedSurveyLogicPath(container, name, /* @__PURE__ */ new Map());
|
|
1129
|
+
if (value !== void 0 || !name.endsWith(LENGTH_SUFFIX)) return value;
|
|
1130
|
+
return readSurveyLogicLength(readSurveyLogicPath(container, name.slice(0, -7)));
|
|
1131
|
+
};
|
|
1129
1132
|
// src/services/evaluator/readSurveyLogicReference.ts
|
|
1130
1133
|
const readSurveyLogicReference = (name, context) => {
|
|
1131
1134
|
const answer = getOwnValue(context.values, name);
|
|
@@ -1165,12 +1168,15 @@ const evaluateSurveyExpression = (node, context) => {
|
|
|
1165
1168
|
};
|
|
1166
1169
|
// src/services/runSurveyExpression.ts
|
|
1167
1170
|
const runSurveyExpression = (source, context) => parseSurveyExpression(source).map((node) => evaluateSurveyExpression(node, context));
|
|
1171
|
+
// src/services/shared/mapSurveyLogicValues.ts
|
|
1172
|
+
const mapSurveyLogicValues = (record, mapValue) => Object.fromEntries(Object.entries(record).map(([name, value]) => [name, mapValue(value)]));
|
|
1168
1173
|
// src/services/shared/toSurveyLogicAnswer.ts
|
|
1169
|
-
const toSurveyLogicAnswers = (record) => Object.fromEntries(Object.entries(record).map(([name, answer]) => [name, toSurveyLogicAnswer(answer)]));
|
|
1170
1174
|
const toSurveyLogicAnswer = (value) => {
|
|
1171
1175
|
if (value === null) return void 0;
|
|
1172
1176
|
if (Array.isArray(value)) return value.map((item) => toSurveyLogicAnswer(item));
|
|
1173
|
-
if (typeof value === "object") return
|
|
1177
|
+
if (typeof value === "object") return mapSurveyLogicValues(value, toSurveyLogicAnswer);
|
|
1174
1178
|
return value;
|
|
1175
1179
|
};
|
|
1176
|
-
|
|
1180
|
+
// src/services/shared/toSurveyLogicAnswers.ts
|
|
1181
|
+
const toSurveyLogicAnswers = (record) => mapSurveyLogicValues(record, toSurveyLogicAnswer);
|
|
1182
|
+
export { ArrayFunctionMap, DateFunctionMap, GeneralFunctionMap, LOWEST_POWER, MAX_DECIMAL_PLACES, MAX_SURVEY_EXPRESSION_LENGTH, PUNCTUATION_CHARACTERS, STRING_QUOTES, SYMBOL_OPERATOR_TEXTS, SurveyExpressionBinaryOperator, SurveyExpressionBinaryOperatorMap, SurveyExpressionNodeType, SurveyExpressionPostfixOperatorMap, SurveyExpressionPrefixOperatorMap, SurveyExpressionTokenType, SurveyExpressionUnaryOperator, SurveyLogicFunctionMap, addSurveyLogicMonths, advanceSurveyExpressionWhile, ageFunction, averageSurveyNumbers, avgFunction, avgInArrayFunction, checkIsCalendarDay, checkIsPunctuation, checkIsSurveyExpressionDigit, checkIsSurveyExpressionKeyword, checkIsSurveyExpressionWhitespace, checkIsSurveyExpressionWordCharacter, checkIsSurveyExpressionWordStart, checkIsSurveyFieldName, checkIsSurveyLogicAllOf, checkIsSurveyLogicAnyOf, checkIsSurveyLogicContaining, checkIsSurveyLogicItemHeld, checkIsSurveyLogicLess, checkIsSurveyLogicPrimitiveEqual, checkIsSurveyLogicValueEmpty, checkIsSurveyLogicValueEqual, checkIsSurveyReturnField, checkSurveyExpression, compareSurveyLogicTexts, countFunction, countInArrayFunction, countSurveyLogicDecimals, createSurveyLogicWallClock, dateAddFunction, dateDiffFunction, dayFunction, evaluateArithmeticOperator, evaluateBinary, evaluateCall, evaluateComparisonOperator, evaluateList, evaluateLogicOperator, evaluateMembershipOperator, evaluateReference, evaluateSurveyExpression, evaluateUnary, findSurveyExpressionRefusal, flattenSurveyNumbers, getCallRefusal, getDateDifference, getDateOrNow, getOwnValue, getSurveyArrayExtreme, getSurveyArrayItems, getSurveyArrayParams, getSurveyDateUnit, getSurveyExpressionChildren, getSurveyExtreme, getSurveyLogicDayNumber, getSurveyNumberWithPrecision, getSurveyOptionalArgument, getSurveyTextIndex, iifFunction, mapSurveyLogicValues, maxFunction, maxInArrayFunction, minFunction, minInArrayFunction, monthFunction, parseBinary, parseBinaryOperators, parseCall, parseGroup, parseList, parseOperand, parsePrefixOperator, parseSequence, parseSequenceItems, parseSurveyExpression, parseSurveyLogicDate, readMemoizedSurveyLogicPath, readSurveyExpressionNumber, readSurveyExpressionReference, readSurveyExpressionString, readSurveyExpressionSymbol, readSurveyExpressionToken, readSurveyExpressionWord, readSurveyLogicKey, readSurveyLogicLength, readSurveyLogicPart, readSurveyLogicPath, readSurveyLogicPathUncached, readSurveyLogicReference, roundFunction, roundSurveyLogicProduct, roundSurveyLogicResult, roundSurveyLogicSum, runSurveyExpression, substringFunction, sumFunction, sumInArrayFunction, sumSurveyNumbers, toSurveyLogicAnswer, toSurveyLogicAnswers, toSurveyLogicDate, toSurveyLogicNumber, toSurveyLogicPrimitive, toSurveyLogicResult, toSurveyLogicText, toSurveyLogicWallClock, todayFunction, tokenizeSurveyExpression, truncFunction, weekdayFunction, yearFunction };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "survey-expression",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "The survey's expression language — conditions, calculated values and validators over a survey's answers, checked against SurveyJS's recorded answers with every deliberate difference listed",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -32,19 +32,20 @@
|
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"@esposter/shared": "4.4.0",
|
|
37
|
-
"neverthrow": "^8.2.0"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@esposter/configuration": "4.4.0",
|
|
41
|
-
"tsdown": "^0.23.5"
|
|
42
|
-
},
|
|
43
35
|
"scripts": {
|
|
44
36
|
"build": "tsdown",
|
|
45
37
|
"lint": "eslint .",
|
|
46
38
|
"lint:fix": "eslint --fix .",
|
|
47
39
|
"test": "vitest",
|
|
48
40
|
"typecheck": "tsrs --fast"
|
|
49
|
-
}
|
|
50
|
-
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@esposter/shared": "4.5.0",
|
|
44
|
+
"neverthrow": "^8.2.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@esposter/configuration": "4.5.0",
|
|
48
|
+
"tsdown": "^0.23.5"
|
|
49
|
+
},
|
|
50
|
+
"gitHead": "e30c001f3b4b15693e75fb53092d62a97ade4d2b"
|
|
51
|
+
}
|