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 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
- if (params === void 0 || params.rows.length === 0) return void 0;
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" && typeof third.value === "string" && checkIsSurveyFieldName(third.value) ? void 0 : `The filter form of "${node.name}" is not supported`;
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 head = readSurveyLogicPart(container, name.slice(0, separatorIndex));
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 readSurveyLogicPath = (container, name) => readMemoizedSurveyLogicPath(container, name, /* @__PURE__ */ new Map());
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 toSurveyLogicAnswers(value);
1177
+ if (typeof value === "object") return mapSurveyLogicValues(value, toSurveyLogicAnswer);
1174
1178
  return value;
1175
1179
  };
1176
- 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, avgFunction, avgInArrayFunction, checkIsCalendarDay, checkIsPunctuation, checkIsSurveyExpressionDigit, checkIsSurveyExpressionKeyword, checkIsSurveyExpressionWhitespace, checkIsSurveyExpressionWordCharacter, checkIsSurveyExpressionWordStart, checkIsSurveyFieldName, checkIsSurveyLogicAllOf, checkIsSurveyLogicAnyOf, checkIsSurveyLogicContaining, checkIsSurveyLogicItemHeld, checkIsSurveyLogicLess, checkIsSurveyLogicPrimitiveEqual, checkIsSurveyLogicValueEmpty, checkIsSurveyLogicValueEqual, 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, 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 };
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.4.0",
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
+ }