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