@questwork/q-utilities 0.1.30 → 0.1.32

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,4744 +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 {
7
- var a = factory();
8
- for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
9
- }
10
- })(this, () => {
11
- return /******/ (() => { // webpackBootstrap
12
- /******/ "use strict";
13
- /******/ // The require scope
14
- /******/ var __webpack_require__ = {};
15
- /******/
16
- /************************************************************************/
17
- /******/ /* webpack/runtime/define property getters */
18
- /******/ (() => {
19
- /******/ // define getter functions for harmony exports
20
- /******/ __webpack_require__.d = (exports, definition) => {
21
- /******/ for(var key in definition) {
22
- /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
23
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
24
- /******/ }
25
- /******/ }
26
- /******/ };
27
- /******/ })();
28
- /******/
29
- /******/ /* webpack/runtime/hasOwnProperty shorthand */
30
- /******/ (() => {
31
- /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
32
- /******/ })();
33
- /******/
34
- /******/ /* webpack/runtime/make namespace object */
35
- /******/ (() => {
36
- /******/ // define __esModule on exports
37
- /******/ __webpack_require__.r = (exports) => {
38
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
39
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
40
- /******/ }
41
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
42
- /******/ };
43
- /******/ })();
44
- /******/
45
- /************************************************************************/
46
- var __webpack_exports__ = {};
47
- // ESM COMPAT FLAG
48
- __webpack_require__.r(__webpack_exports__);
49
-
50
- // EXPORTS
51
- __webpack_require__.d(__webpack_exports__, {
52
- ActionRecord: () => (/* reexport */ ActionRecord),
53
- ApiResponse: () => (/* reexport */ ApiResponse),
54
- AwsStsS3Client: () => (/* reexport */ AwsStsS3Client),
55
- KeyValueObject: () => (/* reexport */ keyValueObject_KeyValueObject),
56
- Metadata: () => (/* reexport */ Metadata),
57
- PushEnvelope: () => (/* reexport */ PushEnvelope),
58
- QMeta: () => (/* reexport */ QMeta),
59
- Repo: () => (/* reexport */ Repo),
60
- Service: () => (/* reexport */ Service),
61
- Status: () => (/* reexport */ Status),
62
- StatusDocument: () => (/* reexport */ StatusDocument),
63
- TemplateCompiler: () => (/* reexport */ TemplateCompiler),
64
- TenantAwareEntity: () => (/* reexport */ TenantAwareEntity),
65
- TrackedEntity: () => (/* reexport */ TrackedEntity),
66
- UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
67
- authorize: () => (/* reexport */ authorize),
68
- bwipJsHelper: () => (/* reexport */ bwipJsHelper),
69
- calculateAge: () => (/* reexport */ calculateAge),
70
- changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
71
- concatStringByArray: () => (/* reexport */ concatStringByArray),
72
- convertString: () => (/* reexport */ convertString),
73
- detectControlCharacters: () => (/* reexport */ detectControlCharacters),
74
- downloadFileByUrl: () => (/* reexport */ downloadFileByUrl),
75
- escapeRegex: () => (/* reexport */ escapeRegex),
76
- expressHelper: () => (/* reexport */ expressHelper),
77
- extractEmails: () => (/* reexport */ extractEmails),
78
- formatDate: () => (/* reexport */ formatDate),
79
- generalPost: () => (/* reexport */ generalPost),
80
- getObjectByArr: () => (/* reexport */ getObjectByArr),
81
- getValidation: () => (/* reexport */ getValidation),
82
- getValueByKeys: () => (/* reexport */ getValueByKeys_getValueByKeys),
83
- groupArrayByKey: () => (/* reexport */ groupArrayByKey),
84
- init: () => (/* reexport */ init),
85
- initFromArray: () => (/* reexport */ initFromArray),
86
- initOnlyValidFromArray: () => (/* reexport */ initOnlyValidFromArray),
87
- isConvertibleToNumber: () => (/* reexport */ isConvertibleToNumber),
88
- makeApiResponse: () => (/* reexport */ makeApiResponse),
89
- makeService: () => (/* reexport */ makeService),
90
- mergeArraysByKey: () => (/* reexport */ mergeArraysByKey),
91
- objectHelper: () => (/* reexport */ objectHelper),
92
- pMap: () => (/* reexport */ pMap),
93
- pMapIterable: () => (/* reexport */ pMapIterable),
94
- pMapSkip: () => (/* reexport */ pMapSkip),
95
- pReduce: () => (/* reexport */ pReduce),
96
- padZeros: () => (/* reexport */ padZeros),
97
- printControlCharReport: () => (/* reexport */ printControlCharReport),
98
- replacePlaceholders: () => (/* reexport */ replacePlaceholders),
99
- sanitizeText: () => (/* reexport */ sanitizeText),
100
- shuffleArray: () => (/* reexport */ shuffleArray),
101
- stringFormatter: () => (/* reexport */ stringFormatter),
102
- stringHelper: () => (/* reexport */ stringHelper),
103
- tenantPlugin: () => (/* reexport */ tenantPlugin),
104
- trackingPlugin: () => (/* reexport */ trackingPlugin)
105
- });
106
-
107
- ;// ./lib/helpers/authorize/authorize.js
108
- function authorize({ allowCoordinator, allowOwner, query = {}, required, user }) {
109
- if (!user) {
110
- throw new Error('Require login.')
111
- }
112
- if (!user.permission) {
113
- // throw new Error('You do not have any permission.')
114
- }
115
- const scopes = user.permission.getScopes(required || {}) || []
116
- if (!scopes || scopes.length === 0) {
117
- // throw new Error('You are not allowed in this scope.')
118
- }
119
- if (!scopes.includes('*')) {
120
- query.tenantCode = user.tenantCode
121
- }
122
- if (!scopes.includes('TENANT')) {
123
- query.eventShortCode = user.eventShortCode
124
- }
125
- // if (!scopes.includes('EVENT')) {
126
- // query.eventRegistrationCode = user.eventRegistrationCode
127
- // }
128
- if (allowCoordinator) {
129
- if (query.registrationGroupCode && user.myManagedRegistrationGroupCodes.includes(query.registrationGroupCode)) {
130
- query.__ALLOW_COORDINATOR = true
131
- } else {
132
- if (!scopes.includes('EVENT')) {
133
- query.eventRegistrationCode = user.eventRegistrationCode
134
- }
135
- }
136
- } else {
137
- if (!scopes.includes('EVENT')) {
138
- query.eventRegistrationCode = user.eventRegistrationCode
139
- }
140
- }
141
- if (allowOwner) {
142
- query.__ALLOW_OWNER = true
143
- }
144
- // not good, just use it as example
145
- if (user.hasExcludedFields) {
146
- query.__EXCLUDED_FIELDS = user.getExcludedFields(required)
147
- }
148
- query.__LOGIN_SUBJECT_CODE = user.loginSubjectCode
149
- return query
150
- }
151
-
152
- ;// ./lib/helpers/authorize/index.js
153
-
154
-
155
- ;// external "bwip-js"
156
- const external_bwip_js_namespaceObject = require("bwip-js");
157
- ;// ./lib/helpers/bwipJsHelper/toDataUrlInBrowser.js
158
-
159
-
160
- function toDataUrlInBrowser({ config = {}, type = 'image/png' }) {
161
- const canvas = document.createElement('canvas')
162
- external_bwip_js_namespaceObject.toCanvas(canvas, {
163
- bcid: 'qrcode',
164
- text: '',
165
- ...config
166
- })
167
- return canvas.toDataURL(type)
168
- }
169
-
170
- /* harmony default export */ const bwipJsHelper_toDataUrlInBrowser = ({
171
- toDataUrlInBrowser
172
- });
173
-
174
-
175
- ;// ./lib/helpers/bwipJsHelper/index.js
176
-
177
-
178
- const bwipJsHelper = {
179
- toDataUrlInBrowser: toDataUrlInBrowser
180
- }
181
-
182
- ;// ./lib/helpers/calculateAge/calculateAge.js
183
- function calculateAge(timestamp, reference) {
184
- const birthDate = new Date(timestamp)
185
- const refDate = reference ? new Date(reference) : new Date()
186
- // Validate inputs
187
- if (isNaN(birthDate.getTime())) {
188
- return null
189
- }
190
- if (isNaN(refDate.getTime())) {
191
- return null
192
- }
193
- if (birthDate > refDate) {
194
- return null
195
- }
196
-
197
- // Calculate raw difference
198
- let age = refDate.getFullYear() - birthDate.getFullYear()
199
- const monthDiff = refDate.getMonth() - birthDate.getMonth()
200
-
201
- // Adjust if birthday hasn't occurred yet this year
202
- if (monthDiff < 0 || (monthDiff === 0 && refDate.getDate() < birthDate.getDate())) {
203
- age--
204
- }
205
-
206
- return age
207
- }
208
-
209
- ;// ./lib/helpers/calculateAge/index.js
210
-
211
-
212
- ;// ./lib/helpers/changeCreatorOwner/changeCreatorOwner.js
213
- function changeCreatorOwner(that, { source, target }) {
214
- if (that.meta) {
215
- if (!that.meta.creator || that.meta.creator === source.getId()) {
216
- that.meta.creator = target.getId()
217
- }
218
- if (!that.meta.owner || that.meta.owner === source.getId()) {
219
- that.meta.owner = target.getId()
220
- }
221
- } else {
222
- if (!that.creator || that.creator === source.getId()) {
223
- that.creator = target.getId()
224
- }
225
- if (!that.owner || that.owner === source.getId()) {
226
- that.owner = target.getId()
227
- }
228
- }
229
- return that
230
- }
231
-
232
- ;// ./lib/helpers/changeCreatorOwner/index.js
233
-
234
-
235
- ;// ./lib/helpers/isConvertibleToNumber/isConvertibleToNumber.js
236
- function isConvertibleToNumber(value) {
237
- return value !== null
238
- && value !== undefined
239
- && typeof value !== 'boolean'
240
- && String(value).trim() !== ''
241
- && !isNaN(Number(value))
242
- }
243
-
244
- ;// ./lib/helpers/getValueByKeys/getValueByKeys.js
245
- // keys can be array or object or string
246
- function getValueByKeys_getValueByKeys(keys, data) {
247
- let _keys = keys
248
- let _data = data
249
- if (typeof keys === 'string') {
250
- _keys = _keys.split('.')
251
- }
252
- if (!Array.isArray(keys) && typeof keys === 'object') {
253
- const { keys: keyArr, obj } = keys
254
- _keys = keyArr
255
- _data = obj
256
- }
257
- if (_keys.length === 0) {
258
- return _data
259
- }
260
- const firstKey = _keys.shift()
261
- if (_data && Object.prototype.hasOwnProperty.call(_data, firstKey)) {
262
- return getValueByKeys_getValueByKeys(_keys, _data[firstKey])
263
- }
264
- if (_data && firstKey) {
265
- if (_keys.length > 0) {
266
- return getValueByKeys_getValueByKeys(_keys, _data[firstKey])
267
- }
268
- return _data[firstKey]
269
- }
270
- return _data
271
- }
272
- /* harmony default export */ const getValueByKeys = ({
273
- getValueByKeys: getValueByKeys_getValueByKeys
274
- });
275
-
276
-
277
- ;// ./lib/helpers/getValueByKeys/index.js
278
-
279
-
280
- ;// ./lib/models/apiResponse/apiResponse.js
281
- class ApiResponse {
282
- constructor(options = {}) {
283
- options = options || {}
284
- this._data = options.data || options._data || []
285
- this.err = options.err
286
- this.isNew = options.isNew || false
287
- this.message = options.message
288
- this.total = options.total || 0
289
- this._instanceBuilder = options._instanceBuilder
290
- }
291
-
292
- static init(options = {}) {
293
- if (options instanceof this) {
294
- return options
295
- }
296
- const instance = new this(options)
297
- return instance
298
- }
299
- static get _classname() {
300
- return 'ApiResponse'
301
- }
302
- static get _superclass() {
303
- return 'ApiResponse'
304
- }
305
-
306
- // getters
307
- get data() {
308
- if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
309
- return this._data.map(this._instanceBuilder)
310
- }
311
- return this._data
312
- }
313
- }
314
-
315
-
316
-
317
- ;// ./lib/models/apiResponse/makeApiResponse.js
318
-
319
-
320
- function makeApiResponse({ repo, result }) {
321
- return ApiResponse.init({
322
- ...result,
323
- _instanceBuilder: (i) => {
324
- return repo.init(i)
325
- }
326
- })
327
- }
328
-
329
-
330
-
331
- ;// ./lib/models/apiResponse/index.js
332
-
333
-
334
-
335
-
336
-
337
- ;// ./lib/models/awsStsS3Client/awsStsS3Client.js
338
- class AwsStsS3Client {
339
- constructor(options) {
340
- options = options || {}
341
-
342
- this.expiration = options.expiration || null
343
- this.s3Client = options.s3Client || null
344
- this.getIdToken = options.getIdToken
345
- this.region = options.region || 'ap-east-1'
346
- this.roleArn = options.roleArn
347
- this.roleSessionName = options.roleSessionName || 'web-identity-session'
348
- this.durationSession = options.durationSession || 3600
349
- this.awsClientSts = options.awsClientSts
350
- this.awsClientS3 = options.awsClientS3
351
- }
352
-
353
- static dummyData() {
354
- return {
355
- getIdToken: () => 'mock-web-identity-token',
356
- roleArn: 'arn:aws:iam::846252828949:role/oidcS3Jccpa',
357
- awsClientSts: {
358
- STSClient: class {},
359
- AssumeRoleWithWebIdentityCommand: class {}
360
- },
361
- awsClientS3: {
362
- S3Client: class {},
363
- PutObjectCommand: class {},
364
- GetObjectCommand: class {},
365
- DeleteObjectCommand: class {}
366
- }
367
- }
368
- }
369
-
370
- static init(options = {}) {
371
- if (options instanceof this) {
372
- return options
373
- }
374
- try {
375
- const instance = new this(options)
376
- if (!instance.isValid) {
377
- return null
378
- }
379
- return instance
380
- } catch (error) {
381
- return null
382
- }
383
- }
384
-
385
- get isExpired() {
386
- if (!this.expiration)
387
- return true
388
- const now = new Date()
389
- const bufferMs = 1 * 60 * 1000 // 一分钟缓冲
390
- return now >= new Date(this.expiration.getTime() - bufferMs)
391
- }
392
-
393
- get isValid() {
394
- if (!this.getIdToken) {
395
- throw new Error('Missing required configuration: getIdToken function')
396
- }
397
- if (!this.roleArn) {
398
- throw new Error('Missing required configuration: roleArn')
399
- }
400
- if (!this.awsClientSts) {
401
- throw new Error('Missing required AWS awsClientSts client configuration')
402
- }
403
- if (!this.awsClientSts.STSClient) {
404
- throw new Error('Missing STSClient in AWS awsClientSts client configuration')
405
- }
406
- if (!this.awsClientSts.AssumeRoleWithWebIdentityCommand) {
407
- throw new Error('Missing AssumeRoleWithWebIdentityCommand in AWS awsClientSts client configuration')
408
- }
409
- if (!this.awsClientS3) {
410
- throw new Error('Missing required AWS awsClientS3 client configuration')
411
- }
412
-
413
- const requiredS3Components = [
414
- 'S3Client',
415
- 'PutObjectCommand',
416
- 'GetObjectCommand',
417
- 'DeleteObjectCommand'
418
- ]
419
-
420
- for (const component of requiredS3Components) {
421
- if (!this.awsClientS3[component]) {
422
- throw new Error(`Missing ${component} in AWS awsClientS3 client configuration`)
423
- }
424
- }
425
-
426
- return true
427
- }
428
-
429
- async refreshCredentials() {
430
- try {
431
- const webIdentityToken = await this.getIdToken()
432
- if (!webIdentityToken) {
433
- throw new Error('getIdToken function returned empty or invalid token')
434
- }
435
-
436
- const stsClient = new this.awsClientSts.STSClient({ region: this.region })
437
-
438
- const stsResponse = await stsClient.send(
439
- new this.awsClientSts.AssumeRoleWithWebIdentityCommand({
440
- RoleArn: this.roleArn,
441
- RoleSessionName: this.roleSessionName,
442
- WebIdentityToken: await this.getIdToken(),
443
- DurationSeconds: this.durationSession,
444
- })
445
- )
446
-
447
- const credentials = stsResponse.Credentials
448
- if (!credentials) {
449
- throw new Error('No credentials returned from awsClientSts')
450
- }
451
-
452
- this.expiration = credentials.Expiration
453
-
454
- this.s3Client = new this.awsClientS3.S3Client({
455
- region: this.region,
456
- credentials: {
457
- accessKeyId: credentials.AccessKeyId,
458
- secretAccessKey: credentials.SecretAccessKey,
459
- sessionToken: credentials.SessionToken,
460
- }
461
- })
462
-
463
- return this
464
- } catch (error) {
465
- throw new Error(`Failed to refresh credentials: ${error.message}`)
466
- }
467
- }
468
-
469
- async getS3Client() {
470
- if (this.isExpired || !this.s3Client) {
471
- await this.refreshCredentials()
472
- }
473
- return this.s3Client
474
- }
475
-
476
- async putObject(params) {
477
- try {
478
- const client = await this.getS3Client()
479
- const command = new this.awsClientS3.PutObjectCommand(params)
480
- await client.send(command)
481
- const fileArr = params.Key.split('/')
482
- return {
483
- url: `https://s3.${this.region}.amazonaws.com/${params.Bucket}/${params.Key}`,
484
- filename: fileArr.pop(),
485
- folder: params.Bucket,
486
- subFolders: fileArr
487
- }
488
- } catch (error) {
489
- throw new Error(`Failed to put object: ${error.message}`)
490
- }
491
- }
492
-
493
- async getObject(params) {
494
- try {
495
- const client = await this.getS3Client()
496
- const command = new this.awsClientS3.GetObjectCommand(params)
497
- const response = await client.send(command)
498
- return {
499
- body: response.Body,
500
- contentType: response.ContentType,
501
- lastModified: response.LastModified,
502
- contentLength: response.ContentLength,
503
- }
504
- } catch (error) {
505
- throw new Error(`Failed to get object: ${error.message}`)
506
- }
507
- }
508
-
509
- async deleteObject(params) {
510
- try {
511
- const client = await this.getS3Client()
512
- const command = new this.awsClientS3.DeleteObjectCommand(params)
513
- await client.send(command)
514
- return true
515
- } catch (error) {
516
- throw new Error(`Failed to delete object: ${error.message}`)
517
- }
518
- }
519
- }
520
-
521
-
522
-
523
- ;// ./lib/models/awsStsS3Client/index.js
524
-
525
-
526
-
527
-
528
- ;// ./lib/helpers/objectHelper/objectHelper.js
529
- const objectHelper = {
530
- get(obj, path) {
531
- const parts = path.split('.')
532
- return parts.reduce((acc, part) => {
533
- if (part.endsWith('[]')) {
534
- // 处理数组遍历
535
- const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
536
- if (Array.isArray(acc[key])) {
537
- return acc[key] // 返回整个数组
538
- }
539
- return [] // 如果不是数组,返回空数组
540
- }
541
- if (part.includes('[') && part.includes(']')) {
542
- // 处理数组索引
543
- const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
544
- if (arrayMatch) {
545
- const key = arrayMatch[1]
546
- const index = arrayMatch[2]
547
- return acc && acc[key] && acc[key][index]
548
- }
549
- } else if (acc && Array.isArray(acc)) {
550
- // 如果当前值是数组,提取每个对象的指定属性
551
- return acc.map((item) => item[part])
552
- } else {
553
- // 处理普通属性
554
- return acc && acc[part]
555
- }
556
- }, obj)
557
- },
558
- isPlainObject,
559
- merge,
560
- set(obj, path, value) {
561
- const parts = path.split('.')
562
- let current = obj
563
-
564
- // 处理所有中间部分
565
- for (let i = 0; i < parts.length - 1; i++) {
566
- const part = parts[i]
567
- let key, index
568
-
569
- // 检查是否是数组索引格式,如key[0]
570
- const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/)
571
- if (arrayMatch) {
572
- key = arrayMatch[1]
573
- index = Number.parseInt(arrayMatch[2], 10)
574
- // 确保当前层级的数组存在
575
- if (!current[key] || !Array.isArray(current[key])) {
576
- current[key] = []
577
- }
578
- // 扩展数组到足够大
579
- while (current[key].length <= index) {
580
- current[key].push(undefined)
581
- }
582
- // 如果当前位置未定义或为null,初始化为对象
583
- if (current[key][index] == null) {
584
- current[key][index] = {}
585
- }
586
- current = current[key][index]
587
- } else {
588
- // 处理普通属性
589
- if (!current[part]) {
590
- current[part] = {}
591
- }
592
- current = current[part]
593
- }
594
- }
595
-
596
- // 处理最后一部分
597
- const lastPart = parts[parts.length - 1]
598
- const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/)
599
- if (arrayMatch) {
600
- const key = arrayMatch[1]
601
- const index = Number.parseInt(arrayMatch[2], 10)
602
- // 确保数组存在
603
- if (!current[key] || !Array.isArray(current[key])) {
604
- current[key] = []
605
- }
606
- // 扩展数组到所需索引
607
- while (current[key].length <= index) {
608
- current[key].push(undefined)
609
- }
610
- current[key][index] = value
611
- } else {
612
- current[lastPart] = value
613
- }
614
- }
615
- }
616
-
617
- function isPlainObject(value) {
618
- return (
619
- value !== null
620
- && typeof value === 'object'
621
- && !Array.isArray(value) &&
622
- !(value instanceof Date) &&
623
- !(value instanceof RegExp) &&
624
- // Optional: exclude other built-in objects
625
- Object.prototype.toString.call(value) === '[object Object]'
626
- )
627
- }
628
-
629
- function merge(target, ...sources) {
630
- if (!sources.length)
631
- return target
632
-
633
- const source = sources.shift() // 取出第一个源对象
634
-
635
- if (_isObject(target) && _isObject(source)) {
636
- for (const key in source) {
637
- if (_isObject(source[key])) {
638
- if (!target[key]) {
639
- // 如果目标对象没有该属性,创建一个空对象
640
- target[key] = {}
641
- }
642
- // 递归合并
643
- merge(target[key], source[key])
644
- } else {
645
- // 直接覆盖
646
- target[key] = source[key]
647
- }
648
- }
649
- }
650
-
651
- // 继续合并剩余的源对象
652
- return merge(target, ...sources)
653
- }
654
-
655
- function _isObject(obj) {
656
- return obj && typeof obj === 'object' && !Array.isArray(obj)
657
- }
658
-
659
-
660
-
661
- ;// ./lib/helpers/objectHelper/index.js
662
-
663
-
664
-
665
-
666
- ;// ./lib/models/keyValueObject/keyValueObject.js
667
-
668
-
669
- class keyValueObject_KeyValueObject {
670
- constructor(options = {}) {
671
- options = options || {}
672
- this.key = options.key || null
673
- this.value = (typeof options.value !== 'undefined') ? options.value : ''
674
- }
675
-
676
- // Class methods
677
- static init(options = {}) {
678
- if (options instanceof this) {
679
- return options
680
- }
681
- const instance = new this(options)
682
- return instance.isValid ? instance : null
683
- }
684
- static initFromArray(arr = []) {
685
- if (Array.isArray(arr)) {
686
- return arr.map((a) => this.init(a))
687
- }
688
- return []
689
- }
690
- static initOnlyValidFromArray(arr = []) {
691
- return this.initFromArray(arr).filter((i) => i)
692
- }
693
- static get _classname() {
694
- return 'KeyValueObject'
695
- }
696
- static get _superclass() {
697
- return 'KeyValueObject'
698
- }
699
-
700
- static addItem(arr, key, value) {
701
- arr.push(this.init({ key, value }))
702
- }
703
- static addRecord(arr = [], key, value) {
704
- if (!this.hasKeyValue(arr, key, value)) {
705
- arr.push(this.init({ key, value }))
706
- }
707
- return arr
708
- }
709
- static appendRecord(arr = [], key, value) {
710
- return arr.map((item) => {
711
- if (this.sameKey(item, key)) {
712
- item.value = [...item.value, ...value]
713
- }
714
- return item
715
- })
716
- }
717
- static appendValueArray(arr = [], key, value) {
718
- return arr.map((item) => {
719
- if (this.sameKey(item, key)) {
720
- item.value = [...item.value, ...value]
721
- }
722
- return item
723
- })
724
- }
725
- static foundByKey(arr = [], key) {
726
- const found = arr.find((m) => {
727
- return this.sameKey(m, key)
728
- })
729
- return found || null
730
- }
731
- static foundValueByKey(arr = [], key) {
732
- const found = this.foundByKey(arr, key)
733
- return found ? found.value : null
734
- }
735
- static fromObject(options = {}) {
736
- return Object.keys(options).reduce((acc, key) => {
737
- acc.push(this.init({ key, value: options[key] }))
738
- return acc
739
- }, [])
740
- }
741
- static getValueByKey(arr = [], key) {
742
- return this.foundValueByKey(arr, key)
743
- }
744
- static getMetadataValueByKeyAsArray(arr = [], key) {
745
- const _value = this.getValueByKey(arr, key)
746
- if (!_value) {
747
- return []
748
- }
749
- if (objectHelper.isPlainObject(_value)) {
750
- return Object.keys(_value).reduce((acc, key) => {
751
- acc.push({ key, value: _value[key] })
752
- return acc
753
- }, [])
754
- }
755
- return _value
756
- }
757
- static getValueByKeyFromArray(arr = [], key) {
758
- if (arr.length === 0) {
759
- return null
760
- }
761
- const firstArr = arr.shift()
762
- const found = firstArr.find((i) => {
763
- return this.sameKey(i, key)
764
- })
765
- if (found && found.value) {
766
- return found.value
767
- }
768
- return this.getValueByKeyFromArray(arr, key)
769
- }
770
- static getValuesByKey(arr = [], key) {
771
- return arr.reduce((acc, item) => {
772
- if (this.sameKey(item, key)) {
773
- acc.push(item.value)
774
- }
775
- return acc
776
- }, [])
777
- }
778
- static hasKeyValue(arr = [], key, value) {
779
- if (typeof value === 'undefined') {
780
- return arr.filter((item) => this.sameKey(item, key)).length > 0
781
- }
782
- return arr.filter((item) => (this.sameKey(item, key) && _isSame(item.value, value))).length > 0
783
- }
784
- static insertOrUpdateRecord(arr = [], key, value) {
785
- let copy = [...arr]
786
- if (!this.hasKeyValue(arr, key)) {
787
- copy.push(this.init({ key, value }))
788
- } else {
789
- copy = this.updateRecord(arr, key, value)
790
- }
791
- return copy
792
- }
793
- static keys(arr = []) {
794
- if (Array.isArray(arr)) {
795
- return arr.reduce((acc, item) => {
796
- acc.push(item.key)
797
- return acc
798
- }, [])
799
- }
800
- return []
801
- }
802
- static merge(toArr, fromArr) {
803
- (fromArr || []).map((from) => {
804
- const found = toArr.find((to) => {
805
- return to.key === from.key
806
- })
807
- if (found) {
808
- found.value = _mergeValues(from.value, found.value)
809
- } else {
810
- toArr.push(from)
811
- }
812
- })
813
- return toArr
814
- }
815
- static removeByKey(arr, key) {
816
- return arr.reduce((acc, item) => {
817
- if (!this.sameKey(item, key)) {
818
- acc.push(item)
819
- }
820
- return acc
821
- }, [])
822
- }
823
- static sameKey(item, key) {
824
- if (item) {
825
- return _isSame(item.key, key)
826
- }
827
- return false
828
- }
829
- static toObject(arr = []) {
830
- if (Array.isArray(arr)) {
831
- return arr.reduce((acc, item) => {
832
- acc[item.key] = item.value
833
- return acc
834
- }, {})
835
- }
836
- return {}
837
- }
838
- static toString(arr = [], delimiter = '; ') {
839
- if (Array.isArray(arr)) {
840
- return arr.reduce((acc, item) => {
841
- acc.push(`${item.key}: ${item.value}`)
842
- return acc
843
- }, []).join(delimiter)
844
- }
845
- return ''
846
- }
847
- static updateRecord(arr = [], key, value) {
848
- return arr.map((item) => {
849
- if (this.sameKey(item, key)) {
850
- return {
851
- ...item,
852
- value
853
- }
854
- }
855
- return item
856
- })
857
- }
858
- static updateOrInsertRecord(arr = [], key, value) {
859
- return this.insertOrUpdateRecord(arr, key, value)
860
- }
861
- static updateRecordsFromArray(arr = [], updateArr = []) {
862
- if (Array.isArray(arr) && Array.isArray(updateArr)) {
863
- const obj1 = this.toObject(arr)
864
- const obj2 = this.toObject(updateArr)
865
- return this.fromObject({
866
- ...obj1,
867
- ...obj2
868
- })
869
- }
870
- return []
871
- }
872
- static values(arr = []) {
873
- if (Array.isArray(arr)) {
874
- return arr.reduce((acc, item) => {
875
- acc.push(item.value)
876
- return acc
877
- }, [])
878
- }
879
- return []
880
- }
881
-
882
- // getters
883
- get isValid() {
884
- return !!this.key
885
- }
886
-
887
- get toObject() {
888
- const obj = {}
889
- if (this.isValid) {
890
- obj[this.key] = this.value
891
- }
892
- return obj
893
- }
894
- }
895
-
896
- function _mergeValues(existingValue, newValue) {
897
- if (existingValue === undefined)
898
- return newValue
899
-
900
- // Handle arrays by concatenating
901
- if (Array.isArray(existingValue) && Array.isArray(newValue)) {
902
- return [...new Set([...existingValue, ...newValue])]
903
- }
904
-
905
- // Handle objects by merging
906
- if (typeof existingValue === 'object' && typeof newValue === 'object'
907
- && !Array.isArray(existingValue) && !Array.isArray(newValue)) {
908
- return { ...existingValue, ...newValue }
909
- }
910
-
911
- // // Handle numbers by adding
912
- // if (typeof existingValue === 'number' && typeof newValue === 'number') {
913
- // return existingValue
914
- // }
915
-
916
- // // Handle strings by concatenating
917
- // if (typeof existingValue === 'string' && typeof newValue === 'string') {
918
- // return existingValue
919
- // }
920
-
921
- // Default: use the new value
922
- return newValue
923
- }
924
-
925
- function _isSame(key1, key2) {
926
- return key1 === key2
927
- }
928
-
929
-
930
-
931
- ;// ./lib/models/keyValueObject/index.js
932
-
933
-
934
-
935
-
936
- ;// ./lib/helpers/stringFormatter/stringFormatter.js
937
- function stringFormatter(str, delimiter = '_') {
938
- if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
939
- return null
940
- }
941
- return str.toString()
942
- .trim()
943
- .toUpperCase()
944
- .replace('-', delimiter)
945
- .replace(' ', delimiter)
946
- }
947
-
948
-
949
-
950
- ;// ./lib/models/metadata/metadata.js
951
-
952
-
953
-
954
- const DELIMITER = '_'
955
-
956
- class Metadata extends keyValueObject_KeyValueObject {
957
- static init(options = {}) {
958
- if (options instanceof this) {
959
- return options
960
- }
961
- const instance = new this({
962
- ...options,
963
- key: stringFormatter(options.key, DELIMITER),
964
- })
965
- return instance.isValid ? instance : null
966
- }
967
- static get _classname() {
968
- return 'Metadata'
969
- }
970
-
971
- static merge(toArr, fromArr) {
972
- (fromArr || []).map((from) => {
973
- const found = toArr.find((to) => {
974
- return metadata_isSame(to.key, from.key)
975
- })
976
- if (found) {
977
- found.value = metadata_mergeValues(from.value, found.value)
978
- } else {
979
- toArr.push(from)
980
- }
981
- })
982
- return toArr
983
- }
984
- static sameKey(item, key) {
985
- return metadata_isSame(item.key, key)
986
- }
987
- }
988
-
989
- function metadata_isSame(key1, key2) {
990
- return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
991
- }
992
-
993
- function metadata_mergeValues(existingValue, newValue) {
994
- if (existingValue === undefined)
995
- return newValue
996
-
997
- // Handle arrays by concatenating
998
- if (Array.isArray(existingValue) && Array.isArray(newValue)) {
999
- return [...new Set([...existingValue, ...newValue])]
1000
- }
1001
-
1002
- // Handle objects by merging
1003
- if (typeof existingValue === 'object' && typeof newValue === 'object'
1004
- && !Array.isArray(existingValue) && !Array.isArray(newValue)) {
1005
- return { ...existingValue, ...newValue }
1006
- }
1007
-
1008
- // // Handle numbers by adding
1009
- // if (typeof existingValue === 'number' && typeof newValue === 'number') {
1010
- // return existingValue
1011
- // }
1012
-
1013
- // // Handle strings by concatenating
1014
- // if (typeof existingValue === 'string' && typeof newValue === 'string') {
1015
- // return existingValue
1016
- // }
1017
-
1018
- // Default: use the new value
1019
- return newValue
1020
- }
1021
-
1022
-
1023
-
1024
- ;// ./lib/models/metadata/index.js
1025
-
1026
-
1027
-
1028
-
1029
- ;// ./lib/models/trackedEntity/trackedEntity.js
1030
-
1031
-
1032
- class TrackedEntity {
1033
- constructor(options = {}) {
1034
- options = options || {}
1035
- const timestamp = Date.now()
1036
- this.meta = {
1037
- active: options.meta?.active ?? options.active ?? true,
1038
- created: options.meta?.created ?? (options.created
1039
- ? new Date(options.created).getTime()
1040
- : timestamp),
1041
- creator: options.meta?.creator ?? options.creator ?? '',
1042
- deleted: options.meta?.deleted ?? options.deleted ?? false,
1043
- modified: options.meta?.modified ?? (options.modified
1044
- ? new Date(options.modified).getTime()
1045
- : timestamp),
1046
- owner: options.meta?.owner ?? options.owner ?? '',
1047
- }
1048
-
1049
- // if (trackFlat) {
1050
- // Object.assign(this, _tracking)
1051
- // } else {
1052
- // this.meta = { ..._tracking, ...options.meta }
1053
- // }
1054
- }
1055
-
1056
- // Class methods
1057
- static get _classname() {
1058
- return 'TrackedEntity'
1059
- }
1060
- static get _superclass() {
1061
- return 'TrackedEntity'
1062
- }
1063
-
1064
- static init(options = {}) {
1065
- return init(this, options)
1066
- }
1067
- static initFromArray(arr = []) {
1068
- return initFromArray(this, arr)
1069
- }
1070
- static initOnlyValidFromArray(arr = []) {
1071
- return initOnlyValidFromArray(this, arr)
1072
- }
1073
- // static nest(entity) {
1074
- // const { active, created, creator, deleted, modified, owner, ...rest } = entity
1075
- // return { ...rest, meta: { active, created, creator, deleted, modified, owner } }
1076
- // }
1077
-
1078
- // getters
1079
- get __valid() {
1080
- return {}
1081
- }
1082
- get isValid() {
1083
- return !!this
1084
- }
1085
- get active() {
1086
- return this.meta?.active ?? this.active
1087
- }
1088
- get created() {
1089
- return this.meta?.created ?? this.created
1090
- }
1091
- get creator() {
1092
- return this.meta?.creator ?? this.creator
1093
- }
1094
- get deleted() {
1095
- return this.meta?.deleted ?? this.deleted
1096
- }
1097
- get modified() {
1098
- return this.meta?.modified ?? this.modified
1099
- }
1100
- get owner() {
1101
- return this.meta?.owner ?? this.owner
1102
- }
1103
- changeCreatorOwner({ source, target }) {
1104
- return changeCreatorOwner(this, { source, target }).setModified()
1105
- }
1106
- delete() {
1107
- return this.setDeleted()
1108
- }
1109
- setActive() {
1110
- if (this.meta) {
1111
- this.meta.active = true
1112
- } else {
1113
- this.active = true
1114
- }
1115
- return this
1116
- }
1117
- setDeleted() {
1118
- if (this.meta) {
1119
- this.meta.deleted = true
1120
- } else {
1121
- this.deleted = true
1122
- }
1123
- return this
1124
- }
1125
- setModified() {
1126
- const timestamp = Date.now()
1127
- if (this.meta) {
1128
- this.meta.modified = timestamp
1129
- } else {
1130
- this.modified = timestamp
1131
- }
1132
- return this
1133
- }
1134
- setOwner(owner) {
1135
- if (!owner) {
1136
- return this
1137
- }
1138
- if (this.meta) {
1139
- this.meta.owner = owner
1140
- } else {
1141
- this.owner = owner
1142
- }
1143
- return this
1144
- }
1145
- unsetActive() {
1146
- if (this.meta) {
1147
- this.meta.active = false
1148
- } else {
1149
- this.active = false
1150
- }
1151
- return this
1152
- }
1153
- unsetDeleted() {
1154
- if (this.meta) {
1155
- this.meta.deleted = false
1156
- } else {
1157
- this.deleted = false
1158
- }
1159
- return this
1160
- }
1161
-
1162
- update(update) {
1163
- if (update.meta) {
1164
- this.meta = { ...this.meta, ...update.meta }
1165
- }
1166
- return this.setModified()
1167
- }
1168
- }
1169
-
1170
- ;// ./lib/models/trackedEntity/index.js
1171
-
1172
- // Explicit named export (optional)
1173
-
1174
- ;// ./lib/models/pushEnvelope/pushEnvelope.js
1175
-
1176
-
1177
-
1178
-
1179
-
1180
- class PushEnvelope extends TrackedEntity {
1181
- constructor(options) {
1182
- options = options || {}
1183
- super(options)
1184
-
1185
- this.id = options.id
1186
- this.body = options.body
1187
- this.data = options.data
1188
- this.dirty = options.dirty
1189
- this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
1190
- this.remarks = keyValueObject_KeyValueObject.initOnlyValidFromArray(options.remarks)
1191
- this.threadID = options.threadID
1192
- this.title = options.title
1193
- }
1194
- static get _classname() {
1195
- return 'PushEnvelope'
1196
- }
1197
- static get _superclass() {
1198
- return 'PushEnvelope'
1199
- }
1200
- static init(options = {}) {
1201
- return init(this, options)
1202
- }
1203
-
1204
- get _classname() {
1205
- return 'PushEnvelope'
1206
- }
1207
-
1208
- get _superclass() {
1209
- return 'PushEnvelope'
1210
- }
1211
-
1212
- get isValid() {
1213
- return super.isValid && this.data
1214
- }
1215
- }
1216
-
1217
- ;// ./lib/models/pushEnvelope/index.js
1218
-
1219
-
1220
- ;// ./lib/models/qMeta/qMeta.js
1221
-
1222
-
1223
- const updateAllowedProps = [
1224
- 'attributes',
1225
- 'ref'
1226
- ]
1227
-
1228
- class QMeta {
1229
- constructor(options = {}) {
1230
- options = options || {}
1231
- this.attributes = keyValueObject_KeyValueObject.initOnlyValidFromArray(options.attributes)
1232
- this.ref = options.ref || {}
1233
- }
1234
-
1235
- static get _classname() {
1236
- return 'QMeta'
1237
- }
1238
- static get _superclass() {
1239
- return 'QMeta'
1240
- }
1241
-
1242
- // Class methods
1243
- static init(options = {}) {
1244
- if (options instanceof QMeta) {
1245
- return options
1246
- }
1247
- return new QMeta(options)
1248
- }
1249
-
1250
- // instance methods
1251
- addAttribute(obj) {
1252
- const kvObject = keyValueObject_KeyValueObject.init(obj)
1253
- if (!kvObject) {
1254
- throw new Error('invalid meta attribute')
1255
- }
1256
- this.attributes.push(kvObject)
1257
- return this
1258
- }
1259
-
1260
- update(obj) {
1261
- Object.keys(obj).forEach((key) => {
1262
- if (updateAllowedProps.includes(key)) {
1263
- if (key === 'attributes') {
1264
- this[key] = keyValueObject_KeyValueObject.initOnlyValidFromArray(obj[key])
1265
- } else {
1266
- this[key] = obj[key]
1267
- }
1268
- }
1269
- })
1270
- return this
1271
- }
1272
- }
1273
-
1274
-
1275
-
1276
- ;// ./lib/models/qMeta/index.js
1277
-
1278
-
1279
-
1280
-
1281
- ;// ./lib/models/repo/repo.js
1282
-
1283
-
1284
- class Repo {
1285
- constructor(options) {
1286
- options = options || {}
1287
- this.model = options.model
1288
- this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1289
- this._queryOptions = options._queryOptions
1290
- this._saveOptions = options._saveOptions
1291
- this._Class = options._constructor && options._constructor._Class
1292
- ? options._constructor._Class
1293
- : null
1294
- }
1295
- static init(options = {}) {
1296
- return init(this, options)
1297
- }
1298
- static get _classname() {
1299
- return 'Repo'
1300
- }
1301
- static get _superclass() {
1302
- return 'Repo'
1303
- }
1304
-
1305
- get _classname() {
1306
- return 'Repo'
1307
- }
1308
-
1309
- get _superclass() {
1310
- return 'Repo'
1311
- }
1312
-
1313
- get isValid() {
1314
- return this.model
1315
- && (typeof this.model.deleteOne === 'function')
1316
- && (typeof this.model.findAll === 'function')
1317
- && (typeof this.model.saveOne === 'function')
1318
- }
1319
-
1320
- get queryOptions() {
1321
- return {
1322
- ...this._sharedOptions,
1323
- ...this._queryOptions,
1324
- }
1325
- }
1326
-
1327
- get saveOptions() {
1328
- return {
1329
- ...this._sharedOptions,
1330
- ...this._saveOptions,
1331
- }
1332
- }
1333
-
1334
- init(options) {
1335
- if (this._Class && typeof this._Class.init === 'function') {
1336
- return this._Class.init(options)
1337
- }
1338
- return options
1339
- }
1340
-
1341
- async deleteOne({ id }) {
1342
- try {
1343
- const result = await this.model.deleteOne({ _id: id })
1344
- return {
1345
- ...result, // { message: 'ok', total }
1346
- isNew: false,
1347
- data: []
1348
- }
1349
- } catch (err) {
1350
- throw err
1351
- }
1352
- }
1353
-
1354
- // systemLog is optional
1355
- findAll({ config = {}, query, systemLog }) {
1356
- const log = _makeLog({
1357
- systemLog,
1358
- label: 'REPO_READ',
1359
- message: `fn ${this._classname}.prototype.findAll`,
1360
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1361
- })
1362
- const queryOptions = {
1363
- ...this.queryOptions,
1364
- ...config,
1365
- }
1366
- return new Promise((resolve, reject) => {
1367
- this.model.findAll(query, queryOptions, (err, data, total) => {
1368
- if (err) {
1369
- log({ level: 'warn', output: err.toString() })
1370
- reject(err)
1371
- } else {
1372
- const result = {
1373
- isNew: false,
1374
- data,
1375
- total: total || data.length
1376
- }
1377
- log({ level: 'info', output: { ...result } })
1378
- resolve(result)
1379
- }
1380
- })
1381
- })
1382
- }
1383
-
1384
- findOne({ config = {}, query, systemLog }) {
1385
- const log = _makeLog({
1386
- systemLog,
1387
- label: 'REPO_READ',
1388
- message: `fn ${this._classname}.prototype.findOne`,
1389
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1390
- })
1391
- const queryOptions = {
1392
- ...this.queryOptions,
1393
- ...config,
1394
- }
1395
- return new Promise((resolve, reject) => {
1396
- this.model.findAll(query, queryOptions, (err, data) => {
1397
- if (err) {
1398
- reject(err)
1399
- } else if (data.length === 1) {
1400
- const result = {
1401
- isNew: false,
1402
- data,
1403
- total: 1
1404
- }
1405
- log({ level: 'info', output: { ...result } })
1406
- resolve(result)
1407
- } else if (data.length === 0) {
1408
- reject(new Error('record not found'))
1409
- } else {
1410
- reject(new Error('more than one is found'))
1411
- }
1412
- })
1413
- })
1414
- .catch((err) => {
1415
- log({ level: 'warn', output: err.toString() })
1416
- throw err
1417
- })
1418
- }
1419
-
1420
- saveAll({ config = {}, docs, systemLog }) {
1421
- let isNew
1422
- const log = _makeLog({
1423
- systemLog,
1424
- label: 'REPO_WRITE',
1425
- message: `fn ${this._classname}.prototype.saveAll`,
1426
- input: [{ config, docs: [...docs], systemLog: { ...systemLog } }]
1427
- })
1428
- const promise = typeof this.model.saveAll === 'function'
1429
- ? this.model.saveAll({ config, docs })
1430
- : _saveAll({ config, docs, service: this })
1431
- // : Promise.all(docs.map(async (doc) => {
1432
- // if (doc) {
1433
- // const result = await this.saveOne({ config, doc })
1434
- // isNew = result.isNew
1435
- // const _data = result._data || result.data
1436
- // return _data[0]
1437
- // }
1438
- // return null
1439
- // }))
1440
- return promise.then((savedData) => {
1441
- if (savedData.length !== 1)
1442
- isNew = null
1443
- const result = {
1444
- data: savedData,
1445
- isNew,
1446
- total: savedData.length
1447
- }
1448
- log({ level: 'info', output: { ...result } })
1449
- return result
1450
- }).catch((err) => {
1451
- log({ level: 'warn', output: err.toString() })
1452
- throw err
1453
- })
1454
- }
1455
-
1456
- saveOne({ config = {}, doc, systemLog }) {
1457
- const log = _makeLog({
1458
- systemLog,
1459
- label: 'REPO_WRITE',
1460
- message: `fn ${this._classname}.prototype.saveOne`,
1461
- input: [{ config, doc: { ...doc }, systemLog: { ...systemLog } }]
1462
- })
1463
- const saveOptions = {
1464
- ...this.saveOptions,
1465
- ...config,
1466
- }
1467
- return new Promise((resolve, reject) => {
1468
- this.model.saveOne(doc, saveOptions, (err, result) => {
1469
- if (err) {
1470
- log({ level: 'warn', output: err.toString() })
1471
- reject(err)
1472
- } else {
1473
- log({ level: 'info', output: { ...result } })
1474
- resolve(result)
1475
- }
1476
- })
1477
- })
1478
- }
1479
- }
1480
-
1481
- function _makeLog({ systemLog, label, message: message1, input } = {}) {
1482
- return ({ level, messgae: massage2, output } = {}) => {
1483
- if (systemLog && systemLog.systemLogHelper) {
1484
- systemLog.systemLogHelper.log({
1485
- batchId: systemLog.batchId,
1486
- label,
1487
- level,
1488
- message: massage2 || message1,
1489
- data: {
1490
- payload: {
1491
- input,
1492
- output
1493
- }
1494
- }
1495
- })
1496
- }
1497
- }
1498
- }
1499
-
1500
- async function _saveAll({ config = {}, docs, service }) {
1501
- let _result = null
1502
- if (config.session || service.saveOptions.session) {
1503
- _result = await pMap(docs, async (doc) => {
1504
- if (doc) {
1505
- const result = await service.saveOne({ config, doc })
1506
- // isNew = result.isNew
1507
- const _data = result._data || result.data
1508
- return _data[0]
1509
- }
1510
- return null
1511
- }, { concurrency: 1 })
1512
- } else {
1513
- _result = await Promise.all(docs.map(async (doc) => {
1514
- if (doc) {
1515
- const result = await service.saveOne({ config, doc })
1516
- // isNew = result.isNew
1517
- const _data = result._data || result.data
1518
- return _data[0]
1519
- }
1520
- return null
1521
- }))
1522
- }
1523
- return _result
1524
- }
1525
-
1526
-
1527
-
1528
- ;// ./lib/models/repo/index.js
1529
-
1530
-
1531
-
1532
-
1533
- ;// ./lib/models/service/service.js
1534
-
1535
-
1536
-
1537
- class Service {
1538
- constructor({ repo }) {
1539
- this.repo = repo
1540
- }
1541
-
1542
- static get _classname() {
1543
- return 'Service'
1544
- }
1545
- static get _superclass() {
1546
- return 'Service'
1547
- }
1548
-
1549
- async deleteOne({ id }) {
1550
- const result = await this.repo.deleteOne({ id })
1551
- return makeApiResponse({
1552
- repo: this.repo,
1553
- result
1554
- })
1555
- // return this.repo.delete({ id })
1556
- // .catch(() => {
1557
- // throw new Error(`Not found for query: ${id}`)
1558
- // })
1559
- }
1560
-
1561
- async findAll({ config = {}, query = {}, systemLog } = {}) {
1562
- const result = await this.repo.findAll({ config, query, systemLog })
1563
- return makeApiResponse({
1564
- repo: this.repo,
1565
- result
1566
- })
1567
- }
1568
-
1569
- async findOne({ config = {}, query = {}, systemLog } = {}) {
1570
- const result = await this.repo.findOne({ config, query, systemLog })
1571
- return makeApiResponse({
1572
- repo: this.repo,
1573
- result
1574
- })
1575
- }
1576
-
1577
- init(options) {
1578
- return this.repo.init(options)
1579
- }
1580
- initFromArray(arr = []) {
1581
- if (Array.isArray(arr)) {
1582
- return arr.map((a) => this.init(a))
1583
- }
1584
- return []
1585
- }
1586
- initOnlyValidFromArray(arr = []) {
1587
- return this.initFromArray(arr).filter((i) => i)
1588
- }
1589
-
1590
- async saveAll({ config = {}, docs = [], systemLog } = {}) {
1591
- const copies = docs.map((doc) => {
1592
- return config.skipInit ? doc : this.init(doc)
1593
- })
1594
- const result = await this.repo.saveAll({ config, docs: copies, systemLog })
1595
- return makeApiResponse({
1596
- repo: this.repo,
1597
- result
1598
- })
1599
- }
1600
-
1601
- // set skipInit to true if we want to use POST for query
1602
- async saveOne({ config = {}, doc = {}, systemLog } = {}) {
1603
- const copy = config.skipInit ? doc : this.init(doc)
1604
- if (copy) {
1605
- const result = await this.repo.saveOne({ config, doc: copy, systemLog })
1606
- return makeApiResponse({
1607
- repo: this.repo,
1608
- result
1609
- })
1610
- }
1611
- return {
1612
- isNew: null,
1613
- data: [],
1614
- err: new Error('doc is not a valid instance')
1615
- }
1616
- }
1617
- }
1618
-
1619
- function makeService({ repo }) {
1620
- if (repo === undefined) {
1621
- throw new Error('repo is required.')
1622
- }
1623
- if (repo._superclass !== Repo._superclass) {
1624
- throw new Error('repo is not an instance of Repo.')
1625
- }
1626
- return new Service({ repo })
1627
- }
1628
-
1629
-
1630
-
1631
- ;// ./lib/models/service/index.js
1632
-
1633
-
1634
-
1635
-
1636
- ;// ./lib/models/status/actionRecord.js
1637
-
1638
-
1639
- class ActionRecord {
1640
- constructor(options) {
1641
- options = options || {}
1642
-
1643
- const { _Actor } = options._constructor || {}
1644
- this._Actor = _Actor
1645
-
1646
- this._actor = options._actor
1647
-
1648
- this.actorCode = typeof options === 'number' ? null : (options.actorCode || null)
1649
- this.timestamp = typeof options === 'number' ? options : (options.timestamp || null)
1650
- }
1651
-
1652
- static get _classname() {
1653
- return 'ActionRecord'
1654
- }
1655
- static get _superclass() {
1656
- return 'ActionRecord'
1657
- }
1658
- static dummyData() {
1659
- return {
1660
- timestamp: (new Date()).valueOf(),
1661
- }
1662
- }
1663
- static init(options = {}) {
1664
- return init(this, options)
1665
- }
1666
-
1667
- get _classname() {
1668
- return 'ActionRecord'
1669
- }
1670
-
1671
- get _superclass() {
1672
- return 'ActionRecord'
1673
- }
1674
-
1675
- get actor() {
1676
- return this._Actor && typeof this._Actor.init === 'function' ? this._Actor.init(this._actor) : this._actor
1677
- }
1678
-
1679
- get isValid() {
1680
- return !!this.timestamp
1681
- }
1682
-
1683
- update(update) {
1684
- if (typeof update === 'number') {
1685
- this.timestamp = update
1686
- return this
1687
- }
1688
- Object.keys(update).forEach((key) => {
1689
- this[key] = update[key]
1690
- })
1691
- return this
1692
- }
1693
- }
1694
-
1695
- ;// ./lib/models/status/status.js
1696
-
1697
-
1698
-
1699
- const notUpdateAllowedProps = [
1700
- '_ActionRecord',
1701
- 'created',
1702
- // 'statusType'
1703
- ]
1704
-
1705
- class Status {
1706
- constructor(options) {
1707
- options = options || {}
1708
-
1709
- const { _ActionRecord } = options._constructor || {}
1710
- this._ActionRecord = _ActionRecord && (_ActionRecord._superclass === ActionRecord._superclass) ? _ActionRecord : ActionRecord
1711
-
1712
- this.created = this._ActionRecord.init(options.created || { timestamp: (new Date()).valueOf() })
1713
- // this.statusType = options.statusType || 'Status'
1714
- }
1715
-
1716
- static get _classname() {
1717
- return 'Status'
1718
- }
1719
- static get _superclass() {
1720
- return 'Status'
1721
- }
1722
- static dummyData() {
1723
- return {}
1724
- }
1725
- static init(options = {}) {
1726
- return init(this, options)
1727
- }
1728
- static initFromArray(arr = []) {
1729
- return initFromArray(this, arr)
1730
- }
1731
- static initOnlyValidFromArray(arr = []) {
1732
- return initOnlyValidFromArray(this, arr)
1733
- }
1734
-
1735
- get _classname() {
1736
- return 'Status'
1737
- }
1738
- get _superclass() {
1739
- return 'Status'
1740
- }
1741
- get isCreated() {
1742
- return this.created?.timestamp !== null
1743
- }
1744
- get isValid() {
1745
- return !!this
1746
- }
1747
-
1748
- setValue(t, actorCode, key) {
1749
- const timestamp = t || Date.now()
1750
- this[key] = this[key] instanceof this._ActionRecord ? this[key].update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
1751
- return this
1752
- }
1753
-
1754
- update(update) {
1755
- Object.keys(update).forEach((key) => {
1756
- if (!notUpdateAllowedProps.includes(key)) {
1757
- this[key] = this[key] instanceof this._ActionRecord ? this[key].update(update[key]) : this._ActionRecord.init(update[key])
1758
- }
1759
- })
1760
- return this
1761
- }
1762
- }
1763
-
1764
- ;// ./lib/models/status/statusDocument.js
1765
-
1766
-
1767
- class StatusDocument extends Status {
1768
- constructor(options) {
1769
- options = options || {}
1770
- super(options)
1771
-
1772
- this.archived = this._ActionRecord.init(options.archived)
1773
- this.completed = this._ActionRecord.init(options.completed)
1774
- this.discarded = this._ActionRecord.init(options.discarded)
1775
- this.drafted = this._ActionRecord.init(options.drafted)
1776
- // this.statusType = 'StatusDocument'
1777
- }
1778
-
1779
- static get _classname() {
1780
- return 'StatusDocument'
1781
- }
1782
- get _classname() {
1783
- return 'StatusDocument'
1784
- }
1785
- get isArchived() {
1786
- return this.created?.timestamp !== null
1787
- }
1788
- get isCompleted() {
1789
- return this.completed?.timestamp !== null
1790
- }
1791
- get isDiscarded() {
1792
- return this.discarded?.timestamp !== null
1793
- }
1794
- get isDrafted() {
1795
- return this.drafted?.timestamp !== null
1796
- }
1797
- get isValid() {
1798
- return super.isValid
1799
- }
1800
- setArchived(value, actorCode) {
1801
- // const timestamp = value || Date.now()
1802
- // this.archived = this.archived instanceof this._ActionRecord ? this.archived.update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
1803
- // return this
1804
- return this.setValue(value, actorCode, 'archived')
1805
- }
1806
- setCompleted(value, actorCode) {
1807
- return this.setValue(value, actorCode, 'completed')
1808
- }
1809
- setDiscarded(value, actorCode) {
1810
- return this.setValue(value, actorCode, 'discarded')
1811
- }
1812
- setDrafted(value, actorCode) {
1813
- return this.setValue(value, actorCode, 'drafted')
1814
- }
1815
- }
1816
-
1817
- ;// ./lib/models/status/index.js
1818
-
1819
-
1820
-
1821
-
1822
- ;// ./lib/models/templateCompiler/templateCompilerException.js
1823
- const TEMPLATE_COMPILER_EXCEPTION_TYPE = {
1824
- argumentEmptyException: 'Argument is empty',
1825
- argumentFormatException: 'Incorrect number or format of argument',
1826
- invalidFuntionException: 'Function Name is invalid',
1827
- invalidRegExpException: 'Invalid regular expression',
1828
- isNotAFunctionException: 'Is not a function',
1829
- notExistException: 'Key does not exist',
1830
- resultEmptyException: 'Result is empty',
1831
- resultMoreThanOneException: 'More than one result'
1832
- }
1833
-
1834
- class TemplateCompilerException extends Error {
1835
- constructor(message) {
1836
- super(message)
1837
- this.message = message
1838
- }
1839
- }
1840
-
1841
-
1842
-
1843
- ;// ./lib/models/templateCompiler/constants.js
1844
- const _EMPTY = '_EMPTY'
1845
- const _FN_NAMES = [
1846
- 'concatIf',
1847
- 'divide',
1848
- 'eq',
1849
- 'exec',
1850
- 'filterAll',
1851
- 'filterOne',
1852
- 'formatDate',
1853
- 'get',
1854
- 'gt',
1855
- 'gte',
1856
- 'isEmpty',
1857
- 'isNotEmpty',
1858
- 'join',
1859
- 'lt',
1860
- 'lte',
1861
- 'map',
1862
- 'neq',
1863
- 'removeHtml',
1864
- 'sum',
1865
- 'toLowerCase',
1866
- 'toUpperCase',
1867
- ]
1868
- const _HIDE = '_HIDE'
1869
- const _NOT_EMPTY = '_NOT_EMPTY'
1870
- const _SELF = '_SELF'
1871
- const TAGS_EJS = ['<%=', '%>']
1872
- const TAGS_HANDLEBAR = ['{{', '}}']
1873
-
1874
-
1875
-
1876
- ;// ./lib/models/templateCompiler/helpers/_concatIf.js
1877
-
1878
-
1879
-
1880
-
1881
- function _concatIf(data, args) {
1882
- if (typeof data !== 'string') {
1883
- throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string :${data.join(', ')}`)
1884
- }
1885
- if (args.length !== 3) {
1886
- throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1887
- }
1888
- if (data === null || (typeof data === 'undefined')) {
1889
- return null
1890
- }
1891
- const [condition, success, failover] = args
1892
- const validConditions = [_EMPTY, _NOT_EMPTY]
1893
- if (validConditions.includes(condition) || success.length !== 2) {
1894
- throw new TemplateCompilerException(`concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException}: ${condition}, ${success}`)
1895
- }
1896
- if (data === '' && failover.includes(_HIDE)) {
1897
- return ''
1898
- }
1899
- if (data !== '' && (data !== null || data !== undefined) && failover.includes(_HIDE)) {
1900
- return `${success[0]}${data}${success[success.length - 1]}`
1901
- }
1902
- return failover
1903
- }
1904
-
1905
-
1906
-
1907
- ;// ./lib/models/templateCompiler/helpers/_divide.js
1908
- function _divide(value, divisor) {
1909
- try {
1910
- if (Number.isNaN(value)) {
1911
- return value
1912
- }
1913
- return (value / divisor)
1914
- } catch (e) {
1915
- throw e
1916
- }
1917
- }
1918
-
1919
-
1920
-
1921
- ;// ./lib/models/templateCompiler/helpers/_eq.js
1922
-
1923
-
1924
-
1925
-
1926
- function _eq(data, args) {
1927
- if (args.length !== 3) {
1928
- throw new TemplateCompilerException(`eq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1929
- }
1930
- if (data === null || (typeof data === 'undefined')) {
1931
- return null
1932
- }
1933
- if (args.includes(_SELF)) {
1934
- args = args.map((arg) => {
1935
- return (arg === _SELF) ? data : arg
1936
- })
1937
- }
1938
- const expected = args[0]
1939
- return data === expected ? args[1] : args[2]
1940
- }
1941
-
1942
-
1943
-
1944
- ;// ./lib/models/templateCompiler/helpers/_exec.js
1945
- function _exec(data, args) {
1946
- try {
1947
- const [methodName, ..._args] = args
1948
- return data[methodName](..._args)
1949
- } catch (e) {
1950
- throw e
1951
- }
1952
- }
1953
-
1954
-
1955
-
1956
- ;// ./lib/models/templateCompiler/helpers/_filterAll.js
1957
-
1958
-
1959
-
1960
- // const DELIMITER = '~~~'
1961
-
1962
- function _filterAll(data, args) {
1963
- try {
1964
- if (!Array.isArray(args) || args.length === 0) {
1965
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
1966
- }
1967
- if (!Array.isArray(data) || data.length === 0) {
1968
- return []
1969
- }
1970
- if (typeof data[0] === 'object') {
1971
- return _existObject(data, args)
1972
- }
1973
- if (typeof data[0] === 'string' || typeof data[0] === 'number') {
1974
- return _exist(data, args)
1975
- }
1976
- return []
1977
- } catch (e) {
1978
- throw e
1979
- }
1980
- }
1981
-
1982
- function _exist(data, args) {
1983
- const _args = args.flat()
1984
- return data.filter((e) => _args.some((arg) => _performOperation(arg, e)))
1985
- }
1986
-
1987
- function _existObject(data, args) {
1988
- if (args.length === 1) {
1989
- const arg = args[0]
1990
- return data.filter((e) => {
1991
- if (arg.includes('.')) {
1992
- return getValueByKeys_getValueByKeys(arg.split('.'), e)
1993
- }
1994
- return Object.prototype.hasOwnProperty.call(e, arg)
1995
- })
1996
- }
1997
-
1998
- if (args.length > 2) {
1999
- let res = data
2000
- for (let i = 0; i < args.length; i += 2) {
2001
- const group = [args[i], args[i + 1]]
2002
- res = _existObject(res, group)
2003
- }
2004
- return res
2005
- }
2006
-
2007
- const [key, ..._argsArr] = args
2008
- const _args = _argsArr.flat()
2009
- return data.filter((e) => {
2010
- const value = key.includes('.') ? getValueByKeys_getValueByKeys(key.split('.'), e) : e[key]
2011
- return _args.some((arg) => _performOperation(arg, value))
2012
- })
2013
- }
2014
-
2015
- function _performOperation(arg, value) {
2016
- // the arg is undefined
2017
- if (arg === undefined && value === undefined)
2018
- return true
2019
-
2020
- // the arg is null
2021
- if (arg === null && value === null)
2022
- return true
2023
-
2024
- // the arg is boolean
2025
- if (typeof arg === 'boolean') {
2026
- return arg === value
2027
- }
2028
-
2029
- // the arg is blank or *: Blank => Empty, * => Not Empty
2030
- if (arg === '' || arg === '*') {
2031
- // null and undefined are not included in either case
2032
- if (value === null || value === undefined) {
2033
- return false
2034
- }
2035
- if (typeof value === 'string') {
2036
- return arg === '' ? value === '' : value !== ''
2037
- }
2038
- if (Array.isArray(value)) {
2039
- return arg === '' ? value.length === 0 : value.length !== 0
2040
- }
2041
- return arg !== ''
2042
- }
2043
-
2044
- // the arg is alphabetic or number
2045
- if (_isPureStringOrNumber(arg)) {
2046
- return arg === value
2047
- }
2048
-
2049
- // the arg is array of [] or [*]: [] => Empty, [*] => Not Empty
2050
- if (arg.startsWith('[') && arg.endsWith(']')) {
2051
- if (arg === '[]') {
2052
- return Array.isArray(value) && value.length === 0
2053
- }
2054
- if (arg === '[*]') {
2055
- return Array.isArray(value) && value.length !== 0
2056
- }
2057
- return false
2058
- }
2059
-
2060
- // the arg is 'operator + string | number'
2061
- const { operator, value: argValue } = _splitOperator(arg)
2062
- if (!operator || (argValue !== 0 && !argValue)) {
2063
- return false
2064
- }
2065
- switch (operator) {
2066
- case '>':
2067
- return value > argValue
2068
- case '<':
2069
- return value < argValue
2070
- case '!=':
2071
- return value !== argValue
2072
- case '>=':
2073
- return value >= argValue
2074
- case '<=':
2075
- return value <= argValue
2076
- default:
2077
- return false
2078
- }
2079
- }
2080
-
2081
- function _isPureStringOrNumber(input) {
2082
- if (typeof input === 'string') {
2083
- if (input.startsWith('[') && input.endsWith(']')) {
2084
- return false
2085
- }
2086
- if (/!=|>=|<=|>|</.test(input)) {
2087
- return false
2088
- }
2089
- return true
2090
- }
2091
- return !Number.isNaN(input)
2092
- }
2093
-
2094
- function _splitOperator(str) {
2095
- const operators = ['!=', '>=', '<=', '>', '<']
2096
-
2097
- const matchedOp = operators.find((op) => str.startsWith(op))
2098
- if (!matchedOp)
2099
- return { operator: null, value: null }
2100
-
2101
- const remaining = str.slice(matchedOp.length)
2102
-
2103
- // '>Primary' or '<Primary' is invalid
2104
- if (/^[a-z]*$/i.test(remaining) && matchedOp !== '!=') {
2105
- return { operator: null, value: null }
2106
- }
2107
-
2108
- // if it is a number it is converted to a number
2109
- const value = (!Number.isNaN(Number.parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
2110
-
2111
- return {
2112
- operator: matchedOp,
2113
- value
2114
- }
2115
- }
2116
-
2117
-
2118
-
2119
- ;// ./lib/models/templateCompiler/helpers/_filterOne.js
2120
-
2121
-
2122
-
2123
- function _filterOne(data, args) {
2124
- try {
2125
- const list = _filterAll(data, args)
2126
- if (list.length === 1) {
2127
- return list[0]
2128
- }
2129
- if (list.length === 0) {
2130
- return null
2131
- }
2132
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.resultMoreThanOneException)
2133
- } catch (e) {
2134
- throw e
2135
- }
2136
- }
2137
-
2138
-
2139
-
2140
- ;// ./lib/models/templateCompiler/helpers/_formatDate.js
2141
-
2142
-
2143
- function _formatDate(timestamp, format) {
2144
- if (format.length === 0) {
2145
- throw new TemplateCompilerException(`_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: format parts must be not empty array`)
2146
- }
2147
-
2148
- if (timestamp === null || timestamp === undefined) {
2149
- return null
2150
- }
2151
-
2152
- const date = new Date(timestamp)
2153
-
2154
- const partsMap = {
2155
- yyyy: String(date.getFullYear()),
2156
- mm: String(date.getMonth() + 1).padStart(2, '0'),
2157
- dd: String(date.getDate()).padStart(2, '0')
2158
- }
2159
-
2160
- // Check for invalid format tokens
2161
- const validTokens = ['yyyy', 'mm', 'dd']
2162
- const invalidTokens = format.filter((part) => part.length > 1 && !validTokens.includes(part))
2163
-
2164
- if (invalidTokens.length > 0) {
2165
- throw new TemplateCompilerException(
2166
- `_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the format type is not valid: ${format.join(', ')}`
2167
- )
2168
- }
2169
-
2170
- // Build the formatted string using reduce
2171
- return format.reduce((result, part) => result + (partsMap[part] || part), '')
2172
- }
2173
-
2174
-
2175
-
2176
- ;// ./lib/models/templateCompiler/helpers/_get.js
2177
-
2178
-
2179
- function _get(data, key, failover = null) {
2180
- try {
2181
- if (key === null || (typeof key === 'undefined') || key === '') {
2182
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
2183
- }
2184
- if (data === null) {
2185
- return null
2186
- }
2187
- if (key.includes('.')) {
2188
- const parts = key.split('.')
2189
- if (parts.length > 1) {
2190
- const first = parts.shift()
2191
- const remainingKey = parts.join('.')
2192
- if (typeof data[first] !== 'undefined') {
2193
- return _get(data[first], remainingKey, failover)
2194
- }
2195
- return _handleFailover(key, failover)
2196
- }
2197
- }
2198
- if (typeof data[key] !== 'undefined') {
2199
- return data[key]
2200
- }
2201
- return _handleFailover(key, failover)
2202
- } catch (e) {
2203
- throw e
2204
- }
2205
- }
2206
-
2207
- function _handleFailover(key, failover) {
2208
- if (failover !== null) {
2209
- return failover
2210
- }
2211
- return null
2212
- // throw new TemplateCompilerException(`Key "${key}" does not exist and no failover`)
2213
- }
2214
-
2215
-
2216
-
2217
- ;// ./lib/models/templateCompiler/helpers/_gt.js
2218
-
2219
-
2220
-
2221
-
2222
- function _gt(data, args) {
2223
- if (args.length !== 3) {
2224
- throw new TemplateCompilerException(`_gt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2225
- }
2226
- if (data === null || (typeof data === 'undefined')) {
2227
- return null
2228
- }
2229
- if (args.includes(_SELF)) {
2230
- args = args.map((arg) => {
2231
- return (arg === _SELF) ? data : arg
2232
- })
2233
- }
2234
- const expected = args[0]
2235
- return data > expected ? args[1] : args[2]
2236
- }
2237
-
2238
-
2239
-
2240
- ;// ./lib/models/templateCompiler/helpers/_gte.js
2241
-
2242
-
2243
-
2244
-
2245
- function _gte(data, args) {
2246
- if (args.length !== 3) {
2247
- throw new TemplateCompilerException(`_gte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2248
- }
2249
- if (data === null || (typeof data === 'undefined')) {
2250
- return null
2251
- }
2252
- if (args.includes(_SELF)) {
2253
- args = args.map((arg) => {
2254
- return (arg === _SELF) ? data : arg
2255
- })
2256
- }
2257
- const expected = args[0]
2258
- return data >= expected ? args[1] : args[2]
2259
- }
2260
-
2261
-
2262
-
2263
- ;// ./lib/models/templateCompiler/helpers/_isEmpty.js
2264
-
2265
-
2266
-
2267
-
2268
- function _isEmpty(data, args) {
2269
- if (args.length !== 2) {
2270
- throw new TemplateCompilerException(`_isEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2271
- }
2272
- // if (data === null || (typeof data === 'undefined')) {
2273
- // return null
2274
- // }
2275
- if (args.includes(_SELF)) {
2276
- args = args.map((arg) => {
2277
- return (arg === _SELF) ? data : arg
2278
- })
2279
- }
2280
- if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
2281
- return args[0]
2282
- }
2283
- return (data === '' || data === null || data === undefined || data.length === 0) ? args[0] : args[1]
2284
- }
2285
-
2286
-
2287
-
2288
- ;// ./lib/models/templateCompiler/helpers/_isNotEmpty.js
2289
-
2290
-
2291
-
2292
-
2293
- function _isNotEmpty(data, args) {
2294
- if (args.length !== 2) {
2295
- throw new TemplateCompilerException(`_isNotEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2296
- }
2297
- // if (data === null || (typeof data === 'undefined')) {
2298
- // return null
2299
- // }
2300
- if (args.includes(_SELF)) {
2301
- args = args.map((arg) => {
2302
- return (arg === _SELF) ? data : arg
2303
- })
2304
- }
2305
- if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
2306
- return args[1]
2307
- }
2308
- if (Array.isArray(data) && data.length === 0) {
2309
- return args[1]
2310
- }
2311
- if (typeof data === 'string' && data === '') {
2312
- return args[1]
2313
- }
2314
- if (data === null || data === undefined) {
2315
- return args[1]
2316
- }
2317
- return args[0]
2318
- }
2319
-
2320
-
2321
-
2322
- ;// ./lib/models/templateCompiler/helpers/_join.js
2323
- function _join(data, delimiter) {
2324
- try {
2325
- if (data.length === 0)
2326
- return ''
2327
- if (data.length === 1)
2328
- return _stringifyObject(data[0])
2329
- return data.map((item) => _stringifyObject(item)).join(delimiter)
2330
- } catch (e) {
2331
- throw e
2332
- }
2333
- }
2334
-
2335
- function _stringifyObject(obj) {
2336
- return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1: ').replace(/"([^"]+)"/g, '$1').replace(/,/g, ', ')
2337
- }
2338
-
2339
-
2340
-
2341
- ;// ./lib/models/templateCompiler/helpers/_lt.js
2342
-
2343
-
2344
-
2345
-
2346
- function _lt(data, args) {
2347
- if (args.length !== 3) {
2348
- throw new TemplateCompilerException(`_lt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2349
- }
2350
- if (data === null || (typeof data === 'undefined')) {
2351
- return null
2352
- }
2353
- if (args.includes(_SELF)) {
2354
- args = args.map((arg) => {
2355
- return (arg === _SELF) ? data : arg
2356
- })
2357
- }
2358
- const expected = args[0]
2359
- return data < expected ? args[1] : args[2]
2360
- }
2361
-
2362
-
2363
-
2364
- ;// ./lib/models/templateCompiler/helpers/_lte.js
2365
-
2366
-
2367
-
2368
-
2369
- function _lte(data, args) {
2370
- if (args.length !== 3) {
2371
- throw new TemplateCompilerException(`_lte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2372
- }
2373
- if (data === null || (typeof data === 'undefined')) {
2374
- return null
2375
- }
2376
- if (args.includes(_SELF)) {
2377
- args = args.map((arg) => {
2378
- return (arg === _SELF) ? data : arg
2379
- })
2380
- }
2381
- const expected = args[0]
2382
- return data <= expected ? args[1] : args[2]
2383
- }
2384
-
2385
-
2386
-
2387
- ;// ./lib/models/templateCompiler/helpers/_map.js
2388
-
2389
-
2390
-
2391
- function _map(data, args) {
2392
- try {
2393
- if (args.length === 0) {
2394
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
2395
- }
2396
- if (data === null || (typeof data === 'undefined')) {
2397
- return null
2398
- }
2399
-
2400
- const result = data.reduce((acc, item) => {
2401
- if (args.length === 1 && Array.isArray(args[0])) {
2402
- args = args[0]
2403
- acc.hasFormat = true
2404
- }
2405
- const list = args.map((key) => {
2406
- if (key.includes('.')) {
2407
- const parts = key.split('.')
2408
- const first = parts[0]
2409
- parts.shift()
2410
- const remainingKey = parts.join('.')
2411
- return _get(item[first], remainingKey)
2412
- }
2413
- if (typeof item[key] !== 'undefined') {
2414
- return item[key]
2415
- }
2416
- return null
2417
- })
2418
- if (acc.hasFormat) {
2419
- acc.content.push(list)
2420
- } else {
2421
- acc.content = acc.content.concat(list)
2422
- }
2423
- return acc
2424
- }, {
2425
- content: [],
2426
- hasFormat: false
2427
- })
2428
- return result.content
2429
- } catch (e) {
2430
- throw e
2431
- }
2432
- }
2433
-
2434
-
2435
-
2436
- ;// ./lib/models/templateCompiler/helpers/_neq.js
2437
-
2438
-
2439
-
2440
-
2441
- function _neq(data, args) {
2442
- if (args.length !== 3) {
2443
- throw new TemplateCompilerException(`_neq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2444
- }
2445
- if (data === null || (typeof data === 'undefined')) {
2446
- return null
2447
- }
2448
- if (args.includes(_SELF)) {
2449
- args = args.map((arg) => {
2450
- return (arg === _SELF) ? data : arg
2451
- })
2452
- }
2453
- const expected = args[0]
2454
- return data !== expected ? args[1] : args[2]
2455
- }
2456
-
2457
-
2458
-
2459
- ;// ./lib/models/templateCompiler/helpers/_removeHtml.js
2460
-
2461
-
2462
- function _removeHtml(html, args) {
2463
- if (html === null || html === undefined) {
2464
- return null
2465
- }
2466
- if (!Array.isArray(args)) {
2467
- throw new TemplateCompilerException(`_removeHtml: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: args parts must be array`)
2468
- }
2469
-
2470
- return _htmlToPlainText(html, args[0])
2471
- }
2472
-
2473
- function _htmlToPlainText(html, delimiter = '\n') {
2474
- if (typeof delimiter !== 'string') {
2475
- delimiter = '\n' // Fallback to default if not a string
2476
- }
2477
-
2478
- // First decode HTML entities and normalize whitespace
2479
- const decodedHtml = html
2480
- .replace(/&nbsp;/g, ' ')
2481
- .replace(/\s+/g, ' ') // Collapse all whitespace to single spaces
2482
-
2483
- // Process HTML tags
2484
- let text = decodedHtml
2485
- // Replace block tags with temporary marker (~~~)
2486
- .replace(/<\/?(p|div|h[1-6]|ul|ol|li|pre|section|article|table|tr|td|th)(\s[^>]*)?>/gi, '~~~')
2487
- // Replace <br> tags with temporary marker (~~~)
2488
- .replace(/<br\s*\/?>/gi, '~~~')
2489
- // Remove all other tags
2490
- .replace(/<[^>]+>/g, '')
2491
- // Convert markers to specified delimiter
2492
- .replace(/~{3,}/g, delimiter)
2493
- // Trim and clean whitespace
2494
- .trim()
2495
-
2496
- // Special handling for empty delimiter
2497
- if (delimiter === '') {
2498
- // Collapse all whitespace to single space
2499
- text = text.replace(/\s+/g, ' ')
2500
- } else {
2501
- // Collapse multiple delimiters to single
2502
- text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter)
2503
- // Remove leading/trailing delimiters
2504
- text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '')
2505
- }
2506
-
2507
- return text
2508
- }
2509
-
2510
- function escapeRegExp(string) {
2511
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
2512
- }
2513
-
2514
-
2515
-
2516
- ;// ./lib/models/templateCompiler/helpers/_sum.js
2517
- function _sum(data, args) {
2518
- if (Number.isNaN(data) || data === null || (typeof data === 'undefined') || data === '') {
2519
- return data
2520
- }
2521
- return args.reduce((acc, e) => (acc + e), data)
2522
- }
2523
-
2524
-
2525
-
2526
- ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
2527
-
2528
-
2529
- function _toLowerCase(data, args) {
2530
- if (args !== undefined) {
2531
- throw new TemplateCompilerException(`_toLowerCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
2532
- }
2533
- if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
2534
- return null
2535
- }
2536
- return String(data).toLowerCase()
2537
- }
2538
-
2539
-
2540
-
2541
- ;// ./lib/models/templateCompiler/helpers/_toUpperCase.js
2542
-
2543
-
2544
- function _toUpperCase(data, args) {
2545
- if (typeof data !== 'string') {
2546
- throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string: ${data}`)
2547
- }
2548
- if (args !== undefined) {
2549
- throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the argument must be empty: ${args.join(', ')}`)
2550
- }
2551
- if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
2552
- return null
2553
- }
2554
- return String(data).toUpperCase()
2555
- }
2556
-
2557
-
2558
-
2559
- ;// ./lib/models/templateCompiler/helpers/index.js
2560
-
2561
-
2562
-
2563
-
2564
-
2565
-
2566
-
2567
-
2568
-
2569
-
2570
-
2571
-
2572
-
2573
-
2574
-
2575
-
2576
-
2577
-
2578
-
2579
-
2580
-
2581
-
2582
-
2583
-
2584
- ;// ./lib/models/templateCompiler/templateCompiler.js
2585
-
2586
-
2587
-
2588
-
2589
- class TemplateCompiler {
2590
- constructor(data) {
2591
- this.data = data
2592
- }
2593
- static init(options) {
2594
- return new this(options)
2595
- }
2596
- static initFromArray(arr = []) {
2597
- if (Array.isArray(arr)) {
2598
- return arr.map((a) => this.init(a))
2599
- }
2600
- return []
2601
- }
2602
- static initOnlyValidFromArray(arr = []) {
2603
- return this.initFromArray(arr).filter((i) => i)
2604
- }
2605
- static concatIf(data, args) {
2606
- return _concatIf(data, args)
2607
- }
2608
- static divide(data, args) {
2609
- return _divide(data, args)
2610
- }
2611
- static eq(data, args) {
2612
- return _eq(data, args)
2613
- }
2614
-
2615
- static filterAll(data, args) {
2616
- return _filterAll(data, args)
2617
- }
2618
-
2619
- static formatDate(data, args) {
2620
- return _formatDate(data, args)
2621
- }
2622
- static get(data, key, failover = null) {
2623
- return _get(data, key, failover)
2624
- }
2625
- static gt(data, args) {
2626
- return _gt(data, args)
2627
- }
2628
- static gte(data, args) {
2629
- return _gte(data, args)
2630
- }
2631
- static isEmpty(data, args) {
2632
- return _isEmpty(data, args)
2633
- }
2634
- static isNotEmpty(data, args) {
2635
- return _isNotEmpty(data, args)
2636
- }
2637
- static join(data, separator = '') {
2638
- return _join(data, separator)
2639
- }
2640
- static lt(data, args) {
2641
- return _lt(data, args)
2642
- }
2643
- static lte(data, args) {
2644
- return _lte(data, args)
2645
- }
2646
- static map(data, args = []) {
2647
- return _map(data, args)
2648
- }
2649
- static neq(data, args) {
2650
- return _neq(data, args)
2651
- }
2652
- static removeHtml(data, args) {
2653
- return _removeHtml(data, args)
2654
- }
2655
- static sum(data, args) {
2656
- return _sum(data, args)
2657
- }
2658
- static toLowerCase(data, args) {
2659
- return _toLowerCase(data, args)
2660
- }
2661
- static toUpperCase(data, args) {
2662
- return _toUpperCase(data, args)
2663
- }
2664
- static parseFunction(expression) {
2665
- return _parseFunction(expression, _FN_NAMES)
2666
- }
2667
- static parseParams(parameters) {
2668
- return _parseParams(parameters)
2669
- }
2670
-
2671
- pipe(expression = '') {
2672
- this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
2673
- const regex = new RegExp(`${this.delimiters[0]}\\s(.*?)\\s${this.delimiters[1]}`)
2674
- const match = expression.match(regex)
2675
- if (match !== null) {
2676
- try {
2677
- const functionList = _parseFunction(match[1], _FN_NAMES)
2678
- return functionList.reduce((acc, fn) => {
2679
- return _callFunction(acc, fn.name, fn.args)
2680
- }, this.data)
2681
- } catch (e) {
2682
- throw new TemplateCompilerException(`TemplateCompiler engine error: ${e.message}`)
2683
- }
2684
- }
2685
- throw new TemplateCompilerException(`TemplateCompiler engine error: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.invalidRegExpException}`)
2686
- }
2687
- }
2688
-
2689
- function _parseFunction(expression, existFunctionNames) {
2690
- const regExp = new RegExp(/(\w+)\(([^)]*)\)/)
2691
- let parts
2692
- if (expression.includes('|')) {
2693
- parts = expression.split('|')
2694
- } else {
2695
- parts = [expression]
2696
- }
2697
- return parts.reduce((acc, part) => {
2698
- const match = part.match(regExp)
2699
- if (match !== null) {
2700
- const functionName = match[1]
2701
- const parameters = match[2]
2702
- const paramList = _parseParams(parameters)
2703
- if (existFunctionNames.includes(functionName)) {
2704
- acc.push({
2705
- name: functionName,
2706
- args: paramList
2707
- })
2708
- } else {
2709
- throw new TemplateCompilerException(`${functionName} is not a valid function`)
2710
- }
2711
- }
2712
- return acc
2713
- }, [])
2714
- }
2715
-
2716
- function _parseParams(parameters) {
2717
- const _parameters = parameters.trim()
2718
- const regExp = new RegExp(/^[^\w\s]+$/)
2719
- const match = _parameters.match(regExp)
2720
- if (match !== null) {
2721
- return [_parameters.substring(1, _parameters.length - 1)]
2722
- }
2723
- if (_parameters.includes(',')) {
2724
- // 用正则表达式匹配逗号,但忽略方括号中的逗号
2725
- const parts = _splitIgnoringBrackets(_parameters)
2726
- return parts.map((part) => _parseSinglePart(part))
2727
- }
2728
- return [_parseSinglePart(_parameters)]
2729
- }
2730
-
2731
- function _splitIgnoringBrackets(input) {
2732
- const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
2733
- const regExp = new RegExp(/(?![^[]*\])\s*,\s*/)
2734
- const parts = input.split(regExp)
2735
- return parts.map((part) => {
2736
- const _part = part.trim()
2737
- if (_part !== '' && !!_part.match(regExp2)) {
2738
- // 如果是数字,转换为 num 类型
2739
- return Number.isNaN(_part) ? _part : Number.parseInt(_part, 10)
2740
- }
2741
- // 否则当作字符串处理
2742
- return _part
2743
- })
2744
- }
2745
-
2746
- function _parseSinglePart(input) {
2747
- if (typeof input === 'string') {
2748
- if (input.startsWith('"') && input.endsWith('"')) {
2749
- // 去掉双引号,返回
2750
- return input.substring(1, input.length - 1)
2751
- }
2752
- if (input.startsWith('\'') && input.endsWith('\'')) {
2753
- // 去掉双引号,返回
2754
- return input.substring(1, input.length - 1)
2755
- }
2756
-
2757
- const _input = _toBasicType(input)
2758
-
2759
- if (typeof _input !== 'string') {
2760
- return _input
2761
- }
2762
-
2763
- // 如果是一个列表形式(例如 ["p", "d"] 或 [p, d])
2764
- if (_input.startsWith('[') && _input.endsWith(']')) {
2765
- const listContent = _input.substring(1, _input.length - 1).trim()
2766
- if (listContent !== '') {
2767
- return listContent.split(',').map((item) => {
2768
- return _toBasicType(item.trim())
2769
- })
2770
- }
2771
- return []
2772
- }
2773
- return input
2774
- }
2775
- return input
2776
- }
2777
-
2778
- function _toBasicType(input) {
2779
- if (input.startsWith('"') && input.endsWith('"')) {
2780
- // 去掉双引号,返回
2781
- return input.substring(1, input.length - 1)
2782
- }
2783
- if (input.startsWith('\'') && input.endsWith('\'')) {
2784
- // 去掉双引号,返回
2785
- return input.substring(1, input.length - 1)
2786
- }
2787
- if (input === 'true') {
2788
- return true
2789
- }
2790
- if (input === 'false') {
2791
- return false
2792
- }
2793
- if (input === 'undefined') {
2794
- return undefined
2795
- }
2796
- if (input === 'null') {
2797
- return null
2798
- }
2799
- if (!Number.isNaN(input) && !Number.isNaN(Number.parseFloat(input))) {
2800
- return Number(input)
2801
- }
2802
- return input
2803
- }
2804
-
2805
- function _callFunction(data, functionName, parameters) {
2806
- try {
2807
- let failover
2808
- switch (functionName) {
2809
- case 'concatIf':
2810
- return _concatIf(data, parameters)
2811
- case 'divide':
2812
- return _divide(data, parameters)
2813
- case 'eq':
2814
- return _eq(data, parameters)
2815
- case 'exec':
2816
- return _exec(data, parameters)
2817
- case 'filterAll':
2818
- return _filterAll(data, parameters)
2819
- case 'filterOne':
2820
- return _filterOne(data, parameters)
2821
- case 'formatDate':
2822
- return _formatDate(data, parameters)
2823
- case 'get':
2824
- if (parameters.length > 2) {
2825
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
2826
- }
2827
- if (parameters.length === 2) {
2828
- failover = parameters[parameters.length - 1]
2829
- }
2830
- return _get(data, parameters[0], failover)
2831
- case 'gt':
2832
- return _gt(data, parameters)
2833
- case 'gte':
2834
- return _gte(data, parameters)
2835
- case 'isEmpty':
2836
- return _isEmpty(data, parameters)
2837
- case 'isNotEmpty':
2838
- return _isNotEmpty(data, parameters)
2839
- case 'join':
2840
- return _join(data, parameters[0])
2841
- case 'lt':
2842
- return _lt(data, parameters)
2843
- case 'lte':
2844
- return _lte(data, parameters)
2845
- case 'map':
2846
- return _map(data, parameters)
2847
- case 'neq':
2848
- return _neq(data, parameters)
2849
- case 'removeHtml':
2850
- return _removeHtml(data, parameters)
2851
- case 'sum':
2852
- return _sum(data, parameters)
2853
- case 'toLowerCase':
2854
- return _toLowerCase(data)
2855
- case 'toUpperCase':
2856
- return _toUpperCase(data)
2857
- default:
2858
- throw new Error(`${functionName} is not a valid function`)
2859
- }
2860
- } catch (e) {
2861
- throw e
2862
- }
2863
- }
2864
-
2865
-
2866
-
2867
- ;// ./lib/models/templateCompiler/index.js
2868
-
2869
-
2870
-
2871
-
2872
- ;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
2873
-
2874
-
2875
-
2876
-
2877
- class TenantAwareEntity extends TrackedEntity {
2878
- constructor(options = {}) {
2879
- options = options || {}
2880
-
2881
- /**
2882
- * instead of throw error, we choose to implement the isValid checking
2883
- */
2884
- // if (!options.tenantCode) {
2885
- // throw new Error('tenantCode required')
2886
- // }
2887
-
2888
- super(options)
2889
-
2890
- this._tenant = options._tenant
2891
-
2892
- this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
2893
- this.remarks = keyValueObject_KeyValueObject.initOnlyValidFromArray(options.remarks)
2894
- this.tenantCode = options.tenantCode // Required for multi-tenancy
2895
- }
2896
-
2897
- // Class methods
2898
- static get _classname() {
2899
- return 'TenantAwareEntity'
2900
- }
2901
- static get _superclass() {
2902
- return 'TenantAwareEntity'
2903
- }
2904
-
2905
- // getters
2906
- get __valid() {
2907
- return {
2908
- ...super.__valid,
2909
- tenantCode: this.tenantCode
2910
- }
2911
- }
2912
- get isValid() {
2913
- return super.isValid && !!this.tenantCode // Required for multi-tenancy
2914
- }
2915
-
2916
- // instance methods
2917
- insertOrUpdateMetadata(key, value) {
2918
- this.metadata = Metadata.insertOrUpdateRecord(this.metadata, key, value)
2919
- return this
2920
- }
2921
- getMetadata() {
2922
- return this.metadata
2923
- }
2924
- getMetadataByKey(key) {
2925
- return Metadata.foundByKey(this.metadata, key)
2926
- }
2927
- getMetadataValueByKey(key) {
2928
- const found = this.getMetadataByKey(key)
2929
- return found ? found.value : null
2930
- }
2931
- getMetadataValueByKeys(keys, kv) {
2932
- if (!Array.isArray(keys)) {
2933
- return null
2934
- }
2935
- kv = kv || this.metadata
2936
- if (keys.length === 0) {
2937
- return kv
2938
- }
2939
- const key = keys.shift()
2940
- const _val = Metadata.getMetadataValueByKeyAsArray(kv, key)
2941
- return this.getMetadataValueByKeys(keys, _val)
2942
- }
2943
- getMetadataValueByKeyAsArray(key) {
2944
- return Metadata.getMetadataValueByKeyAsArray(this.metadata, key)
2945
- }
2946
- getRemarks() {
2947
- return this.remarks
2948
- }
2949
- getRemarkByKey(key) {
2950
- return keyValueObject_KeyValueObject.foundByKey(this.remarks, key)
2951
- }
2952
- getRemarksValueByKey(key) {
2953
- const found = this.getRemarkByKey(key)
2954
- return found ? found.value : null
2955
- }
2956
- getTenantCode() {
2957
- return this.tenantCode
2958
- }
2959
-
2960
- update(update) {
2961
- if (update.metadata && Array.isArray(update.metadata)) {
2962
- this.metadata = Metadata.initOnlyValidFromArray(update.metadata)
2963
- }
2964
- if (update.remarks && Array.isArray(update.remarks)) {
2965
- this.remarks = keyValueObject_KeyValueObject.initOnlyValidFromArray(update.remarks)
2966
- }
2967
- return super.update(update)
2968
- }
2969
- }
2970
-
2971
- ;// ./lib/models/tenantAwareEntity/index.js
2972
-
2973
-
2974
-
2975
- ;// ./lib/models/uniqueKeyGenerator/uniqueKeyGenerator.js
2976
-
2977
-
2978
- class UniqueKeyGenerator {
2979
- static get _classname() {
2980
- return 'UniqueKeyGenerator'
2981
- }
2982
- static get _superclass() {
2983
- return 'UniqueKeyGenerator'
2984
- }
2985
- static makeFormatter({ fieldName, format, options }) {
2986
- switch (format) {
2987
- case 'set_code':
2988
- return _makeSetCode(fieldName, options)
2989
- default:
2990
- return _makeSetCode(fieldName, options)
2991
- }
2992
- }
2993
- static makeGenerator(arr) {
2994
- const fns = arr.map((item) => this.makeFormatter(item))
2995
- return async (obj) => {
2996
- const output = await pReduce(fns, async (acc, fn) => {
2997
- const _obj = await fn(obj)
2998
- return Object.assign(acc, _obj)
2999
- }, obj)
3000
- return output
3001
- }
3002
- }
3003
- }
3004
-
3005
- function _makeSetCode(fieldName, options) {
3006
- return async (obj = {}) => {
3007
- if (obj[fieldName]) {
3008
- return {}
3009
- }
3010
- return {
3011
- [fieldName]: stringHelper.setCode()
3012
- }
3013
- }
3014
- }
3015
-
3016
-
3017
-
3018
- ;// ./lib/models/uniqueKeyGenerator/index.js
3019
-
3020
-
3021
-
3022
-
3023
- ;// ./lib/models/index.js
3024
-
3025
-
3026
-
3027
-
3028
-
3029
-
3030
-
3031
-
3032
-
3033
-
3034
-
3035
-
3036
-
3037
-
3038
- ;// ./lib/helpers/getValidation/getValidation.js
3039
-
3040
-
3041
-
3042
-
3043
- function getValidation(rule, data, getDataByKey = _getDataByKey, KeyValueObject = keyValueObject_KeyValueObject) {
3044
- if (!rule) {
3045
- return true
3046
- }
3047
- if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
3048
- return false
3049
- }
3050
- const { key = '', value, placeholder, keyValuePath = '' } = rule
3051
- const [valueAttribute] = Object.keys(value)
3052
-
3053
- if (!key && typeof placeholder === 'undefined') {
3054
- switch (valueAttribute) {
3055
- case '$and': {
3056
- return value.$and.reduce((acc, item) => (acc && getValidation(item, data, getDataByKey, KeyValueObject)), true)
3057
- }
3058
- case '$or': {
3059
- return value.$or.reduce((acc, item) => (acc || getValidation(item, data, getDataByKey, KeyValueObject)), false)
3060
- }
3061
- default:
3062
- return false
3063
- }
3064
- }
3065
- let rowValue = typeof placeholder === 'undefined' ? getDataByKey(key, data) : placeholder
3066
-
3067
- // if KeyValue object
3068
- if (keyValuePath) {
3069
- const rowValueData = KeyValueObject.toObject(rowValue)
3070
- rowValue = getDataByKey(keyValuePath, rowValueData)
3071
- }
3072
-
3073
- switch (valueAttribute) {
3074
- case '$after': {
3075
- if (isConvertibleToNumber(value?.$after)) {
3076
- const _value = Number(String(value?.$after))
3077
- return Date.now() > _value
3078
- }
3079
- return false
3080
- }
3081
- case '$before': {
3082
- if (isConvertibleToNumber(value?.$before)) {
3083
- const _value = Number(String(value?.$before))
3084
- return Date.now() < _value
3085
- }
3086
- return false
3087
- }
3088
- case '$empty': {
3089
- const isEmpty = rowValue === null || rowValue === undefined
3090
- return isEmpty === value.$empty
3091
- }
3092
- case '$eq': {
3093
- return rowValue === value.$eq
3094
- }
3095
- case '$gt': {
3096
- return rowValue > value.$gt
3097
- }
3098
- case '$gte': {
3099
- return rowValue >= value.$gte
3100
- }
3101
- case '$hasOverlap': {
3102
- return _hasOverlap(rowValue, value.$hasOverlap)
3103
- }
3104
- case '$lt': {
3105
- return rowValue < value.$lt
3106
- }
3107
- case '$lte': {
3108
- return rowValue <= value.$lte
3109
- }
3110
- case '$in': {
3111
- if (Array.isArray(rowValue)) {
3112
- return !!rowValue.find((e) => (value.$in.includes(e)))
3113
- }
3114
- if (typeof rowValue !== 'object') {
3115
- return !!value.$in.includes(rowValue)
3116
- }
3117
- return false
3118
- }
3119
- case '$includes': {
3120
- if (Array.isArray(rowValue)) {
3121
- return rowValue.includes(value.$includes)
3122
- }
3123
- return false
3124
- }
3125
- case '$intervalTimeGt': {
3126
- const now = new Date().getTime()
3127
- const timestamp = new Date(rowValue).getTime()
3128
- return (now - timestamp) > value.$intervalTimeGt
3129
- }
3130
- case '$intervalTimeLt': {
3131
- const now = new Date().getTime()
3132
- const timestamp = new Date(rowValue).getTime()
3133
- return (now - timestamp) < value.$intervalTimeLt
3134
- }
3135
- case '$inValue': {
3136
- const result = getDataByKey(value.$inValue, data)
3137
- const _value = Array.isArray(result) ? result : []
3138
- if (Array.isArray(rowValue)) {
3139
- return !!rowValue.find((e) => (_value.includes(e)))
3140
- }
3141
- if (typeof rowValue === 'string') {
3142
- return !!_value.includes(rowValue)
3143
- }
3144
- return false
3145
- }
3146
- case '$isToday': {
3147
- const currentDate = new Date()
3148
- const start = currentDate.setHours(0, 0, 0, 0)
3149
- const end = currentDate.setHours(23, 59, 59, 59)
3150
- const dateValue = new Date(rowValue).getTime()
3151
- return (start <= dateValue && end >= dateValue) === value.$isToday
3152
- }
3153
- case '$ne': {
3154
- return rowValue !== value.$ne
3155
- }
3156
- case '$notIn': {
3157
- if (Array.isArray(rowValue)) {
3158
- return !rowValue.find((e) => (value.$notIn.includes(e)))
3159
- }
3160
- if (typeof rowValue !== 'object') {
3161
- return !value.$notIn.includes(rowValue)
3162
- }
3163
- return false
3164
- }
3165
- case '$notInValue': {
3166
- const result = getDataByKey(value.$notInValue, data)
3167
- const _value = Array.isArray(result) ? result : []
3168
- if (Array.isArray(rowValue)) {
3169
- return !rowValue.find((e) => (_value.includes(e)))
3170
- }
3171
- if (typeof rowValue !== 'object') {
3172
- return !_value.includes(rowValue)
3173
- }
3174
- return false
3175
- }
3176
- case '$range': {
3177
- const [min, max] = value.$range
3178
- if (typeof min === 'number' && typeof max === 'number' && rowValue >= min && rowValue <= max) {
3179
- return true
3180
- }
3181
- return false
3182
- }
3183
- default:
3184
- return false
3185
- }
3186
- }
3187
-
3188
- function _getDataByKey(key, data) {
3189
- return getValueByKeys_getValueByKeys(key.split('.'), data)
3190
- }
3191
-
3192
- function _hasOverlap(item1, item2) {
3193
- let arr1 = item1
3194
- let arr2 = item2
3195
- if (typeof arr1 === 'string') {
3196
- arr1 = arr1.split(',')
3197
- }
3198
- if (typeof arr2 === 'string') {
3199
- arr2 = arr2.split(',')
3200
- }
3201
- const set1 = new Set(arr1)
3202
- return arr2.find((i) => (set1.has(i)))
3203
- }
3204
-
3205
- /* harmony default export */ const getValidation_getValidation = ({
3206
- getValidation
3207
- });
3208
-
3209
-
3210
- ;// ./lib/helpers/getValidation/index.js
3211
-
3212
-
3213
- ;// ./lib/helpers/formatDate/formatDate.js
3214
- function formatDate(date, format) {
3215
- const _date = date && date instanceof Date ? date : new Date(date)
3216
- const dayMapChi = ['日', '一', '二', '三', '四', '五', '六']
3217
- const dayMapEng = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
3218
- const dayMapEngShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
3219
- const _format = format || 'YYYY/MM/DD hh:mm'
3220
- const e = _date.getDay()
3221
- const ee = dayMapEngShort[e]
3222
- const eee = dayMapChi[e]
3223
- const eeee = dayMapEng[e]
3224
- const y = _date.getFullYear()
3225
- const m = _date.getMonth() + 1
3226
- const d = _date.getDate()
3227
- const h = _date.getHours()
3228
- const mm = _date.getMinutes()
3229
- const s = _date.getSeconds()
3230
-
3231
- return _format.replace('YYYY', y)
3232
- .replace('MM', padding(m))
3233
- .replace('MM', padding(m))
3234
- .replace('DD', padding(d))
3235
- .replace('hh', padding(h))
3236
- .replace('mm', padding(mm))
3237
- .replace('ss', padding(s))
3238
- .replace('M', m)
3239
- .replace('D', d)
3240
- .replace('h', h)
3241
- .replace('m', mm)
3242
- .replace('s', s)
3243
- .replace('EEEE', padding(eeee))
3244
- .replace('EEE', padding(eee))
3245
- .replace('EE', padding(ee))
3246
- .replace('E', padding(e))
3247
- }
3248
-
3249
- function padding(m) {
3250
- return m < 10 ? `0${m}` : m
3251
- }
3252
-
3253
- /* harmony default export */ const formatDate_formatDate = ({
3254
- formatDate
3255
- });
3256
-
3257
-
3258
- ;// ./lib/helpers/formatDate/index.js
3259
-
3260
-
3261
- ;// ./lib/helpers/concatStringByArray/concatStringByArray.js
3262
-
3263
-
3264
-
3265
-
3266
-
3267
- function concatStringByArray(arrTemplate, data) {
3268
- return arrTemplate.reduce((acc, item) => {
3269
- const { type, value = '', restriction, template, format, showMinutes } = item
3270
- switch (type) {
3271
- case ('array'): {
3272
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3273
- const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || []
3274
- acc += _value.reduce((_acc, item) => {
3275
- return _acc += concatStringByArray(template, item)
3276
- }, '')
3277
- }
3278
- break
3279
- }
3280
- case ('date'): {
3281
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3282
- const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
3283
- acc += (formatDate(_value, format).toString())
3284
- }
3285
- break
3286
- }
3287
- case ('ellipsis'): {
3288
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3289
- const { maxLength } = item
3290
- const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
3291
- if (_value.length <= maxLength) {
3292
- acc += (_value.toString())
3293
- } else {
3294
- acc += `${_value.substr(0, maxLength)}...`
3295
- }
3296
- }
3297
- break
3298
- }
3299
- case ('group'): {
3300
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3301
- return concatStringByArray(value, data)
3302
- }
3303
- break
3304
- }
3305
- case ('label'): {
3306
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3307
- acc += (value.toString())
3308
- }
3309
- break
3310
- }
3311
- case ('templateCompiler'): {
3312
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3313
- const templateCompiler = new TemplateCompiler({ data })
3314
- acc += templateCompiler.pipe(value)
3315
- }
3316
- break
3317
- }
3318
- case ('value'): {
3319
- if (getValidation(restriction, data, getValueByKeys_getValueByKeys)) {
3320
- const _value = getValueByKeys_getValueByKeys(value.split('.'), data) || ''
3321
- acc += (_value.toString())
3322
- }
3323
- break
3324
- }
3325
- }
3326
- return acc
3327
- }, '')
3328
- }
3329
- /* harmony default export */ const concatStringByArray_concatStringByArray = ({
3330
- concatStringByArray
3331
- });
3332
-
3333
-
3334
- ;// ./lib/helpers/concatStringByArray/index.js
3335
-
3336
-
3337
- ;// ./lib/helpers/convertString/convertString.js
3338
-
3339
-
3340
- function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByKeys) {
3341
- if (!string) {
3342
- return ''
3343
- }
3344
- const _getValueByKeys = typeof getValueByKeys === 'function' ? getValueByKeys : getValueByKeys_getValueByKeys
3345
- const reg = new RegExp(patternMatch, 'g')
3346
- return string.replace(reg, (match, key) => {
3347
- const result = _getValueByKeys({ keys: key.split('.'), obj: value })
3348
- if (result === null || result === undefined) {
3349
- return ''
3350
- }
3351
- return typeof result === 'object' ? JSON.stringify(result) : result
3352
- })
3353
- }
3354
-
3355
- /* harmony default export */ const convertString_convertString = ({
3356
- convertString
3357
- });
3358
-
3359
-
3360
- ;// ./lib/helpers/convertString/index.js
3361
-
3362
-
3363
- ;// ./lib/helpers/detectControlCharacters/detectControlCharacters.js
3364
- /**
3365
- * Detects and reports hidden/control characters in a string without modifying it.
3366
- * @param {string} input - The string to analyze.
3367
- * @param {Object} [options] - Configuration options.
3368
- * @param {boolean} [options.preserveBasicWhitespace=true] - Whether to consider basic whitespace as valid.
3369
- * @returns {Object} Report object with detection results.
3370
- */
3371
- function detectControlCharacters(input, options = {}) {
3372
- const {
3373
- preserveBasicWhitespace = true,
3374
- removeNewlines = false
3375
- } = options
3376
-
3377
- if (typeof input !== 'string') {
3378
- return {
3379
- hasControlChars: false,
3380
- matches: [],
3381
- inputType: typeof input,
3382
- message: 'Input is not a string'
3383
- }
3384
- }
3385
-
3386
- const matches = []
3387
- let regex
3388
-
3389
- if (preserveBasicWhitespace && !removeNewlines) {
3390
- // Same regex as Phase 1 preserve mode - keep tab (\t), newline (\n), carriage return (\r)
3391
- regex = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
3392
- } else {
3393
- // Same regex as Phase 1 full removal mode - use consistent escape sequences
3394
- regex = /[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
3395
- }
3396
-
3397
- // Use a replacer function to capture matches without modifying the string
3398
- input.replace(regex, (match, offset) => {
3399
- matches.push({
3400
- character: match,
3401
- code: match.charCodeAt(0),
3402
- hex: '0x' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'),
3403
- position: offset,
3404
- context: getContext(input, offset, 10) // Show surrounding text
3405
- })
3406
- return '' // Return empty but we don't use the result
3407
- })
3408
-
3409
- return {
3410
- hasControlChars: matches.length > 0,
3411
- matches,
3412
- totalFound: matches.length,
3413
- inputPreview: input.length > 50 ? input.substring(0, 50) + '...' : input,
3414
- inputLength: input.length,
3415
- optionsUsed: { preserveBasicWhitespace },
3416
- regexPattern: regex.toString()
3417
- }
3418
- }
3419
-
3420
- /**
3421
- * Helper function to get context around a match
3422
- */
3423
- function getContext(str, position, contextLength = 10) {
3424
- const start = Math.max(0, position - contextLength)
3425
- const end = Math.min(str.length, position + contextLength + 1)
3426
- let context = str.substring(start, end)
3427
-
3428
- // Replace control characters with their escape sequences for readability
3429
- context = context.replace(/[\x00-\x1F\x7F-\x9F]/g, (match) => {
3430
- return '\\u' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
3431
- })
3432
-
3433
- return context
3434
- }
3435
-
3436
- /**
3437
- * Pretty print the detection results to console
3438
- */
3439
- function printControlCharReport(report) {
3440
- console.log('=== Control Character Detection Report ===')
3441
- console.log(`Input: "${report.inputPreview}" (${report.inputLength} chars)`)
3442
- console.log(`Options: preserveBasicWhitespace = ${report.optionsUsed.preserveBasicWhitespace}`)
3443
- console.log(`Regex pattern: ${report.regexPattern}`)
3444
- console.log(`Control characters found: ${report.totalFound}`)
3445
-
3446
- if (report.hasControlChars) {
3447
- console.log('\n📋 Matches found:')
3448
- report.matches.forEach((match, index) => {
3449
- console.log(`\n${index + 1}. Character: ${JSON.stringify(match.character)}`)
3450
- console.log(` Code: ${match.code} (${match.hex})`)
3451
- console.log(` Position: ${match.position}`)
3452
- console.log(` Context: "...${match.context}..."`)
3453
- })
3454
- } else {
3455
- console.log('✅ No control characters detected in Phase 1 range')
3456
- }
3457
-
3458
- console.log('=== End Report ===')
3459
- }
3460
-
3461
- ;// ./lib/helpers/detectControlCharacters/index.js
3462
-
3463
-
3464
- ;// ./lib/helpers/downloadFileByUrl/downloadFileByUrl.js
3465
- function downloadFileByUrl({ dataUrl = '', filename = '' } = {}) {
3466
- const link = document.createElement('a')
3467
- link.download = filename
3468
- link.href = dataUrl
3469
- document.body.appendChild(link)
3470
- link.click()
3471
- document.body.removeChild(link)
3472
- }
3473
-
3474
-
3475
-
3476
- ;// ./lib/helpers/downloadFileByUrl/index.js
3477
-
3478
-
3479
-
3480
-
3481
- ;// ./lib/helpers/escapeRegex/escapeRegex.js
3482
- function escapeRegex(string) {
3483
- return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
3484
- }
3485
-
3486
- ;// ./lib/helpers/escapeRegex/index.js
3487
-
3488
-
3489
- ;// ./lib/helpers/expressHelper/customHandler.js
3490
- function customHandler({ responseHelper, handler, ignoreError = false }) {
3491
- return async (req, res, next) => {
3492
- try {
3493
- await handler({ req, res })
3494
- await next()
3495
- } catch (err) {
3496
- if (ignoreError || !responseHelper) {
3497
- await next()
3498
- } else {
3499
- res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
3500
- }
3501
- }
3502
- }
3503
- }
3504
-
3505
- ;// ./lib/helpers/expressHelper/findAllResult.js
3506
- function findAllResult({ responseHelper, service }) {
3507
- return async (req, res, next) => {
3508
- try {
3509
- const { query } = req
3510
- const result = await service.findAll({ query })
3511
- res.locals.findAllResult = result
3512
- await next()
3513
- } catch (err) {
3514
- res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
3515
- }
3516
- }
3517
- }
3518
-
3519
- ;// ./lib/helpers/expressHelper/findOneResult.js
3520
- function findOneResult({ responseHelper, service }) {
3521
- return async (req, res, next) => {
3522
- try {
3523
- const { params, query } = req
3524
- const { id } = params
3525
- const result = await service.findOne({
3526
- query: {
3527
- ...query,
3528
- id
3529
- }
3530
- })
3531
- res.locals.findOneResult = result
3532
- await next()
3533
- } catch (err) {
3534
- res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
3535
- }
3536
- }
3537
- }
3538
-
3539
- ;// ./lib/helpers/expressHelper/postResult.js
3540
- function postResult({ responseHelper, service }) {
3541
- return async (req, res, next) => {
3542
- try {
3543
- const { body } = req
3544
- let result
3545
- if (Array.isArray(body)) {
3546
- result = await service.saveAll({ docs: body })
3547
- } else {
3548
- result = await service.saveOne({ doc: body })
3549
- }
3550
- res.locals.postResult = result
3551
- await next()
3552
- } catch (err) {
3553
- res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
3554
- }
3555
- }
3556
- }
3557
-
3558
- ;// ./lib/helpers/expressHelper/updateOneResult.js
3559
- function updateOneResult({ responseHelper, service }) {
3560
- return async (req, res, next) => {
3561
- try {
3562
- const { body, params } = req
3563
- const { id } = params
3564
- if (id !== body.id) {
3565
- throw new Error('id in params and body must be same')
3566
- }
3567
- const { data } = await service.findOne({ query: { id } })
3568
- const doc = data[0]
3569
- doc.update(body)
3570
- const result = await service.saveOne({ doc })
3571
- res.locals.updateOneResult = result
3572
- await next()
3573
- } catch (err) {
3574
- res.status(400).json(responseHelper.standardizeResponse({ err, message: err.message || err }))
3575
- }
3576
- }
3577
- }
3578
-
3579
- ;// ./lib/helpers/expressHelper/index.js
3580
-
3581
-
3582
-
3583
-
3584
-
3585
-
3586
- const expressHelper = {
3587
- customHandler: customHandler,
3588
- findAllResult: findAllResult,
3589
- findOneResult: findOneResult,
3590
- postResult: postResult,
3591
- updateOneResult: updateOneResult,
3592
- }
3593
-
3594
- ;// ./lib/helpers/extractEmails/extractEmails.js
3595
- /**
3596
- * Extracts and normalizes unique email addresses from an array containing messy entries
3597
- * @param {Array} dirtyArray - Array that may contain emails in various formats (may include null/empty entries)
3598
- * @returns {Array} Sorted array of unique, lowercase email addresses
3599
- */
3600
- function extractEmails(dirtyArray) {
3601
- const emailRegex = /[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi
3602
- const emails = new Set()
3603
-
3604
- // Handle null/undefined input array
3605
- if (!dirtyArray)
3606
- return []
3607
-
3608
- dirtyArray.forEach((entry) => {
3609
- // Skip null, undefined, empty, or whitespace-only entries
3610
- if (!entry || typeof entry !== 'string' || !entry.trim())
3611
- return
3612
-
3613
- try {
3614
- const cleanEntry = entry
3615
- .replace(/[\u200B-\u200D\uFEFF\u202A-\u202E]/g, '') // Remove hidden chars
3616
- .replace(/[<>]/g, ' ') // Convert email delimiters to spaces
3617
- .replace(/\s+/g, ' ') // Collapse multiple whitespace
3618
- .trim()
3619
-
3620
- // Extract all email matches
3621
- const matches = cleanEntry.match(emailRegex)
3622
- if (matches) {
3623
- matches.forEach((email) => emails.add(email.toLowerCase())) // Normalize to lowercase
3624
- }
3625
- } catch (e) {
3626
- console.warn('Failed to process entry:', entry, e)
3627
- }
3628
- })
3629
-
3630
- // Convert Set to array and sort alphabetically
3631
- return Array.from(emails).sort((a, b) => a.localeCompare(b))
3632
- }
3633
-
3634
- ;// ./lib/helpers/extractEmails/index.js
3635
-
3636
-
3637
- ;// ./lib/helpers/pReduce/pReduce.js
3638
- async function pReduce(iterable, reducer, initialValue) {
3639
- return new Promise((resolve, reject) => {
3640
- const iterator = iterable[Symbol.iterator]()
3641
- let index = 0
3642
-
3643
- const next = async (total) => {
3644
- const element = iterator.next()
3645
-
3646
- if (element.done) {
3647
- resolve(total)
3648
- return
3649
- }
3650
-
3651
- try {
3652
- const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
3653
- next(reducer(resolvedTotal, resolvedValue, index++))
3654
- } catch (error) {
3655
- reject(error)
3656
- }
3657
- }
3658
-
3659
- next(initialValue)
3660
- })
3661
- }
3662
-
3663
-
3664
-
3665
- ;// ./lib/helpers/generalPost/generalPost.js
3666
-
3667
-
3668
-
3669
-
3670
-
3671
- async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
3672
- const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
3673
- const _resourceInfo = resourceInfo || body.resourceInfo
3674
- _attachShared(data, globalShared, shared)
3675
- const obj = await pReduce(resources, async (acc, resource) => {
3676
- const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
3677
- _createRelationship(data, relationship[resource], acc)
3678
- const _data = data[resource]
3679
- const result = await service.saveAll({ docs: [].concat(_data) })
3680
- acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
3681
- return acc
3682
- }, {})
3683
- return obj
3684
- }
3685
-
3686
- function _attachShared(data, globalShared = {}, shared = {}) {
3687
- Object.keys(shared).forEach((key) => {
3688
- const _data = data[key]
3689
- if (Array.isArray(_data)) {
3690
- data[key] = _data.map((_dataItem) => {
3691
- return objectHelper.merge({}, _dataItem, globalShared, shared[key] || {})
3692
- })
3693
- } else {
3694
- data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
3695
- }
3696
- })
3697
- }
3698
-
3699
- function _createRelationship(data, relationship = {}, object) {
3700
- Object.keys(relationship).forEach((key) => {
3701
- const path = relationship[key]
3702
- const val = objectHelper.get(object, path)
3703
- objectHelper.set(data, key, val)
3704
- })
3705
- }
3706
-
3707
- function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
3708
- const { collectionName, fields } = resourceInfo[resource]
3709
- const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
3710
- const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
3711
- return makeService({
3712
- repo: new Repo({ model })
3713
- })
3714
- }
3715
-
3716
-
3717
-
3718
- ;// ./lib/helpers/generalPost/index.js
3719
-
3720
-
3721
-
3722
-
3723
- ;// ./lib/helpers/getObjectByArr/getObjectByArr.js
3724
-
3725
-
3726
- function getObjectByArr(arr, data, getValueByKeys, getValidation, KeyValueObject) {
3727
- const _KeyValueObject = KeyValueObject || keyValueObject_KeyValueObject
3728
- if (!Array.isArray(arr) || arr.length === 0) {
3729
- return null
3730
- }
3731
- return arr.reduce((acc, e) => {
3732
- const { key, type, value, restriction } = e
3733
- const isValid = getValidation && typeof getValidation === 'function' ? getValidation({ rule: restriction, data }) : true
3734
- if (isValid) {
3735
- let _value = value
3736
- switch (type) {
3737
- case 'array': {
3738
- // _value = _getObjectByArr(value, data, getValueByKeys, getValidation)
3739
- _value = value.map((el) => {
3740
- const result = getValueByKeys({ keys: el.value.split('.'), obj: data })
3741
- return result
3742
- })
3743
- break
3744
- }
3745
- case 'fromKeyValue': {
3746
- const { dataPath, key: valueKey } = value
3747
- const keyValues = getValueByKeys({ keys: dataPath.split('.'), obj: data })
3748
- _value = _KeyValueObject.getValuesByKey(keyValues, valueKey)[0]
3749
- break
3750
- }
3751
- case 'toKeyValue': {
3752
- const keyValues = getValueByKeys({ keys: value.split('.'), obj: data })
3753
- _value = _KeyValueObject.fromObject(keyValues)
3754
- break
3755
- }
3756
- case 'nested': {
3757
- _value = getObjectByArr(value, data, getValueByKeys, getValidation)
3758
- break
3759
- }
3760
- case 'path': {
3761
- _value = getValueByKeys({ keys: value.split('.'), obj: data })
3762
- break
3763
- }
3764
- // should be deleted
3765
- case 'orgin': {
3766
- _value = value
3767
- break
3768
- }
3769
- case 'origin': {
3770
- _value = value
3771
- break
3772
- }
3773
- default: {
3774
- _value = value
3775
- break
3776
- }
3777
- }
3778
- if (key) {
3779
- return {
3780
- ...acc,
3781
- [key]: _value,
3782
- }
3783
- }
3784
- if (typeof _value === 'string') {
3785
- return _value
3786
- }
3787
- return {
3788
- ...acc,
3789
- ..._value,
3790
- }
3791
- }
3792
- return acc
3793
- }, {})
3794
- }
3795
-
3796
-
3797
- /* harmony default export */ const getObjectByArr_getObjectByArr = ({
3798
- getObjectByArr,
3799
- });
3800
-
3801
-
3802
- ;// ./lib/helpers/getObjectByArr/index.js
3803
-
3804
-
3805
- ;// ./lib/helpers/groupArrayByKey/groupArrayByKey.js
3806
- function groupArrayByKey(arr, key) {
3807
- if (!key || typeof key !== 'string') {
3808
- return {}
3809
- }
3810
- return arr.reduce((acc, curr) => {
3811
- if (!acc[curr[key]]) {
3812
- acc[curr[key]] = 0
3813
- }
3814
- acc[curr[key]]++
3815
- return acc
3816
- }, {})
3817
- }
3818
-
3819
- ;// ./lib/helpers/groupArrayByKey/index.js
3820
-
3821
-
3822
- ;// ./lib/helpers/init/init.js
3823
- function init(_class, options) {
3824
- if (options instanceof _class) {
3825
- return options
3826
- }
3827
- try {
3828
- const instance = new _class(options)
3829
- return instance.isValid !== false ? instance : null
3830
- } catch (e) {
3831
- console.log(`init failed for class: ${_class._classname || 'no _classname'}`, e)
3832
- return null
3833
- }
3834
- }
3835
-
3836
- ;// ./lib/helpers/init/index.js
3837
-
3838
-
3839
- ;// ./lib/helpers/initFromArray/initFromArray.js
3840
-
3841
-
3842
- function initFromArray(_class, arr) {
3843
- if (Array.isArray(arr)) {
3844
- return arr.map((a) => init(_class, a))
3845
- }
3846
- return []
3847
- }
3848
-
3849
- ;// ./lib/helpers/initFromArray/index.js
3850
-
3851
-
3852
- ;// ./lib/helpers/initOnlyValidFromArray/initOnlyValidFromArray.js
3853
-
3854
-
3855
- function initOnlyValidFromArray(_class, arr) {
3856
- return initFromArray(_class, arr).filter((i) => i)
3857
- }
3858
-
3859
- ;// ./lib/helpers/initOnlyValidFromArray/index.js
3860
-
3861
-
3862
- ;// ./lib/helpers/isConvertibleToNumber/index.js
3863
-
3864
-
3865
- ;// ./lib/helpers/mergeArraysByKey/mergeArraysByKey.js
3866
- function mergeArraysByKey(arr1, arr2) {
3867
- // Handle undefined/null inputs by defaulting to empty arrays
3868
- const safeArr1 = Array.isArray(arr1) ? arr1 : []
3869
- const safeArr2 = Array.isArray(arr2) ? arr2 : []
3870
-
3871
- const mergedMap = new Map()
3872
-
3873
- // Helper function to merge values based on their type
3874
- const mergeValues = (existingValue, newValue) => {
3875
- if (existingValue === undefined)
3876
- return newValue
3877
-
3878
- // Handle arrays by concatenating
3879
- if (Array.isArray(existingValue) && Array.isArray(newValue)) {
3880
- return [...new Set([...existingValue, ...newValue])]
3881
- }
3882
-
3883
- // Handle objects by merging
3884
- if (typeof existingValue === 'object' && typeof newValue === 'object'
3885
- && !Array.isArray(existingValue) && !Array.isArray(newValue)) {
3886
- return { ...existingValue, ...newValue }
3887
- }
3888
-
3889
- // // Handle numbers by adding
3890
- // if (typeof existingValue === 'number' && typeof newValue === 'number') {
3891
- // return existingValue
3892
- // }
3893
-
3894
- // // Handle strings by concatenating
3895
- // if (typeof existingValue === 'string' && typeof newValue === 'string') {
3896
- // return existingValue
3897
- // }
3898
-
3899
- // Default: use the new value
3900
- return newValue
3901
- }
3902
-
3903
- // Process first array
3904
- safeArr1.forEach((item) => {
3905
- mergedMap.set(item.key, item.value)
3906
- })
3907
-
3908
- // Process second array and merge values
3909
- safeArr2.forEach((item) => {
3910
- const existingValue = mergedMap.get(item.key)
3911
- mergedMap.set(item.key, mergeValues(existingValue, item.value))
3912
- })
3913
-
3914
- // Convert back to array format
3915
- return Array.from(mergedMap.entries()).map(([key, value]) => ({
3916
- key,
3917
- value
3918
- }))
3919
- }
3920
-
3921
- ;// ./lib/helpers/mergeArraysByKey/index.js
3922
-
3923
-
3924
- ;// ./lib/helpers/padZeros/padZeros.js
3925
- function padZeros(num, minLength = 6) {
3926
- num = num.toString()
3927
- if (num.length < minLength) {
3928
- return padZeros(`0${num}`, minLength)
3929
- }
3930
- return num
3931
- }
3932
-
3933
-
3934
-
3935
- ;// ./lib/helpers/padZeros/index.js
3936
-
3937
-
3938
-
3939
-
3940
- ;// ./lib/helpers/pMap/pMap.js
3941
- async function pMap(
3942
- iterable,
3943
- mapper,
3944
- {
3945
- concurrency = Number.POSITIVE_INFINITY,
3946
- stopOnError = true,
3947
- signal,
3948
- } = {},
3949
- ) {
3950
- return new Promise((resolve_, reject_) => {
3951
- if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
3952
- throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`)
3953
- }
3954
-
3955
- if (typeof mapper !== 'function') {
3956
- throw new TypeError('Mapper function is required')
3957
- }
3958
-
3959
- if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
3960
- throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`)
3961
- }
3962
-
3963
- const result = []
3964
- const errors = []
3965
- const skippedIndexesMap = new Map()
3966
- let isRejected = false
3967
- let isResolved = false
3968
- let isIterableDone = false
3969
- let resolvingCount = 0
3970
- let currentIndex = 0
3971
- const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]()
3972
-
3973
- const signalListener = () => {
3974
- reject(signal.reason)
3975
- }
3976
-
3977
- const cleanup = () => {
3978
- signal?.removeEventListener('abort', signalListener)
3979
- }
3980
-
3981
- const resolve = (value) => {
3982
- resolve_(value)
3983
- cleanup()
3984
- }
3985
-
3986
- const reject = (reason) => {
3987
- isRejected = true
3988
- isResolved = true
3989
- reject_(reason)
3990
- cleanup()
3991
- }
3992
-
3993
- if (signal) {
3994
- if (signal.aborted) {
3995
- reject(signal.reason)
3996
- }
3997
-
3998
- signal.addEventListener('abort', signalListener, { once: true })
3999
- }
4000
-
4001
- const next = async () => {
4002
- if (isResolved) {
4003
- return
4004
- }
4005
-
4006
- const nextItem = await iterator.next()
4007
-
4008
- const index = currentIndex
4009
- currentIndex++
4010
-
4011
- // Note: `iterator.next()` can be called many times in parallel.
4012
- // This can cause multiple calls to this `next()` function to
4013
- // receive a `nextItem` with `done === true`.
4014
- // The shutdown logic that rejects/resolves must be protected
4015
- // so it runs only one time as the `skippedIndex` logic is
4016
- // non-idempotent.
4017
- if (nextItem.done) {
4018
- isIterableDone = true
4019
-
4020
- if (resolvingCount === 0 && !isResolved) {
4021
- if (!stopOnError && errors.length > 0) {
4022
- reject(new AggregateError(errors)) // eslint-disable-line unicorn/error-message
4023
- return
4024
- }
4025
-
4026
- isResolved = true
4027
-
4028
- if (skippedIndexesMap.size === 0) {
4029
- resolve(result)
4030
- return
4031
- }
4032
-
4033
- const pureResult = []
4034
-
4035
- // Support multiple `pMapSkip`'s.
4036
- for (const [index, value] of result.entries()) {
4037
- if (skippedIndexesMap.get(index) === pMapSkip) {
4038
- continue
4039
- }
4040
-
4041
- pureResult.push(value)
4042
- }
4043
-
4044
- resolve(pureResult)
4045
- }
4046
-
4047
- return
4048
- }
4049
-
4050
- resolvingCount++;
4051
-
4052
- // Intentionally detached
4053
- (async () => {
4054
- try {
4055
- const element = await nextItem.value
4056
-
4057
- if (isResolved) {
4058
- return
4059
- }
4060
-
4061
- const value = await mapper(element, index)
4062
-
4063
- // Use Map to stage the index of the element.
4064
- if (value === pMapSkip) {
4065
- skippedIndexesMap.set(index, value)
4066
- }
4067
-
4068
- result[index] = value
4069
-
4070
- resolvingCount--
4071
- await next()
4072
- } catch (error) {
4073
- if (stopOnError) {
4074
- reject(error)
4075
- } else {
4076
- errors.push(error)
4077
- resolvingCount--
4078
-
4079
- // In that case we can't really continue regardless of `stopOnError` state
4080
- // since an iterable is likely to continue throwing after it throws once.
4081
- // If we continue calling `next()` indefinitely we will likely end up
4082
- // in an infinite loop of failed iteration.
4083
- try {
4084
- await next()
4085
- } catch (error) {
4086
- reject(error)
4087
- }
4088
- }
4089
- }
4090
- })()
4091
- };
4092
-
4093
- // Create the concurrent runners in a detached (non-awaited)
4094
- // promise. We need this so we can await the `next()` calls
4095
- // to stop creating runners before hitting the concurrency limit
4096
- // if the iterable has already been marked as done.
4097
- // NOTE: We *must* do this for async iterators otherwise we'll spin up
4098
- // infinite `next()` calls by default and never start the event loop.
4099
- (async () => {
4100
- for (let index = 0; index < concurrency; index++) {
4101
- try {
4102
- await next()
4103
- } catch (error) {
4104
- reject(error)
4105
- break
4106
- }
4107
-
4108
- if (isIterableDone || isRejected) {
4109
- break
4110
- }
4111
- }
4112
- })()
4113
- })
4114
- }
4115
-
4116
- function pMapIterable(
4117
- iterable,
4118
- mapper,
4119
- {
4120
- concurrency = Number.POSITIVE_INFINITY,
4121
- backpressure = concurrency,
4122
- } = {},
4123
- ) {
4124
- if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
4125
- throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`)
4126
- }
4127
-
4128
- if (typeof mapper !== 'function') {
4129
- throw new TypeError('Mapper function is required')
4130
- }
4131
-
4132
- if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
4133
- throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`)
4134
- }
4135
-
4136
- if (!((Number.isSafeInteger(backpressure) && backpressure >= concurrency) || backpressure === Number.POSITIVE_INFINITY)) {
4137
- throw new TypeError(`Expected \`backpressure\` to be an integer from \`concurrency\` (${concurrency}) and up or \`Infinity\`, got \`${backpressure}\` (${typeof backpressure})`)
4138
- }
4139
-
4140
- return {
4141
- async* [Symbol.asyncIterator]() {
4142
- const iterator = iterable[Symbol.asyncIterator] === undefined ? iterable[Symbol.iterator]() : iterable[Symbol.asyncIterator]()
4143
-
4144
- const promises = []
4145
- let pendingPromisesCount = 0
4146
- let isDone = false
4147
- let index = 0
4148
-
4149
- function trySpawn() {
4150
- if (isDone || !(pendingPromisesCount < concurrency && promises.length < backpressure)) {
4151
- return
4152
- }
4153
-
4154
- pendingPromisesCount++
4155
-
4156
- const promise = (async () => {
4157
- const { done, value } = await iterator.next()
4158
-
4159
- if (done) {
4160
- pendingPromisesCount--
4161
- return { done: true }
4162
- }
4163
-
4164
- // Spawn if still below concurrency and backpressure limit
4165
- trySpawn()
4166
-
4167
- try {
4168
- const returnValue = await mapper(await value, index++)
4169
-
4170
- pendingPromisesCount--
4171
-
4172
- if (returnValue === pMapSkip) {
4173
- const index = promises.indexOf(promise)
4174
-
4175
- if (index > 0) {
4176
- promises.splice(index, 1)
4177
- }
4178
- }
4179
-
4180
- // Spawn if still below backpressure limit and just dropped below concurrency limit
4181
- trySpawn()
4182
-
4183
- return { done: false, value: returnValue }
4184
- } catch (error) {
4185
- pendingPromisesCount--
4186
- isDone = true
4187
- return { error }
4188
- }
4189
- })()
4190
-
4191
- promises.push(promise)
4192
- }
4193
-
4194
- trySpawn()
4195
-
4196
- while (promises.length > 0) {
4197
- const { error, done, value } = await promises[0]
4198
-
4199
- promises.shift()
4200
-
4201
- if (error) {
4202
- throw error
4203
- }
4204
-
4205
- if (done) {
4206
- return
4207
- }
4208
-
4209
- // Spawn if just dropped below backpressure limit and below the concurrency limit
4210
- trySpawn()
4211
-
4212
- if (value === pMapSkip) {
4213
- continue
4214
- }
4215
-
4216
- yield value
4217
- }
4218
- },
4219
- }
4220
- }
4221
-
4222
- const pMapSkip = Symbol('skip')
4223
-
4224
- ;// ./lib/helpers/pMap/index.js
4225
-
4226
-
4227
- ;// ./lib/helpers/pReduce/index.js
4228
-
4229
-
4230
-
4231
-
4232
- ;// ./lib/helpers/replacePlaceholders/replacePlaceholders.js
4233
- function replacePlaceholders({ content, mapping }) {
4234
- let isObjectMode = false
4235
-
4236
- if (typeof content === 'object' && content !== null) {
4237
- content = JSON.stringify(content)
4238
- isObjectMode = true
4239
- }
4240
-
4241
- /**
4242
- // [[ eventRegistration.eventRegistrationCode | 0 ]]
4243
- const regex = /(\[*)\[\[\s*([\w.\-]+)(?:\s*\|\s*([^:\]\s]+))?(?:\s*:\s*([^\]\s]+))?\s*\]\](\]*)/g
4244
-
4245
- const result = content.replace(regex, (match, leadingBrackets, path, defaultValue, type, trailingBrackets) => {
4246
- // Split the path into parts
4247
- const keys = path.trim().split('.')
4248
-
4249
- // Traverse the nested object structure
4250
- let value = mapping
4251
- for (const key of keys) {
4252
- // Handle empty keys (in case of double dots or leading/trailing dots)
4253
- if (!key)
4254
- continue
4255
-
4256
- value = value?.[key]
4257
- if (value === undefined) {
4258
- break
4259
- }
4260
- }
4261
-
4262
- // Apply default if missing
4263
- if (value === undefined)
4264
- value = defaultValue?.trim()
4265
- if (value === undefined)
4266
- return isObjectMode ? undefined : match
4267
-
4268
- value = value !== undefined
4269
- ? leadingBrackets + value + trailingBrackets
4270
- : match
4271
-
4272
- // Return replacement or original if not found
4273
- return value
4274
- })
4275
- */
4276
-
4277
- // Regex to match both simple and complex expressions
4278
- const regex = /\[\[\s*([^[\]]+?)\s*\]\]/g;
4279
-
4280
- const result = content.replace(regex, (match, expression) => {
4281
- // Trim whitespace from the expression
4282
- const trimmedExpr = expression.trim();
4283
-
4284
- // Check if it's a simple path (alphanumeric, dots, hyphens only)
4285
- if (/^[\w.\-]+$/.test(trimmedExpr)) {
4286
- // Try to find this path in the mapping
4287
- const keys = trimmedExpr.split('.');
4288
- let value = mapping;
4289
-
4290
- for (const key of keys) {
4291
- if (!key) continue;
4292
- value = value?.[key];
4293
- if (value === undefined) break;
4294
- }
4295
-
4296
- // If found in mapping, return the value
4297
- if (value !== undefined) {
4298
- return value;
4299
- }
4300
- }
4301
-
4302
- // For complex expressions or unmatched simple expressions, convert to EJS syntax
4303
- return `<%= ${trimmedExpr} %>`;
4304
- })
4305
-
4306
- if (isObjectMode) {
4307
- return JSON.parse(result)
4308
- }
4309
- return result
4310
- }
4311
-
4312
- ;// ./lib/helpers/replacePlaceholders/index.js
4313
-
4314
-
4315
- ;// ./lib/helpers/sanitizeText/sanitizeText.js
4316
- /**
4317
- * Sanitizes input by removing hidden/control characters with customizable whitespace handling.
4318
- * @param {string} input - The string to sanitize.
4319
- * @param {object} [options] - Configuration options.
4320
- * @param {boolean} [options.normalizeWhitespace] - Collapse multiple spaces/tabs into one space.
4321
- * @param {boolean} [options.removeNewlines] - If true, replaces newlines with spaces.
4322
- * @param {boolean} [options.trim] - If true, trims leading/trailing whitespace.
4323
- * @param {boolean} [options.debug] - If true, logs debug information about removed characters.
4324
- * @returns {string} The sanitized string.
4325
- */
4326
- function sanitizeText(input, options = {}) {
4327
- const {
4328
- normalizeWhitespace = true,
4329
- removeNewlines = false,
4330
- trim = true,
4331
- preserveBasicWhitespace = true,
4332
- debug = false, // new option for debugging
4333
- } = options
4334
-
4335
- if (typeof input !== 'string') {
4336
- return input
4337
- }
4338
-
4339
- let result = input
4340
-
4341
- if (debug) {
4342
- console.log('Original input:', JSON.stringify(input))
4343
- console.log('Options:', { normalizeWhitespace, removeNewlines, trim, preserveBasicWhitespace })
4344
- }
4345
-
4346
- // Phase 1: Remove all control characters except basic whitespace if requested
4347
- if (preserveBasicWhitespace && !removeNewlines) {
4348
- if (debug) {
4349
- const before = result
4350
- const matches = []
4351
- // Use a replacer function to capture what's being removed
4352
- result = result.replace(/[\x00-\x08\v\f\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, (match) => {
4353
- matches.push({
4354
- char: match,
4355
- code: match.charCodeAt(0),
4356
- hex: `0x${match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`
4357
- })
4358
- return ''
4359
- })
4360
- if (matches.length > 0) {
4361
- console.log('Phase 1 (preserve mode) - Removed characters:')
4362
- matches.forEach((m) => {
4363
- console.log(` - Character: ${JSON.stringify(m.char)}, Code: ${m.code}, Hex: ${m.hex}`)
4364
- })
4365
- console.log(`Removed ${matches.length} control character(s)`)
4366
- } else {
4367
- console.log('Phase 1 (preserve mode) - No control characters found')
4368
- }
4369
- } else {
4370
- result = result.replace(/[\x00-\x08\v\f\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
4371
- }
4372
- } else {
4373
- if (debug) {
4374
- const before = result
4375
- const matches = []
4376
- result = result.replace(/[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, (match) => {
4377
- matches.push({
4378
- char: match,
4379
- code: match.charCodeAt(0),
4380
- hex: `0x${match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`
4381
- })
4382
- return ''
4383
- })
4384
- if (matches.length > 0) {
4385
- console.log('Phase 1 (full removal mode) - Removed characters:')
4386
- matches.forEach((m) => {
4387
- console.log(` - Character: ${JSON.stringify(m.char)}, Code: ${m.code}, Hex: ${m.hex}`)
4388
- })
4389
- console.log(`Removed ${matches.length} control character(s)`)
4390
- } else {
4391
- console.log('Phase 1 (full removal mode) - No control characters found')
4392
- }
4393
- } else {
4394
- result = result.replace(/[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g, '')
4395
- }
4396
- }
4397
-
4398
- if (debug) {
4399
- console.log('After Phase 1:', JSON.stringify(result))
4400
- }
4401
-
4402
- // Phase 2: Handle whitespace transformations
4403
- if (removeNewlines) {
4404
- if (debug) {
4405
- const before = result
4406
- result = result.replace(/[\r\n]+/g, ' ')
4407
- console.log('Phase 2 - Converted newlines to spaces')
4408
- } else {
4409
- result = result.replace(/[\r\n]+/g, ' ')
4410
- }
4411
- }
4412
-
4413
- if (normalizeWhitespace) {
4414
- if (debug) {
4415
- const before = result
4416
- result = result.replace(/[ \t]+/g, ' ')
4417
- console.log('Phase 2 - Normalized whitespace')
4418
- } else {
4419
- result = result.replace(/[ \t]+/g, ' ')
4420
- }
4421
- }
4422
-
4423
- if (debug) {
4424
- console.log('After Phase 2:', JSON.stringify(result))
4425
- }
4426
-
4427
- // Phase 3: Final trimming
4428
- if (trim) {
4429
- if (debug) {
4430
- const before = result
4431
- result = result.trim()
4432
- console.log('Phase 3 - Trimmed leading/trailing whitespace')
4433
- } else {
4434
- result = result.trim()
4435
- }
4436
- }
4437
-
4438
- if (debug) {
4439
- console.log('Final result:', JSON.stringify(result))
4440
- console.log('--- Sanitization complete ---')
4441
- }
4442
-
4443
- return result
4444
- }
4445
-
4446
- ;// ./lib/helpers/sanitizeText/index.js
4447
-
4448
-
4449
- ;// ./lib/helpers/shuffleArray/shuffleArray.js
4450
- function shuffleArray(array) {
4451
- const arr = [...array]
4452
- for (let i = arr.length - 1; i >= 0; i--) { // Changed `i > 0` to `i >= 0`
4453
- const j = Math.floor(Math.random() * (i + 1));
4454
- [arr[i], arr[j]] = [arr[j], arr[i]]
4455
- }
4456
- return arr
4457
- }
4458
-
4459
- ;// ./lib/helpers/shuffleArray/index.js
4460
-
4461
-
4462
- ;// ./lib/helpers/stringFormatter/index.js
4463
-
4464
-
4465
-
4466
-
4467
- ;// ./lib/helpers/stringHelper/stringHelper.js
4468
- function baseXEncode(num, base = 34) {
4469
- const charset = getBaseCharset(base)
4470
- return encode(num, charset)
4471
- }
4472
-
4473
- function encode(int, charset) {
4474
- const { byCode } = charset
4475
- if (int === 0) {
4476
- return byCode[0]
4477
- }
4478
-
4479
- let res = ''
4480
- const max = charset.length
4481
- while (int > 0) {
4482
- res = byCode[int % max] + res
4483
- int = Math.floor(int / max)
4484
- }
4485
- return res
4486
- }
4487
-
4488
- function getBaseCharset(base) {
4489
- let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
4490
- if (base === 58) {
4491
- charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
4492
- }
4493
- return indexCharset(charset)
4494
- }
4495
-
4496
- function indexCharset(str) {
4497
- const byCode = {}
4498
- const byChar = {}
4499
- const { length } = str
4500
- let char
4501
- for (let i = 0; i < length; i++) {
4502
- char = str[i]
4503
- byCode[i] = char
4504
- byChar[char] = i
4505
- }
4506
- return { byCode, byChar, length }
4507
- }
4508
-
4509
- function isSame(str1, str2) {
4510
- if (typeof str1 !== 'string' || typeof str2 !== 'string') {
4511
- return false
4512
- }
4513
- return str1.trim().toUpperCase() === str2.trim().toUpperCase()
4514
- }
4515
-
4516
- function randomString({ len = 16, pattern = 'a1' } = {}) {
4517
- const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
4518
- const a = 'abcdefghijklmnopqrstuvwxyz'
4519
- const num = '1234567890'
4520
- const mark = '~!@#$%^&*_+-='
4521
- let str = ''
4522
- if (pattern.includes('A')) {
4523
- str += A
4524
- }
4525
- if (pattern.includes('a')) {
4526
- str += a
4527
- }
4528
- if (pattern.includes('1')) {
4529
- str += num
4530
- }
4531
- if (pattern.includes('#')) {
4532
- str += mark
4533
- }
4534
- const chars = [...str]
4535
- return [...new Array(len)].map((i) => {
4536
- return chars[(Math.random() * chars.length) | 0]
4537
- }).join``
4538
- }
4539
-
4540
- function reverse(str) {
4541
- const _str = (typeof str !== 'string') ? str.toString() : str
4542
- const splitString = _str.split('')
4543
- const reverseArray = splitString.reverse()
4544
- return reverseArray.join('')
4545
- }
4546
-
4547
- function setCode(base = 34) {
4548
- const now = (new Date()).valueOf()
4549
- const random = randomString({
4550
- len: 8,
4551
- pattern: '1'
4552
- })
4553
- const str = reverse(`${now}${random}`)
4554
- // const str = `${now}${random}`
4555
- return baseXEncode(str, base)
4556
- }
4557
-
4558
- function toCamelCase(str) {
4559
- if (!str)
4560
- return ''
4561
- return str
4562
- .trim()
4563
- .split(/\s+/)
4564
- .map((word, index) => {
4565
- if (!word)
4566
- return ''
4567
- if (index === 0) {
4568
- return word.toLowerCase()
4569
- }
4570
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
4571
- })
4572
- .join('')
4573
- }
4574
-
4575
- function toLowerCase(str) {
4576
- if (!str)
4577
- return ''
4578
- return str
4579
- .trim()
4580
- .toLowerCase()
4581
- }
4582
-
4583
- function toScreamingSnakeCase(str) {
4584
- return str
4585
- .replace(/([a-z])([A-Z])/g, '$1_$2')
4586
- .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
4587
- .toUpperCase()
4588
- }
4589
-
4590
- const stringHelper = {
4591
- isSame,
4592
- setCode,
4593
- toCamelCase,
4594
- toLowerCase,
4595
- toScreamingSnakeCase,
4596
- }
4597
-
4598
-
4599
-
4600
- ;// ./lib/helpers/stringHelper/index.js
4601
-
4602
-
4603
-
4604
-
4605
- ;// ./lib/helpers/trackingPlugin/trackingPlugin.js
4606
- function trackingPlugin(schema, options) {
4607
- // Add meta fields
4608
- schema.add({
4609
- meta: {
4610
- active: { type: Boolean, default: true },
4611
- created: { type: Number },
4612
- creator: { type: String },
4613
- deleted: { type: Boolean, default: false },
4614
- modified: { type: Number },
4615
- owner: { type: String },
4616
- }
4617
- })
4618
-
4619
- // Auto-update hook
4620
- schema.pre('save', function (next) {
4621
- this.meta.modified = Date.now()
4622
- next()
4623
- })
4624
-
4625
- // Add core indexes
4626
- schema.index({
4627
- 'meta.active': 1,
4628
- 'meta.deleted': 1
4629
- }, {
4630
- name: 'tracking_status_index',
4631
- background: true,
4632
- partialFilterExpression: {
4633
- 'meta.active': true,
4634
- 'meta.deleted': false
4635
- }
4636
- })
4637
-
4638
- // Optional: Add helper methods
4639
- // schema.methods.touch = function(userId) {
4640
- // this.meta.updatedAt = new Date()
4641
- // this.meta.updatedBy = userId
4642
- // }
4643
- }
4644
-
4645
- ;// ./lib/helpers/tenantPlugin/tenantPlugin.js
4646
-
4647
-
4648
- function tenantPlugin(schema, options) {
4649
- // Apply tracking plugin first if not already present
4650
- if (!schema.path('meta')) {
4651
- trackingPlugin(schema, options)
4652
- }
4653
-
4654
- // Add tenant-specific fields
4655
- schema.add({
4656
- metadata: [{ type: Object }], // Instead of Schema.Types.Mixed
4657
- remarks: [{ type: Object }],
4658
- tenantCode: { type: String, required: true }
4659
- })
4660
-
4661
- // Add core indexes
4662
- schema.index({
4663
- tenantCode: 1
4664
- }, {
4665
- name: 'tenant_core_index',
4666
- background: true
4667
- })
4668
-
4669
- // 1. ENHANCE EXISTING TRACKING INDEXES
4670
- const existingIndexes = schema.indexes()
4671
-
4672
- // Check if tracking_status_index exists
4673
- const hasTenantStatusIndex = existingIndexes.some((idx) =>
4674
- idx.name === 'tenant_status_index' // Check by name for reliability
4675
- )
4676
-
4677
- if (!hasTenantStatusIndex) {
4678
- schema.index({
4679
- tenantCode: 1, // Unique field first
4680
- _type: 1, // Low-cardinality field last
4681
- }, {
4682
- name: 'tenant_status_index',
4683
- background: true,
4684
- partialFilterExpression: {
4685
- '_type': 'Tenant',
4686
- 'meta.active': true,
4687
- 'meta.deleted': false
4688
- }
4689
- })
4690
- }
4691
- }
4692
-
4693
- ;// ./lib/helpers/tenantPlugin/index.js
4694
-
4695
-
4696
- ;// ./lib/helpers/trackingPlugin/index.js
4697
-
4698
-
4699
- ;// ./lib/helpers/index.js
4700
-
4701
-
4702
-
4703
-
4704
-
4705
-
4706
-
4707
-
4708
-
4709
-
4710
-
4711
-
4712
-
4713
-
4714
-
4715
-
4716
-
4717
-
4718
-
4719
-
4720
-
4721
-
4722
-
4723
-
4724
-
4725
-
4726
-
4727
-
4728
-
4729
-
4730
-
4731
-
4732
-
4733
-
4734
- ;// ./lib/index.js
4735
-
4736
-
4737
-
4738
- ;// ./index.js
4739
-
4740
-
4741
- /******/ return __webpack_exports__;
4742
- /******/ })()
4743
- ;
4744
- });