@aemforms/af-core 0.22.20 → 0.22.23
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/LICENSE +18 -4
- package/README.md +14 -5
- package/lib/cjs/index.cjs +267 -1876
- package/lib/esm/BaseNode-dc59ab07.js +478 -0
- package/lib/esm/BaseNode.js +26 -454
- package/lib/esm/Checkbox.js +37 -1
- package/lib/esm/CheckboxGroup.js +38 -1
- package/lib/esm/Container.js +30 -9
- package/lib/esm/DateField.js +38 -2
- package/lib/esm/Field.d.ts +2 -2
- package/lib/esm/Field.js +62 -26
- package/lib/esm/Fieldset.js +36 -3
- package/lib/esm/FileObject.js +23 -1
- package/lib/esm/FileUpload.js +34 -1
- package/lib/esm/Form.d.ts +1 -1
- package/lib/esm/Form.js +40 -8
- package/lib/esm/FormInstance.js +53 -5
- package/lib/esm/FormMetaData.js +26 -1
- package/lib/esm/InstanceManager.js +35 -8
- package/lib/esm/Node.js +25 -1
- package/lib/esm/Scriptable.js +29 -2
- package/lib/esm/controller/EventQueue.js +23 -1
- package/lib/esm/controller/Events.d.ts +1 -1
- package/lib/esm/controller/Events.js +41 -19
- package/lib/esm/controller/Logger.d.ts +2 -2
- package/lib/esm/controller/Logger.js +23 -1
- package/lib/esm/data/DataGroup.js +24 -1
- package/lib/esm/data/DataValue.js +23 -1
- package/lib/esm/data/EmptyDataValue.js +23 -1
- package/lib/esm/index.js +55 -21
- package/lib/esm/rules/FunctionRuntime.d.ts +3 -3
- package/lib/esm/rules/FunctionRuntime.js +31 -6
- package/lib/esm/rules/RuleEngine.js +30 -1
- package/lib/esm/types/Json.d.ts +16 -16
- package/lib/esm/types/Json.js +24 -2
- package/lib/esm/types/Model.d.ts +4 -4
- package/lib/esm/types/Model.js +23 -1
- package/lib/esm/types/index.js +22 -2
- package/lib/esm/utils/DataRefParser.d.ts +2 -2
- package/lib/esm/utils/DataRefParser.js +31 -6
- package/lib/esm/utils/Fetch.d.ts +1 -1
- package/lib/esm/utils/Fetch.js +24 -2
- package/lib/esm/utils/FormCreationUtils.js +40 -2
- package/lib/esm/utils/FormUtils.js +33 -8
- package/lib/esm/utils/JsonUtils.js +34 -11
- package/lib/esm/utils/LogUtils.js +23 -1
- package/lib/esm/utils/SchemaUtils.js +24 -2
- package/lib/esm/utils/TranslationUtils.d.ts +1 -1
- package/lib/esm/utils/TranslationUtils.js +32 -9
- package/lib/esm/utils/ValidationUtils.d.ts +4 -4
- package/lib/esm/utils/ValidationUtils.js +30 -4
- package/package.json +4 -3
- package/lib/browser/afb-events.js +0 -151
- package/lib/browser/afb-runtime.js +0 -3620
package/lib/cjs/index.cjs
CHANGED
|
@@ -1,168 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const objToMap = (o) => new Map(Object.entries(o));
|
|
21
|
-
const stringViewTypes = objToMap({ 'date': 'date-input', 'data-url': 'file-input', 'binary': 'file-input' });
|
|
22
|
-
const typeToViewTypes = objToMap({
|
|
23
|
-
'number': 'number-input',
|
|
24
|
-
'boolean': 'checkbox',
|
|
25
|
-
'object': 'panel',
|
|
26
|
-
'array': 'panel',
|
|
27
|
-
'file': 'file-input',
|
|
28
|
-
'file[]': 'file-input'
|
|
29
|
-
});
|
|
30
|
-
const arrayTypes = ['string[]', 'boolean[]', 'number[]', 'array'];
|
|
31
|
-
const defaultFieldTypes = (schema) => {
|
|
32
|
-
const type = schema.type || 'string';
|
|
33
|
-
if ('enum' in schema) {
|
|
34
|
-
const enums = schema.enum;
|
|
35
|
-
if (enums.length > 2 || arrayTypes.indexOf(type) > -1) {
|
|
36
|
-
return 'drop-down';
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
return 'checkbox';
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (type === 'string' || type === 'string[]') {
|
|
43
|
-
return stringViewTypes.get(schema.format) || 'text-input';
|
|
44
|
-
}
|
|
45
|
-
return typeToViewTypes.get(type) || 'text-input';
|
|
46
|
-
};
|
|
47
|
-
const fieldSchema = (input) => {
|
|
48
|
-
if ('items' in input) {
|
|
49
|
-
const fieldset = input;
|
|
50
|
-
const items = fieldset.items;
|
|
51
|
-
if (fieldset.type === 'array') {
|
|
52
|
-
return {
|
|
53
|
-
type: 'array',
|
|
54
|
-
items: fieldSchema(items[0]),
|
|
55
|
-
minItems: fieldset?.minItems,
|
|
56
|
-
maxItems: fieldset?.maxItems
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
const iter = items.filter(x => x.name != null);
|
|
61
|
-
return {
|
|
62
|
-
type: 'object',
|
|
63
|
-
properties: Object.fromEntries(iter.map(item => [item.name, fieldSchema(item)])),
|
|
64
|
-
required: iter.filter(x => x.required).map(x => x.name)
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
const field = input;
|
|
70
|
-
const schemaProps = ['type', 'maxLength', 'minLength', 'minimum', 'maximum', 'format', 'pattern', 'step', 'enum'];
|
|
71
|
-
const schema = schemaProps.reduce((acc, prop) => {
|
|
72
|
-
const p = prop;
|
|
73
|
-
if (prop in field && field[p] != undefined) {
|
|
74
|
-
acc[prop] = field[p];
|
|
75
|
-
}
|
|
76
|
-
return acc;
|
|
77
|
-
}, {});
|
|
78
|
-
if (field.dataRef === 'none' || Object.keys(schema).length == 0) {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
title: field.label?.value,
|
|
83
|
-
description: field.description,
|
|
84
|
-
...schema
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
const exportDataSchema = (form) => {
|
|
89
|
-
return fieldSchema(form);
|
|
90
|
-
};
|
|
1
|
+
/*************************************************************************
|
|
2
|
+
* ADOBE CONFIDENTIAL
|
|
3
|
+
* ___________________
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2022 Adobe
|
|
6
|
+
* All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* NOTICE: All information contained herein is, and remains
|
|
9
|
+
* the property of Adobe and its suppliers, if any. The intellectual
|
|
10
|
+
* and technical concepts contained herein are proprietary to Adobe
|
|
11
|
+
* and its suppliers and are protected by all applicable intellectual
|
|
12
|
+
* property laws, including trade secret and copyright laws.
|
|
13
|
+
* Dissemination of this information or reproduction of this material
|
|
14
|
+
* is strictly forbidden unless prior written permission is obtained
|
|
15
|
+
* from Adobe.
|
|
16
|
+
|
|
17
|
+
* Adobe permits you to use and modify this file solely in accordance with
|
|
18
|
+
* the terms of the Adobe license agreement accompanying it.
|
|
19
|
+
*************************************************************************/
|
|
91
20
|
|
|
92
|
-
|
|
93
|
-
if (key in data) {
|
|
94
|
-
return data[key];
|
|
95
|
-
}
|
|
96
|
-
else if (!key.startsWith(':')) {
|
|
97
|
-
const prefixedKey = `:${key}`;
|
|
98
|
-
if (prefixedKey in data) {
|
|
99
|
-
return data[prefixedKey];
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return def;
|
|
103
|
-
};
|
|
104
|
-
const isFile = function (item) {
|
|
105
|
-
return (item?.type === 'file' || item?.type === 'file[]') ||
|
|
106
|
-
((item?.type === 'string' || item?.type === 'string[]') &&
|
|
107
|
-
(item?.format === 'binary' || item?.format === 'data-url'));
|
|
108
|
-
};
|
|
109
|
-
const checkIfConstraintsArePresent = function (item) {
|
|
110
|
-
return constraintProps.some(cp => item[cp] !== undefined);
|
|
111
|
-
};
|
|
112
|
-
const isCheckbox = function (item) {
|
|
113
|
-
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
114
|
-
return fieldType === 'checkbox';
|
|
115
|
-
};
|
|
116
|
-
const isCheckboxGroup = function (item) {
|
|
117
|
-
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
118
|
-
return fieldType === 'checkbox-group';
|
|
119
|
-
};
|
|
120
|
-
const isDateField = function (item) {
|
|
121
|
-
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
122
|
-
return (fieldType === 'text-input' && item?.format === 'date') || fieldType === 'date-input';
|
|
123
|
-
};
|
|
124
|
-
function deepClone(obj, idGenerator) {
|
|
125
|
-
let result;
|
|
126
|
-
if (obj instanceof Array) {
|
|
127
|
-
result = [];
|
|
128
|
-
result = obj.map(x => deepClone(x, idGenerator));
|
|
129
|
-
}
|
|
130
|
-
else if (typeof obj === 'object' && obj !== null) {
|
|
131
|
-
result = {};
|
|
132
|
-
Object.entries(obj).forEach(([key, value]) => {
|
|
133
|
-
result[key] = deepClone(value, idGenerator);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
result = obj;
|
|
138
|
-
}
|
|
139
|
-
if (idGenerator && result && result.id) {
|
|
140
|
-
result.id = idGenerator();
|
|
141
|
-
}
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
function checkIfKeyAdded(currentObj, prevObj, objKey) {
|
|
145
|
-
if (currentObj != null && prevObj != null) {
|
|
146
|
-
const newPrvObj = { ...prevObj };
|
|
147
|
-
newPrvObj[objKey] = currentObj[objKey];
|
|
148
|
-
const newJsonStr = jsonString(currentObj).replace(jsonString(newPrvObj), '');
|
|
149
|
-
return newJsonStr === '';
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const jsonString = (obj) => {
|
|
156
|
-
return JSON.stringify(obj, null, 2);
|
|
157
|
-
};
|
|
158
|
-
const isRepeatable = (obj) => {
|
|
159
|
-
return ((obj.repeatable &&
|
|
160
|
-
((obj.minOccur === undefined && obj.maxOccur === undefined) ||
|
|
161
|
-
(obj.minOccur !== undefined && obj.maxOccur !== undefined && obj.maxOccur !== 0) ||
|
|
162
|
-
(obj.minOccur !== undefined && obj.maxOccur !== undefined && obj.minOccur !== 0 && obj.maxOccur !== 0) ||
|
|
163
|
-
(obj.minOccur !== undefined && obj.minOccur >= 0) ||
|
|
164
|
-
(obj.maxOccur !== undefined && obj.maxOccur !== 0))) || false);
|
|
165
|
-
};
|
|
21
|
+
'use strict';
|
|
166
22
|
|
|
167
23
|
class ActionImpl {
|
|
168
24
|
_metadata;
|
|
@@ -687,12 +543,12 @@ const resolveData = (data, input, create) => {
|
|
|
687
543
|
return result;
|
|
688
544
|
};
|
|
689
545
|
|
|
690
|
-
|
|
546
|
+
function __decorate(decorators, target, key, desc) {
|
|
691
547
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
692
548
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
693
549
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
694
550
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
695
|
-
}
|
|
551
|
+
}
|
|
696
552
|
const editableProperties = [
|
|
697
553
|
'value',
|
|
698
554
|
'label',
|
|
@@ -1123,22 +979,177 @@ class BaseNode {
|
|
|
1123
979
|
}
|
|
1124
980
|
}
|
|
1125
981
|
}
|
|
1126
|
-
__decorate
|
|
982
|
+
__decorate([
|
|
1127
983
|
dependencyTracked()
|
|
1128
984
|
], BaseNode.prototype, "index", null);
|
|
1129
|
-
__decorate
|
|
985
|
+
__decorate([
|
|
1130
986
|
dependencyTracked()
|
|
1131
987
|
], BaseNode.prototype, "description", null);
|
|
1132
|
-
__decorate
|
|
988
|
+
__decorate([
|
|
1133
989
|
dependencyTracked()
|
|
1134
990
|
], BaseNode.prototype, "visible", null);
|
|
1135
|
-
__decorate
|
|
991
|
+
__decorate([
|
|
1136
992
|
dependencyTracked()
|
|
1137
993
|
], BaseNode.prototype, "label", null);
|
|
1138
|
-
__decorate
|
|
994
|
+
__decorate([
|
|
1139
995
|
dependencyTracked()
|
|
1140
996
|
], BaseNode.prototype, "properties", null);
|
|
1141
997
|
|
|
998
|
+
const translationProps = ['description', 'placeholder', 'enum', 'enumNames', 'label.value', 'constraintMessages.accept',
|
|
999
|
+
'constraintMessages.enum', 'constraintMessages.exclusiveMinimum', 'constraintMessages.exclusiveMaximum', 'constraintMessages.format', 'constraintMessages.maxFileSize', 'constraintMessages.maxLength',
|
|
1000
|
+
'constraintMessages.maximum', 'constraintMessages.maxItems', 'constraintMessages.minLength', 'constraintMessages.minimum', 'constraintMessages.minItems', 'constraintMessages.pattern', 'constraintMessages.required',
|
|
1001
|
+
'constraintMessages.step', 'constraintMessages.type', 'constraintMessages.validationExpression'];
|
|
1002
|
+
const constraintProps = ['accept', 'enum', 'exclusiveMinimum', 'exclusiveMaximum',
|
|
1003
|
+
'format', 'maxFileSize', 'maxLength', 'maximum', 'maxItems',
|
|
1004
|
+
'minLength', 'minimum', 'minItems', 'pattern', 'required', 'step', 'validationExpression', 'enumNames'];
|
|
1005
|
+
|
|
1006
|
+
const objToMap = (o) => new Map(Object.entries(o));
|
|
1007
|
+
const stringViewTypes = objToMap({ 'date': 'date-input', 'data-url': 'file-input', 'binary': 'file-input' });
|
|
1008
|
+
const typeToViewTypes = objToMap({
|
|
1009
|
+
'number': 'number-input',
|
|
1010
|
+
'boolean': 'checkbox',
|
|
1011
|
+
'object': 'panel',
|
|
1012
|
+
'array': 'panel',
|
|
1013
|
+
'file': 'file-input',
|
|
1014
|
+
'file[]': 'file-input'
|
|
1015
|
+
});
|
|
1016
|
+
const arrayTypes = ['string[]', 'boolean[]', 'number[]', 'array'];
|
|
1017
|
+
const defaultFieldTypes = (schema) => {
|
|
1018
|
+
const type = schema.type || 'string';
|
|
1019
|
+
if ('enum' in schema) {
|
|
1020
|
+
const enums = schema.enum;
|
|
1021
|
+
if (enums.length > 2 || arrayTypes.indexOf(type) > -1) {
|
|
1022
|
+
return 'drop-down';
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
return 'checkbox';
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if (type === 'string' || type === 'string[]') {
|
|
1029
|
+
return stringViewTypes.get(schema.format) || 'text-input';
|
|
1030
|
+
}
|
|
1031
|
+
return typeToViewTypes.get(type) || 'text-input';
|
|
1032
|
+
};
|
|
1033
|
+
const fieldSchema = (input) => {
|
|
1034
|
+
if ('items' in input) {
|
|
1035
|
+
const fieldset = input;
|
|
1036
|
+
const items = fieldset.items;
|
|
1037
|
+
if (fieldset.type === 'array') {
|
|
1038
|
+
return {
|
|
1039
|
+
type: 'array',
|
|
1040
|
+
items: fieldSchema(items[0]),
|
|
1041
|
+
minItems: fieldset?.minItems,
|
|
1042
|
+
maxItems: fieldset?.maxItems
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
const iter = items.filter(x => x.name != null);
|
|
1047
|
+
return {
|
|
1048
|
+
type: 'object',
|
|
1049
|
+
properties: Object.fromEntries(iter.map(item => [item.name, fieldSchema(item)])),
|
|
1050
|
+
required: iter.filter(x => x.required).map(x => x.name)
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
else {
|
|
1055
|
+
const field = input;
|
|
1056
|
+
const schemaProps = ['type', 'maxLength', 'minLength', 'minimum', 'maximum', 'format', 'pattern', 'step', 'enum'];
|
|
1057
|
+
const schema = schemaProps.reduce((acc, prop) => {
|
|
1058
|
+
const p = prop;
|
|
1059
|
+
if (prop in field && field[p] != undefined) {
|
|
1060
|
+
acc[prop] = field[p];
|
|
1061
|
+
}
|
|
1062
|
+
return acc;
|
|
1063
|
+
}, {});
|
|
1064
|
+
if (field.dataRef === 'none' || Object.keys(schema).length == 0) {
|
|
1065
|
+
return undefined;
|
|
1066
|
+
}
|
|
1067
|
+
return {
|
|
1068
|
+
title: field.label?.value,
|
|
1069
|
+
description: field.description,
|
|
1070
|
+
...schema
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
const exportDataSchema = (form) => {
|
|
1075
|
+
return fieldSchema(form);
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
const getProperty = (data, key, def) => {
|
|
1079
|
+
if (key in data) {
|
|
1080
|
+
return data[key];
|
|
1081
|
+
}
|
|
1082
|
+
else if (!key.startsWith(':')) {
|
|
1083
|
+
const prefixedKey = `:${key}`;
|
|
1084
|
+
if (prefixedKey in data) {
|
|
1085
|
+
return data[prefixedKey];
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return def;
|
|
1089
|
+
};
|
|
1090
|
+
const isFile = function (item) {
|
|
1091
|
+
return (item?.type === 'file' || item?.type === 'file[]') ||
|
|
1092
|
+
((item?.type === 'string' || item?.type === 'string[]') &&
|
|
1093
|
+
(item?.format === 'binary' || item?.format === 'data-url'));
|
|
1094
|
+
};
|
|
1095
|
+
const checkIfConstraintsArePresent = function (item) {
|
|
1096
|
+
return constraintProps.some(cp => item[cp] !== undefined);
|
|
1097
|
+
};
|
|
1098
|
+
const isCheckbox = function (item) {
|
|
1099
|
+
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
1100
|
+
return fieldType === 'checkbox';
|
|
1101
|
+
};
|
|
1102
|
+
const isCheckboxGroup = function (item) {
|
|
1103
|
+
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
1104
|
+
return fieldType === 'checkbox-group';
|
|
1105
|
+
};
|
|
1106
|
+
const isDateField = function (item) {
|
|
1107
|
+
const fieldType = item?.fieldType || defaultFieldTypes(item);
|
|
1108
|
+
return (fieldType === 'text-input' && item?.format === 'date') || fieldType === 'date-input';
|
|
1109
|
+
};
|
|
1110
|
+
function deepClone(obj, idGenerator) {
|
|
1111
|
+
let result;
|
|
1112
|
+
if (obj instanceof Array) {
|
|
1113
|
+
result = [];
|
|
1114
|
+
result = obj.map(x => deepClone(x, idGenerator));
|
|
1115
|
+
}
|
|
1116
|
+
else if (typeof obj === 'object' && obj !== null) {
|
|
1117
|
+
result = {};
|
|
1118
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
1119
|
+
result[key] = deepClone(value, idGenerator);
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
result = obj;
|
|
1124
|
+
}
|
|
1125
|
+
if (idGenerator && result && result.id) {
|
|
1126
|
+
result.id = idGenerator();
|
|
1127
|
+
}
|
|
1128
|
+
return result;
|
|
1129
|
+
}
|
|
1130
|
+
function checkIfKeyAdded(currentObj, prevObj, objKey) {
|
|
1131
|
+
if (currentObj != null && prevObj != null) {
|
|
1132
|
+
const newPrvObj = { ...prevObj };
|
|
1133
|
+
newPrvObj[objKey] = currentObj[objKey];
|
|
1134
|
+
const newJsonStr = jsonString(currentObj).replace(jsonString(newPrvObj), '');
|
|
1135
|
+
return newJsonStr === '';
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
const jsonString = (obj) => {
|
|
1142
|
+
return JSON.stringify(obj, null, 2);
|
|
1143
|
+
};
|
|
1144
|
+
const isRepeatable = (obj) => {
|
|
1145
|
+
return ((obj.repeatable &&
|
|
1146
|
+
((obj.minOccur === undefined && obj.maxOccur === undefined) ||
|
|
1147
|
+
(obj.minOccur !== undefined && obj.maxOccur !== undefined && obj.maxOccur !== 0) ||
|
|
1148
|
+
(obj.minOccur !== undefined && obj.maxOccur !== undefined && obj.minOccur !== 0 && obj.maxOccur !== 0) ||
|
|
1149
|
+
(obj.minOccur !== undefined && obj.minOccur >= 0) ||
|
|
1150
|
+
(obj.maxOccur !== undefined && obj.maxOccur !== 0))) || false);
|
|
1151
|
+
};
|
|
1152
|
+
|
|
1142
1153
|
class Scriptable extends BaseNode {
|
|
1143
1154
|
_events = {};
|
|
1144
1155
|
_rules = {};
|
|
@@ -1301,12 +1312,6 @@ class Scriptable extends BaseNode {
|
|
|
1301
1312
|
}
|
|
1302
1313
|
}
|
|
1303
1314
|
|
|
1304
|
-
var __decorate$2 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
1305
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1306
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1307
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1308
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1309
|
-
};
|
|
1310
1315
|
class Container extends Scriptable {
|
|
1311
1316
|
_children = [];
|
|
1312
1317
|
_childrenReference;
|
|
@@ -1576,13 +1581,13 @@ class Container extends Scriptable {
|
|
|
1576
1581
|
}
|
|
1577
1582
|
}
|
|
1578
1583
|
}
|
|
1579
|
-
__decorate
|
|
1584
|
+
__decorate([
|
|
1580
1585
|
dependencyTracked()
|
|
1581
1586
|
], Container.prototype, "maxItems", null);
|
|
1582
|
-
__decorate
|
|
1587
|
+
__decorate([
|
|
1583
1588
|
dependencyTracked()
|
|
1584
1589
|
], Container.prototype, "minItems", null);
|
|
1585
|
-
__decorate
|
|
1590
|
+
__decorate([
|
|
1586
1591
|
dependencyTracked()
|
|
1587
1592
|
], Container.prototype, "activeChild", null);
|
|
1588
1593
|
|
|
@@ -2448,17 +2453,16 @@ class Form extends Container {
|
|
|
2448
2453
|
super.dispatch(action);
|
|
2449
2454
|
}
|
|
2450
2455
|
}
|
|
2451
|
-
executeAction(action) {
|
|
2452
|
-
if ((action.type !== 'submit') || this._invalidFields.length === 0) {
|
|
2453
|
-
super.executeAction(action);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
2456
|
submit(action, context) {
|
|
2457
2457
|
if (this.validate().length === 0) {
|
|
2458
2458
|
const payload = action?.payload || {};
|
|
2459
2459
|
submit(context, payload?.success, payload?.error, payload?.submit_as, payload?.data);
|
|
2460
2460
|
}
|
|
2461
2461
|
}
|
|
2462
|
+
reset() {
|
|
2463
|
+
super.reset();
|
|
2464
|
+
this._invalidFields = [];
|
|
2465
|
+
}
|
|
2462
2466
|
getElement(id) {
|
|
2463
2467
|
if (id == this.id) {
|
|
2464
2468
|
return this;
|
|
@@ -2485,7 +2489,6 @@ class Form extends Container {
|
|
|
2485
2489
|
}
|
|
2486
2490
|
}
|
|
2487
2491
|
|
|
2488
|
-
// Type constants used to define functions.
|
|
2489
2492
|
var dataTypes = {
|
|
2490
2493
|
TYPE_NUMBER: 0,
|
|
2491
2494
|
TYPE_ANY: 1,
|
|
@@ -2557,11 +2560,9 @@ const {
|
|
|
2557
2560
|
TYPE_CLASS: TYPE_CLASS$1,
|
|
2558
2561
|
TYPE_ARRAY_ARRAY,
|
|
2559
2562
|
} = dataTypes;
|
|
2560
|
-
|
|
2561
2563
|
const {
|
|
2562
2564
|
TOK_EXPREF: TOK_EXPREF$3,
|
|
2563
2565
|
} = tokenDefinitions;
|
|
2564
|
-
|
|
2565
2566
|
const TYPE_NAME_TABLE = {
|
|
2566
2567
|
[TYPE_NUMBER]: 'number',
|
|
2567
2568
|
[TYPE_ANY$1]: 'any',
|
|
@@ -2576,13 +2577,10 @@ const TYPE_NAME_TABLE = {
|
|
|
2576
2577
|
[TYPE_CLASS$1]: 'class',
|
|
2577
2578
|
[TYPE_ARRAY_ARRAY]: 'Array<array>',
|
|
2578
2579
|
};
|
|
2579
|
-
|
|
2580
2580
|
function getTypeName(inputObj, useValueOf = true) {
|
|
2581
2581
|
if (inputObj === null) return TYPE_NULL;
|
|
2582
2582
|
let obj = inputObj;
|
|
2583
2583
|
if (useValueOf) {
|
|
2584
|
-
// check for the case where there's a child named 'valueOf' that's not a function
|
|
2585
|
-
// if so, then it's an object...
|
|
2586
2584
|
if (typeof inputObj.valueOf === 'function') obj = inputObj.valueOf.call(inputObj);
|
|
2587
2585
|
else return TYPE_OBJECT;
|
|
2588
2586
|
}
|
|
@@ -2598,8 +2596,6 @@ function getTypeName(inputObj, useValueOf = true) {
|
|
|
2598
2596
|
case '[object Null]':
|
|
2599
2597
|
return TYPE_NULL;
|
|
2600
2598
|
case '[object Object]':
|
|
2601
|
-
// Check if it's an expref. If it has, it's been
|
|
2602
|
-
// tagged with a jmespathType attr of 'Expref';
|
|
2603
2599
|
if (obj.jmespathType === TOK_EXPREF$3) {
|
|
2604
2600
|
return TYPE_EXPREF;
|
|
2605
2601
|
}
|
|
@@ -2608,23 +2604,17 @@ function getTypeName(inputObj, useValueOf = true) {
|
|
|
2608
2604
|
return TYPE_OBJECT;
|
|
2609
2605
|
}
|
|
2610
2606
|
}
|
|
2611
|
-
|
|
2612
2607
|
function getTypeNames(inputObj) {
|
|
2613
|
-
// return the types with and without using valueOf
|
|
2614
|
-
// needed for the cases where we really need an object passed to a function -- not it's value
|
|
2615
2608
|
const type1 = getTypeName(inputObj);
|
|
2616
2609
|
const type2 = getTypeName(inputObj, false);
|
|
2617
2610
|
return [type1, type2];
|
|
2618
2611
|
}
|
|
2619
|
-
|
|
2620
2612
|
function matchType(actuals, expectedList, argValue, context, toNumber, toString) {
|
|
2621
2613
|
const actual = actuals[0];
|
|
2622
2614
|
if (expectedList.findIndex(
|
|
2623
2615
|
type => type === TYPE_ANY$1 || actual === type,
|
|
2624
2616
|
) !== -1
|
|
2625
2617
|
) return argValue;
|
|
2626
|
-
// Can't coerce Objects to any other type,
|
|
2627
|
-
// and cannot coerce anything to a Class
|
|
2628
2618
|
let wrongType = false;
|
|
2629
2619
|
if (actual === TYPE_OBJECT || (expectedList.length === 1 && expectedList[0] === TYPE_CLASS$1)) {
|
|
2630
2620
|
wrongType = true;
|
|
@@ -2644,11 +2634,9 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2644
2634
|
if (wrongType) {
|
|
2645
2635
|
throw new Error(`TypeError: ${context} expected argument to be type ${TYPE_NAME_TABLE[expectedList[0]]} but received type ${TYPE_NAME_TABLE[actual]} instead.`);
|
|
2646
2636
|
}
|
|
2647
|
-
// no exact match in the list of possible types, see if we can coerce an array type
|
|
2648
2637
|
let expected = -1;
|
|
2649
2638
|
if (actual === TYPE_ARRAY$1) {
|
|
2650
2639
|
if (expectedList.includes(TYPE_ARRAY_STRING$1) && expectedList.includes(TYPE_ARRAY_NUMBER)) {
|
|
2651
|
-
// choose the array type based on the first element
|
|
2652
2640
|
if (argValue.length > 0 && typeof argValue[0] === 'string') expected = TYPE_ARRAY_STRING$1;
|
|
2653
2641
|
else expected = TYPE_ARRAY_NUMBER;
|
|
2654
2642
|
}
|
|
@@ -2658,7 +2646,6 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2658
2646
|
e => [TYPE_ARRAY_STRING$1, TYPE_ARRAY_NUMBER, TYPE_ARRAY$1].includes(e),
|
|
2659
2647
|
);
|
|
2660
2648
|
}
|
|
2661
|
-
// no match, just take the first type
|
|
2662
2649
|
if (expected === -1) [expected] = expectedList;
|
|
2663
2650
|
if (expected === TYPE_ANY$1) return argValue;
|
|
2664
2651
|
if (expected === TYPE_ARRAY_STRING$1
|
|
@@ -2668,12 +2655,8 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2668
2655
|
if (actual === TYPE_ARRAY_NUMBER || actual === TYPE_ARRAY_STRING$1) return argValue;
|
|
2669
2656
|
return argValue === null ? [] : [argValue];
|
|
2670
2657
|
}
|
|
2671
|
-
// The expected type can either just be array,
|
|
2672
|
-
// or it can require a specific subtype (array of numbers).
|
|
2673
2658
|
const subtype = expected === TYPE_ARRAY_NUMBER ? TYPE_NUMBER : TYPE_STRING$1;
|
|
2674
2659
|
if (actual === TYPE_ARRAY$1) {
|
|
2675
|
-
// Otherwise we need to check subtypes.
|
|
2676
|
-
// We're going to modify the array, so take a copy
|
|
2677
2660
|
const returnArray = argValue.slice();
|
|
2678
2661
|
for (let i = 0; i < returnArray.length; i += 1) {
|
|
2679
2662
|
const indexType = getTypeNames(returnArray[i]);
|
|
@@ -2694,7 +2677,6 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2694
2677
|
} else {
|
|
2695
2678
|
if (expected === TYPE_NUMBER) {
|
|
2696
2679
|
if ([TYPE_STRING$1, TYPE_BOOLEAN, TYPE_NULL].includes(actual)) return toNumber(argValue);
|
|
2697
|
-
/* TYPE_ARRAY, TYPE_EXPREF, TYPE_OBJECT, TYPE_ARRAY, TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING */
|
|
2698
2680
|
return 0;
|
|
2699
2681
|
}
|
|
2700
2682
|
if (expected === TYPE_STRING$1) {
|
|
@@ -2717,42 +2699,31 @@ function isArray(obj) {
|
|
|
2717
2699
|
}
|
|
2718
2700
|
return false;
|
|
2719
2701
|
}
|
|
2720
|
-
|
|
2721
2702
|
function isObject(obj) {
|
|
2722
2703
|
if (obj !== null) {
|
|
2723
2704
|
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
2724
2705
|
}
|
|
2725
2706
|
return false;
|
|
2726
2707
|
}
|
|
2727
|
-
|
|
2728
2708
|
function getValueOf(a) {
|
|
2729
2709
|
if (a === null || a === undefined) return a;
|
|
2730
2710
|
if (isArray(a)) {
|
|
2731
2711
|
return a.map(i => getValueOf(i));
|
|
2732
2712
|
}
|
|
2733
|
-
// if we have a child named 'valueOf' then we're an object,
|
|
2734
|
-
// and just return the object.
|
|
2735
2713
|
if (typeof (a.valueOf) !== 'function') return a;
|
|
2736
2714
|
return a.valueOf();
|
|
2737
2715
|
}
|
|
2738
|
-
|
|
2739
2716
|
function strictDeepEqual(lhs, rhs) {
|
|
2740
2717
|
const first = getValueOf(lhs);
|
|
2741
2718
|
const second = getValueOf(rhs);
|
|
2742
|
-
// Check the scalar case first.
|
|
2743
2719
|
if (first === second) {
|
|
2744
2720
|
return true;
|
|
2745
2721
|
}
|
|
2746
|
-
|
|
2747
|
-
// Check if they are the same type.
|
|
2748
2722
|
const firstType = Object.prototype.toString.call(first);
|
|
2749
2723
|
if (firstType !== Object.prototype.toString.call(second)) {
|
|
2750
2724
|
return false;
|
|
2751
2725
|
}
|
|
2752
|
-
// We know that first and second have the same type so we can just check the
|
|
2753
|
-
// first type from now on.
|
|
2754
2726
|
if (isArray(first) === true) {
|
|
2755
|
-
// Short circuit if they're not the same length;
|
|
2756
2727
|
if (first.length !== second.length) {
|
|
2757
2728
|
return false;
|
|
2758
2729
|
}
|
|
@@ -2764,9 +2735,7 @@ function strictDeepEqual(lhs, rhs) {
|
|
|
2764
2735
|
return true;
|
|
2765
2736
|
}
|
|
2766
2737
|
if (isObject(first) === true) {
|
|
2767
|
-
// An object is equal if it has the same key/value pairs.
|
|
2768
2738
|
const keysSeen = {};
|
|
2769
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
2770
2739
|
for (const key in first) {
|
|
2771
2740
|
if (hasOwnProperty.call(first, key)) {
|
|
2772
2741
|
if (strictDeepEqual(first[key], second[key]) === false) {
|
|
@@ -2775,9 +2744,6 @@ function strictDeepEqual(lhs, rhs) {
|
|
|
2775
2744
|
keysSeen[key] = true;
|
|
2776
2745
|
}
|
|
2777
2746
|
}
|
|
2778
|
-
// Now check that there aren't any keys in second that weren't
|
|
2779
|
-
// in first.
|
|
2780
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
2781
2747
|
for (const key2 in second) {
|
|
2782
2748
|
if (hasOwnProperty.call(second, key2)) {
|
|
2783
2749
|
if (keysSeen[key2] !== true) {
|
|
@@ -2803,42 +2769,22 @@ const {
|
|
|
2803
2769
|
TOK_NE: TOK_NE$2,
|
|
2804
2770
|
TOK_FLATTEN: TOK_FLATTEN$2,
|
|
2805
2771
|
} = tokenDefinitions;
|
|
2806
|
-
|
|
2807
2772
|
const {
|
|
2808
2773
|
TYPE_STRING,
|
|
2809
2774
|
TYPE_ARRAY_STRING,
|
|
2810
2775
|
TYPE_ARRAY,
|
|
2811
2776
|
} = dataTypes;
|
|
2812
|
-
|
|
2813
2777
|
function isFalse(value) {
|
|
2814
|
-
// From the spec:
|
|
2815
|
-
// A false value corresponds to the following values:
|
|
2816
|
-
// Empty list
|
|
2817
|
-
// Empty object
|
|
2818
|
-
// Empty string
|
|
2819
|
-
// False boolean
|
|
2820
|
-
// null value
|
|
2821
|
-
// (new) use JS truthy evaluation. This changes the spec behavior.
|
|
2822
|
-
// Where in the past a zero (0) would be True, it's now false
|
|
2823
|
-
|
|
2824
|
-
// First check the scalar values.
|
|
2825
2778
|
if (value === null) return true;
|
|
2826
|
-
// in case it's an object with a valueOf defined
|
|
2827
2779
|
const obj = getValueOf(value);
|
|
2828
2780
|
if (obj === '' || obj === false || obj === null) {
|
|
2829
2781
|
return true;
|
|
2830
2782
|
}
|
|
2831
2783
|
if (isArray(obj) && obj.length === 0) {
|
|
2832
|
-
// Check for an empty array.
|
|
2833
2784
|
return true;
|
|
2834
2785
|
}
|
|
2835
2786
|
if (isObject(obj)) {
|
|
2836
|
-
// Check for an empty object.
|
|
2837
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
2838
2787
|
for (const key in obj) {
|
|
2839
|
-
// If there are any keys, then
|
|
2840
|
-
// the object is not empty so the object
|
|
2841
|
-
// is not false.
|
|
2842
2788
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
2843
2789
|
return false;
|
|
2844
2790
|
}
|
|
@@ -2847,11 +2793,9 @@ function isFalse(value) {
|
|
|
2847
2793
|
}
|
|
2848
2794
|
return !obj;
|
|
2849
2795
|
}
|
|
2850
|
-
|
|
2851
2796
|
function objValues(obj) {
|
|
2852
2797
|
return Object.values(obj);
|
|
2853
2798
|
}
|
|
2854
|
-
|
|
2855
2799
|
class TreeInterpreter {
|
|
2856
2800
|
constructor(runtime, globals, toNumber, toString, debug, language) {
|
|
2857
2801
|
this.runtime = runtime;
|
|
@@ -2861,27 +2805,20 @@ class TreeInterpreter {
|
|
|
2861
2805
|
this.debug = debug;
|
|
2862
2806
|
this.language = language;
|
|
2863
2807
|
}
|
|
2864
|
-
|
|
2865
2808
|
search(node, value) {
|
|
2866
2809
|
return this.visit(node, value);
|
|
2867
2810
|
}
|
|
2868
|
-
|
|
2869
2811
|
visit(n, v) {
|
|
2870
2812
|
const visitFunctions = {
|
|
2871
2813
|
Field: (node, value) => {
|
|
2872
|
-
// we used to check isObject(value) here -- but it is possible for an array-based
|
|
2873
|
-
// object to have properties. So we'll allow the child check on objects and arrays.
|
|
2874
2814
|
if (value !== null && (isObject(value) || isArray(value))) {
|
|
2875
2815
|
let field = value[node.name];
|
|
2876
|
-
// fields can be objects with overridden methods. e.g. valueOf
|
|
2877
|
-
// so don't resolve to a function...
|
|
2878
2816
|
if (typeof field === 'function') field = undefined;
|
|
2879
2817
|
if (field === undefined) {
|
|
2880
2818
|
try {
|
|
2881
2819
|
this.debug.push(`Failed to find: '${node.name}'`);
|
|
2882
2820
|
const available = Object.keys(value).map(a => `'${a}'`).toString();
|
|
2883
2821
|
if (available.length) this.debug.push(`Available fields: ${available}`);
|
|
2884
|
-
// eslint-disable-next-line no-empty
|
|
2885
2822
|
} catch (e) {}
|
|
2886
2823
|
return null;
|
|
2887
2824
|
}
|
|
@@ -2889,7 +2826,6 @@ class TreeInterpreter {
|
|
|
2889
2826
|
}
|
|
2890
2827
|
return null;
|
|
2891
2828
|
},
|
|
2892
|
-
|
|
2893
2829
|
Subexpression: (node, value) => {
|
|
2894
2830
|
let result = this.visit(node.children[0], value);
|
|
2895
2831
|
for (let i = 1; i < node.children.length; i += 1) {
|
|
@@ -2898,12 +2834,10 @@ class TreeInterpreter {
|
|
|
2898
2834
|
}
|
|
2899
2835
|
return result;
|
|
2900
2836
|
},
|
|
2901
|
-
|
|
2902
2837
|
IndexExpression: (node, value) => {
|
|
2903
2838
|
const left = this.visit(node.children[0], value);
|
|
2904
2839
|
return this.visit(node.children[1], left);
|
|
2905
2840
|
},
|
|
2906
|
-
|
|
2907
2841
|
Index: (node, value) => {
|
|
2908
2842
|
if (isArray(value)) {
|
|
2909
2843
|
let index = this.toNumber(this.visit(node.value, value));
|
|
@@ -2929,7 +2863,6 @@ class TreeInterpreter {
|
|
|
2929
2863
|
this.debug.push(`left side of index expression ${value} is not an array or object.`);
|
|
2930
2864
|
return null;
|
|
2931
2865
|
},
|
|
2932
|
-
|
|
2933
2866
|
Slice: (node, value) => {
|
|
2934
2867
|
if (!isArray(value)) return null;
|
|
2935
2868
|
const sliceParams = node.children.slice(0).map(
|
|
@@ -2949,9 +2882,7 @@ class TreeInterpreter {
|
|
|
2949
2882
|
}
|
|
2950
2883
|
return result;
|
|
2951
2884
|
},
|
|
2952
|
-
|
|
2953
2885
|
Projection: (node, value) => {
|
|
2954
|
-
// Evaluate left child.
|
|
2955
2886
|
const base = this.visit(node.children[0], value);
|
|
2956
2887
|
if (!isArray(base)) return null;
|
|
2957
2888
|
const collected = [];
|
|
@@ -2963,9 +2894,7 @@ class TreeInterpreter {
|
|
|
2963
2894
|
});
|
|
2964
2895
|
return collected;
|
|
2965
2896
|
},
|
|
2966
|
-
|
|
2967
2897
|
ValueProjection: (node, value) => {
|
|
2968
|
-
// Evaluate left child.
|
|
2969
2898
|
const projection = this.visit(node.children[0], value);
|
|
2970
2899
|
if (!isObject(getValueOf(projection))) return null;
|
|
2971
2900
|
const collected = [];
|
|
@@ -2976,7 +2905,6 @@ class TreeInterpreter {
|
|
|
2976
2905
|
});
|
|
2977
2906
|
return collected;
|
|
2978
2907
|
},
|
|
2979
|
-
|
|
2980
2908
|
FilterProjection: (node, value) => {
|
|
2981
2909
|
const base = this.visit(node.children[0], value);
|
|
2982
2910
|
if (!isArray(base)) return null;
|
|
@@ -2984,7 +2912,6 @@ class TreeInterpreter {
|
|
|
2984
2912
|
const matched = this.visit(node.children[2], b);
|
|
2985
2913
|
return !isFalse(matched);
|
|
2986
2914
|
});
|
|
2987
|
-
|
|
2988
2915
|
const finalResults = [];
|
|
2989
2916
|
filtered.forEach(f => {
|
|
2990
2917
|
const current = this.visit(node.children[1], f);
|
|
@@ -2992,11 +2919,9 @@ class TreeInterpreter {
|
|
|
2992
2919
|
});
|
|
2993
2920
|
return finalResults;
|
|
2994
2921
|
},
|
|
2995
|
-
|
|
2996
2922
|
Comparator: (node, value) => {
|
|
2997
2923
|
const first = this.visit(node.children[0], value);
|
|
2998
2924
|
const second = this.visit(node.children[1], value);
|
|
2999
|
-
|
|
3000
2925
|
if (node.name === TOK_EQ$2) return strictDeepEqual(first, second);
|
|
3001
2926
|
if (node.name === TOK_NE$2) return !strictDeepEqual(first, second);
|
|
3002
2927
|
if (node.name === TOK_GT$2) return first > second;
|
|
@@ -3005,7 +2930,6 @@ class TreeInterpreter {
|
|
|
3005
2930
|
if (node.name === TOK_LTE$2) return first <= second;
|
|
3006
2931
|
throw new Error(`Unknown comparator: ${node.name}`);
|
|
3007
2932
|
},
|
|
3008
|
-
|
|
3009
2933
|
[TOK_FLATTEN$2]: (node, value) => {
|
|
3010
2934
|
const original = this.visit(node.children[0], value);
|
|
3011
2935
|
if (!isArray(original)) return null;
|
|
@@ -3019,14 +2943,11 @@ class TreeInterpreter {
|
|
|
3019
2943
|
});
|
|
3020
2944
|
return merged;
|
|
3021
2945
|
},
|
|
3022
|
-
|
|
3023
2946
|
Identity: (_node, value) => value,
|
|
3024
|
-
|
|
3025
2947
|
MultiSelectList: (node, value) => {
|
|
3026
2948
|
if (value === null) return null;
|
|
3027
2949
|
return node.children.map(child => this.visit(child, value));
|
|
3028
2950
|
},
|
|
3029
|
-
|
|
3030
2951
|
MultiSelectHash: (node, value) => {
|
|
3031
2952
|
if (value === null) return null;
|
|
3032
2953
|
const collected = {};
|
|
@@ -3035,26 +2956,21 @@ class TreeInterpreter {
|
|
|
3035
2956
|
});
|
|
3036
2957
|
return collected;
|
|
3037
2958
|
},
|
|
3038
|
-
|
|
3039
2959
|
OrExpression: (node, value) => {
|
|
3040
2960
|
let matched = this.visit(node.children[0], value);
|
|
3041
2961
|
if (isFalse(matched)) matched = this.visit(node.children[1], value);
|
|
3042
2962
|
return matched;
|
|
3043
2963
|
},
|
|
3044
|
-
|
|
3045
2964
|
AndExpression: (node, value) => {
|
|
3046
2965
|
const first = this.visit(node.children[0], value);
|
|
3047
|
-
|
|
3048
2966
|
if (isFalse(first) === true) return first;
|
|
3049
2967
|
return this.visit(node.children[1], value);
|
|
3050
2968
|
},
|
|
3051
|
-
|
|
3052
2969
|
AddExpression: (node, value) => {
|
|
3053
2970
|
const first = this.visit(node.children[0], value);
|
|
3054
2971
|
const second = this.visit(node.children[1], value);
|
|
3055
2972
|
return this.applyOperator(first, second, '+');
|
|
3056
2973
|
},
|
|
3057
|
-
|
|
3058
2974
|
ConcatenateExpression: (node, value) => {
|
|
3059
2975
|
let first = this.visit(node.children[0], value);
|
|
3060
2976
|
let second = this.visit(node.children[1], value);
|
|
@@ -3062,7 +2978,6 @@ class TreeInterpreter {
|
|
|
3062
2978
|
second = matchType(getTypeNames(second), [TYPE_STRING, TYPE_ARRAY_STRING], second, 'concatenate', this.toNumber, this.toString);
|
|
3063
2979
|
return this.applyOperator(first, second, '&');
|
|
3064
2980
|
},
|
|
3065
|
-
|
|
3066
2981
|
UnionExpression: (node, value) => {
|
|
3067
2982
|
let first = this.visit(node.children[0], value);
|
|
3068
2983
|
let second = this.visit(node.children[1], value);
|
|
@@ -3070,72 +2985,52 @@ class TreeInterpreter {
|
|
|
3070
2985
|
second = matchType(getTypeNames(second), [TYPE_ARRAY], second, 'union', this.toNumber, this.toString);
|
|
3071
2986
|
return first.concat(second);
|
|
3072
2987
|
},
|
|
3073
|
-
|
|
3074
2988
|
SubtractExpression: (node, value) => {
|
|
3075
2989
|
const first = this.visit(node.children[0], value);
|
|
3076
2990
|
const second = this.visit(node.children[1], value);
|
|
3077
2991
|
return this.applyOperator(first, second, '-');
|
|
3078
2992
|
},
|
|
3079
|
-
|
|
3080
2993
|
MultiplyExpression: (node, value) => {
|
|
3081
2994
|
const first = this.visit(node.children[0], value);
|
|
3082
2995
|
const second = this.visit(node.children[1], value);
|
|
3083
2996
|
return this.applyOperator(first, second, '*');
|
|
3084
2997
|
},
|
|
3085
|
-
|
|
3086
2998
|
DivideExpression: (node, value) => {
|
|
3087
2999
|
const first = this.visit(node.children[0], value);
|
|
3088
3000
|
const second = this.visit(node.children[1], value);
|
|
3089
3001
|
return this.applyOperator(first, second, '/');
|
|
3090
3002
|
},
|
|
3091
|
-
|
|
3092
3003
|
PowerExpression: (node, value) => {
|
|
3093
3004
|
const first = this.visit(node.children[0], value);
|
|
3094
3005
|
const second = this.visit(node.children[1], value);
|
|
3095
3006
|
return this.applyOperator(first, second, '^');
|
|
3096
3007
|
},
|
|
3097
|
-
|
|
3098
3008
|
NotExpression: (node, value) => {
|
|
3099
3009
|
const first = this.visit(node.children[0], value);
|
|
3100
3010
|
return isFalse(first);
|
|
3101
3011
|
},
|
|
3102
|
-
|
|
3103
3012
|
UnaryMinusExpression: (node, value) => {
|
|
3104
3013
|
const first = this.visit(node.children[0], value);
|
|
3105
3014
|
return first * -1;
|
|
3106
3015
|
},
|
|
3107
|
-
|
|
3108
3016
|
Literal: node => node.value,
|
|
3109
|
-
|
|
3110
3017
|
Number: node => node.value,
|
|
3111
|
-
|
|
3112
3018
|
[TOK_PIPE$2]: (node, value) => {
|
|
3113
3019
|
const left = this.visit(node.children[0], value);
|
|
3114
3020
|
return this.visit(node.children[1], left);
|
|
3115
3021
|
},
|
|
3116
|
-
|
|
3117
3022
|
[TOK_CURRENT$2]: (_node, value) => value,
|
|
3118
|
-
|
|
3119
3023
|
[TOK_GLOBAL$2]: node => {
|
|
3120
3024
|
const result = this.globals[node.name];
|
|
3121
3025
|
return result === undefined ? null : result;
|
|
3122
3026
|
},
|
|
3123
|
-
|
|
3124
3027
|
Function: (node, value) => {
|
|
3125
|
-
// Special case for if()
|
|
3126
|
-
// we need to make sure the results are called only after the condition is evaluated
|
|
3127
|
-
// Otherwise we end up with both results invoked -- which could include side effects
|
|
3128
|
-
// For "if", the last parameter to callFunction is false (bResolved) to indicate there's
|
|
3129
|
-
// no point in validating the argument type.
|
|
3130
3028
|
if (node.name === 'if') return this.runtime.callFunction(node.name, node.children, value, this, false);
|
|
3131
3029
|
const resolvedArgs = node.children.map(child => this.visit(child, value));
|
|
3132
3030
|
return this.runtime.callFunction(node.name, resolvedArgs, value, this);
|
|
3133
3031
|
},
|
|
3134
|
-
|
|
3135
3032
|
ExpressionReference: node => {
|
|
3136
3033
|
const [refNode] = node.children;
|
|
3137
|
-
// Tag the node with a specific attribute so the type
|
|
3138
|
-
// checker verify the type.
|
|
3139
3034
|
refNode.jmespathType = TOK_EXPREF$2;
|
|
3140
3035
|
return refNode;
|
|
3141
3036
|
},
|
|
@@ -3144,8 +3039,6 @@ class TreeInterpreter {
|
|
|
3144
3039
|
if (!fn) throw new Error(`Unknown/missing node type ${(n && n.type) || ''}`);
|
|
3145
3040
|
return fn(n, v);
|
|
3146
3041
|
}
|
|
3147
|
-
|
|
3148
|
-
// eslint-disable-next-line class-methods-use-this
|
|
3149
3042
|
computeSliceParams(arrayLength, sliceParams) {
|
|
3150
3043
|
function capSliceRange(arrayLen, actual, stp) {
|
|
3151
3044
|
let actualValue = actual;
|
|
@@ -3159,7 +3052,6 @@ class TreeInterpreter {
|
|
|
3159
3052
|
}
|
|
3160
3053
|
return actualValue;
|
|
3161
3054
|
}
|
|
3162
|
-
|
|
3163
3055
|
let [start, stop, step] = sliceParams;
|
|
3164
3056
|
if (step === null) {
|
|
3165
3057
|
step = 1;
|
|
@@ -3169,13 +3061,11 @@ class TreeInterpreter {
|
|
|
3169
3061
|
throw error;
|
|
3170
3062
|
}
|
|
3171
3063
|
const stepValueNegative = step < 0;
|
|
3172
|
-
|
|
3173
3064
|
if (start === null) {
|
|
3174
3065
|
start = stepValueNegative ? arrayLength - 1 : 0;
|
|
3175
3066
|
} else {
|
|
3176
3067
|
start = capSliceRange(arrayLength, start, step);
|
|
3177
3068
|
}
|
|
3178
|
-
|
|
3179
3069
|
if (stop === null) {
|
|
3180
3070
|
stop = stepValueNegative ? -1 : arrayLength;
|
|
3181
3071
|
} else {
|
|
@@ -3183,10 +3073,8 @@ class TreeInterpreter {
|
|
|
3183
3073
|
}
|
|
3184
3074
|
return [start, stop, step];
|
|
3185
3075
|
}
|
|
3186
|
-
|
|
3187
3076
|
applyOperator(first, second, operator) {
|
|
3188
3077
|
if (isArray(first) && isArray(second)) {
|
|
3189
|
-
// balance the size of the arrays
|
|
3190
3078
|
const shorter = first.length < second.length ? first : second;
|
|
3191
3079
|
const diff = Math.abs(first.length - second.length);
|
|
3192
3080
|
shorter.length += diff;
|
|
@@ -3197,10 +3085,8 @@ class TreeInterpreter {
|
|
|
3197
3085
|
}
|
|
3198
3086
|
return result;
|
|
3199
3087
|
}
|
|
3200
|
-
|
|
3201
3088
|
if (isArray(first)) return first.map(a => this.applyOperator(a, second, operator));
|
|
3202
3089
|
if (isArray(second)) return second.map(a => this.applyOperator(first, a, operator));
|
|
3203
|
-
|
|
3204
3090
|
if (operator === '*') return this.toNumber(first) * this.toNumber(second);
|
|
3205
3091
|
if (operator === '&') return first + second;
|
|
3206
3092
|
if (operator === '+') {
|
|
@@ -3218,8 +3104,6 @@ class TreeInterpreter {
|
|
|
3218
3104
|
}
|
|
3219
3105
|
}
|
|
3220
3106
|
|
|
3221
|
-
/* eslint-disable no-underscore-dangle */
|
|
3222
|
-
|
|
3223
3107
|
const {
|
|
3224
3108
|
TOK_UNQUOTEDIDENTIFIER: TOK_UNQUOTEDIDENTIFIER$1,
|
|
3225
3109
|
TOK_QUOTEDIDENTIFIER: TOK_QUOTEDIDENTIFIER$1,
|
|
@@ -3259,16 +3143,8 @@ const {
|
|
|
3259
3143
|
TOK_LPAREN: TOK_LPAREN$1,
|
|
3260
3144
|
TOK_LITERAL: TOK_LITERAL$1,
|
|
3261
3145
|
} = tokenDefinitions;
|
|
3262
|
-
|
|
3263
|
-
// The "&", "[", "<", ">" tokens
|
|
3264
|
-
// are not in basicToken because
|
|
3265
|
-
// there are two token variants
|
|
3266
|
-
// ("&&", "[?", "<=", ">="). This is specially handled
|
|
3267
|
-
// below.
|
|
3268
|
-
|
|
3269
3146
|
const basicTokens = {
|
|
3270
3147
|
'.': TOK_DOT$1,
|
|
3271
|
-
// "*": TOK_STAR,
|
|
3272
3148
|
',': TOK_COMMA$1,
|
|
3273
3149
|
':': TOK_COLON$1,
|
|
3274
3150
|
'{': TOK_LBRACE$1,
|
|
@@ -3278,7 +3154,6 @@ const basicTokens = {
|
|
|
3278
3154
|
')': TOK_RPAREN$1,
|
|
3279
3155
|
'@': TOK_CURRENT$1,
|
|
3280
3156
|
};
|
|
3281
|
-
|
|
3282
3157
|
const globalStartToken = '$';
|
|
3283
3158
|
const operatorStartToken = {
|
|
3284
3159
|
'<': true,
|
|
@@ -3286,42 +3161,34 @@ const operatorStartToken = {
|
|
|
3286
3161
|
'=': true,
|
|
3287
3162
|
'!': true,
|
|
3288
3163
|
};
|
|
3289
|
-
|
|
3290
3164
|
const skipChars = {
|
|
3291
3165
|
' ': true,
|
|
3292
3166
|
'\t': true,
|
|
3293
3167
|
'\n': true,
|
|
3294
3168
|
};
|
|
3295
|
-
|
|
3296
3169
|
function isNum(ch) {
|
|
3297
3170
|
return (ch >= '0' && ch <= '9') || (ch === '.');
|
|
3298
3171
|
}
|
|
3299
|
-
|
|
3300
3172
|
function isAlphaNum(ch) {
|
|
3301
3173
|
return (ch >= 'a' && ch <= 'z')
|
|
3302
3174
|
|| (ch >= 'A' && ch <= 'Z')
|
|
3303
3175
|
|| (ch >= '0' && ch <= '9')
|
|
3304
3176
|
|| ch === '_';
|
|
3305
3177
|
}
|
|
3306
|
-
|
|
3307
3178
|
function isIdentifier(stream, pos) {
|
|
3308
3179
|
const ch = stream[pos];
|
|
3309
|
-
// $ is special -- it's allowed to be part of an identifier if it's the first character
|
|
3310
3180
|
if (ch === '$') {
|
|
3311
3181
|
return stream.length > pos && isAlphaNum(stream[pos + 1]);
|
|
3312
3182
|
}
|
|
3313
|
-
// return whether character 'isAlpha'
|
|
3314
3183
|
return (ch >= 'a' && ch <= 'z')
|
|
3315
3184
|
|| (ch >= 'A' && ch <= 'Z')
|
|
3316
3185
|
|| ch === '_';
|
|
3317
3186
|
}
|
|
3318
|
-
|
|
3319
3187
|
class Lexer {
|
|
3320
3188
|
constructor(allowedGlobalNames = [], debug = []) {
|
|
3321
3189
|
this._allowedGlobalNames = allowedGlobalNames;
|
|
3322
3190
|
this.debug = debug;
|
|
3323
3191
|
}
|
|
3324
|
-
|
|
3325
3192
|
tokenize(stream) {
|
|
3326
3193
|
const tokens = [];
|
|
3327
3194
|
this._current = 0;
|
|
@@ -3330,7 +3197,6 @@ class Lexer {
|
|
|
3330
3197
|
let token;
|
|
3331
3198
|
while (this._current < stream.length) {
|
|
3332
3199
|
const prev = tokens.length ? tokens.slice(-1)[0].type : null;
|
|
3333
|
-
|
|
3334
3200
|
if (this._isGlobal(prev, stream, this._current)) {
|
|
3335
3201
|
tokens.push(this._consumeGlobal(stream));
|
|
3336
3202
|
} else if (isIdentifier(stream, this._current)) {
|
|
@@ -3355,8 +3221,6 @@ class Lexer {
|
|
|
3355
3221
|
token = this._consumeNumber(stream);
|
|
3356
3222
|
tokens.push(token);
|
|
3357
3223
|
} else if (stream[this._current] === '[') {
|
|
3358
|
-
// No need to increment this._current. This happens
|
|
3359
|
-
// in _consumeLBracket
|
|
3360
3224
|
token = this._consumeLBracket(stream);
|
|
3361
3225
|
tokens.push(token);
|
|
3362
3226
|
} else if (stream[this._current] === '"') {
|
|
@@ -3386,7 +3250,6 @@ class Lexer {
|
|
|
3386
3250
|
} else if (operatorStartToken[stream[this._current]] !== undefined) {
|
|
3387
3251
|
tokens.push(this._consumeOperator(stream));
|
|
3388
3252
|
} else if (skipChars[stream[this._current]] !== undefined) {
|
|
3389
|
-
// Ignore whitespace.
|
|
3390
3253
|
this._current += 1;
|
|
3391
3254
|
} else if (stream[this._current] === '&') {
|
|
3392
3255
|
start = this._current;
|
|
@@ -3395,9 +3258,6 @@ class Lexer {
|
|
|
3395
3258
|
this._current += 1;
|
|
3396
3259
|
tokens.push({ type: TOK_AND$1, value: '&&', start });
|
|
3397
3260
|
} else if (prev === TOK_COMMA$1 || prev === TOK_LPAREN$1) {
|
|
3398
|
-
// based on previous token we'll know if this & is a JMESPath expression-type
|
|
3399
|
-
// or if it's a concatenation operator
|
|
3400
|
-
// if we're a function arg then it's an expression-type
|
|
3401
3261
|
tokens.push({ type: TOK_EXPREF$1, value: '&', start });
|
|
3402
3262
|
} else {
|
|
3403
3263
|
tokens.push({ type: TOK_CONCATENATE$1, value: '&', start });
|
|
@@ -3417,8 +3277,6 @@ class Lexer {
|
|
|
3417
3277
|
} else if (stream[this._current] === '*') {
|
|
3418
3278
|
start = this._current;
|
|
3419
3279
|
this._current += 1;
|
|
3420
|
-
// based on previous token we'll know if this asterix is a star -- not a multiply
|
|
3421
|
-
// might be better to list the prev tokens that are valid for multiply?
|
|
3422
3280
|
const prevToken = tokens.length && tokens.slice(-1)[0].type;
|
|
3423
3281
|
if (tokens.length === 0 || [
|
|
3424
3282
|
TOK_LBRACKET$1,
|
|
@@ -3458,7 +3316,6 @@ class Lexer {
|
|
|
3458
3316
|
}
|
|
3459
3317
|
return tokens;
|
|
3460
3318
|
}
|
|
3461
|
-
|
|
3462
3319
|
_consumeUnquotedIdentifier(stream) {
|
|
3463
3320
|
const start = this._current;
|
|
3464
3321
|
this._current += 1;
|
|
@@ -3467,14 +3324,12 @@ class Lexer {
|
|
|
3467
3324
|
}
|
|
3468
3325
|
return stream.slice(start, this._current);
|
|
3469
3326
|
}
|
|
3470
|
-
|
|
3471
3327
|
_consumeQuotedIdentifier(stream) {
|
|
3472
3328
|
const start = this._current;
|
|
3473
3329
|
this._current += 1;
|
|
3474
3330
|
const maxLength = stream.length;
|
|
3475
3331
|
let foundNonAlpha = !isIdentifier(stream, start + 1);
|
|
3476
3332
|
while (stream[this._current] !== '"' && this._current < maxLength) {
|
|
3477
|
-
// You can escape a double quote and you can escape an escape.
|
|
3478
3333
|
let current = this._current;
|
|
3479
3334
|
if (!isAlphaNum(stream[current])) foundNonAlpha = true;
|
|
3480
3335
|
if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
@@ -3487,26 +3342,19 @@ class Lexer {
|
|
|
3487
3342
|
}
|
|
3488
3343
|
this._current += 1;
|
|
3489
3344
|
const val = stream.slice(start, this._current);
|
|
3490
|
-
// Check for unnecessary double quotes.
|
|
3491
|
-
// json-formula uses double quotes to escape characters that don't belong in names names.
|
|
3492
|
-
// e.g. "purchase-order".address
|
|
3493
|
-
// If we find a double-quoted entity with spaces or all legal characters, issue a warning
|
|
3494
3345
|
try {
|
|
3495
3346
|
if (!foundNonAlpha || val.includes(' ')) {
|
|
3496
3347
|
this.debug.push(`Suspicious quotes: ${val}`);
|
|
3497
3348
|
this.debug.push(`Did you intend a literal? '${val.replace(/"/g, '')}'?`);
|
|
3498
3349
|
}
|
|
3499
|
-
// eslint-disable-next-line no-empty
|
|
3500
3350
|
} catch (e) {}
|
|
3501
3351
|
return JSON.parse(val);
|
|
3502
3352
|
}
|
|
3503
|
-
|
|
3504
3353
|
_consumeRawStringLiteral(stream) {
|
|
3505
3354
|
const start = this._current;
|
|
3506
3355
|
this._current += 1;
|
|
3507
3356
|
const maxLength = stream.length;
|
|
3508
3357
|
while (stream[this._current] !== "'" && this._current < maxLength) {
|
|
3509
|
-
// You can escape a single quote and you can escape an escape.
|
|
3510
3358
|
let current = this._current;
|
|
3511
3359
|
if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
3512
3360
|
|| stream[current + 1] === "'")) {
|
|
@@ -3520,7 +3368,6 @@ class Lexer {
|
|
|
3520
3368
|
const literal = stream.slice(start + 1, this._current - 1);
|
|
3521
3369
|
return literal.replaceAll("\\'", "'");
|
|
3522
3370
|
}
|
|
3523
|
-
|
|
3524
3371
|
_consumeNumber(stream) {
|
|
3525
3372
|
const start = this._current;
|
|
3526
3373
|
this._current += 1;
|
|
@@ -3537,13 +3384,11 @@ class Lexer {
|
|
|
3537
3384
|
}
|
|
3538
3385
|
return { type: TOK_NUMBER$1, value, start };
|
|
3539
3386
|
}
|
|
3540
|
-
|
|
3541
3387
|
_consumeUnaryMinus() {
|
|
3542
3388
|
const start = this._current;
|
|
3543
3389
|
this._current += 1;
|
|
3544
3390
|
return { type: TOK_UNARY_MINUS$1, value: '-', start };
|
|
3545
3391
|
}
|
|
3546
|
-
|
|
3547
3392
|
_consumeLBracket(stream) {
|
|
3548
3393
|
const start = this._current;
|
|
3549
3394
|
this._current += 1;
|
|
@@ -3557,28 +3402,22 @@ class Lexer {
|
|
|
3557
3402
|
}
|
|
3558
3403
|
return { type: TOK_LBRACKET$1, value: '[', start };
|
|
3559
3404
|
}
|
|
3560
|
-
|
|
3561
3405
|
_isGlobal(prev, stream, pos) {
|
|
3562
|
-
// global tokens occur only at the start of an expression
|
|
3563
3406
|
if (prev !== null && prev === TOK_DOT$1) return false;
|
|
3564
3407
|
const ch = stream[pos];
|
|
3565
3408
|
if (ch !== globalStartToken) return false;
|
|
3566
|
-
// $ is special -- it's allowed to be part of an identifier if it's the first character
|
|
3567
3409
|
let i = pos + 1;
|
|
3568
3410
|
while (i < stream.length && isAlphaNum(stream[i])) i += 1;
|
|
3569
3411
|
const global = stream.slice(pos, i);
|
|
3570
3412
|
return this._allowedGlobalNames.includes(global);
|
|
3571
3413
|
}
|
|
3572
|
-
|
|
3573
3414
|
_consumeGlobal(stream) {
|
|
3574
3415
|
const start = this._current;
|
|
3575
3416
|
this._current += 1;
|
|
3576
3417
|
while (this._current < stream.length && isAlphaNum(stream[this._current])) this._current += 1;
|
|
3577
3418
|
const global = stream.slice(start, this._current);
|
|
3578
|
-
|
|
3579
3419
|
return { type: TOK_GLOBAL$1, name: global, start };
|
|
3580
3420
|
}
|
|
3581
|
-
|
|
3582
3421
|
_consumeOperator(stream) {
|
|
3583
3422
|
const start = this._current;
|
|
3584
3423
|
const startingChar = stream[start];
|
|
@@ -3604,20 +3443,17 @@ class Lexer {
|
|
|
3604
3443
|
}
|
|
3605
3444
|
return { type: TOK_GT$1, value: '>', start };
|
|
3606
3445
|
}
|
|
3607
|
-
// startingChar is '='
|
|
3608
3446
|
if (stream[this._current] === '=') {
|
|
3609
3447
|
this._current += 1;
|
|
3610
3448
|
return { type: TOK_EQ$1, value: '==', start };
|
|
3611
3449
|
}
|
|
3612
3450
|
return { type: TOK_EQ$1, value: '=', start };
|
|
3613
3451
|
}
|
|
3614
|
-
|
|
3615
3452
|
_consumeLiteral(stream) {
|
|
3616
3453
|
function _looksLikeJSON(str) {
|
|
3617
3454
|
if (str === '') return false;
|
|
3618
3455
|
if ('[{"'.includes(str[0])) return true;
|
|
3619
3456
|
if (['true', 'false', 'null'].includes(str)) return true;
|
|
3620
|
-
|
|
3621
3457
|
if ('-0123456789'.includes(str[0])) {
|
|
3622
3458
|
try {
|
|
3623
3459
|
JSON.parse(str);
|
|
@@ -3629,7 +3465,6 @@ class Lexer {
|
|
|
3629
3465
|
return false;
|
|
3630
3466
|
}
|
|
3631
3467
|
}
|
|
3632
|
-
|
|
3633
3468
|
this._current += 1;
|
|
3634
3469
|
const start = this._current;
|
|
3635
3470
|
const maxLength = stream.length;
|
|
@@ -3637,14 +3472,12 @@ class Lexer {
|
|
|
3637
3472
|
let inQuotes = false;
|
|
3638
3473
|
while ((inQuotes || stream[this._current] !== '`') && this._current < maxLength) {
|
|
3639
3474
|
let current = this._current;
|
|
3640
|
-
// bypass escaped double quotes when we're inside quotes
|
|
3641
3475
|
if (inQuotes && stream[current] === '\\' && stream[current + 1] === '"') current += 2;
|
|
3642
3476
|
else {
|
|
3643
3477
|
if (stream[current] === '"') inQuotes = !inQuotes;
|
|
3644
3478
|
if (inQuotes && stream[current + 1] === '`') current += 2;
|
|
3645
3479
|
else if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
3646
3480
|
|| stream[current + 1] === '`')) {
|
|
3647
|
-
// You can escape a literal char or you can escape the escape.
|
|
3648
3481
|
current += 2;
|
|
3649
3482
|
} else {
|
|
3650
3483
|
current += 1;
|
|
@@ -3657,16 +3490,13 @@ class Lexer {
|
|
|
3657
3490
|
if (_looksLikeJSON(literalString)) {
|
|
3658
3491
|
literal = JSON.parse(literalString);
|
|
3659
3492
|
} else {
|
|
3660
|
-
// Try to JSON parse it as "<literal>"
|
|
3661
3493
|
literal = JSON.parse(`"${literalString}"`);
|
|
3662
3494
|
}
|
|
3663
|
-
// +1 gets us to the ending "`", +1 to move on to the next char.
|
|
3664
3495
|
this._current += 1;
|
|
3665
3496
|
return literal;
|
|
3666
3497
|
}
|
|
3667
3498
|
}
|
|
3668
3499
|
|
|
3669
|
-
/* eslint-disable no-underscore-dangle */
|
|
3670
3500
|
const {
|
|
3671
3501
|
TOK_LITERAL,
|
|
3672
3502
|
TOK_COLON,
|
|
@@ -3708,7 +3538,6 @@ const {
|
|
|
3708
3538
|
TOK_LBRACKET,
|
|
3709
3539
|
TOK_LPAREN,
|
|
3710
3540
|
} = tokenDefinitions;
|
|
3711
|
-
|
|
3712
3541
|
const bindingPower = {
|
|
3713
3542
|
[TOK_EOF]: 0,
|
|
3714
3543
|
[TOK_UNQUOTEDIDENTIFIER]: 0,
|
|
@@ -3748,12 +3577,10 @@ const bindingPower = {
|
|
|
3748
3577
|
[TOK_LBRACKET]: 55,
|
|
3749
3578
|
[TOK_LPAREN]: 60,
|
|
3750
3579
|
};
|
|
3751
|
-
|
|
3752
3580
|
class Parser {
|
|
3753
3581
|
constructor(allowedGlobalNames = []) {
|
|
3754
3582
|
this._allowedGlobalNames = allowedGlobalNames;
|
|
3755
3583
|
}
|
|
3756
|
-
|
|
3757
3584
|
parse(expression, debug) {
|
|
3758
3585
|
this._loadTokens(expression, debug);
|
|
3759
3586
|
this.index = 0;
|
|
@@ -3768,14 +3595,12 @@ class Parser {
|
|
|
3768
3595
|
}
|
|
3769
3596
|
return ast;
|
|
3770
3597
|
}
|
|
3771
|
-
|
|
3772
3598
|
_loadTokens(expression, debug) {
|
|
3773
3599
|
const lexer = new Lexer(this._allowedGlobalNames, debug);
|
|
3774
3600
|
const tokens = lexer.tokenize(expression);
|
|
3775
3601
|
tokens.push({ type: TOK_EOF, value: '', start: expression.length });
|
|
3776
3602
|
this.tokens = tokens;
|
|
3777
3603
|
}
|
|
3778
|
-
|
|
3779
3604
|
expression(rbp) {
|
|
3780
3605
|
const leftToken = this._lookaheadToken(0);
|
|
3781
3606
|
this._advance();
|
|
@@ -3788,28 +3613,21 @@ class Parser {
|
|
|
3788
3613
|
}
|
|
3789
3614
|
return left;
|
|
3790
3615
|
}
|
|
3791
|
-
|
|
3792
3616
|
_lookahead(number) {
|
|
3793
3617
|
return this.tokens[this.index + number].type;
|
|
3794
3618
|
}
|
|
3795
|
-
|
|
3796
3619
|
_lookaheadToken(number) {
|
|
3797
3620
|
return this.tokens[this.index + number];
|
|
3798
3621
|
}
|
|
3799
|
-
|
|
3800
3622
|
_advance() {
|
|
3801
3623
|
this.index += 1;
|
|
3802
3624
|
}
|
|
3803
|
-
|
|
3804
3625
|
_getIndex() {
|
|
3805
3626
|
return this.index;
|
|
3806
3627
|
}
|
|
3807
|
-
|
|
3808
3628
|
_setIndex(index) {
|
|
3809
3629
|
this.index = index;
|
|
3810
3630
|
}
|
|
3811
|
-
|
|
3812
|
-
// eslint-disable-next-line consistent-return
|
|
3813
3631
|
nud(token) {
|
|
3814
3632
|
let left;
|
|
3815
3633
|
let right;
|
|
@@ -3838,8 +3656,6 @@ class Parser {
|
|
|
3838
3656
|
case TOK_STAR:
|
|
3839
3657
|
left = { type: 'Identity' };
|
|
3840
3658
|
if (this._lookahead(0) === TOK_RBRACKET) {
|
|
3841
|
-
// This can happen in a multiselect,
|
|
3842
|
-
// [a, b, *]
|
|
3843
3659
|
right = { type: 'Identity' };
|
|
3844
3660
|
} else {
|
|
3845
3661
|
right = this._parseProjectionRHS(bindingPower.Star);
|
|
@@ -3886,8 +3702,6 @@ class Parser {
|
|
|
3886
3702
|
this._errorToken(token);
|
|
3887
3703
|
}
|
|
3888
3704
|
}
|
|
3889
|
-
|
|
3890
|
-
// eslint-disable-next-line consistent-return
|
|
3891
3705
|
led(tokenName, left) {
|
|
3892
3706
|
let condition;
|
|
3893
3707
|
let right;
|
|
@@ -3908,7 +3722,6 @@ class Parser {
|
|
|
3908
3722
|
right = this._parseDotRHS(rbp);
|
|
3909
3723
|
return { type: 'Subexpression', children: [left, right] };
|
|
3910
3724
|
}
|
|
3911
|
-
// Creating a projection.
|
|
3912
3725
|
this._advance();
|
|
3913
3726
|
right = this._parseProjectionRHS(rbp);
|
|
3914
3727
|
return { type: 'ValueProjection', children: [left, right] };
|
|
@@ -3986,7 +3799,6 @@ class Parser {
|
|
|
3986
3799
|
this._errorToken(this._lookaheadToken(0));
|
|
3987
3800
|
}
|
|
3988
3801
|
}
|
|
3989
|
-
|
|
3990
3802
|
_match(tokenType) {
|
|
3991
3803
|
if (this._lookahead(0) === tokenType) {
|
|
3992
3804
|
this._advance();
|
|
@@ -3997,8 +3809,6 @@ class Parser {
|
|
|
3997
3809
|
throw error;
|
|
3998
3810
|
}
|
|
3999
3811
|
}
|
|
4000
|
-
|
|
4001
|
-
// eslint-disable-next-line class-methods-use-this
|
|
4002
3812
|
_errorToken(token) {
|
|
4003
3813
|
const error = new Error(`Invalid token (${
|
|
4004
3814
|
token.type}): "${
|
|
@@ -4006,17 +3816,14 @@ class Parser {
|
|
|
4006
3816
|
error.name = 'ParserError';
|
|
4007
3817
|
throw error;
|
|
4008
3818
|
}
|
|
4009
|
-
|
|
4010
3819
|
_parseChainedIndexExpression() {
|
|
4011
3820
|
const oldIndex = this._getIndex();
|
|
4012
3821
|
if (this._lookahead(0) === TOK_COLON) {
|
|
4013
3822
|
return this._parseSliceExpression();
|
|
4014
3823
|
}
|
|
4015
|
-
// look ahead of the first expression to determine the type
|
|
4016
3824
|
const first = this.expression(0);
|
|
4017
3825
|
const token = this._lookahead(0);
|
|
4018
3826
|
if (token === TOK_COLON) {
|
|
4019
|
-
// now that we know the type revert back to the old position and parse
|
|
4020
3827
|
this._setIndex(oldIndex);
|
|
4021
3828
|
return this._parseSliceExpression();
|
|
4022
3829
|
}
|
|
@@ -4026,7 +3833,6 @@ class Parser {
|
|
|
4026
3833
|
value: first,
|
|
4027
3834
|
};
|
|
4028
3835
|
}
|
|
4029
|
-
|
|
4030
3836
|
_parseUnchainedIndexExpression() {
|
|
4031
3837
|
const oldIndex = this._getIndex();
|
|
4032
3838
|
const firstToken = this._lookahead(0);
|
|
@@ -4055,7 +3861,6 @@ class Parser {
|
|
|
4055
3861
|
this._setIndex(oldIndex);
|
|
4056
3862
|
return this._parseMultiselectList();
|
|
4057
3863
|
}
|
|
4058
|
-
|
|
4059
3864
|
_projectIfSlice(left, right) {
|
|
4060
3865
|
const indexExpr = { type: 'IndexExpression', children: [left, right] };
|
|
4061
3866
|
if (right.type === 'Slice') {
|
|
@@ -4066,20 +3871,16 @@ class Parser {
|
|
|
4066
3871
|
}
|
|
4067
3872
|
return indexExpr;
|
|
4068
3873
|
}
|
|
4069
|
-
|
|
4070
3874
|
_parseSliceExpression() {
|
|
4071
|
-
// [start:end:step] where each part is optional, as well as the last
|
|
4072
|
-
// colon.
|
|
4073
3875
|
const parts = [null, null, null];
|
|
4074
3876
|
let index = 0;
|
|
4075
3877
|
let currentToken = this._lookahead(0);
|
|
4076
3878
|
while (currentToken !== TOK_RBRACKET && index < 3) {
|
|
4077
|
-
if (currentToken === TOK_COLON && index < 2) {
|
|
3879
|
+
if (currentToken === TOK_COLON && index < 2) {
|
|
4078
3880
|
index += 1;
|
|
4079
3881
|
this._advance();
|
|
4080
3882
|
} else {
|
|
4081
3883
|
parts[index] = this.expression(0);
|
|
4082
|
-
// check next token to be either colon or rbracket
|
|
4083
3884
|
const t = this._lookahead(0);
|
|
4084
3885
|
if (t !== TOK_COLON && t !== TOK_RBRACKET) {
|
|
4085
3886
|
const error = new Error(`Syntax error, unexpected token: ${
|
|
@@ -4096,13 +3897,10 @@ class Parser {
|
|
|
4096
3897
|
children: parts,
|
|
4097
3898
|
};
|
|
4098
3899
|
}
|
|
4099
|
-
|
|
4100
3900
|
_parseComparator(left, comparator) {
|
|
4101
3901
|
const right = this.expression(bindingPower[comparator]);
|
|
4102
3902
|
return { type: 'Comparator', name: comparator, children: [left, right] };
|
|
4103
3903
|
}
|
|
4104
|
-
|
|
4105
|
-
// eslint-disable-next-line consistent-return
|
|
4106
3904
|
_parseDotRHS(rbp) {
|
|
4107
3905
|
const lookahead = this._lookahead(0);
|
|
4108
3906
|
const exprTokens = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER, TOK_STAR];
|
|
@@ -4118,7 +3916,6 @@ class Parser {
|
|
|
4118
3916
|
return this._parseMultiselectHash();
|
|
4119
3917
|
}
|
|
4120
3918
|
}
|
|
4121
|
-
|
|
4122
3919
|
_parseProjectionRHS(rbp) {
|
|
4123
3920
|
let right;
|
|
4124
3921
|
if (bindingPower[this._lookahead(0)] < 10) {
|
|
@@ -4139,7 +3936,6 @@ class Parser {
|
|
|
4139
3936
|
}
|
|
4140
3937
|
return right;
|
|
4141
3938
|
}
|
|
4142
|
-
|
|
4143
3939
|
_parseMultiselectList() {
|
|
4144
3940
|
const expressions = [];
|
|
4145
3941
|
while (this._lookahead(0) !== TOK_RBRACKET) {
|
|
@@ -4155,7 +3951,6 @@ class Parser {
|
|
|
4155
3951
|
this._match(TOK_RBRACKET);
|
|
4156
3952
|
return { type: 'MultiSelectList', children: expressions };
|
|
4157
3953
|
}
|
|
4158
|
-
|
|
4159
3954
|
_parseMultiselectHash() {
|
|
4160
3955
|
const pairs = [];
|
|
4161
3956
|
const identifierTypes = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER];
|
|
@@ -4188,20 +3983,6 @@ class Parser {
|
|
|
4188
3983
|
}
|
|
4189
3984
|
}
|
|
4190
3985
|
|
|
4191
|
-
/*
|
|
4192
|
-
Copyright 2021 Adobe. All rights reserved.
|
|
4193
|
-
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4194
|
-
you may not use this file except in compliance with the License. You may obtain a copy
|
|
4195
|
-
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
4196
|
-
|
|
4197
|
-
Unless required by applicable law or agreed to in writing, software distributed under
|
|
4198
|
-
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
4199
|
-
OF ANY KIND, either express or implied. See the License for the specific language
|
|
4200
|
-
governing permissions and limitations under the License.
|
|
4201
|
-
*/
|
|
4202
|
-
|
|
4203
|
-
// get the offset in MS, given a date and timezone
|
|
4204
|
-
// timezone is an IANA name. e.g. 'America/New_York'
|
|
4205
3986
|
function offsetMS(dateObj, timeZone) {
|
|
4206
3987
|
const tzOffset = new Intl.DateTimeFormat('en-US', { timeZone, timeZoneName: 'longOffset' }).format(dateObj);
|
|
4207
3988
|
const offset = /GMT([+\-−])?(\d{1,2}):?(\d{0,2})?/.exec(tzOffset);
|
|
@@ -4210,16 +3991,11 @@ function offsetMS(dateObj, timeZone) {
|
|
|
4210
3991
|
const result = (((hours || 0) * 60) + 1 * (minutes || 0)) * 60 * 1000;
|
|
4211
3992
|
return sign === '-' ? result * -1 : result;
|
|
4212
3993
|
}
|
|
4213
|
-
|
|
4214
3994
|
function round(num, digits) {
|
|
4215
3995
|
const precision = 10 ** digits;
|
|
4216
3996
|
return Math.round(num * precision) / precision;
|
|
4217
3997
|
}
|
|
4218
|
-
|
|
4219
3998
|
const MS_IN_DAY = 24 * 60 * 60 * 1000;
|
|
4220
|
-
|
|
4221
|
-
// If we create a non-UTC date, then we need to adjust from the default JavaScript timezone
|
|
4222
|
-
// to the default timezone
|
|
4223
3999
|
function adjustTimeZone(dateObj, timeZone) {
|
|
4224
4000
|
if (dateObj === null) return null;
|
|
4225
4001
|
let baseDate = Date.UTC(
|
|
@@ -4232,32 +4008,10 @@ function adjustTimeZone(dateObj, timeZone) {
|
|
|
4232
4008
|
dateObj.getMilliseconds(),
|
|
4233
4009
|
);
|
|
4234
4010
|
baseDate += offsetMS(dateObj, timeZone);
|
|
4235
|
-
|
|
4236
|
-
// get the offset for the default JS environment
|
|
4237
|
-
// return days since the epoch
|
|
4238
4011
|
return new Date(baseDate);
|
|
4239
4012
|
}
|
|
4240
|
-
|
|
4241
4013
|
function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
4242
4014
|
return {
|
|
4243
|
-
/**
|
|
4244
|
-
* Returns the logical AND result of all parameters.
|
|
4245
|
-
* If the parameters are not boolean they will be cast to boolean as per the following rules
|
|
4246
|
-
* * null -> false
|
|
4247
|
-
* * number -> false if the number is 0, true otherwise
|
|
4248
|
-
* * string -> false if the string is empty, true otherwise. String "false" resolves to true
|
|
4249
|
-
* * array -> true
|
|
4250
|
-
* * object -> true
|
|
4251
|
-
* @param {any} firstOperand logical expression
|
|
4252
|
-
* @param {...any} [additionalOperands] any number of additional expressions
|
|
4253
|
-
* @returns {boolean} The logical result of applying AND to all parameters
|
|
4254
|
-
* @example
|
|
4255
|
-
* and(10 > 8, length('foo') < 5) // returns true
|
|
4256
|
-
* @example
|
|
4257
|
-
* and(`null`, length('foo') < 5) // returns false
|
|
4258
|
-
* @function
|
|
4259
|
-
* @category openFormula
|
|
4260
|
-
*/
|
|
4261
4015
|
and: {
|
|
4262
4016
|
_func: resolvedArgs => {
|
|
4263
4017
|
let result = !!valueOf(resolvedArgs[0]);
|
|
@@ -4268,17 +4022,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4268
4022
|
},
|
|
4269
4023
|
_signature: [{ types: [dataTypes.TYPE_ANY], variadic: true }],
|
|
4270
4024
|
},
|
|
4271
|
-
|
|
4272
|
-
/**
|
|
4273
|
-
* Returns a lower-case string of the `input` string using locale-specific mappings.
|
|
4274
|
-
* e.g. Strings with German lowercase letter 'ß' can be compared to 'ss'
|
|
4275
|
-
* @param {string} input string to casefold
|
|
4276
|
-
* @returns {string} A new string converted to lower case
|
|
4277
|
-
* @function casefold
|
|
4278
|
-
* @example
|
|
4279
|
-
* casefold('AbC') // returns 'abc'
|
|
4280
|
-
* @category JSONFormula
|
|
4281
|
-
*/
|
|
4282
4025
|
casefold: {
|
|
4283
4026
|
_func: (args, _data, interpreter) => {
|
|
4284
4027
|
const str = toString(args[0]);
|
|
@@ -4288,34 +4031,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4288
4031
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4289
4032
|
],
|
|
4290
4033
|
},
|
|
4291
|
-
|
|
4292
|
-
/**
|
|
4293
|
-
* Return difference between two date values.
|
|
4294
|
-
* @param {number} start_date The starting date.
|
|
4295
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
4296
|
-
* @param {number} end_date The end date -- must be greater or equal to start_date.
|
|
4297
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
4298
|
-
* @param {string} unit One of:
|
|
4299
|
-
* * `y` the number of whole years between start_date and end_date
|
|
4300
|
-
* * `m` the number of whole months between start_date and end_date.
|
|
4301
|
-
* * `d` the number of days between start_date and end_date
|
|
4302
|
-
* * `md` the number of days between start_date and end_date after subtracting whole months.
|
|
4303
|
-
* * `ym` the number of whole months between start_date and end_date
|
|
4304
|
-
* after subtracting whole years.
|
|
4305
|
-
* * `yd` the number of days between start_date and end_date, assuming start_date
|
|
4306
|
-
* and end_date were no more than one year apart
|
|
4307
|
-
* @returns {integer} The number of days/months/years difference
|
|
4308
|
-
* @function
|
|
4309
|
-
* @category openFormula
|
|
4310
|
-
* @example
|
|
4311
|
-
* datedif(datetime(2001, 1, 1), datetime(2003, 1, 1), 'y') // returns 2
|
|
4312
|
-
* @example
|
|
4313
|
-
* datedif(datetime(2001, 6, 1), datetime(2003, 8, 15), 'D') // returns 440
|
|
4314
|
-
* // 440 days between June 1, 2001, and August 15, 2002 (440)
|
|
4315
|
-
* @example
|
|
4316
|
-
* datedif(datetime(2001, 6, 1), datetime(2003, 8, 15), 'YD') // returns 440
|
|
4317
|
-
* // 75 days between June 1 and August 15, ignoring the years of the dates (75)
|
|
4318
|
-
*/
|
|
4319
4034
|
datedif: {
|
|
4320
4035
|
_func: args => {
|
|
4321
4036
|
const d1 = toNumber(args[0]);
|
|
@@ -4329,7 +4044,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4329
4044
|
const yearDiff = date2.getFullYear() - date1.getFullYear();
|
|
4330
4045
|
let monthDiff = date2.getMonth() - date1.getMonth();
|
|
4331
4046
|
const dayDiff = date2.getDate() - date1.getDate();
|
|
4332
|
-
|
|
4333
4047
|
if (unit === 'y') {
|
|
4334
4048
|
let y = yearDiff;
|
|
4335
4049
|
if (monthDiff < 0) y -= 1;
|
|
@@ -4358,32 +4072,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4358
4072
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4359
4073
|
],
|
|
4360
4074
|
},
|
|
4361
|
-
|
|
4362
|
-
/**
|
|
4363
|
-
* Return a date/time value.
|
|
4364
|
-
* @param {integer} year Integer value representing the year.
|
|
4365
|
-
* Values from 0 to 99 map to the years 1900 to 1999. All other values are the actual year
|
|
4366
|
-
* @param {integer} month Integer value representing the month, beginning with 1 for
|
|
4367
|
-
* January to 12 for December.
|
|
4368
|
-
* @param {integer} day Integer value representing the day of the month.
|
|
4369
|
-
* @param {integer} [hours] Integer value between 0 and 23 representing the hour of the day.
|
|
4370
|
-
* Defaults to 0.
|
|
4371
|
-
* @param {integer} [minutes] Integer value representing the minute segment of a time.
|
|
4372
|
-
* The default is 0 minutes past the hour.
|
|
4373
|
-
* @param {integer} [seconds] Integer value representing the second segment of a time.
|
|
4374
|
-
* The default is 0 seconds past the minute.
|
|
4375
|
-
* @param {integer} [milliseconds] Integer value representing the millisecond segment of a time.
|
|
4376
|
-
* The default is 0 milliseconds past the second.
|
|
4377
|
-
* @param {string} [timeZoneName] according to IANA time zone names. e.g. "America/Toronto"
|
|
4378
|
-
* @returns {number} A date/time value represented by number of seconds since 1 January 1970.
|
|
4379
|
-
* @kind function
|
|
4380
|
-
* @function
|
|
4381
|
-
* @category JSONFormula
|
|
4382
|
-
* @example
|
|
4383
|
-
* datetime(2010, 10, 10) // returns representation of October 10, 2010
|
|
4384
|
-
* @example
|
|
4385
|
-
* datetime(2010, 2, 28) // returns representation of February 28, 2010
|
|
4386
|
-
*/
|
|
4387
4075
|
datetime: {
|
|
4388
4076
|
_func: args => {
|
|
4389
4077
|
const year = toNumber(args[0]);
|
|
@@ -4394,7 +4082,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4394
4082
|
const seconds = args.length > 5 ? toNumber(args[5]) : 0;
|
|
4395
4083
|
const ms = args.length > 6 ? toNumber(args[6]) : 0;
|
|
4396
4084
|
const tz = args.length > 7 ? toString(args[7]) : null;
|
|
4397
|
-
// javascript months starts from 0
|
|
4398
4085
|
let jsDate = new Date(year, month - 1, day, hours, minutes, seconds, ms);
|
|
4399
4086
|
if (tz) {
|
|
4400
4087
|
jsDate = adjustTimeZone(jsDate, tz);
|
|
@@ -4412,18 +4099,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4412
4099
|
{ types: [dataTypes.TYPE_STRING], optional: true },
|
|
4413
4100
|
],
|
|
4414
4101
|
},
|
|
4415
|
-
|
|
4416
|
-
/**
|
|
4417
|
-
* Returns the day of a date, represented by a serial number.
|
|
4418
|
-
* The day is given as an integer ranging from 1 to 31.
|
|
4419
|
-
* @param {number} The date of the day you are trying to find.
|
|
4420
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
4421
|
-
* @return {number}
|
|
4422
|
-
* @function day
|
|
4423
|
-
* @category openFormula
|
|
4424
|
-
* @example
|
|
4425
|
-
* day(datetime(2008,5,23)) //returns 23
|
|
4426
|
-
*/
|
|
4427
4102
|
day: {
|
|
4428
4103
|
_func: args => {
|
|
4429
4104
|
const date = toNumber(args[0]);
|
|
@@ -4434,19 +4109,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4434
4109
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4435
4110
|
],
|
|
4436
4111
|
},
|
|
4437
|
-
|
|
4438
|
-
/**
|
|
4439
|
-
* Searches a nested hierarchy of objects to return an array of elements that match a `name`.
|
|
4440
|
-
* The name can be either a key into a map or an array index.
|
|
4441
|
-
* This is similar to the JSONPath deep scan operator (..)
|
|
4442
|
-
* @param {object} object The starting object or array where we start the search
|
|
4443
|
-
* @param {string} name The name (or index position) of the elements to find
|
|
4444
|
-
* @returns {any}
|
|
4445
|
-
* @function
|
|
4446
|
-
* @category JSONFormula
|
|
4447
|
-
* @example
|
|
4448
|
-
* deepScan({a : {b1 : {c : 2}, b2 : {c : 3}}}, 'c') //returns [2, 3]
|
|
4449
|
-
*/
|
|
4450
4112
|
deepScan: {
|
|
4451
4113
|
_func: resolvedArgs => {
|
|
4452
4114
|
const [source, n] = resolvedArgs;
|
|
@@ -4467,16 +4129,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4467
4129
|
{ types: [dataTypes.TYPE_STRING, dataTypes.TYPE_NUMBER] },
|
|
4468
4130
|
],
|
|
4469
4131
|
},
|
|
4470
|
-
|
|
4471
|
-
/**
|
|
4472
|
-
* returns an array of a given object's property `[key, value]` pairs.
|
|
4473
|
-
* @param {object} obj Object whose `[key, value]` pairs need to be extracted
|
|
4474
|
-
* @returns {any[]} an array of [key, value] pairs
|
|
4475
|
-
* @function entries
|
|
4476
|
-
* @category JSONFormula
|
|
4477
|
-
* @example
|
|
4478
|
-
* entries({a: 1, b: 2}) //returns [['a', 1], ['b', 2]]
|
|
4479
|
-
*/
|
|
4480
4132
|
entries: {
|
|
4481
4133
|
_func: args => {
|
|
4482
4134
|
const obj = valueOf(args[0]);
|
|
@@ -4494,27 +4146,11 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4494
4146
|
},
|
|
4495
4147
|
],
|
|
4496
4148
|
},
|
|
4497
|
-
|
|
4498
|
-
/**
|
|
4499
|
-
* Returns the serial number of the end of a month, given `startDate` plus `monthAdd` months
|
|
4500
|
-
* @param {number} startDate The base date to start from.
|
|
4501
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
4502
|
-
* @param {integer} monthAdd Number of months to add to start date
|
|
4503
|
-
* @return {integer} the number of days in the computed month
|
|
4504
|
-
* @function
|
|
4505
|
-
* @category openFormula
|
|
4506
|
-
* @example
|
|
4507
|
-
* eomonth(datetime(2011, 1, 1), 1) //returns datetime(2011, 2, 28)
|
|
4508
|
-
* @example
|
|
4509
|
-
* eomonth(datetime(2011, 1, 1), -3) //returns datetime(2010, 10, 31)
|
|
4510
|
-
*/
|
|
4511
4149
|
eomonth: {
|
|
4512
4150
|
_func: args => {
|
|
4513
4151
|
const date = toNumber(args[0]);
|
|
4514
4152
|
const months = toNumber(args[1]);
|
|
4515
4153
|
const jsDate = new Date(date * MS_IN_DAY);
|
|
4516
|
-
// We can give the constructor a month value > 11 and it will increment the years
|
|
4517
|
-
// Since day is 1-based, giving zero will yield the last day of the previous month
|
|
4518
4154
|
const newDate = new Date(jsDate.getFullYear(), jsDate.getMonth() + months + 1, 0);
|
|
4519
4155
|
return newDate.getTime() / MS_IN_DAY;
|
|
4520
4156
|
},
|
|
@@ -4523,16 +4159,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4523
4159
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4524
4160
|
],
|
|
4525
4161
|
},
|
|
4526
|
-
|
|
4527
|
-
/**
|
|
4528
|
-
* Returns e (the base of natural logarithms) raised to a power x. (i.e. e<sup>x</sup>)
|
|
4529
|
-
* @param x {number} A numeric expression representing the power of e.
|
|
4530
|
-
* @returns {number} e (the base of natural logarithms) raised to a power x
|
|
4531
|
-
* @function exp
|
|
4532
|
-
* @category openFormula
|
|
4533
|
-
* @example
|
|
4534
|
-
* exp(10) //returns e^10
|
|
4535
|
-
*/
|
|
4536
4162
|
exp: {
|
|
4537
4163
|
_func: args => {
|
|
4538
4164
|
const value = toNumber(args[0]);
|
|
@@ -4542,37 +4168,10 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4542
4168
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4543
4169
|
],
|
|
4544
4170
|
},
|
|
4545
|
-
|
|
4546
|
-
/**
|
|
4547
|
-
* Return constant boolean false value.
|
|
4548
|
-
* Note that expressions may also use the JSON literal false: `` `false` ``
|
|
4549
|
-
* @returns {boolean} constant boolean value `false`
|
|
4550
|
-
* @function
|
|
4551
|
-
* @category openFormula
|
|
4552
|
-
*/
|
|
4553
4171
|
false: {
|
|
4554
4172
|
_func: () => false,
|
|
4555
4173
|
_signature: [],
|
|
4556
4174
|
},
|
|
4557
|
-
|
|
4558
|
-
/**
|
|
4559
|
-
* finds and returns the index of query in text from a start position
|
|
4560
|
-
* @param {string} query string to search
|
|
4561
|
-
* @param {string} text text in which the query has to be searched
|
|
4562
|
-
* @param {number} [start] starting position: defaults to 0
|
|
4563
|
-
* @returns {number|null} the index of the query to be searched in the text. If not found
|
|
4564
|
-
* returns null
|
|
4565
|
-
* @function
|
|
4566
|
-
* @category openFormula
|
|
4567
|
-
* @example
|
|
4568
|
-
* find('m', 'abm') //returns 2
|
|
4569
|
-
* @example
|
|
4570
|
-
* find('M', 'abMcdM', 3) //returns 2
|
|
4571
|
-
* @example
|
|
4572
|
-
* find('M', 'ab') //returns `null`
|
|
4573
|
-
* @example
|
|
4574
|
-
* find('M', 'abMcdM', 2) //returns 2
|
|
4575
|
-
*/
|
|
4576
4175
|
find: {
|
|
4577
4176
|
_func: args => {
|
|
4578
4177
|
const query = toString(args[0]);
|
|
@@ -4590,16 +4189,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4590
4189
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
4591
4190
|
],
|
|
4592
4191
|
},
|
|
4593
|
-
|
|
4594
|
-
/**
|
|
4595
|
-
* returns an object by transforming a list of key-value `pairs` into an object.
|
|
4596
|
-
* @param {any[]} pairs list of key-value pairs to create the object from
|
|
4597
|
-
* @returns {object}
|
|
4598
|
-
* @category JSONFormula
|
|
4599
|
-
* @function fromEntries
|
|
4600
|
-
* @example
|
|
4601
|
-
* fromEntries([['a', 1], ['b', 2]]) //returns {a: 1, b: 2}
|
|
4602
|
-
*/
|
|
4603
4192
|
fromEntries: {
|
|
4604
4193
|
_func: args => {
|
|
4605
4194
|
const array = args[0];
|
|
@@ -4609,51 +4198,19 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4609
4198
|
{ types: [dataTypes.TYPE_ARRAY_ARRAY] },
|
|
4610
4199
|
],
|
|
4611
4200
|
},
|
|
4612
|
-
|
|
4613
|
-
/**
|
|
4614
|
-
* Extract the hour (0 through 23) from a time/datetime representation
|
|
4615
|
-
* @param {number} The datetime/time for which the hour is to be returned.
|
|
4616
|
-
* Dates should be specified using the [datetime]{@link datetime} or [time]{@link time} function
|
|
4617
|
-
* @return {number}
|
|
4618
|
-
* @function hour
|
|
4619
|
-
* @category openFormula
|
|
4620
|
-
* @example
|
|
4621
|
-
* hour(datetime(2008,5,23,12, 0, 0)) //returns 12
|
|
4622
|
-
* hour(time(12, 0, 0)) //returns 12
|
|
4623
|
-
*/
|
|
4624
4201
|
hour: {
|
|
4625
4202
|
_func: args => {
|
|
4626
|
-
// grab just the fraction part
|
|
4627
4203
|
const time = toNumber(args[0]) % 1;
|
|
4628
4204
|
if (time < 0) {
|
|
4629
4205
|
return null;
|
|
4630
4206
|
}
|
|
4631
|
-
// Normally we'd round to 15 digits, but since we're also multiplying by 24,
|
|
4632
|
-
// a reasonable precision is around 14 digits.
|
|
4633
|
-
|
|
4634
4207
|
const hour = round(time * 24, 14);
|
|
4635
|
-
|
|
4636
4208
|
return Math.floor(hour % 24);
|
|
4637
4209
|
},
|
|
4638
4210
|
_signature: [
|
|
4639
4211
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4640
4212
|
],
|
|
4641
4213
|
},
|
|
4642
|
-
|
|
4643
|
-
/**
|
|
4644
|
-
* Return one of two values `result1` or `result2`, depending on the `condition`
|
|
4645
|
-
* @returns {boolean} True
|
|
4646
|
-
* @param {any} condition logical expression to evaluate
|
|
4647
|
-
* @param {any} result1 if logical condition is true
|
|
4648
|
-
* @param {any} result2 if logical condition is false
|
|
4649
|
-
* @return {any} either result1 or result2
|
|
4650
|
-
* @function
|
|
4651
|
-
* @category openFormula
|
|
4652
|
-
* @example
|
|
4653
|
-
* if(true(), 1, 2) // returns 1
|
|
4654
|
-
* @example
|
|
4655
|
-
* if(false(), 1, 2) // returns 2
|
|
4656
|
-
*/
|
|
4657
4214
|
if: {
|
|
4658
4215
|
_func: (unresolvedArgs, data, interpreter) => {
|
|
4659
4216
|
const conditionNode = unresolvedArgs[0];
|
|
@@ -4670,22 +4227,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4670
4227
|
{ types: [dataTypes.TYPE_ANY] },
|
|
4671
4228
|
{ types: [dataTypes.TYPE_ANY] }],
|
|
4672
4229
|
},
|
|
4673
|
-
|
|
4674
|
-
/**
|
|
4675
|
-
* Return a selected number of text characters from the left or
|
|
4676
|
-
* in case of array selected number of elements from the start
|
|
4677
|
-
* @param {string|array} subject The text/array of characters/elements to extract.
|
|
4678
|
-
* @param {number} [elements] number of elements to pick. Defaults to 1
|
|
4679
|
-
* @return {string|array}
|
|
4680
|
-
* @function left
|
|
4681
|
-
* @category openFormula
|
|
4682
|
-
* @example
|
|
4683
|
-
* left('Sale Price', 4) //returns 'Sale'
|
|
4684
|
-
* @example
|
|
4685
|
-
* left('Sweden') // returns 'S'
|
|
4686
|
-
* @example
|
|
4687
|
-
* left([4, 5, 6], 2) // returns [4, 5]
|
|
4688
|
-
*/
|
|
4689
4230
|
left: {
|
|
4690
4231
|
_func: args => {
|
|
4691
4232
|
const numEntries = args.length > 1 ? toNumber(args[1]) : 1;
|
|
@@ -4701,18 +4242,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4701
4242
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
4702
4243
|
],
|
|
4703
4244
|
},
|
|
4704
|
-
|
|
4705
|
-
/**
|
|
4706
|
-
* Converts all the alphabetic characters in a string to lowercase. If the value
|
|
4707
|
-
* is not a string it will be converted into string
|
|
4708
|
-
* using the default toString method
|
|
4709
|
-
* @param {string} input input string
|
|
4710
|
-
* @returns {string} the lower case value of the input string
|
|
4711
|
-
* @function lower
|
|
4712
|
-
* @category openFormula
|
|
4713
|
-
* @example
|
|
4714
|
-
* lower('E. E. Cummings') //returns e. e. cummings
|
|
4715
|
-
*/
|
|
4716
4245
|
lower: {
|
|
4717
4246
|
_func: args => {
|
|
4718
4247
|
const value = toString(args[0]);
|
|
@@ -4722,27 +4251,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4722
4251
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4723
4252
|
],
|
|
4724
4253
|
},
|
|
4725
|
-
|
|
4726
|
-
/**
|
|
4727
|
-
* Returns extracted text, given an original text, starting position, and length.
|
|
4728
|
-
* or in case of array, extracts a subset of the array from start till the length
|
|
4729
|
-
* number of elements.
|
|
4730
|
-
* Returns null if the `startPos` is greater than the length of the array
|
|
4731
|
-
* @param {string|array} subject the text string or array of characters or elements to extract.
|
|
4732
|
-
* @param {number} startPos the position of the first character or element to extract.
|
|
4733
|
-
* The position starts with 0
|
|
4734
|
-
* @param {number} length The number of characters or elements to return from text. If it
|
|
4735
|
-
* is greater then the length of `subject` the argument is set to the length of the subject.
|
|
4736
|
-
* @return {string|array}
|
|
4737
|
-
* @function mid
|
|
4738
|
-
* @category openFormula
|
|
4739
|
-
* @example
|
|
4740
|
-
* mid("Fluid Flow",1,5) //returns 'Fluid'
|
|
4741
|
-
* @example
|
|
4742
|
-
* mid("Fluid Flow",7,20) //returns 'Flow'
|
|
4743
|
-
* @example
|
|
4744
|
-
* mid("Fluid Flow",20,5) //returns `null`
|
|
4745
|
-
*/
|
|
4746
4254
|
mid: {
|
|
4747
4255
|
_func: args => {
|
|
4748
4256
|
const startPos = toNumber(args[1]);
|
|
@@ -4760,27 +4268,12 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4760
4268
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4761
4269
|
],
|
|
4762
4270
|
},
|
|
4763
|
-
|
|
4764
|
-
/**
|
|
4765
|
-
* Extract the minute (0 through 59) from a time/datetime representation
|
|
4766
|
-
* @param {number} The datetime/time for which the minute is to be returned.
|
|
4767
|
-
* Dates should be specified using the [datetime]{@link datetime} or [time]{@link time} function
|
|
4768
|
-
* @return {number}
|
|
4769
|
-
* @function minute
|
|
4770
|
-
* @category openFormula
|
|
4771
|
-
* @example
|
|
4772
|
-
* month(datetime(2008,5,23,12, 10, 0)) //returns 10
|
|
4773
|
-
* month(time(12, 10, 0)) //returns 10
|
|
4774
|
-
*/
|
|
4775
4271
|
minute: {
|
|
4776
4272
|
_func: args => {
|
|
4777
4273
|
const time = toNumber(args[0]) % 1;
|
|
4778
4274
|
if (time < 0) {
|
|
4779
4275
|
return null;
|
|
4780
4276
|
}
|
|
4781
|
-
|
|
4782
|
-
// Normally we'd round to 15 digits, but since we're also multiplying by 1440,
|
|
4783
|
-
// a reasonable precision is around 10 digits.
|
|
4784
4277
|
const minute = Math.round(time * 1440, 10);
|
|
4785
4278
|
return Math.floor(minute % 60);
|
|
4786
4279
|
},
|
|
@@ -4788,20 +4281,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4788
4281
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4789
4282
|
],
|
|
4790
4283
|
},
|
|
4791
|
-
|
|
4792
|
-
/**
|
|
4793
|
-
* Return the remainder when one number is divided by another number.
|
|
4794
|
-
* The sign is the same as divisor
|
|
4795
|
-
* @param {number} dividend The number for which to find the remainder.
|
|
4796
|
-
* @param {number} divisor The number by which to divide number.
|
|
4797
|
-
* @return {number} Computes the remainder of `dividend`/`divisor`.
|
|
4798
|
-
* @function mod
|
|
4799
|
-
* @category openFormula
|
|
4800
|
-
* @example
|
|
4801
|
-
* mod(3, 2) //returns 1
|
|
4802
|
-
* @example
|
|
4803
|
-
* mod(-3, 2) //returns 1
|
|
4804
|
-
*/
|
|
4805
4284
|
mod: {
|
|
4806
4285
|
_func: args => {
|
|
4807
4286
|
const p1 = toNumber(args[0]);
|
|
@@ -4813,97 +4292,28 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4813
4292
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4814
4293
|
],
|
|
4815
4294
|
},
|
|
4816
|
-
|
|
4817
|
-
/**
|
|
4818
|
-
* Returns the month of a date represented by a serial number.
|
|
4819
|
-
* The month is given as an integer, ranging from 1 (January) to 12 (December).
|
|
4820
|
-
* @param {number} The date for which the month is to be returned.
|
|
4821
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
4822
|
-
* @return {number}
|
|
4823
|
-
* @function month
|
|
4824
|
-
* @category openFormula
|
|
4825
|
-
* @example
|
|
4826
|
-
* month(datetime(2008,5,23)) //returns 5
|
|
4827
|
-
*/
|
|
4828
4295
|
month: {
|
|
4829
4296
|
_func: args => {
|
|
4830
4297
|
const date = toNumber(args[0]);
|
|
4831
4298
|
const jsDate = new Date(date * MS_IN_DAY);
|
|
4832
|
-
// javascript months start from 0ß
|
|
4833
4299
|
return jsDate.getMonth() + 1;
|
|
4834
4300
|
},
|
|
4835
4301
|
_signature: [
|
|
4836
4302
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4837
4303
|
],
|
|
4838
4304
|
},
|
|
4839
|
-
|
|
4840
|
-
/**
|
|
4841
|
-
* Compute logical NOT of a `value`. If the parameter is not boolean it will be cast to boolean
|
|
4842
|
-
* as per the following rules
|
|
4843
|
-
* * null -> false
|
|
4844
|
-
* * number -> false if the number is 0, true otherwise
|
|
4845
|
-
* * string -> false if the string is empty, true otherwise. String "false" resolves to true
|
|
4846
|
-
* * array -> true
|
|
4847
|
-
* * object -> true
|
|
4848
|
-
* Note that it is also possible to use the logical and operator: `A && B`
|
|
4849
|
-
* @param {any} value - any data type
|
|
4850
|
-
* @returns {boolean} The logical NOT applied to the input parameter
|
|
4851
|
-
* @example
|
|
4852
|
-
* not(length('bar') > 0) // returns false
|
|
4853
|
-
* @example
|
|
4854
|
-
* not(false()) // returns true
|
|
4855
|
-
* @example
|
|
4856
|
-
* not('abcd') // returns false
|
|
4857
|
-
* @example
|
|
4858
|
-
* not('') // returns true
|
|
4859
|
-
* @function
|
|
4860
|
-
* @category openFormula
|
|
4861
|
-
*/
|
|
4862
4305
|
not: {
|
|
4863
4306
|
_func: resolveArgs => !valueOf(resolveArgs[0]),
|
|
4864
4307
|
_signature: [{ types: [dataTypes.TYPE_ANY] }],
|
|
4865
4308
|
},
|
|
4866
|
-
|
|
4867
|
-
/**
|
|
4868
|
-
* returns the time since epoch with days as exponent and time of day as fraction
|
|
4869
|
-
* @return {number} representation of current time as a number
|
|
4870
|
-
* @function now
|
|
4871
|
-
* @category openFormula
|
|
4872
|
-
*/
|
|
4873
4309
|
now: {
|
|
4874
4310
|
_func: () => Date.now() / MS_IN_DAY,
|
|
4875
4311
|
_signature: [],
|
|
4876
4312
|
},
|
|
4877
|
-
|
|
4878
|
-
/**
|
|
4879
|
-
* Return constant null value.
|
|
4880
|
-
* Note that expressions may also use the JSON literal null: `` `null` ``
|
|
4881
|
-
* @returns {boolean} True
|
|
4882
|
-
* @function
|
|
4883
|
-
* @category JSONFormula
|
|
4884
|
-
*/
|
|
4885
4313
|
null: {
|
|
4886
4314
|
_func: () => null,
|
|
4887
4315
|
_signature: [],
|
|
4888
4316
|
},
|
|
4889
|
-
|
|
4890
|
-
/**
|
|
4891
|
-
* Returns the logical OR result of two parameters.
|
|
4892
|
-
* If the parameters are not boolean they will be cast to boolean as per the following rules
|
|
4893
|
-
* * null -> false
|
|
4894
|
-
* * number -> false if the number is 0, true otherwise
|
|
4895
|
-
* * string -> false if the string is empty, true otherwise. String "false" resolves to true
|
|
4896
|
-
* * array -> true
|
|
4897
|
-
* * object -> true
|
|
4898
|
-
* @param {any} first logical expression
|
|
4899
|
-
* @param {...any} [operand] any number of additional expressions
|
|
4900
|
-
* @returns {boolean} The logical result of applying OR to all parameters
|
|
4901
|
-
* @example
|
|
4902
|
-
* or((x / 2) == y, (y * 2) == x)
|
|
4903
|
-
* // true
|
|
4904
|
-
* @function
|
|
4905
|
-
* @category openFormula
|
|
4906
|
-
*/
|
|
4907
4317
|
or: {
|
|
4908
4318
|
_func: resolvedArgs => {
|
|
4909
4319
|
let result = !!valueOf(resolvedArgs[0]);
|
|
@@ -4914,17 +4324,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4914
4324
|
},
|
|
4915
4325
|
_signature: [{ types: [dataTypes.TYPE_ANY], variadic: true }],
|
|
4916
4326
|
},
|
|
4917
|
-
|
|
4918
|
-
/**
|
|
4919
|
-
* Computes `a` raised to a power `x`. (a<sup>x</sup>)
|
|
4920
|
-
* @param {number} a The base number. It can be any real number.
|
|
4921
|
-
* @param {number} x The exponent to which the base number is raised.
|
|
4922
|
-
* @return {number}
|
|
4923
|
-
* @function power
|
|
4924
|
-
* @category openFormula
|
|
4925
|
-
* @example
|
|
4926
|
-
* power(10, 2) //returns 100 (10 raised to power 2)
|
|
4927
|
-
*/
|
|
4928
4327
|
power: {
|
|
4929
4328
|
_func: args => {
|
|
4930
4329
|
const base = toNumber(args[0]);
|
|
@@ -4936,21 +4335,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4936
4335
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4937
4336
|
],
|
|
4938
4337
|
},
|
|
4939
|
-
|
|
4940
|
-
/**
|
|
4941
|
-
* Return the input string with the first letter of each word converted to an
|
|
4942
|
-
* uppercase letter and the rest of the letters in the word converted to lowercase.
|
|
4943
|
-
* @param {string} text the text to partially capitalize.
|
|
4944
|
-
* @returns {string}
|
|
4945
|
-
* @function proper
|
|
4946
|
-
* @category openFormula
|
|
4947
|
-
* @example
|
|
4948
|
-
* proper('this is a TITLE') //returns 'This Is A Title'
|
|
4949
|
-
* @example
|
|
4950
|
-
* proper('2-way street') //returns '2-Way Street'
|
|
4951
|
-
* @example
|
|
4952
|
-
* proper('76BudGet') //returns '76Budget'
|
|
4953
|
-
*/
|
|
4954
4338
|
proper: {
|
|
4955
4339
|
_func: args => {
|
|
4956
4340
|
const text = toString(args[0]);
|
|
@@ -4963,24 +4347,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4963
4347
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4964
4348
|
],
|
|
4965
4349
|
},
|
|
4966
|
-
|
|
4967
|
-
/**
|
|
4968
|
-
* Returns text where an old text is substituted at a given start position and
|
|
4969
|
-
* length, with a new text.
|
|
4970
|
-
* @param {string} text original text
|
|
4971
|
-
* @param {number} start index in the original text from where to begin the replacement.
|
|
4972
|
-
* @param {number} length number of characters to be replaced
|
|
4973
|
-
* @param {string} replacement string to replace at the start index
|
|
4974
|
-
* @returns {string}
|
|
4975
|
-
* @function replace
|
|
4976
|
-
* @category openFormula
|
|
4977
|
-
* @example
|
|
4978
|
-
* replace('abcdefghijk', 6, 5, '*') //returns abcde*k
|
|
4979
|
-
* @example
|
|
4980
|
-
* replace('2009',3,2,'10') //returns 2010
|
|
4981
|
-
* @example
|
|
4982
|
-
* replace('123456',1,3,'@') //returns @456
|
|
4983
|
-
*/
|
|
4984
4350
|
replace: {
|
|
4985
4351
|
_func: args => {
|
|
4986
4352
|
const oldText = toString(args[0]);
|
|
@@ -4990,7 +4356,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4990
4356
|
if (startNum < 0) {
|
|
4991
4357
|
return null;
|
|
4992
4358
|
}
|
|
4993
|
-
|
|
4994
4359
|
const lhs = oldText.substr(0, startNum);
|
|
4995
4360
|
const rhs = oldText.substr(startNum + numChars);
|
|
4996
4361
|
return lhs + newText + rhs;
|
|
@@ -5002,17 +4367,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5002
4367
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5003
4368
|
],
|
|
5004
4369
|
},
|
|
5005
|
-
|
|
5006
|
-
/**
|
|
5007
|
-
* Return text repeated Count times.
|
|
5008
|
-
* @param {string} text text to repeat
|
|
5009
|
-
* @param {number} count number of times to repeat the text
|
|
5010
|
-
* @returns {string}
|
|
5011
|
-
* @function rept
|
|
5012
|
-
* @category openFormula
|
|
5013
|
-
* @example
|
|
5014
|
-
* rept('x', 5) //returns 'xxxxx'
|
|
5015
|
-
*/
|
|
5016
4370
|
rept: {
|
|
5017
4371
|
_func: args => {
|
|
5018
4372
|
const text = toString(args[0]);
|
|
@@ -5027,23 +4381,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5027
4381
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5028
4382
|
],
|
|
5029
4383
|
},
|
|
5030
|
-
|
|
5031
|
-
/**
|
|
5032
|
-
* Return a selected number of text characters from the right of a `subject` or
|
|
5033
|
-
* in case of array selected number of elements from the end of `subject` array
|
|
5034
|
-
* Returns null if the number of elements is less than 0
|
|
5035
|
-
* @param {string|array} subject The text/array containing the characters/elements to extract.
|
|
5036
|
-
* @param {number} [elements] number of elements to pick. Defaults to 1
|
|
5037
|
-
* @return {string|array}
|
|
5038
|
-
* @function right
|
|
5039
|
-
* @category openFormula
|
|
5040
|
-
* @example
|
|
5041
|
-
* right('Sale Price', 4) //returns 'rice'
|
|
5042
|
-
* @example
|
|
5043
|
-
* left('Sweden') // returns 'n'
|
|
5044
|
-
* @example
|
|
5045
|
-
* left([4, 5, 6], 2) // returns [5, 6]
|
|
5046
|
-
*/
|
|
5047
4384
|
right: {
|
|
5048
4385
|
_func: args => {
|
|
5049
4386
|
const numEntries = args.length > 1 ? toNumber(args[1]) : 1;
|
|
@@ -5061,29 +4398,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5061
4398
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5062
4399
|
],
|
|
5063
4400
|
},
|
|
5064
|
-
|
|
5065
|
-
/**
|
|
5066
|
-
* Round a number to a specified `precision`.
|
|
5067
|
-
* ### Remarks
|
|
5068
|
-
* * If `precision` is greater than zero, round to the specified number of decimal places.
|
|
5069
|
-
* * If `precision` is 0, round to the nearest integer.
|
|
5070
|
-
* * If `precision` is less than 0, round to the left of the decimal point.
|
|
5071
|
-
* @param {number} num number to round off
|
|
5072
|
-
* @param {number} precision number is rounded to the specified precision.
|
|
5073
|
-
* @returns {number}
|
|
5074
|
-
* @function round
|
|
5075
|
-
* @category openFormula
|
|
5076
|
-
* @example
|
|
5077
|
-
* round(2.15, 1) //returns 2.2
|
|
5078
|
-
* @example
|
|
5079
|
-
* round(626.3,-3) //returns 1000 (Rounds 626.3 to the nearest multiple of 1000)
|
|
5080
|
-
* @example
|
|
5081
|
-
* round(626.3, 0) //returns 626
|
|
5082
|
-
* @example
|
|
5083
|
-
* round(1.98,-1) //returns 0 (Rounds 1.98 to the nearest multiple of 10)
|
|
5084
|
-
* @example
|
|
5085
|
-
* round(-50.55,-2) // -100 (round -50.55 to the nearest multiple of 100)
|
|
5086
|
-
*/
|
|
5087
4401
|
round: {
|
|
5088
4402
|
_func: args => {
|
|
5089
4403
|
const number = toNumber(args[0]);
|
|
@@ -5095,38 +4409,15 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5095
4409
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5096
4410
|
],
|
|
5097
4411
|
},
|
|
5098
|
-
|
|
5099
|
-
/**
|
|
5100
|
-
* Perform a wildcard search. The search is case-sensitive and supports two forms of wildcards:
|
|
5101
|
-
* "*" finds a a sequence of characters and "?" finds a single character.
|
|
5102
|
-
* To use "*" or "?" as text values, precede them with a tilde ("~") character.
|
|
5103
|
-
* Note that the wildcard search is not greedy.
|
|
5104
|
-
* e.g. search('a*b', 'abb') will return [0, 'ab'] Not [0, 'abb']
|
|
5105
|
-
* @param {string} findText the search string -- which may include wild cards.
|
|
5106
|
-
* @param {string} withinText The string to search.
|
|
5107
|
-
* @param {integer} startPos The zero-based position of withinText to start searching.
|
|
5108
|
-
* Defaults to zero.
|
|
5109
|
-
* @returns {array} returns an array with two values:
|
|
5110
|
-
* The start position of the found text and the text string that was found.
|
|
5111
|
-
* If a match was not found, an empty array is returned.
|
|
5112
|
-
* @function search
|
|
5113
|
-
* @category openFormula
|
|
5114
|
-
* @example
|
|
5115
|
-
* search('a?c', 'acabc') //returns [2, 'abc']
|
|
5116
|
-
*/
|
|
5117
4412
|
search: {
|
|
5118
4413
|
_func: args => {
|
|
5119
4414
|
const findText = toString(args[0]);
|
|
5120
4415
|
const withinText = toString(args[1]);
|
|
5121
4416
|
const startPos = toNumber(args[2]);
|
|
5122
4417
|
if (findText === null || withinText === null || withinText.length === 0) return [];
|
|
5123
|
-
// escape all characters that would otherwise create a regular expression
|
|
5124
4418
|
const reString = findText.replace(/([[.\\^$()+{])/g, '\\$1')
|
|
5125
|
-
// add the single character wildcard
|
|
5126
4419
|
.replace(/~?\?/g, match => match === '~?' ? '\\?' : '.')
|
|
5127
|
-
// add the multi-character wildcard
|
|
5128
4420
|
.replace(/~?\*/g, match => match === '~*' ? '\\*' : '.*?')
|
|
5129
|
-
// get rid of the escape characters
|
|
5130
4421
|
.replace(/~~/g, '~');
|
|
5131
4422
|
const re = new RegExp(reString);
|
|
5132
4423
|
const result = withinText.substring(startPos).match(re);
|
|
@@ -5138,28 +4429,13 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5138
4429
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5139
4430
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5140
4431
|
],
|
|
5141
|
-
|
|
5142
4432
|
},
|
|
5143
|
-
/**
|
|
5144
|
-
* Extract the second (0 through 59) from a time/datetime representation
|
|
5145
|
-
* @param {number} The datetime/time for which the second is to be returned.
|
|
5146
|
-
* Dates should be specified using the [datetime]{@link datetime} or [time]{@link time} function
|
|
5147
|
-
* @return {number}
|
|
5148
|
-
* @function second
|
|
5149
|
-
* @category openFormula
|
|
5150
|
-
* @example
|
|
5151
|
-
* second(datetime(2008,5,23,12, 10, 53)) //returns 53
|
|
5152
|
-
* second(time(12, 10, 53)) //returns 53
|
|
5153
|
-
*/
|
|
5154
4433
|
second: {
|
|
5155
4434
|
_func: args => {
|
|
5156
4435
|
const time = toNumber(args[0]) % 1;
|
|
5157
4436
|
if (time < 0) {
|
|
5158
4437
|
return null;
|
|
5159
4438
|
}
|
|
5160
|
-
|
|
5161
|
-
// Normally we'd round to 15 digits, but since we're also multiplying by 86400,
|
|
5162
|
-
// a reasonable precision is around 10 digits.
|
|
5163
4439
|
const seconds = round(time * 86400, 10);
|
|
5164
4440
|
return Math.floor(seconds % 60);
|
|
5165
4441
|
},
|
|
@@ -5167,19 +4443,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5167
4443
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5168
4444
|
],
|
|
5169
4445
|
},
|
|
5170
|
-
|
|
5171
|
-
/**
|
|
5172
|
-
* split a string into an array, given a separator
|
|
5173
|
-
* @param {string} string string to split
|
|
5174
|
-
* @param {string} separator separator where the split should occur
|
|
5175
|
-
* @return {string[]}
|
|
5176
|
-
* @function split
|
|
5177
|
-
* @category openFormula
|
|
5178
|
-
* @example
|
|
5179
|
-
* split('abcdef', '') //returns ['a', 'b', 'c', 'd', 'e', 'f']
|
|
5180
|
-
* @example
|
|
5181
|
-
* split('abcdef', 'e') //returns ['abcd', 'f']
|
|
5182
|
-
*/
|
|
5183
4446
|
split: {
|
|
5184
4447
|
_func: args => {
|
|
5185
4448
|
const str = toString(args[0]);
|
|
@@ -5191,16 +4454,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5191
4454
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5192
4455
|
],
|
|
5193
4456
|
},
|
|
5194
|
-
|
|
5195
|
-
/**
|
|
5196
|
-
* Return the square root of a number
|
|
5197
|
-
* @param {number} num number whose square root has to be calculated
|
|
5198
|
-
* @return {number}
|
|
5199
|
-
* @function sqrt
|
|
5200
|
-
* @category openFormula
|
|
5201
|
-
* @example
|
|
5202
|
-
* sqrt(4) //returns 2
|
|
5203
|
-
*/
|
|
5204
4457
|
sqrt: {
|
|
5205
4458
|
_func: args => {
|
|
5206
4459
|
const result = Math.sqrt(toNumber(args[0]));
|
|
@@ -5213,20 +4466,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5213
4466
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5214
4467
|
],
|
|
5215
4468
|
},
|
|
5216
|
-
|
|
5217
|
-
/**
|
|
5218
|
-
* Estimates standard deviation based on a sample.
|
|
5219
|
-
* `stdev` assumes that its arguments are a sample of the entire population.
|
|
5220
|
-
* If your data represents a entire population,
|
|
5221
|
-
* then compute the standard deviation using [stdevp]{@link stdevp}.
|
|
5222
|
-
* @param {number[]} numbers The array of numbers comprising the population
|
|
5223
|
-
* @returns {number}
|
|
5224
|
-
* @category openFormula
|
|
5225
|
-
* @function stdev
|
|
5226
|
-
* @example
|
|
5227
|
-
* stdev([1345, 1301, 1368]) //returns 34.044089061098404
|
|
5228
|
-
* stdevp([1345, 1301, 1368]) //returns 27.797
|
|
5229
|
-
*/
|
|
5230
4469
|
stdev: {
|
|
5231
4470
|
_func: args => {
|
|
5232
4471
|
const values = args[0] || [];
|
|
@@ -5238,7 +4477,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5238
4477
|
const sumSquare = coercedValues.reduce((a, b) => a + b * b, 0);
|
|
5239
4478
|
const result = Math.sqrt((sumSquare - values.length * mean * mean) / (values.length - 1));
|
|
5240
4479
|
if (Number.isNaN(result)) {
|
|
5241
|
-
// this would never happen
|
|
5242
4480
|
return null;
|
|
5243
4481
|
}
|
|
5244
4482
|
return result;
|
|
@@ -5247,20 +4485,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5247
4485
|
{ types: [dataTypes.TYPE_ARRAY_NUMBER] },
|
|
5248
4486
|
],
|
|
5249
4487
|
},
|
|
5250
|
-
|
|
5251
|
-
/**
|
|
5252
|
-
* Calculates standard deviation based on the entire population given as arguments.
|
|
5253
|
-
* `stdevp` assumes that its arguments are the entire population.
|
|
5254
|
-
* If your data represents a sample of the population,
|
|
5255
|
-
* then compute the standard deviation using [stdev]{@link stdev}.
|
|
5256
|
-
* @param {number[]} numbers The array of numbers comprising the population
|
|
5257
|
-
* @returns {number}
|
|
5258
|
-
* @category openFormula
|
|
5259
|
-
* @function stdevp
|
|
5260
|
-
* @example
|
|
5261
|
-
* stdevp([1345, 1301, 1368]) //returns 27.797
|
|
5262
|
-
* stdev([1345, 1301, 1368]) //returns 34.044
|
|
5263
|
-
*/
|
|
5264
4488
|
stdevp: {
|
|
5265
4489
|
_func: args => {
|
|
5266
4490
|
const values = args[0] || [];
|
|
@@ -5272,7 +4496,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5272
4496
|
const meanSumSquare = coercedValues.reduce((a, b) => a + b * b, 0) / values.length;
|
|
5273
4497
|
const result = Math.sqrt(meanSumSquare - mean * mean);
|
|
5274
4498
|
if (Number.isNaN(result)) {
|
|
5275
|
-
// this would never happen
|
|
5276
4499
|
return null;
|
|
5277
4500
|
}
|
|
5278
4501
|
return result;
|
|
@@ -5281,43 +4504,18 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5281
4504
|
{ types: [dataTypes.TYPE_ARRAY_NUMBER] },
|
|
5282
4505
|
],
|
|
5283
4506
|
},
|
|
5284
|
-
|
|
5285
|
-
/**
|
|
5286
|
-
* Returns input `text`, with text `old` replaced by text `new` (when searching from the left).
|
|
5287
|
-
* If `which` parameter is omitted, every occurrence of `old` is replaced with `new`;
|
|
5288
|
-
* If `which` is provided, only that occurrence of `old` is replaced by `new`
|
|
5289
|
-
* (starting the count from 1).
|
|
5290
|
-
* If there is no match, or if `old` has length 0, `text` is returned unchanged.
|
|
5291
|
-
* Note that `old` and `new` may have different lengths. If `which` < 1, return `text` unchanged
|
|
5292
|
-
* @param {string} text The text for which to substitute characters.
|
|
5293
|
-
* @param {string} old The text to replace.
|
|
5294
|
-
* @param {string} new The text to replace `old` with.
|
|
5295
|
-
* @param {integer} [which] The one-based occurrence of `old` text to replace with `new` text.
|
|
5296
|
-
* @returns {string} replaced string
|
|
5297
|
-
* @function
|
|
5298
|
-
* @category openFormula
|
|
5299
|
-
* @example
|
|
5300
|
-
* substitute('Sales Data', 'Sales', 'Cost') //returns 'Cost Data'
|
|
5301
|
-
* @example
|
|
5302
|
-
* substitute('Quarter 1, 2008', '1', '2', 1) //returns 'Quarter 2, 2008'
|
|
5303
|
-
* @example
|
|
5304
|
-
* substitute('Quarter 1, 1008', '1', '2', 2) //returns 'Quarter 1, 2008'
|
|
5305
|
-
*/
|
|
5306
4507
|
substitute: {
|
|
5307
4508
|
_func: args => {
|
|
5308
4509
|
const src = toString(args[0]);
|
|
5309
4510
|
const old = toString(args[1]);
|
|
5310
4511
|
const replacement = toString(args[2]);
|
|
5311
|
-
// no third parameter? replace all instances
|
|
5312
4512
|
if (args.length <= 3) return src.replaceAll(old, replacement);
|
|
5313
4513
|
const whch = toNumber(args[3]);
|
|
5314
4514
|
if (whch < 1) return src;
|
|
5315
|
-
// find the instance to replace
|
|
5316
4515
|
let pos = -1;
|
|
5317
4516
|
for (let i = 0; i < whch; i += 1) {
|
|
5318
4517
|
pos += 1;
|
|
5319
4518
|
const nextFind = src.slice(pos).indexOf(old);
|
|
5320
|
-
// no instance to match 'Which'
|
|
5321
4519
|
if (nextFind === -1) return src;
|
|
5322
4520
|
pos += nextFind;
|
|
5323
4521
|
}
|
|
@@ -5330,21 +4528,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5330
4528
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5331
4529
|
],
|
|
5332
4530
|
},
|
|
5333
|
-
|
|
5334
|
-
/**
|
|
5335
|
-
* Construct and returns time from hours, minutes, and seconds.
|
|
5336
|
-
* @param {integer} hours Integer value between 0 and 23 representing the hour of the day.
|
|
5337
|
-
* Defaults to 0.
|
|
5338
|
-
* @param {integer} minutes Integer value representing the minute segment of a time.
|
|
5339
|
-
* The default is 0 minutes past the hour.
|
|
5340
|
-
* @param {integer} seconds Integer value representing the second segment of a time.
|
|
5341
|
-
* The default is 0 seconds past the minute.
|
|
5342
|
-
* @return {number} Returns the fraction of the day consumed by the given time
|
|
5343
|
-
* @function time
|
|
5344
|
-
* @category openFormula
|
|
5345
|
-
* @example
|
|
5346
|
-
* time(12, 0, 0) //returns 0.5 (half day)
|
|
5347
|
-
*/
|
|
5348
4531
|
time: {
|
|
5349
4532
|
_func: args => {
|
|
5350
4533
|
const hours = toNumber(args[0]);
|
|
@@ -5362,65 +4545,23 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5362
4545
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5363
4546
|
],
|
|
5364
4547
|
},
|
|
5365
|
-
|
|
5366
|
-
/**
|
|
5367
|
-
* returns the number of days since epoch
|
|
5368
|
-
* @return number
|
|
5369
|
-
* @function today
|
|
5370
|
-
* @category openFormula
|
|
5371
|
-
*/
|
|
5372
4548
|
today: {
|
|
5373
4549
|
_func: () => Math.floor(Date.now() / MS_IN_DAY),
|
|
5374
4550
|
_signature: [],
|
|
5375
4551
|
},
|
|
5376
|
-
|
|
5377
|
-
/**
|
|
5378
|
-
* Remove leading and trailing spaces, and replace all internal multiple spaces
|
|
5379
|
-
* with a single space.
|
|
5380
|
-
* @param {string} text string to trim
|
|
5381
|
-
* @return {string} removes all leading and trailing space.
|
|
5382
|
-
* Any other sequence of 2 or more spaces is replaced with a single space.
|
|
5383
|
-
* @function trim
|
|
5384
|
-
* @category openFormula
|
|
5385
|
-
* @example
|
|
5386
|
-
* trim(' ab c ') //returns 'ab c'
|
|
5387
|
-
*/
|
|
5388
4552
|
trim: {
|
|
5389
4553
|
_func: args => {
|
|
5390
4554
|
const text = toString(args[0]);
|
|
5391
|
-
// only removes the space character
|
|
5392
|
-
// other whitespace characters like \t \n left intact
|
|
5393
4555
|
return text.split(' ').filter(x => x).join(' ');
|
|
5394
4556
|
},
|
|
5395
4557
|
_signature: [
|
|
5396
4558
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5397
4559
|
],
|
|
5398
4560
|
},
|
|
5399
|
-
|
|
5400
|
-
/**
|
|
5401
|
-
* Return constant boolean true value.
|
|
5402
|
-
* Note that expressions may also use the JSON literal true: `` `true` ``
|
|
5403
|
-
* @returns {boolean} True
|
|
5404
|
-
* @function
|
|
5405
|
-
* @category openFormula
|
|
5406
|
-
*/
|
|
5407
4561
|
true: {
|
|
5408
4562
|
_func: () => true,
|
|
5409
4563
|
_signature: [],
|
|
5410
4564
|
},
|
|
5411
|
-
|
|
5412
|
-
/**
|
|
5413
|
-
* Truncates a number to an integer by removing the fractional part of the number.
|
|
5414
|
-
* @param {number} numA number to truncate
|
|
5415
|
-
* @param {number} [numB] A number specifying the precision of the truncation. Default is 0
|
|
5416
|
-
* @return {number}
|
|
5417
|
-
* @function trunc
|
|
5418
|
-
* @category openFormula
|
|
5419
|
-
* @example
|
|
5420
|
-
* trunc(8.9) //returns 8
|
|
5421
|
-
* trunc(-8.9) //returns -8
|
|
5422
|
-
* trunc(8.912, 2) //returns 8.91
|
|
5423
|
-
*/
|
|
5424
4565
|
trunc: {
|
|
5425
4566
|
_func: args => {
|
|
5426
4567
|
const number = toNumber(args[0]);
|
|
@@ -5433,20 +4574,8 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5433
4574
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5434
4575
|
],
|
|
5435
4576
|
},
|
|
5436
|
-
|
|
5437
|
-
/**
|
|
5438
|
-
* takes an array and returns unique elements within it
|
|
5439
|
-
* @param {array} input input array
|
|
5440
|
-
* @return {array} array with duplicate elements removed
|
|
5441
|
-
* @function unique
|
|
5442
|
-
* @category JSONFormula
|
|
5443
|
-
* @example
|
|
5444
|
-
* unique([1, 2, 3, 4, 1, 1, 2]) //returns [1, 2, 3, 4]
|
|
5445
|
-
*/
|
|
5446
4577
|
unique: {
|
|
5447
4578
|
_func: args => {
|
|
5448
|
-
// create an array of values for searching. That way if the array elements are
|
|
5449
|
-
// represented by objects with a valueOf(), then we'll locate them in the valueArray
|
|
5450
4579
|
const valueArray = args[0].map(a => valueOf(a));
|
|
5451
4580
|
return args[0].filter((v, index) => valueArray.indexOf(valueOf(v)) === index);
|
|
5452
4581
|
},
|
|
@@ -5454,18 +4583,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5454
4583
|
{ types: [dataTypes.TYPE_ARRAY] },
|
|
5455
4584
|
],
|
|
5456
4585
|
},
|
|
5457
|
-
|
|
5458
|
-
/**
|
|
5459
|
-
* Converts all the alphabetic characters in a string to uppercase.
|
|
5460
|
-
* If the value is not a string it will be converted into string
|
|
5461
|
-
* using the default toString method
|
|
5462
|
-
* @param {string} input input string
|
|
5463
|
-
* @returns {string} the upper case value of the input string
|
|
5464
|
-
* @function upper
|
|
5465
|
-
* @category openFormula
|
|
5466
|
-
* @example
|
|
5467
|
-
* upper('abcd') //returns 'ABCD'
|
|
5468
|
-
*/
|
|
5469
4586
|
upper: {
|
|
5470
4587
|
_func: args => {
|
|
5471
4588
|
const value = toString(args[0]);
|
|
@@ -5475,19 +4592,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5475
4592
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5476
4593
|
],
|
|
5477
4594
|
},
|
|
5478
|
-
|
|
5479
|
-
/**
|
|
5480
|
-
* Perform an indexed lookup on a map or array
|
|
5481
|
-
* @param {map | array} object on which to perform the lookup
|
|
5482
|
-
* @param {string | integer} index: a named child for a map or an integer offset for an array
|
|
5483
|
-
* @returns {any} the result of the lookup -- or `null` if not found.
|
|
5484
|
-
* @function
|
|
5485
|
-
* @category JSONFormula
|
|
5486
|
-
* @example
|
|
5487
|
-
* value({a: 1, b:2, c:3}, a) //returns 1
|
|
5488
|
-
* @example
|
|
5489
|
-
* value([1, 2, 3, 4], 2) //returns 3
|
|
5490
|
-
*/
|
|
5491
4595
|
value: {
|
|
5492
4596
|
_func: args => {
|
|
5493
4597
|
const obj = args[0] || {};
|
|
@@ -5497,7 +4601,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5497
4601
|
debug.push(`Failed to find: '${index}'`);
|
|
5498
4602
|
const available = Object.keys(obj).map(a => `'${a}'`).toString();
|
|
5499
4603
|
if (available.length) debug.push(`Available fields: ${available}`);
|
|
5500
|
-
|
|
5501
4604
|
return null;
|
|
5502
4605
|
}
|
|
5503
4606
|
return result;
|
|
@@ -5507,43 +4610,18 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5507
4610
|
{ types: [dataTypes.TYPE_STRING, dataTypes.TYPE_NUMBER] },
|
|
5508
4611
|
],
|
|
5509
4612
|
},
|
|
5510
|
-
|
|
5511
|
-
/**
|
|
5512
|
-
* Extract the day of the week from a date; if text, uses current locale to convert to a date.
|
|
5513
|
-
* @param {number} The datetime for which the day of the week is to be returned.
|
|
5514
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
5515
|
-
* @param {number} [returnType] A number that determines the
|
|
5516
|
-
* numeral representation (a number from 0 to 7) of the
|
|
5517
|
-
* day of week. Default is 1. Supports the following values
|
|
5518
|
-
* * 1 : Sunday (1), Monday (2), ..., Saturday (7)
|
|
5519
|
-
* * 2 : Monday (1), Tuesday (2), ..., Sunday(7)
|
|
5520
|
-
* * 3 : Monday (0), Tuesday (2), ...., Sunday(6)
|
|
5521
|
-
* @returns {number} day of the week
|
|
5522
|
-
* @function weekday
|
|
5523
|
-
* @category openFormula
|
|
5524
|
-
* @example
|
|
5525
|
-
* weekday(datetime(2006,5,21)) // 1
|
|
5526
|
-
* @example
|
|
5527
|
-
* weekday(datetime(2006,5,21), 2) // 7
|
|
5528
|
-
* @example
|
|
5529
|
-
* weekday(datetime(2006,5,21), 3) // 6
|
|
5530
|
-
*/
|
|
5531
4613
|
weekday: {
|
|
5532
4614
|
_func: args => {
|
|
5533
4615
|
const date = toNumber(args[0]);
|
|
5534
4616
|
const type = args.length > 1 ? toNumber(args[1]) : 1;
|
|
5535
4617
|
const jsDate = new Date(date * MS_IN_DAY);
|
|
5536
4618
|
const day = jsDate.getDay();
|
|
5537
|
-
// day is in range [0-7) with 0 mapping to sunday
|
|
5538
4619
|
switch (type) {
|
|
5539
4620
|
case 1:
|
|
5540
|
-
// range = [1, 7], sunday = 1
|
|
5541
4621
|
return day + 1;
|
|
5542
4622
|
case 2:
|
|
5543
|
-
// range = [1, 7] sunday = 7
|
|
5544
4623
|
return ((day + 6) % 7) + 1;
|
|
5545
4624
|
case 3:
|
|
5546
|
-
// range = [0, 6] sunday = 6
|
|
5547
4625
|
return (day + 6) % 7;
|
|
5548
4626
|
default:
|
|
5549
4627
|
return null;
|
|
@@ -5554,17 +4632,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5554
4632
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5555
4633
|
],
|
|
5556
4634
|
},
|
|
5557
|
-
|
|
5558
|
-
/**
|
|
5559
|
-
* Returns the year of a date represented by a serial number.
|
|
5560
|
-
* @param {number} The date for which the year is to be returned.
|
|
5561
|
-
* Dates should be entered by using the [datetime]{@link datetime} function
|
|
5562
|
-
* @return {number}
|
|
5563
|
-
* @function year
|
|
5564
|
-
* @category openFormula
|
|
5565
|
-
* @example
|
|
5566
|
-
* year(datetime(2008,5,23)) //returns 2008
|
|
5567
|
-
*/
|
|
5568
4635
|
year: {
|
|
5569
4636
|
_func: args => {
|
|
5570
4637
|
const date = toNumber(args[0]);
|
|
@@ -5575,7 +4642,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5575
4642
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5576
4643
|
],
|
|
5577
4644
|
},
|
|
5578
|
-
|
|
5579
4645
|
charCode: {
|
|
5580
4646
|
_func: args => {
|
|
5581
4647
|
const code = toNumber(args[0]);
|
|
@@ -5588,7 +4654,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5588
4654
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5589
4655
|
],
|
|
5590
4656
|
},
|
|
5591
|
-
|
|
5592
4657
|
codePoint: {
|
|
5593
4658
|
_func: args => {
|
|
5594
4659
|
const text = toString(args[0]);
|
|
@@ -5601,28 +4666,24 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5601
4666
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5602
4667
|
],
|
|
5603
4668
|
},
|
|
5604
|
-
|
|
5605
4669
|
encodeUrlComponent: {
|
|
5606
4670
|
_func: args => encodeURIComponent(args[0]),
|
|
5607
4671
|
_signature: [
|
|
5608
4672
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5609
4673
|
],
|
|
5610
4674
|
},
|
|
5611
|
-
|
|
5612
4675
|
encodeUrl: {
|
|
5613
4676
|
_func: args => encodeURI(args[0]),
|
|
5614
4677
|
_signature: [
|
|
5615
4678
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5616
4679
|
],
|
|
5617
4680
|
},
|
|
5618
|
-
|
|
5619
4681
|
decodeUrlComponent: {
|
|
5620
4682
|
_func: args => decodeURIComponent(args[0]),
|
|
5621
4683
|
_signature: [
|
|
5622
4684
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5623
4685
|
],
|
|
5624
4686
|
},
|
|
5625
|
-
|
|
5626
4687
|
decodeUrl: {
|
|
5627
4688
|
_func: args => decodeURI(args[0]),
|
|
5628
4689
|
_signature: [
|
|
@@ -5632,27 +4693,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5632
4693
|
};
|
|
5633
4694
|
}
|
|
5634
4695
|
|
|
5635
|
-
/*
|
|
5636
|
-
Copyright 2014 James Saryerwinnie
|
|
5637
|
-
|
|
5638
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5639
|
-
you may not use this file except in compliance with the License.
|
|
5640
|
-
You may obtain a copy of the License at
|
|
5641
|
-
|
|
5642
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
5643
|
-
|
|
5644
|
-
Unless required by applicable law or agreed to in writing, software
|
|
5645
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
5646
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
5647
|
-
See the License for the specific language governing permissions and
|
|
5648
|
-
limitations under the License.
|
|
5649
|
-
|
|
5650
|
-
NOTICE:
|
|
5651
|
-
This file is substantially modified from the original source taken from:
|
|
5652
|
-
https://github.com/jmespath/jmespath.js
|
|
5653
|
-
|
|
5654
|
-
*/
|
|
5655
|
-
|
|
5656
4696
|
function functions(
|
|
5657
4697
|
runtime,
|
|
5658
4698
|
isObject,
|
|
@@ -5675,7 +4715,6 @@ function functions(
|
|
|
5675
4715
|
TYPE_ARRAY_NUMBER,
|
|
5676
4716
|
TYPE_ARRAY_STRING,
|
|
5677
4717
|
} = dataTypes;
|
|
5678
|
-
|
|
5679
4718
|
function createKeyFunction(exprefNode, allowedTypes) {
|
|
5680
4719
|
return x => {
|
|
5681
4720
|
const current = runtime.interpreter.visit(exprefNode, x);
|
|
@@ -5687,46 +4726,11 @@ function functions(
|
|
|
5687
4726
|
return current;
|
|
5688
4727
|
};
|
|
5689
4728
|
}
|
|
5690
|
-
|
|
5691
4729
|
const functionMap = {
|
|
5692
|
-
// name: [function, <signature>]
|
|
5693
|
-
// The <signature> can be:
|
|
5694
|
-
//
|
|
5695
|
-
// {
|
|
5696
|
-
// args: [[type1, type2], [type1, type2]],
|
|
5697
|
-
// variadic: true|false
|
|
5698
|
-
// }
|
|
5699
|
-
//
|
|
5700
|
-
// Each arg in the arg list is a list of valid types
|
|
5701
|
-
// (if the function is overloaded and supports multiple
|
|
5702
|
-
// types. If the type is "any" then no type checking
|
|
5703
|
-
// occurs on the argument. Variadic is optional
|
|
5704
|
-
// and if not provided is assumed to be false.
|
|
5705
|
-
/**
|
|
5706
|
-
* Returns the absolute value of the provided argument `value`.
|
|
5707
|
-
* @param {number} value argument whose absolute value has to be returned
|
|
5708
|
-
* @return {number} returns the absolute value of the `value` argument
|
|
5709
|
-
* @function abs
|
|
5710
|
-
* @example
|
|
5711
|
-
* abs(-1) //returns 1
|
|
5712
|
-
* @category jmespath
|
|
5713
|
-
*/
|
|
5714
4730
|
abs: {
|
|
5715
4731
|
_func: resolvedArgs => Math.abs(resolvedArgs[0]),
|
|
5716
4732
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5717
4733
|
},
|
|
5718
|
-
/**
|
|
5719
|
-
* Returns the average of the elements in the provided array.
|
|
5720
|
-
* An empty array will produce a return value of `null`.
|
|
5721
|
-
* @param {number[]} elements array of elements whose average has to be computed
|
|
5722
|
-
* @return {number} average value
|
|
5723
|
-
* @function avg
|
|
5724
|
-
* @example
|
|
5725
|
-
* avg([]) //returns null
|
|
5726
|
-
* @example
|
|
5727
|
-
* avg([1, 2, 3]) //returns 2
|
|
5728
|
-
* @category jmespath
|
|
5729
|
-
*/
|
|
5730
4734
|
avg: {
|
|
5731
4735
|
_func: resolvedArgs => {
|
|
5732
4736
|
let sum = 0;
|
|
@@ -5738,59 +4742,15 @@ function functions(
|
|
|
5738
4742
|
},
|
|
5739
4743
|
_signature: [{ types: [TYPE_ARRAY_NUMBER] }],
|
|
5740
4744
|
},
|
|
5741
|
-
|
|
5742
|
-
/**
|
|
5743
|
-
* Returns the next highest integer value of the argument `num` by rounding up if necessary.
|
|
5744
|
-
* @param {number} num number whose next highest integer value has to be computed
|
|
5745
|
-
* @return {number}
|
|
5746
|
-
* @function ceil
|
|
5747
|
-
* @example
|
|
5748
|
-
* ceil(10) //returns 10
|
|
5749
|
-
* @example
|
|
5750
|
-
* ceil(10.4) //return 11
|
|
5751
|
-
* @category jmespath
|
|
5752
|
-
*/
|
|
5753
4745
|
ceil: {
|
|
5754
4746
|
_func: resolvedArgs => Math.ceil(resolvedArgs[0]),
|
|
5755
4747
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5756
4748
|
},
|
|
5757
|
-
/**
|
|
5758
|
-
* Returns true if the given `subject` contains the provided `search` string.
|
|
5759
|
-
* If `subject` is an array, this function returns true if one of the elements
|
|
5760
|
-
* in the array is equal to the provided `search` value. If the provided `subject`
|
|
5761
|
-
* is a string, this function returns true if the string contains the provided
|
|
5762
|
-
* `search` argument.
|
|
5763
|
-
* @param {array|string} subject the subject in which the element has to be searched
|
|
5764
|
-
* @param {string|boolean|number|date} search element to search
|
|
5765
|
-
* @return {boolean}
|
|
5766
|
-
* @function contains
|
|
5767
|
-
* @example
|
|
5768
|
-
* contains([1, 2, 3, 4], 2) //returns true
|
|
5769
|
-
* @example
|
|
5770
|
-
* contains([1, 2, 3, 4], -1) //returns false
|
|
5771
|
-
* @example
|
|
5772
|
-
* contains('Abcd', 'd') //returns true
|
|
5773
|
-
* @example
|
|
5774
|
-
* contains('Abcd', 'x') //returns false
|
|
5775
|
-
* @category jmespath
|
|
5776
|
-
*/
|
|
5777
4749
|
contains: {
|
|
5778
4750
|
_func: resolvedArgs => valueOf(resolvedArgs[0]).indexOf(valueOf(resolvedArgs[1])) >= 0,
|
|
5779
4751
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY] },
|
|
5780
4752
|
{ types: [TYPE_ANY] }],
|
|
5781
4753
|
},
|
|
5782
|
-
/**
|
|
5783
|
-
* Returns true if the `subject` ends with the `suffix`, otherwise this function returns false.
|
|
5784
|
-
* @param {string} subject subject in which the `suffix` is being searched for
|
|
5785
|
-
* @param {string} suffix suffix to search in the subject
|
|
5786
|
-
* @return {boolean}
|
|
5787
|
-
* @function endsWith
|
|
5788
|
-
* @example
|
|
5789
|
-
* endsWith('Abcd', 'd') //returns true
|
|
5790
|
-
* @example
|
|
5791
|
-
* endsWith('Abcd', 'A') //returns false
|
|
5792
|
-
* @category jmespath
|
|
5793
|
-
*/
|
|
5794
4754
|
endsWith: {
|
|
5795
4755
|
_func: resolvedArgs => {
|
|
5796
4756
|
const searchStr = valueOf(resolvedArgs[0]);
|
|
@@ -5799,34 +4759,10 @@ function functions(
|
|
|
5799
4759
|
},
|
|
5800
4760
|
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }],
|
|
5801
4761
|
},
|
|
5802
|
-
|
|
5803
|
-
/**
|
|
5804
|
-
* Returns the next lowest integer value of the argument `num` by rounding down if necessary.
|
|
5805
|
-
* @param {number} num number whose next lowest integer value has to be returned
|
|
5806
|
-
* @return {number}
|
|
5807
|
-
* @function floor
|
|
5808
|
-
* @example
|
|
5809
|
-
* floor(10.4) //returns 10
|
|
5810
|
-
* @example
|
|
5811
|
-
* floor(10) //returns 10
|
|
5812
|
-
* @category jmespath
|
|
5813
|
-
*/
|
|
5814
4762
|
floor: {
|
|
5815
4763
|
_func: resolvedArgs => Math.floor(resolvedArgs[0]),
|
|
5816
4764
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5817
4765
|
},
|
|
5818
|
-
|
|
5819
|
-
/**
|
|
5820
|
-
* Returns all the elements from the provided `stringsarray`
|
|
5821
|
-
* array joined together using the `glue` argument as a separator between each.
|
|
5822
|
-
* @param {string} glue
|
|
5823
|
-
* @param {string[]} stringsarray
|
|
5824
|
-
* @return {string}
|
|
5825
|
-
* @function join
|
|
5826
|
-
* @example
|
|
5827
|
-
* join(',', ['a', 'b', 'c']) //returns 'a,b,c'
|
|
5828
|
-
* @category jmespath
|
|
5829
|
-
*/
|
|
5830
4766
|
join: {
|
|
5831
4767
|
_func: resolvedArgs => {
|
|
5832
4768
|
const joinChar = resolvedArgs[0];
|
|
@@ -5838,17 +4774,6 @@ function functions(
|
|
|
5838
4774
|
{ types: [TYPE_ARRAY_STRING] },
|
|
5839
4775
|
],
|
|
5840
4776
|
},
|
|
5841
|
-
|
|
5842
|
-
/**
|
|
5843
|
-
* Returns an array containing the keys of the provided object `obj`. If the passed
|
|
5844
|
-
* object is null, the value returned is an empty array
|
|
5845
|
-
* @param {object} obj the object whose keys need to be extracted
|
|
5846
|
-
* @return {array}
|
|
5847
|
-
* @function keys
|
|
5848
|
-
* @example
|
|
5849
|
-
* keys({a : 3, b : 4}) //returns ['a', 'b']
|
|
5850
|
-
* @category jmespath
|
|
5851
|
-
*/
|
|
5852
4777
|
keys: {
|
|
5853
4778
|
_func: resolvedArgs => {
|
|
5854
4779
|
if (resolvedArgs[0] === null) return [];
|
|
@@ -5856,54 +4781,14 @@ function functions(
|
|
|
5856
4781
|
},
|
|
5857
4782
|
_signature: [{ types: [TYPE_ANY] }],
|
|
5858
4783
|
},
|
|
5859
|
-
|
|
5860
|
-
/**
|
|
5861
|
-
* Returns the length of the given argument `subject` using the following types rules:
|
|
5862
|
-
* * string: returns the number of code points in the string
|
|
5863
|
-
* * array: returns the number of elements in the array
|
|
5864
|
-
* * object: returns the number of key-value pairs in the object
|
|
5865
|
-
* @param {string | array | object} subject subject whose length has to be calculated
|
|
5866
|
-
* @return {number}
|
|
5867
|
-
* @function length
|
|
5868
|
-
* @example
|
|
5869
|
-
* length([]) //returns 0
|
|
5870
|
-
* @example
|
|
5871
|
-
* length('') //returns 0
|
|
5872
|
-
* @example
|
|
5873
|
-
* length('abcd') //returns 4
|
|
5874
|
-
* @example
|
|
5875
|
-
* length([1, 2, 3, 4]) //returns 4
|
|
5876
|
-
* @example
|
|
5877
|
-
* length({}) // returns 0
|
|
5878
|
-
* @example
|
|
5879
|
-
* length({a : 3, b : 4}) //returns 2
|
|
5880
|
-
* @category jmespath
|
|
5881
|
-
*/
|
|
5882
4784
|
length: {
|
|
5883
4785
|
_func: resolvedArgs => {
|
|
5884
4786
|
const arg = valueOf(resolvedArgs[0]);
|
|
5885
4787
|
if (isObject(arg)) return Object.keys(arg).length;
|
|
5886
|
-
|
|
5887
4788
|
return isArray(arg) ? arg.length : toString(arg).length;
|
|
5888
4789
|
},
|
|
5889
4790
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT] }],
|
|
5890
4791
|
},
|
|
5891
|
-
|
|
5892
|
-
/**
|
|
5893
|
-
* Apply the `expr` to every element in the `elements` array and return the array of results.
|
|
5894
|
-
* An elements of length N will produce a return array of length N. Unlike a projection,
|
|
5895
|
-
* `[*].bar`, `map()` will include the result of applying the `expr` for every element
|
|
5896
|
-
* in the elements array, even if the result is `null`.
|
|
5897
|
-
* @param {expression} expr expression to evaluate on each element
|
|
5898
|
-
* @param {array} elements array of elements on which the expression will be evaluated
|
|
5899
|
-
* @return {array}
|
|
5900
|
-
* @function map
|
|
5901
|
-
* @example
|
|
5902
|
-
* map(&(@ + 1), [1, 2, 3, 4]) // returns [2, 3, 4, 5]
|
|
5903
|
-
* @example
|
|
5904
|
-
* map(&length(@), ['doe', 'nick', 'chris']) // returns [3,4, 5]
|
|
5905
|
-
* @category jmespath
|
|
5906
|
-
*/
|
|
5907
4792
|
map: {
|
|
5908
4793
|
_func: resolvedArgs => {
|
|
5909
4794
|
const exprefNode = resolvedArgs[0];
|
|
@@ -5911,35 +4796,15 @@ function functions(
|
|
|
5911
4796
|
},
|
|
5912
4797
|
_signature: [{ types: [TYPE_EXPREF] }, { types: [TYPE_ARRAY] }],
|
|
5913
4798
|
},
|
|
5914
|
-
|
|
5915
|
-
/**
|
|
5916
|
-
* Returns the highest value in the provided `collection` arguments.
|
|
5917
|
-
* If all collections are empty `null` is returned.
|
|
5918
|
-
* max() can work on numbers or strings.
|
|
5919
|
-
* If a mix of numbers and strings are provided, the type of the first value will be used.
|
|
5920
|
-
* @param {number[]|string[]} collection array in which the maximum element is to be calculated
|
|
5921
|
-
* @return {number}
|
|
5922
|
-
* @function max
|
|
5923
|
-
* @example
|
|
5924
|
-
* max([1, 2, 3], [4, 5, 6], 7) //returns 7
|
|
5925
|
-
* @example
|
|
5926
|
-
* max([]) // returns null
|
|
5927
|
-
* @example
|
|
5928
|
-
* max(['a', 'a1', 'b']) // returns 'b'
|
|
5929
|
-
* @category jmespath
|
|
5930
|
-
*/
|
|
5931
4799
|
max: {
|
|
5932
4800
|
_func: args => {
|
|
5933
|
-
// flatten the args into a single array
|
|
5934
4801
|
const array = args.reduce((prev, cur) => {
|
|
5935
4802
|
if (Array.isArray(cur)) prev.push(...cur);
|
|
5936
4803
|
else prev.push(cur);
|
|
5937
4804
|
return prev;
|
|
5938
4805
|
}, []);
|
|
5939
|
-
|
|
5940
4806
|
const first = array.find(r => r !== null);
|
|
5941
4807
|
if (array.length === 0 || first === undefined) return null;
|
|
5942
|
-
// use the first value to determine the comparison type
|
|
5943
4808
|
const isNumber = getTypeName(first, true) === TYPE_NUMBER;
|
|
5944
4809
|
const compare = isNumber
|
|
5945
4810
|
? (prev, cur) => {
|
|
@@ -5950,25 +4815,10 @@ function functions(
|
|
|
5950
4815
|
const current = toString(cur);
|
|
5951
4816
|
return prev.localeCompare(current) === 1 ? prev : current;
|
|
5952
4817
|
};
|
|
5953
|
-
|
|
5954
4818
|
return array.reduce(compare, isNumber ? toNumber(first) : toString(first));
|
|
5955
4819
|
},
|
|
5956
4820
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING], variadic: true }],
|
|
5957
4821
|
},
|
|
5958
|
-
|
|
5959
|
-
/**
|
|
5960
|
-
* Returns the maximum element in an array using the expression `expr` as the comparison key.
|
|
5961
|
-
* The entire element is returned.
|
|
5962
|
-
* @param {array} elements the array in which the maximum element is to be found
|
|
5963
|
-
* @param {expression} expr the expr to use as the `comparison` key
|
|
5964
|
-
* @return {any}
|
|
5965
|
-
* @function maxBy
|
|
5966
|
-
* @example
|
|
5967
|
-
* maxBy(['abcd', 'e', 'def'], &length(@)) //returns 'abcd'
|
|
5968
|
-
* @example
|
|
5969
|
-
* maxBy([{year: 2010}, {year: 2020}, {year: 1910}], &year) //returns {year: 2020}
|
|
5970
|
-
* @category jmespath
|
|
5971
|
-
*/
|
|
5972
4822
|
maxBy: {
|
|
5973
4823
|
_func: resolvedArgs => {
|
|
5974
4824
|
const exprefNode = resolvedArgs[1];
|
|
@@ -5988,22 +4838,6 @@ function functions(
|
|
|
5988
4838
|
},
|
|
5989
4839
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
5990
4840
|
},
|
|
5991
|
-
|
|
5992
|
-
/**
|
|
5993
|
-
* Accepts 0 or more objects as arguments, and returns a single object with
|
|
5994
|
-
* subsequent objects merged. Each subsequent object’s key/value pairs are
|
|
5995
|
-
* added to the preceding object. This function is used to combine multiple
|
|
5996
|
-
* objects into one. You can think of this as the first object being the base object,
|
|
5997
|
-
* and each subsequent argument being overrides that are applied to the base object.
|
|
5998
|
-
* @param {...object} args
|
|
5999
|
-
* @return {object}
|
|
6000
|
-
* @function merge
|
|
6001
|
-
* @example
|
|
6002
|
-
* merge({a: 1, b: 2}, {c : 3, d: 4}) // returns {a :1, b: 2, c: 3, d: 4}
|
|
6003
|
-
* @example
|
|
6004
|
-
* merge({a: 1, b: 2}, {a : 3, d: 4}) // returns {a :3, b: 2, d: 4}
|
|
6005
|
-
* @category jmespath
|
|
6006
|
-
*/
|
|
6007
4841
|
merge: {
|
|
6008
4842
|
_func: resolvedArgs => {
|
|
6009
4843
|
const merged = {};
|
|
@@ -6016,35 +4850,15 @@ function functions(
|
|
|
6016
4850
|
},
|
|
6017
4851
|
_signature: [{ types: [TYPE_OBJECT], variadic: true }],
|
|
6018
4852
|
},
|
|
6019
|
-
|
|
6020
|
-
/**
|
|
6021
|
-
* Returns the lowest value in the provided `collection` arguments.
|
|
6022
|
-
* If all collections are empty `null` is returned.
|
|
6023
|
-
* min() can work on numbers or strings.
|
|
6024
|
-
* If a mix of numbers and strings are provided, the type of the first value will be used.
|
|
6025
|
-
* @param {number[]|string[]} collection array in which the minimum element is to be calculated
|
|
6026
|
-
* @return {number}
|
|
6027
|
-
* @function min
|
|
6028
|
-
* @example
|
|
6029
|
-
* min([1, 2, 3], [4, 5, 6], 7) //returns 1
|
|
6030
|
-
* @example
|
|
6031
|
-
* min([]) // returns null
|
|
6032
|
-
* @example
|
|
6033
|
-
* min(['a', 'a1', 'b']) // returns 'a'
|
|
6034
|
-
* @category jmespath
|
|
6035
|
-
*/
|
|
6036
4853
|
min: {
|
|
6037
4854
|
_func: args => {
|
|
6038
|
-
// flatten the args into a single array
|
|
6039
4855
|
const array = args.reduce((prev, cur) => {
|
|
6040
4856
|
if (Array.isArray(cur)) prev.push(...cur);
|
|
6041
4857
|
else prev.push(cur);
|
|
6042
4858
|
return prev;
|
|
6043
4859
|
}, []);
|
|
6044
|
-
|
|
6045
4860
|
const first = array.find(r => r !== null);
|
|
6046
4861
|
if (array.length === 0 || first === undefined) return null;
|
|
6047
|
-
// use the first value to determine the comparison type
|
|
6048
4862
|
const isNumber = getTypeName(first, true) === TYPE_NUMBER;
|
|
6049
4863
|
const compare = isNumber
|
|
6050
4864
|
? (prev, cur) => {
|
|
@@ -6055,25 +4869,10 @@ function functions(
|
|
|
6055
4869
|
const current = toString(cur);
|
|
6056
4870
|
return prev.localeCompare(current) === 1 ? current : prev;
|
|
6057
4871
|
};
|
|
6058
|
-
|
|
6059
4872
|
return array.reduce(compare, isNumber ? toNumber(first) : toString(first));
|
|
6060
4873
|
},
|
|
6061
4874
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING], variadic: true }],
|
|
6062
4875
|
},
|
|
6063
|
-
|
|
6064
|
-
/**
|
|
6065
|
-
* Returns the minimum element in `elements` array using the expression `expr`
|
|
6066
|
-
* as the comparison key.
|
|
6067
|
-
* @param {array} elements
|
|
6068
|
-
* @param {expression} expr expression that returns either a string or a number
|
|
6069
|
-
* @return {any}
|
|
6070
|
-
* @function minBy
|
|
6071
|
-
* @example
|
|
6072
|
-
* minBy(['abcd', 'e', 'def'], &length(@)) //returns 'e'
|
|
6073
|
-
* @example
|
|
6074
|
-
* minBy([{year: 2010}, {year: 2020}, {year: 1910}], &year) //returns {year: 1910}
|
|
6075
|
-
* @category jmespath
|
|
6076
|
-
*/
|
|
6077
4876
|
minBy: {
|
|
6078
4877
|
_func: resolvedArgs => {
|
|
6079
4878
|
const exprefNode = resolvedArgs[1];
|
|
@@ -6093,48 +4892,10 @@ function functions(
|
|
|
6093
4892
|
},
|
|
6094
4893
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
6095
4894
|
},
|
|
6096
|
-
|
|
6097
|
-
/**
|
|
6098
|
-
* Returns the first argument that does not resolve to `null`.
|
|
6099
|
-
* This function accepts one or more arguments, and will evaluate
|
|
6100
|
-
* them in order until a non null argument is encounted. If all
|
|
6101
|
-
* arguments values resolve to null, then a value of null is returned.
|
|
6102
|
-
* @param {...any} argument
|
|
6103
|
-
* @return {any}
|
|
6104
|
-
* @function notNull
|
|
6105
|
-
* @example
|
|
6106
|
-
* notNull(1, 2, 3, 4, `null`) //returns 1
|
|
6107
|
-
* @example
|
|
6108
|
-
* notNull(`null`, 2, 3, 4, `null`) //returns 2
|
|
6109
|
-
* @category jmespath
|
|
6110
|
-
*/
|
|
6111
4895
|
notNull: {
|
|
6112
4896
|
_func: resolvedArgs => resolvedArgs.find(arg => getTypeName(arg) !== TYPE_NULL) || null,
|
|
6113
4897
|
_signature: [{ types: [TYPE_ANY], variadic: true }],
|
|
6114
4898
|
},
|
|
6115
|
-
|
|
6116
|
-
/**
|
|
6117
|
-
* executes a user-supplied reducer expression `expr` on each element of the
|
|
6118
|
-
* array, in order, passing in the return value from the calculation on the preceding element.
|
|
6119
|
-
* The final result of running the reducer across all elements of the `elements` array is a
|
|
6120
|
-
* single value.
|
|
6121
|
-
* The expression can access the following properties
|
|
6122
|
-
* * accumulated: accumulated value based on the previous calculations. Initial value is `null`
|
|
6123
|
-
* * current: current element to process
|
|
6124
|
-
* * index: index of the `current` element in the array
|
|
6125
|
-
* * array: original array
|
|
6126
|
-
* @param {expression} expr reducer expr to be executed on each element
|
|
6127
|
-
* @param {array} elements array of elements on which the expression will be evaluated
|
|
6128
|
-
* @return {any}
|
|
6129
|
-
* @function reduce
|
|
6130
|
-
* @example
|
|
6131
|
-
* reduce(&(accumulated + current), [1, 2, 3]) //returns 6
|
|
6132
|
-
* @example
|
|
6133
|
-
* reduce(&(accumulated - current), [3, 3, 3]) //returns -9
|
|
6134
|
-
* @example
|
|
6135
|
-
* reduce(&if(accumulated == `null`, current, accumulated * current), [3, 3, 3]) //returns 27
|
|
6136
|
-
* @category jmespath
|
|
6137
|
-
*/
|
|
6138
4899
|
reduce: {
|
|
6139
4900
|
_func: resolvedArgs => {
|
|
6140
4901
|
const exprefNode = resolvedArgs[0];
|
|
@@ -6151,23 +4912,10 @@ function functions(
|
|
|
6151
4912
|
{ types: [TYPE_ANY], optional: true },
|
|
6152
4913
|
],
|
|
6153
4914
|
},
|
|
6154
|
-
|
|
6155
|
-
/**
|
|
6156
|
-
* Register a function to allow code re-use. The registered function may take one parameter.
|
|
6157
|
-
* If more parameters are needed, combine them in an array or map.
|
|
6158
|
-
* @param {string} functionName Name of the function to register
|
|
6159
|
-
* @param {expression} expr Expression to execute with this function call
|
|
6160
|
-
* @return {{}} returns an empty object
|
|
6161
|
-
* @function register
|
|
6162
|
-
* @example
|
|
6163
|
-
* register('product', &@[0] * @[1]) // can now call: product([2,21]) => returns 42
|
|
6164
|
-
* @category jmespath
|
|
6165
|
-
*/
|
|
6166
4915
|
register: {
|
|
6167
4916
|
_func: resolvedArgs => {
|
|
6168
4917
|
const functionName = resolvedArgs[0];
|
|
6169
4918
|
const exprefNode = resolvedArgs[1];
|
|
6170
|
-
|
|
6171
4919
|
if (functionMap[functionName]) {
|
|
6172
4920
|
debug.push(`Cannot re-register '${functionName}'`);
|
|
6173
4921
|
return {};
|
|
@@ -6183,15 +4931,6 @@ function functions(
|
|
|
6183
4931
|
{ types: [TYPE_EXPREF] },
|
|
6184
4932
|
],
|
|
6185
4933
|
},
|
|
6186
|
-
/**
|
|
6187
|
-
* Reverses the order of the `argument`.
|
|
6188
|
-
* @param {string|array} argument
|
|
6189
|
-
* @return {array}
|
|
6190
|
-
* @function reverse
|
|
6191
|
-
* @example
|
|
6192
|
-
* reverse(['a', 'b', 'c']) //returns ['c', 'b', 'a']
|
|
6193
|
-
* @category jmespath
|
|
6194
|
-
*/
|
|
6195
4934
|
reverse: {
|
|
6196
4935
|
_func: resolvedArgs => {
|
|
6197
4936
|
const originalStr = valueOf(resolvedArgs[0]);
|
|
@@ -6209,18 +4948,6 @@ function functions(
|
|
|
6209
4948
|
},
|
|
6210
4949
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY] }],
|
|
6211
4950
|
},
|
|
6212
|
-
|
|
6213
|
-
/**
|
|
6214
|
-
* This function accepts an array `list` argument and returns the sorted elements of
|
|
6215
|
-
* the `list` as an array. The array must be a list of strings or numbers.
|
|
6216
|
-
* Sorting strings is based on code points. Locale is not taken into account.
|
|
6217
|
-
* @param {number[]|string[]} list
|
|
6218
|
-
* @return {number[]|string[]}
|
|
6219
|
-
* @function sort
|
|
6220
|
-
* @example
|
|
6221
|
-
* sort([1, 2, 4, 3, 1]) // returns [1, 1, 2, 3, 4]
|
|
6222
|
-
* @category jmespath
|
|
6223
|
-
*/
|
|
6224
4951
|
sort: {
|
|
6225
4952
|
_func: resolvedArgs => {
|
|
6226
4953
|
const sortedArray = resolvedArgs[0].slice(0);
|
|
@@ -6238,24 +4965,6 @@ function functions(
|
|
|
6238
4965
|
},
|
|
6239
4966
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_STRING, TYPE_ARRAY_NUMBER] }],
|
|
6240
4967
|
},
|
|
6241
|
-
|
|
6242
|
-
/**
|
|
6243
|
-
* Sort an array using an expression `expr` as the sort key. For each element
|
|
6244
|
-
* in the array of elements, the `expr` expression is applied and the resulting
|
|
6245
|
-
* value is used as the key used when sorting the elements. If the result of
|
|
6246
|
-
* evaluating the `expr` against the current array element results in type
|
|
6247
|
-
* other than a number or a string, a type error will occur.
|
|
6248
|
-
* @param {array} elements
|
|
6249
|
-
* @param {expression} expr
|
|
6250
|
-
* @return {array}
|
|
6251
|
-
* @function sortBy
|
|
6252
|
-
* @example
|
|
6253
|
-
* sortBy(['abcd', 'e', 'def'], &length(@)) //returns ['e', 'def', 'abcd']
|
|
6254
|
-
* @example
|
|
6255
|
-
* // returns [{year: 1910}, {year: 2010}, {year: 2020}]
|
|
6256
|
-
* sortBy([{year: 2010}, {year: 2020}, {year: 1910}], &year)
|
|
6257
|
-
* @category jmespath
|
|
6258
|
-
*/
|
|
6259
4968
|
sortBy: {
|
|
6260
4969
|
_func: resolvedArgs => {
|
|
6261
4970
|
const sortedArray = resolvedArgs[0].slice(0);
|
|
@@ -6269,13 +4978,6 @@ function functions(
|
|
|
6269
4978
|
if ([TYPE_NUMBER, TYPE_STRING].indexOf(requiredType) < 0) {
|
|
6270
4979
|
throw new Error('TypeError');
|
|
6271
4980
|
}
|
|
6272
|
-
// In order to get a stable sort out of an unstable
|
|
6273
|
-
// sort algorithm, we decorate/sort/undecorate (DSU)
|
|
6274
|
-
// by creating a new list of [index, element] pairs.
|
|
6275
|
-
// In the cmp function, if the evaluated elements are
|
|
6276
|
-
// equal, then the index will be used as the tiebreaker.
|
|
6277
|
-
// After the decorated list has been sorted, it will be
|
|
6278
|
-
// undecorated to extract the original elements.
|
|
6279
4981
|
const decorated = [];
|
|
6280
4982
|
for (let i = 0; i < sortedArray.length; i += 1) {
|
|
6281
4983
|
decorated.push([i, sortedArray[i]]);
|
|
@@ -6300,12 +5002,8 @@ function functions(
|
|
|
6300
5002
|
if (exprA < exprB) {
|
|
6301
5003
|
return -1;
|
|
6302
5004
|
}
|
|
6303
|
-
// If they're equal compare the items by their
|
|
6304
|
-
// order to maintain relative order of equal keys
|
|
6305
|
-
// (i.e. to get a stable sort).
|
|
6306
5005
|
return a[0] - b[0];
|
|
6307
5006
|
});
|
|
6308
|
-
// Undecorate: extract out the original list elements.
|
|
6309
5007
|
for (let j = 0; j < decorated.length; j += 1) {
|
|
6310
5008
|
[, sortedArray[j]] = decorated[j];
|
|
6311
5009
|
}
|
|
@@ -6313,32 +5011,10 @@ function functions(
|
|
|
6313
5011
|
},
|
|
6314
5012
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
6315
5013
|
},
|
|
6316
|
-
|
|
6317
|
-
/**
|
|
6318
|
-
* Returns true if the `subject` starts with the `prefix`, otherwise returns false.
|
|
6319
|
-
* @param {string} subject subject in which the `prefix` is being searched for
|
|
6320
|
-
* @param {string} prefix prefix to search in the subject
|
|
6321
|
-
* @return {boolean}
|
|
6322
|
-
* @function startsWith
|
|
6323
|
-
* @example
|
|
6324
|
-
* startsWith('jack is at home', 'jack') // returns true
|
|
6325
|
-
* @category jmespath
|
|
6326
|
-
*/
|
|
6327
5014
|
startsWith: {
|
|
6328
5015
|
_func: resolvedArgs => valueOf(resolvedArgs[0]).startsWith(valueOf(resolvedArgs[1])),
|
|
6329
5016
|
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }],
|
|
6330
5017
|
},
|
|
6331
|
-
|
|
6332
|
-
/**
|
|
6333
|
-
* Returns the sum of the provided `collection` array argument.
|
|
6334
|
-
* An empty array will produce a return value of 0.
|
|
6335
|
-
* @param {number[]} collection array whose element's sum has to be computed
|
|
6336
|
-
* @return {number}
|
|
6337
|
-
* @function sum
|
|
6338
|
-
* @example
|
|
6339
|
-
* sum([1, 2, 3]) //returns 6
|
|
6340
|
-
* @category jmespath
|
|
6341
|
-
*/
|
|
6342
5018
|
sum: {
|
|
6343
5019
|
_func: resolvedArgs => {
|
|
6344
5020
|
let sum = 0;
|
|
@@ -6349,20 +5025,6 @@ function functions(
|
|
|
6349
5025
|
},
|
|
6350
5026
|
_signature: [{ types: [TYPE_ARRAY_NUMBER] }],
|
|
6351
5027
|
},
|
|
6352
|
-
|
|
6353
|
-
/**
|
|
6354
|
-
* converts the passed `arg` to an array. The conversion happens as per the following rules
|
|
6355
|
-
* * array - Returns the passed in value.
|
|
6356
|
-
* * number/string/object/boolean - Returns a one element array containing the argument.
|
|
6357
|
-
* @param {any} arg
|
|
6358
|
-
* @return {array}
|
|
6359
|
-
* @function toArray
|
|
6360
|
-
* @example
|
|
6361
|
-
* toArray(1) // returns [1]
|
|
6362
|
-
* @example
|
|
6363
|
-
* toArray(null()) // returns [`null`]
|
|
6364
|
-
* @category jmespath
|
|
6365
|
-
*/
|
|
6366
5028
|
toArray: {
|
|
6367
5029
|
_func: resolvedArgs => {
|
|
6368
5030
|
if (getTypeName(resolvedArgs[0]) === TYPE_ARRAY) {
|
|
@@ -6370,31 +5032,8 @@ function functions(
|
|
|
6370
5032
|
}
|
|
6371
5033
|
return [resolvedArgs[0]];
|
|
6372
5034
|
},
|
|
6373
|
-
|
|
6374
5035
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6375
5036
|
},
|
|
6376
|
-
|
|
6377
|
-
/**
|
|
6378
|
-
* converts the passed arg to a number. The conversion happens as per the following rules
|
|
6379
|
-
* * string - Returns the parsed number.
|
|
6380
|
-
* * number - Returns the passed in value.
|
|
6381
|
-
* * array - null
|
|
6382
|
-
* * object - null
|
|
6383
|
-
* * boolean - null
|
|
6384
|
-
* * null - null
|
|
6385
|
-
* @param {any} arg
|
|
6386
|
-
* @return {number}
|
|
6387
|
-
* @function toNumber
|
|
6388
|
-
* @example
|
|
6389
|
-
* toNumber(1) //returns 1
|
|
6390
|
-
* @example
|
|
6391
|
-
* toNumber('10') //returns 10
|
|
6392
|
-
* @example
|
|
6393
|
-
* toNumber({a: 1}) //returns null
|
|
6394
|
-
* @example
|
|
6395
|
-
* toNumber(true()) //returns null
|
|
6396
|
-
* @category jmespath
|
|
6397
|
-
*/
|
|
6398
5037
|
toNumber: {
|
|
6399
5038
|
_func: resolvedArgs => {
|
|
6400
5039
|
const typeName = getTypeName(resolvedArgs[0]);
|
|
@@ -6408,20 +5047,6 @@ function functions(
|
|
|
6408
5047
|
},
|
|
6409
5048
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6410
5049
|
},
|
|
6411
|
-
|
|
6412
|
-
/**
|
|
6413
|
-
* converts the passed `arg` to a string. The conversion happens as per the following rules
|
|
6414
|
-
* * string - Returns the passed in value.
|
|
6415
|
-
* * number/array/object/boolean - The JSON encoded value of the object.
|
|
6416
|
-
* @param {any} arg
|
|
6417
|
-
* @return {string}
|
|
6418
|
-
* @function toString
|
|
6419
|
-
* @example
|
|
6420
|
-
* toString(1) //returns '1'
|
|
6421
|
-
* @example
|
|
6422
|
-
* toString(true()) //returns 'true'
|
|
6423
|
-
* @category jmespath
|
|
6424
|
-
*/
|
|
6425
5050
|
toString: {
|
|
6426
5051
|
_func: resolvedArgs => {
|
|
6427
5052
|
if (getTypeName(resolvedArgs[0]) === TYPE_STRING) {
|
|
@@ -6429,30 +5054,8 @@ function functions(
|
|
|
6429
5054
|
}
|
|
6430
5055
|
return JSON.stringify(resolvedArgs[0]);
|
|
6431
5056
|
},
|
|
6432
|
-
|
|
6433
5057
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6434
5058
|
},
|
|
6435
|
-
|
|
6436
|
-
/**
|
|
6437
|
-
* Returns the JavaScript type of the given `subject` argument as a string value.
|
|
6438
|
-
*
|
|
6439
|
-
* The return value MUST be one of the following:
|
|
6440
|
-
* * number
|
|
6441
|
-
* * string
|
|
6442
|
-
* * boolean
|
|
6443
|
-
* * array
|
|
6444
|
-
* * object
|
|
6445
|
-
* * null
|
|
6446
|
-
* @param {any} subject
|
|
6447
|
-
* @return {string}
|
|
6448
|
-
*
|
|
6449
|
-
* @function type
|
|
6450
|
-
* @example
|
|
6451
|
-
* type(1) //returns 'number'
|
|
6452
|
-
* @example
|
|
6453
|
-
* type('') //returns 'string'
|
|
6454
|
-
* @category jmespath
|
|
6455
|
-
*/
|
|
6456
5059
|
type: {
|
|
6457
5060
|
_func: resolvedArgs => ({
|
|
6458
5061
|
[TYPE_NUMBER]: 'number',
|
|
@@ -6465,18 +5068,6 @@ function functions(
|
|
|
6465
5068
|
}[getTypeName(resolvedArgs[0])]),
|
|
6466
5069
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6467
5070
|
},
|
|
6468
|
-
|
|
6469
|
-
/**
|
|
6470
|
-
* Returns the values of the provided object `obj`. Note that because JSON hashes are
|
|
6471
|
-
* inherently unordered, the values associated with the provided object obj are
|
|
6472
|
-
* inherently unordered.
|
|
6473
|
-
* @param {object} obj
|
|
6474
|
-
* @return {array}
|
|
6475
|
-
* @function values
|
|
6476
|
-
* @example
|
|
6477
|
-
* values({a : 3, b : 4}) //returns [3, 4]
|
|
6478
|
-
* @category jmespath
|
|
6479
|
-
*/
|
|
6480
5071
|
values: {
|
|
6481
5072
|
_func: resolvedArgs => {
|
|
6482
5073
|
const arg = valueOf(resolvedArgs[0]);
|
|
@@ -6485,19 +5076,6 @@ function functions(
|
|
|
6485
5076
|
},
|
|
6486
5077
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6487
5078
|
},
|
|
6488
|
-
|
|
6489
|
-
/**
|
|
6490
|
-
* Returns a convolved (zipped) array containing grouped arrays of values from
|
|
6491
|
-
* the array arguments from index 0, 1, 2, etc.
|
|
6492
|
-
* This function accepts a variable number of arguments.
|
|
6493
|
-
* The length of the returned array is equal to the length of the shortest array.
|
|
6494
|
-
* @param {...array} arrays array of arrays to zip together
|
|
6495
|
-
* @return {array} An array of arrays with elements zipped together
|
|
6496
|
-
* @function zip
|
|
6497
|
-
* @example
|
|
6498
|
-
* zip([1, 2, 3], [4, 5, 6]) //returns [[1, 4], [2, 5], [3, 6]]
|
|
6499
|
-
* @category jmespath
|
|
6500
|
-
*/
|
|
6501
5079
|
zip: {
|
|
6502
5080
|
_func: args => {
|
|
6503
5081
|
const count = args.reduce((min, current) => Math.min(min, current.length), args[0].length);
|
|
@@ -6516,17 +5094,13 @@ function functions(
|
|
|
6516
5094
|
return functionMap;
|
|
6517
5095
|
}
|
|
6518
5096
|
|
|
6519
|
-
/* eslint-disable max-classes-per-file */
|
|
6520
|
-
|
|
6521
|
-
// Type constants used to define functions.
|
|
6522
5097
|
const {
|
|
6523
5098
|
TYPE_CLASS,
|
|
6524
5099
|
TYPE_ANY,
|
|
6525
5100
|
} = dataTypes;
|
|
6526
|
-
|
|
6527
5101
|
function getToNumber(stringToNumber, debug = []) {
|
|
6528
5102
|
return value => {
|
|
6529
|
-
const n = getValueOf(value);
|
|
5103
|
+
const n = getValueOf(value);
|
|
6530
5104
|
if (n === null) return null;
|
|
6531
5105
|
if (n instanceof Array) {
|
|
6532
5106
|
debug.push('Converted array to zero');
|
|
@@ -6542,26 +5116,20 @@ function getToNumber(stringToNumber, debug = []) {
|
|
|
6542
5116
|
}
|
|
6543
5117
|
function toString(a) {
|
|
6544
5118
|
if (a === null || a === undefined) return '';
|
|
6545
|
-
// don't call a 'toString' method, since we could have a child named 'toString()'
|
|
6546
5119
|
return a.toString();
|
|
6547
5120
|
}
|
|
6548
|
-
|
|
6549
5121
|
const defaultStringToNumber = (str => {
|
|
6550
5122
|
const n = +str;
|
|
6551
5123
|
return Number.isNaN(n) ? 0 : n;
|
|
6552
5124
|
});
|
|
6553
|
-
|
|
6554
5125
|
function isClass(obj) {
|
|
6555
5126
|
if (obj === null) return false;
|
|
6556
5127
|
if (Array.isArray(obj)) return false;
|
|
6557
5128
|
return obj.constructor.name !== 'Object';
|
|
6558
5129
|
}
|
|
6559
|
-
|
|
6560
5130
|
function matchClass(arg, expectedList) {
|
|
6561
|
-
// checking isClass() generates a dependency -- so call it only if necessary
|
|
6562
5131
|
return expectedList.includes(TYPE_CLASS) && isClass(arg);
|
|
6563
5132
|
}
|
|
6564
|
-
|
|
6565
5133
|
class Runtime {
|
|
6566
5134
|
constructor(debug, toNumber, customFunctions = {}) {
|
|
6567
5135
|
this.strictDeepEqual = strictDeepEqual;
|
|
@@ -6576,25 +5144,16 @@ class Runtime {
|
|
|
6576
5144
|
toString,
|
|
6577
5145
|
debug,
|
|
6578
5146
|
);
|
|
6579
|
-
|
|
6580
5147
|
Object.entries(
|
|
6581
5148
|
openFormulaFunctions(getValueOf, toString, toNumber, debug),
|
|
6582
5149
|
).forEach(([fname, func]) => {
|
|
6583
5150
|
this.functionTable[fname] = func;
|
|
6584
5151
|
});
|
|
6585
|
-
|
|
6586
5152
|
Object.entries(customFunctions).forEach(([fname, func]) => {
|
|
6587
5153
|
this.functionTable[fname] = func;
|
|
6588
5154
|
});
|
|
6589
5155
|
}
|
|
6590
|
-
|
|
6591
|
-
// eslint-disable-next-line class-methods-use-this
|
|
6592
5156
|
_validateArgs(argName, args, signature, bResolved) {
|
|
6593
|
-
// Validating the args requires validating
|
|
6594
|
-
// the correct arity and the correct type of each arg.
|
|
6595
|
-
// If the last argument is declared as variadic, then we need
|
|
6596
|
-
// a minimum number of args to be required. Otherwise it has to
|
|
6597
|
-
// be an exact amount.
|
|
6598
5157
|
if (signature.length === 0) {
|
|
6599
5158
|
return;
|
|
6600
5159
|
}
|
|
@@ -6613,39 +5172,31 @@ class Runtime {
|
|
|
6613
5172
|
+ `takes ${signature.length}${pluralized
|
|
6614
5173
|
} but received ${args.length}`);
|
|
6615
5174
|
}
|
|
6616
|
-
// if the arguments are unresolved, there's no point in validating types
|
|
6617
5175
|
if (!bResolved) return;
|
|
6618
5176
|
let currentSpec;
|
|
6619
5177
|
let actualType;
|
|
6620
5178
|
const limit = Math.min(signature.length, args.length);
|
|
6621
5179
|
for (let i = 0; i < limit; i += 1) {
|
|
6622
5180
|
currentSpec = signature[i].types;
|
|
6623
|
-
// Try to avoid checks that will introspect the object and generate dependencies
|
|
6624
5181
|
if (!matchClass(args[i], currentSpec) && !currentSpec.includes(TYPE_ANY)) {
|
|
6625
5182
|
actualType = getTypeNames(args[i]);
|
|
6626
|
-
// eslint-disable-next-line no-param-reassign
|
|
6627
5183
|
args[i] = matchType(actualType, currentSpec, args[i], argName, this.toNumber, toString);
|
|
6628
5184
|
}
|
|
6629
5185
|
}
|
|
6630
5186
|
}
|
|
6631
|
-
|
|
6632
5187
|
callFunction(name, resolvedArgs, data, interpreter, bResolved = true) {
|
|
6633
|
-
// this check will weed out 'valueOf', 'toString' etc
|
|
6634
5188
|
if (!Object.prototype.hasOwnProperty.call(this.functionTable, name)) throw new Error(`Unknown function: ${name}()`);
|
|
6635
|
-
|
|
6636
5189
|
const functionEntry = this.functionTable[name];
|
|
6637
5190
|
this._validateArgs(name, resolvedArgs, functionEntry._signature, bResolved);
|
|
6638
5191
|
return functionEntry._func.call(this, resolvedArgs, data, interpreter);
|
|
6639
5192
|
}
|
|
6640
5193
|
}
|
|
6641
|
-
|
|
6642
5194
|
class Formula {
|
|
6643
5195
|
constructor(debug, customFunctions, stringToNumberFn) {
|
|
6644
5196
|
this.debug = debug;
|
|
6645
5197
|
this.toNumber = getToNumber(stringToNumberFn || defaultStringToNumber, debug);
|
|
6646
5198
|
this.runtime = new Runtime(debug, this.toNumber, customFunctions);
|
|
6647
5199
|
}
|
|
6648
|
-
|
|
6649
5200
|
compile(stream, allowedGlobalNames = []) {
|
|
6650
5201
|
let ast;
|
|
6651
5202
|
try {
|
|
@@ -6657,11 +5208,7 @@ class Formula {
|
|
|
6657
5208
|
}
|
|
6658
5209
|
return ast;
|
|
6659
5210
|
}
|
|
6660
|
-
|
|
6661
5211
|
search(node, data, globals = {}, language = 'en-US') {
|
|
6662
|
-
// This needs to be improved. Both the interpreter and runtime depend on
|
|
6663
|
-
// each other. The runtime needs the interpreter to support exprefs.
|
|
6664
|
-
// There's likely a clean way to avoid the cyclic dependency.
|
|
6665
5212
|
this.runtime.interpreter = new TreeInterpreter(
|
|
6666
5213
|
this.runtime,
|
|
6667
5214
|
globals,
|
|
@@ -6670,7 +5217,6 @@ class Formula {
|
|
|
6670
5217
|
this.debug,
|
|
6671
5218
|
language,
|
|
6672
5219
|
);
|
|
6673
|
-
|
|
6674
5220
|
try {
|
|
6675
5221
|
return this.runtime.interpreter.search(node, data);
|
|
6676
5222
|
} catch (e) {
|
|
@@ -6680,33 +5226,7 @@ class Formula {
|
|
|
6680
5226
|
}
|
|
6681
5227
|
}
|
|
6682
5228
|
|
|
6683
|
-
/*
|
|
6684
|
-
Copyright 2021 Adobe. All rights reserved.
|
|
6685
|
-
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
6686
|
-
you may not use this file except in compliance with the License. You may obtain a copy
|
|
6687
|
-
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6688
|
-
|
|
6689
|
-
Unless required by applicable law or agreed to in writing, software distributed under
|
|
6690
|
-
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
6691
|
-
OF ANY KIND, either express or implied. See the License for the specific language
|
|
6692
|
-
governing permissions and limitations under the License.
|
|
6693
|
-
*/
|
|
6694
|
-
|
|
6695
|
-
/**
|
|
6696
|
-
* Returns an instance of JSON JsonFormula Expression that can be executed later on with
|
|
6697
|
-
* multiple instances of JSON Data. The instance of the class has a single search
|
|
6698
|
-
* function that can be used to evaluate the expression on a json payload. The advantage
|
|
6699
|
-
* of using this over {jsonJsonFormula} function is that it can be performant if a single expression
|
|
6700
|
-
* has to be used for multiple json data instances.
|
|
6701
|
-
*/
|
|
6702
5229
|
class JsonFormula {
|
|
6703
|
-
/**
|
|
6704
|
-
* @param customFunctions {*} custom functions needed by a hosting application.
|
|
6705
|
-
* @param stringToNumber {function} A function that converts string values to numbers.
|
|
6706
|
-
* Can be used to convert currencies/dates to numbers
|
|
6707
|
-
* @param language
|
|
6708
|
-
* @param debug {array} will be populated with any errors/warnings
|
|
6709
|
-
*/
|
|
6710
5230
|
constructor(
|
|
6711
5231
|
customFunctions = {},
|
|
6712
5232
|
stringToNumber = null,
|
|
@@ -6717,25 +5237,10 @@ class JsonFormula {
|
|
|
6717
5237
|
this.debug = debug;
|
|
6718
5238
|
this.formula = new Formula(debug, customFunctions, stringToNumber);
|
|
6719
5239
|
}
|
|
6720
|
-
|
|
6721
|
-
/**
|
|
6722
|
-
* Evaluates the JsonFormula on a particular json payload and return the result
|
|
6723
|
-
* @param json {object} the json data on which the expression needs to be evaluated
|
|
6724
|
-
* @param globals {*} global objects that can be accessed via custom functions.
|
|
6725
|
-
* @returns {*} the result of the expression being evaluated
|
|
6726
|
-
*/
|
|
6727
5240
|
search(expression, json, globals = {}, language = 'en-US') {
|
|
6728
5241
|
const ast = this.compile(expression, Object.keys(globals));
|
|
6729
5242
|
return this.run(ast, json, language, globals);
|
|
6730
5243
|
}
|
|
6731
|
-
|
|
6732
|
-
/**
|
|
6733
|
-
* Execute a previously compiled expression against a json object and return the result
|
|
6734
|
-
* @param ast {object} The abstract syntax tree returned from compile()
|
|
6735
|
-
* @param json {object} the json data on which the expression needs to be evaluated
|
|
6736
|
-
* @param globals {*} set of objects available in global scope
|
|
6737
|
-
* @returns {*} the result of the expression being evaluated
|
|
6738
|
-
*/
|
|
6739
5244
|
run(ast, json, language, globals) {
|
|
6740
5245
|
return this.formula.search(
|
|
6741
5246
|
ast,
|
|
@@ -6744,14 +5249,6 @@ class JsonFormula {
|
|
|
6744
5249
|
language,
|
|
6745
5250
|
);
|
|
6746
5251
|
}
|
|
6747
|
-
|
|
6748
|
-
/*
|
|
6749
|
-
* Creates a compiled expression that can be executed later on with some data.
|
|
6750
|
-
* @param expression {string} the expression to evaluate
|
|
6751
|
-
* @param allowedGlobalNames {string[]} A list of names of the global variables
|
|
6752
|
-
* being used in the expression.
|
|
6753
|
-
* @param debug {array} will be populated with any errors/warnings
|
|
6754
|
-
*/
|
|
6755
5252
|
compile(expression, allowedGlobalNames = []) {
|
|
6756
5253
|
this.debug.length = 0;
|
|
6757
5254
|
return this.formula.compile(expression, allowedGlobalNames);
|
|
@@ -6804,7 +5301,8 @@ class RuleEngine {
|
|
|
6804
5301
|
}
|
|
6805
5302
|
|
|
6806
5303
|
const defaults = {
|
|
6807
|
-
visible: true
|
|
5304
|
+
visible: true,
|
|
5305
|
+
enabled: true
|
|
6808
5306
|
};
|
|
6809
5307
|
class Fieldset extends Container {
|
|
6810
5308
|
constructor(params, _options) {
|
|
@@ -6847,12 +5345,6 @@ class Fieldset extends Container {
|
|
|
6847
5345
|
}
|
|
6848
5346
|
}
|
|
6849
5347
|
|
|
6850
|
-
var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
6851
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6852
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
6853
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6854
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6855
|
-
};
|
|
6856
5348
|
class InstanceManager extends Fieldset {
|
|
6857
5349
|
get maxOccur() {
|
|
6858
5350
|
return this._jsonModel.maxItems;
|
|
@@ -6870,13 +5362,22 @@ class InstanceManager extends Fieldset {
|
|
|
6870
5362
|
return this.removeItem(action);
|
|
6871
5363
|
}
|
|
6872
5364
|
}
|
|
6873
|
-
__decorate
|
|
5365
|
+
__decorate([
|
|
6874
5366
|
dependencyTracked()
|
|
6875
5367
|
], InstanceManager.prototype, "maxOccur", null);
|
|
6876
|
-
__decorate
|
|
5368
|
+
__decorate([
|
|
6877
5369
|
dependencyTracked()
|
|
6878
5370
|
], InstanceManager.prototype, "minOccur", null);
|
|
6879
5371
|
|
|
5372
|
+
class ValidationError {
|
|
5373
|
+
fieldName;
|
|
5374
|
+
errorMessages;
|
|
5375
|
+
constructor(fieldName = '', errorMessages = []) {
|
|
5376
|
+
this.errorMessages = errorMessages;
|
|
5377
|
+
this.fieldName = fieldName;
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
|
|
6880
5381
|
const dateRegex = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
|
|
6881
5382
|
const days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
6882
5383
|
const daysInMonth = (leapYear, month) => {
|
|
@@ -7150,33 +5651,9 @@ const Constraints = {
|
|
|
7150
5651
|
}
|
|
7151
5652
|
};
|
|
7152
5653
|
|
|
7153
|
-
/*************************************************************************
|
|
7154
|
-
* ADOBE CONFIDENTIAL
|
|
7155
|
-
* ___________________
|
|
7156
|
-
*
|
|
7157
|
-
* Copyright 2022 Adobe
|
|
7158
|
-
* All Rights Reserved.
|
|
7159
|
-
*
|
|
7160
|
-
* NOTICE: All information contained herein is, and remains
|
|
7161
|
-
* the property of Adobe and its suppliers, if any. The intellectual
|
|
7162
|
-
* and technical concepts contained herein are proprietary to Adobe
|
|
7163
|
-
* and its suppliers and are protected by all applicable intellectual
|
|
7164
|
-
* property laws, including trade secret and copyright laws.
|
|
7165
|
-
* Dissemination of this information or reproduction of this material
|
|
7166
|
-
* is strictly forbidden unless prior written permission is obtained
|
|
7167
|
-
* from Adobe.
|
|
7168
|
-
**************************************************************************/
|
|
7169
|
-
/**
|
|
7170
|
-
* https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
|
|
7171
|
-
* Credit: https://git.corp.adobe.com/dc/dfl/blob/master/src/patterns/parseDateTimeSkeleton.js
|
|
7172
|
-
* Created a separate library to be used elsewhere as well.
|
|
7173
|
-
*/
|
|
7174
5654
|
const DATE_TIME_REGEX =
|
|
7175
|
-
// eslint-disable-next-line max-len
|
|
7176
5655
|
/(?:[Eec]{1,6}|G{1,5}|[Qq]{1,5}|(?:[yYur]+|U{1,5})|[ML]{1,5}|d{1,2}|D{1,3}|F{1}|[abB]{1,5}|[hkHK]{1,2}|w{1,2}|W{1}|m{1,2}|s{1,2}|[zZOvV]{1,5}|[zZOvVxX]{1,3}|S{1,3}|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
7177
|
-
|
|
7178
5656
|
const ShorthandStyles$1 = ["full", "long", "medium", "short"];
|
|
7179
|
-
|
|
7180
5657
|
function getSkeleton(skeleton, language) {
|
|
7181
5658
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7182
5659
|
const parsed = parseDateStyle(skeleton, language);
|
|
@@ -7197,24 +5674,13 @@ function getSkeleton(skeleton, language) {
|
|
|
7197
5674
|
}
|
|
7198
5675
|
return skeleton;
|
|
7199
5676
|
}
|
|
7200
|
-
|
|
7201
|
-
/**
|
|
7202
|
-
*
|
|
7203
|
-
* @param skeleton shorthand style for the date concatenated with shorthand style of time. The
|
|
7204
|
-
* Shorthand style for both date and time is one of ['full', 'long', 'medium', 'short'].
|
|
7205
|
-
* @param language {string} language to parse the date shorthand style
|
|
7206
|
-
* @returns {[*,string][]}
|
|
7207
|
-
*/
|
|
7208
5677
|
function parseDateStyle(skeleton, language) {
|
|
7209
5678
|
const options = {};
|
|
7210
|
-
// the skeleton could have two keywords -- one for date, one for time
|
|
7211
5679
|
const styles = skeleton.split(/\s/).filter(s => s.length);
|
|
7212
5680
|
options.dateStyle = styles[0];
|
|
7213
5681
|
if (styles.length > 1) options.timeStyle = styles[1];
|
|
7214
|
-
|
|
7215
5682
|
const testDate = new Date(2000, 2, 1, 2, 3, 4);
|
|
7216
5683
|
const parts = new Intl.DateTimeFormat(language, options).formatToParts(testDate);
|
|
7217
|
-
// oddly, the formatted month name can be different from the standalone month name
|
|
7218
5684
|
const formattedMarch = parts.find(p => p.type === 'month').value;
|
|
7219
5685
|
const longMarch = new Intl.DateTimeFormat(language, {month: 'long'}).formatToParts(testDate)[0].value;
|
|
7220
5686
|
const shortMarch = new Intl.DateTimeFormat(language, {month: 'short'}).formatToParts(testDate)[0].value;
|
|
@@ -7238,11 +5704,6 @@ function parseDateStyle(skeleton, language) {
|
|
|
7238
5704
|
});
|
|
7239
5705
|
return result;
|
|
7240
5706
|
}
|
|
7241
|
-
|
|
7242
|
-
/**
|
|
7243
|
-
* Parse Date time skeleton into Intl.DateTimeFormatOptions parts
|
|
7244
|
-
* Ref: https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
|
|
7245
|
-
*/
|
|
7246
5707
|
function parseDateTimeSkeleton(skeleton, language) {
|
|
7247
5708
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7248
5709
|
return parseDateStyle(skeleton, language);
|
|
@@ -7251,11 +5712,9 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7251
5712
|
skeleton.replace(DATE_TIME_REGEX, match => {
|
|
7252
5713
|
const len = match.length;
|
|
7253
5714
|
switch (match[0]) {
|
|
7254
|
-
// Era
|
|
7255
5715
|
case 'G':
|
|
7256
5716
|
result.push(['era', len === 4 ? 'long' : len === 5 ? 'narrow' : 'short', len]);
|
|
7257
5717
|
break;
|
|
7258
|
-
// Year
|
|
7259
5718
|
case 'y':
|
|
7260
5719
|
result.push(['year', len === 2 ? '2-digit' : 'numeric', len]);
|
|
7261
5720
|
break;
|
|
@@ -7266,16 +5725,13 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7266
5725
|
throw new RangeError(
|
|
7267
5726
|
'`Y/u/U/r` (year) patterns are not supported, use `y` instead'
|
|
7268
5727
|
);
|
|
7269
|
-
// Quarter
|
|
7270
5728
|
case 'q':
|
|
7271
5729
|
case 'Q':
|
|
7272
5730
|
throw new RangeError('`q/Q` (quarter) patterns are not supported');
|
|
7273
|
-
// Month
|
|
7274
5731
|
case 'M':
|
|
7275
5732
|
case 'L':
|
|
7276
5733
|
result.push(['month', ['numeric', '2-digit', 'short', 'long', 'narrow'][len - 1], len]);
|
|
7277
5734
|
break;
|
|
7278
|
-
// Week
|
|
7279
5735
|
case 'w':
|
|
7280
5736
|
case 'W':
|
|
7281
5737
|
throw new RangeError('`w/W` (week) patterns are not supported');
|
|
@@ -7288,7 +5744,6 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7288
5744
|
throw new RangeError(
|
|
7289
5745
|
'`D/F/g` (day) patterns are not supported, use `d` instead'
|
|
7290
5746
|
);
|
|
7291
|
-
// Weekday
|
|
7292
5747
|
case 'E':
|
|
7293
5748
|
result.push(['weekday', ['short', 'short', 'short', 'long', 'narrow', 'narrow'][len - 1], len]);
|
|
7294
5749
|
break;
|
|
@@ -7304,16 +5759,14 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7304
5759
|
}
|
|
7305
5760
|
result.push(['weekday', ['short', 'long', 'narrow', 'short'][len - 3], len]);
|
|
7306
5761
|
break;
|
|
7307
|
-
|
|
7308
|
-
case 'a': // AM, PM
|
|
5762
|
+
case 'a':
|
|
7309
5763
|
result.push(['hour12', true, 1]);
|
|
7310
5764
|
break;
|
|
7311
|
-
case 'b':
|
|
7312
|
-
case 'B':
|
|
5765
|
+
case 'b':
|
|
5766
|
+
case 'B':
|
|
7313
5767
|
throw new RangeError(
|
|
7314
5768
|
'`b/B` (period) patterns are not supported, use `a` instead'
|
|
7315
5769
|
);
|
|
7316
|
-
// Hour
|
|
7317
5770
|
case 'h':
|
|
7318
5771
|
result.push(['hourCycle', 'h12']);
|
|
7319
5772
|
result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
|
|
@@ -7336,11 +5789,9 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7336
5789
|
throw new RangeError(
|
|
7337
5790
|
'`j/J/C` (hour) patterns are not supported, use `h/H/K/k` instead'
|
|
7338
5791
|
);
|
|
7339
|
-
// Minute
|
|
7340
5792
|
case 'm':
|
|
7341
5793
|
result.push(['minute', ['numeric', '2-digit'][len - 1], len]);
|
|
7342
5794
|
break;
|
|
7343
|
-
// Second
|
|
7344
5795
|
case 's':
|
|
7345
5796
|
result.push(['second', ['numeric', '2-digit'][len - 1], len]);
|
|
7346
5797
|
break;
|
|
@@ -7351,23 +5802,19 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7351
5802
|
throw new RangeError(
|
|
7352
5803
|
'`S/A` (millisecond) patterns are not supported, use `s` instead'
|
|
7353
5804
|
);
|
|
7354
|
-
|
|
7355
|
-
case 'O': // timeZone GMT-8 or GMT-08:00
|
|
5805
|
+
case 'O':
|
|
7356
5806
|
result.push(['timeZoneName', len < 4 ? 'shortOffset' : 'longOffset', len]);
|
|
7357
5807
|
result.push(['x-timeZoneName', len < 4 ? 'O' : 'OOOO', len]);
|
|
7358
5808
|
break;
|
|
7359
|
-
case 'X':
|
|
7360
|
-
case 'x':
|
|
7361
|
-
case 'Z':
|
|
7362
|
-
// Z, ZZ, ZZZ should produce -0800
|
|
7363
|
-
// ZZZZ should produce GMT-08:00
|
|
7364
|
-
// ZZZZZ should produce -8:00 or -07:52:58
|
|
5809
|
+
case 'X':
|
|
5810
|
+
case 'x':
|
|
5811
|
+
case 'Z':
|
|
7365
5812
|
result.push(['timeZoneName', 'longOffset', 1]);
|
|
7366
5813
|
result.push(['x-timeZoneName', match, 1]);
|
|
7367
5814
|
break;
|
|
7368
|
-
case 'z':
|
|
7369
|
-
case 'v':
|
|
7370
|
-
case 'V':
|
|
5815
|
+
case 'z':
|
|
5816
|
+
case 'v':
|
|
5817
|
+
case 'V':
|
|
7371
5818
|
throw new RangeError(
|
|
7372
5819
|
'z/v/V` (timeZone) patterns are not supported, use `X/x/Z/O` instead'
|
|
7373
5820
|
);
|
|
@@ -7382,29 +5829,6 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7382
5829
|
return result;
|
|
7383
5830
|
}
|
|
7384
5831
|
|
|
7385
|
-
/*************************************************************************
|
|
7386
|
-
* ADOBE CONFIDENTIAL
|
|
7387
|
-
* ___________________
|
|
7388
|
-
*
|
|
7389
|
-
* Copyright 2022 Adobe
|
|
7390
|
-
* All Rights Reserved.
|
|
7391
|
-
*
|
|
7392
|
-
* NOTICE: All information contained herein is, and remains
|
|
7393
|
-
* the property of Adobe and its suppliers, if any. The intellectual
|
|
7394
|
-
* and technical concepts contained herein are proprietary to Adobe
|
|
7395
|
-
* and its suppliers and are protected by all applicable intellectual
|
|
7396
|
-
* property laws, including trade secret and copyright laws.
|
|
7397
|
-
* Dissemination of this information or reproduction of this material
|
|
7398
|
-
* is strictly forbidden unless prior written permission is obtained
|
|
7399
|
-
* from Adobe.
|
|
7400
|
-
**************************************************************************/
|
|
7401
|
-
|
|
7402
|
-
/**
|
|
7403
|
-
* in some cases, DateTimeFormat doesn't respect the 'numeric' vs. '2-digit' setting
|
|
7404
|
-
* for time values. The function corrects that
|
|
7405
|
-
* @param formattedParts instance of Intl.DateTimeFormatPart[]
|
|
7406
|
-
* @param parsed
|
|
7407
|
-
*/
|
|
7408
5832
|
function fixDigits(formattedParts, parsed) {
|
|
7409
5833
|
['hour', 'minute', 'second'].forEach(type => {
|
|
7410
5834
|
const defn = formattedParts.find(f => f.type === type);
|
|
@@ -7414,55 +5838,29 @@ function fixDigits(formattedParts, parsed) {
|
|
|
7414
5838
|
if (fmt === 'numeric' && defn.value.length === 2 && defn.value.charAt(0) === '0') defn.value = defn.value.slice(1);
|
|
7415
5839
|
});
|
|
7416
5840
|
}
|
|
7417
|
-
|
|
7418
5841
|
function fixYear(formattedParts, parsed) {
|
|
7419
|
-
// two digit years are handled differently in DateTimeFormat. 00 becomes 1900
|
|
7420
|
-
// providing a two digit year 0010 gets formatted to 10 and when parsed becomes 1910
|
|
7421
|
-
// Hence we need to pad the year with 0 as required by the skeleton and mentioned in
|
|
7422
|
-
// unicode. https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-year
|
|
7423
5842
|
const defn = formattedParts.find(f => f.type === 'year');
|
|
7424
5843
|
if (!defn) return;
|
|
7425
|
-
// eslint-disable-next-line no-unused-vars
|
|
7426
5844
|
const chars = parsed.find(pair => pair[0] === 'year')[2];
|
|
7427
5845
|
while(defn.value.length < chars) {
|
|
7428
5846
|
defn.value = `0${defn.value}`;
|
|
7429
5847
|
}
|
|
7430
5848
|
}
|
|
7431
|
-
|
|
7432
|
-
/**
|
|
7433
|
-
*
|
|
7434
|
-
* @param dateValue {Date}
|
|
7435
|
-
* @param language {string}
|
|
7436
|
-
* @param skeleton {string}
|
|
7437
|
-
* @param timeZone {string}
|
|
7438
|
-
* @returns {T}
|
|
7439
|
-
*/
|
|
7440
5849
|
function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
7441
|
-
// DateTimeFormat renames some of the options in its formatted output
|
|
7442
|
-
//@ts-ignore
|
|
7443
5850
|
const mappings = key => ({
|
|
7444
5851
|
hour12: 'dayPeriod',
|
|
7445
5852
|
fractionalSecondDigits: 'fractionalSecond',
|
|
7446
5853
|
})[key] || key;
|
|
7447
|
-
|
|
7448
|
-
// produces an array of name/value pairs of skeleton parts
|
|
7449
5854
|
const allParameters = parseDateTimeSkeleton(skeleton, language);
|
|
7450
5855
|
allParameters.push(['timeZone', timeZone]);
|
|
7451
|
-
|
|
7452
5856
|
const parsed = allParameters.filter(p => !p[0].startsWith('x-'));
|
|
7453
5857
|
const nonStandard = allParameters.filter(p => p[0].startsWith('x-'));
|
|
7454
|
-
// reduce to a set of options that can be used to format
|
|
7455
5858
|
const options = Object.fromEntries(parsed);
|
|
7456
5859
|
delete options.literal;
|
|
7457
|
-
|
|
7458
5860
|
const df = new Intl.DateTimeFormat(language, options);
|
|
7459
|
-
// formattedParts will have all the pieces we need for our date -- but not in the correct order
|
|
7460
5861
|
const formattedParts = df.formatToParts(dateValue);
|
|
7461
|
-
|
|
7462
5862
|
fixDigits(formattedParts, allParameters);
|
|
7463
5863
|
fixYear(formattedParts, parsed);
|
|
7464
|
-
// iterate through the original parsed components and use its ordering and literals,
|
|
7465
|
-
// and add the formatted pieces
|
|
7466
5864
|
return parsed.reduce((result, cur) => {
|
|
7467
5865
|
if (cur[0] === 'literal') result.push(cur);
|
|
7468
5866
|
else {
|
|
@@ -7472,37 +5870,25 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
7472
5870
|
const category = tz[0];
|
|
7473
5871
|
if (category === 'Z') {
|
|
7474
5872
|
if (tz.length < 4) {
|
|
7475
|
-
// handle 'Z', 'ZZ', 'ZZZ' Time Zone: ISO8601 basic hms? / RFC 822
|
|
7476
5873
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
7477
5874
|
if (v.value === '') v.value = '+0000';
|
|
7478
5875
|
} else if (tz.length === 5) {
|
|
7479
|
-
// 'ZZZZZ' Time Zone: ISO8601 extended hms?
|
|
7480
5876
|
if (v.value === 'GMT') v.value = 'Z';
|
|
7481
5877
|
else v.value = v.value.replace(/GMT/, '');
|
|
7482
5878
|
}
|
|
7483
5879
|
}
|
|
7484
5880
|
if (category === 'X' || category === 'x') {
|
|
7485
5881
|
if (tz.length === 1) {
|
|
7486
|
-
// 'X' ISO8601 basic hm?, with Z for 0
|
|
7487
|
-
// -08, +0530, Z
|
|
7488
|
-
// 'x' ISO8601 basic hm?, without Z for 0
|
|
7489
5882
|
v.value = v.value.replace(/(GMT|:(00)?)/g, '');
|
|
7490
5883
|
}
|
|
7491
5884
|
if (tz.length === 2) {
|
|
7492
|
-
// 'XX' ISO8601 basic hm, with Z
|
|
7493
|
-
// -0800, Z
|
|
7494
|
-
// 'xx' ISO8601 basic hm, without Z
|
|
7495
5885
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
7496
5886
|
}
|
|
7497
5887
|
if (tz.length === 3) {
|
|
7498
|
-
// 'XXX' ISO8601 extended hm, with Z
|
|
7499
|
-
// -08:00, Z
|
|
7500
|
-
// 'xxx' ISO8601 extended hm, without Z
|
|
7501
5888
|
v.value = v.value.replace(/GMT/g, '');
|
|
7502
5889
|
}
|
|
7503
5890
|
if (category === 'X' && v.value === '') v.value = 'Z';
|
|
7504
5891
|
} else if (tz === 'O') {
|
|
7505
|
-
// eliminate 'GMT', leading and trailing zeros
|
|
7506
5892
|
v.value = v.value.replace(/GMT/g, '').replace(/0(\d+):/, '$1:').replace(/:00/, '');
|
|
7507
5893
|
if (v.value === '') v.value = '+0';
|
|
7508
5894
|
}
|
|
@@ -7512,18 +5898,12 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
7512
5898
|
return result;
|
|
7513
5899
|
}, []);
|
|
7514
5900
|
}
|
|
7515
|
-
|
|
7516
|
-
/**
|
|
7517
|
-
*
|
|
7518
|
-
* @param dateValue {Date}
|
|
7519
|
-
* @param language {string}
|
|
7520
|
-
* @param skeleton {string}
|
|
7521
|
-
* @param timeZone {string}
|
|
7522
|
-
*/
|
|
7523
5901
|
function formatDate(dateValue, language, skeleton, timeZone) {
|
|
5902
|
+
if (skeleton.startsWith('date|')) {
|
|
5903
|
+
skeleton = skeleton.split('|')[1];
|
|
5904
|
+
}
|
|
7524
5905
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7525
5906
|
const options = {timeZone};
|
|
7526
|
-
// the skeleton could have two keywords -- one for date, one for time
|
|
7527
5907
|
const parts = skeleton.split(/\s/).filter(s => s.length);
|
|
7528
5908
|
if (ShorthandStyles$1.indexOf(parts[0]) > -1) {
|
|
7529
5909
|
options.dateStyle = parts[0];
|
|
@@ -7559,9 +5939,7 @@ const currencies = {
|
|
|
7559
5939
|
'ru-RU': 'RUB',
|
|
7560
5940
|
'tr-TR': 'TRY'
|
|
7561
5941
|
};
|
|
7562
|
-
|
|
7563
5942
|
const locales = Object.keys(currencies);
|
|
7564
|
-
|
|
7565
5943
|
const getCurrency = function (locale) {
|
|
7566
5944
|
if (locales.indexOf(locale) > -1) {
|
|
7567
5945
|
return currencies[locale]
|
|
@@ -7575,8 +5953,7 @@ const getCurrency = function (locale) {
|
|
|
7575
5953
|
};
|
|
7576
5954
|
|
|
7577
5955
|
const NUMBER_REGEX =
|
|
7578
|
-
|
|
7579
|
-
/(?:[#]+|[@]+(?:#+)?|[0]+|[,]|[.]|[-]|[+]|[%]|[¤]{1,4}(?:\/([a-zA-Z]{3}))?|[;]|[K]{1,2}|E{1,2}[+]?|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
5956
|
+
/(?:[#]+|[@]+(#+)?|[0]+|[,]|[.]|[-]|[+]|[%]|[¤]{1,4}(?:\/([a-zA-Z]{3}))?|[;]|[K]{1,2}|E{1,2}[+]?|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
7580
5957
|
const supportedUnits = ['acre', 'bit', 'byte', 'celsius', 'centimeter', 'day',
|
|
7581
5958
|
'degree', 'fahrenheit', 'fluid-ounce', 'foot', 'gallon', 'gigabit',
|
|
7582
5959
|
'gigabyte', 'gram', 'hectare', 'hour', 'inch', 'kilobit', 'kilobyte',
|
|
@@ -7584,8 +5961,6 @@ const supportedUnits = ['acre', 'bit', 'byte', 'celsius', 'centimeter', 'day',
|
|
|
7584
5961
|
'mile-scandinavian', 'milliliter', 'millimeter', 'millisecond', 'minute', 'month',
|
|
7585
5962
|
'ounce', 'percent', 'petabyte', 'pound', 'second', 'stone', 'terabit', 'terabyte', 'week', 'yard', 'year'].join('|');
|
|
7586
5963
|
const ShorthandStyles = [/^currency(?:\/([a-zA-Z]{3}))?$/, /^decimal$/, /^integer$/, /^percent$/, new RegExp(`^unit\/(${supportedUnits})$`)];
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
5964
|
function parseNumberSkeleton(skeleton, language) {
|
|
7590
5965
|
const options = {};
|
|
7591
5966
|
const order = [];
|
|
@@ -7614,6 +5989,7 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7614
5989
|
break;
|
|
7615
5990
|
case 4:
|
|
7616
5991
|
options.style = 'percent';
|
|
5992
|
+
options.maximumFractionDigits = 2;
|
|
7617
5993
|
break;
|
|
7618
5994
|
case 5:
|
|
7619
5995
|
options.style = "unit";
|
|
@@ -7630,7 +6006,7 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7630
6006
|
options.minimumIntegerDigits = 1;
|
|
7631
6007
|
options.maximumFractionDigits = 0;
|
|
7632
6008
|
options.minimumFractionDigits = 0;
|
|
7633
|
-
skeleton.replace(NUMBER_REGEX, (match, offset) => {
|
|
6009
|
+
skeleton.replace(NUMBER_REGEX, (match, maxSignificantDigits, currencySymbol, offset) => {
|
|
7634
6010
|
const len = match.length;
|
|
7635
6011
|
switch(match[0]) {
|
|
7636
6012
|
case '#':
|
|
@@ -7643,10 +6019,10 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7643
6019
|
if (options?.minimumSignificantDigits) {
|
|
7644
6020
|
throw "@ symbol should occur together"
|
|
7645
6021
|
}
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
options.maximumSignificantDigits = len
|
|
6022
|
+
const hashes = maxSignificantDigits || "";
|
|
6023
|
+
order.push(['@', len - hashes.length]);
|
|
6024
|
+
options.minimumSignificantDigits = len - hashes.length;
|
|
6025
|
+
options.maximumSignificantDigits = len;
|
|
7650
6026
|
order.push(['digit', hashes.length]);
|
|
7651
6027
|
break;
|
|
7652
6028
|
case ',':
|
|
@@ -7671,6 +6047,9 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7671
6047
|
}
|
|
7672
6048
|
if (options?.decimal === true) {
|
|
7673
6049
|
options.minimumFractionDigits = len;
|
|
6050
|
+
if (!options.maximumFractionDigits) {
|
|
6051
|
+
options.maximumFractionDigits = len;
|
|
6052
|
+
}
|
|
7674
6053
|
} else {
|
|
7675
6054
|
options.minimumIntegerDigits = len;
|
|
7676
6055
|
}
|
|
@@ -7694,18 +6073,20 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7694
6073
|
case '¤':
|
|
7695
6074
|
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
7696
6075
|
console.error("currency display should be either in the beginning or at the end");
|
|
6076
|
+
} else {
|
|
6077
|
+
options.style = 'currency';
|
|
6078
|
+
options.currencyDisplay = ['symbol', 'code', 'name', 'narrowSymbol'][len - 1];
|
|
6079
|
+
options.currency = currencySymbol || getCurrency(language);
|
|
6080
|
+
order.push(['currency', len]);
|
|
7697
6081
|
}
|
|
7698
|
-
options.style = 'currency';
|
|
7699
|
-
options.currencyDisplay = ['symbol', 'code', 'name', 'narrowSymbol'][len -1];
|
|
7700
|
-
options.currency = getCurrency(language);
|
|
7701
|
-
order.push(['currency', len]);
|
|
7702
6082
|
break;
|
|
7703
6083
|
case '%':
|
|
7704
6084
|
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
7705
6085
|
console.error("percent display should be either in the beginning or at the end");
|
|
6086
|
+
} else {
|
|
6087
|
+
order.push(['%', 1]);
|
|
6088
|
+
options.style = 'percent';
|
|
7706
6089
|
}
|
|
7707
|
-
order.push(['%', 1]);
|
|
7708
|
-
options.style = 'percent';
|
|
7709
6090
|
break;
|
|
7710
6091
|
case 'E':
|
|
7711
6092
|
order.push(['E', len]);
|
|
@@ -7722,6 +6103,9 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7722
6103
|
}
|
|
7723
6104
|
|
|
7724
6105
|
function formatNumber(numberValue, language, skeletn) {
|
|
6106
|
+
if (skeletn.startsWith('num|')) {
|
|
6107
|
+
skeletn = skel.split('|')[1];
|
|
6108
|
+
}
|
|
7725
6109
|
if (!skeletn) return numberValue
|
|
7726
6110
|
language = language || "en";
|
|
7727
6111
|
const {options, order} = parseNumberSkeleton(skeletn, language);
|
|
@@ -7732,7 +6116,6 @@ const getCategory = function (skeleton) {
|
|
|
7732
6116
|
const chkCategory = skeleton?.match(/^(?:(num|date)\|)?(.+)/);
|
|
7733
6117
|
return [chkCategory?.[1], chkCategory?.[2]]
|
|
7734
6118
|
};
|
|
7735
|
-
|
|
7736
6119
|
const format = function (value, locale, skeleton, timezone) {
|
|
7737
6120
|
const [category, skelton] = getCategory(skeleton);
|
|
7738
6121
|
switch (category) {
|
|
@@ -7748,12 +6131,6 @@ const format = function (value, locale, skeleton, timezone) {
|
|
|
7748
6131
|
}
|
|
7749
6132
|
};
|
|
7750
6133
|
|
|
7751
|
-
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
7752
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
7753
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
7754
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
7755
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7756
|
-
};
|
|
7757
6134
|
const validTypes = ['string', 'number', 'boolean', 'file', 'string[]', 'number[]', 'boolean[]', 'file[]', 'array', 'object'];
|
|
7758
6135
|
class Field extends Scriptable {
|
|
7759
6136
|
constructor(params, _options) {
|
|
@@ -7902,10 +6279,10 @@ class Field extends Scriptable {
|
|
|
7902
6279
|
}
|
|
7903
6280
|
}
|
|
7904
6281
|
get editFormat() {
|
|
7905
|
-
return this._jsonModel.editFormat;
|
|
6282
|
+
return this.withCategory(this._jsonModel.editFormat);
|
|
7906
6283
|
}
|
|
7907
6284
|
get displayFormat() {
|
|
7908
|
-
return this._jsonModel.displayFormat;
|
|
6285
|
+
return this.withCategory(this._jsonModel.displayFormat);
|
|
7909
6286
|
}
|
|
7910
6287
|
get placeholder() {
|
|
7911
6288
|
return this._jsonModel.placeholder;
|
|
@@ -7978,31 +6355,43 @@ class Field extends Scriptable {
|
|
|
7978
6355
|
return this._jsonModel.value === undefined || this._jsonModel.value === null || this._jsonModel.value === '';
|
|
7979
6356
|
}
|
|
7980
6357
|
withCategory(df) {
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
if (
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
6358
|
+
if (df) {
|
|
6359
|
+
const hasCategory = df?.match(/^(?:date|num)\|/);
|
|
6360
|
+
if (hasCategory === null) {
|
|
6361
|
+
if (this.format === 'date') {
|
|
6362
|
+
df = `date|${df}`;
|
|
6363
|
+
}
|
|
6364
|
+
else if (this.type === 'number') {
|
|
6365
|
+
df = `num|${df}`;
|
|
6366
|
+
}
|
|
6367
|
+
return df;
|
|
7988
6368
|
}
|
|
7989
|
-
return df;
|
|
7990
6369
|
}
|
|
7991
6370
|
return df;
|
|
7992
6371
|
}
|
|
7993
6372
|
get editValue() {
|
|
7994
|
-
const df = this.
|
|
6373
|
+
const df = this.editFormat;
|
|
7995
6374
|
if (df && this.isNotEmpty(this.value) && this.valid !== false) {
|
|
7996
|
-
|
|
6375
|
+
try {
|
|
6376
|
+
return format(this.value, this.language, df);
|
|
6377
|
+
}
|
|
6378
|
+
catch (e) {
|
|
6379
|
+
return this.value;
|
|
6380
|
+
}
|
|
7997
6381
|
}
|
|
7998
6382
|
else {
|
|
7999
6383
|
return this.value;
|
|
8000
6384
|
}
|
|
8001
6385
|
}
|
|
8002
6386
|
get displayValue() {
|
|
8003
|
-
const df = this.
|
|
6387
|
+
const df = this.displayFormat;
|
|
8004
6388
|
if (df && this.isNotEmpty(this.value) && this.valid !== false) {
|
|
8005
|
-
|
|
6389
|
+
try {
|
|
6390
|
+
return format(this.value, this.language, df);
|
|
6391
|
+
}
|
|
6392
|
+
catch (e) {
|
|
6393
|
+
return this.value;
|
|
6394
|
+
}
|
|
8006
6395
|
}
|
|
8007
6396
|
else {
|
|
8008
6397
|
return this.value;
|
|
@@ -8142,7 +6531,7 @@ class Field extends Scriptable {
|
|
|
8142
6531
|
const iv = this._jsonModel.minimum || this._jsonModel.default || 0;
|
|
8143
6532
|
const fIVal = iv * factor;
|
|
8144
6533
|
const qt = (fVal - fIVal) / fStep;
|
|
8145
|
-
const valid = (fVal - fIVal) % fStep < .001;
|
|
6534
|
+
const valid = Math.abs(fVal - fIVal) % fStep < .001;
|
|
8146
6535
|
let next, prev;
|
|
8147
6536
|
if (!valid) {
|
|
8148
6537
|
next = (Math.ceil(qt) * fStep + fIVal) / factor;
|
|
@@ -8345,6 +6734,8 @@ class Field extends Scriptable {
|
|
|
8345
6734
|
getState() {
|
|
8346
6735
|
return {
|
|
8347
6736
|
...super.getState(),
|
|
6737
|
+
editFormat: this.editFormat,
|
|
6738
|
+
displayFormat: this.displayFormat,
|
|
8348
6739
|
editValue: this.editValue,
|
|
8349
6740
|
displayValue: this.displayValue
|
|
8350
6741
|
};
|