@questwork/q-utilities 0.1.13 → 0.1.15

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.
@@ -0,0 +1,3434 @@
1
+
2
+ ;// ./lib/helpers/authorize/authorize.js
3
+ function authorize({ allowOwner, query = {}, required, user }) {
4
+ if (!user) {
5
+ throw new Error('Require login.')
6
+ }
7
+ if (!user.permission) {
8
+ throw new Error('You do not have any permission.')
9
+ }
10
+ const scopes = user.permission.getScopes(required || {})
11
+ if (!scopes || scopes.length === 0) {
12
+ throw new Error('You are not allowed in this scope.')
13
+ }
14
+ if (!scopes.includes('*')) {
15
+ query.tenantCode = user.tenantCode
16
+ }
17
+ if (!scopes.includes('TENANT')) {
18
+ query.eventShortCode = user.eventShortCode
19
+ }
20
+ if (!scopes.includes('EVENT')) {
21
+ query.eventRegistrationCode = user.eventRegistrationCode
22
+ }
23
+ if (allowOwner) {
24
+ query.__ALLOW_OWNER = true
25
+ }
26
+ // not good, just use it as example
27
+ if (user.hasExcludedFields) {
28
+ query.__EXCLUDED_FIELDS = user.getExcludedFields(required)
29
+ }
30
+ query.__LOGIN_SUBJECT_CODE = user.loginSubjectCode
31
+ return query
32
+ }
33
+
34
+ ;// ./lib/helpers/authorize/index.js
35
+
36
+
37
+ ;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
38
+ function changeCreatorOwner(that, { source, target }) {
39
+ if (that.meta) {
40
+ if (!that.meta.creator || that.meta.creator === source.getId()) {
41
+ that.meta.creator = target.getId()
42
+ }
43
+ if (!that.meta.owner || that.meta.owner === source.getId()) {
44
+ that.meta.owner = target.getId()
45
+ }
46
+ } else {
47
+ if (!that.creator || that.creator === source.getId()) {
48
+ that.creator = target.getId()
49
+ }
50
+ if (!that.owner || that.owner === source.getId()) {
51
+ that.owner = target.getId()
52
+ }
53
+ }
54
+ return that
55
+ }
56
+
57
+ ;// ./lib/helpers/changeCreatorOwner/index.js
58
+
59
+
60
+ ;// ./lib/helpers/getValidation/getValidation.js
61
+ function getValidation(rule, data, getDataByKey, KeyValueObject) {
62
+ if (!rule) {
63
+ return true
64
+ }
65
+ if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
66
+ return false
67
+ }
68
+ const { key = '', value, placeholder, keyValuePath = '' } = rule
69
+ const [valueAttribute] = Object.keys(value)
70
+
71
+ if (!key && typeof placeholder === 'undefined') {
72
+ switch (valueAttribute) {
73
+ case '$and': {
74
+ return value['$and'].reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
75
+ }
76
+ case '$or': {
77
+ return value['$or'].reduce((acc, item) => (acc || getValidation(item, data, getDataByKey, KeyValueObject)), false)
78
+ }
79
+ default:
80
+ return false
81
+ }
82
+ }
83
+ let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
84
+
85
+ // if KeyValue object
86
+ if (keyValuePath) {
87
+ const rowValueData = KeyValueObject.toObject(rowValue)
88
+ rowValue = getDataByKey(keyValuePath, rowValueData)
89
+ }
90
+
91
+ switch (valueAttribute) {
92
+ case '$empty': {
93
+ const isEmpty = rowValue === null || rowValue === undefined
94
+ return isEmpty === value['$empty']
95
+ }
96
+ case '$eq': {
97
+ return rowValue === value['$eq']
98
+ }
99
+ case '$gt': {
100
+ return rowValue > value['$gt']
101
+ }
102
+ case '$gte': {
103
+ return rowValue >= value['$gte']
104
+ }
105
+ case '$hasOverlap': {
106
+ return _hasOverlap(rowValue, value['$hasOverlap'])
107
+ }
108
+ case '$lt': {
109
+ return rowValue < value['$lt']
110
+ }
111
+ case '$lte': {
112
+ return rowValue <= value['$lte']
113
+ }
114
+ case '$in': {
115
+ if (Array.isArray(rowValue)) {
116
+ return !!rowValue.find((e) => (value['$in'].includes(e)))
117
+ }
118
+ if (typeof rowValue !== 'object') {
119
+ return !!value['$in'].includes(rowValue)
120
+ }
121
+ return false
122
+ }
123
+ case '$inValue': {
124
+ const result = getDataByKey(value['$inValue'], data)
125
+ const _value = Array.isArray(result) ? result : []
126
+ if (Array.isArray(rowValue)) {
127
+ return !!rowValue.find((e) => (_value.includes(e)))
128
+ }
129
+ if (typeof rowValue === 'string') {
130
+ return !!_value.includes(rowValue)
131
+ }
132
+ return false
133
+ }
134
+ case '$ne': {
135
+ return rowValue !== value['$ne']
136
+ }
137
+ case '$notIn': {
138
+ if (Array.isArray(rowValue)) {
139
+ return !rowValue.find((e) => (value['$notIn'].includes(e)))
140
+ }
141
+ if (typeof rowValue !== 'object') {
142
+ return !value['$notIn'].includes(rowValue)
143
+ }
144
+ return false
145
+ }
146
+ case '$intervalTimeGt': {
147
+ const now = new Date().getTime()
148
+ const timestamp = new Date(rowValue).getTime()
149
+ return (now - timestamp) > value['$intervalTimeGt']
150
+ }
151
+ case '$intervalTimeLt': {
152
+ const now = new Date().getTime()
153
+ const timestamp = new Date(rowValue).getTime()
154
+ return (now - timestamp) < value['$intervalTimeLt']
155
+ }
156
+ case '$isToday': {
157
+ const currentDate = new Date()
158
+ const start = currentDate.setHours(0,0,0,0)
159
+ const end = currentDate.setHours(23,59,59,59)
160
+ const dateValue = new Date(rowValue).getTime()
161
+ return (start <= dateValue && end >= dateValue) === value['$isToday']
162
+ }
163
+ case '$notInValue': {
164
+ const result = getDataByKey(value['$notInValue'], data)
165
+ const _value = Array.isArray(result) ? result : []
166
+ if (Array.isArray(rowValue)) {
167
+ return !rowValue.find((e) => (_value.includes(e)))
168
+ }
169
+ if (typeof rowValue !== 'object') {
170
+ return !_value.includes(rowValue)
171
+ }
172
+ return false
173
+ }
174
+ case '$range': {
175
+ const [min, max] = value['$range']
176
+ if (typeof min === 'number' && typeof max === 'number' && rowValue >= min && rowValue <= max) {
177
+ return true
178
+ }
179
+ return false
180
+ }
181
+ default:
182
+ return false
183
+ }
184
+
185
+ }
186
+
187
+ function _hasOverlap(item1, item2) {
188
+ let arr1 = item1
189
+ let arr2 = item2
190
+ if (typeof arr1 === 'string') {
191
+ arr1 = arr1.split(',')
192
+ }
193
+ if (typeof arr2 === 'string') {
194
+ arr2 = arr2.split(',')
195
+ }
196
+ const set1 = new Set(arr1)
197
+ return arr2.find((i) => (set1.has(i)))
198
+ }
199
+
200
+ /* harmony default export */ const getValidation_getValidation = ({
201
+ getValidation
202
+ });
203
+
204
+
205
+ ;// ./lib/helpers/getValidation/index.js
206
+
207
+
208
+ ;// ./lib/helpers/formatDate/formatDate.js
209
+
210
+ function formatDate(date, format) {
211
+ const _date = date && date instanceof Date ? date : new Date(date)
212
+ const dayMapChi = ['日','一','二','三','四','五','六']
213
+ const dayMapEng = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
214
+ const dayMapEngShort = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
215
+ const _format = format || 'YYYY/MM/DD hh:mm'
216
+ const e = _date.getDay()
217
+ const ee = dayMapEngShort[e]
218
+ const eee = dayMapChi[e]
219
+ const eeee = dayMapEng[e]
220
+ const y = _date.getFullYear()
221
+ const m = _date.getMonth() + 1
222
+ const d = _date.getDate()
223
+ const h = _date.getHours()
224
+ const mm = _date.getMinutes()
225
+ const s = _date.getSeconds()
226
+
227
+ return _format.replace('YYYY', y)
228
+ .replace('MM', padding(m))
229
+ .replace('MM', padding(m))
230
+ .replace('DD', padding(d))
231
+ .replace('hh', padding(h))
232
+ .replace('mm', padding(mm))
233
+ .replace('ss', padding(s))
234
+ .replace('M', m)
235
+ .replace('D', d)
236
+ .replace('h', h)
237
+ .replace('m', mm)
238
+ .replace('s', s)
239
+ .replace('EEEE', padding(eeee))
240
+ .replace('EEE', padding(eee))
241
+ .replace('EE', padding(ee))
242
+ .replace('E', padding(e))
243
+ }
244
+
245
+ function padding(m) {
246
+ return m < 10 ? `0${m}` : m
247
+ }
248
+
249
+
250
+ /* harmony default export */ const formatDate_formatDate = ({
251
+ formatDate
252
+ });
253
+
254
+
255
+
256
+ ;// ./lib/helpers/formatDate/index.js
257
+
258
+
259
+ ;// ./lib/helpers/getValueByKeys/getValueByKeys.js
260
+ // keys can be array or object or string
261
+ function getValueByKeys_getValueByKeys(keys, data) {
262
+ let _keys = keys
263
+ let _data = data
264
+ if (typeof keys === 'string') {
265
+ _keys = _keys.split('.')
266
+ }
267
+ if (!Array.isArray(keys) && typeof keys === 'object') {
268
+ const { keys: keyArr, obj } = keys
269
+ _keys = keyArr
270
+ _data = obj
271
+ }
272
+ if (_keys.length === 0) {
273
+ return _data
274
+ }
275
+ const firstKey = _keys.shift()
276
+ if (_data && Object.prototype.hasOwnProperty.call(_data, firstKey)) {
277
+ return getValueByKeys_getValueByKeys(_keys, _data[firstKey])
278
+ }
279
+ if (_data && firstKey) {
280
+ return _data[firstKey]
281
+ }
282
+ return _data
283
+
284
+ }
285
+ /* harmony default export */ const getValueByKeys = ({
286
+ getValueByKeys: getValueByKeys_getValueByKeys
287
+ });
288
+
289
+
290
+ ;// ./lib/helpers/getValueByKeys/index.js
291
+
292
+
293
+ ;// ./lib/models/templateCompiler/templateCompilerException.js
294
+ const TEMPLATE_COMPILER_EXCEPTION_TYPE = {
295
+ argumentEmptyException: 'Argument is empty',
296
+ argumentFormatException: 'Incorrect number or format of argument',
297
+ invalidFuntionException: 'Function Name is invalid',
298
+ invalidRegExpException: 'Invalid regular expression',
299
+ isNotAFunctionException: 'Is not a function',
300
+ notExistException: 'Key does not exist',
301
+ resultEmptyException: 'Result is empty',
302
+ resultMoreThanOneException: 'More than one result'
303
+ }
304
+
305
+ class TemplateCompilerException extends Error {
306
+ constructor(message) {
307
+ super(message)
308
+ this.message = message
309
+ }
310
+ }
311
+
312
+
313
+
314
+ ;// ./lib/models/templateCompiler/constants.js
315
+ const _EMPTY = '_EMPTY'
316
+ const _FN_NAMES = [
317
+ 'concatIf',
318
+ 'divide',
319
+ 'eq',
320
+ 'exec',
321
+ 'filterAll',
322
+ 'filterOne',
323
+ 'formatDate',
324
+ 'get',
325
+ 'gt',
326
+ 'gte',
327
+ 'isEmpty',
328
+ 'isNotEmpty',
329
+ 'join',
330
+ 'lt',
331
+ 'lte',
332
+ 'map',
333
+ 'neq',
334
+ 'removeHtml',
335
+ 'toLowerCase',
336
+ 'toUpperCase',
337
+ ]
338
+ const _HIDE = '_HIDE'
339
+ const _NOT_EMPTY = '_NOT_EMPTY'
340
+ const _SELF = '_SELF'
341
+ const TAGS_EJS = ['<%=', '%>']
342
+ const TAGS_HANDLEBAR = ['{{', '}}']
343
+
344
+
345
+
346
+ ;// ./lib/models/templateCompiler/helpers/_concatIf.js
347
+
348
+
349
+
350
+
351
+ function _concatIf(data, args) {
352
+ if (typeof data !== 'string') {
353
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string :${data.join(', ')}`)
354
+ }
355
+ if (args.length !== 3) {
356
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
357
+ }
358
+ if (data === null || (typeof data === 'undefined')) {
359
+ return null
360
+ }
361
+ const [condition, success, failover] = args
362
+ const validConditions = [_EMPTY, _NOT_EMPTY]
363
+ if (validConditions.includes(condition) || success.length !== 2) {
364
+ throw new TemplateCompilerException(`concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException}: ${condition}, ${success}`)
365
+ }
366
+ if (data === '' && failover.includes(_HIDE)) {
367
+ return ''
368
+ }
369
+ if (data !== '' && (data !== null || data !== undefined) && failover.includes(_HIDE)) {
370
+ return `${success[0]}${data}${success[success.length - 1]}`
371
+ }
372
+ return failover
373
+ }
374
+
375
+
376
+
377
+ ;// ./lib/models/templateCompiler/helpers/_divide.js
378
+ function _divide(value, divisor) {
379
+ try {
380
+ if (Number.isNaN(value)) {
381
+ return value
382
+ }
383
+ return (value / divisor)
384
+ } catch (e) {
385
+ throw e
386
+ }
387
+ }
388
+
389
+
390
+
391
+ ;// ./lib/models/templateCompiler/helpers/_eq.js
392
+
393
+
394
+
395
+
396
+ function _eq(data, args) {
397
+ if (args.length !== 3) {
398
+ throw new TemplateCompilerException(`eq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
399
+ }
400
+ if (data === null || (typeof data === 'undefined')) {
401
+ return null
402
+ }
403
+ if (args.includes(_SELF)) {
404
+ args = args.map((arg) => {
405
+ return (arg === _SELF) ? data : arg
406
+ })
407
+ }
408
+ const expected = args[0]
409
+ return data === expected ? args[1] : args[2]
410
+ }
411
+
412
+
413
+
414
+ ;// ./lib/models/templateCompiler/helpers/_exec.js
415
+ function _exec(data, args) {
416
+ try {
417
+ const [methodName, ..._args] = args
418
+ return data[methodName](..._args)
419
+ } catch (e) {
420
+ throw e
421
+ }
422
+ }
423
+
424
+
425
+
426
+ ;// ./lib/models/templateCompiler/helpers/_filterAll.js
427
+
428
+
429
+
430
+ // const DELIMITER = '~~~'
431
+
432
+ function _filterAll(data, args) {
433
+ try {
434
+ if (!Array.isArray(args) || args.length === 0) {
435
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
436
+ }
437
+ if (!Array.isArray(data) || data.length === 0) {
438
+ return []
439
+ }
440
+ if (typeof data[0] === 'object') {
441
+ return _existObject(data, args)
442
+ }
443
+ if (typeof data[0] === 'string' || typeof data[0] === 'number') {
444
+ return _exist(data, args)
445
+ }
446
+ return []
447
+ } catch (e) {
448
+ throw e
449
+ }
450
+ }
451
+
452
+ function _exist(data, args) {
453
+ const _args = args.flat()
454
+ return data.filter((e) => _args.some((arg) => _performOperation(arg, e)))
455
+ }
456
+
457
+ function _existObject(data, args) {
458
+ if (args.length === 1) {
459
+ const arg = args[0]
460
+ return data.filter((e) => {
461
+ if (arg.includes('.')) {
462
+ return getValueByKeys_getValueByKeys(arg.split('.'), e)
463
+ }
464
+ return Object.prototype.hasOwnProperty.call(e, arg)
465
+ })
466
+ }
467
+
468
+ if (args.length > 2) {
469
+ let res = data
470
+ for (let i = 0; i < args.length; i += 2) {
471
+ const group = [args[i], args[i + 1]]
472
+ res = _existObject(res, group)
473
+ }
474
+ return res
475
+ }
476
+
477
+ const [key, ..._argsArr] = args
478
+ const _args = _argsArr.flat()
479
+ return data.filter((e) => {
480
+ const value = key.includes('.') ? getValueByKeys_getValueByKeys(key.split('.'), e) : e[key]
481
+ return _args.some((arg) => _performOperation(arg, value))
482
+ })
483
+ }
484
+
485
+ function _performOperation(arg, value) {
486
+ // the arg is undefined
487
+ if (arg === undefined && value === undefined) return true
488
+
489
+ // the arg is null
490
+ if (arg === null && value === null) return true
491
+
492
+ // the arg is boolean
493
+ if (typeof arg === 'boolean') {
494
+ return arg === value
495
+ }
496
+
497
+ // the arg is blank or *: Blank => Empty, * => Not Empty
498
+ if (arg === '' || arg === '*') {
499
+ // null and undefined are not included in either case
500
+ if (value === null || value === undefined) {
501
+ return false
502
+ }
503
+ if (typeof value === 'string') {
504
+ return arg === '' ? value === '' : value !== ''
505
+ }
506
+ if (Array.isArray(value)) {
507
+ return arg === '' ? value.length === 0 : value.length !== 0
508
+ }
509
+ return arg !== ''
510
+ }
511
+
512
+ // the arg is alphabetic or number
513
+ if (_isPureStringOrNumber(arg)) {
514
+ return arg === value
515
+ }
516
+
517
+ // the arg is array of [] or [*]: [] => Empty, [*] => Not Empty
518
+ if (arg.startsWith('[') && arg.endsWith(']')) {
519
+ if (arg === '[]') {
520
+ return Array.isArray(value) && value.length === 0
521
+ }
522
+ if (arg === '[*]') {
523
+ return Array.isArray(value) && value.length !== 0
524
+ }
525
+ return false
526
+ }
527
+
528
+ // the arg is 'operator + string | number'
529
+ const { operator, value: argValue } = _splitOperator(arg)
530
+ if (!operator || (argValue !== 0 && !argValue)) {
531
+ return false
532
+ }
533
+ switch (operator) {
534
+ case '>':
535
+ return value > argValue
536
+ case '<':
537
+ return value < argValue
538
+ case '!=':
539
+ return value !== argValue
540
+ case '>=':
541
+ return value >= argValue
542
+ case '<=':
543
+ return value <= argValue
544
+ default:
545
+ return false
546
+ }
547
+ }
548
+
549
+ function _isPureStringOrNumber(input) {
550
+ if (typeof input === 'string') {
551
+ if (input.startsWith('[') && input.endsWith(']')) {
552
+ return false
553
+ }
554
+ if (/!=|>=|<=|>|</.test(input)) {
555
+ return false
556
+ }
557
+ return true
558
+ }
559
+ return !Number.isNaN(input)
560
+ }
561
+
562
+ function _splitOperator(str) {
563
+ const operators = ['!=', '>=', '<=', '>', '<']
564
+
565
+ const matchedOp = operators.find((op) => str.startsWith(op))
566
+ if (!matchedOp) return { operator: null, value: null }
567
+
568
+ const remaining = str.slice(matchedOp.length)
569
+
570
+ // '>Primary' or '<Primary' is invalid
571
+ if (/^[a-zA-Z]*$/.test(remaining) && matchedOp !== '!=') {
572
+ return { operator: null, value: null }
573
+ }
574
+
575
+ // if it is a number it is converted to a number
576
+ const value = (!Number.isNaN(parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
577
+
578
+ return {
579
+ operator: matchedOp,
580
+ value
581
+ }
582
+ }
583
+
584
+
585
+
586
+ ;// ./lib/models/templateCompiler/helpers/_filterOne.js
587
+
588
+
589
+
590
+ function _filterOne(data, args) {
591
+ try {
592
+ const list = _filterAll(data, args)
593
+ if (list.length === 1) {
594
+ return list[0]
595
+ }
596
+ if (list.length === 0) {
597
+ return null
598
+ }
599
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.resultMoreThanOneException)
600
+ } catch (e) {
601
+ throw e
602
+ }
603
+ }
604
+
605
+
606
+
607
+ ;// ./lib/models/templateCompiler/helpers/_formatDate.js
608
+
609
+
610
+ function _formatDate(timestamp, format) {
611
+ if (format.length === 0) {
612
+ throw new TemplateCompilerException(`_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: format parts must be not empty array`)
613
+ }
614
+
615
+ if (timestamp === null || timestamp === undefined) {
616
+ return null
617
+ }
618
+
619
+ const date = new Date(timestamp)
620
+
621
+ const partsMap = {
622
+ yyyy: String(date.getFullYear()),
623
+ mm: String(date.getMonth() + 1).padStart(2, '0'),
624
+ dd: String(date.getDate()).padStart(2, '0')
625
+ }
626
+
627
+ // Check for invalid format tokens
628
+ const validTokens = ['yyyy', 'mm', 'dd']
629
+ const invalidTokens = format.filter((part) => part.length > 1 && !validTokens.includes(part))
630
+
631
+ if (invalidTokens.length > 0) {
632
+ throw new TemplateCompilerException(
633
+ `_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the format type is not valid: ${format.join(', ')}`
634
+ )
635
+ }
636
+
637
+ // Build the formatted string using reduce
638
+ return format.reduce((result, part) => result + (partsMap[part] || part), '')
639
+ }
640
+
641
+
642
+
643
+ ;// ./lib/models/templateCompiler/helpers/_get.js
644
+
645
+
646
+ function _get(data, key, failover = null) {
647
+ try {
648
+ if (key === null || (typeof key === 'undefined') || key === '') {
649
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
650
+ }
651
+ if (data === null) {
652
+ return null
653
+ }
654
+ if (key.includes('.')) {
655
+ const parts = key.split('.')
656
+ if (parts.length > 1) {
657
+ const first = parts.shift()
658
+ const remainingKey = parts.join('.')
659
+ if (typeof data[first] !== 'undefined') {
660
+ return _get(data[first], remainingKey, failover)
661
+ }
662
+ return _handleFailover(key, failover)
663
+ }
664
+ }
665
+ if (typeof data[key] !== 'undefined') {
666
+ return data[key]
667
+ }
668
+ return _handleFailover(key, failover)
669
+ } catch (e) {
670
+ throw e
671
+ }
672
+ }
673
+
674
+ function _handleFailover(key, failover) {
675
+ if (failover !== null) {
676
+ return failover
677
+ }
678
+ return null
679
+ // throw new TemplateCompilerException(`Key "${key}" does not exist and no failover`)
680
+ }
681
+
682
+
683
+
684
+ ;// ./lib/models/templateCompiler/helpers/_gt.js
685
+
686
+
687
+
688
+
689
+ function _gt(data, args) {
690
+ if (args.length !== 3) {
691
+ throw new TemplateCompilerException(`_gt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
692
+ }
693
+ if (data === null || (typeof data === 'undefined')) {
694
+ return null
695
+ }
696
+ if (args.includes(_SELF)) {
697
+ args = args.map((arg) => {
698
+ return (arg === _SELF) ? data : arg
699
+ })
700
+ }
701
+ const expected = args[0]
702
+ return data > expected ? args[1] : args[2]
703
+ }
704
+
705
+
706
+
707
+ ;// ./lib/models/templateCompiler/helpers/_gte.js
708
+
709
+
710
+
711
+
712
+ function _gte(data, args) {
713
+ if (args.length !== 3) {
714
+ throw new TemplateCompilerException(`_gte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
715
+ }
716
+ if (data === null || (typeof data === 'undefined')) {
717
+ return null
718
+ }
719
+ if (args.includes(_SELF)) {
720
+ args = args.map((arg) => {
721
+ return (arg === _SELF) ? data : arg
722
+ })
723
+ }
724
+ const expected = args[0]
725
+ return data >= expected ? args[1] : args[2]
726
+ }
727
+
728
+
729
+
730
+ ;// ./lib/models/templateCompiler/helpers/_isEmpty.js
731
+
732
+
733
+
734
+
735
+ function _isEmpty(data, args) {
736
+ if (args.length !== 2) {
737
+ throw new TemplateCompilerException(`_isEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
738
+ }
739
+ // if (data === null || (typeof data === 'undefined')) {
740
+ // return null
741
+ // }
742
+ if (args.includes(_SELF)) {
743
+ args = args.map((arg) => {
744
+ return (arg === _SELF) ? data : arg
745
+ })
746
+ }
747
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
748
+ return args[0]
749
+ }
750
+ return (data === '' || data === null || data === undefined || data.length === 0) ? args[0] : args[1]
751
+ }
752
+
753
+
754
+
755
+ ;// ./lib/models/templateCompiler/helpers/_isNotEmpty.js
756
+
757
+
758
+
759
+
760
+ function _isNotEmpty(data, args) {
761
+ if (args.length !== 2) {
762
+ throw new TemplateCompilerException(`_isNotEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
763
+ }
764
+ // if (data === null || (typeof data === 'undefined')) {
765
+ // return null
766
+ // }
767
+ if (args.includes(_SELF)) {
768
+ args = args.map((arg) => {
769
+ return (arg === _SELF) ? data : arg
770
+ })
771
+ }
772
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
773
+ return args[1]
774
+ }
775
+ if (Array.isArray(data) && data.length === 0) {
776
+ return args[1]
777
+ }
778
+ if (typeof data === 'string' && data === '') {
779
+ return args[1]
780
+ }
781
+ if (data === null || data === undefined) {
782
+ return args[1]
783
+ }
784
+ return args[0]
785
+ }
786
+
787
+
788
+ ;// ./lib/models/templateCompiler/helpers/_join.js
789
+ function _join(data, delimiter) {
790
+ try {
791
+ if (data.length === 0) return ''
792
+ if (data.length === 1) return _stringifyObject(data[0])
793
+ return data.map((item) => _stringifyObject(item)).join(delimiter)
794
+ } catch (e) {
795
+ throw e
796
+ }
797
+ }
798
+
799
+ function _stringifyObject(obj) {
800
+ return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1: ').replace(/"([^"]+)"/g, '$1').replace(/,/g, ', ')
801
+ }
802
+
803
+
804
+
805
+ ;// ./lib/models/templateCompiler/helpers/_lt.js
806
+
807
+
808
+
809
+
810
+ function _lt(data, args) {
811
+ if (args.length !== 3) {
812
+ throw new TemplateCompilerException(`_lt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
813
+ }
814
+ if (data === null || (typeof data === 'undefined')) {
815
+ return null
816
+ }
817
+ if (args.includes(_SELF)) {
818
+ args = args.map((arg) => {
819
+ return (arg === _SELF) ? data : arg
820
+ })
821
+ }
822
+ const expected = args[0]
823
+ return data < expected ? args[1] : args[2]
824
+ }
825
+
826
+
827
+
828
+ ;// ./lib/models/templateCompiler/helpers/_lte.js
829
+
830
+
831
+
832
+
833
+ function _lte(data, args) {
834
+ if (args.length !== 3) {
835
+ throw new TemplateCompilerException(`_lte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
836
+ }
837
+ if (data === null || (typeof data === 'undefined')) {
838
+ return null
839
+ }
840
+ if (args.includes(_SELF)) {
841
+ args = args.map((arg) => {
842
+ return (arg === _SELF) ? data : arg
843
+ })
844
+ }
845
+ const expected = args[0]
846
+ return data <= expected ? args[1] : args[2]
847
+ }
848
+
849
+
850
+
851
+ ;// ./lib/models/templateCompiler/helpers/_map.js
852
+
853
+
854
+
855
+ function _map(data, args) {
856
+ try {
857
+ if (args.length === 0) {
858
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
859
+ }
860
+ if (data === null || (typeof data === 'undefined')) {
861
+ return null
862
+ }
863
+
864
+ const result = data.reduce((acc, item) => {
865
+ if (args.length === 1 && Array.isArray(args[0])) {
866
+ args = args[0]
867
+ acc.hasFormat = true
868
+ }
869
+ const list = args.map((key) => {
870
+ if (key.includes('.')) {
871
+ const parts = key.split('.')
872
+ const first = parts[0]
873
+ parts.shift()
874
+ const remainingKey = parts.join('.')
875
+ return _get(item[first], remainingKey)
876
+ }
877
+ if (typeof item[key] !== 'undefined') {
878
+ return item[key]
879
+ }
880
+ return null
881
+ })
882
+ if (acc.hasFormat) {
883
+ acc.content.push(list)
884
+ } else {
885
+ acc.content = acc.content.concat(list)
886
+ }
887
+ return acc
888
+ }, {
889
+ content: [],
890
+ hasFormat: false
891
+ })
892
+ return result.content
893
+ } catch (e) {
894
+ throw e
895
+ }
896
+ }
897
+
898
+
899
+
900
+ ;// ./lib/models/templateCompiler/helpers/_neq.js
901
+
902
+
903
+
904
+
905
+ function _neq(data, args) {
906
+ if (args.length !== 3) {
907
+ throw new TemplateCompilerException(`_neq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
908
+ }
909
+ if (data === null || (typeof data === 'undefined')) {
910
+ return null
911
+ }
912
+ if (args.includes(_SELF)) {
913
+ args = args.map((arg) => {
914
+ return (arg === _SELF) ? data : arg
915
+ })
916
+ }
917
+ const expected = args[0]
918
+ return data !== expected ? args[1] : args[2]
919
+ }
920
+
921
+
922
+
923
+ ;// ./lib/models/templateCompiler/helpers/_removeHtml.js
924
+
925
+
926
+ function _removeHtml(html, args) {
927
+ if (html === null || html === undefined) {
928
+ return null
929
+ }
930
+ if (!Array.isArray(args)) {
931
+ throw new TemplateCompilerException(`_removeHtml: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: args parts must be array`)
932
+ }
933
+
934
+ return _htmlToPlainText(html, args[0])
935
+ }
936
+
937
+ function _htmlToPlainText(html, delimiter = '\n') {
938
+ if (typeof delimiter !== 'string') {
939
+ delimiter = '\n'; // Fallback to default if not a string
940
+ }
941
+
942
+ // First decode HTML entities and normalize whitespace
943
+ const decodedHtml = html
944
+ .replace(/&nbsp;/g, ' ')
945
+ .replace(/\s+/g, ' '); // Collapse all whitespace to single spaces
946
+
947
+ // Process HTML tags
948
+ let text = decodedHtml
949
+ // Replace block tags with temporary marker (~~~)
950
+ .replace(/<\/?(p|div|h[1-6]|ul|ol|li|pre|section|article|table|tr|td|th)(\s[^>]*)?>/gi, '~~~')
951
+ // Replace <br> tags with temporary marker (~~~)
952
+ .replace(/<br\s*\/?>/gi, '~~~')
953
+ // Remove all other tags
954
+ .replace(/<[^>]+>/g, '')
955
+ // Convert markers to specified delimiter
956
+ .replace(/~~~+/g, delimiter)
957
+ // Trim and clean whitespace
958
+ .trim();
959
+
960
+ // Special handling for empty delimiter
961
+ if (delimiter === '') {
962
+ // Collapse all whitespace to single space
963
+ text = text.replace(/\s+/g, ' ');
964
+ } else {
965
+
966
+
967
+ // Collapse multiple delimiters to single
968
+ text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter);
969
+ // Remove leading/trailing delimiters
970
+ text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '');
971
+ }
972
+
973
+ return text;
974
+ }
975
+
976
+
977
+ function escapeRegExp(string) {
978
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
979
+ }
980
+
981
+
982
+
983
+ ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
984
+
985
+
986
+ function _toLowerCase(data, args) {
987
+ if (args !== undefined) {
988
+ throw new TemplateCompilerException(`_toLowerCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
989
+ }
990
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
991
+ return null
992
+ }
993
+ return String(data).toLowerCase()
994
+ }
995
+
996
+
997
+
998
+ ;// ./lib/models/templateCompiler/helpers/_toUpperCase.js
999
+
1000
+
1001
+ function _toUpperCase(data, args) {
1002
+ if (typeof data !== 'string') {
1003
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string: ${data}`)
1004
+ }
1005
+ if (args !== undefined) {
1006
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the argument must be empty: ${args.join(', ')}`)
1007
+ }
1008
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
1009
+ return null
1010
+ }
1011
+ return String(data).toUpperCase()
1012
+ }
1013
+
1014
+
1015
+
1016
+ ;// ./lib/models/templateCompiler/helpers/index.js
1017
+
1018
+
1019
+
1020
+
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+
1037
+
1038
+
1039
+
1040
+ ;// ./lib/models/templateCompiler/templateCompiler.js
1041
+
1042
+
1043
+
1044
+
1045
+ class TemplateCompiler {
1046
+ constructor(data) {
1047
+ this.data = data
1048
+ }
1049
+ static init(options) {
1050
+ return new this(options)
1051
+ }
1052
+ static initFromArray(arr = []) {
1053
+ if (Array.isArray(arr)) {
1054
+ return arr.map((a) => this.init(a))
1055
+ }
1056
+ return []
1057
+ }
1058
+ static initOnlyValidFromArray(arr = []) {
1059
+ return this.initFromArray(arr).filter((i) => i)
1060
+ }
1061
+ static concatIf(data, args) {
1062
+ return _concatIf(data, args)
1063
+ }
1064
+ static divide(data, args) {
1065
+ return _divide(data, args)
1066
+ }
1067
+ static eq(data, args) {
1068
+ return _eq(data, args)
1069
+ }
1070
+
1071
+ static filterAll(data, args) {
1072
+ return _filterAll(data, args)
1073
+ }
1074
+
1075
+ static formatDate(data, args) {
1076
+ return _formatDate(data, args)
1077
+ }
1078
+ static get(data, key, failover = null) {
1079
+ return _get(data, key, failover)
1080
+ }
1081
+ static gt(data, args) {
1082
+ return _gt(data, args)
1083
+ }
1084
+ static gte(data, args) {
1085
+ return _gte(data, args)
1086
+ }
1087
+ static isEmpty(data, args) {
1088
+ return _isEmpty(data, args)
1089
+ }
1090
+ static isNotEmpty(data, args) {
1091
+ return _isNotEmpty(data, args)
1092
+ }
1093
+ static join(data, separator = '') {
1094
+ return _join(data, separator)
1095
+ }
1096
+ static lt(data, args) {
1097
+ return _lt(data, args)
1098
+ }
1099
+ static lte(data, args) {
1100
+ return _lte(data, args)
1101
+ }
1102
+ static map(data, args = []) {
1103
+ return _map(data, args)
1104
+ }
1105
+ static neq(data, args) {
1106
+ return _neq(data, args)
1107
+ }
1108
+ static removeHtml(data, args) {
1109
+ return _removeHtml(data, args)
1110
+ }
1111
+ static toLowerCase(data, args) {
1112
+ return _toLowerCase(data, args)
1113
+ }
1114
+ static toUpperCase(data, args) {
1115
+ return _toUpperCase(data, args)
1116
+ }
1117
+ static parseFunction(expression) {
1118
+ return _parseFunction(expression, _FN_NAMES)
1119
+ }
1120
+ static parseParams(parameters) {
1121
+ return _parseParams(parameters)
1122
+ }
1123
+
1124
+ pipe(expression = '') {
1125
+ this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
1126
+ const regex = new RegExp(`${this.delimiters[0]}\\s(.*?)\\s${this.delimiters[1]}`)
1127
+ const match = expression.match(regex)
1128
+ if (match !== null) {
1129
+ try {
1130
+ const functionList = _parseFunction(match[1], _FN_NAMES)
1131
+ return functionList.reduce((acc, fn) => {
1132
+ return _callFunction(acc, fn.name, fn.args)
1133
+ }, this.data)
1134
+ } catch (e) {
1135
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${e.message}`)
1136
+ }
1137
+ }
1138
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.invalidRegExpException}`)
1139
+ }
1140
+ }
1141
+
1142
+ function _parseFunction(expression, existFunctionNames) {
1143
+ const regExp = new RegExp(/(\w+)\(([^)]*)\)/)
1144
+ let parts
1145
+ if (expression.includes('|')) {
1146
+ parts = expression.split('|')
1147
+ } else {
1148
+ parts = [expression]
1149
+ }
1150
+ return parts.reduce((acc, part) => {
1151
+ const match = part.match(regExp)
1152
+ if (match !== null) {
1153
+ const functionName = match[1]
1154
+ const parameters = match[2]
1155
+ const paramList = _parseParams(parameters)
1156
+ if (existFunctionNames.includes(functionName)) {
1157
+ acc.push({
1158
+ name: functionName,
1159
+ args: paramList
1160
+ })
1161
+ } else {
1162
+ throw new TemplateCompilerException(`${functionName} is not a valid function`)
1163
+ }
1164
+ }
1165
+ return acc
1166
+ }, [])
1167
+ }
1168
+
1169
+ function _parseParams(parameters) {
1170
+ const _parameters = parameters.trim()
1171
+ const regExp = new RegExp(/^[^\w\d\s]+$/)
1172
+ const match = _parameters.match(regExp)
1173
+ if (match !== null) {
1174
+ return [_parameters.substring(1, _parameters.length - 1)]
1175
+ }
1176
+ if (_parameters.includes(',')) {
1177
+ // 用正则表达式匹配逗号,但忽略方括号中的逗号
1178
+ const parts = _splitIgnoringBrackets(_parameters)
1179
+ return parts.map((part) => _parseSinglePart(part))
1180
+ }
1181
+ return [_parseSinglePart(_parameters)]
1182
+ }
1183
+
1184
+ function _splitIgnoringBrackets(input) {
1185
+ const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
1186
+ const regExp = new RegExp(/(?![^\[]*\])\s*,\s*/)
1187
+ const parts = input.split(regExp)
1188
+ return parts.map((part) => {
1189
+ const _part = part.trim()
1190
+ if (_part !== '' && !!_part.match(regExp2)) {
1191
+ // 如果是数字,转换为 num 类型
1192
+ return Number.isNaN(_part) ? _part : parseInt(_part, 10)
1193
+ }
1194
+ // 否则当作字符串处理
1195
+ return _part
1196
+ })
1197
+ }
1198
+
1199
+ function _parseSinglePart(input) {
1200
+ if (typeof input === 'string') {
1201
+ if (input.startsWith('"') && input.endsWith('"')) {
1202
+ // 去掉双引号,返回
1203
+ return input.substring(1, input.length - 1)
1204
+ }
1205
+ if (input.startsWith("'") && input.endsWith("'")) {
1206
+ // 去掉双引号,返回
1207
+ return input.substring(1, input.length - 1)
1208
+ }
1209
+
1210
+ const _input = _toBasicType(input)
1211
+
1212
+ if (typeof _input !== 'string') {
1213
+ return _input
1214
+ }
1215
+
1216
+ // 如果是一个列表形式(例如 ["p", "d"] 或 [p, d])
1217
+ if (_input.startsWith('[') && _input.endsWith(']')) {
1218
+ const listContent = _input.substring(1, _input.length - 1).trim()
1219
+ if (listContent !== '') {
1220
+ return listContent.split(',').map((item) => {
1221
+ return _toBasicType(item.trim())
1222
+ })
1223
+ }
1224
+ return []
1225
+ }
1226
+ return input
1227
+ }
1228
+ return input
1229
+ }
1230
+
1231
+ function _toBasicType(input) {
1232
+ if (input.startsWith('"') && input.endsWith('"')) {
1233
+ // 去掉双引号,返回
1234
+ return input.substring(1, input.length - 1)
1235
+ }
1236
+ if (input.startsWith("'") && input.endsWith("'")) {
1237
+ // 去掉双引号,返回
1238
+ return input.substring(1, input.length - 1)
1239
+ }
1240
+ if (input === 'true') {
1241
+ return true
1242
+ }
1243
+ if (input === 'false') {
1244
+ return false
1245
+ }
1246
+ if (input === 'undefined') {
1247
+ return undefined
1248
+ }
1249
+ if (input === 'null') {
1250
+ return null
1251
+ }
1252
+ if (!Number.isNaN(input) && !Number.isNaN(Number.parseFloat(input))) {
1253
+ return Number(input)
1254
+ }
1255
+ return input
1256
+ }
1257
+
1258
+ function _callFunction(data, functionName, parameters) {
1259
+ try {
1260
+ let failover
1261
+ switch (functionName) {
1262
+ case 'concatIf':
1263
+ return _concatIf(data, parameters)
1264
+ case 'divide':
1265
+ return _divide(data, parameters)
1266
+ case 'eq':
1267
+ return _eq(data, parameters)
1268
+ case 'exec':
1269
+ return _exec(data, parameters)
1270
+ case 'filterAll':
1271
+ return _filterAll(data, parameters)
1272
+ case 'filterOne':
1273
+ return _filterOne(data, parameters)
1274
+ case 'formatDate':
1275
+ return _formatDate(data, parameters)
1276
+ case 'get':
1277
+ if (parameters.length > 2) {
1278
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
1279
+ }
1280
+ if (parameters.length === 2) {
1281
+ failover = parameters[parameters.length - 1]
1282
+ }
1283
+ return _get(data, parameters[0], failover)
1284
+ case 'gt':
1285
+ return _gt(data, parameters)
1286
+ case 'gte':
1287
+ return _gte(data, parameters)
1288
+ case 'isEmpty':
1289
+ return _isEmpty(data, parameters)
1290
+ case 'isNotEmpty':
1291
+ return _isNotEmpty(data, parameters)
1292
+ case 'join':
1293
+ return _join(data, parameters[0])
1294
+ case 'lt':
1295
+ return _lt(data, parameters)
1296
+ case 'lte':
1297
+ return _lte(data, parameters)
1298
+ case 'map':
1299
+ return _map(data, parameters)
1300
+ case 'neq':
1301
+ return _neq(data, parameters)
1302
+ case 'removeHtml':
1303
+ return _removeHtml(data, parameters)
1304
+ case 'toLowerCase':
1305
+ return _toLowerCase(data)
1306
+ case 'toUpperCase':
1307
+ return _toUpperCase(data)
1308
+ default:
1309
+ throw new Error(`${functionName} is not a valid function`)
1310
+ }
1311
+ } catch (e) {
1312
+ throw e
1313
+ }
1314
+ }
1315
+
1316
+
1317
+
1318
+ ;// ./lib/models/templateCompiler/index.js
1319
+
1320
+
1321
+
1322
+
1323
+ ;// ./lib/helpers/concatStringByArray/concatStringByArray.js
1324
+
1325
+
1326
+
1327
+
1328
+
1329
+ function concatStringByArray(arrTemplate, data) {
1330
+ return arrTemplate.reduce((acc, item) => {
1331
+ const { type, value = '', restriction, template, format, showMinutes } = item
1332
+ switch (type) {
1333
+ case('label'): {
1334
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1335
+ acc += (value.toString())
1336
+ }
1337
+ break
1338
+ }
1339
+ case('value'): {
1340
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1341
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1342
+ acc += (_value.toString())
1343
+ }
1344
+ break
1345
+ }
1346
+ case('array'): {
1347
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1348
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || []
1349
+ acc += _value.reduce((_acc, item) => {
1350
+ return _acc += concatStringByArray(template, item)
1351
+ }, '')
1352
+ }
1353
+ break
1354
+ }
1355
+ case('ellipsis'): {
1356
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1357
+ const { maxLength } = item
1358
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1359
+ if (_value.length <= maxLength) {
1360
+ acc += (_value.toString())
1361
+ } else {
1362
+ acc += `${_value.substr(0, maxLength)}...`
1363
+ }
1364
+ }
1365
+ break
1366
+ }
1367
+ case ('date'): {
1368
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1369
+ const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
1370
+ acc += (formatDate(_value, format).toString())
1371
+ }
1372
+ break
1373
+ }
1374
+ case ('templateCompiler'): {
1375
+ if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
1376
+ const templateCompiler = new TemplateCompiler({ data })
1377
+ acc += templateCompiler.pipe(value)
1378
+ }
1379
+ break
1380
+ }
1381
+ }
1382
+ return acc
1383
+ }, '')
1384
+ }
1385
+ /* harmony default export */ const concatStringByArray_concatStringByArray = ({
1386
+ concatStringByArray
1387
+ });
1388
+
1389
+
1390
+
1391
+ ;// ./lib/helpers/concatStringByArray/index.js
1392
+
1393
+
1394
+ ;// ./lib/helpers/convertString/convertString.js
1395
+
1396
+
1397
+ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByKeys) {
1398
+ if (!string) {
1399
+ return ''
1400
+ }
1401
+ let _getValueByKeys = typeof getValueByKeys !== 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
1402
+ const reg = new RegExp(patternMatch, 'g')
1403
+ return string.replace(reg, (match, key) => {
1404
+ const result = _getValueByKeys({ keys: key.split('.'), obj: value })
1405
+ if (result === null || result === undefined) {
1406
+ return ''
1407
+ }
1408
+ return typeof result === 'object' ? JSON.stringify(result) : result
1409
+ })
1410
+ }
1411
+
1412
+ /* harmony default export */ const convertString_convertString = ({
1413
+ convertString
1414
+ });
1415
+
1416
+
1417
+ ;// ./lib/helpers/convertString/index.js
1418
+
1419
+
1420
+ ;// ./lib/helpers/escapeRegex/escapeRegex.js
1421
+ function escapeRegex(string) {
1422
+ return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
1423
+ }
1424
+
1425
+ ;// ./lib/helpers/escapeRegex/index.js
1426
+
1427
+
1428
+ ;// ./lib/helpers/expressHelper/customHandler.js
1429
+ function customHandler({ responseHelper, handler, ignoreError = false }) {
1430
+ return async (req, res, next) => {
1431
+ try {
1432
+ await handler({ req, res })
1433
+ await next()
1434
+ } catch (err) {
1435
+ if (ignoreError) {
1436
+ await next()
1437
+ } else {
1438
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1439
+ }
1440
+ }
1441
+ }
1442
+ }
1443
+
1444
+ ;// ./lib/helpers/expressHelper/findAllResult.js
1445
+ function findAllResult({ responseHelper, service }) {
1446
+ return async (req, res, next) => {
1447
+ try {
1448
+ const { query } = req
1449
+ const result = await service.findAll({ query })
1450
+ res.locals.findAllResult = result
1451
+ await next()
1452
+ } catch (err) {
1453
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1454
+ }
1455
+ }
1456
+ }
1457
+
1458
+ ;// ./lib/helpers/expressHelper/findOneResult.js
1459
+ function findOneResult({ responseHelper, service }) {
1460
+ return async (req, res, next) => {
1461
+ try {
1462
+ const { params, query } = req
1463
+ const { id } = params
1464
+ const result = await service.findOne({
1465
+ query: {
1466
+ ...query,
1467
+ id
1468
+ }
1469
+ })
1470
+ res.locals.findOneResult = result
1471
+ await next()
1472
+ } catch (err) {
1473
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ ;// ./lib/helpers/expressHelper/postResult.js
1479
+ function postResult({ responseHelper, service }) {
1480
+ return async (req, res, next) => {
1481
+ try {
1482
+ const { body } = req
1483
+ let result
1484
+ if (Array.isArray(body)) {
1485
+ result = await service.saveAll({ docs: body })
1486
+ } else {
1487
+ result = await service.saveOne({ doc: body })
1488
+ }
1489
+ res.locals.postResult = result
1490
+ await next()
1491
+ } catch (err) {
1492
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1493
+ }
1494
+ }
1495
+ }
1496
+
1497
+ ;// ./lib/helpers/expressHelper/updateOneResult.js
1498
+ function updateOneResult({ responseHelper, service }) {
1499
+ return async (req, res, next) => {
1500
+ try {
1501
+ const { body, params } = req
1502
+ const { id } = params
1503
+ if (id !== body.id) {
1504
+ throw new Error('id in params and body must be same')
1505
+ }
1506
+ const { data } = await service.findOne({ query: { id } })
1507
+ const doc = data[0]
1508
+ doc.update(body)
1509
+ const result = await service.saveOne({ doc })
1510
+ res.locals.updateOneResult = result
1511
+ await next()
1512
+ } catch (err) {
1513
+ res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
1514
+ }
1515
+ }
1516
+ }
1517
+
1518
+ ;// ./lib/helpers/expressHelper/index.js
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+
1525
+
1526
+ const expressHelper = {
1527
+ customHandler: customHandler,
1528
+ findAllResult: findAllResult,
1529
+ findOneResult: findOneResult,
1530
+ postResult: postResult,
1531
+ updateOneResult: updateOneResult,
1532
+ }
1533
+
1534
+ ;// ./lib/helpers/extractEmails/extractEmails.js
1535
+ /**
1536
+ * Extracts and normalizes unique email addresses from an array containing messy entries
1537
+ * @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
1538
+ * @returns {Array} Sorted array of unique, lowercase email addresses
1539
+ */
1540
+ function extractEmails(dirtyArray) {
1541
+ const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g
1542
+ const emails = new Set()
1543
+
1544
+ // Handle null/undefined input array
1545
+ if (!dirtyArray) return []
1546
+
1547
+ dirtyArray.forEach(entry => {
1548
+ // Skip null, undefined, empty, or whitespace-only entries
1549
+ if (!entry || typeof entry !== 'string' || !entry.trim()) return
1550
+
1551
+ try {
1552
+ const cleanEntry = entry
1553
+ .replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
1554
+ .replace(/[<>]/g, ' ') // Convert email delimiters to spaces
1555
+ .replace(/\s+/g, ' ') // Collapse multiple whitespace
1556
+ .trim()
1557
+
1558
+ // Extract all email matches
1559
+ const matches = cleanEntry.match(emailRegex)
1560
+ if (matches) {
1561
+ matches.forEach(email => emails.add(email.toLowerCase())) // Normalize to lowercase
1562
+ }
1563
+ } catch (e) {
1564
+ console.warn('Failed to process entry:', entry, e)
1565
+ }
1566
+ })
1567
+
1568
+ // Convert Set to array and sort alphabetically
1569
+ return Array.from(emails).sort((a, b) => a.localeCompare(b))
1570
+ }
1571
+
1572
+ ;// ./lib/helpers/extractEmails/index.js
1573
+
1574
+
1575
+ ;// ./lib/helpers/objectHelper/objectHelper.js
1576
+ const objectHelper = {
1577
+ get(obj, path) {
1578
+ const parts = path.split('.')
1579
+ return parts.reduce((acc, part) => {
1580
+ if (part.endsWith('[]')) {
1581
+ // 处理数组遍历
1582
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
1583
+ if (Array.isArray(acc[key])) {
1584
+ return acc[key] // 返回整个数组
1585
+ }
1586
+ return [] // 如果不是数组,返回空数组
1587
+ }
1588
+ if (part.includes('[') && part.includes(']')) {
1589
+ // 处理数组索引
1590
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
1591
+ if (arrayMatch) {
1592
+ const key = arrayMatch[1]
1593
+ const index = arrayMatch[2]
1594
+ return acc && acc[key] && acc[key][index]
1595
+ }
1596
+ } else if (acc && Array.isArray(acc)) {
1597
+ // 如果当前值是数组,提取每个对象的指定属性
1598
+ return acc.map((item) => item[part])
1599
+ } else {
1600
+ // 处理普通属性
1601
+ return acc && acc[part]
1602
+ }
1603
+ }, obj)
1604
+ },
1605
+ merge,
1606
+ set(obj, path, value) {
1607
+ const parts = path.split('.');
1608
+ let current = obj;
1609
+
1610
+ // 处理所有中间部分
1611
+ for (let i = 0; i < parts.length - 1; i++) {
1612
+ const part = parts[i];
1613
+ let key, index;
1614
+
1615
+ // 检查是否是数组索引格式,如key[0]
1616
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1617
+ if (arrayMatch) {
1618
+ key = arrayMatch[1];
1619
+ index = parseInt(arrayMatch[2], 10);
1620
+ // 确保当前层级的数组存在
1621
+ if (!current[key] || !Array.isArray(current[key])) {
1622
+ current[key] = [];
1623
+ }
1624
+ // 扩展数组到足够大
1625
+ while (current[key].length <= index) {
1626
+ current[key].push(undefined);
1627
+ }
1628
+ // 如果当前位置未定义或为null,初始化为对象
1629
+ if (current[key][index] == null) {
1630
+ current[key][index] = {};
1631
+ }
1632
+ current = current[key][index];
1633
+ } else {
1634
+ // 处理普通属性
1635
+ if (!current[part]) {
1636
+ current[part] = {};
1637
+ }
1638
+ current = current[part];
1639
+ }
1640
+ }
1641
+
1642
+ // 处理最后一部分
1643
+ const lastPart = parts[parts.length - 1];
1644
+ const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
1645
+ if (arrayMatch) {
1646
+ const key = arrayMatch[1];
1647
+ const index = parseInt(arrayMatch[2], 10);
1648
+ // 确保数组存在
1649
+ if (!current[key] || !Array.isArray(current[key])) {
1650
+ current[key] = [];
1651
+ }
1652
+ // 扩展数组到所需索引
1653
+ while (current[key].length <= index) {
1654
+ current[key].push(undefined);
1655
+ }
1656
+ current[key][index] = value;
1657
+ } else {
1658
+ current[lastPart] = value;
1659
+ }
1660
+ }
1661
+ }
1662
+
1663
+ function merge(target, ...sources) {
1664
+ if (!sources.length) return target
1665
+
1666
+ const source = sources.shift() // 取出第一个源对象
1667
+
1668
+ if (_isObject(target) && _isObject(source)) {
1669
+ for (const key in source) {
1670
+ if (_isObject(source[key])) {
1671
+ if (!target[key]) {
1672
+ // 如果目标对象没有该属性,创建一个空对象
1673
+ target[key] = {}
1674
+ }
1675
+ // 递归合并
1676
+ merge(target[key], source[key])
1677
+ } else {
1678
+ // 直接覆盖
1679
+ target[key] = source[key]
1680
+ }
1681
+ }
1682
+ }
1683
+
1684
+ // 继续合并剩余的源对象
1685
+ return merge(target, ...sources)
1686
+ }
1687
+
1688
+ function _isObject(obj) {
1689
+ return obj && typeof obj === 'object' && !Array.isArray(obj)
1690
+ }
1691
+
1692
+
1693
+
1694
+ ;// ./lib/helpers/objectHelper/index.js
1695
+
1696
+
1697
+
1698
+
1699
+ ;// ./lib/helpers/pReduce/pReduce.js
1700
+ async function pReduce(iterable, reducer, initialValue) {
1701
+ return new Promise((resolve, reject) => {
1702
+ const iterator = iterable[Symbol.iterator]()
1703
+ let index = 0
1704
+
1705
+ const next = async total => {
1706
+ const element = iterator.next()
1707
+
1708
+ if (element.done) {
1709
+ resolve(total)
1710
+ return
1711
+ }
1712
+
1713
+ try {
1714
+ const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
1715
+ next(reducer(resolvedTotal, resolvedValue, index++))
1716
+ } catch (error) {
1717
+ reject(error)
1718
+ }
1719
+ }
1720
+
1721
+ next(initialValue)
1722
+ })
1723
+ }
1724
+
1725
+
1726
+
1727
+ ;// ./lib/models/repo/repo.js
1728
+
1729
+
1730
+ class Repo {
1731
+ constructor(options) {
1732
+ options = options || {}
1733
+ this.model = options.model
1734
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1735
+ this._queryOptions = options._queryOptions
1736
+ this._saveOptions = options._saveOptions
1737
+ this._Class = options._constructor && options._constructor._Class
1738
+ ? options._constructor._Class
1739
+ : null
1740
+ }
1741
+ static init(options = {}) {
1742
+ return init(this, options)
1743
+ }
1744
+ static get _classname() {
1745
+ return 'Repo'
1746
+ }
1747
+ static get _superclass() {
1748
+ return 'Repo'
1749
+ }
1750
+
1751
+ get _classname() {
1752
+ return 'Repo'
1753
+ }
1754
+
1755
+ get _superclass() {
1756
+ return 'Repo'
1757
+ }
1758
+
1759
+ get isValid() {
1760
+ return this.model
1761
+ && (typeof this.model.deleteOne === 'function')
1762
+ && (typeof this.model.findAll === 'function')
1763
+ && (typeof this.model.saveOne === 'function')
1764
+ }
1765
+
1766
+ get queryOptions() {
1767
+ return {
1768
+ ...this._sharedOptions,
1769
+ ...this._queryOptions,
1770
+ }
1771
+ }
1772
+
1773
+ get saveOptions() {
1774
+ return {
1775
+ ...this._sharedOptions,
1776
+ ...this._saveOptions,
1777
+ }
1778
+ }
1779
+
1780
+ init(options) {
1781
+ if (this._Class && typeof this._Class.init === 'function') {
1782
+ return this._Class.init(options)
1783
+ }
1784
+ return options
1785
+ }
1786
+
1787
+ async deleteOne({ id }) {
1788
+ try {
1789
+ const result = await this.model.deleteOne({ _id: id })
1790
+ return {
1791
+ ...result, // { message: 'ok', total }
1792
+ isNew: false,
1793
+ data: []
1794
+ }
1795
+ } catch (err) {
1796
+ throw err
1797
+ }
1798
+ }
1799
+
1800
+ // systemLog is optional
1801
+ findAll({ query, systemLog }) {
1802
+ const log = _makeLog({
1803
+ systemLog,
1804
+ label: 'REPO_READ',
1805
+ message: `fn ${this._classname}.prototype.findAll`,
1806
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1807
+ })
1808
+ return new Promise((resolve, reject) => {
1809
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
1810
+ if (err) {
1811
+ log({ level: 'warn', output: err.toString() })
1812
+ reject(err)
1813
+ } else {
1814
+ const result = {
1815
+ isNew: false,
1816
+ data,
1817
+ total: total || data.length
1818
+ }
1819
+ log({ level: 'info', output: { ...result } })
1820
+ resolve(result)
1821
+ }
1822
+ })
1823
+ })
1824
+ }
1825
+
1826
+ findOne({ query, systemLog }) {
1827
+ const log = _makeLog({
1828
+ systemLog,
1829
+ label: 'REPO_READ',
1830
+ message: `fn ${this._classname}.prototype.findOne`,
1831
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1832
+ })
1833
+ return new Promise((resolve, reject) => {
1834
+ this.model.findAll(query, this.queryOptions, (err, data) => {
1835
+ if (err) {
1836
+ reject(err)
1837
+ } else if (data.length === 1) {
1838
+ const result = {
1839
+ isNew: false,
1840
+ data,
1841
+ total: 1
1842
+ }
1843
+ log({ level: 'info', output: { ...result } })
1844
+ resolve(result)
1845
+ } else if (data.length === 0) {
1846
+ reject(new Error('record not found'))
1847
+ } else {
1848
+ reject(new Error('more than one is found'))
1849
+ }
1850
+ })
1851
+ })
1852
+ .catch((err) => {
1853
+ log({ level: 'warn', output: err.toString() })
1854
+ throw err
1855
+ })
1856
+ }
1857
+
1858
+ saveAll({ docs, systemLog }) {
1859
+ let isNew
1860
+ const log = _makeLog({
1861
+ systemLog,
1862
+ label: 'REPO_WRITE',
1863
+ message: `fn ${this._classname}.prototype.saveAll`,
1864
+ input: [{ docs: [...docs], systemLog: { ...systemLog } }]
1865
+ })
1866
+ const promise = typeof this.model.saveAll === 'function'
1867
+ ? this.model.saveAll({ docs })
1868
+ : Promise.all(docs.map(async (doc) => {
1869
+ if (doc) {
1870
+ const result = await this.saveOne({ doc })
1871
+ isNew = result.isNew
1872
+ const _data = result._data || result.data
1873
+ return _data[0]
1874
+ }
1875
+ return null
1876
+ }))
1877
+ return promise.then((savedData) => {
1878
+ if (savedData.length !== 1) isNew = null
1879
+ const result = {
1880
+ data: savedData,
1881
+ isNew,
1882
+ total: savedData.length
1883
+ }
1884
+ log({ level: 'info', output: { ...result } })
1885
+ return result
1886
+ }).catch((err) => {
1887
+ log({ level: 'warn', output: err.toString() })
1888
+ throw err
1889
+ })
1890
+ }
1891
+
1892
+ saveOne({ doc, systemLog }) {
1893
+ const log = _makeLog({
1894
+ systemLog,
1895
+ label: 'REPO_WRITE',
1896
+ message: `fn ${this._classname}.prototype.saveOne`,
1897
+ input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
1898
+ })
1899
+ return new Promise((resolve, reject) => {
1900
+ this.model.saveOne(doc, this.saveOptions, (err, result) => {
1901
+ if (err) {
1902
+ log({ level: 'warn', output: err.toString() })
1903
+ reject(err)
1904
+ } else {
1905
+ log({ level: 'info', output: { ...result } })
1906
+ resolve(result)
1907
+ }
1908
+ })
1909
+ })
1910
+ }
1911
+ }
1912
+
1913
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
1914
+ return ({ level, messgae: massage2, output } = {}) => {
1915
+ if (systemLog && systemLog.systemLogHelper) {
1916
+ systemLog.systemLogHelper.log({
1917
+ batchId: systemLog.batchId,
1918
+ label,
1919
+ level,
1920
+ message: massage2 || message1,
1921
+ data: {
1922
+ payload: {
1923
+ input,
1924
+ output
1925
+ }
1926
+ }
1927
+ })
1928
+ }
1929
+ }
1930
+ }
1931
+
1932
+
1933
+
1934
+ ;// ./lib/models/repo/index.js
1935
+
1936
+
1937
+
1938
+
1939
+ ;// ./lib/models/apiResponse/apiResponse.js
1940
+ class ApiResponse {
1941
+ constructor(options = {}) {
1942
+ options = options || {}
1943
+ this._data = options.data || options._data || []
1944
+ this.err = options.err
1945
+ this.isNew = options.isNew || false
1946
+ this.message = options.message
1947
+ this.total = options.total || 0
1948
+ this._instanceBuilder = options._instanceBuilder
1949
+ }
1950
+
1951
+ static init(options = {}) {
1952
+ if (options instanceof this) {
1953
+ return options
1954
+ }
1955
+ const instance = new this(options)
1956
+ return instance
1957
+ }
1958
+ static get _classname() {
1959
+ return 'ApiResponse'
1960
+ }
1961
+ static get _superclass() {
1962
+ return 'ApiResponse'
1963
+ }
1964
+
1965
+ // getters
1966
+ get data() {
1967
+ if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
1968
+ return this._data.map(this._instanceBuilder)
1969
+ }
1970
+ return this._data
1971
+ }
1972
+ }
1973
+
1974
+
1975
+
1976
+ ;// ./lib/models/apiResponse/makeApiResponse.js
1977
+
1978
+
1979
+ function makeApiResponse({ repo, result }) {
1980
+ return ApiResponse.init({
1981
+ ...result,
1982
+ _instanceBuilder: (i) => {
1983
+ return repo.init(i)
1984
+ }
1985
+ })
1986
+ }
1987
+
1988
+
1989
+
1990
+ ;// ./lib/models/service/service.js
1991
+
1992
+
1993
+
1994
+ class Service {
1995
+ constructor({ repo }) {
1996
+ this.repo = repo
1997
+ }
1998
+
1999
+ static get _classname() {
2000
+ return 'Service'
2001
+ }
2002
+ static get _superclass() {
2003
+ return 'Service'
2004
+ }
2005
+
2006
+ deleteOne({ id }) {
2007
+ return this.repo.deleteOne({ id })
2008
+ .catch(() => {
2009
+ throw new Error(`Not found for query: ${id}`)
2010
+ })
2011
+ }
2012
+
2013
+ async findAll({ query = {}, systemLog } = {}) {
2014
+ const result = await this.repo.findAll({ query, systemLog })
2015
+ return makeApiResponse({
2016
+ repo: this.repo,
2017
+ result
2018
+ })
2019
+ }
2020
+
2021
+ async findOne({ query = {}, systemLog } = {}) {
2022
+ const result = await this.repo.findOne({ query, systemLog })
2023
+ return makeApiResponse({
2024
+ repo: this.repo,
2025
+ result
2026
+ })
2027
+ }
2028
+
2029
+ init(options) {
2030
+ return this.repo.init(options)
2031
+ }
2032
+ initFromArray(arr = []) {
2033
+ if (Array.isArray(arr)) {
2034
+ return arr.map((a) => this.init(a))
2035
+ }
2036
+ return []
2037
+ }
2038
+ initOnlyValidFromArray(arr = []) {
2039
+ return this.initFromArray(arr).filter((i) => i)
2040
+ }
2041
+
2042
+ async saveAll({ docs = [], config = {}, systemLog } = {}) {
2043
+ const copies = docs.map((doc) => {
2044
+ return config.skipInit ? doc : this.init(doc)
2045
+ })
2046
+ const result = await this.repo.saveAll({ docs: copies, systemLog })
2047
+ return makeApiResponse({
2048
+ repo: this.repo,
2049
+ result
2050
+ })
2051
+ }
2052
+
2053
+ // set skipInit to true if we want to use POST for query
2054
+ async saveOne({ doc = {}, config = {}, systemLog } = {}) {
2055
+ const copy = config.skipInit ? doc : this.init(doc)
2056
+ if (copy) {
2057
+ const result = await this.repo.saveOne({ doc: copy, systemLog })
2058
+ return makeApiResponse({
2059
+ repo: this.repo,
2060
+ result
2061
+ })
2062
+ }
2063
+ return {
2064
+ isNew: null,
2065
+ data: [],
2066
+ err: new Error('doc is not a valid instance')
2067
+ }
2068
+ }
2069
+ }
2070
+
2071
+ function makeService({ repo }) {
2072
+ if (repo === undefined) {
2073
+ throw new Error('repo is required.')
2074
+ }
2075
+ if (repo._superclass !== Repo._superclass) {
2076
+ throw new Error('repo is not an instance of Repo.')
2077
+ }
2078
+ return new Service({ repo })
2079
+ }
2080
+
2081
+
2082
+
2083
+ ;// ./lib/models/service/index.js
2084
+
2085
+
2086
+
2087
+
2088
+ ;// ./lib/helpers/generalPost/generalPost.js
2089
+
2090
+
2091
+
2092
+
2093
+
2094
+ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
2095
+ const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
2096
+ const _resourceInfo = resourceInfo || body.resourceInfo
2097
+ _attachShared(data, globalShared, shared)
2098
+ const obj = await pReduce(resources, async (acc, resource) => {
2099
+ const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
2100
+ _createRelationship(data, relationship[resource], acc)
2101
+ const _data = data[resource]
2102
+ const result = await service.saveAll({ docs: [].concat(_data) })
2103
+ acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
2104
+ return acc
2105
+ }, {})
2106
+ return obj
2107
+ }
2108
+
2109
+ function _attachShared(data, globalShared = {}, shared = {}) {
2110
+ Object.keys(shared).forEach((key) => {
2111
+ const _data = data[key]
2112
+ if (Array.isArray(_data)) {
2113
+ data[key] = _data.map((_dataItem) => {
2114
+ return objectHelper.merge({}, _dataItem, globalShared, shared[key] || {})
2115
+ })
2116
+ } else {
2117
+ data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
2118
+ }
2119
+ })
2120
+ }
2121
+
2122
+ function _createRelationship(data, relationship = {}, object) {
2123
+ Object.keys(relationship).forEach((key) => {
2124
+ const path = relationship[key]
2125
+ const val = objectHelper.get(object, path)
2126
+ objectHelper.set(data, key, val)
2127
+ })
2128
+ }
2129
+
2130
+ function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
2131
+ const { collectionName, fields } = resourceInfo[resource]
2132
+ const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
2133
+ const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
2134
+ return makeService({
2135
+ repo: new Repo({ model })
2136
+ })
2137
+ }
2138
+
2139
+
2140
+
2141
+ ;// ./lib/helpers/generalPost/index.js
2142
+
2143
+
2144
+
2145
+
2146
+ ;// ./lib/helpers/init/init.js
2147
+ function init(_class, options) {
2148
+ if (options instanceof _class) {
2149
+ return options
2150
+ }
2151
+ try {
2152
+ const instance = new _class(options)
2153
+ return instance.isValid !== false ? instance : null
2154
+ } catch (e) {
2155
+ console.log(`init failed for class: ${_class._classname || 'no _classname'}`, e)
2156
+ return null
2157
+ }
2158
+ }
2159
+
2160
+ ;// ./lib/helpers/init/index.js
2161
+
2162
+
2163
+ ;// ./lib/helpers/initFromArray/initFromArray.js
2164
+
2165
+
2166
+ function initFromArray(_class, arr) {
2167
+ if (Array.isArray(arr)) {
2168
+ return arr.map((a) => init(_class, a))
2169
+ }
2170
+ return []
2171
+ }
2172
+
2173
+ ;// ./lib/helpers/initFromArray/index.js
2174
+
2175
+
2176
+ ;// ./lib/helpers/initOnlyValidFromArray/initOnlyValidFromArray.js
2177
+
2178
+
2179
+ function initOnlyValidFromArray(_class, arr) {
2180
+ return initFromArray(_class, arr).filter((i) => i)
2181
+ }
2182
+
2183
+ ;// ./lib/helpers/initOnlyValidFromArray/index.js
2184
+
2185
+
2186
+ ;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
2187
+ function mergeArraysByKey(arr1, arr2) {
2188
+ // Handle undefined/null inputs by defaulting to empty arrays
2189
+ const safeArr1 = Array.isArray(arr1) ? arr1 : []
2190
+ const safeArr2 = Array.isArray(arr2) ? arr2 : []
2191
+
2192
+ const mergedMap = new Map()
2193
+
2194
+ // Helper function to merge values based on their type
2195
+ const mergeValues = (existingValue, newValue) => {
2196
+ if (existingValue === undefined) return newValue
2197
+
2198
+ // Handle arrays by concatenating
2199
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
2200
+ return [...new Set([...existingValue, ...newValue])]
2201
+ }
2202
+
2203
+ // Handle objects by merging
2204
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
2205
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
2206
+ return { ...existingValue, ...newValue }
2207
+ }
2208
+
2209
+ // // Handle numbers by adding
2210
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
2211
+ // return existingValue
2212
+ // }
2213
+
2214
+ // // Handle strings by concatenating
2215
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
2216
+ // return existingValue
2217
+ // }
2218
+
2219
+ // Default: use the new value
2220
+ return newValue
2221
+ }
2222
+
2223
+ // Process first array
2224
+ safeArr1.forEach(item => {
2225
+ mergedMap.set(item.key, item.value)
2226
+ })
2227
+
2228
+ // Process second array and merge values
2229
+ safeArr2.forEach(item => {
2230
+ const existingValue = mergedMap.get(item.key)
2231
+ mergedMap.set(item.key, mergeValues(existingValue, item.value))
2232
+ })
2233
+
2234
+ // Convert back to array format
2235
+ return Array.from(mergedMap.entries()).map(([key, value]) => ({
2236
+ key,
2237
+ value
2238
+ }))
2239
+ }
2240
+
2241
+ ;// ./lib/helpers/mergeArraysByKey/index.js
2242
+
2243
+
2244
+ ;// ./lib/helpers/padZeros/padZeros.js
2245
+ function padZeros(num, minLength = 6) {
2246
+ num = num.toString()
2247
+ if (num.length < minLength) {
2248
+ return padZeros('0' + num, minLength)
2249
+ }
2250
+ return num
2251
+ }
2252
+
2253
+
2254
+
2255
+ ;// ./lib/helpers/padZeros/index.js
2256
+
2257
+
2258
+
2259
+
2260
+ ;// ./lib/helpers/pReduce/index.js
2261
+
2262
+
2263
+
2264
+
2265
+ ;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
2266
+ function replacePlaceholders({ content, mapping }) {
2267
+ let isObjectMode = false
2268
+
2269
+ if (typeof content === 'object' && content !== null) {
2270
+ content = JSON.stringify(content)
2271
+ isObjectMode = true
2272
+ }
2273
+
2274
+ // [[ eventRegistration.eventRegistrationCode | 0 ]]
2275
+ const regex = /(\[*)\[\[\s*([\w.\-_]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g;
2276
+
2277
+ const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
2278
+
2279
+ // Split the path into parts
2280
+ const keys = path.trim().split('.')
2281
+
2282
+ // Traverse the nested object structure
2283
+ let value = mapping
2284
+ for (const key of keys) {
2285
+ // Handle empty keys (in case of double dots or leading/trailing dots)
2286
+ if (!key) continue
2287
+
2288
+ value = value?.[key]
2289
+ if (value === undefined) {
2290
+ break
2291
+ }
2292
+ }
2293
+
2294
+ // Apply default if missing
2295
+ if (value === undefined) value = defaultValue?.trim();
2296
+ if (value === undefined) return isObjectMode ? undefined : match;
2297
+
2298
+ value = value !== undefined
2299
+ ? leadingBrackets + value + trailingBrackets
2300
+ : match
2301
+
2302
+ // Return replacement or original if not found
2303
+ return value
2304
+ })
2305
+
2306
+ if (isObjectMode) {
2307
+ return JSON.parse(result)
2308
+ }
2309
+ return result
2310
+ }
2311
+
2312
+ ;// ./lib/helpers/replacePlaceholders/index.js
2313
+
2314
+
2315
+ ;// ./lib/helpers/sanitizeText/sanitizeText.js
2316
+ /**
2317
+ * Sanitizes input by removing hidden/control characters with customizable whitespace handling.
2318
+ * @param {string} input - The string to sanitize.
2319
+ * @param {Object} [options] - Configuration options.
2320
+ * @param {boolean} [options.normalizeWhitespace=true] - Collapse multiple spaces/tabs into one space.
2321
+ * @param {boolean} [options.removeNewlines=false] - If true, replaces newlines with spaces.
2322
+ * @param {boolean} [options.trim=true] - If true, trims leading/trailing whitespace.
2323
+ * @returns {string} The sanitized string.
2324
+ */
2325
+ function sanitizeText(input, options = {}) {
2326
+ const {
2327
+ normalizeWhitespace = true,
2328
+ removeNewlines = false,
2329
+ trim = true,
2330
+ } = options
2331
+
2332
+ if (typeof input !== 'string') {
2333
+ return input
2334
+ }
2335
+
2336
+ let result = input
2337
+
2338
+ // Phase 1: Remove hidden/control characters
2339
+ result = result.replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
2340
+
2341
+ // Phase 2: Handle whitespace transformations
2342
+ if (removeNewlines) {
2343
+ result = result.replace(/[\r\n]+/g, ' ') // Convert newlines to spaces
2344
+ }
2345
+
2346
+ if (normalizeWhitespace) {
2347
+ result = result.replace(/[ \t]+/g, ' ') // Collapse spaces/tabs to single space
2348
+ }
2349
+
2350
+ // Phase 3: Final trimming
2351
+ if (trim) {
2352
+ result = result.trim()
2353
+ }
2354
+
2355
+ return result
2356
+ }
2357
+
2358
+ ;// ./lib/helpers/sanitizeText/index.js
2359
+
2360
+
2361
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
2362
+ function stringFormatter(str, delimiter = '_') {
2363
+ if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
2364
+ return null
2365
+ }
2366
+ return str.toString()
2367
+ .trim()
2368
+ .toUpperCase()
2369
+ .replace('-', delimiter)
2370
+ .replace(' ', delimiter)
2371
+ }
2372
+
2373
+
2374
+
2375
+ ;// ./lib/helpers/stringFormatter/index.js
2376
+
2377
+
2378
+
2379
+
2380
+ ;// ./lib/helpers/stringHelper/stringHelper.js
2381
+ function baseXEncode(num, base = 34) {
2382
+ const charset = getBaseCharset(base)
2383
+ return encode(num, charset)
2384
+ }
2385
+
2386
+ function encode(int, charset) {
2387
+ const { byCode } = charset
2388
+ if (int === 0) {
2389
+ return byCode[0]
2390
+ }
2391
+
2392
+ let res = ''
2393
+ const max = charset.length
2394
+ while (int > 0) {
2395
+ res = byCode[int % max] + res
2396
+ int = Math.floor(int / max)
2397
+ }
2398
+ return res
2399
+ }
2400
+
2401
+ function getBaseCharset(base) {
2402
+ let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
2403
+ if (base === 58) {
2404
+ charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
2405
+ }
2406
+ return indexCharset(charset)
2407
+ }
2408
+
2409
+ function indexCharset(str) {
2410
+ const byCode = {}
2411
+ const byChar = {}
2412
+ const { length } = str
2413
+ let char
2414
+ for (let i = 0; i < length; i++) {
2415
+ char = str[i]
2416
+ byCode[i] = char
2417
+ byChar[char] = i;
2418
+ }
2419
+ return { byCode, byChar, length }
2420
+ }
2421
+
2422
+ function isSame(str1, str2) {
2423
+ if (typeof str1 !== 'string' || typeof str2 !== 'string') {
2424
+ return false
2425
+ }
2426
+ return str1.trim().toUpperCase() === str2.trim().toUpperCase()
2427
+ }
2428
+
2429
+ function randomString({ len = 16, pattern = 'a1' } = {}) {
2430
+ const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
2431
+ const a = 'abcdefghijklmnopqrstuvwxyz'
2432
+ const num = '1234567890'
2433
+ const mark = '~!@#$%^&*_+-='
2434
+ let str = ''
2435
+ if (pattern.includes('A')) {
2436
+ str += A
2437
+ }
2438
+ if (pattern.includes('a')) {
2439
+ str += a
2440
+ }
2441
+ if (pattern.includes('1')) {
2442
+ str += num
2443
+ }
2444
+ if (pattern.includes('#')) {
2445
+ str += mark
2446
+ }
2447
+ const chars = [...str]
2448
+ return [...Array(len)].map(i => {
2449
+ return chars[(Math.random() * chars.length) | 0]
2450
+ }).join``
2451
+ }
2452
+
2453
+ function reverse(str) {
2454
+ const _str = (typeof str !== 'string') ? str.toString() : str
2455
+ const splitString = _str.split('')
2456
+ const reverseArray = splitString.reverse()
2457
+ return reverseArray.join('')
2458
+ }
2459
+
2460
+ function setCode(base = 34) {
2461
+ const now = (new Date()).valueOf()
2462
+ const random = randomString({
2463
+ len: 8,
2464
+ pattern: '1'
2465
+ })
2466
+ const str = reverse(`${now}${random}`)
2467
+ // const str = `${now}${random}`
2468
+ return baseXEncode(str, base)
2469
+ }
2470
+
2471
+ function toCamelCase(str) {
2472
+ if (!str) return ''
2473
+ return str
2474
+ .trim()
2475
+ .split(/\s+/)
2476
+ .map((word, index) => {
2477
+ if (!word) return ''
2478
+ if (index === 0) {
2479
+ return word.toLowerCase()
2480
+ }
2481
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
2482
+ })
2483
+ .join('')
2484
+ }
2485
+
2486
+ function toLowerCase(str) {
2487
+ if (!str) return ''
2488
+ return str
2489
+ .trim()
2490
+ .toLowerCase()
2491
+ }
2492
+
2493
+ const stringHelper = {
2494
+ isSame,
2495
+ setCode,
2496
+ toCamelCase,
2497
+ toLowerCase,
2498
+ }
2499
+
2500
+
2501
+
2502
+ ;// ./lib/helpers/stringHelper/index.js
2503
+
2504
+
2505
+
2506
+
2507
+ ;// ./lib/helpers/trackingPlugin/trackingPlugin.js
2508
+ function trackingPlugin(schema, options) {
2509
+ // Add meta fields
2510
+ schema.add({
2511
+ meta: {
2512
+ active: { type: Boolean, default: true },
2513
+ created: { type: Number },
2514
+ creator: { type: String },
2515
+ deleted: { type: Boolean, default: false },
2516
+ modified: { type: Number },
2517
+ owner: { type: String },
2518
+ }
2519
+ })
2520
+
2521
+ // Auto-update hook
2522
+ schema.pre('save', function(next) {
2523
+ this.meta.modified = Date.now()
2524
+ next()
2525
+ })
2526
+
2527
+ // Optional: Add helper methods
2528
+ // schema.methods.touch = function(userId) {
2529
+ // this.meta.updatedAt = new Date()
2530
+ // this.meta.updatedBy = userId
2531
+ // }
2532
+ }
2533
+
2534
+ ;// ./lib/helpers/trackingPlugin/index.js
2535
+
2536
+
2537
+ ;// ./lib/helpers/index.js
2538
+
2539
+
2540
+
2541
+
2542
+
2543
+
2544
+
2545
+
2546
+
2547
+
2548
+
2549
+
2550
+
2551
+
2552
+
2553
+
2554
+
2555
+
2556
+
2557
+
2558
+
2559
+
2560
+
2561
+
2562
+ ;// ./lib/models/apiResponse/index.js
2563
+
2564
+
2565
+
2566
+
2567
+
2568
+ ;// ./lib/models/awsStsS3Client/awsStsS3Client.js
2569
+ class AwsStsS3Client {
2570
+ constructor(options) {
2571
+ options = options || {}
2572
+
2573
+ this.expiration = options.expiration || null
2574
+ this.s3Client = options.s3Client || null
2575
+ this.getIdToken = options.getIdToken
2576
+ this.region = options.region || 'ap-east-1'
2577
+ this.roleArn = options.roleArn
2578
+ this.roleSessionName = options.roleSessionName || 'web-identity-session'
2579
+ this.durationSession = options.durationSession || 3600
2580
+ this.awsClientSts = options.awsClientSts
2581
+ this.awsClientS3 = options.awsClientS3
2582
+ }
2583
+
2584
+ static dummyData() {
2585
+ return {
2586
+ getIdToken: () => 'mock-web-identity-token',
2587
+ roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
2588
+ awsClientSts: {
2589
+ STSClient: class {},
2590
+ AssumeRoleWithWebIdentityCommand: class {}
2591
+ },
2592
+ awsClientS3: {
2593
+ S3Client: class {},
2594
+ PutObjectCommand: class {},
2595
+ GetObjectCommand: class {},
2596
+ DeleteObjectCommand: class {}
2597
+ }
2598
+ }
2599
+ }
2600
+
2601
+ static init(options = {}) {
2602
+ if (options instanceof this) {
2603
+ return options
2604
+ }
2605
+ try {
2606
+ const instance = new this(options)
2607
+ if (!instance.isValid) {
2608
+ return null
2609
+ }
2610
+ return instance
2611
+ } catch (error) {
2612
+ return null
2613
+ }
2614
+ }
2615
+
2616
+ get isExpired() {
2617
+ if (!this.expiration) return true;
2618
+ const now = new Date();
2619
+ const bufferMs = 1 * 60 * 1000; // 一分钟缓冲
2620
+ return now >= new Date(this.expiration.getTime() - bufferMs);
2621
+ }
2622
+
2623
+ get isValid() {
2624
+ if (!this.getIdToken) {
2625
+ throw new Error('Missing required configuration: getIdToken function')
2626
+ }
2627
+ if (!this.roleArn) {
2628
+ throw new Error('Missing required configuration: roleArn')
2629
+ }
2630
+ if (!this.awsClientSts) {
2631
+ throw new Error('Missing required AWS awsClientSts client configuration')
2632
+ }
2633
+ if (!this.awsClientSts.STSClient) {
2634
+ throw new Error('Missing STSClient in AWS awsClientSts client configuration')
2635
+ }
2636
+ if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
2637
+ throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
2638
+ }
2639
+ if (!this.awsClientS3) {
2640
+ throw new Error('Missing required AWS awsClientS3 client configuration')
2641
+ }
2642
+
2643
+ const requiredS3Components = [
2644
+ 'S3Client',
2645
+ 'PutObjectCommand',
2646
+ 'GetObjectCommand',
2647
+ 'DeleteObjectCommand'
2648
+ ]
2649
+
2650
+ for (const component of requiredS3Components) {
2651
+ if (!this.awsClientS3[component]) {
2652
+ throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
2653
+ }
2654
+ }
2655
+
2656
+ return true
2657
+ }
2658
+
2659
+ async refreshCredentials() {
2660
+ try {
2661
+ const webIdentityToken = await this.getIdToken()
2662
+ if (!webIdentityToken) {
2663
+ throw new Error('getIdToken function returned empty or invalid token')
2664
+ }
2665
+
2666
+ const stsClient = new this.awsClientSts.STSClient({ region: this.region })
2667
+
2668
+ const stsResponse = await stsClient.send(
2669
+ new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
2670
+ RoleArn: this.roleArn,
2671
+ RoleSessionName: this.roleSessionName,
2672
+ WebIdentityToken: await this.getIdToken(),
2673
+ DurationSeconds: this.durationSession,
2674
+ })
2675
+ )
2676
+
2677
+ const credentials = stsResponse.Credentials
2678
+ if (!credentials) {
2679
+ throw new Error('No credentials returned from awsClientSts')
2680
+ }
2681
+
2682
+ this.expiration = credentials.Expiration
2683
+
2684
+ this.s3Client = new this.awsClientS3.S3Client({
2685
+ region: this.region,
2686
+ credentials: {
2687
+ accessKeyId: credentials.AccessKeyId,
2688
+ secretAccessKey: credentials.SecretAccessKey,
2689
+ sessionToken: credentials.SessionToken,
2690
+ }
2691
+ })
2692
+
2693
+ return this
2694
+ } catch (error) {
2695
+ throw new Error(`Failed to refresh credentials: ${error.message}`)
2696
+ }
2697
+ }
2698
+
2699
+ async getS3Client() {
2700
+ if (this.isExpired || !this.s3Client) {
2701
+ await this.refreshCredentials()
2702
+ }
2703
+ return this.s3Client
2704
+ }
2705
+
2706
+ async putObject(params) {
2707
+ try {
2708
+ const client = await this.getS3Client()
2709
+ const command = new this.awsClientS3.PutObjectCommand(params)
2710
+ await client.send(command)
2711
+ const fileArr = params.Key.split('/')
2712
+ return {
2713
+ url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
2714
+ filename: fileArr.pop(),
2715
+ folder: params.Bucket,
2716
+ subFolders: fileArr
2717
+ }
2718
+ } catch (error) {
2719
+ throw new Error(`Failed to put object: ${error.message}`)
2720
+ }
2721
+ }
2722
+
2723
+ async getObject(params) {
2724
+ try {
2725
+ const client = await this.getS3Client()
2726
+ const command = new this.awsClientS3.GetObjectCommand(params)
2727
+ const response = await client.send(command)
2728
+ return {
2729
+ body: response.Body,
2730
+ contentType: response.ContentType,
2731
+ lastModified: response.LastModified,
2732
+ contentLength: response.ContentLength,
2733
+ }
2734
+ } catch (error) {
2735
+ throw new Error(`Failed to get object: ${error.message}`)
2736
+ }
2737
+ }
2738
+
2739
+ async deleteObject(params) {
2740
+ try {
2741
+ const client = await this.getS3Client()
2742
+ const command = new this.awsClientS3.DeleteObjectCommand(params)
2743
+ await client.send(command)
2744
+ return true
2745
+ } catch (error) {
2746
+ throw new Error(`Failed to delete object: ${error.message}`)
2747
+ }
2748
+ }
2749
+ }
2750
+
2751
+
2752
+
2753
+ ;// ./lib/models/awsStsS3Client/index.js
2754
+
2755
+
2756
+
2757
+
2758
+ ;// ./lib/models/keyValueObject/keyValueObject.js
2759
+ class KeyValueObject {
2760
+ constructor(options = {}) {
2761
+ options = options || {}
2762
+ this.key = options.key || null
2763
+ this.value = (typeof options.value !== 'undefined') ? options.value : ''
2764
+ }
2765
+
2766
+ // Class methods
2767
+ static init(options = {}) {
2768
+ if (options instanceof this) {
2769
+ return options
2770
+ }
2771
+ const instance = new this(options)
2772
+ return instance.isValid ? instance : null
2773
+ }
2774
+ static initFromArray(arr = []) {
2775
+ if (Array.isArray(arr)) {
2776
+ return arr.map((a) => this.init(a))
2777
+ }
2778
+ return []
2779
+ }
2780
+ static initOnlyValidFromArray(arr = []) {
2781
+ return this.initFromArray(arr).filter((i) => i)
2782
+ }
2783
+ static get _classname() {
2784
+ return 'KeyValueObject'
2785
+ }
2786
+ static get _superclass() {
2787
+ return 'KeyValueObject'
2788
+ }
2789
+
2790
+ static addItem(arr, key, value) {
2791
+ arr.push(this.init({ key, value }))
2792
+ }
2793
+ static addRecord(arr = [], key, value) {
2794
+ if (!this.hasKeyValue(arr, key, value)) {
2795
+ arr.push(this.init({ key, value }))
2796
+ }
2797
+ return arr
2798
+ }
2799
+ static appendRecord(arr = [], key, value) {
2800
+ return arr.map((item) => {
2801
+ if (this.sameKey(item, key)) {
2802
+ item.value = [...item.value, ...value]
2803
+ }
2804
+ return item
2805
+ })
2806
+ }
2807
+ static appendValueArray(arr = [], key, value) {
2808
+ return arr.map((item) => {
2809
+ if (this.sameKey(item, key)) {
2810
+ item.value = [...item.value, ...value]
2811
+ }
2812
+ return item
2813
+ })
2814
+ }
2815
+ static foundByKey(arr = [], key) {
2816
+ const found = arr.find((m) => {
2817
+ return this.sameKey(m, key)
2818
+ })
2819
+ return found || null
2820
+ }
2821
+ static foundValueByKey(arr = [], key) {
2822
+ const found = this.foundByKey(arr, key)
2823
+ return found ? found.value : null
2824
+ }
2825
+ static fromObject(options = {}) {
2826
+ return Object.keys(options).reduce((acc, key) => {
2827
+ acc.push(this.init({ key, value: options[key] }))
2828
+ return acc
2829
+ }, [])
2830
+ }
2831
+ static getValueByKey(arr = [], key) {
2832
+ return this.foundValueByKey(arr, key)
2833
+ }
2834
+ static getValueByKeyFromArray(arr = [], key) {
2835
+ if (arr.length === 0) {
2836
+ return null
2837
+ }
2838
+ const firstArr = arr.shift()
2839
+ const found = firstArr.find((i) => {
2840
+ return this.sameKey(i, key)
2841
+ })
2842
+ if (found && found.value) {
2843
+ return found.value
2844
+ }
2845
+ return this.getValueByKeyFromArray(arr, key)
2846
+ }
2847
+ static getValuesByKey(arr = [], key) {
2848
+ return arr.reduce((acc, item) => {
2849
+ if (this.sameKey(item, key)) {
2850
+ acc.push(item.value)
2851
+ }
2852
+ return acc
2853
+ }, [])
2854
+ }
2855
+ static hasKeyValue(arr = [], key, value) {
2856
+ if (typeof value === 'undefined') {
2857
+ return arr.filter((item) => this.sameKey(item, key)).length > 0
2858
+ }
2859
+ return arr.filter((item) => (this.sameKey(item, key) && _isSame(item.value, value))).length > 0
2860
+ }
2861
+ static insertOrUpdateRecord(arr = [], key, value) {
2862
+ let copy = [...arr]
2863
+ if (!this.hasKeyValue(arr, key)) {
2864
+ copy.push(this.init({ key, value }))
2865
+ } else {
2866
+ copy = this.updateRecord(arr, key, value)
2867
+ }
2868
+ return copy
2869
+ }
2870
+ static keys(arr = []) {
2871
+ if (Array.isArray(arr)) {
2872
+ return arr.reduce((acc, item) => {
2873
+ acc.push(item.key)
2874
+ return acc
2875
+ }, [])
2876
+ }
2877
+ return []
2878
+ }
2879
+ static merge(toArr, fromArr) {
2880
+ (fromArr || []).map((from) => {
2881
+ const found = toArr.find((to) => {
2882
+ return to.key === from.key
2883
+ })
2884
+ if (found) {
2885
+ found.value = _mergeValues(from.value, found.value)
2886
+ } else {
2887
+ toArr.push(from)
2888
+ }
2889
+ })
2890
+ return toArr
2891
+ }
2892
+ static removeByKey(arr, key) {
2893
+ return arr.reduce((acc, item) => {
2894
+ if (!this.sameKey(item, key)) {
2895
+ acc.push(item)
2896
+ }
2897
+ return acc
2898
+ }, [])
2899
+ }
2900
+ static sameKey(item, key) {
2901
+ return _isSame(item.key, key)
2902
+ }
2903
+ static toObject(arr = []) {
2904
+ if (Array.isArray(arr)) {
2905
+ return arr.reduce((acc, item) => {
2906
+ acc[item.key] = item.value
2907
+ return acc
2908
+ }, {})
2909
+ }
2910
+ return {}
2911
+ }
2912
+ static toString(arr = [], delimiter = '; ') {
2913
+ if (Array.isArray(arr)) {
2914
+ return arr.reduce((acc, item) => {
2915
+ acc.push(`${item.key}: ${item.value}`)
2916
+ return acc
2917
+ }, []).join(delimiter)
2918
+ }
2919
+ return ''
2920
+ }
2921
+ static updateRecord(arr = [], key, value) {
2922
+ return arr.map((item) => {
2923
+ if (this.sameKey(item, key)) {
2924
+ return {
2925
+ ...item,
2926
+ value
2927
+ }
2928
+ }
2929
+ return item
2930
+ })
2931
+ }
2932
+ static updateOrInsertRecord(arr = [], key, value) {
2933
+ return this.insertOrUpdateRecord(arr, key, value)
2934
+ }
2935
+ static updateRecordsFromArray(arr = [], updateArr = []) {
2936
+ if (Array.isArray(arr) && Array.isArray(updateArr)) {
2937
+ const obj1 = this.toObject(arr)
2938
+ const obj2 = this.toObject(updateArr)
2939
+ return this.fromObject({
2940
+ ...obj1,
2941
+ ...obj2
2942
+ })
2943
+ }
2944
+ return []
2945
+ }
2946
+ static values(arr = []) {
2947
+ if (Array.isArray(arr)) {
2948
+ return arr.reduce((acc, item) => {
2949
+ acc.push(item.value)
2950
+ return acc
2951
+ }, [])
2952
+ }
2953
+ return []
2954
+ }
2955
+
2956
+ // getters
2957
+ get isValid() {
2958
+ return !!this.key
2959
+ }
2960
+
2961
+ get toObject() {
2962
+ const obj = {}
2963
+ if (this.isValid) {
2964
+ obj[this.key] = this.value
2965
+ }
2966
+ return obj
2967
+ }
2968
+ }
2969
+
2970
+ function _mergeValues(existingValue, newValue) {
2971
+ if (existingValue === undefined) return newValue
2972
+
2973
+ // Handle arrays by concatenating
2974
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
2975
+ return [...new Set([...existingValue, ...newValue])]
2976
+ }
2977
+
2978
+ // Handle objects by merging
2979
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
2980
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
2981
+ return { ...existingValue, ...newValue }
2982
+ }
2983
+
2984
+ // // Handle numbers by adding
2985
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
2986
+ // return existingValue
2987
+ // }
2988
+
2989
+ // // Handle strings by concatenating
2990
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
2991
+ // return existingValue
2992
+ // }
2993
+
2994
+ // Default: use the new value
2995
+ return newValue
2996
+ }
2997
+
2998
+ function _isSame(key1, key2) {
2999
+ return key1 === key2
3000
+ }
3001
+
3002
+
3003
+
3004
+ ;// ./lib/models/keyValueObject/index.js
3005
+
3006
+
3007
+
3008
+
3009
+ ;// ./lib/models/metadata/metadata.js
3010
+
3011
+
3012
+
3013
+ const DELIMITER = '_'
3014
+
3015
+ class Metadata extends KeyValueObject {
3016
+ static init(options = {}) {
3017
+ if (options instanceof this) {
3018
+ return options
3019
+ }
3020
+ const instance = new this({
3021
+ ...options,
3022
+ key: stringFormatter(options.key, DELIMITER),
3023
+ })
3024
+ return instance.isValid ? instance : null
3025
+ }
3026
+ static get _classname() {
3027
+ return 'Metadata'
3028
+ }
3029
+
3030
+ static merge(toArr, fromArr) {
3031
+ (fromArr || []).map((from) => {
3032
+ const found = toArr.find((to) => {
3033
+ return metadata_isSame(to.key, from.key)
3034
+ })
3035
+ if (found) {
3036
+ found.value = metadata_mergeValues(from.value, found.value)
3037
+ } else {
3038
+ toArr.push(from)
3039
+ }
3040
+ })
3041
+ return toArr
3042
+ }
3043
+ static sameKey(item, key) {
3044
+ return metadata_isSame(item.key, key)
3045
+ }
3046
+ }
3047
+
3048
+ function metadata_isSame(key1, key2) {
3049
+ return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
3050
+ }
3051
+
3052
+ function metadata_mergeValues(existingValue, newValue) {
3053
+ if (existingValue === undefined) return newValue
3054
+
3055
+ // Handle arrays by concatenating
3056
+ if (Array.isArray(existingValue) && Array.isArray(newValue)) {
3057
+ return [...new Set([...existingValue, ...newValue])]
3058
+ }
3059
+
3060
+ // Handle objects by merging
3061
+ if (typeof existingValue === 'object' && typeof newValue === 'object' &&
3062
+ !Array.isArray(existingValue) && !Array.isArray(newValue)) {
3063
+ return { ...existingValue, ...newValue }
3064
+ }
3065
+
3066
+ // // Handle numbers by adding
3067
+ // if (typeof existingValue === 'number' && typeof newValue === 'number') {
3068
+ // return existingValue
3069
+ // }
3070
+
3071
+ // // Handle strings by concatenating
3072
+ // if (typeof existingValue === 'string' && typeof newValue === 'string') {
3073
+ // return existingValue
3074
+ // }
3075
+
3076
+ // Default: use the new value
3077
+ return newValue
3078
+ }
3079
+
3080
+
3081
+
3082
+ ;// ./lib/models/metadata/index.js
3083
+
3084
+
3085
+
3086
+
3087
+ ;// ./lib/models/qMeta/qMeta.js
3088
+
3089
+
3090
+ const updateAllowedProps = [
3091
+ 'attributes',
3092
+ 'ref'
3093
+ ]
3094
+
3095
+ class QMeta {
3096
+ constructor(options = {}) {
3097
+ options = options || {}
3098
+ this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
3099
+ this.ref = options.ref || {}
3100
+ }
3101
+
3102
+ static get _classname() {
3103
+ return 'QMeta'
3104
+ }
3105
+ static get _superclass() {
3106
+ return 'QMeta'
3107
+ }
3108
+
3109
+ // Class methods
3110
+ static init(options = {}) {
3111
+ if (options instanceof QMeta) {
3112
+ return options
3113
+ }
3114
+ return new QMeta(options)
3115
+ }
3116
+
3117
+ // instance methods
3118
+ addAttribute(obj) {
3119
+ const kvObject = KeyValueObject.init(obj)
3120
+ if (!kvObject) {
3121
+ throw new Error('invalid meta attribute')
3122
+ }
3123
+ this.attributes.push(kvObject)
3124
+ return this
3125
+ }
3126
+
3127
+ update(obj) {
3128
+ Object.keys(obj).forEach((key) => {
3129
+ if (updateAllowedProps.includes(key)) {
3130
+ if (key === 'attributes') {
3131
+ this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
3132
+ } else {
3133
+ this[key] = obj[key]
3134
+ }
3135
+ }
3136
+ })
3137
+ return this
3138
+ }
3139
+ }
3140
+
3141
+
3142
+
3143
+ ;// ./lib/models/qMeta/index.js
3144
+
3145
+
3146
+
3147
+
3148
+ ;// ./lib/models/trackedEntity/trackedEntity.js
3149
+
3150
+
3151
+ class TrackedEntity {
3152
+ constructor(options = {}) {
3153
+ options = options || {}
3154
+ const timestamp = Date.now()
3155
+ const _tracking = {
3156
+ active: options.active ?? true,
3157
+ created: options.created ?? timestamp,
3158
+ creator: options.creator ?? '',
3159
+ deleted: options.deleted ?? false,
3160
+ modified: options.modified ?? timestamp,
3161
+ owner: options.owner ?? '',
3162
+ }
3163
+
3164
+ this.meta = { ..._tracking, ...options.meta }
3165
+
3166
+ // if (trackFlat) {
3167
+ // Object.assign(this, _tracking)
3168
+ // } else {
3169
+ // this.meta = { ..._tracking, ...options.meta }
3170
+ // }
3171
+ }
3172
+
3173
+ // Class methods
3174
+ static get _classname() {
3175
+ return 'TrackedEntity'
3176
+ }
3177
+ static get _superclass() {
3178
+ return 'TrackedEntity'
3179
+ }
3180
+
3181
+ static init(options = {}) {
3182
+ return init(this, options)
3183
+ }
3184
+ static initFromArray(arr = []) {
3185
+ return initFromArray(this, arr)
3186
+ }
3187
+ static initOnlyValidFromArray(arr = []) {
3188
+ return initOnlyValidFromArray(this, arr)
3189
+ }
3190
+ // static nest(entity) {
3191
+ // const { active, created, creator, deleted, modified, owner, ...rest } = entity
3192
+ // return { ...rest, meta: { active, created, creator, deleted, modified, owner } }
3193
+ // }
3194
+
3195
+ // getters
3196
+ get isValid() {
3197
+ return !!this
3198
+ }
3199
+ get active() {
3200
+ return this.meta?.active ?? this.active
3201
+ }
3202
+ get created() {
3203
+ return this.meta?.created ?? this.created
3204
+ }
3205
+ get creator() {
3206
+ return this.meta?.creator ?? this.creator
3207
+ }
3208
+ get deleted() {
3209
+ return this.meta?.deleted ?? this.deleted
3210
+ }
3211
+ get modified() {
3212
+ return this.meta?.modified ?? this.modified
3213
+ }
3214
+ get owner() {
3215
+ return this.meta?.owner ?? this.owner
3216
+ }
3217
+ changeCreatorOwner({ source, target }) {
3218
+ return changeCreatorOwner(this, { source, target }).setModified()
3219
+ }
3220
+ delete() {
3221
+ return this.setDeleted()
3222
+ }
3223
+ setActive() {
3224
+ if (this.meta) {
3225
+ this.meta.active = true
3226
+ } else {
3227
+ this.active = true
3228
+ }
3229
+ return this
3230
+ }
3231
+ setDeleted() {
3232
+ if (this.meta) {
3233
+ this.meta.deleted = true
3234
+ } else {
3235
+ this.deleted = true
3236
+ }
3237
+ return this
3238
+ }
3239
+ setModified() {
3240
+ const timestamp = Date.now()
3241
+ if (this.meta) {
3242
+ this.meta.modified = timestamp
3243
+ } else {
3244
+ this.modified = timestamp
3245
+ }
3246
+ return this
3247
+ }
3248
+ setOwner(owner) {
3249
+ if (!owner) {
3250
+ return this
3251
+ }
3252
+ if (this.meta) {
3253
+ this.meta.owner = owner
3254
+ } else {
3255
+ this.owner = owner
3256
+ }
3257
+ return this
3258
+ }
3259
+ unsetActive() {
3260
+ if (this.meta) {
3261
+ this.meta.active = false
3262
+ } else {
3263
+ this.active = false
3264
+ }
3265
+ return this
3266
+ }
3267
+ unsetDeleted() {
3268
+ if (this.meta) {
3269
+ this.meta.deleted = false
3270
+ } else {
3271
+ this.deleted = false
3272
+ }
3273
+ return this
3274
+ }
3275
+
3276
+ update(update) {
3277
+ if (update.meta) {
3278
+ this.meta = { ...this.meta, ...update.meta }
3279
+ }
3280
+ return this.setModified()
3281
+ }
3282
+ }
3283
+
3284
+ ;// ./lib/models/trackedEntity/index.js
3285
+
3286
+ // Explicit named export (optional)
3287
+
3288
+ ;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
3289
+
3290
+
3291
+
3292
+
3293
+ class TenantAwareEntity extends TrackedEntity {
3294
+ constructor(options = {}) {
3295
+ options = options || {}
3296
+
3297
+ /**
3298
+ * instead of throw error, we choose to implement the isValid checking
3299
+ */
3300
+ // if (!options.tenantCode) {
3301
+ // throw new Error('tenantCode required')
3302
+ // }
3303
+
3304
+ super(options)
3305
+
3306
+ this._tenant = options._tenant
3307
+
3308
+ this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
3309
+ this.remarks = KeyValueObject.initOnlyValidFromArray(options.remarks)
3310
+ this.tenantCode = options.tenantCode // Required for multi-tenancy
3311
+ }
3312
+
3313
+ // Class methods
3314
+ static get _classname() {
3315
+ return 'TenantAwareEntity'
3316
+ }
3317
+ static get _superclass() {
3318
+ return 'TenantAwareEntity'
3319
+ }
3320
+
3321
+ // getters
3322
+ get isValid() {
3323
+ return super.isValid && !!this.tenantCode // Required for multi-tenancy
3324
+ }
3325
+
3326
+ // instance methods
3327
+ getMetadata() {
3328
+ return this.metadata
3329
+ }
3330
+ getMetadataByKey(key) {
3331
+ return Metadata.foundByKey(this.metadata, key)
3332
+ }
3333
+ getMetadataValueByKey(key) {
3334
+ const found = this.getMetadataByKey(key)
3335
+ return found ? found.value : null
3336
+ }
3337
+ getRemarks() {
3338
+ return this.remarks
3339
+ }
3340
+ getRemarkByKey(key) {
3341
+ return KeyValueObject.foundByKey(this.remarks, key)
3342
+ }
3343
+ getRemarksValueByKey(key) {
3344
+ const found = this.getRemarkByKey(key)
3345
+ return found ? found.value : null
3346
+ }
3347
+ getTenantCode() {
3348
+ return this.tenantCode
3349
+ }
3350
+
3351
+ update(update) {
3352
+ if (update.metadata && Array.isArray(update.metadata)) {
3353
+ this.metadata = Metadata.initOnlyValidFromArray(update.metadata)
3354
+ }
3355
+ if (update.remarks && Array.isArray(update.remarks)) {
3356
+ this.remarks = KeyValueObject.initOnlyValidFromArray(update.remarks)
3357
+ }
3358
+ return super.update(update)
3359
+ }
3360
+ }
3361
+
3362
+ ;// ./lib/models/tenantAwareEntity/index.js
3363
+
3364
+
3365
+
3366
+ ;// ./lib/models/uniqueKeyGenerator/uniqueKeyGenerator.js
3367
+
3368
+
3369
+ class UniqueKeyGenerator {
3370
+ static get _classname() {
3371
+ return 'UniqueKeyGenerator'
3372
+ }
3373
+ static get _superclass() {
3374
+ return 'UniqueKeyGenerator'
3375
+ }
3376
+ static makeFormatter({ fieldName, format, options }) {
3377
+ switch (format) {
3378
+ case 'set_code':
3379
+ return _makeSetCode(fieldName, options)
3380
+ default:
3381
+ return _makeSetCode(fieldName, options)
3382
+ }
3383
+ }
3384
+ static makeGenerator(arr) {
3385
+ const fns = arr.map((item) => this.makeFormatter(item))
3386
+ return async (obj) => {
3387
+ const output = await pReduce(fns, async (acc, fn) => {
3388
+ const _obj = await fn(obj)
3389
+ return Object.assign(acc, _obj)
3390
+ }, obj)
3391
+ return output
3392
+ }
3393
+ }
3394
+ }
3395
+
3396
+ function _makeSetCode(fieldName, options) {
3397
+ return async (obj = {}) => {
3398
+ if (obj[fieldName]) {
3399
+ return {}
3400
+ }
3401
+ return {
3402
+ [fieldName]: stringHelper.setCode()
3403
+ }
3404
+ }
3405
+ }
3406
+
3407
+
3408
+
3409
+ ;// ./lib/models/uniqueKeyGenerator/index.js
3410
+
3411
+
3412
+
3413
+
3414
+ ;// ./lib/models/index.js
3415
+
3416
+
3417
+
3418
+
3419
+
3420
+
3421
+
3422
+
3423
+
3424
+
3425
+
3426
+
3427
+ ;// ./lib/index.js
3428
+
3429
+
3430
+
3431
+ ;// ./index.js
3432
+
3433
+
3434
+ export { ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, stringFormatter, stringHelper, trackingPlugin };