@questwork/q-utilities 0.1.16 → 0.1.18

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