@questwork/q-utilities 0.1.30 → 0.1.33

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