@aemforms/af-core 0.22.26 → 0.22.29
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/lib/cjs/index.cjs +345 -1886
- package/lib/esm/BaseNode-d78cc1b0.js +478 -0
- package/lib/esm/BaseNode.d.ts +1 -1
- 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.d.ts +6 -1
- package/lib/esm/Container.js +108 -19
- 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 +14 -2
- 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',
|
|
@@ -919,7 +775,7 @@ class BaseNode {
|
|
|
919
775
|
const isNonTransparent = this.parent?._jsonModel.type === 'array';
|
|
920
776
|
return !this._jsonModel.name && !isNonTransparent;
|
|
921
777
|
}
|
|
922
|
-
getState() {
|
|
778
|
+
getState(isRepeatableChild = false) {
|
|
923
779
|
return {
|
|
924
780
|
...this._jsonModel,
|
|
925
781
|
properties: this.properties,
|
|
@@ -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;
|
|
@@ -1349,12 +1354,39 @@ class Container extends Scriptable {
|
|
|
1349
1354
|
return true;
|
|
1350
1355
|
}
|
|
1351
1356
|
_activeChild = null;
|
|
1352
|
-
|
|
1357
|
+
isSiteContainer(item) {
|
|
1358
|
+
return ':items' in item;
|
|
1359
|
+
}
|
|
1360
|
+
isAFormField(item) {
|
|
1361
|
+
return ('fieldType' in item || 'id' in item || 'name' in item || 'dataRef' in item || 'type' in item);
|
|
1362
|
+
}
|
|
1363
|
+
getItemsState(isRepeatableChild = false) {
|
|
1364
|
+
if (this._jsonModel.type === 'array' || isRepeatable(this._jsonModel) || isRepeatableChild) {
|
|
1365
|
+
return this._children.map(x => {
|
|
1366
|
+
return { ...x.getState(true) };
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
else {
|
|
1370
|
+
return this._jsonModel.items.map(x => {
|
|
1371
|
+
if (this.isSiteContainer(x)) {
|
|
1372
|
+
return {
|
|
1373
|
+
...x,
|
|
1374
|
+
':items': this.walkSiteContainerItems(x)
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
else if (this.isAFormField(x)) {
|
|
1378
|
+
return { ...this.form.getElement(x?.id).getState(isRepeatableChild) };
|
|
1379
|
+
}
|
|
1380
|
+
else {
|
|
1381
|
+
return x;
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
getState(isRepeatableChild = false) {
|
|
1353
1387
|
return {
|
|
1354
|
-
...super.getState(),
|
|
1355
|
-
items: this.
|
|
1356
|
-
return { ...x.getState() };
|
|
1357
|
-
})
|
|
1388
|
+
...super.getState(isRepeatableChild),
|
|
1389
|
+
items: this.getItemsState(isRepeatableChild)
|
|
1358
1390
|
};
|
|
1359
1391
|
}
|
|
1360
1392
|
_createChild(child, options) {
|
|
@@ -1364,6 +1396,19 @@ class Container extends Scriptable {
|
|
|
1364
1396
|
parent
|
|
1365
1397
|
});
|
|
1366
1398
|
}
|
|
1399
|
+
walkSiteContainerItems(x) {
|
|
1400
|
+
return Object.fromEntries(Object.entries(x[':items']).map(([key, value]) => {
|
|
1401
|
+
if (this.isAFormField(value)) {
|
|
1402
|
+
return [key, this.form.getElement(value?.id).getState()];
|
|
1403
|
+
}
|
|
1404
|
+
else if (this.isSiteContainer(value)) {
|
|
1405
|
+
return this.walkSiteContainerItems(value);
|
|
1406
|
+
}
|
|
1407
|
+
else {
|
|
1408
|
+
return [key, value];
|
|
1409
|
+
}
|
|
1410
|
+
}));
|
|
1411
|
+
}
|
|
1367
1412
|
_addChildToRuleNode(child, options) {
|
|
1368
1413
|
const self = this;
|
|
1369
1414
|
const { parent = this } = options;
|
|
@@ -1403,6 +1448,7 @@ class Container extends Scriptable {
|
|
|
1403
1448
|
...deepClone(itemJson, cloneIds ? () => { return form.getUniqueId(); } : undefined)
|
|
1404
1449
|
};
|
|
1405
1450
|
const retVal = this._createChild(itemTemplate, { parent: this, form: this.form });
|
|
1451
|
+
itemJson.id = retVal.id;
|
|
1406
1452
|
this.form.fieldAdded(retVal);
|
|
1407
1453
|
this._addChildToRuleNode(retVal, { parent: nonTransparentParent });
|
|
1408
1454
|
if (index === this._children.length) {
|
|
@@ -1429,7 +1475,6 @@ class Container extends Scriptable {
|
|
|
1429
1475
|
_initialize() {
|
|
1430
1476
|
super._initialize();
|
|
1431
1477
|
const items = this._jsonModel.items || [];
|
|
1432
|
-
this._jsonModel.items = [];
|
|
1433
1478
|
this._childrenReference = this._jsonModel.type == 'array' ? [] : {};
|
|
1434
1479
|
if (this._jsonModel.type == 'array' && items.length === 1 && this.getDataNode() != null) {
|
|
1435
1480
|
this._itemTemplate = deepClone(items[0]);
|
|
@@ -1443,14 +1488,23 @@ class Container extends Scriptable {
|
|
|
1443
1488
|
this._jsonModel.initialItems = Math.max(1, this._jsonModel.minItems);
|
|
1444
1489
|
}
|
|
1445
1490
|
for (let i = 0; i < this._jsonModel.initialItems; i++) {
|
|
1446
|
-
const child = this._addChild(this._itemTemplate);
|
|
1491
|
+
const child = this._addChild(this._itemTemplate, null, true);
|
|
1492
|
+
items[0].id = child.id;
|
|
1447
1493
|
child._initialize();
|
|
1448
1494
|
}
|
|
1449
1495
|
}
|
|
1450
1496
|
else if (items.length > 0) {
|
|
1451
1497
|
items.forEach((item) => {
|
|
1452
|
-
|
|
1453
|
-
|
|
1498
|
+
if (this.isSiteContainer(item)) {
|
|
1499
|
+
this._initializeSiteContainer(item);
|
|
1500
|
+
}
|
|
1501
|
+
else if (this.isAFormField(item)) {
|
|
1502
|
+
const child = this._addChild(item);
|
|
1503
|
+
child._initialize();
|
|
1504
|
+
}
|
|
1505
|
+
else {
|
|
1506
|
+
this.form.logger.warn('A container item was not initialized.');
|
|
1507
|
+
}
|
|
1454
1508
|
});
|
|
1455
1509
|
this._jsonModel.minItems = this._children.length;
|
|
1456
1510
|
this._jsonModel.maxItems = this._children.length;
|
|
@@ -1461,6 +1515,17 @@ class Container extends Scriptable {
|
|
|
1461
1515
|
}
|
|
1462
1516
|
this.setupRuleNode();
|
|
1463
1517
|
}
|
|
1518
|
+
_initializeSiteContainer(item) {
|
|
1519
|
+
Object.entries(item[':items']).forEach(([key, value]) => {
|
|
1520
|
+
if (this.isAFormField(value)) {
|
|
1521
|
+
const child = this._addChild(value);
|
|
1522
|
+
child._initialize();
|
|
1523
|
+
}
|
|
1524
|
+
else if (this.isSiteContainer(value)) {
|
|
1525
|
+
return this._initializeSiteContainer(value);
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1464
1529
|
addItem(action) {
|
|
1465
1530
|
if ((action.type === 'addItem' || action.type == 'addInstance') && this._itemTemplate != null) {
|
|
1466
1531
|
if ((this._jsonModel.maxItems === -1) || (this._children.length < this._jsonModel.maxItems)) {
|
|
@@ -1514,6 +1579,14 @@ class Container extends Scriptable {
|
|
|
1514
1579
|
}
|
|
1515
1580
|
}
|
|
1516
1581
|
reset() {
|
|
1582
|
+
if (this.type === 'array' || isRepeatable(this._jsonModel)) {
|
|
1583
|
+
if (this.items.length > this._jsonModel.initialItems) {
|
|
1584
|
+
const itemsToBeRemoved = this.items.length - this._jsonModel.initialItems;
|
|
1585
|
+
for (let i = 0; i < itemsToBeRemoved; i++) {
|
|
1586
|
+
this.dispatch(new RemoveItem());
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1517
1590
|
this.items.forEach(x => {
|
|
1518
1591
|
x.reset();
|
|
1519
1592
|
});
|
|
@@ -1576,13 +1649,13 @@ class Container extends Scriptable {
|
|
|
1576
1649
|
}
|
|
1577
1650
|
}
|
|
1578
1651
|
}
|
|
1579
|
-
__decorate
|
|
1652
|
+
__decorate([
|
|
1580
1653
|
dependencyTracked()
|
|
1581
1654
|
], Container.prototype, "maxItems", null);
|
|
1582
|
-
__decorate
|
|
1655
|
+
__decorate([
|
|
1583
1656
|
dependencyTracked()
|
|
1584
1657
|
], Container.prototype, "minItems", null);
|
|
1585
|
-
__decorate
|
|
1658
|
+
__decorate([
|
|
1586
1659
|
dependencyTracked()
|
|
1587
1660
|
], Container.prototype, "activeChild", null);
|
|
1588
1661
|
|
|
@@ -2448,17 +2521,16 @@ class Form extends Container {
|
|
|
2448
2521
|
super.dispatch(action);
|
|
2449
2522
|
}
|
|
2450
2523
|
}
|
|
2451
|
-
executeAction(action) {
|
|
2452
|
-
if ((action.type !== 'submit') || this._invalidFields.length === 0) {
|
|
2453
|
-
super.executeAction(action);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
2524
|
submit(action, context) {
|
|
2457
2525
|
if (this.validate().length === 0) {
|
|
2458
2526
|
const payload = action?.payload || {};
|
|
2459
2527
|
submit(context, payload?.success, payload?.error, payload?.submit_as, payload?.data);
|
|
2460
2528
|
}
|
|
2461
2529
|
}
|
|
2530
|
+
reset() {
|
|
2531
|
+
super.reset();
|
|
2532
|
+
this._invalidFields = [];
|
|
2533
|
+
}
|
|
2462
2534
|
getElement(id) {
|
|
2463
2535
|
if (id == this.id) {
|
|
2464
2536
|
return this;
|
|
@@ -2485,7 +2557,6 @@ class Form extends Container {
|
|
|
2485
2557
|
}
|
|
2486
2558
|
}
|
|
2487
2559
|
|
|
2488
|
-
// Type constants used to define functions.
|
|
2489
2560
|
var dataTypes = {
|
|
2490
2561
|
TYPE_NUMBER: 0,
|
|
2491
2562
|
TYPE_ANY: 1,
|
|
@@ -2557,11 +2628,9 @@ const {
|
|
|
2557
2628
|
TYPE_CLASS: TYPE_CLASS$1,
|
|
2558
2629
|
TYPE_ARRAY_ARRAY,
|
|
2559
2630
|
} = dataTypes;
|
|
2560
|
-
|
|
2561
2631
|
const {
|
|
2562
2632
|
TOK_EXPREF: TOK_EXPREF$3,
|
|
2563
2633
|
} = tokenDefinitions;
|
|
2564
|
-
|
|
2565
2634
|
const TYPE_NAME_TABLE = {
|
|
2566
2635
|
[TYPE_NUMBER]: 'number',
|
|
2567
2636
|
[TYPE_ANY$1]: 'any',
|
|
@@ -2576,13 +2645,10 @@ const TYPE_NAME_TABLE = {
|
|
|
2576
2645
|
[TYPE_CLASS$1]: 'class',
|
|
2577
2646
|
[TYPE_ARRAY_ARRAY]: 'Array<array>',
|
|
2578
2647
|
};
|
|
2579
|
-
|
|
2580
2648
|
function getTypeName(inputObj, useValueOf = true) {
|
|
2581
2649
|
if (inputObj === null) return TYPE_NULL;
|
|
2582
2650
|
let obj = inputObj;
|
|
2583
2651
|
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
2652
|
if (typeof inputObj.valueOf === 'function') obj = inputObj.valueOf.call(inputObj);
|
|
2587
2653
|
else return TYPE_OBJECT;
|
|
2588
2654
|
}
|
|
@@ -2598,8 +2664,6 @@ function getTypeName(inputObj, useValueOf = true) {
|
|
|
2598
2664
|
case '[object Null]':
|
|
2599
2665
|
return TYPE_NULL;
|
|
2600
2666
|
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
2667
|
if (obj.jmespathType === TOK_EXPREF$3) {
|
|
2604
2668
|
return TYPE_EXPREF;
|
|
2605
2669
|
}
|
|
@@ -2608,23 +2672,17 @@ function getTypeName(inputObj, useValueOf = true) {
|
|
|
2608
2672
|
return TYPE_OBJECT;
|
|
2609
2673
|
}
|
|
2610
2674
|
}
|
|
2611
|
-
|
|
2612
2675
|
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
2676
|
const type1 = getTypeName(inputObj);
|
|
2616
2677
|
const type2 = getTypeName(inputObj, false);
|
|
2617
2678
|
return [type1, type2];
|
|
2618
2679
|
}
|
|
2619
|
-
|
|
2620
2680
|
function matchType(actuals, expectedList, argValue, context, toNumber, toString) {
|
|
2621
2681
|
const actual = actuals[0];
|
|
2622
2682
|
if (expectedList.findIndex(
|
|
2623
2683
|
type => type === TYPE_ANY$1 || actual === type,
|
|
2624
2684
|
) !== -1
|
|
2625
2685
|
) return argValue;
|
|
2626
|
-
// Can't coerce Objects to any other type,
|
|
2627
|
-
// and cannot coerce anything to a Class
|
|
2628
2686
|
let wrongType = false;
|
|
2629
2687
|
if (actual === TYPE_OBJECT || (expectedList.length === 1 && expectedList[0] === TYPE_CLASS$1)) {
|
|
2630
2688
|
wrongType = true;
|
|
@@ -2644,11 +2702,9 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2644
2702
|
if (wrongType) {
|
|
2645
2703
|
throw new Error(`TypeError: ${context} expected argument to be type ${TYPE_NAME_TABLE[expectedList[0]]} but received type ${TYPE_NAME_TABLE[actual]} instead.`);
|
|
2646
2704
|
}
|
|
2647
|
-
// no exact match in the list of possible types, see if we can coerce an array type
|
|
2648
2705
|
let expected = -1;
|
|
2649
2706
|
if (actual === TYPE_ARRAY$1) {
|
|
2650
2707
|
if (expectedList.includes(TYPE_ARRAY_STRING$1) && expectedList.includes(TYPE_ARRAY_NUMBER)) {
|
|
2651
|
-
// choose the array type based on the first element
|
|
2652
2708
|
if (argValue.length > 0 && typeof argValue[0] === 'string') expected = TYPE_ARRAY_STRING$1;
|
|
2653
2709
|
else expected = TYPE_ARRAY_NUMBER;
|
|
2654
2710
|
}
|
|
@@ -2658,7 +2714,6 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2658
2714
|
e => [TYPE_ARRAY_STRING$1, TYPE_ARRAY_NUMBER, TYPE_ARRAY$1].includes(e),
|
|
2659
2715
|
);
|
|
2660
2716
|
}
|
|
2661
|
-
// no match, just take the first type
|
|
2662
2717
|
if (expected === -1) [expected] = expectedList;
|
|
2663
2718
|
if (expected === TYPE_ANY$1) return argValue;
|
|
2664
2719
|
if (expected === TYPE_ARRAY_STRING$1
|
|
@@ -2668,12 +2723,8 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2668
2723
|
if (actual === TYPE_ARRAY_NUMBER || actual === TYPE_ARRAY_STRING$1) return argValue;
|
|
2669
2724
|
return argValue === null ? [] : [argValue];
|
|
2670
2725
|
}
|
|
2671
|
-
// The expected type can either just be array,
|
|
2672
|
-
// or it can require a specific subtype (array of numbers).
|
|
2673
2726
|
const subtype = expected === TYPE_ARRAY_NUMBER ? TYPE_NUMBER : TYPE_STRING$1;
|
|
2674
2727
|
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
2728
|
const returnArray = argValue.slice();
|
|
2678
2729
|
for (let i = 0; i < returnArray.length; i += 1) {
|
|
2679
2730
|
const indexType = getTypeNames(returnArray[i]);
|
|
@@ -2694,7 +2745,6 @@ function matchType(actuals, expectedList, argValue, context, toNumber, toString)
|
|
|
2694
2745
|
} else {
|
|
2695
2746
|
if (expected === TYPE_NUMBER) {
|
|
2696
2747
|
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
2748
|
return 0;
|
|
2699
2749
|
}
|
|
2700
2750
|
if (expected === TYPE_STRING$1) {
|
|
@@ -2717,42 +2767,31 @@ function isArray(obj) {
|
|
|
2717
2767
|
}
|
|
2718
2768
|
return false;
|
|
2719
2769
|
}
|
|
2720
|
-
|
|
2721
2770
|
function isObject(obj) {
|
|
2722
2771
|
if (obj !== null) {
|
|
2723
2772
|
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
2724
2773
|
}
|
|
2725
2774
|
return false;
|
|
2726
2775
|
}
|
|
2727
|
-
|
|
2728
2776
|
function getValueOf(a) {
|
|
2729
2777
|
if (a === null || a === undefined) return a;
|
|
2730
2778
|
if (isArray(a)) {
|
|
2731
2779
|
return a.map(i => getValueOf(i));
|
|
2732
2780
|
}
|
|
2733
|
-
// if we have a child named 'valueOf' then we're an object,
|
|
2734
|
-
// and just return the object.
|
|
2735
2781
|
if (typeof (a.valueOf) !== 'function') return a;
|
|
2736
2782
|
return a.valueOf();
|
|
2737
2783
|
}
|
|
2738
|
-
|
|
2739
2784
|
function strictDeepEqual(lhs, rhs) {
|
|
2740
2785
|
const first = getValueOf(lhs);
|
|
2741
2786
|
const second = getValueOf(rhs);
|
|
2742
|
-
// Check the scalar case first.
|
|
2743
2787
|
if (first === second) {
|
|
2744
2788
|
return true;
|
|
2745
2789
|
}
|
|
2746
|
-
|
|
2747
|
-
// Check if they are the same type.
|
|
2748
2790
|
const firstType = Object.prototype.toString.call(first);
|
|
2749
2791
|
if (firstType !== Object.prototype.toString.call(second)) {
|
|
2750
2792
|
return false;
|
|
2751
2793
|
}
|
|
2752
|
-
// We know that first and second have the same type so we can just check the
|
|
2753
|
-
// first type from now on.
|
|
2754
2794
|
if (isArray(first) === true) {
|
|
2755
|
-
// Short circuit if they're not the same length;
|
|
2756
2795
|
if (first.length !== second.length) {
|
|
2757
2796
|
return false;
|
|
2758
2797
|
}
|
|
@@ -2764,9 +2803,7 @@ function strictDeepEqual(lhs, rhs) {
|
|
|
2764
2803
|
return true;
|
|
2765
2804
|
}
|
|
2766
2805
|
if (isObject(first) === true) {
|
|
2767
|
-
// An object is equal if it has the same key/value pairs.
|
|
2768
2806
|
const keysSeen = {};
|
|
2769
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
2770
2807
|
for (const key in first) {
|
|
2771
2808
|
if (hasOwnProperty.call(first, key)) {
|
|
2772
2809
|
if (strictDeepEqual(first[key], second[key]) === false) {
|
|
@@ -2775,9 +2812,6 @@ function strictDeepEqual(lhs, rhs) {
|
|
|
2775
2812
|
keysSeen[key] = true;
|
|
2776
2813
|
}
|
|
2777
2814
|
}
|
|
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
2815
|
for (const key2 in second) {
|
|
2782
2816
|
if (hasOwnProperty.call(second, key2)) {
|
|
2783
2817
|
if (keysSeen[key2] !== true) {
|
|
@@ -2803,42 +2837,22 @@ const {
|
|
|
2803
2837
|
TOK_NE: TOK_NE$2,
|
|
2804
2838
|
TOK_FLATTEN: TOK_FLATTEN$2,
|
|
2805
2839
|
} = tokenDefinitions;
|
|
2806
|
-
|
|
2807
2840
|
const {
|
|
2808
2841
|
TYPE_STRING,
|
|
2809
2842
|
TYPE_ARRAY_STRING,
|
|
2810
2843
|
TYPE_ARRAY,
|
|
2811
2844
|
} = dataTypes;
|
|
2812
|
-
|
|
2813
2845
|
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
2846
|
if (value === null) return true;
|
|
2826
|
-
// in case it's an object with a valueOf defined
|
|
2827
2847
|
const obj = getValueOf(value);
|
|
2828
2848
|
if (obj === '' || obj === false || obj === null) {
|
|
2829
2849
|
return true;
|
|
2830
2850
|
}
|
|
2831
2851
|
if (isArray(obj) && obj.length === 0) {
|
|
2832
|
-
// Check for an empty array.
|
|
2833
2852
|
return true;
|
|
2834
2853
|
}
|
|
2835
2854
|
if (isObject(obj)) {
|
|
2836
|
-
// Check for an empty object.
|
|
2837
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
2838
2855
|
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
2856
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
2843
2857
|
return false;
|
|
2844
2858
|
}
|
|
@@ -2847,11 +2861,9 @@ function isFalse(value) {
|
|
|
2847
2861
|
}
|
|
2848
2862
|
return !obj;
|
|
2849
2863
|
}
|
|
2850
|
-
|
|
2851
2864
|
function objValues(obj) {
|
|
2852
2865
|
return Object.values(obj);
|
|
2853
2866
|
}
|
|
2854
|
-
|
|
2855
2867
|
class TreeInterpreter {
|
|
2856
2868
|
constructor(runtime, globals, toNumber, toString, debug, language) {
|
|
2857
2869
|
this.runtime = runtime;
|
|
@@ -2861,27 +2873,20 @@ class TreeInterpreter {
|
|
|
2861
2873
|
this.debug = debug;
|
|
2862
2874
|
this.language = language;
|
|
2863
2875
|
}
|
|
2864
|
-
|
|
2865
2876
|
search(node, value) {
|
|
2866
2877
|
return this.visit(node, value);
|
|
2867
2878
|
}
|
|
2868
|
-
|
|
2869
2879
|
visit(n, v) {
|
|
2870
2880
|
const visitFunctions = {
|
|
2871
2881
|
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
2882
|
if (value !== null && (isObject(value) || isArray(value))) {
|
|
2875
2883
|
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
2884
|
if (typeof field === 'function') field = undefined;
|
|
2879
2885
|
if (field === undefined) {
|
|
2880
2886
|
try {
|
|
2881
2887
|
this.debug.push(`Failed to find: '${node.name}'`);
|
|
2882
2888
|
const available = Object.keys(value).map(a => `'${a}'`).toString();
|
|
2883
2889
|
if (available.length) this.debug.push(`Available fields: ${available}`);
|
|
2884
|
-
// eslint-disable-next-line no-empty
|
|
2885
2890
|
} catch (e) {}
|
|
2886
2891
|
return null;
|
|
2887
2892
|
}
|
|
@@ -2889,7 +2894,6 @@ class TreeInterpreter {
|
|
|
2889
2894
|
}
|
|
2890
2895
|
return null;
|
|
2891
2896
|
},
|
|
2892
|
-
|
|
2893
2897
|
Subexpression: (node, value) => {
|
|
2894
2898
|
let result = this.visit(node.children[0], value);
|
|
2895
2899
|
for (let i = 1; i < node.children.length; i += 1) {
|
|
@@ -2898,12 +2902,10 @@ class TreeInterpreter {
|
|
|
2898
2902
|
}
|
|
2899
2903
|
return result;
|
|
2900
2904
|
},
|
|
2901
|
-
|
|
2902
2905
|
IndexExpression: (node, value) => {
|
|
2903
2906
|
const left = this.visit(node.children[0], value);
|
|
2904
2907
|
return this.visit(node.children[1], left);
|
|
2905
2908
|
},
|
|
2906
|
-
|
|
2907
2909
|
Index: (node, value) => {
|
|
2908
2910
|
if (isArray(value)) {
|
|
2909
2911
|
let index = this.toNumber(this.visit(node.value, value));
|
|
@@ -2929,7 +2931,6 @@ class TreeInterpreter {
|
|
|
2929
2931
|
this.debug.push(`left side of index expression ${value} is not an array or object.`);
|
|
2930
2932
|
return null;
|
|
2931
2933
|
},
|
|
2932
|
-
|
|
2933
2934
|
Slice: (node, value) => {
|
|
2934
2935
|
if (!isArray(value)) return null;
|
|
2935
2936
|
const sliceParams = node.children.slice(0).map(
|
|
@@ -2949,9 +2950,7 @@ class TreeInterpreter {
|
|
|
2949
2950
|
}
|
|
2950
2951
|
return result;
|
|
2951
2952
|
},
|
|
2952
|
-
|
|
2953
2953
|
Projection: (node, value) => {
|
|
2954
|
-
// Evaluate left child.
|
|
2955
2954
|
const base = this.visit(node.children[0], value);
|
|
2956
2955
|
if (!isArray(base)) return null;
|
|
2957
2956
|
const collected = [];
|
|
@@ -2963,9 +2962,7 @@ class TreeInterpreter {
|
|
|
2963
2962
|
});
|
|
2964
2963
|
return collected;
|
|
2965
2964
|
},
|
|
2966
|
-
|
|
2967
2965
|
ValueProjection: (node, value) => {
|
|
2968
|
-
// Evaluate left child.
|
|
2969
2966
|
const projection = this.visit(node.children[0], value);
|
|
2970
2967
|
if (!isObject(getValueOf(projection))) return null;
|
|
2971
2968
|
const collected = [];
|
|
@@ -2976,7 +2973,6 @@ class TreeInterpreter {
|
|
|
2976
2973
|
});
|
|
2977
2974
|
return collected;
|
|
2978
2975
|
},
|
|
2979
|
-
|
|
2980
2976
|
FilterProjection: (node, value) => {
|
|
2981
2977
|
const base = this.visit(node.children[0], value);
|
|
2982
2978
|
if (!isArray(base)) return null;
|
|
@@ -2984,7 +2980,6 @@ class TreeInterpreter {
|
|
|
2984
2980
|
const matched = this.visit(node.children[2], b);
|
|
2985
2981
|
return !isFalse(matched);
|
|
2986
2982
|
});
|
|
2987
|
-
|
|
2988
2983
|
const finalResults = [];
|
|
2989
2984
|
filtered.forEach(f => {
|
|
2990
2985
|
const current = this.visit(node.children[1], f);
|
|
@@ -2992,11 +2987,9 @@ class TreeInterpreter {
|
|
|
2992
2987
|
});
|
|
2993
2988
|
return finalResults;
|
|
2994
2989
|
},
|
|
2995
|
-
|
|
2996
2990
|
Comparator: (node, value) => {
|
|
2997
2991
|
const first = this.visit(node.children[0], value);
|
|
2998
2992
|
const second = this.visit(node.children[1], value);
|
|
2999
|
-
|
|
3000
2993
|
if (node.name === TOK_EQ$2) return strictDeepEqual(first, second);
|
|
3001
2994
|
if (node.name === TOK_NE$2) return !strictDeepEqual(first, second);
|
|
3002
2995
|
if (node.name === TOK_GT$2) return first > second;
|
|
@@ -3005,7 +2998,6 @@ class TreeInterpreter {
|
|
|
3005
2998
|
if (node.name === TOK_LTE$2) return first <= second;
|
|
3006
2999
|
throw new Error(`Unknown comparator: ${node.name}`);
|
|
3007
3000
|
},
|
|
3008
|
-
|
|
3009
3001
|
[TOK_FLATTEN$2]: (node, value) => {
|
|
3010
3002
|
const original = this.visit(node.children[0], value);
|
|
3011
3003
|
if (!isArray(original)) return null;
|
|
@@ -3019,14 +3011,11 @@ class TreeInterpreter {
|
|
|
3019
3011
|
});
|
|
3020
3012
|
return merged;
|
|
3021
3013
|
},
|
|
3022
|
-
|
|
3023
3014
|
Identity: (_node, value) => value,
|
|
3024
|
-
|
|
3025
3015
|
MultiSelectList: (node, value) => {
|
|
3026
3016
|
if (value === null) return null;
|
|
3027
3017
|
return node.children.map(child => this.visit(child, value));
|
|
3028
3018
|
},
|
|
3029
|
-
|
|
3030
3019
|
MultiSelectHash: (node, value) => {
|
|
3031
3020
|
if (value === null) return null;
|
|
3032
3021
|
const collected = {};
|
|
@@ -3035,26 +3024,21 @@ class TreeInterpreter {
|
|
|
3035
3024
|
});
|
|
3036
3025
|
return collected;
|
|
3037
3026
|
},
|
|
3038
|
-
|
|
3039
3027
|
OrExpression: (node, value) => {
|
|
3040
3028
|
let matched = this.visit(node.children[0], value);
|
|
3041
3029
|
if (isFalse(matched)) matched = this.visit(node.children[1], value);
|
|
3042
3030
|
return matched;
|
|
3043
3031
|
},
|
|
3044
|
-
|
|
3045
3032
|
AndExpression: (node, value) => {
|
|
3046
3033
|
const first = this.visit(node.children[0], value);
|
|
3047
|
-
|
|
3048
3034
|
if (isFalse(first) === true) return first;
|
|
3049
3035
|
return this.visit(node.children[1], value);
|
|
3050
3036
|
},
|
|
3051
|
-
|
|
3052
3037
|
AddExpression: (node, value) => {
|
|
3053
3038
|
const first = this.visit(node.children[0], value);
|
|
3054
3039
|
const second = this.visit(node.children[1], value);
|
|
3055
3040
|
return this.applyOperator(first, second, '+');
|
|
3056
3041
|
},
|
|
3057
|
-
|
|
3058
3042
|
ConcatenateExpression: (node, value) => {
|
|
3059
3043
|
let first = this.visit(node.children[0], value);
|
|
3060
3044
|
let second = this.visit(node.children[1], value);
|
|
@@ -3062,7 +3046,6 @@ class TreeInterpreter {
|
|
|
3062
3046
|
second = matchType(getTypeNames(second), [TYPE_STRING, TYPE_ARRAY_STRING], second, 'concatenate', this.toNumber, this.toString);
|
|
3063
3047
|
return this.applyOperator(first, second, '&');
|
|
3064
3048
|
},
|
|
3065
|
-
|
|
3066
3049
|
UnionExpression: (node, value) => {
|
|
3067
3050
|
let first = this.visit(node.children[0], value);
|
|
3068
3051
|
let second = this.visit(node.children[1], value);
|
|
@@ -3070,72 +3053,52 @@ class TreeInterpreter {
|
|
|
3070
3053
|
second = matchType(getTypeNames(second), [TYPE_ARRAY], second, 'union', this.toNumber, this.toString);
|
|
3071
3054
|
return first.concat(second);
|
|
3072
3055
|
},
|
|
3073
|
-
|
|
3074
3056
|
SubtractExpression: (node, value) => {
|
|
3075
3057
|
const first = this.visit(node.children[0], value);
|
|
3076
3058
|
const second = this.visit(node.children[1], value);
|
|
3077
3059
|
return this.applyOperator(first, second, '-');
|
|
3078
3060
|
},
|
|
3079
|
-
|
|
3080
3061
|
MultiplyExpression: (node, value) => {
|
|
3081
3062
|
const first = this.visit(node.children[0], value);
|
|
3082
3063
|
const second = this.visit(node.children[1], value);
|
|
3083
3064
|
return this.applyOperator(first, second, '*');
|
|
3084
3065
|
},
|
|
3085
|
-
|
|
3086
3066
|
DivideExpression: (node, value) => {
|
|
3087
3067
|
const first = this.visit(node.children[0], value);
|
|
3088
3068
|
const second = this.visit(node.children[1], value);
|
|
3089
3069
|
return this.applyOperator(first, second, '/');
|
|
3090
3070
|
},
|
|
3091
|
-
|
|
3092
3071
|
PowerExpression: (node, value) => {
|
|
3093
3072
|
const first = this.visit(node.children[0], value);
|
|
3094
3073
|
const second = this.visit(node.children[1], value);
|
|
3095
3074
|
return this.applyOperator(first, second, '^');
|
|
3096
3075
|
},
|
|
3097
|
-
|
|
3098
3076
|
NotExpression: (node, value) => {
|
|
3099
3077
|
const first = this.visit(node.children[0], value);
|
|
3100
3078
|
return isFalse(first);
|
|
3101
3079
|
},
|
|
3102
|
-
|
|
3103
3080
|
UnaryMinusExpression: (node, value) => {
|
|
3104
3081
|
const first = this.visit(node.children[0], value);
|
|
3105
3082
|
return first * -1;
|
|
3106
3083
|
},
|
|
3107
|
-
|
|
3108
3084
|
Literal: node => node.value,
|
|
3109
|
-
|
|
3110
3085
|
Number: node => node.value,
|
|
3111
|
-
|
|
3112
3086
|
[TOK_PIPE$2]: (node, value) => {
|
|
3113
3087
|
const left = this.visit(node.children[0], value);
|
|
3114
3088
|
return this.visit(node.children[1], left);
|
|
3115
3089
|
},
|
|
3116
|
-
|
|
3117
3090
|
[TOK_CURRENT$2]: (_node, value) => value,
|
|
3118
|
-
|
|
3119
3091
|
[TOK_GLOBAL$2]: node => {
|
|
3120
3092
|
const result = this.globals[node.name];
|
|
3121
3093
|
return result === undefined ? null : result;
|
|
3122
3094
|
},
|
|
3123
|
-
|
|
3124
3095
|
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
3096
|
if (node.name === 'if') return this.runtime.callFunction(node.name, node.children, value, this, false);
|
|
3131
3097
|
const resolvedArgs = node.children.map(child => this.visit(child, value));
|
|
3132
3098
|
return this.runtime.callFunction(node.name, resolvedArgs, value, this);
|
|
3133
3099
|
},
|
|
3134
|
-
|
|
3135
3100
|
ExpressionReference: node => {
|
|
3136
3101
|
const [refNode] = node.children;
|
|
3137
|
-
// Tag the node with a specific attribute so the type
|
|
3138
|
-
// checker verify the type.
|
|
3139
3102
|
refNode.jmespathType = TOK_EXPREF$2;
|
|
3140
3103
|
return refNode;
|
|
3141
3104
|
},
|
|
@@ -3144,8 +3107,6 @@ class TreeInterpreter {
|
|
|
3144
3107
|
if (!fn) throw new Error(`Unknown/missing node type ${(n && n.type) || ''}`);
|
|
3145
3108
|
return fn(n, v);
|
|
3146
3109
|
}
|
|
3147
|
-
|
|
3148
|
-
// eslint-disable-next-line class-methods-use-this
|
|
3149
3110
|
computeSliceParams(arrayLength, sliceParams) {
|
|
3150
3111
|
function capSliceRange(arrayLen, actual, stp) {
|
|
3151
3112
|
let actualValue = actual;
|
|
@@ -3159,7 +3120,6 @@ class TreeInterpreter {
|
|
|
3159
3120
|
}
|
|
3160
3121
|
return actualValue;
|
|
3161
3122
|
}
|
|
3162
|
-
|
|
3163
3123
|
let [start, stop, step] = sliceParams;
|
|
3164
3124
|
if (step === null) {
|
|
3165
3125
|
step = 1;
|
|
@@ -3169,13 +3129,11 @@ class TreeInterpreter {
|
|
|
3169
3129
|
throw error;
|
|
3170
3130
|
}
|
|
3171
3131
|
const stepValueNegative = step < 0;
|
|
3172
|
-
|
|
3173
3132
|
if (start === null) {
|
|
3174
3133
|
start = stepValueNegative ? arrayLength - 1 : 0;
|
|
3175
3134
|
} else {
|
|
3176
3135
|
start = capSliceRange(arrayLength, start, step);
|
|
3177
3136
|
}
|
|
3178
|
-
|
|
3179
3137
|
if (stop === null) {
|
|
3180
3138
|
stop = stepValueNegative ? -1 : arrayLength;
|
|
3181
3139
|
} else {
|
|
@@ -3183,10 +3141,8 @@ class TreeInterpreter {
|
|
|
3183
3141
|
}
|
|
3184
3142
|
return [start, stop, step];
|
|
3185
3143
|
}
|
|
3186
|
-
|
|
3187
3144
|
applyOperator(first, second, operator) {
|
|
3188
3145
|
if (isArray(first) && isArray(second)) {
|
|
3189
|
-
// balance the size of the arrays
|
|
3190
3146
|
const shorter = first.length < second.length ? first : second;
|
|
3191
3147
|
const diff = Math.abs(first.length - second.length);
|
|
3192
3148
|
shorter.length += diff;
|
|
@@ -3197,10 +3153,8 @@ class TreeInterpreter {
|
|
|
3197
3153
|
}
|
|
3198
3154
|
return result;
|
|
3199
3155
|
}
|
|
3200
|
-
|
|
3201
3156
|
if (isArray(first)) return first.map(a => this.applyOperator(a, second, operator));
|
|
3202
3157
|
if (isArray(second)) return second.map(a => this.applyOperator(first, a, operator));
|
|
3203
|
-
|
|
3204
3158
|
if (operator === '*') return this.toNumber(first) * this.toNumber(second);
|
|
3205
3159
|
if (operator === '&') return first + second;
|
|
3206
3160
|
if (operator === '+') {
|
|
@@ -3218,8 +3172,6 @@ class TreeInterpreter {
|
|
|
3218
3172
|
}
|
|
3219
3173
|
}
|
|
3220
3174
|
|
|
3221
|
-
/* eslint-disable no-underscore-dangle */
|
|
3222
|
-
|
|
3223
3175
|
const {
|
|
3224
3176
|
TOK_UNQUOTEDIDENTIFIER: TOK_UNQUOTEDIDENTIFIER$1,
|
|
3225
3177
|
TOK_QUOTEDIDENTIFIER: TOK_QUOTEDIDENTIFIER$1,
|
|
@@ -3259,16 +3211,8 @@ const {
|
|
|
3259
3211
|
TOK_LPAREN: TOK_LPAREN$1,
|
|
3260
3212
|
TOK_LITERAL: TOK_LITERAL$1,
|
|
3261
3213
|
} = 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
3214
|
const basicTokens = {
|
|
3270
3215
|
'.': TOK_DOT$1,
|
|
3271
|
-
// "*": TOK_STAR,
|
|
3272
3216
|
',': TOK_COMMA$1,
|
|
3273
3217
|
':': TOK_COLON$1,
|
|
3274
3218
|
'{': TOK_LBRACE$1,
|
|
@@ -3278,7 +3222,6 @@ const basicTokens = {
|
|
|
3278
3222
|
')': TOK_RPAREN$1,
|
|
3279
3223
|
'@': TOK_CURRENT$1,
|
|
3280
3224
|
};
|
|
3281
|
-
|
|
3282
3225
|
const globalStartToken = '$';
|
|
3283
3226
|
const operatorStartToken = {
|
|
3284
3227
|
'<': true,
|
|
@@ -3286,42 +3229,34 @@ const operatorStartToken = {
|
|
|
3286
3229
|
'=': true,
|
|
3287
3230
|
'!': true,
|
|
3288
3231
|
};
|
|
3289
|
-
|
|
3290
3232
|
const skipChars = {
|
|
3291
3233
|
' ': true,
|
|
3292
3234
|
'\t': true,
|
|
3293
3235
|
'\n': true,
|
|
3294
3236
|
};
|
|
3295
|
-
|
|
3296
3237
|
function isNum(ch) {
|
|
3297
3238
|
return (ch >= '0' && ch <= '9') || (ch === '.');
|
|
3298
3239
|
}
|
|
3299
|
-
|
|
3300
3240
|
function isAlphaNum(ch) {
|
|
3301
3241
|
return (ch >= 'a' && ch <= 'z')
|
|
3302
3242
|
|| (ch >= 'A' && ch <= 'Z')
|
|
3303
3243
|
|| (ch >= '0' && ch <= '9')
|
|
3304
3244
|
|| ch === '_';
|
|
3305
3245
|
}
|
|
3306
|
-
|
|
3307
3246
|
function isIdentifier(stream, pos) {
|
|
3308
3247
|
const ch = stream[pos];
|
|
3309
|
-
// $ is special -- it's allowed to be part of an identifier if it's the first character
|
|
3310
3248
|
if (ch === '$') {
|
|
3311
3249
|
return stream.length > pos && isAlphaNum(stream[pos + 1]);
|
|
3312
3250
|
}
|
|
3313
|
-
// return whether character 'isAlpha'
|
|
3314
3251
|
return (ch >= 'a' && ch <= 'z')
|
|
3315
3252
|
|| (ch >= 'A' && ch <= 'Z')
|
|
3316
3253
|
|| ch === '_';
|
|
3317
3254
|
}
|
|
3318
|
-
|
|
3319
3255
|
class Lexer {
|
|
3320
3256
|
constructor(allowedGlobalNames = [], debug = []) {
|
|
3321
3257
|
this._allowedGlobalNames = allowedGlobalNames;
|
|
3322
3258
|
this.debug = debug;
|
|
3323
3259
|
}
|
|
3324
|
-
|
|
3325
3260
|
tokenize(stream) {
|
|
3326
3261
|
const tokens = [];
|
|
3327
3262
|
this._current = 0;
|
|
@@ -3330,7 +3265,6 @@ class Lexer {
|
|
|
3330
3265
|
let token;
|
|
3331
3266
|
while (this._current < stream.length) {
|
|
3332
3267
|
const prev = tokens.length ? tokens.slice(-1)[0].type : null;
|
|
3333
|
-
|
|
3334
3268
|
if (this._isGlobal(prev, stream, this._current)) {
|
|
3335
3269
|
tokens.push(this._consumeGlobal(stream));
|
|
3336
3270
|
} else if (isIdentifier(stream, this._current)) {
|
|
@@ -3355,8 +3289,6 @@ class Lexer {
|
|
|
3355
3289
|
token = this._consumeNumber(stream);
|
|
3356
3290
|
tokens.push(token);
|
|
3357
3291
|
} else if (stream[this._current] === '[') {
|
|
3358
|
-
// No need to increment this._current. This happens
|
|
3359
|
-
// in _consumeLBracket
|
|
3360
3292
|
token = this._consumeLBracket(stream);
|
|
3361
3293
|
tokens.push(token);
|
|
3362
3294
|
} else if (stream[this._current] === '"') {
|
|
@@ -3386,7 +3318,6 @@ class Lexer {
|
|
|
3386
3318
|
} else if (operatorStartToken[stream[this._current]] !== undefined) {
|
|
3387
3319
|
tokens.push(this._consumeOperator(stream));
|
|
3388
3320
|
} else if (skipChars[stream[this._current]] !== undefined) {
|
|
3389
|
-
// Ignore whitespace.
|
|
3390
3321
|
this._current += 1;
|
|
3391
3322
|
} else if (stream[this._current] === '&') {
|
|
3392
3323
|
start = this._current;
|
|
@@ -3395,9 +3326,6 @@ class Lexer {
|
|
|
3395
3326
|
this._current += 1;
|
|
3396
3327
|
tokens.push({ type: TOK_AND$1, value: '&&', start });
|
|
3397
3328
|
} 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
3329
|
tokens.push({ type: TOK_EXPREF$1, value: '&', start });
|
|
3402
3330
|
} else {
|
|
3403
3331
|
tokens.push({ type: TOK_CONCATENATE$1, value: '&', start });
|
|
@@ -3417,8 +3345,6 @@ class Lexer {
|
|
|
3417
3345
|
} else if (stream[this._current] === '*') {
|
|
3418
3346
|
start = this._current;
|
|
3419
3347
|
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
3348
|
const prevToken = tokens.length && tokens.slice(-1)[0].type;
|
|
3423
3349
|
if (tokens.length === 0 || [
|
|
3424
3350
|
TOK_LBRACKET$1,
|
|
@@ -3458,7 +3384,6 @@ class Lexer {
|
|
|
3458
3384
|
}
|
|
3459
3385
|
return tokens;
|
|
3460
3386
|
}
|
|
3461
|
-
|
|
3462
3387
|
_consumeUnquotedIdentifier(stream) {
|
|
3463
3388
|
const start = this._current;
|
|
3464
3389
|
this._current += 1;
|
|
@@ -3467,14 +3392,12 @@ class Lexer {
|
|
|
3467
3392
|
}
|
|
3468
3393
|
return stream.slice(start, this._current);
|
|
3469
3394
|
}
|
|
3470
|
-
|
|
3471
3395
|
_consumeQuotedIdentifier(stream) {
|
|
3472
3396
|
const start = this._current;
|
|
3473
3397
|
this._current += 1;
|
|
3474
3398
|
const maxLength = stream.length;
|
|
3475
3399
|
let foundNonAlpha = !isIdentifier(stream, start + 1);
|
|
3476
3400
|
while (stream[this._current] !== '"' && this._current < maxLength) {
|
|
3477
|
-
// You can escape a double quote and you can escape an escape.
|
|
3478
3401
|
let current = this._current;
|
|
3479
3402
|
if (!isAlphaNum(stream[current])) foundNonAlpha = true;
|
|
3480
3403
|
if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
@@ -3487,26 +3410,19 @@ class Lexer {
|
|
|
3487
3410
|
}
|
|
3488
3411
|
this._current += 1;
|
|
3489
3412
|
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
3413
|
try {
|
|
3495
3414
|
if (!foundNonAlpha || val.includes(' ')) {
|
|
3496
3415
|
this.debug.push(`Suspicious quotes: ${val}`);
|
|
3497
3416
|
this.debug.push(`Did you intend a literal? '${val.replace(/"/g, '')}'?`);
|
|
3498
3417
|
}
|
|
3499
|
-
// eslint-disable-next-line no-empty
|
|
3500
3418
|
} catch (e) {}
|
|
3501
3419
|
return JSON.parse(val);
|
|
3502
3420
|
}
|
|
3503
|
-
|
|
3504
3421
|
_consumeRawStringLiteral(stream) {
|
|
3505
3422
|
const start = this._current;
|
|
3506
3423
|
this._current += 1;
|
|
3507
3424
|
const maxLength = stream.length;
|
|
3508
3425
|
while (stream[this._current] !== "'" && this._current < maxLength) {
|
|
3509
|
-
// You can escape a single quote and you can escape an escape.
|
|
3510
3426
|
let current = this._current;
|
|
3511
3427
|
if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
3512
3428
|
|| stream[current + 1] === "'")) {
|
|
@@ -3520,7 +3436,6 @@ class Lexer {
|
|
|
3520
3436
|
const literal = stream.slice(start + 1, this._current - 1);
|
|
3521
3437
|
return literal.replaceAll("\\'", "'");
|
|
3522
3438
|
}
|
|
3523
|
-
|
|
3524
3439
|
_consumeNumber(stream) {
|
|
3525
3440
|
const start = this._current;
|
|
3526
3441
|
this._current += 1;
|
|
@@ -3537,13 +3452,11 @@ class Lexer {
|
|
|
3537
3452
|
}
|
|
3538
3453
|
return { type: TOK_NUMBER$1, value, start };
|
|
3539
3454
|
}
|
|
3540
|
-
|
|
3541
3455
|
_consumeUnaryMinus() {
|
|
3542
3456
|
const start = this._current;
|
|
3543
3457
|
this._current += 1;
|
|
3544
3458
|
return { type: TOK_UNARY_MINUS$1, value: '-', start };
|
|
3545
3459
|
}
|
|
3546
|
-
|
|
3547
3460
|
_consumeLBracket(stream) {
|
|
3548
3461
|
const start = this._current;
|
|
3549
3462
|
this._current += 1;
|
|
@@ -3557,28 +3470,22 @@ class Lexer {
|
|
|
3557
3470
|
}
|
|
3558
3471
|
return { type: TOK_LBRACKET$1, value: '[', start };
|
|
3559
3472
|
}
|
|
3560
|
-
|
|
3561
3473
|
_isGlobal(prev, stream, pos) {
|
|
3562
|
-
// global tokens occur only at the start of an expression
|
|
3563
3474
|
if (prev !== null && prev === TOK_DOT$1) return false;
|
|
3564
3475
|
const ch = stream[pos];
|
|
3565
3476
|
if (ch !== globalStartToken) return false;
|
|
3566
|
-
// $ is special -- it's allowed to be part of an identifier if it's the first character
|
|
3567
3477
|
let i = pos + 1;
|
|
3568
3478
|
while (i < stream.length && isAlphaNum(stream[i])) i += 1;
|
|
3569
3479
|
const global = stream.slice(pos, i);
|
|
3570
3480
|
return this._allowedGlobalNames.includes(global);
|
|
3571
3481
|
}
|
|
3572
|
-
|
|
3573
3482
|
_consumeGlobal(stream) {
|
|
3574
3483
|
const start = this._current;
|
|
3575
3484
|
this._current += 1;
|
|
3576
3485
|
while (this._current < stream.length && isAlphaNum(stream[this._current])) this._current += 1;
|
|
3577
3486
|
const global = stream.slice(start, this._current);
|
|
3578
|
-
|
|
3579
3487
|
return { type: TOK_GLOBAL$1, name: global, start };
|
|
3580
3488
|
}
|
|
3581
|
-
|
|
3582
3489
|
_consumeOperator(stream) {
|
|
3583
3490
|
const start = this._current;
|
|
3584
3491
|
const startingChar = stream[start];
|
|
@@ -3604,20 +3511,17 @@ class Lexer {
|
|
|
3604
3511
|
}
|
|
3605
3512
|
return { type: TOK_GT$1, value: '>', start };
|
|
3606
3513
|
}
|
|
3607
|
-
// startingChar is '='
|
|
3608
3514
|
if (stream[this._current] === '=') {
|
|
3609
3515
|
this._current += 1;
|
|
3610
3516
|
return { type: TOK_EQ$1, value: '==', start };
|
|
3611
3517
|
}
|
|
3612
3518
|
return { type: TOK_EQ$1, value: '=', start };
|
|
3613
3519
|
}
|
|
3614
|
-
|
|
3615
3520
|
_consumeLiteral(stream) {
|
|
3616
3521
|
function _looksLikeJSON(str) {
|
|
3617
3522
|
if (str === '') return false;
|
|
3618
3523
|
if ('[{"'.includes(str[0])) return true;
|
|
3619
3524
|
if (['true', 'false', 'null'].includes(str)) return true;
|
|
3620
|
-
|
|
3621
3525
|
if ('-0123456789'.includes(str[0])) {
|
|
3622
3526
|
try {
|
|
3623
3527
|
JSON.parse(str);
|
|
@@ -3629,7 +3533,6 @@ class Lexer {
|
|
|
3629
3533
|
return false;
|
|
3630
3534
|
}
|
|
3631
3535
|
}
|
|
3632
|
-
|
|
3633
3536
|
this._current += 1;
|
|
3634
3537
|
const start = this._current;
|
|
3635
3538
|
const maxLength = stream.length;
|
|
@@ -3637,14 +3540,12 @@ class Lexer {
|
|
|
3637
3540
|
let inQuotes = false;
|
|
3638
3541
|
while ((inQuotes || stream[this._current] !== '`') && this._current < maxLength) {
|
|
3639
3542
|
let current = this._current;
|
|
3640
|
-
// bypass escaped double quotes when we're inside quotes
|
|
3641
3543
|
if (inQuotes && stream[current] === '\\' && stream[current + 1] === '"') current += 2;
|
|
3642
3544
|
else {
|
|
3643
3545
|
if (stream[current] === '"') inQuotes = !inQuotes;
|
|
3644
3546
|
if (inQuotes && stream[current + 1] === '`') current += 2;
|
|
3645
3547
|
else if (stream[current] === '\\' && (stream[current + 1] === '\\'
|
|
3646
3548
|
|| stream[current + 1] === '`')) {
|
|
3647
|
-
// You can escape a literal char or you can escape the escape.
|
|
3648
3549
|
current += 2;
|
|
3649
3550
|
} else {
|
|
3650
3551
|
current += 1;
|
|
@@ -3657,16 +3558,13 @@ class Lexer {
|
|
|
3657
3558
|
if (_looksLikeJSON(literalString)) {
|
|
3658
3559
|
literal = JSON.parse(literalString);
|
|
3659
3560
|
} else {
|
|
3660
|
-
// Try to JSON parse it as "<literal>"
|
|
3661
3561
|
literal = JSON.parse(`"${literalString}"`);
|
|
3662
3562
|
}
|
|
3663
|
-
// +1 gets us to the ending "`", +1 to move on to the next char.
|
|
3664
3563
|
this._current += 1;
|
|
3665
3564
|
return literal;
|
|
3666
3565
|
}
|
|
3667
3566
|
}
|
|
3668
3567
|
|
|
3669
|
-
/* eslint-disable no-underscore-dangle */
|
|
3670
3568
|
const {
|
|
3671
3569
|
TOK_LITERAL,
|
|
3672
3570
|
TOK_COLON,
|
|
@@ -3708,7 +3606,6 @@ const {
|
|
|
3708
3606
|
TOK_LBRACKET,
|
|
3709
3607
|
TOK_LPAREN,
|
|
3710
3608
|
} = tokenDefinitions;
|
|
3711
|
-
|
|
3712
3609
|
const bindingPower = {
|
|
3713
3610
|
[TOK_EOF]: 0,
|
|
3714
3611
|
[TOK_UNQUOTEDIDENTIFIER]: 0,
|
|
@@ -3748,12 +3645,10 @@ const bindingPower = {
|
|
|
3748
3645
|
[TOK_LBRACKET]: 55,
|
|
3749
3646
|
[TOK_LPAREN]: 60,
|
|
3750
3647
|
};
|
|
3751
|
-
|
|
3752
3648
|
class Parser {
|
|
3753
3649
|
constructor(allowedGlobalNames = []) {
|
|
3754
3650
|
this._allowedGlobalNames = allowedGlobalNames;
|
|
3755
3651
|
}
|
|
3756
|
-
|
|
3757
3652
|
parse(expression, debug) {
|
|
3758
3653
|
this._loadTokens(expression, debug);
|
|
3759
3654
|
this.index = 0;
|
|
@@ -3768,14 +3663,12 @@ class Parser {
|
|
|
3768
3663
|
}
|
|
3769
3664
|
return ast;
|
|
3770
3665
|
}
|
|
3771
|
-
|
|
3772
3666
|
_loadTokens(expression, debug) {
|
|
3773
3667
|
const lexer = new Lexer(this._allowedGlobalNames, debug);
|
|
3774
3668
|
const tokens = lexer.tokenize(expression);
|
|
3775
3669
|
tokens.push({ type: TOK_EOF, value: '', start: expression.length });
|
|
3776
3670
|
this.tokens = tokens;
|
|
3777
3671
|
}
|
|
3778
|
-
|
|
3779
3672
|
expression(rbp) {
|
|
3780
3673
|
const leftToken = this._lookaheadToken(0);
|
|
3781
3674
|
this._advance();
|
|
@@ -3788,28 +3681,21 @@ class Parser {
|
|
|
3788
3681
|
}
|
|
3789
3682
|
return left;
|
|
3790
3683
|
}
|
|
3791
|
-
|
|
3792
3684
|
_lookahead(number) {
|
|
3793
3685
|
return this.tokens[this.index + number].type;
|
|
3794
3686
|
}
|
|
3795
|
-
|
|
3796
3687
|
_lookaheadToken(number) {
|
|
3797
3688
|
return this.tokens[this.index + number];
|
|
3798
3689
|
}
|
|
3799
|
-
|
|
3800
3690
|
_advance() {
|
|
3801
3691
|
this.index += 1;
|
|
3802
3692
|
}
|
|
3803
|
-
|
|
3804
3693
|
_getIndex() {
|
|
3805
3694
|
return this.index;
|
|
3806
3695
|
}
|
|
3807
|
-
|
|
3808
3696
|
_setIndex(index) {
|
|
3809
3697
|
this.index = index;
|
|
3810
3698
|
}
|
|
3811
|
-
|
|
3812
|
-
// eslint-disable-next-line consistent-return
|
|
3813
3699
|
nud(token) {
|
|
3814
3700
|
let left;
|
|
3815
3701
|
let right;
|
|
@@ -3838,8 +3724,6 @@ class Parser {
|
|
|
3838
3724
|
case TOK_STAR:
|
|
3839
3725
|
left = { type: 'Identity' };
|
|
3840
3726
|
if (this._lookahead(0) === TOK_RBRACKET) {
|
|
3841
|
-
// This can happen in a multiselect,
|
|
3842
|
-
// [a, b, *]
|
|
3843
3727
|
right = { type: 'Identity' };
|
|
3844
3728
|
} else {
|
|
3845
3729
|
right = this._parseProjectionRHS(bindingPower.Star);
|
|
@@ -3886,8 +3770,6 @@ class Parser {
|
|
|
3886
3770
|
this._errorToken(token);
|
|
3887
3771
|
}
|
|
3888
3772
|
}
|
|
3889
|
-
|
|
3890
|
-
// eslint-disable-next-line consistent-return
|
|
3891
3773
|
led(tokenName, left) {
|
|
3892
3774
|
let condition;
|
|
3893
3775
|
let right;
|
|
@@ -3908,7 +3790,6 @@ class Parser {
|
|
|
3908
3790
|
right = this._parseDotRHS(rbp);
|
|
3909
3791
|
return { type: 'Subexpression', children: [left, right] };
|
|
3910
3792
|
}
|
|
3911
|
-
// Creating a projection.
|
|
3912
3793
|
this._advance();
|
|
3913
3794
|
right = this._parseProjectionRHS(rbp);
|
|
3914
3795
|
return { type: 'ValueProjection', children: [left, right] };
|
|
@@ -3986,7 +3867,6 @@ class Parser {
|
|
|
3986
3867
|
this._errorToken(this._lookaheadToken(0));
|
|
3987
3868
|
}
|
|
3988
3869
|
}
|
|
3989
|
-
|
|
3990
3870
|
_match(tokenType) {
|
|
3991
3871
|
if (this._lookahead(0) === tokenType) {
|
|
3992
3872
|
this._advance();
|
|
@@ -3997,8 +3877,6 @@ class Parser {
|
|
|
3997
3877
|
throw error;
|
|
3998
3878
|
}
|
|
3999
3879
|
}
|
|
4000
|
-
|
|
4001
|
-
// eslint-disable-next-line class-methods-use-this
|
|
4002
3880
|
_errorToken(token) {
|
|
4003
3881
|
const error = new Error(`Invalid token (${
|
|
4004
3882
|
token.type}): "${
|
|
@@ -4006,17 +3884,14 @@ class Parser {
|
|
|
4006
3884
|
error.name = 'ParserError';
|
|
4007
3885
|
throw error;
|
|
4008
3886
|
}
|
|
4009
|
-
|
|
4010
3887
|
_parseChainedIndexExpression() {
|
|
4011
3888
|
const oldIndex = this._getIndex();
|
|
4012
3889
|
if (this._lookahead(0) === TOK_COLON) {
|
|
4013
3890
|
return this._parseSliceExpression();
|
|
4014
3891
|
}
|
|
4015
|
-
// look ahead of the first expression to determine the type
|
|
4016
3892
|
const first = this.expression(0);
|
|
4017
3893
|
const token = this._lookahead(0);
|
|
4018
3894
|
if (token === TOK_COLON) {
|
|
4019
|
-
// now that we know the type revert back to the old position and parse
|
|
4020
3895
|
this._setIndex(oldIndex);
|
|
4021
3896
|
return this._parseSliceExpression();
|
|
4022
3897
|
}
|
|
@@ -4026,7 +3901,6 @@ class Parser {
|
|
|
4026
3901
|
value: first,
|
|
4027
3902
|
};
|
|
4028
3903
|
}
|
|
4029
|
-
|
|
4030
3904
|
_parseUnchainedIndexExpression() {
|
|
4031
3905
|
const oldIndex = this._getIndex();
|
|
4032
3906
|
const firstToken = this._lookahead(0);
|
|
@@ -4055,7 +3929,6 @@ class Parser {
|
|
|
4055
3929
|
this._setIndex(oldIndex);
|
|
4056
3930
|
return this._parseMultiselectList();
|
|
4057
3931
|
}
|
|
4058
|
-
|
|
4059
3932
|
_projectIfSlice(left, right) {
|
|
4060
3933
|
const indexExpr = { type: 'IndexExpression', children: [left, right] };
|
|
4061
3934
|
if (right.type === 'Slice') {
|
|
@@ -4066,20 +3939,16 @@ class Parser {
|
|
|
4066
3939
|
}
|
|
4067
3940
|
return indexExpr;
|
|
4068
3941
|
}
|
|
4069
|
-
|
|
4070
3942
|
_parseSliceExpression() {
|
|
4071
|
-
// [start:end:step] where each part is optional, as well as the last
|
|
4072
|
-
// colon.
|
|
4073
3943
|
const parts = [null, null, null];
|
|
4074
3944
|
let index = 0;
|
|
4075
3945
|
let currentToken = this._lookahead(0);
|
|
4076
3946
|
while (currentToken !== TOK_RBRACKET && index < 3) {
|
|
4077
|
-
if (currentToken === TOK_COLON && index < 2) {
|
|
3947
|
+
if (currentToken === TOK_COLON && index < 2) {
|
|
4078
3948
|
index += 1;
|
|
4079
3949
|
this._advance();
|
|
4080
3950
|
} else {
|
|
4081
3951
|
parts[index] = this.expression(0);
|
|
4082
|
-
// check next token to be either colon or rbracket
|
|
4083
3952
|
const t = this._lookahead(0);
|
|
4084
3953
|
if (t !== TOK_COLON && t !== TOK_RBRACKET) {
|
|
4085
3954
|
const error = new Error(`Syntax error, unexpected token: ${
|
|
@@ -4096,13 +3965,10 @@ class Parser {
|
|
|
4096
3965
|
children: parts,
|
|
4097
3966
|
};
|
|
4098
3967
|
}
|
|
4099
|
-
|
|
4100
3968
|
_parseComparator(left, comparator) {
|
|
4101
3969
|
const right = this.expression(bindingPower[comparator]);
|
|
4102
3970
|
return { type: 'Comparator', name: comparator, children: [left, right] };
|
|
4103
3971
|
}
|
|
4104
|
-
|
|
4105
|
-
// eslint-disable-next-line consistent-return
|
|
4106
3972
|
_parseDotRHS(rbp) {
|
|
4107
3973
|
const lookahead = this._lookahead(0);
|
|
4108
3974
|
const exprTokens = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER, TOK_STAR];
|
|
@@ -4118,7 +3984,6 @@ class Parser {
|
|
|
4118
3984
|
return this._parseMultiselectHash();
|
|
4119
3985
|
}
|
|
4120
3986
|
}
|
|
4121
|
-
|
|
4122
3987
|
_parseProjectionRHS(rbp) {
|
|
4123
3988
|
let right;
|
|
4124
3989
|
if (bindingPower[this._lookahead(0)] < 10) {
|
|
@@ -4139,7 +4004,6 @@ class Parser {
|
|
|
4139
4004
|
}
|
|
4140
4005
|
return right;
|
|
4141
4006
|
}
|
|
4142
|
-
|
|
4143
4007
|
_parseMultiselectList() {
|
|
4144
4008
|
const expressions = [];
|
|
4145
4009
|
while (this._lookahead(0) !== TOK_RBRACKET) {
|
|
@@ -4155,7 +4019,6 @@ class Parser {
|
|
|
4155
4019
|
this._match(TOK_RBRACKET);
|
|
4156
4020
|
return { type: 'MultiSelectList', children: expressions };
|
|
4157
4021
|
}
|
|
4158
|
-
|
|
4159
4022
|
_parseMultiselectHash() {
|
|
4160
4023
|
const pairs = [];
|
|
4161
4024
|
const identifierTypes = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER];
|
|
@@ -4188,20 +4051,6 @@ class Parser {
|
|
|
4188
4051
|
}
|
|
4189
4052
|
}
|
|
4190
4053
|
|
|
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
4054
|
function offsetMS(dateObj, timeZone) {
|
|
4206
4055
|
const tzOffset = new Intl.DateTimeFormat('en-US', { timeZone, timeZoneName: 'longOffset' }).format(dateObj);
|
|
4207
4056
|
const offset = /GMT([+\-−])?(\d{1,2}):?(\d{0,2})?/.exec(tzOffset);
|
|
@@ -4210,16 +4059,11 @@ function offsetMS(dateObj, timeZone) {
|
|
|
4210
4059
|
const result = (((hours || 0) * 60) + 1 * (minutes || 0)) * 60 * 1000;
|
|
4211
4060
|
return sign === '-' ? result * -1 : result;
|
|
4212
4061
|
}
|
|
4213
|
-
|
|
4214
4062
|
function round(num, digits) {
|
|
4215
4063
|
const precision = 10 ** digits;
|
|
4216
4064
|
return Math.round(num * precision) / precision;
|
|
4217
4065
|
}
|
|
4218
|
-
|
|
4219
4066
|
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
4067
|
function adjustTimeZone(dateObj, timeZone) {
|
|
4224
4068
|
if (dateObj === null) return null;
|
|
4225
4069
|
let baseDate = Date.UTC(
|
|
@@ -4232,32 +4076,10 @@ function adjustTimeZone(dateObj, timeZone) {
|
|
|
4232
4076
|
dateObj.getMilliseconds(),
|
|
4233
4077
|
);
|
|
4234
4078
|
baseDate += offsetMS(dateObj, timeZone);
|
|
4235
|
-
|
|
4236
|
-
// get the offset for the default JS environment
|
|
4237
|
-
// return days since the epoch
|
|
4238
4079
|
return new Date(baseDate);
|
|
4239
4080
|
}
|
|
4240
|
-
|
|
4241
4081
|
function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
4242
4082
|
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
4083
|
and: {
|
|
4262
4084
|
_func: resolvedArgs => {
|
|
4263
4085
|
let result = !!valueOf(resolvedArgs[0]);
|
|
@@ -4268,17 +4090,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4268
4090
|
},
|
|
4269
4091
|
_signature: [{ types: [dataTypes.TYPE_ANY], variadic: true }],
|
|
4270
4092
|
},
|
|
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
4093
|
casefold: {
|
|
4283
4094
|
_func: (args, _data, interpreter) => {
|
|
4284
4095
|
const str = toString(args[0]);
|
|
@@ -4288,34 +4099,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4288
4099
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4289
4100
|
],
|
|
4290
4101
|
},
|
|
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
4102
|
datedif: {
|
|
4320
4103
|
_func: args => {
|
|
4321
4104
|
const d1 = toNumber(args[0]);
|
|
@@ -4329,7 +4112,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4329
4112
|
const yearDiff = date2.getFullYear() - date1.getFullYear();
|
|
4330
4113
|
let monthDiff = date2.getMonth() - date1.getMonth();
|
|
4331
4114
|
const dayDiff = date2.getDate() - date1.getDate();
|
|
4332
|
-
|
|
4333
4115
|
if (unit === 'y') {
|
|
4334
4116
|
let y = yearDiff;
|
|
4335
4117
|
if (monthDiff < 0) y -= 1;
|
|
@@ -4358,32 +4140,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4358
4140
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4359
4141
|
],
|
|
4360
4142
|
},
|
|
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
4143
|
datetime: {
|
|
4388
4144
|
_func: args => {
|
|
4389
4145
|
const year = toNumber(args[0]);
|
|
@@ -4394,7 +4150,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4394
4150
|
const seconds = args.length > 5 ? toNumber(args[5]) : 0;
|
|
4395
4151
|
const ms = args.length > 6 ? toNumber(args[6]) : 0;
|
|
4396
4152
|
const tz = args.length > 7 ? toString(args[7]) : null;
|
|
4397
|
-
// javascript months starts from 0
|
|
4398
4153
|
let jsDate = new Date(year, month - 1, day, hours, minutes, seconds, ms);
|
|
4399
4154
|
if (tz) {
|
|
4400
4155
|
jsDate = adjustTimeZone(jsDate, tz);
|
|
@@ -4412,18 +4167,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4412
4167
|
{ types: [dataTypes.TYPE_STRING], optional: true },
|
|
4413
4168
|
],
|
|
4414
4169
|
},
|
|
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
4170
|
day: {
|
|
4428
4171
|
_func: args => {
|
|
4429
4172
|
const date = toNumber(args[0]);
|
|
@@ -4434,19 +4177,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4434
4177
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4435
4178
|
],
|
|
4436
4179
|
},
|
|
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
4180
|
deepScan: {
|
|
4451
4181
|
_func: resolvedArgs => {
|
|
4452
4182
|
const [source, n] = resolvedArgs;
|
|
@@ -4467,16 +4197,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4467
4197
|
{ types: [dataTypes.TYPE_STRING, dataTypes.TYPE_NUMBER] },
|
|
4468
4198
|
],
|
|
4469
4199
|
},
|
|
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
4200
|
entries: {
|
|
4481
4201
|
_func: args => {
|
|
4482
4202
|
const obj = valueOf(args[0]);
|
|
@@ -4494,27 +4214,11 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4494
4214
|
},
|
|
4495
4215
|
],
|
|
4496
4216
|
},
|
|
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
4217
|
eomonth: {
|
|
4512
4218
|
_func: args => {
|
|
4513
4219
|
const date = toNumber(args[0]);
|
|
4514
4220
|
const months = toNumber(args[1]);
|
|
4515
4221
|
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
4222
|
const newDate = new Date(jsDate.getFullYear(), jsDate.getMonth() + months + 1, 0);
|
|
4519
4223
|
return newDate.getTime() / MS_IN_DAY;
|
|
4520
4224
|
},
|
|
@@ -4523,16 +4227,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4523
4227
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4524
4228
|
],
|
|
4525
4229
|
},
|
|
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
4230
|
exp: {
|
|
4537
4231
|
_func: args => {
|
|
4538
4232
|
const value = toNumber(args[0]);
|
|
@@ -4542,37 +4236,10 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4542
4236
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4543
4237
|
],
|
|
4544
4238
|
},
|
|
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
4239
|
false: {
|
|
4554
4240
|
_func: () => false,
|
|
4555
4241
|
_signature: [],
|
|
4556
4242
|
},
|
|
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
4243
|
find: {
|
|
4577
4244
|
_func: args => {
|
|
4578
4245
|
const query = toString(args[0]);
|
|
@@ -4590,16 +4257,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4590
4257
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
4591
4258
|
],
|
|
4592
4259
|
},
|
|
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
4260
|
fromEntries: {
|
|
4604
4261
|
_func: args => {
|
|
4605
4262
|
const array = args[0];
|
|
@@ -4609,51 +4266,19 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4609
4266
|
{ types: [dataTypes.TYPE_ARRAY_ARRAY] },
|
|
4610
4267
|
],
|
|
4611
4268
|
},
|
|
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
4269
|
hour: {
|
|
4625
4270
|
_func: args => {
|
|
4626
|
-
// grab just the fraction part
|
|
4627
4271
|
const time = toNumber(args[0]) % 1;
|
|
4628
4272
|
if (time < 0) {
|
|
4629
4273
|
return null;
|
|
4630
4274
|
}
|
|
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
4275
|
const hour = round(time * 24, 14);
|
|
4635
|
-
|
|
4636
4276
|
return Math.floor(hour % 24);
|
|
4637
4277
|
},
|
|
4638
4278
|
_signature: [
|
|
4639
4279
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4640
4280
|
],
|
|
4641
4281
|
},
|
|
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
4282
|
if: {
|
|
4658
4283
|
_func: (unresolvedArgs, data, interpreter) => {
|
|
4659
4284
|
const conditionNode = unresolvedArgs[0];
|
|
@@ -4670,22 +4295,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4670
4295
|
{ types: [dataTypes.TYPE_ANY] },
|
|
4671
4296
|
{ types: [dataTypes.TYPE_ANY] }],
|
|
4672
4297
|
},
|
|
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
4298
|
left: {
|
|
4690
4299
|
_func: args => {
|
|
4691
4300
|
const numEntries = args.length > 1 ? toNumber(args[1]) : 1;
|
|
@@ -4701,18 +4310,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4701
4310
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
4702
4311
|
],
|
|
4703
4312
|
},
|
|
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
4313
|
lower: {
|
|
4717
4314
|
_func: args => {
|
|
4718
4315
|
const value = toString(args[0]);
|
|
@@ -4722,27 +4319,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4722
4319
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4723
4320
|
],
|
|
4724
4321
|
},
|
|
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
4322
|
mid: {
|
|
4747
4323
|
_func: args => {
|
|
4748
4324
|
const startPos = toNumber(args[1]);
|
|
@@ -4760,27 +4336,12 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4760
4336
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4761
4337
|
],
|
|
4762
4338
|
},
|
|
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
4339
|
minute: {
|
|
4776
4340
|
_func: args => {
|
|
4777
4341
|
const time = toNumber(args[0]) % 1;
|
|
4778
4342
|
if (time < 0) {
|
|
4779
4343
|
return null;
|
|
4780
4344
|
}
|
|
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
4345
|
const minute = Math.round(time * 1440, 10);
|
|
4785
4346
|
return Math.floor(minute % 60);
|
|
4786
4347
|
},
|
|
@@ -4788,20 +4349,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4788
4349
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4789
4350
|
],
|
|
4790
4351
|
},
|
|
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
4352
|
mod: {
|
|
4806
4353
|
_func: args => {
|
|
4807
4354
|
const p1 = toNumber(args[0]);
|
|
@@ -4813,97 +4360,28 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4813
4360
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4814
4361
|
],
|
|
4815
4362
|
},
|
|
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
4363
|
month: {
|
|
4829
4364
|
_func: args => {
|
|
4830
4365
|
const date = toNumber(args[0]);
|
|
4831
4366
|
const jsDate = new Date(date * MS_IN_DAY);
|
|
4832
|
-
// javascript months start from 0ß
|
|
4833
4367
|
return jsDate.getMonth() + 1;
|
|
4834
4368
|
},
|
|
4835
4369
|
_signature: [
|
|
4836
4370
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4837
4371
|
],
|
|
4838
4372
|
},
|
|
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
4373
|
not: {
|
|
4863
4374
|
_func: resolveArgs => !valueOf(resolveArgs[0]),
|
|
4864
4375
|
_signature: [{ types: [dataTypes.TYPE_ANY] }],
|
|
4865
4376
|
},
|
|
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
4377
|
now: {
|
|
4874
4378
|
_func: () => Date.now() / MS_IN_DAY,
|
|
4875
4379
|
_signature: [],
|
|
4876
4380
|
},
|
|
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
4381
|
null: {
|
|
4886
4382
|
_func: () => null,
|
|
4887
4383
|
_signature: [],
|
|
4888
4384
|
},
|
|
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
4385
|
or: {
|
|
4908
4386
|
_func: resolvedArgs => {
|
|
4909
4387
|
let result = !!valueOf(resolvedArgs[0]);
|
|
@@ -4914,17 +4392,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4914
4392
|
},
|
|
4915
4393
|
_signature: [{ types: [dataTypes.TYPE_ANY], variadic: true }],
|
|
4916
4394
|
},
|
|
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
4395
|
power: {
|
|
4929
4396
|
_func: args => {
|
|
4930
4397
|
const base = toNumber(args[0]);
|
|
@@ -4936,21 +4403,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4936
4403
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
4937
4404
|
],
|
|
4938
4405
|
},
|
|
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
4406
|
proper: {
|
|
4955
4407
|
_func: args => {
|
|
4956
4408
|
const text = toString(args[0]);
|
|
@@ -4963,24 +4415,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4963
4415
|
{ types: [dataTypes.TYPE_STRING] },
|
|
4964
4416
|
],
|
|
4965
4417
|
},
|
|
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
4418
|
replace: {
|
|
4985
4419
|
_func: args => {
|
|
4986
4420
|
const oldText = toString(args[0]);
|
|
@@ -4990,7 +4424,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
4990
4424
|
if (startNum < 0) {
|
|
4991
4425
|
return null;
|
|
4992
4426
|
}
|
|
4993
|
-
|
|
4994
4427
|
const lhs = oldText.substr(0, startNum);
|
|
4995
4428
|
const rhs = oldText.substr(startNum + numChars);
|
|
4996
4429
|
return lhs + newText + rhs;
|
|
@@ -5002,17 +4435,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5002
4435
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5003
4436
|
],
|
|
5004
4437
|
},
|
|
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
4438
|
rept: {
|
|
5017
4439
|
_func: args => {
|
|
5018
4440
|
const text = toString(args[0]);
|
|
@@ -5027,23 +4449,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5027
4449
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5028
4450
|
],
|
|
5029
4451
|
},
|
|
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
4452
|
right: {
|
|
5048
4453
|
_func: args => {
|
|
5049
4454
|
const numEntries = args.length > 1 ? toNumber(args[1]) : 1;
|
|
@@ -5061,29 +4466,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5061
4466
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5062
4467
|
],
|
|
5063
4468
|
},
|
|
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
4469
|
round: {
|
|
5088
4470
|
_func: args => {
|
|
5089
4471
|
const number = toNumber(args[0]);
|
|
@@ -5095,38 +4477,15 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5095
4477
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5096
4478
|
],
|
|
5097
4479
|
},
|
|
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
4480
|
search: {
|
|
5118
4481
|
_func: args => {
|
|
5119
4482
|
const findText = toString(args[0]);
|
|
5120
4483
|
const withinText = toString(args[1]);
|
|
5121
4484
|
const startPos = toNumber(args[2]);
|
|
5122
4485
|
if (findText === null || withinText === null || withinText.length === 0) return [];
|
|
5123
|
-
// escape all characters that would otherwise create a regular expression
|
|
5124
4486
|
const reString = findText.replace(/([[.\\^$()+{])/g, '\\$1')
|
|
5125
|
-
// add the single character wildcard
|
|
5126
4487
|
.replace(/~?\?/g, match => match === '~?' ? '\\?' : '.')
|
|
5127
|
-
// add the multi-character wildcard
|
|
5128
4488
|
.replace(/~?\*/g, match => match === '~*' ? '\\*' : '.*?')
|
|
5129
|
-
// get rid of the escape characters
|
|
5130
4489
|
.replace(/~~/g, '~');
|
|
5131
4490
|
const re = new RegExp(reString);
|
|
5132
4491
|
const result = withinText.substring(startPos).match(re);
|
|
@@ -5138,28 +4497,13 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5138
4497
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5139
4498
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5140
4499
|
],
|
|
5141
|
-
|
|
5142
4500
|
},
|
|
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
4501
|
second: {
|
|
5155
4502
|
_func: args => {
|
|
5156
4503
|
const time = toNumber(args[0]) % 1;
|
|
5157
4504
|
if (time < 0) {
|
|
5158
4505
|
return null;
|
|
5159
4506
|
}
|
|
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
4507
|
const seconds = round(time * 86400, 10);
|
|
5164
4508
|
return Math.floor(seconds % 60);
|
|
5165
4509
|
},
|
|
@@ -5167,19 +4511,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5167
4511
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5168
4512
|
],
|
|
5169
4513
|
},
|
|
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
4514
|
split: {
|
|
5184
4515
|
_func: args => {
|
|
5185
4516
|
const str = toString(args[0]);
|
|
@@ -5191,16 +4522,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5191
4522
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5192
4523
|
],
|
|
5193
4524
|
},
|
|
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
4525
|
sqrt: {
|
|
5205
4526
|
_func: args => {
|
|
5206
4527
|
const result = Math.sqrt(toNumber(args[0]));
|
|
@@ -5213,20 +4534,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5213
4534
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5214
4535
|
],
|
|
5215
4536
|
},
|
|
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
4537
|
stdev: {
|
|
5231
4538
|
_func: args => {
|
|
5232
4539
|
const values = args[0] || [];
|
|
@@ -5238,7 +4545,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5238
4545
|
const sumSquare = coercedValues.reduce((a, b) => a + b * b, 0);
|
|
5239
4546
|
const result = Math.sqrt((sumSquare - values.length * mean * mean) / (values.length - 1));
|
|
5240
4547
|
if (Number.isNaN(result)) {
|
|
5241
|
-
// this would never happen
|
|
5242
4548
|
return null;
|
|
5243
4549
|
}
|
|
5244
4550
|
return result;
|
|
@@ -5247,20 +4553,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5247
4553
|
{ types: [dataTypes.TYPE_ARRAY_NUMBER] },
|
|
5248
4554
|
],
|
|
5249
4555
|
},
|
|
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
4556
|
stdevp: {
|
|
5265
4557
|
_func: args => {
|
|
5266
4558
|
const values = args[0] || [];
|
|
@@ -5272,7 +4564,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5272
4564
|
const meanSumSquare = coercedValues.reduce((a, b) => a + b * b, 0) / values.length;
|
|
5273
4565
|
const result = Math.sqrt(meanSumSquare - mean * mean);
|
|
5274
4566
|
if (Number.isNaN(result)) {
|
|
5275
|
-
// this would never happen
|
|
5276
4567
|
return null;
|
|
5277
4568
|
}
|
|
5278
4569
|
return result;
|
|
@@ -5281,43 +4572,18 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5281
4572
|
{ types: [dataTypes.TYPE_ARRAY_NUMBER] },
|
|
5282
4573
|
],
|
|
5283
4574
|
},
|
|
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
4575
|
substitute: {
|
|
5307
4576
|
_func: args => {
|
|
5308
4577
|
const src = toString(args[0]);
|
|
5309
4578
|
const old = toString(args[1]);
|
|
5310
4579
|
const replacement = toString(args[2]);
|
|
5311
|
-
// no third parameter? replace all instances
|
|
5312
4580
|
if (args.length <= 3) return src.replaceAll(old, replacement);
|
|
5313
4581
|
const whch = toNumber(args[3]);
|
|
5314
4582
|
if (whch < 1) return src;
|
|
5315
|
-
// find the instance to replace
|
|
5316
4583
|
let pos = -1;
|
|
5317
4584
|
for (let i = 0; i < whch; i += 1) {
|
|
5318
4585
|
pos += 1;
|
|
5319
4586
|
const nextFind = src.slice(pos).indexOf(old);
|
|
5320
|
-
// no instance to match 'Which'
|
|
5321
4587
|
if (nextFind === -1) return src;
|
|
5322
4588
|
pos += nextFind;
|
|
5323
4589
|
}
|
|
@@ -5330,21 +4596,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5330
4596
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5331
4597
|
],
|
|
5332
4598
|
},
|
|
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
4599
|
time: {
|
|
5349
4600
|
_func: args => {
|
|
5350
4601
|
const hours = toNumber(args[0]);
|
|
@@ -5362,65 +4613,23 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5362
4613
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5363
4614
|
],
|
|
5364
4615
|
},
|
|
5365
|
-
|
|
5366
|
-
/**
|
|
5367
|
-
* returns the number of days since epoch
|
|
5368
|
-
* @return number
|
|
5369
|
-
* @function today
|
|
5370
|
-
* @category openFormula
|
|
5371
|
-
*/
|
|
5372
4616
|
today: {
|
|
5373
4617
|
_func: () => Math.floor(Date.now() / MS_IN_DAY),
|
|
5374
4618
|
_signature: [],
|
|
5375
4619
|
},
|
|
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
4620
|
trim: {
|
|
5389
4621
|
_func: args => {
|
|
5390
4622
|
const text = toString(args[0]);
|
|
5391
|
-
// only removes the space character
|
|
5392
|
-
// other whitespace characters like \t \n left intact
|
|
5393
4623
|
return text.split(' ').filter(x => x).join(' ');
|
|
5394
4624
|
},
|
|
5395
4625
|
_signature: [
|
|
5396
4626
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5397
4627
|
],
|
|
5398
4628
|
},
|
|
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
4629
|
true: {
|
|
5408
4630
|
_func: () => true,
|
|
5409
4631
|
_signature: [],
|
|
5410
4632
|
},
|
|
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
4633
|
trunc: {
|
|
5425
4634
|
_func: args => {
|
|
5426
4635
|
const number = toNumber(args[0]);
|
|
@@ -5433,20 +4642,8 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5433
4642
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5434
4643
|
],
|
|
5435
4644
|
},
|
|
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
4645
|
unique: {
|
|
5447
4646
|
_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
4647
|
const valueArray = args[0].map(a => valueOf(a));
|
|
5451
4648
|
return args[0].filter((v, index) => valueArray.indexOf(valueOf(v)) === index);
|
|
5452
4649
|
},
|
|
@@ -5454,18 +4651,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5454
4651
|
{ types: [dataTypes.TYPE_ARRAY] },
|
|
5455
4652
|
],
|
|
5456
4653
|
},
|
|
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
4654
|
upper: {
|
|
5470
4655
|
_func: args => {
|
|
5471
4656
|
const value = toString(args[0]);
|
|
@@ -5475,19 +4660,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5475
4660
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5476
4661
|
],
|
|
5477
4662
|
},
|
|
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
4663
|
value: {
|
|
5492
4664
|
_func: args => {
|
|
5493
4665
|
const obj = args[0] || {};
|
|
@@ -5497,7 +4669,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5497
4669
|
debug.push(`Failed to find: '${index}'`);
|
|
5498
4670
|
const available = Object.keys(obj).map(a => `'${a}'`).toString();
|
|
5499
4671
|
if (available.length) debug.push(`Available fields: ${available}`);
|
|
5500
|
-
|
|
5501
4672
|
return null;
|
|
5502
4673
|
}
|
|
5503
4674
|
return result;
|
|
@@ -5507,43 +4678,18 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5507
4678
|
{ types: [dataTypes.TYPE_STRING, dataTypes.TYPE_NUMBER] },
|
|
5508
4679
|
],
|
|
5509
4680
|
},
|
|
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
4681
|
weekday: {
|
|
5532
4682
|
_func: args => {
|
|
5533
4683
|
const date = toNumber(args[0]);
|
|
5534
4684
|
const type = args.length > 1 ? toNumber(args[1]) : 1;
|
|
5535
4685
|
const jsDate = new Date(date * MS_IN_DAY);
|
|
5536
4686
|
const day = jsDate.getDay();
|
|
5537
|
-
// day is in range [0-7) with 0 mapping to sunday
|
|
5538
4687
|
switch (type) {
|
|
5539
4688
|
case 1:
|
|
5540
|
-
// range = [1, 7], sunday = 1
|
|
5541
4689
|
return day + 1;
|
|
5542
4690
|
case 2:
|
|
5543
|
-
// range = [1, 7] sunday = 7
|
|
5544
4691
|
return ((day + 6) % 7) + 1;
|
|
5545
4692
|
case 3:
|
|
5546
|
-
// range = [0, 6] sunday = 6
|
|
5547
4693
|
return (day + 6) % 7;
|
|
5548
4694
|
default:
|
|
5549
4695
|
return null;
|
|
@@ -5554,17 +4700,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5554
4700
|
{ types: [dataTypes.TYPE_NUMBER], optional: true },
|
|
5555
4701
|
],
|
|
5556
4702
|
},
|
|
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
4703
|
year: {
|
|
5569
4704
|
_func: args => {
|
|
5570
4705
|
const date = toNumber(args[0]);
|
|
@@ -5575,7 +4710,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5575
4710
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5576
4711
|
],
|
|
5577
4712
|
},
|
|
5578
|
-
|
|
5579
4713
|
charCode: {
|
|
5580
4714
|
_func: args => {
|
|
5581
4715
|
const code = toNumber(args[0]);
|
|
@@ -5588,7 +4722,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5588
4722
|
{ types: [dataTypes.TYPE_NUMBER] },
|
|
5589
4723
|
],
|
|
5590
4724
|
},
|
|
5591
|
-
|
|
5592
4725
|
codePoint: {
|
|
5593
4726
|
_func: args => {
|
|
5594
4727
|
const text = toString(args[0]);
|
|
@@ -5601,28 +4734,24 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5601
4734
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5602
4735
|
],
|
|
5603
4736
|
},
|
|
5604
|
-
|
|
5605
4737
|
encodeUrlComponent: {
|
|
5606
4738
|
_func: args => encodeURIComponent(args[0]),
|
|
5607
4739
|
_signature: [
|
|
5608
4740
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5609
4741
|
],
|
|
5610
4742
|
},
|
|
5611
|
-
|
|
5612
4743
|
encodeUrl: {
|
|
5613
4744
|
_func: args => encodeURI(args[0]),
|
|
5614
4745
|
_signature: [
|
|
5615
4746
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5616
4747
|
],
|
|
5617
4748
|
},
|
|
5618
|
-
|
|
5619
4749
|
decodeUrlComponent: {
|
|
5620
4750
|
_func: args => decodeURIComponent(args[0]),
|
|
5621
4751
|
_signature: [
|
|
5622
4752
|
{ types: [dataTypes.TYPE_STRING] },
|
|
5623
4753
|
],
|
|
5624
4754
|
},
|
|
5625
|
-
|
|
5626
4755
|
decodeUrl: {
|
|
5627
4756
|
_func: args => decodeURI(args[0]),
|
|
5628
4757
|
_signature: [
|
|
@@ -5632,27 +4761,6 @@ function openFormulaFunctions(valueOf, toString, toNumber, debug = []) {
|
|
|
5632
4761
|
};
|
|
5633
4762
|
}
|
|
5634
4763
|
|
|
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
4764
|
function functions(
|
|
5657
4765
|
runtime,
|
|
5658
4766
|
isObject,
|
|
@@ -5675,7 +4783,6 @@ function functions(
|
|
|
5675
4783
|
TYPE_ARRAY_NUMBER,
|
|
5676
4784
|
TYPE_ARRAY_STRING,
|
|
5677
4785
|
} = dataTypes;
|
|
5678
|
-
|
|
5679
4786
|
function createKeyFunction(exprefNode, allowedTypes) {
|
|
5680
4787
|
return x => {
|
|
5681
4788
|
const current = runtime.interpreter.visit(exprefNode, x);
|
|
@@ -5687,46 +4794,11 @@ function functions(
|
|
|
5687
4794
|
return current;
|
|
5688
4795
|
};
|
|
5689
4796
|
}
|
|
5690
|
-
|
|
5691
4797
|
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
4798
|
abs: {
|
|
5715
4799
|
_func: resolvedArgs => Math.abs(resolvedArgs[0]),
|
|
5716
4800
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5717
4801
|
},
|
|
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
4802
|
avg: {
|
|
5731
4803
|
_func: resolvedArgs => {
|
|
5732
4804
|
let sum = 0;
|
|
@@ -5738,59 +4810,15 @@ function functions(
|
|
|
5738
4810
|
},
|
|
5739
4811
|
_signature: [{ types: [TYPE_ARRAY_NUMBER] }],
|
|
5740
4812
|
},
|
|
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
4813
|
ceil: {
|
|
5754
4814
|
_func: resolvedArgs => Math.ceil(resolvedArgs[0]),
|
|
5755
4815
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5756
4816
|
},
|
|
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
4817
|
contains: {
|
|
5778
4818
|
_func: resolvedArgs => valueOf(resolvedArgs[0]).indexOf(valueOf(resolvedArgs[1])) >= 0,
|
|
5779
4819
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY] },
|
|
5780
4820
|
{ types: [TYPE_ANY] }],
|
|
5781
4821
|
},
|
|
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
4822
|
endsWith: {
|
|
5795
4823
|
_func: resolvedArgs => {
|
|
5796
4824
|
const searchStr = valueOf(resolvedArgs[0]);
|
|
@@ -5799,34 +4827,10 @@ function functions(
|
|
|
5799
4827
|
},
|
|
5800
4828
|
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }],
|
|
5801
4829
|
},
|
|
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
4830
|
floor: {
|
|
5815
4831
|
_func: resolvedArgs => Math.floor(resolvedArgs[0]),
|
|
5816
4832
|
_signature: [{ types: [TYPE_NUMBER] }],
|
|
5817
4833
|
},
|
|
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
4834
|
join: {
|
|
5831
4835
|
_func: resolvedArgs => {
|
|
5832
4836
|
const joinChar = resolvedArgs[0];
|
|
@@ -5838,17 +4842,6 @@ function functions(
|
|
|
5838
4842
|
{ types: [TYPE_ARRAY_STRING] },
|
|
5839
4843
|
],
|
|
5840
4844
|
},
|
|
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
4845
|
keys: {
|
|
5853
4846
|
_func: resolvedArgs => {
|
|
5854
4847
|
if (resolvedArgs[0] === null) return [];
|
|
@@ -5856,54 +4849,14 @@ function functions(
|
|
|
5856
4849
|
},
|
|
5857
4850
|
_signature: [{ types: [TYPE_ANY] }],
|
|
5858
4851
|
},
|
|
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
4852
|
length: {
|
|
5883
4853
|
_func: resolvedArgs => {
|
|
5884
4854
|
const arg = valueOf(resolvedArgs[0]);
|
|
5885
4855
|
if (isObject(arg)) return Object.keys(arg).length;
|
|
5886
|
-
|
|
5887
4856
|
return isArray(arg) ? arg.length : toString(arg).length;
|
|
5888
4857
|
},
|
|
5889
4858
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT] }],
|
|
5890
4859
|
},
|
|
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
4860
|
map: {
|
|
5908
4861
|
_func: resolvedArgs => {
|
|
5909
4862
|
const exprefNode = resolvedArgs[0];
|
|
@@ -5911,35 +4864,15 @@ function functions(
|
|
|
5911
4864
|
},
|
|
5912
4865
|
_signature: [{ types: [TYPE_EXPREF] }, { types: [TYPE_ARRAY] }],
|
|
5913
4866
|
},
|
|
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
4867
|
max: {
|
|
5932
4868
|
_func: args => {
|
|
5933
|
-
// flatten the args into a single array
|
|
5934
4869
|
const array = args.reduce((prev, cur) => {
|
|
5935
4870
|
if (Array.isArray(cur)) prev.push(...cur);
|
|
5936
4871
|
else prev.push(cur);
|
|
5937
4872
|
return prev;
|
|
5938
4873
|
}, []);
|
|
5939
|
-
|
|
5940
4874
|
const first = array.find(r => r !== null);
|
|
5941
4875
|
if (array.length === 0 || first === undefined) return null;
|
|
5942
|
-
// use the first value to determine the comparison type
|
|
5943
4876
|
const isNumber = getTypeName(first, true) === TYPE_NUMBER;
|
|
5944
4877
|
const compare = isNumber
|
|
5945
4878
|
? (prev, cur) => {
|
|
@@ -5950,25 +4883,10 @@ function functions(
|
|
|
5950
4883
|
const current = toString(cur);
|
|
5951
4884
|
return prev.localeCompare(current) === 1 ? prev : current;
|
|
5952
4885
|
};
|
|
5953
|
-
|
|
5954
4886
|
return array.reduce(compare, isNumber ? toNumber(first) : toString(first));
|
|
5955
4887
|
},
|
|
5956
4888
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING], variadic: true }],
|
|
5957
4889
|
},
|
|
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
4890
|
maxBy: {
|
|
5973
4891
|
_func: resolvedArgs => {
|
|
5974
4892
|
const exprefNode = resolvedArgs[1];
|
|
@@ -5988,22 +4906,6 @@ function functions(
|
|
|
5988
4906
|
},
|
|
5989
4907
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
5990
4908
|
},
|
|
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
4909
|
merge: {
|
|
6008
4910
|
_func: resolvedArgs => {
|
|
6009
4911
|
const merged = {};
|
|
@@ -6016,35 +4918,15 @@ function functions(
|
|
|
6016
4918
|
},
|
|
6017
4919
|
_signature: [{ types: [TYPE_OBJECT], variadic: true }],
|
|
6018
4920
|
},
|
|
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
4921
|
min: {
|
|
6037
4922
|
_func: args => {
|
|
6038
|
-
// flatten the args into a single array
|
|
6039
4923
|
const array = args.reduce((prev, cur) => {
|
|
6040
4924
|
if (Array.isArray(cur)) prev.push(...cur);
|
|
6041
4925
|
else prev.push(cur);
|
|
6042
4926
|
return prev;
|
|
6043
4927
|
}, []);
|
|
6044
|
-
|
|
6045
4928
|
const first = array.find(r => r !== null);
|
|
6046
4929
|
if (array.length === 0 || first === undefined) return null;
|
|
6047
|
-
// use the first value to determine the comparison type
|
|
6048
4930
|
const isNumber = getTypeName(first, true) === TYPE_NUMBER;
|
|
6049
4931
|
const compare = isNumber
|
|
6050
4932
|
? (prev, cur) => {
|
|
@@ -6055,25 +4937,10 @@ function functions(
|
|
|
6055
4937
|
const current = toString(cur);
|
|
6056
4938
|
return prev.localeCompare(current) === 1 ? current : prev;
|
|
6057
4939
|
};
|
|
6058
|
-
|
|
6059
4940
|
return array.reduce(compare, isNumber ? toNumber(first) : toString(first));
|
|
6060
4941
|
},
|
|
6061
4942
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING], variadic: true }],
|
|
6062
4943
|
},
|
|
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
4944
|
minBy: {
|
|
6078
4945
|
_func: resolvedArgs => {
|
|
6079
4946
|
const exprefNode = resolvedArgs[1];
|
|
@@ -6093,48 +4960,10 @@ function functions(
|
|
|
6093
4960
|
},
|
|
6094
4961
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
6095
4962
|
},
|
|
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
4963
|
notNull: {
|
|
6112
4964
|
_func: resolvedArgs => resolvedArgs.find(arg => getTypeName(arg) !== TYPE_NULL) || null,
|
|
6113
4965
|
_signature: [{ types: [TYPE_ANY], variadic: true }],
|
|
6114
4966
|
},
|
|
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
4967
|
reduce: {
|
|
6139
4968
|
_func: resolvedArgs => {
|
|
6140
4969
|
const exprefNode = resolvedArgs[0];
|
|
@@ -6151,23 +4980,10 @@ function functions(
|
|
|
6151
4980
|
{ types: [TYPE_ANY], optional: true },
|
|
6152
4981
|
],
|
|
6153
4982
|
},
|
|
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
4983
|
register: {
|
|
6167
4984
|
_func: resolvedArgs => {
|
|
6168
4985
|
const functionName = resolvedArgs[0];
|
|
6169
4986
|
const exprefNode = resolvedArgs[1];
|
|
6170
|
-
|
|
6171
4987
|
if (functionMap[functionName]) {
|
|
6172
4988
|
debug.push(`Cannot re-register '${functionName}'`);
|
|
6173
4989
|
return {};
|
|
@@ -6183,15 +4999,6 @@ function functions(
|
|
|
6183
4999
|
{ types: [TYPE_EXPREF] },
|
|
6184
5000
|
],
|
|
6185
5001
|
},
|
|
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
5002
|
reverse: {
|
|
6196
5003
|
_func: resolvedArgs => {
|
|
6197
5004
|
const originalStr = valueOf(resolvedArgs[0]);
|
|
@@ -6209,18 +5016,6 @@ function functions(
|
|
|
6209
5016
|
},
|
|
6210
5017
|
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY] }],
|
|
6211
5018
|
},
|
|
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
5019
|
sort: {
|
|
6225
5020
|
_func: resolvedArgs => {
|
|
6226
5021
|
const sortedArray = resolvedArgs[0].slice(0);
|
|
@@ -6238,24 +5033,6 @@ function functions(
|
|
|
6238
5033
|
},
|
|
6239
5034
|
_signature: [{ types: [TYPE_ARRAY, TYPE_ARRAY_STRING, TYPE_ARRAY_NUMBER] }],
|
|
6240
5035
|
},
|
|
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
5036
|
sortBy: {
|
|
6260
5037
|
_func: resolvedArgs => {
|
|
6261
5038
|
const sortedArray = resolvedArgs[0].slice(0);
|
|
@@ -6269,13 +5046,6 @@ function functions(
|
|
|
6269
5046
|
if ([TYPE_NUMBER, TYPE_STRING].indexOf(requiredType) < 0) {
|
|
6270
5047
|
throw new Error('TypeError');
|
|
6271
5048
|
}
|
|
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
5049
|
const decorated = [];
|
|
6280
5050
|
for (let i = 0; i < sortedArray.length; i += 1) {
|
|
6281
5051
|
decorated.push([i, sortedArray[i]]);
|
|
@@ -6300,12 +5070,8 @@ function functions(
|
|
|
6300
5070
|
if (exprA < exprB) {
|
|
6301
5071
|
return -1;
|
|
6302
5072
|
}
|
|
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
5073
|
return a[0] - b[0];
|
|
6307
5074
|
});
|
|
6308
|
-
// Undecorate: extract out the original list elements.
|
|
6309
5075
|
for (let j = 0; j < decorated.length; j += 1) {
|
|
6310
5076
|
[, sortedArray[j]] = decorated[j];
|
|
6311
5077
|
}
|
|
@@ -6313,32 +5079,10 @@ function functions(
|
|
|
6313
5079
|
},
|
|
6314
5080
|
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }],
|
|
6315
5081
|
},
|
|
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
5082
|
startsWith: {
|
|
6328
5083
|
_func: resolvedArgs => valueOf(resolvedArgs[0]).startsWith(valueOf(resolvedArgs[1])),
|
|
6329
5084
|
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }],
|
|
6330
5085
|
},
|
|
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
5086
|
sum: {
|
|
6343
5087
|
_func: resolvedArgs => {
|
|
6344
5088
|
let sum = 0;
|
|
@@ -6349,20 +5093,6 @@ function functions(
|
|
|
6349
5093
|
},
|
|
6350
5094
|
_signature: [{ types: [TYPE_ARRAY_NUMBER] }],
|
|
6351
5095
|
},
|
|
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
5096
|
toArray: {
|
|
6367
5097
|
_func: resolvedArgs => {
|
|
6368
5098
|
if (getTypeName(resolvedArgs[0]) === TYPE_ARRAY) {
|
|
@@ -6370,31 +5100,8 @@ function functions(
|
|
|
6370
5100
|
}
|
|
6371
5101
|
return [resolvedArgs[0]];
|
|
6372
5102
|
},
|
|
6373
|
-
|
|
6374
5103
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6375
5104
|
},
|
|
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
5105
|
toNumber: {
|
|
6399
5106
|
_func: resolvedArgs => {
|
|
6400
5107
|
const typeName = getTypeName(resolvedArgs[0]);
|
|
@@ -6408,20 +5115,6 @@ function functions(
|
|
|
6408
5115
|
},
|
|
6409
5116
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6410
5117
|
},
|
|
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
5118
|
toString: {
|
|
6426
5119
|
_func: resolvedArgs => {
|
|
6427
5120
|
if (getTypeName(resolvedArgs[0]) === TYPE_STRING) {
|
|
@@ -6429,30 +5122,8 @@ function functions(
|
|
|
6429
5122
|
}
|
|
6430
5123
|
return JSON.stringify(resolvedArgs[0]);
|
|
6431
5124
|
},
|
|
6432
|
-
|
|
6433
5125
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6434
5126
|
},
|
|
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
5127
|
type: {
|
|
6457
5128
|
_func: resolvedArgs => ({
|
|
6458
5129
|
[TYPE_NUMBER]: 'number',
|
|
@@ -6465,18 +5136,6 @@ function functions(
|
|
|
6465
5136
|
}[getTypeName(resolvedArgs[0])]),
|
|
6466
5137
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6467
5138
|
},
|
|
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
5139
|
values: {
|
|
6481
5140
|
_func: resolvedArgs => {
|
|
6482
5141
|
const arg = valueOf(resolvedArgs[0]);
|
|
@@ -6485,19 +5144,6 @@ function functions(
|
|
|
6485
5144
|
},
|
|
6486
5145
|
_signature: [{ types: [TYPE_ANY] }],
|
|
6487
5146
|
},
|
|
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
5147
|
zip: {
|
|
6502
5148
|
_func: args => {
|
|
6503
5149
|
const count = args.reduce((min, current) => Math.min(min, current.length), args[0].length);
|
|
@@ -6516,17 +5162,13 @@ function functions(
|
|
|
6516
5162
|
return functionMap;
|
|
6517
5163
|
}
|
|
6518
5164
|
|
|
6519
|
-
/* eslint-disable max-classes-per-file */
|
|
6520
|
-
|
|
6521
|
-
// Type constants used to define functions.
|
|
6522
5165
|
const {
|
|
6523
5166
|
TYPE_CLASS,
|
|
6524
5167
|
TYPE_ANY,
|
|
6525
5168
|
} = dataTypes;
|
|
6526
|
-
|
|
6527
5169
|
function getToNumber(stringToNumber, debug = []) {
|
|
6528
5170
|
return value => {
|
|
6529
|
-
const n = getValueOf(value);
|
|
5171
|
+
const n = getValueOf(value);
|
|
6530
5172
|
if (n === null) return null;
|
|
6531
5173
|
if (n instanceof Array) {
|
|
6532
5174
|
debug.push('Converted array to zero');
|
|
@@ -6542,26 +5184,20 @@ function getToNumber(stringToNumber, debug = []) {
|
|
|
6542
5184
|
}
|
|
6543
5185
|
function toString(a) {
|
|
6544
5186
|
if (a === null || a === undefined) return '';
|
|
6545
|
-
// don't call a 'toString' method, since we could have a child named 'toString()'
|
|
6546
5187
|
return a.toString();
|
|
6547
5188
|
}
|
|
6548
|
-
|
|
6549
5189
|
const defaultStringToNumber = (str => {
|
|
6550
5190
|
const n = +str;
|
|
6551
5191
|
return Number.isNaN(n) ? 0 : n;
|
|
6552
5192
|
});
|
|
6553
|
-
|
|
6554
5193
|
function isClass(obj) {
|
|
6555
5194
|
if (obj === null) return false;
|
|
6556
5195
|
if (Array.isArray(obj)) return false;
|
|
6557
5196
|
return obj.constructor.name !== 'Object';
|
|
6558
5197
|
}
|
|
6559
|
-
|
|
6560
5198
|
function matchClass(arg, expectedList) {
|
|
6561
|
-
// checking isClass() generates a dependency -- so call it only if necessary
|
|
6562
5199
|
return expectedList.includes(TYPE_CLASS) && isClass(arg);
|
|
6563
5200
|
}
|
|
6564
|
-
|
|
6565
5201
|
class Runtime {
|
|
6566
5202
|
constructor(debug, toNumber, customFunctions = {}) {
|
|
6567
5203
|
this.strictDeepEqual = strictDeepEqual;
|
|
@@ -6576,25 +5212,16 @@ class Runtime {
|
|
|
6576
5212
|
toString,
|
|
6577
5213
|
debug,
|
|
6578
5214
|
);
|
|
6579
|
-
|
|
6580
5215
|
Object.entries(
|
|
6581
5216
|
openFormulaFunctions(getValueOf, toString, toNumber, debug),
|
|
6582
5217
|
).forEach(([fname, func]) => {
|
|
6583
5218
|
this.functionTable[fname] = func;
|
|
6584
5219
|
});
|
|
6585
|
-
|
|
6586
5220
|
Object.entries(customFunctions).forEach(([fname, func]) => {
|
|
6587
5221
|
this.functionTable[fname] = func;
|
|
6588
5222
|
});
|
|
6589
5223
|
}
|
|
6590
|
-
|
|
6591
|
-
// eslint-disable-next-line class-methods-use-this
|
|
6592
5224
|
_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
5225
|
if (signature.length === 0) {
|
|
6599
5226
|
return;
|
|
6600
5227
|
}
|
|
@@ -6613,39 +5240,31 @@ class Runtime {
|
|
|
6613
5240
|
+ `takes ${signature.length}${pluralized
|
|
6614
5241
|
} but received ${args.length}`);
|
|
6615
5242
|
}
|
|
6616
|
-
// if the arguments are unresolved, there's no point in validating types
|
|
6617
5243
|
if (!bResolved) return;
|
|
6618
5244
|
let currentSpec;
|
|
6619
5245
|
let actualType;
|
|
6620
5246
|
const limit = Math.min(signature.length, args.length);
|
|
6621
5247
|
for (let i = 0; i < limit; i += 1) {
|
|
6622
5248
|
currentSpec = signature[i].types;
|
|
6623
|
-
// Try to avoid checks that will introspect the object and generate dependencies
|
|
6624
5249
|
if (!matchClass(args[i], currentSpec) && !currentSpec.includes(TYPE_ANY)) {
|
|
6625
5250
|
actualType = getTypeNames(args[i]);
|
|
6626
|
-
// eslint-disable-next-line no-param-reassign
|
|
6627
5251
|
args[i] = matchType(actualType, currentSpec, args[i], argName, this.toNumber, toString);
|
|
6628
5252
|
}
|
|
6629
5253
|
}
|
|
6630
5254
|
}
|
|
6631
|
-
|
|
6632
5255
|
callFunction(name, resolvedArgs, data, interpreter, bResolved = true) {
|
|
6633
|
-
// this check will weed out 'valueOf', 'toString' etc
|
|
6634
5256
|
if (!Object.prototype.hasOwnProperty.call(this.functionTable, name)) throw new Error(`Unknown function: ${name}()`);
|
|
6635
|
-
|
|
6636
5257
|
const functionEntry = this.functionTable[name];
|
|
6637
5258
|
this._validateArgs(name, resolvedArgs, functionEntry._signature, bResolved);
|
|
6638
5259
|
return functionEntry._func.call(this, resolvedArgs, data, interpreter);
|
|
6639
5260
|
}
|
|
6640
5261
|
}
|
|
6641
|
-
|
|
6642
5262
|
class Formula {
|
|
6643
5263
|
constructor(debug, customFunctions, stringToNumberFn) {
|
|
6644
5264
|
this.debug = debug;
|
|
6645
5265
|
this.toNumber = getToNumber(stringToNumberFn || defaultStringToNumber, debug);
|
|
6646
5266
|
this.runtime = new Runtime(debug, this.toNumber, customFunctions);
|
|
6647
5267
|
}
|
|
6648
|
-
|
|
6649
5268
|
compile(stream, allowedGlobalNames = []) {
|
|
6650
5269
|
let ast;
|
|
6651
5270
|
try {
|
|
@@ -6657,11 +5276,7 @@ class Formula {
|
|
|
6657
5276
|
}
|
|
6658
5277
|
return ast;
|
|
6659
5278
|
}
|
|
6660
|
-
|
|
6661
5279
|
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
5280
|
this.runtime.interpreter = new TreeInterpreter(
|
|
6666
5281
|
this.runtime,
|
|
6667
5282
|
globals,
|
|
@@ -6670,7 +5285,6 @@ class Formula {
|
|
|
6670
5285
|
this.debug,
|
|
6671
5286
|
language,
|
|
6672
5287
|
);
|
|
6673
|
-
|
|
6674
5288
|
try {
|
|
6675
5289
|
return this.runtime.interpreter.search(node, data);
|
|
6676
5290
|
} catch (e) {
|
|
@@ -6680,33 +5294,7 @@ class Formula {
|
|
|
6680
5294
|
}
|
|
6681
5295
|
}
|
|
6682
5296
|
|
|
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
5297
|
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
5298
|
constructor(
|
|
6711
5299
|
customFunctions = {},
|
|
6712
5300
|
stringToNumber = null,
|
|
@@ -6717,25 +5305,10 @@ class JsonFormula {
|
|
|
6717
5305
|
this.debug = debug;
|
|
6718
5306
|
this.formula = new Formula(debug, customFunctions, stringToNumber);
|
|
6719
5307
|
}
|
|
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
5308
|
search(expression, json, globals = {}, language = 'en-US') {
|
|
6728
5309
|
const ast = this.compile(expression, Object.keys(globals));
|
|
6729
5310
|
return this.run(ast, json, language, globals);
|
|
6730
5311
|
}
|
|
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
5312
|
run(ast, json, language, globals) {
|
|
6740
5313
|
return this.formula.search(
|
|
6741
5314
|
ast,
|
|
@@ -6744,14 +5317,6 @@ class JsonFormula {
|
|
|
6744
5317
|
language,
|
|
6745
5318
|
);
|
|
6746
5319
|
}
|
|
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
5320
|
compile(expression, allowedGlobalNames = []) {
|
|
6756
5321
|
this.debug.length = 0;
|
|
6757
5322
|
return this.formula.compile(expression, allowedGlobalNames);
|
|
@@ -6804,7 +5369,8 @@ class RuleEngine {
|
|
|
6804
5369
|
}
|
|
6805
5370
|
|
|
6806
5371
|
const defaults = {
|
|
6807
|
-
visible: true
|
|
5372
|
+
visible: true,
|
|
5373
|
+
enabled: true
|
|
6808
5374
|
};
|
|
6809
5375
|
class Fieldset extends Container {
|
|
6810
5376
|
constructor(params, _options) {
|
|
@@ -6847,12 +5413,6 @@ class Fieldset extends Container {
|
|
|
6847
5413
|
}
|
|
6848
5414
|
}
|
|
6849
5415
|
|
|
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
5416
|
class InstanceManager extends Fieldset {
|
|
6857
5417
|
get maxOccur() {
|
|
6858
5418
|
return this._jsonModel.maxItems;
|
|
@@ -6870,13 +5430,22 @@ class InstanceManager extends Fieldset {
|
|
|
6870
5430
|
return this.removeItem(action);
|
|
6871
5431
|
}
|
|
6872
5432
|
}
|
|
6873
|
-
__decorate
|
|
5433
|
+
__decorate([
|
|
6874
5434
|
dependencyTracked()
|
|
6875
5435
|
], InstanceManager.prototype, "maxOccur", null);
|
|
6876
|
-
__decorate
|
|
5436
|
+
__decorate([
|
|
6877
5437
|
dependencyTracked()
|
|
6878
5438
|
], InstanceManager.prototype, "minOccur", null);
|
|
6879
5439
|
|
|
5440
|
+
class ValidationError {
|
|
5441
|
+
fieldName;
|
|
5442
|
+
errorMessages;
|
|
5443
|
+
constructor(fieldName = '', errorMessages = []) {
|
|
5444
|
+
this.errorMessages = errorMessages;
|
|
5445
|
+
this.fieldName = fieldName;
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
|
|
6880
5449
|
const dateRegex = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
|
|
6881
5450
|
const days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
6882
5451
|
const daysInMonth = (leapYear, month) => {
|
|
@@ -7150,33 +5719,9 @@ const Constraints = {
|
|
|
7150
5719
|
}
|
|
7151
5720
|
};
|
|
7152
5721
|
|
|
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
5722
|
const DATE_TIME_REGEX =
|
|
7175
|
-
// eslint-disable-next-line max-len
|
|
7176
5723
|
/(?:[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
5724
|
const ShorthandStyles$1 = ["full", "long", "medium", "short"];
|
|
7179
|
-
|
|
7180
5725
|
function getSkeleton(skeleton, language) {
|
|
7181
5726
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7182
5727
|
const parsed = parseDateStyle(skeleton, language);
|
|
@@ -7197,24 +5742,13 @@ function getSkeleton(skeleton, language) {
|
|
|
7197
5742
|
}
|
|
7198
5743
|
return skeleton;
|
|
7199
5744
|
}
|
|
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
5745
|
function parseDateStyle(skeleton, language) {
|
|
7209
5746
|
const options = {};
|
|
7210
|
-
// the skeleton could have two keywords -- one for date, one for time
|
|
7211
5747
|
const styles = skeleton.split(/\s/).filter(s => s.length);
|
|
7212
5748
|
options.dateStyle = styles[0];
|
|
7213
5749
|
if (styles.length > 1) options.timeStyle = styles[1];
|
|
7214
|
-
|
|
7215
5750
|
const testDate = new Date(2000, 2, 1, 2, 3, 4);
|
|
7216
5751
|
const parts = new Intl.DateTimeFormat(language, options).formatToParts(testDate);
|
|
7217
|
-
// oddly, the formatted month name can be different from the standalone month name
|
|
7218
5752
|
const formattedMarch = parts.find(p => p.type === 'month').value;
|
|
7219
5753
|
const longMarch = new Intl.DateTimeFormat(language, {month: 'long'}).formatToParts(testDate)[0].value;
|
|
7220
5754
|
const shortMarch = new Intl.DateTimeFormat(language, {month: 'short'}).formatToParts(testDate)[0].value;
|
|
@@ -7238,11 +5772,6 @@ function parseDateStyle(skeleton, language) {
|
|
|
7238
5772
|
});
|
|
7239
5773
|
return result;
|
|
7240
5774
|
}
|
|
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
5775
|
function parseDateTimeSkeleton(skeleton, language) {
|
|
7247
5776
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7248
5777
|
return parseDateStyle(skeleton, language);
|
|
@@ -7251,11 +5780,9 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7251
5780
|
skeleton.replace(DATE_TIME_REGEX, match => {
|
|
7252
5781
|
const len = match.length;
|
|
7253
5782
|
switch (match[0]) {
|
|
7254
|
-
// Era
|
|
7255
5783
|
case 'G':
|
|
7256
5784
|
result.push(['era', len === 4 ? 'long' : len === 5 ? 'narrow' : 'short', len]);
|
|
7257
5785
|
break;
|
|
7258
|
-
// Year
|
|
7259
5786
|
case 'y':
|
|
7260
5787
|
result.push(['year', len === 2 ? '2-digit' : 'numeric', len]);
|
|
7261
5788
|
break;
|
|
@@ -7266,16 +5793,13 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7266
5793
|
throw new RangeError(
|
|
7267
5794
|
'`Y/u/U/r` (year) patterns are not supported, use `y` instead'
|
|
7268
5795
|
);
|
|
7269
|
-
// Quarter
|
|
7270
5796
|
case 'q':
|
|
7271
5797
|
case 'Q':
|
|
7272
5798
|
throw new RangeError('`q/Q` (quarter) patterns are not supported');
|
|
7273
|
-
// Month
|
|
7274
5799
|
case 'M':
|
|
7275
5800
|
case 'L':
|
|
7276
5801
|
result.push(['month', ['numeric', '2-digit', 'short', 'long', 'narrow'][len - 1], len]);
|
|
7277
5802
|
break;
|
|
7278
|
-
// Week
|
|
7279
5803
|
case 'w':
|
|
7280
5804
|
case 'W':
|
|
7281
5805
|
throw new RangeError('`w/W` (week) patterns are not supported');
|
|
@@ -7288,7 +5812,6 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7288
5812
|
throw new RangeError(
|
|
7289
5813
|
'`D/F/g` (day) patterns are not supported, use `d` instead'
|
|
7290
5814
|
);
|
|
7291
|
-
// Weekday
|
|
7292
5815
|
case 'E':
|
|
7293
5816
|
result.push(['weekday', ['short', 'short', 'short', 'long', 'narrow', 'narrow'][len - 1], len]);
|
|
7294
5817
|
break;
|
|
@@ -7304,16 +5827,14 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7304
5827
|
}
|
|
7305
5828
|
result.push(['weekday', ['short', 'long', 'narrow', 'short'][len - 3], len]);
|
|
7306
5829
|
break;
|
|
7307
|
-
|
|
7308
|
-
case 'a': // AM, PM
|
|
5830
|
+
case 'a':
|
|
7309
5831
|
result.push(['hour12', true, 1]);
|
|
7310
5832
|
break;
|
|
7311
|
-
case 'b':
|
|
7312
|
-
case 'B':
|
|
5833
|
+
case 'b':
|
|
5834
|
+
case 'B':
|
|
7313
5835
|
throw new RangeError(
|
|
7314
5836
|
'`b/B` (period) patterns are not supported, use `a` instead'
|
|
7315
5837
|
);
|
|
7316
|
-
// Hour
|
|
7317
5838
|
case 'h':
|
|
7318
5839
|
result.push(['hourCycle', 'h12']);
|
|
7319
5840
|
result.push(['hour', ['numeric', '2-digit'][len - 1], len]);
|
|
@@ -7336,11 +5857,9 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7336
5857
|
throw new RangeError(
|
|
7337
5858
|
'`j/J/C` (hour) patterns are not supported, use `h/H/K/k` instead'
|
|
7338
5859
|
);
|
|
7339
|
-
// Minute
|
|
7340
5860
|
case 'm':
|
|
7341
5861
|
result.push(['minute', ['numeric', '2-digit'][len - 1], len]);
|
|
7342
5862
|
break;
|
|
7343
|
-
// Second
|
|
7344
5863
|
case 's':
|
|
7345
5864
|
result.push(['second', ['numeric', '2-digit'][len - 1], len]);
|
|
7346
5865
|
break;
|
|
@@ -7351,23 +5870,19 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7351
5870
|
throw new RangeError(
|
|
7352
5871
|
'`S/A` (millisecond) patterns are not supported, use `s` instead'
|
|
7353
5872
|
);
|
|
7354
|
-
|
|
7355
|
-
case 'O': // timeZone GMT-8 or GMT-08:00
|
|
5873
|
+
case 'O':
|
|
7356
5874
|
result.push(['timeZoneName', len < 4 ? 'shortOffset' : 'longOffset', len]);
|
|
7357
5875
|
result.push(['x-timeZoneName', len < 4 ? 'O' : 'OOOO', len]);
|
|
7358
5876
|
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
|
|
5877
|
+
case 'X':
|
|
5878
|
+
case 'x':
|
|
5879
|
+
case 'Z':
|
|
7365
5880
|
result.push(['timeZoneName', 'longOffset', 1]);
|
|
7366
5881
|
result.push(['x-timeZoneName', match, 1]);
|
|
7367
5882
|
break;
|
|
7368
|
-
case 'z':
|
|
7369
|
-
case 'v':
|
|
7370
|
-
case 'V':
|
|
5883
|
+
case 'z':
|
|
5884
|
+
case 'v':
|
|
5885
|
+
case 'V':
|
|
7371
5886
|
throw new RangeError(
|
|
7372
5887
|
'z/v/V` (timeZone) patterns are not supported, use `X/x/Z/O` instead'
|
|
7373
5888
|
);
|
|
@@ -7382,29 +5897,6 @@ function parseDateTimeSkeleton(skeleton, language) {
|
|
|
7382
5897
|
return result;
|
|
7383
5898
|
}
|
|
7384
5899
|
|
|
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
5900
|
function fixDigits(formattedParts, parsed) {
|
|
7409
5901
|
['hour', 'minute', 'second'].forEach(type => {
|
|
7410
5902
|
const defn = formattedParts.find(f => f.type === type);
|
|
@@ -7414,55 +5906,29 @@ function fixDigits(formattedParts, parsed) {
|
|
|
7414
5906
|
if (fmt === 'numeric' && defn.value.length === 2 && defn.value.charAt(0) === '0') defn.value = defn.value.slice(1);
|
|
7415
5907
|
});
|
|
7416
5908
|
}
|
|
7417
|
-
|
|
7418
5909
|
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
5910
|
const defn = formattedParts.find(f => f.type === 'year');
|
|
7424
5911
|
if (!defn) return;
|
|
7425
|
-
// eslint-disable-next-line no-unused-vars
|
|
7426
5912
|
const chars = parsed.find(pair => pair[0] === 'year')[2];
|
|
7427
5913
|
while(defn.value.length < chars) {
|
|
7428
5914
|
defn.value = `0${defn.value}`;
|
|
7429
5915
|
}
|
|
7430
5916
|
}
|
|
7431
|
-
|
|
7432
|
-
/**
|
|
7433
|
-
*
|
|
7434
|
-
* @param dateValue {Date}
|
|
7435
|
-
* @param language {string}
|
|
7436
|
-
* @param skeleton {string}
|
|
7437
|
-
* @param timeZone {string}
|
|
7438
|
-
* @returns {T}
|
|
7439
|
-
*/
|
|
7440
5917
|
function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
7441
|
-
// DateTimeFormat renames some of the options in its formatted output
|
|
7442
|
-
//@ts-ignore
|
|
7443
5918
|
const mappings = key => ({
|
|
7444
5919
|
hour12: 'dayPeriod',
|
|
7445
5920
|
fractionalSecondDigits: 'fractionalSecond',
|
|
7446
5921
|
})[key] || key;
|
|
7447
|
-
|
|
7448
|
-
// produces an array of name/value pairs of skeleton parts
|
|
7449
5922
|
const allParameters = parseDateTimeSkeleton(skeleton, language);
|
|
7450
5923
|
allParameters.push(['timeZone', timeZone]);
|
|
7451
|
-
|
|
7452
5924
|
const parsed = allParameters.filter(p => !p[0].startsWith('x-'));
|
|
7453
5925
|
const nonStandard = allParameters.filter(p => p[0].startsWith('x-'));
|
|
7454
|
-
// reduce to a set of options that can be used to format
|
|
7455
5926
|
const options = Object.fromEntries(parsed);
|
|
7456
5927
|
delete options.literal;
|
|
7457
|
-
|
|
7458
5928
|
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
5929
|
const formattedParts = df.formatToParts(dateValue);
|
|
7461
|
-
|
|
7462
5930
|
fixDigits(formattedParts, allParameters);
|
|
7463
5931
|
fixYear(formattedParts, parsed);
|
|
7464
|
-
// iterate through the original parsed components and use its ordering and literals,
|
|
7465
|
-
// and add the formatted pieces
|
|
7466
5932
|
return parsed.reduce((result, cur) => {
|
|
7467
5933
|
if (cur[0] === 'literal') result.push(cur);
|
|
7468
5934
|
else {
|
|
@@ -7472,37 +5938,25 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
7472
5938
|
const category = tz[0];
|
|
7473
5939
|
if (category === 'Z') {
|
|
7474
5940
|
if (tz.length < 4) {
|
|
7475
|
-
// handle 'Z', 'ZZ', 'ZZZ' Time Zone: ISO8601 basic hms? / RFC 822
|
|
7476
5941
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
7477
5942
|
if (v.value === '') v.value = '+0000';
|
|
7478
5943
|
} else if (tz.length === 5) {
|
|
7479
|
-
// 'ZZZZZ' Time Zone: ISO8601 extended hms?
|
|
7480
5944
|
if (v.value === 'GMT') v.value = 'Z';
|
|
7481
5945
|
else v.value = v.value.replace(/GMT/, '');
|
|
7482
5946
|
}
|
|
7483
5947
|
}
|
|
7484
5948
|
if (category === 'X' || category === 'x') {
|
|
7485
5949
|
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
5950
|
v.value = v.value.replace(/(GMT|:(00)?)/g, '');
|
|
7490
5951
|
}
|
|
7491
5952
|
if (tz.length === 2) {
|
|
7492
|
-
// 'XX' ISO8601 basic hm, with Z
|
|
7493
|
-
// -0800, Z
|
|
7494
|
-
// 'xx' ISO8601 basic hm, without Z
|
|
7495
5953
|
v.value = v.value.replace(/(GMT|:)/g, '');
|
|
7496
5954
|
}
|
|
7497
5955
|
if (tz.length === 3) {
|
|
7498
|
-
// 'XXX' ISO8601 extended hm, with Z
|
|
7499
|
-
// -08:00, Z
|
|
7500
|
-
// 'xxx' ISO8601 extended hm, without Z
|
|
7501
5956
|
v.value = v.value.replace(/GMT/g, '');
|
|
7502
5957
|
}
|
|
7503
5958
|
if (category === 'X' && v.value === '') v.value = 'Z';
|
|
7504
5959
|
} else if (tz === 'O') {
|
|
7505
|
-
// eliminate 'GMT', leading and trailing zeros
|
|
7506
5960
|
v.value = v.value.replace(/GMT/g, '').replace(/0(\d+):/, '$1:').replace(/:00/, '');
|
|
7507
5961
|
if (v.value === '') v.value = '+0';
|
|
7508
5962
|
}
|
|
@@ -7512,18 +5966,12 @@ function formatDateToParts(dateValue, language, skeleton, timeZone) {
|
|
|
7512
5966
|
return result;
|
|
7513
5967
|
}, []);
|
|
7514
5968
|
}
|
|
7515
|
-
|
|
7516
|
-
/**
|
|
7517
|
-
*
|
|
7518
|
-
* @param dateValue {Date}
|
|
7519
|
-
* @param language {string}
|
|
7520
|
-
* @param skeleton {string}
|
|
7521
|
-
* @param timeZone {string}
|
|
7522
|
-
*/
|
|
7523
5969
|
function formatDate(dateValue, language, skeleton, timeZone) {
|
|
5970
|
+
if (skeleton.startsWith('date|')) {
|
|
5971
|
+
skeleton = skeleton.split('|')[1];
|
|
5972
|
+
}
|
|
7524
5973
|
if (ShorthandStyles$1.find(type => skeleton.includes(type))) {
|
|
7525
5974
|
const options = {timeZone};
|
|
7526
|
-
// the skeleton could have two keywords -- one for date, one for time
|
|
7527
5975
|
const parts = skeleton.split(/\s/).filter(s => s.length);
|
|
7528
5976
|
if (ShorthandStyles$1.indexOf(parts[0]) > -1) {
|
|
7529
5977
|
options.dateStyle = parts[0];
|
|
@@ -7559,9 +6007,7 @@ const currencies = {
|
|
|
7559
6007
|
'ru-RU': 'RUB',
|
|
7560
6008
|
'tr-TR': 'TRY'
|
|
7561
6009
|
};
|
|
7562
|
-
|
|
7563
6010
|
const locales = Object.keys(currencies);
|
|
7564
|
-
|
|
7565
6011
|
const getCurrency = function (locale) {
|
|
7566
6012
|
if (locales.indexOf(locale) > -1) {
|
|
7567
6013
|
return currencies[locale]
|
|
@@ -7575,8 +6021,7 @@ const getCurrency = function (locale) {
|
|
|
7575
6021
|
};
|
|
7576
6022
|
|
|
7577
6023
|
const NUMBER_REGEX =
|
|
7578
|
-
|
|
7579
|
-
/(?:[#]+|[@]+(?:#+)?|[0]+|[,]|[.]|[-]|[+]|[%]|[¤]{1,4}(?:\/([a-zA-Z]{3}))?|[;]|[K]{1,2}|E{1,2}[+]?|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
6024
|
+
/(?:[#]+|[@]+(#+)?|[0]+|[,]|[.]|[-]|[+]|[%]|[¤]{1,4}(?:\/([a-zA-Z]{3}))?|[;]|[K]{1,2}|E{1,2}[+]?|'(?:[^']|'')*')|[^a-zA-Z']+/g;
|
|
7580
6025
|
const supportedUnits = ['acre', 'bit', 'byte', 'celsius', 'centimeter', 'day',
|
|
7581
6026
|
'degree', 'fahrenheit', 'fluid-ounce', 'foot', 'gallon', 'gigabit',
|
|
7582
6027
|
'gigabyte', 'gram', 'hectare', 'hour', 'inch', 'kilobit', 'kilobyte',
|
|
@@ -7584,8 +6029,6 @@ const supportedUnits = ['acre', 'bit', 'byte', 'celsius', 'centimeter', 'day',
|
|
|
7584
6029
|
'mile-scandinavian', 'milliliter', 'millimeter', 'millisecond', 'minute', 'month',
|
|
7585
6030
|
'ounce', 'percent', 'petabyte', 'pound', 'second', 'stone', 'terabit', 'terabyte', 'week', 'yard', 'year'].join('|');
|
|
7586
6031
|
const ShorthandStyles = [/^currency(?:\/([a-zA-Z]{3}))?$/, /^decimal$/, /^integer$/, /^percent$/, new RegExp(`^unit\/(${supportedUnits})$`)];
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
6032
|
function parseNumberSkeleton(skeleton, language) {
|
|
7590
6033
|
const options = {};
|
|
7591
6034
|
const order = [];
|
|
@@ -7614,6 +6057,7 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7614
6057
|
break;
|
|
7615
6058
|
case 4:
|
|
7616
6059
|
options.style = 'percent';
|
|
6060
|
+
options.maximumFractionDigits = 2;
|
|
7617
6061
|
break;
|
|
7618
6062
|
case 5:
|
|
7619
6063
|
options.style = "unit";
|
|
@@ -7630,7 +6074,7 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7630
6074
|
options.minimumIntegerDigits = 1;
|
|
7631
6075
|
options.maximumFractionDigits = 0;
|
|
7632
6076
|
options.minimumFractionDigits = 0;
|
|
7633
|
-
skeleton.replace(NUMBER_REGEX, (match, offset) => {
|
|
6077
|
+
skeleton.replace(NUMBER_REGEX, (match, maxSignificantDigits, currencySymbol, offset) => {
|
|
7634
6078
|
const len = match.length;
|
|
7635
6079
|
switch(match[0]) {
|
|
7636
6080
|
case '#':
|
|
@@ -7643,10 +6087,10 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7643
6087
|
if (options?.minimumSignificantDigits) {
|
|
7644
6088
|
throw "@ symbol should occur together"
|
|
7645
6089
|
}
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
options.maximumSignificantDigits = len
|
|
6090
|
+
const hashes = maxSignificantDigits || "";
|
|
6091
|
+
order.push(['@', len - hashes.length]);
|
|
6092
|
+
options.minimumSignificantDigits = len - hashes.length;
|
|
6093
|
+
options.maximumSignificantDigits = len;
|
|
7650
6094
|
order.push(['digit', hashes.length]);
|
|
7651
6095
|
break;
|
|
7652
6096
|
case ',':
|
|
@@ -7671,6 +6115,9 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7671
6115
|
}
|
|
7672
6116
|
if (options?.decimal === true) {
|
|
7673
6117
|
options.minimumFractionDigits = len;
|
|
6118
|
+
if (!options.maximumFractionDigits) {
|
|
6119
|
+
options.maximumFractionDigits = len;
|
|
6120
|
+
}
|
|
7674
6121
|
} else {
|
|
7675
6122
|
options.minimumIntegerDigits = len;
|
|
7676
6123
|
}
|
|
@@ -7694,18 +6141,20 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7694
6141
|
case '¤':
|
|
7695
6142
|
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
7696
6143
|
console.error("currency display should be either in the beginning or at the end");
|
|
6144
|
+
} else {
|
|
6145
|
+
options.style = 'currency';
|
|
6146
|
+
options.currencyDisplay = ['symbol', 'code', 'name', 'narrowSymbol'][len - 1];
|
|
6147
|
+
options.currency = currencySymbol || getCurrency(language);
|
|
6148
|
+
order.push(['currency', len]);
|
|
7697
6149
|
}
|
|
7698
|
-
options.style = 'currency';
|
|
7699
|
-
options.currencyDisplay = ['symbol', 'code', 'name', 'narrowSymbol'][len -1];
|
|
7700
|
-
options.currency = getCurrency(language);
|
|
7701
|
-
order.push(['currency', len]);
|
|
7702
6150
|
break;
|
|
7703
6151
|
case '%':
|
|
7704
6152
|
if (offset !== 0 && offset !== skeleton.length - 1) {
|
|
7705
6153
|
console.error("percent display should be either in the beginning or at the end");
|
|
6154
|
+
} else {
|
|
6155
|
+
order.push(['%', 1]);
|
|
6156
|
+
options.style = 'percent';
|
|
7706
6157
|
}
|
|
7707
|
-
order.push(['%', 1]);
|
|
7708
|
-
options.style = 'percent';
|
|
7709
6158
|
break;
|
|
7710
6159
|
case 'E':
|
|
7711
6160
|
order.push(['E', len]);
|
|
@@ -7722,6 +6171,9 @@ function parseNumberSkeleton(skeleton, language) {
|
|
|
7722
6171
|
}
|
|
7723
6172
|
|
|
7724
6173
|
function formatNumber(numberValue, language, skeletn) {
|
|
6174
|
+
if (skeletn.startsWith('num|')) {
|
|
6175
|
+
skeletn = skel.split('|')[1];
|
|
6176
|
+
}
|
|
7725
6177
|
if (!skeletn) return numberValue
|
|
7726
6178
|
language = language || "en";
|
|
7727
6179
|
const {options, order} = parseNumberSkeleton(skeletn, language);
|
|
@@ -7732,7 +6184,6 @@ const getCategory = function (skeleton) {
|
|
|
7732
6184
|
const chkCategory = skeleton?.match(/^(?:(num|date)\|)?(.+)/);
|
|
7733
6185
|
return [chkCategory?.[1], chkCategory?.[2]]
|
|
7734
6186
|
};
|
|
7735
|
-
|
|
7736
6187
|
const format = function (value, locale, skeleton, timezone) {
|
|
7737
6188
|
const [category, skelton] = getCategory(skeleton);
|
|
7738
6189
|
switch (category) {
|
|
@@ -7748,12 +6199,6 @@ const format = function (value, locale, skeleton, timezone) {
|
|
|
7748
6199
|
}
|
|
7749
6200
|
};
|
|
7750
6201
|
|
|
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
6202
|
const validTypes = ['string', 'number', 'boolean', 'file', 'string[]', 'number[]', 'boolean[]', 'file[]', 'array', 'object'];
|
|
7758
6203
|
class Field extends Scriptable {
|
|
7759
6204
|
constructor(params, _options) {
|
|
@@ -7902,10 +6347,10 @@ class Field extends Scriptable {
|
|
|
7902
6347
|
}
|
|
7903
6348
|
}
|
|
7904
6349
|
get editFormat() {
|
|
7905
|
-
return this._jsonModel.editFormat;
|
|
6350
|
+
return this.withCategory(this._jsonModel.editFormat);
|
|
7906
6351
|
}
|
|
7907
6352
|
get displayFormat() {
|
|
7908
|
-
return this._jsonModel.displayFormat;
|
|
6353
|
+
return this.withCategory(this._jsonModel.displayFormat);
|
|
7909
6354
|
}
|
|
7910
6355
|
get placeholder() {
|
|
7911
6356
|
return this._jsonModel.placeholder;
|
|
@@ -7978,31 +6423,43 @@ class Field extends Scriptable {
|
|
|
7978
6423
|
return this._jsonModel.value === undefined || this._jsonModel.value === null || this._jsonModel.value === '';
|
|
7979
6424
|
}
|
|
7980
6425
|
withCategory(df) {
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
if (
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
6426
|
+
if (df) {
|
|
6427
|
+
const hasCategory = df?.match(/^(?:date|num)\|/);
|
|
6428
|
+
if (hasCategory === null) {
|
|
6429
|
+
if (this.format === 'date') {
|
|
6430
|
+
df = `date|${df}`;
|
|
6431
|
+
}
|
|
6432
|
+
else if (this.type === 'number') {
|
|
6433
|
+
df = `num|${df}`;
|
|
6434
|
+
}
|
|
6435
|
+
return df;
|
|
7988
6436
|
}
|
|
7989
|
-
return df;
|
|
7990
6437
|
}
|
|
7991
6438
|
return df;
|
|
7992
6439
|
}
|
|
7993
6440
|
get editValue() {
|
|
7994
|
-
const df = this.
|
|
6441
|
+
const df = this.editFormat;
|
|
7995
6442
|
if (df && this.isNotEmpty(this.value) && this.valid !== false) {
|
|
7996
|
-
|
|
6443
|
+
try {
|
|
6444
|
+
return format(this.value, this.language, df);
|
|
6445
|
+
}
|
|
6446
|
+
catch (e) {
|
|
6447
|
+
return this.value;
|
|
6448
|
+
}
|
|
7997
6449
|
}
|
|
7998
6450
|
else {
|
|
7999
6451
|
return this.value;
|
|
8000
6452
|
}
|
|
8001
6453
|
}
|
|
8002
6454
|
get displayValue() {
|
|
8003
|
-
const df = this.
|
|
6455
|
+
const df = this.displayFormat;
|
|
8004
6456
|
if (df && this.isNotEmpty(this.value) && this.valid !== false) {
|
|
8005
|
-
|
|
6457
|
+
try {
|
|
6458
|
+
return format(this.value, this.language, df);
|
|
6459
|
+
}
|
|
6460
|
+
catch (e) {
|
|
6461
|
+
return this.value;
|
|
6462
|
+
}
|
|
8006
6463
|
}
|
|
8007
6464
|
else {
|
|
8008
6465
|
return this.value;
|
|
@@ -8142,7 +6599,7 @@ class Field extends Scriptable {
|
|
|
8142
6599
|
const iv = this._jsonModel.minimum || this._jsonModel.default || 0;
|
|
8143
6600
|
const fIVal = iv * factor;
|
|
8144
6601
|
const qt = (fVal - fIVal) / fStep;
|
|
8145
|
-
const valid = (fVal - fIVal) % fStep < .001;
|
|
6602
|
+
const valid = Math.abs(fVal - fIVal) % fStep < .001;
|
|
8146
6603
|
let next, prev;
|
|
8147
6604
|
if (!valid) {
|
|
8148
6605
|
next = (Math.ceil(qt) * fStep + fIVal) / factor;
|
|
@@ -8345,6 +6802,8 @@ class Field extends Scriptable {
|
|
|
8345
6802
|
getState() {
|
|
8346
6803
|
return {
|
|
8347
6804
|
...super.getState(),
|
|
6805
|
+
editFormat: this.editFormat,
|
|
6806
|
+
displayFormat: this.displayFormat,
|
|
8348
6807
|
editValue: this.editValue,
|
|
8349
6808
|
displayValue: this.displayValue
|
|
8350
6809
|
};
|