@questwork/q-utilities 0.1.18 → 0.1.19

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