@questwork/q-utilities 0.1.19 → 0.1.21
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/.github/workflows/publish.yml +6 -6
- package/dist/index.min.cjs +640 -211
- package/dist/q-utilities.esm.js +635 -212
- package/dist/q-utilities.min.js +640 -211
- package/eslint.config.js +3 -0
- package/package.json +3 -2
package/dist/q-utilities.min.js
CHANGED
|
@@ -48,6 +48,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
48
48
|
|
|
49
49
|
// EXPORTS
|
|
50
50
|
__webpack_require__.d(__webpack_exports__, {
|
|
51
|
+
ActionRecord: () => (/* reexport */ ActionRecord),
|
|
51
52
|
ApiResponse: () => (/* reexport */ ApiResponse),
|
|
52
53
|
AwsStsS3Client: () => (/* reexport */ AwsStsS3Client),
|
|
53
54
|
KeyValueObject: () => (/* reexport */ KeyValueObject),
|
|
@@ -56,6 +57,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
56
57
|
QMeta: () => (/* reexport */ QMeta),
|
|
57
58
|
Repo: () => (/* reexport */ Repo),
|
|
58
59
|
Service: () => (/* reexport */ Service),
|
|
60
|
+
Status: () => (/* reexport */ Status),
|
|
61
|
+
StatusDocument: () => (/* reexport */ StatusDocument),
|
|
59
62
|
TemplateCompiler: () => (/* reexport */ TemplateCompiler),
|
|
60
63
|
TenantAwareEntity: () => (/* reexport */ TenantAwareEntity),
|
|
61
64
|
TrackedEntity: () => (/* reexport */ TrackedEntity),
|
|
@@ -65,6 +68,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
65
68
|
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
66
69
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
67
70
|
convertString: () => (/* reexport */ convertString),
|
|
71
|
+
detectControlCharacters: () => (/* reexport */ detectControlCharacters),
|
|
68
72
|
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
69
73
|
expressHelper: () => (/* reexport */ expressHelper),
|
|
70
74
|
extractEmails: () => (/* reexport */ extractEmails),
|
|
@@ -76,12 +80,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
76
80
|
init: () => (/* reexport */ init),
|
|
77
81
|
initFromArray: () => (/* reexport */ initFromArray),
|
|
78
82
|
initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
|
|
83
|
+
isConvertibleToNumber: () => (/* reexport */ isConvertibleToNumber),
|
|
79
84
|
makeApiResponse: () => (/* reexport */ makeApiResponse),
|
|
80
85
|
makeService: () => (/* reexport */ makeService),
|
|
81
86
|
mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
|
|
82
87
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
83
88
|
pReduce: () => (/* reexport */ pReduce),
|
|
84
89
|
padZeros: () => (/* reexport */ padZeros),
|
|
90
|
+
printControlCharReport: () => (/* reexport */ printControlCharReport),
|
|
85
91
|
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
86
92
|
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
87
93
|
shuffleArray: () => (/* reexport */ shuffleArray),
|
|
@@ -116,14 +122,14 @@ function authorize({ allowCoordinator, allowOwner, query = {}, required, user })
|
|
|
116
122
|
if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
|
|
117
123
|
query.__ALLOW_COORDINATOR = true
|
|
118
124
|
} else {
|
|
119
|
-
if (!scopes.includes('EVENT')) {
|
|
120
|
-
query.eventRegistrationCode = user.eventRegistrationCode
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
125
|
if (!scopes.includes('EVENT')) {
|
|
125
126
|
query.eventRegistrationCode = user.eventRegistrationCode
|
|
126
127
|
}
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
if (!scopes.includes('EVENT')) {
|
|
131
|
+
query.eventRegistrationCode = user.eventRegistrationCode
|
|
132
|
+
}
|
|
127
133
|
}
|
|
128
134
|
if (allowOwner) {
|
|
129
135
|
query.__ALLOW_OWNER = true
|
|
@@ -155,14 +161,14 @@ function calculateAge(timestamp, reference) {
|
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
// Calculate raw difference
|
|
158
|
-
let age = refDate.getFullYear() - birthDate.getFullYear()
|
|
159
|
-
const monthDiff = refDate.getMonth() - birthDate.getMonth()
|
|
160
|
-
|
|
164
|
+
let age = refDate.getFullYear() - birthDate.getFullYear()
|
|
165
|
+
const monthDiff = refDate.getMonth() - birthDate.getMonth()
|
|
166
|
+
|
|
161
167
|
// Adjust if birthday hasn't occurred yet this year
|
|
162
168
|
if (monthDiff < 0 || (monthDiff === 0 && refDate.getDate() < birthDate.getDate())) {
|
|
163
169
|
age--
|
|
164
170
|
}
|
|
165
|
-
|
|
171
|
+
|
|
166
172
|
return age
|
|
167
173
|
}
|
|
168
174
|
|
|
@@ -192,7 +198,18 @@ function changeCreatorOwner(that, { source, target }) {
|
|
|
192
198
|
;// ./lib/helpers/changeCreatorOwner/index.js
|
|
193
199
|
|
|
194
200
|
|
|
201
|
+
;// ./lib/helpers/isConvertibleToNumber/isConvertibleToNumber.js
|
|
202
|
+
function isConvertibleToNumber(value) {
|
|
203
|
+
return value !== null
|
|
204
|
+
&& value !== undefined
|
|
205
|
+
&& typeof value !== 'boolean'
|
|
206
|
+
&& String(value).trim() !== ''
|
|
207
|
+
&& !isNaN(Number(value))
|
|
208
|
+
}
|
|
209
|
+
|
|
195
210
|
;// ./lib/helpers/getValidation/getValidation.js
|
|
211
|
+
|
|
212
|
+
|
|
196
213
|
function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
197
214
|
if (!rule) {
|
|
198
215
|
return true
|
|
@@ -206,10 +223,10 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
206
223
|
if (!key && typeof placeholder === 'undefined') {
|
|
207
224
|
switch (valueAttribute) {
|
|
208
225
|
case '$and': {
|
|
209
|
-
return value
|
|
226
|
+
return value.$and.reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
|
|
210
227
|
}
|
|
211
228
|
case '$or': {
|
|
212
|
-
return value
|
|
229
|
+
return value.$or.reduce((acc, item) => (acc || getValidation(item, data, getDataByKey, KeyValueObject)), false)
|
|
213
230
|
}
|
|
214
231
|
default:
|
|
215
232
|
return false
|
|
@@ -224,39 +241,53 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
224
241
|
}
|
|
225
242
|
|
|
226
243
|
switch (valueAttribute) {
|
|
244
|
+
case '$after': {
|
|
245
|
+
if (isConvertibleToNumber(value?.$after)) {
|
|
246
|
+
const _value = Number(String(value?.$after))
|
|
247
|
+
return Date.now() > _value
|
|
248
|
+
}
|
|
249
|
+
return false
|
|
250
|
+
}
|
|
251
|
+
case '$before': {
|
|
252
|
+
if (isConvertibleToNumber(value?.$before)) {
|
|
253
|
+
const _value = Number(String(value?.$before))
|
|
254
|
+
return Date.now() < _value
|
|
255
|
+
}
|
|
256
|
+
return false
|
|
257
|
+
}
|
|
227
258
|
case '$empty': {
|
|
228
259
|
const isEmpty = rowValue === null || rowValue === undefined
|
|
229
|
-
return isEmpty === value
|
|
260
|
+
return isEmpty === value.$empty
|
|
230
261
|
}
|
|
231
262
|
case '$eq': {
|
|
232
|
-
return rowValue === value
|
|
263
|
+
return rowValue === value.$eq
|
|
233
264
|
}
|
|
234
265
|
case '$gt': {
|
|
235
|
-
return rowValue > value
|
|
266
|
+
return rowValue > value.$gt
|
|
236
267
|
}
|
|
237
268
|
case '$gte': {
|
|
238
|
-
return rowValue >= value
|
|
269
|
+
return rowValue >= value.$gte
|
|
239
270
|
}
|
|
240
271
|
case '$hasOverlap': {
|
|
241
|
-
return _hasOverlap(rowValue, value
|
|
272
|
+
return _hasOverlap(rowValue, value.$hasOverlap)
|
|
242
273
|
}
|
|
243
274
|
case '$lt': {
|
|
244
|
-
return rowValue < value
|
|
275
|
+
return rowValue < value.$lt
|
|
245
276
|
}
|
|
246
277
|
case '$lte': {
|
|
247
|
-
return rowValue <= value
|
|
278
|
+
return rowValue <= value.$lte
|
|
248
279
|
}
|
|
249
280
|
case '$in': {
|
|
250
281
|
if (Array.isArray(rowValue)) {
|
|
251
|
-
return !!rowValue.find((e) => (value
|
|
282
|
+
return !!rowValue.find((e) => (value.$in.includes(e)))
|
|
252
283
|
}
|
|
253
284
|
if (typeof rowValue !== 'object') {
|
|
254
|
-
return !!value
|
|
285
|
+
return !!value.$in.includes(rowValue)
|
|
255
286
|
}
|
|
256
287
|
return false
|
|
257
288
|
}
|
|
258
289
|
case '$inValue': {
|
|
259
|
-
const result = getDataByKey(value
|
|
290
|
+
const result = getDataByKey(value.$inValue, data)
|
|
260
291
|
const _value = Array.isArray(result) ? result : []
|
|
261
292
|
if (Array.isArray(rowValue)) {
|
|
262
293
|
return !!rowValue.find((e) => (_value.includes(e)))
|
|
@@ -267,36 +298,36 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
267
298
|
return false
|
|
268
299
|
}
|
|
269
300
|
case '$ne': {
|
|
270
|
-
return rowValue !== value
|
|
301
|
+
return rowValue !== value.$ne
|
|
271
302
|
}
|
|
272
303
|
case '$notIn': {
|
|
273
304
|
if (Array.isArray(rowValue)) {
|
|
274
|
-
return !rowValue.find((e) => (value
|
|
305
|
+
return !rowValue.find((e) => (value.$notIn.includes(e)))
|
|
275
306
|
}
|
|
276
307
|
if (typeof rowValue !== 'object') {
|
|
277
|
-
return !value
|
|
308
|
+
return !value.$notIn.includes(rowValue)
|
|
278
309
|
}
|
|
279
310
|
return false
|
|
280
311
|
}
|
|
281
312
|
case '$intervalTimeGt': {
|
|
282
313
|
const now = new Date().getTime()
|
|
283
314
|
const timestamp = new Date(rowValue).getTime()
|
|
284
|
-
return (now - timestamp) > value
|
|
315
|
+
return (now - timestamp) > value.$intervalTimeGt
|
|
285
316
|
}
|
|
286
317
|
case '$intervalTimeLt': {
|
|
287
318
|
const now = new Date().getTime()
|
|
288
319
|
const timestamp = new Date(rowValue).getTime()
|
|
289
|
-
return (now - timestamp) < value
|
|
320
|
+
return (now - timestamp) < value.$intervalTimeLt
|
|
290
321
|
}
|
|
291
322
|
case '$isToday': {
|
|
292
323
|
const currentDate = new Date()
|
|
293
|
-
const start = currentDate.setHours(0,0,0,0)
|
|
294
|
-
const end = currentDate.setHours(23,59,59,59)
|
|
324
|
+
const start = currentDate.setHours(0, 0, 0, 0)
|
|
325
|
+
const end = currentDate.setHours(23, 59, 59, 59)
|
|
295
326
|
const dateValue = new Date(rowValue).getTime()
|
|
296
|
-
return (start <= dateValue && end >= dateValue) === value
|
|
327
|
+
return (start <= dateValue && end >= dateValue) === value.$isToday
|
|
297
328
|
}
|
|
298
329
|
case '$notInValue': {
|
|
299
|
-
const result = getDataByKey(value
|
|
330
|
+
const result = getDataByKey(value.$notInValue, data)
|
|
300
331
|
const _value = Array.isArray(result) ? result : []
|
|
301
332
|
if (Array.isArray(rowValue)) {
|
|
302
333
|
return !rowValue.find((e) => (_value.includes(e)))
|
|
@@ -307,7 +338,7 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
307
338
|
return false
|
|
308
339
|
}
|
|
309
340
|
case '$range': {
|
|
310
|
-
const [min, max] = value
|
|
341
|
+
const [min, max] = value.$range
|
|
311
342
|
if (typeof min === 'number' && typeof max === 'number' && rowValue >= min && rowValue <= max) {
|
|
312
343
|
return true
|
|
313
344
|
}
|
|
@@ -316,7 +347,6 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
|
|
|
316
347
|
default:
|
|
317
348
|
return false
|
|
318
349
|
}
|
|
319
|
-
|
|
320
350
|
}
|
|
321
351
|
|
|
322
352
|
function _hasOverlap(item1, item2) {
|
|
@@ -341,12 +371,11 @@ function _hasOverlap(item1, item2) {
|
|
|
341
371
|
|
|
342
372
|
|
|
343
373
|
;// ./lib/helpers/formatDate/formatDate.js
|
|
344
|
-
|
|
345
374
|
function formatDate(date, format) {
|
|
346
375
|
const _date = date && date instanceof Date ? date : new Date(date)
|
|
347
|
-
const dayMapChi = ['日','一','二','三','四','五','六']
|
|
348
|
-
const dayMapEng = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
|
|
349
|
-
const dayMapEngShort = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
|
|
376
|
+
const dayMapChi = ['日', '一', '二', '三', '四', '五', '六']
|
|
377
|
+
const dayMapEng = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
|
378
|
+
const dayMapEngShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
|
350
379
|
const _format = format || 'YYYY/MM/DD hh:mm'
|
|
351
380
|
const e = _date.getDay()
|
|
352
381
|
const ee = dayMapEngShort[e]
|
|
@@ -381,13 +410,11 @@ function padding(m) {
|
|
|
381
410
|
return m < 10 ? `0${m}` : m
|
|
382
411
|
}
|
|
383
412
|
|
|
384
|
-
|
|
385
413
|
/* harmony default export */ const formatDate_formatDate = ({
|
|
386
414
|
formatDate
|
|
387
415
|
});
|
|
388
416
|
|
|
389
417
|
|
|
390
|
-
|
|
391
418
|
;// ./lib/helpers/formatDate/index.js
|
|
392
419
|
|
|
393
420
|
|
|
@@ -418,7 +445,6 @@ function getValueByKeys_getValueByKeys(keys, data) {
|
|
|
418
445
|
return _data[firstKey]
|
|
419
446
|
}
|
|
420
447
|
return _data
|
|
421
|
-
|
|
422
448
|
}
|
|
423
449
|
/* harmony default export */ const getValueByKeys = ({
|
|
424
450
|
getValueByKeys: getValueByKeys_getValueByKeys
|
|
@@ -470,6 +496,7 @@ const _FN_NAMES = [
|
|
|
470
496
|
'map',
|
|
471
497
|
'neq',
|
|
472
498
|
'removeHtml',
|
|
499
|
+
'sum',
|
|
473
500
|
'toLowerCase',
|
|
474
501
|
'toUpperCase',
|
|
475
502
|
]
|
|
@@ -622,10 +649,12 @@ function _existObject(data, args) {
|
|
|
622
649
|
|
|
623
650
|
function _performOperation(arg, value) {
|
|
624
651
|
// the arg is undefined
|
|
625
|
-
if (arg === undefined && value === undefined)
|
|
652
|
+
if (arg === undefined && value === undefined)
|
|
653
|
+
return true
|
|
626
654
|
|
|
627
655
|
// the arg is null
|
|
628
|
-
if (arg === null && value === null)
|
|
656
|
+
if (arg === null && value === null)
|
|
657
|
+
return true
|
|
629
658
|
|
|
630
659
|
// the arg is boolean
|
|
631
660
|
if (typeof arg === 'boolean') {
|
|
@@ -701,17 +730,18 @@ function _splitOperator(str) {
|
|
|
701
730
|
const operators = ['!=', '>=', '<=', '>', '<']
|
|
702
731
|
|
|
703
732
|
const matchedOp = operators.find((op) => str.startsWith(op))
|
|
704
|
-
if (!matchedOp)
|
|
733
|
+
if (!matchedOp)
|
|
734
|
+
return { operator: null, value: null }
|
|
705
735
|
|
|
706
736
|
const remaining = str.slice(matchedOp.length)
|
|
707
737
|
|
|
708
738
|
// '>Primary' or '<Primary' is invalid
|
|
709
|
-
if (/^[a-
|
|
739
|
+
if (/^[a-z]*$/i.test(remaining) && matchedOp !== '!=') {
|
|
710
740
|
return { operator: null, value: null }
|
|
711
741
|
}
|
|
712
742
|
|
|
713
743
|
// if it is a number it is converted to a number
|
|
714
|
-
const value = (!Number.isNaN(parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
|
|
744
|
+
const value = (!Number.isNaN(Number.parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
|
|
715
745
|
|
|
716
746
|
return {
|
|
717
747
|
operator: matchedOp,
|
|
@@ -923,11 +953,14 @@ function _isNotEmpty(data, args) {
|
|
|
923
953
|
}
|
|
924
954
|
|
|
925
955
|
|
|
956
|
+
|
|
926
957
|
;// ./lib/models/templateCompiler/helpers/_join.js
|
|
927
958
|
function _join(data, delimiter) {
|
|
928
959
|
try {
|
|
929
|
-
if (data.length === 0)
|
|
930
|
-
|
|
960
|
+
if (data.length === 0)
|
|
961
|
+
return ''
|
|
962
|
+
if (data.length === 1)
|
|
963
|
+
return _stringifyObject(data[0])
|
|
931
964
|
return data.map((item) => _stringifyObject(item)).join(delimiter)
|
|
932
965
|
} catch (e) {
|
|
933
966
|
throw e
|
|
@@ -1074,13 +1107,13 @@ function _removeHtml(html, args) {
|
|
|
1074
1107
|
|
|
1075
1108
|
function _htmlToPlainText(html, delimiter = '\n') {
|
|
1076
1109
|
if (typeof delimiter !== 'string') {
|
|
1077
|
-
delimiter = '\n'
|
|
1110
|
+
delimiter = '\n' // Fallback to default if not a string
|
|
1078
1111
|
}
|
|
1079
1112
|
|
|
1080
1113
|
// First decode HTML entities and normalize whitespace
|
|
1081
1114
|
const decodedHtml = html
|
|
1082
1115
|
.replace(/ /g, ' ')
|
|
1083
|
-
.replace(/\s+/g, ' ')
|
|
1116
|
+
.replace(/\s+/g, ' ') // Collapse all whitespace to single spaces
|
|
1084
1117
|
|
|
1085
1118
|
// Process HTML tags
|
|
1086
1119
|
let text = decodedHtml
|
|
@@ -1091,29 +1124,36 @@ function _htmlToPlainText(html, delimiter = '\n') {
|
|
|
1091
1124
|
// Remove all other tags
|
|
1092
1125
|
.replace(/<[^>]+>/g, '')
|
|
1093
1126
|
// Convert markers to specified delimiter
|
|
1094
|
-
.replace(
|
|
1127
|
+
.replace(/~{3,}/g, delimiter)
|
|
1095
1128
|
// Trim and clean whitespace
|
|
1096
|
-
.trim()
|
|
1129
|
+
.trim()
|
|
1097
1130
|
|
|
1098
1131
|
// Special handling for empty delimiter
|
|
1099
1132
|
if (delimiter === '') {
|
|
1100
1133
|
// Collapse all whitespace to single space
|
|
1101
|
-
text = text.replace(/\s+/g, ' ')
|
|
1134
|
+
text = text.replace(/\s+/g, ' ')
|
|
1102
1135
|
} else {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
1136
|
// Collapse multiple delimiters to single
|
|
1106
|
-
text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter)
|
|
1137
|
+
text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter)
|
|
1107
1138
|
// Remove leading/trailing delimiters
|
|
1108
|
-
text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '')
|
|
1139
|
+
text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '')
|
|
1109
1140
|
}
|
|
1110
1141
|
|
|
1111
|
-
return text
|
|
1142
|
+
return text
|
|
1112
1143
|
}
|
|
1113
1144
|
|
|
1114
|
-
|
|
1115
1145
|
function escapeRegExp(string) {
|
|
1116
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
1146
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
;// ./lib/models/templateCompiler/helpers/_sum.js
|
|
1152
|
+
function _sum(data, args) {
|
|
1153
|
+
if (Number.isNaN(data) || data === null || (typeof data === 'undefined') || data === '') {
|
|
1154
|
+
return data
|
|
1155
|
+
}
|
|
1156
|
+
return args.reduce((acc, e) => (acc + e), data)
|
|
1117
1157
|
}
|
|
1118
1158
|
|
|
1119
1159
|
|
|
@@ -1173,6 +1213,7 @@ function _toUpperCase(data, args) {
|
|
|
1173
1213
|
|
|
1174
1214
|
|
|
1175
1215
|
|
|
1216
|
+
|
|
1176
1217
|
|
|
1177
1218
|
|
|
1178
1219
|
;// ./lib/models/templateCompiler/templateCompiler.js
|
|
@@ -1246,6 +1287,9 @@ class TemplateCompiler {
|
|
|
1246
1287
|
static removeHtml(data, args) {
|
|
1247
1288
|
return _removeHtml(data, args)
|
|
1248
1289
|
}
|
|
1290
|
+
static sum(data, args) {
|
|
1291
|
+
return _sum(data, args)
|
|
1292
|
+
}
|
|
1249
1293
|
static toLowerCase(data, args) {
|
|
1250
1294
|
return _toLowerCase(data, args)
|
|
1251
1295
|
}
|
|
@@ -1306,7 +1350,7 @@ function _parseFunction(expression, existFunctionNames) {
|
|
|
1306
1350
|
|
|
1307
1351
|
function _parseParams(parameters) {
|
|
1308
1352
|
const _parameters = parameters.trim()
|
|
1309
|
-
const regExp = new RegExp(/^[^\w\
|
|
1353
|
+
const regExp = new RegExp(/^[^\w\s]+$/)
|
|
1310
1354
|
const match = _parameters.match(regExp)
|
|
1311
1355
|
if (match !== null) {
|
|
1312
1356
|
return [_parameters.substring(1, _parameters.length - 1)]
|
|
@@ -1321,13 +1365,13 @@ function _parseParams(parameters) {
|
|
|
1321
1365
|
|
|
1322
1366
|
function _splitIgnoringBrackets(input) {
|
|
1323
1367
|
const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
|
|
1324
|
-
const regExp = new RegExp(/(?![
|
|
1368
|
+
const regExp = new RegExp(/(?![^[]*\])\s*,\s*/)
|
|
1325
1369
|
const parts = input.split(regExp)
|
|
1326
1370
|
return parts.map((part) => {
|
|
1327
1371
|
const _part = part.trim()
|
|
1328
1372
|
if (_part !== '' && !!_part.match(regExp2)) {
|
|
1329
1373
|
// 如果是数字,转换为 num 类型
|
|
1330
|
-
return Number.isNaN(_part) ? _part : parseInt(_part, 10)
|
|
1374
|
+
return Number.isNaN(_part) ? _part : Number.parseInt(_part, 10)
|
|
1331
1375
|
}
|
|
1332
1376
|
// 否则当作字符串处理
|
|
1333
1377
|
return _part
|
|
@@ -1340,7 +1384,7 @@ function _parseSinglePart(input) {
|
|
|
1340
1384
|
// 去掉双引号,返回
|
|
1341
1385
|
return input.substring(1, input.length - 1)
|
|
1342
1386
|
}
|
|
1343
|
-
if (input.startsWith(
|
|
1387
|
+
if (input.startsWith('\'') && input.endsWith('\'')) {
|
|
1344
1388
|
// 去掉双引号,返回
|
|
1345
1389
|
return input.substring(1, input.length - 1)
|
|
1346
1390
|
}
|
|
@@ -1371,7 +1415,7 @@ function _toBasicType(input) {
|
|
|
1371
1415
|
// 去掉双引号,返回
|
|
1372
1416
|
return input.substring(1, input.length - 1)
|
|
1373
1417
|
}
|
|
1374
|
-
if (input.startsWith(
|
|
1418
|
+
if (input.startsWith('\'') && input.endsWith('\'')) {
|
|
1375
1419
|
// 去掉双引号,返回
|
|
1376
1420
|
return input.substring(1, input.length - 1)
|
|
1377
1421
|
}
|
|
@@ -1439,6 +1483,8 @@ function _callFunction(data, functionName, parameters) {
|
|
|
1439
1483
|
return _neq(data, parameters)
|
|
1440
1484
|
case 'removeHtml':
|
|
1441
1485
|
return _removeHtml(data, parameters)
|
|
1486
|
+
case 'sum':
|
|
1487
|
+
return _sum(data, parameters)
|
|
1442
1488
|
case 'toLowerCase':
|
|
1443
1489
|
return _toLowerCase(data)
|
|
1444
1490
|
case 'toUpperCase':
|
|
@@ -1468,14 +1514,14 @@ function concatStringByArray(arrTemplate, data) {
|
|
|
1468
1514
|
return arrTemplate.reduce((acc, item) => {
|
|
1469
1515
|
const { type, value = '', restriction, template, format, showMinutes } = item
|
|
1470
1516
|
switch (type) {
|
|
1471
|
-
case('array'): {
|
|
1517
|
+
case ('array'): {
|
|
1472
1518
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
1473
1519
|
const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || []
|
|
1474
1520
|
acc += _value.reduce((_acc, item) => {
|
|
1475
1521
|
return _acc += concatStringByArray(template, item)
|
|
1476
1522
|
}, '')
|
|
1477
1523
|
}
|
|
1478
|
-
break
|
|
1524
|
+
break
|
|
1479
1525
|
}
|
|
1480
1526
|
case ('date'): {
|
|
1481
1527
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
@@ -1484,7 +1530,7 @@ function concatStringByArray(arrTemplate, data) {
|
|
|
1484
1530
|
}
|
|
1485
1531
|
break
|
|
1486
1532
|
}
|
|
1487
|
-
case('ellipsis'): {
|
|
1533
|
+
case ('ellipsis'): {
|
|
1488
1534
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
1489
1535
|
const { maxLength } = item
|
|
1490
1536
|
const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
|
|
@@ -1494,15 +1540,15 @@ function concatStringByArray(arrTemplate, data) {
|
|
|
1494
1540
|
acc += `${_value.substr(0, maxLength)}...`
|
|
1495
1541
|
}
|
|
1496
1542
|
}
|
|
1497
|
-
break
|
|
1543
|
+
break
|
|
1498
1544
|
}
|
|
1499
|
-
case('group'): {
|
|
1545
|
+
case ('group'): {
|
|
1500
1546
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
1501
1547
|
return concatStringByArray(value, data)
|
|
1502
1548
|
}
|
|
1503
1549
|
break
|
|
1504
1550
|
}
|
|
1505
|
-
case('label'): {
|
|
1551
|
+
case ('label'): {
|
|
1506
1552
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
1507
1553
|
acc += (value.toString())
|
|
1508
1554
|
}
|
|
@@ -1515,12 +1561,12 @@ function concatStringByArray(arrTemplate, data) {
|
|
|
1515
1561
|
}
|
|
1516
1562
|
break
|
|
1517
1563
|
}
|
|
1518
|
-
case('value'): {
|
|
1564
|
+
case ('value'): {
|
|
1519
1565
|
if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
|
|
1520
1566
|
const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
|
|
1521
1567
|
acc += (_value.toString())
|
|
1522
1568
|
}
|
|
1523
|
-
break
|
|
1569
|
+
break
|
|
1524
1570
|
}
|
|
1525
1571
|
}
|
|
1526
1572
|
return acc
|
|
@@ -1531,7 +1577,6 @@ function concatStringByArray(arrTemplate, data) {
|
|
|
1531
1577
|
});
|
|
1532
1578
|
|
|
1533
1579
|
|
|
1534
|
-
|
|
1535
1580
|
;// ./lib/helpers/concatStringByArray/index.js
|
|
1536
1581
|
|
|
1537
1582
|
|
|
@@ -1542,7 +1587,7 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1542
1587
|
if (!string) {
|
|
1543
1588
|
return ''
|
|
1544
1589
|
}
|
|
1545
|
-
|
|
1590
|
+
const _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
|
|
1546
1591
|
const reg = new RegExp(patternMatch, 'g')
|
|
1547
1592
|
return string.replace(reg, (match, key) => {
|
|
1548
1593
|
const result = _getValueByKeys({ keys: key.split('.'), obj: value })
|
|
@@ -1561,9 +1606,110 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1561
1606
|
;// ./lib/helpers/convertString/index.js
|
|
1562
1607
|
|
|
1563
1608
|
|
|
1609
|
+
;// ./lib/helpers/detectControlCharacters/detectControlCharacters.js
|
|
1610
|
+
/**
|
|
1611
|
+
* Detects and reports hidden/control characters in a string without modifying it.
|
|
1612
|
+
* @param {string} input - The string to analyze.
|
|
1613
|
+
* @param {Object} [options] - Configuration options.
|
|
1614
|
+
* @param {boolean} [options.preserveBasicWhitespace=true] - Whether to consider basic whitespace as valid.
|
|
1615
|
+
* @returns {Object} Report object with detection results.
|
|
1616
|
+
*/
|
|
1617
|
+
function detectControlCharacters(input, options = {}) {
|
|
1618
|
+
const {
|
|
1619
|
+
preserveBasicWhitespace = true,
|
|
1620
|
+
removeNewlines = false
|
|
1621
|
+
} = options
|
|
1622
|
+
|
|
1623
|
+
if (typeof input !== 'string') {
|
|
1624
|
+
return {
|
|
1625
|
+
hasControlChars: false,
|
|
1626
|
+
matches: [],
|
|
1627
|
+
inputType: typeof input,
|
|
1628
|
+
message: 'Input is not a string'
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const matches = []
|
|
1633
|
+
let regex
|
|
1634
|
+
|
|
1635
|
+
if (preserveBasicWhitespace && !removeNewlines) {
|
|
1636
|
+
// Same regex as Phase 1 preserve mode - keep tab (\t), newline (\n), carriage return (\r)
|
|
1637
|
+
regex = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1638
|
+
} else {
|
|
1639
|
+
// Same regex as Phase 1 full removal mode - use consistent escape sequences
|
|
1640
|
+
regex = /[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// Use a replacer function to capture matches without modifying the string
|
|
1644
|
+
input.replace(regex, (match, offset) => {
|
|
1645
|
+
matches.push({
|
|
1646
|
+
character: match,
|
|
1647
|
+
code: match.charCodeAt(0),
|
|
1648
|
+
hex: '0x' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'),
|
|
1649
|
+
position: offset,
|
|
1650
|
+
context: getContext(input, offset, 10) // Show surrounding text
|
|
1651
|
+
})
|
|
1652
|
+
return '' // Return empty but we don't use the result
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
return {
|
|
1656
|
+
hasControlChars: matches.length > 0,
|
|
1657
|
+
matches: matches,
|
|
1658
|
+
totalFound: matches.length,
|
|
1659
|
+
inputPreview: input.length > 50 ? input.substring(0, 50) + '...' : input,
|
|
1660
|
+
inputLength: input.length,
|
|
1661
|
+
optionsUsed: { preserveBasicWhitespace },
|
|
1662
|
+
regexPattern: regex.toString()
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* Helper function to get context around a match
|
|
1668
|
+
*/
|
|
1669
|
+
function getContext(str, position, contextLength = 10) {
|
|
1670
|
+
const start = Math.max(0, position - contextLength)
|
|
1671
|
+
const end = Math.min(str.length, position + contextLength + 1)
|
|
1672
|
+
let context = str.substring(start, end)
|
|
1673
|
+
|
|
1674
|
+
// Replace control characters with their escape sequences for readability
|
|
1675
|
+
context = context.replace(/[\x00-\x1F\x7F-\x9F]/g, (match) => {
|
|
1676
|
+
return '\\u' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
|
|
1677
|
+
})
|
|
1678
|
+
|
|
1679
|
+
return context
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/**
|
|
1683
|
+
* Pretty print the detection results to console
|
|
1684
|
+
*/
|
|
1685
|
+
function printControlCharReport(report) {
|
|
1686
|
+
console.log('=== Control Character Detection Report ===')
|
|
1687
|
+
console.log(`Input: "${report.inputPreview}" (${report.inputLength} chars)`)
|
|
1688
|
+
console.log(`Options: preserveBasicWhitespace = ${report.optionsUsed.preserveBasicWhitespace}`)
|
|
1689
|
+
console.log(`Regex pattern: ${report.regexPattern}`)
|
|
1690
|
+
console.log(`Control characters found: ${report.totalFound}`)
|
|
1691
|
+
|
|
1692
|
+
if (report.hasControlChars) {
|
|
1693
|
+
console.log('\n📋 Matches found:')
|
|
1694
|
+
report.matches.forEach((match, index) => {
|
|
1695
|
+
console.log(`\n${index + 1}. Character: ${JSON.stringify(match.character)}`)
|
|
1696
|
+
console.log(` Code: ${match.code} (${match.hex})`)
|
|
1697
|
+
console.log(` Position: ${match.position}`)
|
|
1698
|
+
console.log(` Context: "...${match.context}..."`)
|
|
1699
|
+
})
|
|
1700
|
+
} else {
|
|
1701
|
+
console.log('✅ No control characters detected in Phase 1 range')
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
console.log('=== End Report ===')
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
;// ./lib/helpers/detectControlCharacters/index.js
|
|
1708
|
+
|
|
1709
|
+
|
|
1564
1710
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1565
1711
|
function escapeRegex(string) {
|
|
1566
|
-
return String(string).replace(/[
|
|
1712
|
+
return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
1567
1713
|
}
|
|
1568
1714
|
|
|
1569
1715
|
;// ./lib/helpers/escapeRegex/index.js
|
|
@@ -1666,7 +1812,6 @@ function updateOneResult({ responseHelper, service }) {
|
|
|
1666
1812
|
|
|
1667
1813
|
|
|
1668
1814
|
|
|
1669
|
-
|
|
1670
1815
|
const expressHelper = {
|
|
1671
1816
|
customHandler: customHandler,
|
|
1672
1817
|
findAllResult: findAllResult,
|
|
@@ -1682,27 +1827,29 @@ const expressHelper = {
|
|
|
1682
1827
|
* @returns {Array} Sorted array of unique, lowercase email addresses
|
|
1683
1828
|
*/
|
|
1684
1829
|
function extractEmails(dirtyArray) {
|
|
1685
|
-
const emailRegex = /[
|
|
1830
|
+
const emailRegex = /[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi
|
|
1686
1831
|
const emails = new Set()
|
|
1687
1832
|
|
|
1688
1833
|
// Handle null/undefined input array
|
|
1689
|
-
if (!dirtyArray)
|
|
1834
|
+
if (!dirtyArray)
|
|
1835
|
+
return []
|
|
1690
1836
|
|
|
1691
|
-
dirtyArray.forEach(entry => {
|
|
1837
|
+
dirtyArray.forEach((entry) => {
|
|
1692
1838
|
// Skip null, undefined, empty, or whitespace-only entries
|
|
1693
|
-
if (!entry || typeof entry !== 'string' || !entry.trim())
|
|
1839
|
+
if (!entry || typeof entry !== 'string' || !entry.trim())
|
|
1840
|
+
return
|
|
1694
1841
|
|
|
1695
1842
|
try {
|
|
1696
1843
|
const cleanEntry = entry
|
|
1697
1844
|
.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
|
|
1698
|
-
.replace(/[<>]/g, ' ')
|
|
1699
|
-
.replace(/\s+/g, ' ')
|
|
1845
|
+
.replace(/[<>]/g, ' ') // Convert email delimiters to spaces
|
|
1846
|
+
.replace(/\s+/g, ' ') // Collapse multiple whitespace
|
|
1700
1847
|
.trim()
|
|
1701
1848
|
|
|
1702
1849
|
// Extract all email matches
|
|
1703
1850
|
const matches = cleanEntry.match(emailRegex)
|
|
1704
1851
|
if (matches) {
|
|
1705
|
-
matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1852
|
+
matches.forEach((email) => emails.add(email.toLowerCase())) // Normalize to lowercase
|
|
1706
1853
|
}
|
|
1707
1854
|
} catch (e) {
|
|
1708
1855
|
console.warn('Failed to process entry:', entry, e)
|
|
@@ -1748,64 +1895,65 @@ const objectHelper = {
|
|
|
1748
1895
|
},
|
|
1749
1896
|
merge,
|
|
1750
1897
|
set(obj, path, value) {
|
|
1751
|
-
const parts = path.split('.')
|
|
1752
|
-
let current = obj
|
|
1898
|
+
const parts = path.split('.')
|
|
1899
|
+
let current = obj
|
|
1753
1900
|
|
|
1754
1901
|
// 处理所有中间部分
|
|
1755
1902
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
1756
|
-
const part = parts[i]
|
|
1757
|
-
let key, index
|
|
1903
|
+
const part = parts[i]
|
|
1904
|
+
let key, index
|
|
1758
1905
|
|
|
1759
1906
|
// 检查是否是数组索引格式,如key[0]
|
|
1760
|
-
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/)
|
|
1907
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/)
|
|
1761
1908
|
if (arrayMatch) {
|
|
1762
|
-
key = arrayMatch[1]
|
|
1763
|
-
index = parseInt(arrayMatch[2], 10)
|
|
1909
|
+
key = arrayMatch[1]
|
|
1910
|
+
index = Number.parseInt(arrayMatch[2], 10)
|
|
1764
1911
|
// 确保当前层级的数组存在
|
|
1765
1912
|
if (!current[key] || !Array.isArray(current[key])) {
|
|
1766
|
-
current[key] = []
|
|
1913
|
+
current[key] = []
|
|
1767
1914
|
}
|
|
1768
1915
|
// 扩展数组到足够大
|
|
1769
1916
|
while (current[key].length <= index) {
|
|
1770
|
-
current[key].push(undefined)
|
|
1917
|
+
current[key].push(undefined)
|
|
1771
1918
|
}
|
|
1772
1919
|
// 如果当前位置未定义或为null,初始化为对象
|
|
1773
1920
|
if (current[key][index] == null) {
|
|
1774
|
-
current[key][index] = {}
|
|
1921
|
+
current[key][index] = {}
|
|
1775
1922
|
}
|
|
1776
|
-
current = current[key][index]
|
|
1923
|
+
current = current[key][index]
|
|
1777
1924
|
} else {
|
|
1778
1925
|
// 处理普通属性
|
|
1779
1926
|
if (!current[part]) {
|
|
1780
|
-
current[part] = {}
|
|
1927
|
+
current[part] = {}
|
|
1781
1928
|
}
|
|
1782
|
-
current = current[part]
|
|
1929
|
+
current = current[part]
|
|
1783
1930
|
}
|
|
1784
1931
|
}
|
|
1785
1932
|
|
|
1786
1933
|
// 处理最后一部分
|
|
1787
|
-
const lastPart = parts[parts.length - 1]
|
|
1788
|
-
const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/)
|
|
1934
|
+
const lastPart = parts[parts.length - 1]
|
|
1935
|
+
const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/)
|
|
1789
1936
|
if (arrayMatch) {
|
|
1790
|
-
const key = arrayMatch[1]
|
|
1791
|
-
const index = parseInt(arrayMatch[2], 10)
|
|
1937
|
+
const key = arrayMatch[1]
|
|
1938
|
+
const index = Number.parseInt(arrayMatch[2], 10)
|
|
1792
1939
|
// 确保数组存在
|
|
1793
1940
|
if (!current[key] || !Array.isArray(current[key])) {
|
|
1794
|
-
current[key] = []
|
|
1941
|
+
current[key] = []
|
|
1795
1942
|
}
|
|
1796
1943
|
// 扩展数组到所需索引
|
|
1797
1944
|
while (current[key].length <= index) {
|
|
1798
|
-
current[key].push(undefined)
|
|
1945
|
+
current[key].push(undefined)
|
|
1799
1946
|
}
|
|
1800
|
-
current[key][index] = value
|
|
1947
|
+
current[key][index] = value
|
|
1801
1948
|
} else {
|
|
1802
|
-
current[lastPart] = value
|
|
1949
|
+
current[lastPart] = value
|
|
1803
1950
|
}
|
|
1804
1951
|
}
|
|
1805
1952
|
}
|
|
1806
1953
|
|
|
1807
1954
|
function merge(target, ...sources) {
|
|
1808
|
-
if (!sources.length)
|
|
1955
|
+
if (!sources.length)
|
|
1956
|
+
return target
|
|
1809
1957
|
|
|
1810
1958
|
const source = sources.shift() // 取出第一个源对象
|
|
1811
1959
|
|
|
@@ -1842,28 +1990,28 @@ function _isObject(obj) {
|
|
|
1842
1990
|
|
|
1843
1991
|
;// ./lib/helpers/pReduce/pReduce.js
|
|
1844
1992
|
async function pReduce(iterable, reducer, initialValue) {
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1993
|
+
return new Promise((resolve, reject) => {
|
|
1994
|
+
const iterator = iterable[Symbol.iterator]()
|
|
1995
|
+
let index = 0
|
|
1848
1996
|
|
|
1849
|
-
|
|
1850
|
-
|
|
1997
|
+
const next = async (total) => {
|
|
1998
|
+
const element = iterator.next()
|
|
1851
1999
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
2000
|
+
if (element.done) {
|
|
2001
|
+
resolve(total)
|
|
2002
|
+
return
|
|
2003
|
+
}
|
|
1856
2004
|
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2005
|
+
try {
|
|
2006
|
+
const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
|
|
2007
|
+
next(reducer(resolvedTotal, resolvedValue, index++))
|
|
2008
|
+
} catch (error) {
|
|
2009
|
+
reject(error)
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
1864
2012
|
|
|
1865
|
-
|
|
1866
|
-
|
|
2013
|
+
next(initialValue)
|
|
2014
|
+
})
|
|
1867
2015
|
}
|
|
1868
2016
|
|
|
1869
2017
|
|
|
@@ -2010,16 +2158,17 @@ class Repo {
|
|
|
2010
2158
|
const promise = typeof this.model.saveAll === 'function'
|
|
2011
2159
|
? this.model.saveAll({ config, docs })
|
|
2012
2160
|
: Promise.all(docs.map(async (doc) => {
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2161
|
+
if (doc) {
|
|
2162
|
+
const result = await this.saveOne({ config, doc })
|
|
2163
|
+
isNew = result.isNew
|
|
2164
|
+
const _data = result._data || result.data
|
|
2165
|
+
return _data[0]
|
|
2166
|
+
}
|
|
2167
|
+
return null
|
|
2168
|
+
}))
|
|
2021
2169
|
return promise.then((savedData) => {
|
|
2022
|
-
if (savedData.length !== 1)
|
|
2170
|
+
if (savedData.length !== 1)
|
|
2171
|
+
isNew = null
|
|
2023
2172
|
const result = {
|
|
2024
2173
|
data: savedData,
|
|
2025
2174
|
isNew,
|
|
@@ -2353,6 +2502,9 @@ function initOnlyValidFromArray(_class, arr) {
|
|
|
2353
2502
|
;// ./lib/helpers/initOnlyValidFromArray/index.js
|
|
2354
2503
|
|
|
2355
2504
|
|
|
2505
|
+
;// ./lib/helpers/isConvertibleToNumber/index.js
|
|
2506
|
+
|
|
2507
|
+
|
|
2356
2508
|
;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
|
|
2357
2509
|
function mergeArraysByKey(arr1, arr2) {
|
|
2358
2510
|
// Handle undefined/null inputs by defaulting to empty arrays
|
|
@@ -2363,40 +2515,41 @@ function mergeArraysByKey(arr1, arr2) {
|
|
|
2363
2515
|
|
|
2364
2516
|
// Helper function to merge values based on their type
|
|
2365
2517
|
const mergeValues = (existingValue, newValue) => {
|
|
2366
|
-
if (existingValue === undefined)
|
|
2367
|
-
|
|
2518
|
+
if (existingValue === undefined)
|
|
2519
|
+
return newValue
|
|
2520
|
+
|
|
2368
2521
|
// Handle arrays by concatenating
|
|
2369
2522
|
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
2370
2523
|
return [...new Set([...existingValue, ...newValue])]
|
|
2371
2524
|
}
|
|
2372
|
-
|
|
2525
|
+
|
|
2373
2526
|
// Handle objects by merging
|
|
2374
|
-
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
2375
|
-
|
|
2527
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
2528
|
+
&& !Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
2376
2529
|
return { ...existingValue, ...newValue }
|
|
2377
2530
|
}
|
|
2378
|
-
|
|
2531
|
+
|
|
2379
2532
|
// // Handle numbers by adding
|
|
2380
2533
|
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
2381
2534
|
// return existingValue
|
|
2382
2535
|
// }
|
|
2383
|
-
|
|
2536
|
+
|
|
2384
2537
|
// // Handle strings by concatenating
|
|
2385
2538
|
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
2386
2539
|
// return existingValue
|
|
2387
2540
|
// }
|
|
2388
|
-
|
|
2541
|
+
|
|
2389
2542
|
// Default: use the new value
|
|
2390
2543
|
return newValue
|
|
2391
2544
|
}
|
|
2392
2545
|
|
|
2393
2546
|
// Process first array
|
|
2394
|
-
safeArr1.forEach(item => {
|
|
2547
|
+
safeArr1.forEach((item) => {
|
|
2395
2548
|
mergedMap.set(item.key, item.value)
|
|
2396
2549
|
})
|
|
2397
2550
|
|
|
2398
2551
|
// Process second array and merge values
|
|
2399
|
-
safeArr2.forEach(item => {
|
|
2552
|
+
safeArr2.forEach((item) => {
|
|
2400
2553
|
const existingValue = mergedMap.get(item.key)
|
|
2401
2554
|
mergedMap.set(item.key, mergeValues(existingValue, item.value))
|
|
2402
2555
|
})
|
|
@@ -2415,7 +2568,7 @@ function mergeArraysByKey(arr1, arr2) {
|
|
|
2415
2568
|
function padZeros(num, minLength = 6) {
|
|
2416
2569
|
num = num.toString()
|
|
2417
2570
|
if (num.length < minLength) {
|
|
2418
|
-
return padZeros(
|
|
2571
|
+
return padZeros(`0${num}`, minLength)
|
|
2419
2572
|
}
|
|
2420
2573
|
return num
|
|
2421
2574
|
}
|
|
@@ -2435,26 +2588,26 @@ function padZeros(num, minLength = 6) {
|
|
|
2435
2588
|
;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
|
|
2436
2589
|
function replacePlaceholders({ content, mapping }) {
|
|
2437
2590
|
let isObjectMode = false
|
|
2438
|
-
|
|
2591
|
+
|
|
2439
2592
|
if (typeof content === 'object' && content !== null) {
|
|
2440
2593
|
content = JSON.stringify(content)
|
|
2441
2594
|
isObjectMode = true
|
|
2442
2595
|
}
|
|
2443
2596
|
|
|
2444
2597
|
// [[ eventRegistration.eventRegistrationCode | 0 ]]
|
|
2445
|
-
const regex = /(\[*)\[\[\s*([\w.\-
|
|
2598
|
+
const regex = /(\[*)\[\[\s*([\w.\-]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g
|
|
2446
2599
|
|
|
2447
2600
|
const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
|
|
2448
|
-
|
|
2449
2601
|
// Split the path into parts
|
|
2450
2602
|
const keys = path.trim().split('.')
|
|
2451
|
-
|
|
2603
|
+
|
|
2452
2604
|
// Traverse the nested object structure
|
|
2453
2605
|
let value = mapping
|
|
2454
2606
|
for (const key of keys) {
|
|
2455
2607
|
// Handle empty keys (in case of double dots or leading/trailing dots)
|
|
2456
|
-
if (!key)
|
|
2457
|
-
|
|
2608
|
+
if (!key)
|
|
2609
|
+
continue
|
|
2610
|
+
|
|
2458
2611
|
value = value?.[key]
|
|
2459
2612
|
if (value === undefined) {
|
|
2460
2613
|
break
|
|
@@ -2462,10 +2615,12 @@ function replacePlaceholders({ content, mapping }) {
|
|
|
2462
2615
|
}
|
|
2463
2616
|
|
|
2464
2617
|
// Apply default if missing
|
|
2465
|
-
if (value === undefined)
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2618
|
+
if (value === undefined)
|
|
2619
|
+
value = defaultValue?.trim()
|
|
2620
|
+
if (value === undefined)
|
|
2621
|
+
return isObjectMode ? undefined : match
|
|
2622
|
+
|
|
2623
|
+
value = value !== undefined
|
|
2469
2624
|
? leadingBrackets + value + trailingBrackets
|
|
2470
2625
|
: match
|
|
2471
2626
|
|
|
@@ -2486,10 +2641,11 @@ function replacePlaceholders({ content, mapping }) {
|
|
|
2486
2641
|
/**
|
|
2487
2642
|
* Sanitizes input by removing hidden/control characters with customizable whitespace handling.
|
|
2488
2643
|
* @param {string} input - The string to sanitize.
|
|
2489
|
-
* @param {
|
|
2490
|
-
* @param {boolean} [options.normalizeWhitespace
|
|
2491
|
-
* @param {boolean} [options.removeNewlines
|
|
2492
|
-
* @param {boolean} [options.trim
|
|
2644
|
+
* @param {object} [options] - Configuration options.
|
|
2645
|
+
* @param {boolean} [options.normalizeWhitespace] - Collapse multiple spaces/tabs into one space.
|
|
2646
|
+
* @param {boolean} [options.removeNewlines] - If true, replaces newlines with spaces.
|
|
2647
|
+
* @param {boolean} [options.trim] - If true, trims leading/trailing whitespace.
|
|
2648
|
+
* @param {boolean} [options.debug] - If true, logs debug information about removed characters.
|
|
2493
2649
|
* @returns {string} The sanitized string.
|
|
2494
2650
|
*/
|
|
2495
2651
|
function sanitizeText(input, options = {}) {
|
|
@@ -2497,7 +2653,8 @@ function sanitizeText(input, options = {}) {
|
|
|
2497
2653
|
normalizeWhitespace = true,
|
|
2498
2654
|
removeNewlines = false,
|
|
2499
2655
|
trim = true,
|
|
2500
|
-
preserveBasicWhitespace = true,
|
|
2656
|
+
preserveBasicWhitespace = true,
|
|
2657
|
+
debug = false, // new option for debugging
|
|
2501
2658
|
} = options
|
|
2502
2659
|
|
|
2503
2660
|
if (typeof input !== 'string') {
|
|
@@ -2506,27 +2663,106 @@ function sanitizeText(input, options = {}) {
|
|
|
2506
2663
|
|
|
2507
2664
|
let result = input
|
|
2508
2665
|
|
|
2666
|
+
if (debug) {
|
|
2667
|
+
console.log('Original input:', JSON.stringify(input))
|
|
2668
|
+
console.log('Options:', { normalizeWhitespace, removeNewlines, trim, preserveBasicWhitespace })
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2509
2671
|
// Phase 1: Remove all control characters except basic whitespace if requested
|
|
2510
2672
|
if (preserveBasicWhitespace && !removeNewlines) {
|
|
2511
|
-
|
|
2512
|
-
|
|
2673
|
+
if (debug) {
|
|
2674
|
+
const before = result
|
|
2675
|
+
const matches = []
|
|
2676
|
+
// Use a replacer function to capture what's being removed
|
|
2677
|
+
result = result.replace(/[\x00-\x08\v\f\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, (match) => {
|
|
2678
|
+
matches.push({
|
|
2679
|
+
char: match,
|
|
2680
|
+
code: match.charCodeAt(0),
|
|
2681
|
+
hex: `0x${match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`
|
|
2682
|
+
})
|
|
2683
|
+
return ''
|
|
2684
|
+
})
|
|
2685
|
+
if (matches.length > 0) {
|
|
2686
|
+
console.log('Phase 1 (preserve mode) - Removed characters:')
|
|
2687
|
+
matches.forEach((m) => {
|
|
2688
|
+
console.log(` - Character: ${JSON.stringify(m.char)}, Code: ${m.code}, Hex: ${m.hex}`)
|
|
2689
|
+
})
|
|
2690
|
+
console.log(`Removed ${matches.length} control character(s)`)
|
|
2691
|
+
} else {
|
|
2692
|
+
console.log('Phase 1 (preserve mode) - No control characters found')
|
|
2693
|
+
}
|
|
2694
|
+
} else {
|
|
2695
|
+
result = result.replace(/[\x00-\x08\v\f\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2696
|
+
}
|
|
2513
2697
|
} else {
|
|
2514
|
-
|
|
2515
|
-
|
|
2698
|
+
if (debug) {
|
|
2699
|
+
const before = result
|
|
2700
|
+
const matches = []
|
|
2701
|
+
result = result.replace(/[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, (match) => {
|
|
2702
|
+
matches.push({
|
|
2703
|
+
char: match,
|
|
2704
|
+
code: match.charCodeAt(0),
|
|
2705
|
+
hex: `0x${match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`
|
|
2706
|
+
})
|
|
2707
|
+
return ''
|
|
2708
|
+
})
|
|
2709
|
+
if (matches.length > 0) {
|
|
2710
|
+
console.log('Phase 1 (full removal mode) - Removed characters:')
|
|
2711
|
+
matches.forEach((m) => {
|
|
2712
|
+
console.log(` - Character: ${JSON.stringify(m.char)}, Code: ${m.code}, Hex: ${m.hex}`)
|
|
2713
|
+
})
|
|
2714
|
+
console.log(`Removed ${matches.length} control character(s)`)
|
|
2715
|
+
} else {
|
|
2716
|
+
console.log('Phase 1 (full removal mode) - No control characters found')
|
|
2717
|
+
}
|
|
2718
|
+
} else {
|
|
2719
|
+
result = result.replace(/[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
if (debug) {
|
|
2724
|
+
console.log('After Phase 1:', JSON.stringify(result))
|
|
2516
2725
|
}
|
|
2517
2726
|
|
|
2518
2727
|
// Phase 2: Handle whitespace transformations
|
|
2519
2728
|
if (removeNewlines) {
|
|
2520
|
-
|
|
2729
|
+
if (debug) {
|
|
2730
|
+
const before = result
|
|
2731
|
+
result = result.replace(/[\r\n]+/g, ' ')
|
|
2732
|
+
console.log('Phase 2 - Converted newlines to spaces')
|
|
2733
|
+
} else {
|
|
2734
|
+
result = result.replace(/[\r\n]+/g, ' ')
|
|
2735
|
+
}
|
|
2521
2736
|
}
|
|
2522
2737
|
|
|
2523
2738
|
if (normalizeWhitespace) {
|
|
2524
|
-
|
|
2739
|
+
if (debug) {
|
|
2740
|
+
const before = result
|
|
2741
|
+
result = result.replace(/[ \t]+/g, ' ')
|
|
2742
|
+
console.log('Phase 2 - Normalized whitespace')
|
|
2743
|
+
} else {
|
|
2744
|
+
result = result.replace(/[ \t]+/g, ' ')
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
if (debug) {
|
|
2749
|
+
console.log('After Phase 2:', JSON.stringify(result))
|
|
2525
2750
|
}
|
|
2526
2751
|
|
|
2527
2752
|
// Phase 3: Final trimming
|
|
2528
2753
|
if (trim) {
|
|
2529
|
-
|
|
2754
|
+
if (debug) {
|
|
2755
|
+
const before = result
|
|
2756
|
+
result = result.trim()
|
|
2757
|
+
console.log('Phase 3 - Trimmed leading/trailing whitespace')
|
|
2758
|
+
} else {
|
|
2759
|
+
result = result.trim()
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
if (debug) {
|
|
2764
|
+
console.log('Final result:', JSON.stringify(result))
|
|
2765
|
+
console.log('--- Sanitization complete ---')
|
|
2530
2766
|
}
|
|
2531
2767
|
|
|
2532
2768
|
return result
|
|
@@ -2537,12 +2773,12 @@ function sanitizeText(input, options = {}) {
|
|
|
2537
2773
|
|
|
2538
2774
|
;// ./lib/helpers/shuffleArray/shuffleArray.js
|
|
2539
2775
|
function shuffleArray(array) {
|
|
2540
|
-
const arr = [...array]
|
|
2541
|
-
for (let i = arr.length - 1; i >= 0; i--) {
|
|
2776
|
+
const arr = [...array]
|
|
2777
|
+
for (let i = arr.length - 1; i >= 0; i--) { // Changed `i > 0` to `i >= 0`
|
|
2542
2778
|
const j = Math.floor(Math.random() * (i + 1));
|
|
2543
|
-
[arr[i], arr[j]] = [arr[j], arr[i]]
|
|
2779
|
+
[arr[i], arr[j]] = [arr[j], arr[i]]
|
|
2544
2780
|
}
|
|
2545
|
-
return arr
|
|
2781
|
+
return arr
|
|
2546
2782
|
}
|
|
2547
2783
|
|
|
2548
2784
|
;// ./lib/helpers/shuffleArray/index.js
|
|
@@ -2604,7 +2840,7 @@ function indexCharset(str) {
|
|
|
2604
2840
|
for (let i = 0; i < length; i++) {
|
|
2605
2841
|
char = str[i]
|
|
2606
2842
|
byCode[i] = char
|
|
2607
|
-
byChar[char] = i
|
|
2843
|
+
byChar[char] = i
|
|
2608
2844
|
}
|
|
2609
2845
|
return { byCode, byChar, length }
|
|
2610
2846
|
}
|
|
@@ -2635,7 +2871,7 @@ function randomString({ len = 16, pattern = 'a1' } = {}) {
|
|
|
2635
2871
|
str += mark
|
|
2636
2872
|
}
|
|
2637
2873
|
const chars = [...str]
|
|
2638
|
-
return [...Array(len)].map(i => {
|
|
2874
|
+
return [...new Array(len)].map((i) => {
|
|
2639
2875
|
return chars[(Math.random() * chars.length) | 0]
|
|
2640
2876
|
}).join``
|
|
2641
2877
|
}
|
|
@@ -2659,12 +2895,14 @@ function setCode(base = 34) {
|
|
|
2659
2895
|
}
|
|
2660
2896
|
|
|
2661
2897
|
function toCamelCase(str) {
|
|
2662
|
-
if (!str)
|
|
2898
|
+
if (!str)
|
|
2899
|
+
return ''
|
|
2663
2900
|
return str
|
|
2664
2901
|
.trim()
|
|
2665
2902
|
.split(/\s+/)
|
|
2666
2903
|
.map((word, index) => {
|
|
2667
|
-
if (!word)
|
|
2904
|
+
if (!word)
|
|
2905
|
+
return ''
|
|
2668
2906
|
if (index === 0) {
|
|
2669
2907
|
return word.toLowerCase()
|
|
2670
2908
|
}
|
|
@@ -2674,7 +2912,8 @@ function toCamelCase(str) {
|
|
|
2674
2912
|
}
|
|
2675
2913
|
|
|
2676
2914
|
function toLowerCase(str) {
|
|
2677
|
-
if (!str)
|
|
2915
|
+
if (!str)
|
|
2916
|
+
return ''
|
|
2678
2917
|
return str
|
|
2679
2918
|
.trim()
|
|
2680
2919
|
.toLowerCase()
|
|
@@ -2709,7 +2948,7 @@ function trackingPlugin(schema, options) {
|
|
|
2709
2948
|
})
|
|
2710
2949
|
|
|
2711
2950
|
// Auto-update hook
|
|
2712
|
-
schema.pre('save', function(next) {
|
|
2951
|
+
schema.pre('save', function (next) {
|
|
2713
2952
|
this.meta.modified = Date.now()
|
|
2714
2953
|
next()
|
|
2715
2954
|
})
|
|
@@ -2721,9 +2960,9 @@ function trackingPlugin(schema, options) {
|
|
|
2721
2960
|
}, {
|
|
2722
2961
|
name: 'tracking_status_index',
|
|
2723
2962
|
background: true,
|
|
2724
|
-
partialFilterExpression: {
|
|
2963
|
+
partialFilterExpression: {
|
|
2725
2964
|
'meta.active': true,
|
|
2726
|
-
'meta.deleted': false
|
|
2965
|
+
'meta.deleted': false
|
|
2727
2966
|
}
|
|
2728
2967
|
})
|
|
2729
2968
|
|
|
@@ -2752,7 +2991,7 @@ function tenantPlugin(schema, options) {
|
|
|
2752
2991
|
|
|
2753
2992
|
// Add core indexes
|
|
2754
2993
|
schema.index({
|
|
2755
|
-
|
|
2994
|
+
tenantCode: 1
|
|
2756
2995
|
}, {
|
|
2757
2996
|
name: 'tenant_core_index',
|
|
2758
2997
|
background: true
|
|
@@ -2760,15 +2999,15 @@ function tenantPlugin(schema, options) {
|
|
|
2760
2999
|
|
|
2761
3000
|
// 1. ENHANCE EXISTING TRACKING INDEXES
|
|
2762
3001
|
const existingIndexes = schema.indexes()
|
|
2763
|
-
|
|
3002
|
+
|
|
2764
3003
|
// Check if tracking_status_index exists
|
|
2765
|
-
const hasTenantStatusIndex = existingIndexes.some(idx =>
|
|
3004
|
+
const hasTenantStatusIndex = existingIndexes.some((idx) =>
|
|
2766
3005
|
idx.name === 'tenant_status_index' // Check by name for reliability
|
|
2767
3006
|
)
|
|
2768
3007
|
|
|
2769
3008
|
if (!hasTenantStatusIndex) {
|
|
2770
3009
|
schema.index({
|
|
2771
|
-
|
|
3010
|
+
tenantCode: 1, // Unique field first
|
|
2772
3011
|
_type: 1, // Low-cardinality field last
|
|
2773
3012
|
}, {
|
|
2774
3013
|
name: 'tenant_status_index',
|
|
@@ -2776,7 +3015,7 @@ function tenantPlugin(schema, options) {
|
|
|
2776
3015
|
partialFilterExpression: {
|
|
2777
3016
|
'_type': 'Tenant',
|
|
2778
3017
|
'meta.active': true,
|
|
2779
|
-
'meta.deleted': false
|
|
3018
|
+
'meta.deleted': false
|
|
2780
3019
|
}
|
|
2781
3020
|
})
|
|
2782
3021
|
}
|
|
@@ -2814,6 +3053,8 @@ function tenantPlugin(schema, options) {
|
|
|
2814
3053
|
|
|
2815
3054
|
|
|
2816
3055
|
|
|
3056
|
+
|
|
3057
|
+
|
|
2817
3058
|
|
|
2818
3059
|
|
|
2819
3060
|
|
|
@@ -2872,10 +3113,11 @@ class AwsStsS3Client {
|
|
|
2872
3113
|
}
|
|
2873
3114
|
|
|
2874
3115
|
get isExpired() {
|
|
2875
|
-
if (!this.expiration)
|
|
2876
|
-
|
|
2877
|
-
const
|
|
2878
|
-
|
|
3116
|
+
if (!this.expiration)
|
|
3117
|
+
return true
|
|
3118
|
+
const now = new Date()
|
|
3119
|
+
const bufferMs = 1 * 60 * 1000 // 一分钟缓冲
|
|
3120
|
+
return now >= new Date(this.expiration.getTime() - bufferMs)
|
|
2879
3121
|
}
|
|
2880
3122
|
|
|
2881
3123
|
get isValid() {
|
|
@@ -2910,7 +3152,7 @@ class AwsStsS3Client {
|
|
|
2910
3152
|
throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
|
|
2911
3153
|
}
|
|
2912
3154
|
}
|
|
2913
|
-
|
|
3155
|
+
|
|
2914
3156
|
return true
|
|
2915
3157
|
}
|
|
2916
3158
|
|
|
@@ -2920,9 +3162,9 @@ class AwsStsS3Client {
|
|
|
2920
3162
|
if (!webIdentityToken) {
|
|
2921
3163
|
throw new Error('getIdToken function returned empty or invalid token')
|
|
2922
3164
|
}
|
|
2923
|
-
|
|
3165
|
+
|
|
2924
3166
|
const stsClient = new this.awsClientSts.STSClient({ region: this.region })
|
|
2925
|
-
|
|
3167
|
+
|
|
2926
3168
|
const stsResponse = await stsClient.send(
|
|
2927
3169
|
new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
|
|
2928
3170
|
RoleArn: this.roleArn,
|
|
@@ -3229,29 +3471,30 @@ class KeyValueObject {
|
|
|
3229
3471
|
}
|
|
3230
3472
|
|
|
3231
3473
|
function _mergeValues(existingValue, newValue) {
|
|
3232
|
-
if (existingValue === undefined)
|
|
3233
|
-
|
|
3474
|
+
if (existingValue === undefined)
|
|
3475
|
+
return newValue
|
|
3476
|
+
|
|
3234
3477
|
// Handle arrays by concatenating
|
|
3235
3478
|
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3236
3479
|
return [...new Set([...existingValue, ...newValue])]
|
|
3237
3480
|
}
|
|
3238
|
-
|
|
3481
|
+
|
|
3239
3482
|
// Handle objects by merging
|
|
3240
|
-
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
3241
|
-
|
|
3483
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
3484
|
+
&& !Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3242
3485
|
return { ...existingValue, ...newValue }
|
|
3243
3486
|
}
|
|
3244
|
-
|
|
3487
|
+
|
|
3245
3488
|
// // Handle numbers by adding
|
|
3246
3489
|
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3247
3490
|
// return existingValue
|
|
3248
3491
|
// }
|
|
3249
|
-
|
|
3492
|
+
|
|
3250
3493
|
// // Handle strings by concatenating
|
|
3251
3494
|
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3252
3495
|
// return existingValue
|
|
3253
3496
|
// }
|
|
3254
|
-
|
|
3497
|
+
|
|
3255
3498
|
// Default: use the new value
|
|
3256
3499
|
return newValue
|
|
3257
3500
|
}
|
|
@@ -3311,29 +3554,30 @@ function metadata_isSame(key1, key2) {
|
|
|
3311
3554
|
}
|
|
3312
3555
|
|
|
3313
3556
|
function metadata_mergeValues(existingValue, newValue) {
|
|
3314
|
-
if (existingValue === undefined)
|
|
3315
|
-
|
|
3557
|
+
if (existingValue === undefined)
|
|
3558
|
+
return newValue
|
|
3559
|
+
|
|
3316
3560
|
// Handle arrays by concatenating
|
|
3317
3561
|
if (Array.isArray(existingValue) && Array.isArray(newValue)) {
|
|
3318
3562
|
return [...new Set([...existingValue, ...newValue])]
|
|
3319
3563
|
}
|
|
3320
|
-
|
|
3564
|
+
|
|
3321
3565
|
// Handle objects by merging
|
|
3322
|
-
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
3323
|
-
|
|
3566
|
+
if (typeof existingValue === 'object' && typeof newValue === 'object'
|
|
3567
|
+
&& !Array.isArray(existingValue) && !Array.isArray(newValue)) {
|
|
3324
3568
|
return { ...existingValue, ...newValue }
|
|
3325
3569
|
}
|
|
3326
|
-
|
|
3570
|
+
|
|
3327
3571
|
// // Handle numbers by adding
|
|
3328
3572
|
// if (typeof existingValue === 'number' && typeof newValue === 'number') {
|
|
3329
3573
|
// return existingValue
|
|
3330
3574
|
// }
|
|
3331
|
-
|
|
3575
|
+
|
|
3332
3576
|
// // Handle strings by concatenating
|
|
3333
3577
|
// if (typeof existingValue === 'string' && typeof newValue === 'string') {
|
|
3334
3578
|
// return existingValue
|
|
3335
3579
|
// }
|
|
3336
|
-
|
|
3580
|
+
|
|
3337
3581
|
// Default: use the new value
|
|
3338
3582
|
return newValue
|
|
3339
3583
|
}
|
|
@@ -3354,14 +3598,14 @@ class TrackedEntity {
|
|
|
3354
3598
|
const timestamp = Date.now()
|
|
3355
3599
|
this.meta = {
|
|
3356
3600
|
active: options.meta?.active ?? options.active ?? true,
|
|
3357
|
-
created: options.meta?.created ?? (options.created
|
|
3358
|
-
|
|
3359
|
-
|
|
3601
|
+
created: options.meta?.created ?? (options.created
|
|
3602
|
+
? new Date(options.created).getTime()
|
|
3603
|
+
: timestamp),
|
|
3360
3604
|
creator: options.meta?.creator ?? options.creator ?? '',
|
|
3361
3605
|
deleted: options.meta?.deleted ?? options.deleted ?? false,
|
|
3362
|
-
modified: options.meta?.modified ?? (options.modified
|
|
3363
|
-
|
|
3364
|
-
|
|
3606
|
+
modified: options.meta?.modified ?? (options.modified
|
|
3607
|
+
? new Date(options.modified).getTime()
|
|
3608
|
+
: timestamp),
|
|
3365
3609
|
owner: options.meta?.owner ?? options.owner ?? '',
|
|
3366
3610
|
}
|
|
3367
3611
|
|
|
@@ -3528,7 +3772,6 @@ class PushEnvelope extends TrackedEntity {
|
|
|
3528
3772
|
get isValid() {
|
|
3529
3773
|
return super.isValid && this.data
|
|
3530
3774
|
}
|
|
3531
|
-
|
|
3532
3775
|
}
|
|
3533
3776
|
|
|
3534
3777
|
;// ./lib/models/pushEnvelope/index.js
|
|
@@ -3595,6 +3838,191 @@ class QMeta {
|
|
|
3595
3838
|
|
|
3596
3839
|
|
|
3597
3840
|
|
|
3841
|
+
;// ./lib/models/status/actionRecord.js
|
|
3842
|
+
|
|
3843
|
+
|
|
3844
|
+
class ActionRecord {
|
|
3845
|
+
constructor(options) {
|
|
3846
|
+
options = options || {}
|
|
3847
|
+
|
|
3848
|
+
const { _Actor } = options._constructor || {}
|
|
3849
|
+
this._Actor = _Actor
|
|
3850
|
+
|
|
3851
|
+
this._actor = options._actor
|
|
3852
|
+
|
|
3853
|
+
this.actorCode = typeof options === 'number' ? null : (options.actorCode || null)
|
|
3854
|
+
this.timestamp = typeof options === 'number' ? options : (options.timestamp || null)
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
static get _classname() {
|
|
3858
|
+
return 'ActionRecord'
|
|
3859
|
+
}
|
|
3860
|
+
static get _superclass() {
|
|
3861
|
+
return 'ActionRecord'
|
|
3862
|
+
}
|
|
3863
|
+
static dummyData() {
|
|
3864
|
+
return {
|
|
3865
|
+
timestamp: (new Date()).valueOf(),
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
static init(options = {}) {
|
|
3869
|
+
return init(this, options)
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
get _classname() {
|
|
3873
|
+
return 'ActionRecord'
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3876
|
+
get _superclass() {
|
|
3877
|
+
return 'ActionRecord'
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
get actor() {
|
|
3881
|
+
return this._Actor && typeof this._Actor.init === 'function' ? this._Actor.init(this._actor) : this._actor
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
get isValid() {
|
|
3885
|
+
return !!this.timestamp
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
update(update) {
|
|
3889
|
+
if (typeof update === 'number') {
|
|
3890
|
+
this.timestamp = update
|
|
3891
|
+
return this
|
|
3892
|
+
}
|
|
3893
|
+
Object.keys(update).forEach((key) => {
|
|
3894
|
+
this[key] = update[key]
|
|
3895
|
+
})
|
|
3896
|
+
return this
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
;// ./lib/models/status/status.js
|
|
3901
|
+
|
|
3902
|
+
|
|
3903
|
+
|
|
3904
|
+
const notUpdateAllowedProps = [
|
|
3905
|
+
'created',
|
|
3906
|
+
// 'statusType'
|
|
3907
|
+
]
|
|
3908
|
+
|
|
3909
|
+
class Status {
|
|
3910
|
+
constructor(options) {
|
|
3911
|
+
options = options || {}
|
|
3912
|
+
|
|
3913
|
+
const { _ActionRecord } = options._constructor || {}
|
|
3914
|
+
this._ActionRecord = _ActionRecord && (_ActionRecord._superclass === ActionRecord._superclass) ? _ActionRecord : ActionRecord
|
|
3915
|
+
|
|
3916
|
+
this.created = this._ActionRecord.init(options.created || { timestamp: (new Date()).valueOf() })
|
|
3917
|
+
// this.statusType = options.statusType || 'Status'
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3920
|
+
static get _classname() {
|
|
3921
|
+
return 'Status'
|
|
3922
|
+
}
|
|
3923
|
+
static get _superclass() {
|
|
3924
|
+
return 'Status'
|
|
3925
|
+
}
|
|
3926
|
+
static dummyData() {
|
|
3927
|
+
return {}
|
|
3928
|
+
}
|
|
3929
|
+
static init(options = {}) {
|
|
3930
|
+
return init(this, options)
|
|
3931
|
+
}
|
|
3932
|
+
static initFromArray(arr = []) {
|
|
3933
|
+
return initFromArray(this, arr)
|
|
3934
|
+
}
|
|
3935
|
+
static initOnlyValidFromArray(arr = []) {
|
|
3936
|
+
return initOnlyValidFromArray(this, arr)
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
get _classname() {
|
|
3940
|
+
return 'Status'
|
|
3941
|
+
}
|
|
3942
|
+
get _superclass() {
|
|
3943
|
+
return 'Status'
|
|
3944
|
+
}
|
|
3945
|
+
get isCreated() {
|
|
3946
|
+
return this.created?.timestamp !== null
|
|
3947
|
+
}
|
|
3948
|
+
get isValid() {
|
|
3949
|
+
return !!this
|
|
3950
|
+
}
|
|
3951
|
+
|
|
3952
|
+
setValue(t, actorCode, key) {
|
|
3953
|
+
const timestamp = t || Date.now()
|
|
3954
|
+
this[key] = this[key] instanceof this._ActionRecord ? this[key].update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
|
|
3955
|
+
return this
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
update(update) {
|
|
3959
|
+
Object.keys(update).forEach((key) => {
|
|
3960
|
+
if (!notUpdateAllowedProps.includes(key)) {
|
|
3961
|
+
this[key] = this[key] instanceof this._ActionRecord ? this[key].update(update[key]) : this._ActionRecord.init(update[key])
|
|
3962
|
+
}
|
|
3963
|
+
})
|
|
3964
|
+
return this
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
|
|
3968
|
+
;// ./lib/models/status/statusDocument.js
|
|
3969
|
+
|
|
3970
|
+
|
|
3971
|
+
class StatusDocument extends Status {
|
|
3972
|
+
constructor(options) {
|
|
3973
|
+
options = options || {}
|
|
3974
|
+
super(options)
|
|
3975
|
+
|
|
3976
|
+
this.archived = this._ActionRecord.init(options.archived)
|
|
3977
|
+
this.completed = this._ActionRecord.init(options.completed)
|
|
3978
|
+
this.discarded = this._ActionRecord.init(options.discarded)
|
|
3979
|
+
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3980
|
+
// this.statusType = 'StatusDocument'
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
static get _classname() {
|
|
3984
|
+
return 'StatusDocument'
|
|
3985
|
+
}
|
|
3986
|
+
get _classname() {
|
|
3987
|
+
return 'StatusDocument'
|
|
3988
|
+
}
|
|
3989
|
+
get isArchived() {
|
|
3990
|
+
return this.created?.timestamp !== null
|
|
3991
|
+
}
|
|
3992
|
+
get isCompleted() {
|
|
3993
|
+
return this.completed?.timestamp !== null
|
|
3994
|
+
}
|
|
3995
|
+
get isDiscarded() {
|
|
3996
|
+
return this.discarded?.timestamp !== null
|
|
3997
|
+
}
|
|
3998
|
+
get isDrafted() {
|
|
3999
|
+
return this.drafted?.timestamp !== null
|
|
4000
|
+
}
|
|
4001
|
+
get isValid() {
|
|
4002
|
+
return super.isValid
|
|
4003
|
+
}
|
|
4004
|
+
setArchived(value, actorCode) {
|
|
4005
|
+
// const timestamp = value || Date.now()
|
|
4006
|
+
// this.archived = this.archived instanceof this._ActionRecord ? this.archived.update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
|
|
4007
|
+
// return this
|
|
4008
|
+
return this.setValue(value, actorCode, 'archived')
|
|
4009
|
+
}
|
|
4010
|
+
setCompleted(value, actorCode) {
|
|
4011
|
+
return this.setValue(value, actorCode, 'completed')
|
|
4012
|
+
}
|
|
4013
|
+
setDiscarded(value, actorCode) {
|
|
4014
|
+
return this.setValue(value, actorCode, 'discarded')
|
|
4015
|
+
}
|
|
4016
|
+
setDrafted(value, actorCode) {
|
|
4017
|
+
return this.setValue(value, actorCode, 'drafted')
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
;// ./lib/models/status/index.js
|
|
4022
|
+
|
|
4023
|
+
|
|
4024
|
+
|
|
4025
|
+
|
|
3598
4026
|
;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
|
|
3599
4027
|
|
|
3600
4028
|
|
|
@@ -3735,6 +4163,7 @@ function _makeSetCode(fieldName, options) {
|
|
|
3735
4163
|
|
|
3736
4164
|
|
|
3737
4165
|
|
|
4166
|
+
|
|
3738
4167
|
;// ./lib/index.js
|
|
3739
4168
|
|
|
3740
4169
|
|