@questwork/q-utilities 0.1.10 → 0.1.11

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.
Files changed (3) hide show
  1. package/dist/index.min.cjs +1591 -1508
  2. package/dist/index.min.js +1593 -1509
  3. package/package.json +1 -1
@@ -57,6 +57,7 @@ __webpack_require__.d(__webpack_exports__, {
57
57
  Service: () => (/* reexport */ Service),
58
58
  TemplateCompiler: () => (/* reexport */ TemplateCompiler),
59
59
  UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
60
+ concatStringByArray: () => (/* reexport */ concatStringByArray),
60
61
  convertString: () => (/* reexport */ convertString),
61
62
  formatDate: () => (/* reexport */ formatDate),
62
63
  generalPost: () => (/* reexport */ generalPost),
@@ -71,86 +72,12 @@ __webpack_require__.d(__webpack_exports__, {
71
72
  stringHelper: () => (/* reexport */ stringHelper)
72
73
  });
73
74
 
74
- ;// ./lib/helpers/convertString/convertString.js
75
- function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByKeys) {
76
- if (!string || typeof getValueByKeys !== 'function') {
77
- return ''
78
- }
79
- const reg = new RegExp(patternMatch, 'g')
80
- return string.replace(reg, (match, key) => {
81
- const result = getValueByKeys({ keys: key.split('.'), obj: value })
82
- if (result === null || result === undefined) {
83
- return ''
84
- }
85
- return typeof result === 'object' ? JSON.stringify(result) : result
86
- })
87
- }
88
-
89
- /* harmony default export */ const convertString_convertString = ({
90
- convertString
91
- });
92
-
93
-
94
- ;// ./lib/helpers/convertString/index.js
95
-
96
-
97
- ;// ./lib/helpers/formatDate/formatDate.js
98
-
99
- function formatDate(date, format) {
100
- const _date = date && date instanceof Date ? date : new Date(date)
101
- const dayMapChi = ['日','一','二','三','四','五','六']
102
- const dayMapEng = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
103
- const dayMapEngShort = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
104
- const _format = format || 'YYYY/MM/DD hh:mm'
105
- const e = _date.getDay()
106
- const ee = dayMapEngShort[e]
107
- const eee = dayMapChi[e]
108
- const eeee = dayMapEng[e]
109
- const y = _date.getFullYear()
110
- const m = _date.getMonth() + 1
111
- const d = _date.getDate()
112
- const h = _date.getHours()
113
- const mm = _date.getMinutes()
114
- const s = _date.getSeconds()
115
-
116
- return _format.replace('YYYY', y)
117
- .replace('MM', padding(m))
118
- .replace('MM', padding(m))
119
- .replace('DD', padding(d))
120
- .replace('hh', padding(h))
121
- .replace('mm', padding(mm))
122
- .replace('ss', padding(s))
123
- .replace('M', m)
124
- .replace('D', d)
125
- .replace('h', h)
126
- .replace('m', mm)
127
- .replace('s', s)
128
- .replace('EEEE', padding(eeee))
129
- .replace('EEE', padding(eee))
130
- .replace('EE', padding(ee))
131
- .replace('E', padding(e))
132
- }
133
-
134
- function padding(m) {
135
- return m < 10 ? `0${m}` : m
136
- }
137
-
138
-
139
- /* harmony default export */ const formatDate_formatDate = ({
140
- formatDate
141
- });
142
-
143
-
144
-
145
- ;// ./lib/helpers/formatDate/index.js
146
-
147
-
148
75
  ;// ./lib/helpers/getValidation/getValidation.js
149
76
  function getValidation(rule, data, getDataByKey, KeyValueObject) {
150
77
  if (!rule) {
151
78
  return true
152
79
  }
153
- if (typeof getDataByKey !== 'function' || typeof KeyValueObject !== 'function') {
80
+ if (typeof getDataByKey !== 'function' || (KeyValueObject && typeof KeyValueObject !== 'function')) {
154
81
  return false
155
82
  }
156
83
  const { key = '', value, keyValuePath = '' } = rule
@@ -242,6 +169,13 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
242
169
  const timestamp = new Date(rowValue).getTime()
243
170
  return (now - timestamp) < value['$intervalTimeLt']
244
171
  }
172
+ case '$isToday': {
173
+ const currentDate = new Date()
174
+ const start = currentDate.setHours(0,0,0,0)
175
+ const end = currentDate.setHours(23,59,59,59)
176
+ const dateValue = new Date(rowValue).getTime()
177
+ return (start <= dateValue && end >= dateValue) === value['$isToday']
178
+ }
245
179
  case '$notInValue': {
246
180
  const result = getDataByKey(value['$notInValue'], data)
247
181
  const _value = Array.isArray(result) ? result : []
@@ -273,12 +207,66 @@ function getValidation(rule, data, getDataByKey, KeyValueObject) {
273
207
  ;// ./lib/helpers/getValidation/index.js
274
208
 
275
209
 
210
+ ;// ./lib/helpers/formatDate/formatDate.js
211
+
212
+ function formatDate(date, format) {
213
+ const _date = date && date instanceof Date ? date : new Date(date)
214
+ const dayMapChi = ['日','一','二','三','四','五','六']
215
+ const dayMapEng = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
216
+ const dayMapEngShort = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
217
+ const _format = format || 'YYYY/MM/DD hh:mm'
218
+ const e = _date.getDay()
219
+ const ee = dayMapEngShort[e]
220
+ const eee = dayMapChi[e]
221
+ const eeee = dayMapEng[e]
222
+ const y = _date.getFullYear()
223
+ const m = _date.getMonth() + 1
224
+ const d = _date.getDate()
225
+ const h = _date.getHours()
226
+ const mm = _date.getMinutes()
227
+ const s = _date.getSeconds()
228
+
229
+ return _format.replace('YYYY', y)
230
+ .replace('MM', padding(m))
231
+ .replace('MM', padding(m))
232
+ .replace('DD', padding(d))
233
+ .replace('hh', padding(h))
234
+ .replace('mm', padding(mm))
235
+ .replace('ss', padding(s))
236
+ .replace('M', m)
237
+ .replace('D', d)
238
+ .replace('h', h)
239
+ .replace('m', mm)
240
+ .replace('s', s)
241
+ .replace('EEEE', padding(eeee))
242
+ .replace('EEE', padding(eee))
243
+ .replace('EE', padding(ee))
244
+ .replace('E', padding(e))
245
+ }
246
+
247
+ function padding(m) {
248
+ return m < 10 ? `0${m}` : m
249
+ }
250
+
251
+
252
+ /* harmony default export */ const formatDate_formatDate = ({
253
+ formatDate
254
+ });
255
+
256
+
257
+
258
+ ;// ./lib/helpers/formatDate/index.js
259
+
260
+
276
261
  ;// ./lib/helpers/getValueByKeys/getValueByKeys.js
277
- // keys can be array or string
262
+ // keys can be array or object or string
278
263
  function getValueByKeys(keys, data) {
279
264
  let _keys = keys
280
265
  let _data = data
281
- if (!Array.isArray(keys)) {
266
+ if (typeof keys === 'string') {
267
+ _keys = _keys.split('.')
268
+ }
269
+ if (!Array.isArray(keys) && typeof keys === 'object') {
282
270
  const { keys: keyArr, obj } = keys
283
271
  _keys = keyArr
284
272
  _data = obj
@@ -305,930 +293,516 @@ function getValueByKeys(keys, data) {
305
293
  ;// ./lib/helpers/getValueByKeys/index.js
306
294
 
307
295
 
308
- ;// ./lib/helpers/objectHelper/objectHelper.js
309
- const objectHelper = {
310
- get(obj, path) {
311
- const parts = path.split('.')
312
- return parts.reduce((acc, part) => {
313
- if (part.endsWith('[]')) {
314
- // 处理数组遍历
315
- const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
316
- if (Array.isArray(acc[key])) {
317
- return acc[key] // 返回整个数组
318
- }
319
- return [] // 如果不是数组,返回空数组
320
- }
321
- if (part.includes('[') && part.includes(']')) {
322
- // 处理数组索引
323
- const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
324
- if (arrayMatch) {
325
- const key = arrayMatch[1]
326
- const index = arrayMatch[2]
327
- return acc && acc[key] && acc[key][index]
328
- }
329
- } else if (acc && Array.isArray(acc)) {
330
- // 如果当前值是数组,提取每个对象的指定属性
331
- return acc.map((item) => item[part])
332
- } else {
333
- // 处理普通属性
334
- return acc && acc[part]
335
- }
336
- }, obj)
337
- },
338
- merge,
339
- set(obj, path, value) {
340
- const parts = path.split('.')
341
- let current = obj
342
- for (let i = 0; i < parts.length - 1; i++) {
343
- const part = parts[i]
344
- if (part.endsWith('[]')) {
345
- // 处理数组遍历
346
- const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
347
- if (Array.isArray(current[key])) {
348
- current[key].forEach((item) => set(item, parts.slice(i + 1).join('.'), value))
349
- }
350
- return // 处理完数组后直接返回
351
- }
352
- if (part.includes('[') && part.includes(']')) {
353
- // 处理数组索引
354
- const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
355
- if (arrayMatch) {
356
- const key = arrayMatch[1]
357
- const index = arrayMatch[2]
358
- if (Array.isArray(current[key]) && current[key][index]) {
359
- current = current[key][index]
360
- } else {
361
- return // 如果数组或索引不存在,直接返回
362
- }
363
- }
364
- } else {
365
- // 处理普通属性
366
- if (!current[part]) {
367
- current[part] = {} // 如果属性不存在,创建一个空对象
368
- }
369
- current = current[part]
370
- }
371
- }
372
-
373
- // 设置最终属性值
374
- const lastPart = parts[parts.length - 1]
375
- current[lastPart] = value
376
- }
296
+ ;// ./lib/models/templateCompiler/templateCompilerException.js
297
+ const TEMPLATE_COMPILER_EXCEPTION_TYPE = {
298
+ argumentEmptyException: 'Argument is empty',
299
+ argumentFormatException: 'Incorrect number or format of argument',
300
+ invalidFuntionException: 'Function Name is invalid',
301
+ invalidRegExpException: 'Invalid regular expression',
302
+ isNotAFunctionException: 'Is not a function',
303
+ notExistException: 'Key does not exist',
304
+ resultEmptyException: 'Result is empty',
305
+ resultMoreThanOneException: 'More than one result'
377
306
  }
378
307
 
379
- function merge(target, ...sources) {
380
- if (!sources.length) return target
381
-
382
- const source = sources.shift() // 取出第一个源对象
383
-
384
- if (_isObject(target) && _isObject(source)) {
385
- for (const key in source) {
386
- if (_isObject(source[key])) {
387
- if (!target[key]) {
388
- // 如果目标对象没有该属性,创建一个空对象
389
- target[key] = {}
390
- }
391
- // 递归合并
392
- merge(target[key], source[key])
393
- } else {
394
- // 直接覆盖
395
- target[key] = source[key]
396
- }
397
- }
308
+ class TemplateCompilerException extends Error {
309
+ constructor(message) {
310
+ super(message)
311
+ this.message = message
398
312
  }
399
-
400
- // 继续合并剩余的源对象
401
- return merge(target, ...sources)
402
313
  }
403
314
 
404
- function _isObject(obj) {
405
- return obj && typeof obj === 'object' && !Array.isArray(obj)
406
- }
407
315
 
408
316
 
317
+ ;// ./lib/models/templateCompiler/constants.js
318
+ const _EMPTY = '_EMPTY'
319
+ const _FN_NAMES = [
320
+ 'get', 'map', 'join', 'concatIf', 'exec', 'filterOne', 'filterAll', 'formatDate', 'eq', 'neq', 'gt', 'lt', 'gte', 'lte', 'isEmpty', 'isNotEmpty', 'toLowerCase', 'toUpperCase'
321
+ ]
322
+ const _HIDE = '_HIDE'
323
+ const _NOT_EMPTY = '_NOT_EMPTY'
324
+ const _SELF = '_SELF'
325
+ const TAGS_EJS = ['<%=', '%>']
326
+ const TAGS_HANDLEBAR = ['{{', '}}']
409
327
 
410
- ;// ./lib/helpers/objectHelper/index.js
411
328
 
412
329
 
330
+ ;// ./lib/models/templateCompiler/helpers/_concatIf.js
413
331
 
414
332
 
415
- ;// ./lib/helpers/pReduce/pReduce.js
416
- async function pReduce(iterable, reducer, initialValue) {
417
- return new Promise((resolve, reject) => {
418
- const iterator = iterable[Symbol.iterator]()
419
- let index = 0
420
333
 
421
- const next = async total => {
422
- const element = iterator.next()
423
334
 
424
- if (element.done) {
425
- resolve(total)
426
- return
427
- }
335
+ function _concatIf(data, args) {
336
+ if (typeof data !== 'string') {
337
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string :${data.join(', ')}`)
338
+ }
339
+ if (args.length !== 3) {
340
+ throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
341
+ }
342
+ if (data === null || (typeof data === 'undefined')) {
343
+ return null
344
+ }
345
+ const [condition, success, failover] = args
346
+ const validConditions = [_EMPTY, _NOT_EMPTY]
347
+ if (validConditions.includes(condition) || success.length !== 2) {
348
+ throw new TemplateCompilerException(`concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException}: ${condition}, ${success}`)
349
+ }
350
+ if (data === '' && failover.includes(_HIDE)) {
351
+ return ''
352
+ }
353
+ if (data !== '' && (data !== null || data !== undefined) && failover.includes(_HIDE)) {
354
+ return `${success[0]}${data}${success[success.length - 1]}`
355
+ }
356
+ return failover
357
+ }
428
358
 
429
- try {
430
- const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
431
- next(reducer(resolvedTotal, resolvedValue, index++))
432
- } catch (error) {
433
- reject(error)
434
- }
435
- }
436
359
 
437
- next(initialValue)
438
- })
439
- }
440
360
 
361
+ ;// ./lib/models/templateCompiler/helpers/_eq.js
441
362
 
442
363
 
443
- ;// ./lib/models/apiResponse/apiResponse.js
444
- class ApiResponse {
445
- constructor(options = {}) {
446
- options = options || {}
447
- this._data = options.data || options._data || []
448
- this.err = options.err
449
- this.isNew = options.isNew || false
450
- this.message = options.message
451
- this.total = options.total || 0
452
- this._instanceBuilder = options._instanceBuilder
453
- }
454
364
 
455
- static init(options = {}) {
456
- if (options instanceof this) {
457
- return options
458
- }
459
- const instance = new this(options)
460
- return instance
365
+
366
+ function _eq(data, args) {
367
+ if (args.length !== 3) {
368
+ throw new TemplateCompilerException(`eq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
461
369
  }
462
- static get _classname() {
463
- return 'ApiResponse'
370
+ if (data === null || (typeof data === 'undefined')) {
371
+ return null
464
372
  }
465
- static get _superclass() {
466
- return 'ApiResponse'
373
+ if (args.includes(_SELF)) {
374
+ args = args.map((arg) => {
375
+ return (arg === _SELF) ? data : arg
376
+ })
467
377
  }
378
+ const expected = args[0]
379
+ return data === expected ? args[1] : args[2]
380
+ }
468
381
 
469
- // getters
470
- get data() {
471
- if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
472
- return this._data.map(this._instanceBuilder)
473
- }
474
- return this._data
382
+
383
+
384
+ ;// ./lib/models/templateCompiler/helpers/_exec.js
385
+ function _exec(data, args) {
386
+ try {
387
+ const [methodName, ..._args] = args
388
+ return data[methodName](..._args)
389
+ } catch (e) {
390
+ throw e
475
391
  }
476
392
  }
477
393
 
478
394
 
479
395
 
480
- ;// ./lib/models/apiResponse/makeApiResponse.js
396
+ ;// ./lib/models/templateCompiler/helpers/_filterAll.js
481
397
 
482
398
 
483
- function makeApiResponse({ repo, result }) {
484
- return ApiResponse.init({
485
- ...result,
486
- _instanceBuilder: (i) => {
487
- return repo.init(i)
399
+
400
+ // const DELIMITER = '~~~'
401
+
402
+ function _filterAll(data, args) {
403
+ try {
404
+ if (!Array.isArray(args) || args.length === 0) {
405
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
488
406
  }
489
- })
407
+ if (!Array.isArray(data) || data.length === 0) {
408
+ return []
409
+ }
410
+ if (typeof data[0] === 'object') {
411
+ return _existObject(data, args)
412
+ }
413
+ if (typeof data[0] === 'string' || typeof data[0] === 'number') {
414
+ return _exist(data, args)
415
+ }
416
+ return []
417
+ } catch (e) {
418
+ throw e
419
+ }
490
420
  }
491
421
 
422
+ function _exist(data, args) {
423
+ const _args = args.flat()
424
+ return data.filter((e) => _args.some((arg) => _performOperation(arg, e)))
425
+ }
492
426
 
427
+ function _existObject(data, args) {
428
+ if (args.length === 1) {
429
+ const arg = args[0]
430
+ return data.filter((e) => {
431
+ if (arg.includes('.')) {
432
+ return getValueByKeys(arg.split('.'), e)
433
+ }
434
+ return Object.prototype.hasOwnProperty.call(e, arg)
435
+ })
436
+ }
493
437
 
494
- ;// ./lib/models/apiResponse/index.js
495
-
438
+ if (args.length > 2) {
439
+ let res = data
440
+ for (let i = 0; i < args.length; i += 2) {
441
+ const group = [args[i], args[i + 1]]
442
+ res = _existObject(res, group)
443
+ }
444
+ return res
445
+ }
496
446
 
447
+ const [key, ..._argsArr] = args
448
+ const _args = _argsArr.flat()
449
+ return data.filter((e) => {
450
+ const value = key.includes('.') ? getValueByKeys(key.split('.'), e) : e[key]
451
+ return _args.some((arg) => _performOperation(arg, value))
452
+ })
453
+ }
497
454
 
455
+ function _performOperation(arg, value) {
456
+ // the arg is undefined
457
+ if (arg === undefined && value === undefined) return true
498
458
 
459
+ // the arg is null
460
+ if (arg === null && value === null) return true
499
461
 
500
- ;// ./lib/models/keyValueObject/keyValueObject.js
501
- class KeyValueObject {
502
- constructor(options = {}) {
503
- options = options || {}
504
- this.key = options.key || null
505
- this.value = (typeof options.value !== 'undefined') ? options.value : ''
462
+ // the arg is boolean
463
+ if (typeof arg === 'boolean') {
464
+ return arg === value
506
465
  }
507
466
 
508
- // Class methods
509
- static init(options = {}) {
510
- if (options instanceof this) {
511
- return options
467
+ // the arg is blank or *: Blank => Empty, * => Not Empty
468
+ if (arg === '' || arg === '*') {
469
+ // null and undefined are not included in either case
470
+ if (value === null || value === undefined) {
471
+ return false
512
472
  }
513
- const instance = new this(options)
514
- return instance.isValid ? instance : null
515
- }
516
- static initFromArray(arr = []) {
517
- if (Array.isArray(arr)) {
518
- return arr.map((a) => this.init(a))
473
+ if (typeof value === 'string') {
474
+ return arg === '' ? value === '' : value !== ''
519
475
  }
520
- return []
521
- }
522
- static initOnlyValidFromArray(arr = []) {
523
- return this.initFromArray(arr).filter((i) => i)
524
- }
525
- static get _classname() {
526
- return 'KeyValueObject'
527
- }
528
- static get _superclass() {
529
- return 'KeyValueObject'
476
+ if (Array.isArray(value)) {
477
+ return arg === '' ? value.length === 0 : value.length !== 0
478
+ }
479
+ return arg !== ''
530
480
  }
531
481
 
532
- static addItem(arr, key, value) {
533
- arr.push(this.init({ key, value }))
482
+ // the arg is alphabetic or number
483
+ if (_isPureStringOrNumber(arg)) {
484
+ return arg === value
534
485
  }
535
- static addRecord(arr = [], key, value) {
536
- if (!this.hasKeyValue(arr, key, value)) {
537
- arr.push(this.init({ key, value }))
486
+
487
+ // the arg is array of [] or [*]: [] => Empty, [*] => Not Empty
488
+ if (arg.startsWith('[') && arg.endsWith(']')) {
489
+ if (arg === '[]') {
490
+ return Array.isArray(value) && value.length === 0
538
491
  }
539
- return arr
492
+ if (arg === '[*]') {
493
+ return Array.isArray(value) && value.length !== 0
494
+ }
495
+ return false
540
496
  }
541
- static appendRecord(arr = [], key, value) {
542
- return arr.map((item) => {
543
- if (this.sameKey(item, key)) {
544
- item.value = [...item.value, ...value]
545
- }
546
- return item
547
- })
497
+
498
+ // the arg is 'operator + string | number'
499
+ const { operator, value: argValue } = _splitOperator(arg)
500
+ if (!operator || (argValue !== 0 && !argValue)) {
501
+ return false
548
502
  }
549
- static appendValueArray(arr = [], key, value) {
550
- return arr.map((item) => {
551
- if (this.sameKey(item, key)) {
552
- item.value = [...item.value, ...value]
553
- }
554
- return item
555
- })
503
+ switch (operator) {
504
+ case '>':
505
+ return value > argValue
506
+ case '<':
507
+ return value < argValue
508
+ case '!=':
509
+ return value !== argValue
510
+ case '>=':
511
+ return value >= argValue
512
+ case '<=':
513
+ return value <= argValue
514
+ default:
515
+ return false
556
516
  }
557
- static foundByKey(arr = [], key) {
558
- const found = arr.find((m) => {
559
- return this.sameKey(m, key)
560
- })
561
- return found || null
562
- }
563
- static foundValueByKey(arr = [], key) {
564
- const found = this.foundByKey(arr, key)
565
- return found ? found.value : null
566
- }
567
- static fromObject(options = {}) {
568
- return Object.keys(options).reduce((acc, key) => {
569
- acc.push(this.init({ key, value: options[key] }))
570
- return acc
571
- }, [])
572
- }
573
- static getValueByKey(arr = [], key) {
574
- return this.foundValueByKey(arr, key)
575
- }
576
- static getValueByKeyFromArray(arr = [], key) {
577
- if (arr.length === 0) {
578
- return null
579
- }
580
- const firstArr = arr.shift()
581
- const found = firstArr.find((i) => {
582
- return this.sameKey(i, key)
583
- })
584
- if (found && found.value) {
585
- return found.value
586
- }
587
- return this.getValueByKeyFromArray(arr, key)
588
- }
589
- static getValuesByKey(arr = [], key) {
590
- return arr.reduce((acc, item) => {
591
- if (this.sameKey(item, key)) {
592
- acc.push(item.value)
593
- }
594
- return acc
595
- }, [])
596
- }
597
- static hasKeyValue(arr = [], key, value) {
598
- if (typeof value === 'undefined') {
599
- return arr.filter((item) => this.sameKey(item, key)).length > 0
600
- }
601
- return arr.filter((item) => (this.sameKey(item, key) && _isSame(item.value, value))).length > 0
602
- }
603
- static insertOrUpdateRecord(arr = [], key, value) {
604
- let copy = [...arr]
605
- if (!this.hasKeyValue(arr, key)) {
606
- copy.push(this.init({ key, value }))
607
- } else {
608
- copy = this.updateRecord(arr, key, value)
609
- }
610
- return copy
611
- }
612
- static keys(arr = []) {
613
- if (Array.isArray(arr)) {
614
- return arr.reduce((acc, item) => {
615
- acc.push(item.key)
616
- return acc
617
- }, [])
618
- }
619
- return []
620
- }
621
- static merge(toArr, fromArr) {
622
- (fromArr || []).map((from) => {
623
- const found = toArr.find((to) => {
624
- return to.key === from.key
625
- })
626
- if (found) {
627
- found.value = (found.value || []).concat(from.value)
628
- } else {
629
- toArr.push(from)
630
- }
631
- })
632
- return toArr
633
- }
634
- static removeByKey(arr, key) {
635
- return arr.reduce((acc, item) => {
636
- if (!this.sameKey(item, key)) {
637
- acc.push(item)
638
- }
639
- return acc
640
- }, [])
641
- }
642
- static sameKey(item, key) {
643
- return _isSame(item.key, key)
644
- }
645
- static toObject(arr = []) {
646
- if (Array.isArray(arr)) {
647
- return arr.reduce((acc, item) => {
648
- acc[item.key] = item.value
649
- return acc
650
- }, {})
651
- }
652
- return {}
653
- }
654
- static toString(arr = [], delimiter = '; ') {
655
- if (Array.isArray(arr)) {
656
- return arr.reduce((acc, item) => {
657
- acc.push(`${item.key}: ${item.value}`)
658
- return acc
659
- }, []).join(delimiter)
660
- }
661
- return ''
662
- }
663
- static updateRecord(arr = [], key, value) {
664
- return arr.map((item) => {
665
- if (this.sameKey(item, key)) {
666
- return {
667
- ...item,
668
- value
669
- }
670
- }
671
- return item
672
- })
673
- }
674
- static updateOrInsertRecord(arr = [], key, value) {
675
- return this.insertOrUpdateRecord(arr, key, value)
676
- }
677
- static updateRecordsFromArray(arr = [], updateArr = []) {
678
- if (Array.isArray(arr) && Array.isArray(updateArr)) {
679
- const obj1 = this.toObject(arr)
680
- const obj2 = this.toObject(updateArr)
681
- return this.fromObject({
682
- ...obj1,
683
- ...obj2
684
- })
685
- }
686
- return []
687
- }
688
- static values(arr = []) {
689
- if (Array.isArray(arr)) {
690
- return arr.reduce((acc, item) => {
691
- acc.push(item.value)
692
- return acc
693
- }, [])
694
- }
695
- return []
517
+ }
518
+
519
+ function _isPureStringOrNumber(input) {
520
+ if (typeof input === 'string') {
521
+ if (input.startsWith('[') && input.endsWith(']')) {
522
+ return false
523
+ }
524
+ if (/!=|>=|<=|>|</.test(input)) {
525
+ return false
526
+ }
527
+ return true
696
528
  }
529
+ return !Number.isNaN(input)
530
+ }
697
531
 
698
- // getters
699
- get isValid() {
700
- return !!this.key
701
- }
532
+ function _splitOperator(str) {
533
+ const operators = ['!=', '>=', '<=', '>', '<']
702
534
 
703
- get toObject() {
704
- const obj = {}
705
- if (this.isValid) {
706
- obj[this.key] = this.value
707
- }
708
- return obj
535
+ const matchedOp = operators.find((op) => str.startsWith(op))
536
+ if (!matchedOp) return { operator: null, value: null }
537
+
538
+ const remaining = str.slice(matchedOp.length)
539
+
540
+ // '>Primary' or '<Primary' is invalid
541
+ if (/^[a-zA-Z]*$/.test(remaining) && matchedOp !== '!=') {
542
+ return { operator: null, value: null }
709
543
  }
710
- }
711
544
 
712
- function _isSame(key1, key2) {
713
- return key1 === key2
714
- }
545
+ // if it is a number it is converted to a number
546
+ const value = (!Number.isNaN(parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
715
547
 
548
+ return {
549
+ operator: matchedOp,
550
+ value
551
+ }
552
+ }
716
553
 
717
554
 
718
- ;// ./lib/models/keyValueObject/index.js
719
555
 
556
+ ;// ./lib/models/templateCompiler/helpers/_filterOne.js
720
557
 
721
558
 
722
559
 
723
- ;// ./lib/helpers/stringFormatter/stringFormatter.js
724
- function stringFormatter(str, delimiter = '_') {
725
- if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
726
- return null
560
+ function _filterOne(data, args) {
561
+ try {
562
+ const list = _filterAll(data, args)
563
+ if (list.length === 1) {
564
+ return list[0]
565
+ }
566
+ if (list.length === 0) {
567
+ return null
568
+ }
569
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.resultMoreThanOneException)
570
+ } catch (e) {
571
+ throw e
727
572
  }
728
- return str.toString()
729
- .trim()
730
- .toUpperCase()
731
- .replace('-', delimiter)
732
- .replace(' ', delimiter)
733
573
  }
734
574
 
735
575
 
736
576
 
737
- ;// ./lib/models/metadata/metadata.js
738
-
739
-
577
+ ;// ./lib/models/templateCompiler/helpers/_formatDate.js
740
578
 
741
- const DELIMITER = '_'
742
579
 
743
- class Metadata extends KeyValueObject {
744
- static init(options = {}) {
745
- if (options instanceof this) {
746
- return options
747
- }
748
- const instance = new this({
749
- ...options,
750
- key: stringFormatter(options.key, DELIMITER),
751
- })
752
- return instance.isValid ? instance : null
753
- }
754
- static get _classname() {
755
- return 'Metadata'
580
+ function _formatDate(timestamp, format) {
581
+ if (format.length === 0) {
582
+ throw new TemplateCompilerException(`_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: format parts must be not empty array`)
756
583
  }
757
584
 
758
- static merge(toArr, fromArr) {
759
- (fromArr || []).map((from) => {
760
- const found = toArr.find((to) => {
761
- return metadata_isSame(to.key, from.key)
762
- })
763
- if (found) {
764
- found.value = (found.value || []).concat(from.value)
765
- } else {
766
- toArr.push(from)
767
- }
768
- })
769
- return toArr
770
- }
771
- static sameKey(item, key) {
772
- return metadata_isSame(item.key, key)
585
+ if (timestamp === null || timestamp === undefined) {
586
+ return null
773
587
  }
774
- }
775
-
776
- function metadata_isSame(key1, key2) {
777
- return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
778
- }
779
588
 
589
+ const date = new Date(timestamp)
780
590
 
591
+ const partsMap = {
592
+ yyyy: String(date.getFullYear()),
593
+ mm: String(date.getMonth() + 1).padStart(2, '0'),
594
+ dd: String(date.getDate()).padStart(2, '0')
595
+ }
781
596
 
782
- ;// ./lib/models/metadata/index.js
597
+ // Check for invalid format tokens
598
+ const validTokens = ['yyyy', 'mm', 'dd']
599
+ const invalidTokens = format.filter((part) => part.length > 1 && !validTokens.includes(part))
783
600
 
601
+ if (invalidTokens.length > 0) {
602
+ throw new TemplateCompilerException(
603
+ `_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the format type is not valid: ${format.join(', ')}`
604
+ )
605
+ }
784
606
 
607
+ // Build the formatted string using reduce
608
+ return format.reduce((result, part) => result + (partsMap[part] || part), '')
609
+ }
785
610
 
786
611
 
787
- ;// ./lib/models/qMeta/qMeta.js
788
612
 
613
+ ;// ./lib/models/templateCompiler/helpers/_get.js
789
614
 
790
- const updateAllowedProps = [
791
- 'attributes',
792
- 'ref'
793
- ]
794
615
 
795
- class QMeta {
796
- constructor(options = {}) {
797
- options = options || {}
798
- this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
799
- this.ref = options.ref || {}
616
+ function _get(data, key, failover = null) {
617
+ try {
618
+ if (key === null || (typeof key === 'undefined') || key === '') {
619
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
620
+ }
621
+ if (data === null) {
622
+ return null
623
+ }
624
+ if (key.includes('.')) {
625
+ const parts = key.split('.')
626
+ if (parts.length > 1) {
627
+ const first = parts.shift()
628
+ const remainingKey = parts.join('.')
629
+ if (typeof data[first] !== 'undefined') {
630
+ return _get(data[first], remainingKey, failover)
631
+ }
632
+ return _handleFailover(key, failover)
633
+ }
634
+ }
635
+ if (typeof data[key] !== 'undefined') {
636
+ return data[key]
637
+ }
638
+ return _handleFailover(key, failover)
639
+ } catch (e) {
640
+ throw e
800
641
  }
642
+ }
801
643
 
802
- static get _classname() {
803
- return 'QMeta'
804
- }
805
- static get _superclass() {
806
- return 'QMeta'
644
+ function _handleFailover(key, failover) {
645
+ if (failover !== null) {
646
+ return failover
807
647
  }
648
+ return null
649
+ // throw new TemplateCompilerException(`Key "${key}" does not exist and no failover`)
650
+ }
808
651
 
809
- // Class methods
810
- static init(options = {}) {
811
- if (options instanceof QMeta) {
812
- return options
813
- }
814
- return new QMeta(options)
815
- }
816
652
 
817
- // instance methods
818
- addAttribute(obj) {
819
- const kvObject = KeyValueObject.init(obj)
820
- if (!kvObject) {
821
- throw new Error('invalid meta attribute')
822
- }
823
- this.attributes.push(kvObject)
824
- return this
825
- }
826
653
 
827
- update(obj) {
828
- Object.keys(obj).forEach((key) => {
829
- if (updateAllowedProps.includes(key)) {
830
- if (key === 'attributes') {
831
- this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
832
- } else {
833
- this[key] = obj[key]
834
- }
835
- }
654
+ ;// ./lib/models/templateCompiler/helpers/_gt.js
655
+
656
+
657
+
658
+
659
+ function _gt(data, args) {
660
+ if (args.length !== 3) {
661
+ throw new TemplateCompilerException(`_gt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
662
+ }
663
+ if (data === null || (typeof data === 'undefined')) {
664
+ return null
665
+ }
666
+ if (args.includes(_SELF)) {
667
+ args = args.map((arg) => {
668
+ return (arg === _SELF) ? data : arg
836
669
  })
837
- return this
838
670
  }
671
+ const expected = args[0]
672
+ return data > expected ? args[1] : args[2]
839
673
  }
840
674
 
841
675
 
842
676
 
843
- ;// ./lib/models/qMeta/index.js
677
+ ;// ./lib/models/templateCompiler/helpers/_gte.js
844
678
 
845
679
 
846
680
 
847
681
 
848
- ;// ./lib/models/repo/repo.js
849
- class Repo {
850
- constructor(options) {
851
- options = options || {}
852
- this.model = options.model
853
- this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
854
- this._queryOptions = options._queryOptions
855
- this._saveOptions = options._saveOptions
856
- this._Class = options._constructor && options._constructor._Class
857
- ? options._constructor._Class
858
- : null
859
- }
860
- static init(options = {}) {
861
- if (options instanceof this) {
862
- return options
863
- }
864
- const instance = new this(options)
865
- return instance.isValid ? instance : null
682
+ function _gte(data, args) {
683
+ if (args.length !== 3) {
684
+ throw new TemplateCompilerException(`_gte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
866
685
  }
867
- static get _classname() {
868
- return 'Repo'
686
+ if (data === null || (typeof data === 'undefined')) {
687
+ return null
869
688
  }
870
- static get _superclass() {
871
- return 'Repo'
689
+ if (args.includes(_SELF)) {
690
+ args = args.map((arg) => {
691
+ return (arg === _SELF) ? data : arg
692
+ })
872
693
  }
694
+ const expected = args[0]
695
+ return data >= expected ? args[1] : args[2]
696
+ }
873
697
 
874
- get _classname() {
875
- return 'Repo'
876
- }
877
698
 
878
- get _superclass() {
879
- return 'Repo'
880
- }
881
699
 
882
- get isValid() {
883
- return this.model
884
- && (typeof this.model.deleteOne === 'function')
885
- && (typeof this.model.findAll === 'function')
886
- && (typeof this.model.saveOne === 'function')
887
- }
700
+ ;// ./lib/models/templateCompiler/helpers/_isEmpty.js
888
701
 
889
- get queryOptions() {
890
- return {
891
- ...this._sharedOptions,
892
- ...this._queryOptions,
893
- }
894
- }
895
702
 
896
- get saveOptions() {
897
- return {
898
- ...this._sharedOptions,
899
- ...this._saveOptions,
900
- }
901
- }
902
703
 
903
- init(options) {
904
- if (this._Class && typeof this._Class.init === 'function') {
905
- return this._Class.init(options)
906
- }
907
- return options
908
- }
909
704
 
910
- async deleteOne({ id }) {
911
- try {
912
- const result = await this.model.deleteOne({ _id: id })
913
- return {
914
- ...result, // { message: 'ok', total }
915
- isNew: false,
916
- data: []
917
- }
918
- } catch (err) {
919
- throw err
920
- }
705
+ function _isEmpty(data, args) {
706
+ if (args.length !== 2) {
707
+ throw new TemplateCompilerException(`_isEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
921
708
  }
922
-
923
- // systemLog is optional
924
- findAll({ query, systemLog }) {
925
- const log = _makeLog({
926
- systemLog,
927
- label: 'REPO_READ',
928
- message: `fn ${this._classname}.prototype.findAll`,
929
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
930
- })
931
- return new Promise((resolve, reject) => {
932
- this.model.findAll(query, this.queryOptions, (err, data, total) => {
933
- if (err) {
934
- log({ level: 'warn', output: err.toString() })
935
- reject(err)
936
- } else {
937
- const result = {
938
- isNew: false,
939
- data,
940
- total: total || data.length
941
- }
942
- log({ level: 'info', output: { ...result } })
943
- resolve(result)
944
- }
945
- })
709
+ // if (data === null || (typeof data === 'undefined')) {
710
+ // return null
711
+ // }
712
+ if (args.includes(_SELF)) {
713
+ args = args.map((arg) => {
714
+ return (arg === _SELF) ? data : arg
946
715
  })
947
716
  }
948
-
949
- findOne({ query, systemLog }) {
950
- const log = _makeLog({
951
- systemLog,
952
- label: 'REPO_READ',
953
- message: `fn ${this._classname}.prototype.findOne`,
954
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
955
- })
956
- return new Promise((resolve, reject) => {
957
- this.model.findAll(query, this.queryOptions, (err, data) => {
958
- if (err) {
959
- reject(err)
960
- } else if (data.length === 1) {
961
- const result = {
962
- isNew: false,
963
- data,
964
- total: 1
965
- }
966
- log({ level: 'info', output: { ...result } })
967
- resolve(result)
968
- } else if (data.length === 0) {
969
- reject(new Error('record not found'))
970
- } else {
971
- reject(new Error('more than one is found'))
972
- }
973
- })
974
- })
975
- .catch((err) => {
976
- log({ level: 'warn', output: err.toString() })
977
- throw err
978
- })
717
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
718
+ return args[0]
979
719
  }
720
+ return (data === '' || data === null || data === undefined || data.length === 0) ? args[0] : args[1]
721
+ }
980
722
 
981
- saveAll({ docs, systemLog }) {
982
- let isNew
983
- const log = _makeLog({
984
- systemLog,
985
- label: 'REPO_WRITE',
986
- message: `fn ${this._classname}.prototype.saveAll`,
987
- input: [{ docs: [...docs], systemLog: { ...systemLog } }]
723
+
724
+
725
+ ;// ./lib/models/templateCompiler/helpers/_isNotEmpty.js
726
+
727
+
728
+
729
+
730
+ function _isNotEmpty(data, args) {
731
+ if (args.length !== 2) {
732
+ throw new TemplateCompilerException(`_isNotEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
733
+ }
734
+ // if (data === null || (typeof data === 'undefined')) {
735
+ // return null
736
+ // }
737
+ if (args.includes(_SELF)) {
738
+ args = args.map((arg) => {
739
+ return (arg === _SELF) ? data : arg
988
740
  })
989
- const promise = typeof this.model.saveAll === 'function'
990
- ? this.model.saveAll({ docs })
991
- : Promise.all(docs.map(async (doc) => {
992
- if (doc) {
993
- const result = await this.saveOne({ doc })
994
- isNew = result.isNew
995
- const _data = result._data || result.data
996
- return _data[0]
997
- }
998
- return null
999
- }))
1000
- return promise.then((savedData) => {
1001
- if (savedData.length !== 1) isNew = null
1002
- const result = {
1003
- data: savedData,
1004
- isNew,
1005
- total: savedData.length
1006
- }
1007
- log({ level: 'info', output: { ...result } })
1008
- return result
1009
- }).catch((err) => {
1010
- log({ level: 'warn', output: err.toString() })
1011
- throw err
1012
- })
1013
- }
1014
-
1015
- saveOne({ doc, systemLog }) {
1016
- const log = _makeLog({
1017
- systemLog,
1018
- label: 'REPO_WRITE',
1019
- message: `fn ${this._classname}.prototype.saveOne`,
1020
- input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
1021
- })
1022
- return new Promise((resolve, reject) => {
1023
- this.model.saveOne(doc, this.saveOptions, (err, result) => {
1024
- if (err) {
1025
- log({ level: 'warn', output: err.toString() })
1026
- reject(err)
1027
- } else {
1028
- log({ level: 'info', output: { ...result } })
1029
- resolve(result)
1030
- }
1031
- })
1032
- })
1033
- }
1034
- }
1035
-
1036
- function _makeLog({ systemLog, label, message: message1, input } = {}) {
1037
- return ({ level, messgae: massage2, output } = {}) => {
1038
- if (systemLog && systemLog.systemLogHelper) {
1039
- systemLog.systemLogHelper.log({
1040
- batchId: systemLog.batchId,
1041
- label,
1042
- level,
1043
- message: massage2 || message1,
1044
- data: {
1045
- payload: {
1046
- input,
1047
- output
1048
- }
1049
- }
1050
- })
1051
- }
1052
- }
1053
- }
1054
-
1055
-
1056
-
1057
- ;// ./lib/models/repo/index.js
1058
-
1059
-
1060
-
1061
-
1062
- ;// ./lib/models/service/service.js
1063
-
1064
-
1065
-
1066
- class Service {
1067
- constructor({ repo }) {
1068
- this.repo = repo
1069
- }
1070
-
1071
- static get _classname() {
1072
- return 'Service'
1073
- }
1074
- static get _superclass() {
1075
- return 'Service'
1076
- }
1077
-
1078
- deleteOne({ id }) {
1079
- return this.repo.deleteOne({ id })
1080
- .catch(() => {
1081
- throw new Error(`Not found for query: ${id}`)
1082
- })
1083
- }
1084
-
1085
- async findAll({ query = {}, systemLog } = {}) {
1086
- const result = await this.repo.findAll({ query, systemLog })
1087
- return makeApiResponse({
1088
- repo: this.repo,
1089
- result
1090
- })
1091
- }
1092
-
1093
- async findOne({ query = {}, systemLog } = {}) {
1094
- const result = await this.repo.findOne({ query, systemLog })
1095
- return makeApiResponse({
1096
- repo: this.repo,
1097
- result
1098
- })
1099
- }
1100
-
1101
- init(options) {
1102
- return this.repo.init(options)
1103
- }
1104
- initFromArray(arr = []) {
1105
- if (Array.isArray(arr)) {
1106
- return arr.map((a) => this.init(a))
1107
- }
1108
- return []
1109
- }
1110
- initOnlyValidFromArray(arr = []) {
1111
- return this.initFromArray(arr).filter((i) => i)
1112
741
  }
1113
-
1114
- async saveAll({ docs = [], systemLog } = {}) {
1115
- const copies = docs.map((doc) => {
1116
- return this.init(doc)
1117
- })
1118
- const result = await this.repo.saveAll({ docs: copies, systemLog })
1119
- return makeApiResponse({
1120
- repo: this.repo,
1121
- result
1122
- })
742
+ if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
743
+ return args[1]
1123
744
  }
1124
-
1125
- async saveOne({ doc = {}, systemLog } = {}) {
1126
- const copy = this.init(doc)
1127
- if (copy) {
1128
- const result = await this.repo.saveOne({ doc: copy, systemLog })
1129
- return makeApiResponse({
1130
- repo: this.repo,
1131
- result
1132
- })
1133
- }
1134
- return {
1135
- isNew: null,
1136
- data: [],
1137
- err: new Error('doc is not a valid instance')
1138
- }
745
+ if (Array.isArray(data) && data.length === 0) {
746
+ return args[1]
1139
747
  }
1140
- }
1141
-
1142
- function makeService({ repo }) {
1143
- if (repo === undefined) {
1144
- throw new Error('repo is required.')
748
+ if (typeof data === 'string' && data === '') {
749
+ return args[1]
1145
750
  }
1146
- if (repo._superclass !== Repo._superclass) {
1147
- throw new Error('repo is not an instance of Repo.')
751
+ if (data === null || data === undefined) {
752
+ return args[1]
1148
753
  }
1149
- return new Service({ repo })
754
+ return args[0]
1150
755
  }
1151
756
 
1152
757
 
1153
-
1154
- ;// ./lib/models/service/index.js
1155
-
1156
-
1157
-
1158
-
1159
- ;// ./lib/models/templateCompiler/templateCompilerException.js
1160
- const TEMPLATE_COMPILER_EXCEPTION_TYPE = {
1161
- argumentEmptyException: 'Argument is empty',
1162
- argumentFormatException: 'Incorrect number or format of argument',
1163
- invalidFuntionException: 'Function Name is invalid',
1164
- invalidRegExpException: 'Invalid regular expression',
1165
- isNotAFunctionException: 'Is not a function',
1166
- notExistException: 'Key does not exist',
1167
- resultEmptyException: 'Result is empty',
1168
- resultMoreThanOneException: 'More than one result'
1169
- }
1170
-
1171
- class TemplateCompilerException extends Error {
1172
- constructor(message) {
1173
- super(message)
1174
- this.message = message
758
+ ;// ./lib/models/templateCompiler/helpers/_join.js
759
+ function _join(data, delimiter) {
760
+ try {
761
+ if (data.length === 0) return ''
762
+ if (data.length === 1) return _stringifyObject(data[0])
763
+ return data.map((item) => _stringifyObject(item)).join(delimiter)
764
+ } catch (e) {
765
+ throw e
1175
766
  }
1176
767
  }
1177
768
 
1178
-
1179
-
1180
- ;// ./lib/models/templateCompiler/constants.js
1181
- const _EMPTY = '_EMPTY'
1182
- const _FN_NAMES = [
1183
- 'get', 'map', 'join', 'concatIf', 'exec', 'filterOne', 'filterAll', 'formatDate', 'eq', 'neq', 'gt', 'lt', 'gte', 'lte', 'isEmpty', 'isNotEmpty', 'toLowerCase', 'toUpperCase'
1184
- ]
1185
- const _HIDE = '_HIDE'
1186
- const _NOT_EMPTY = '_NOT_EMPTY'
1187
- const _SELF = '_SELF'
1188
- const TAGS_EJS = ['<%=', '%>']
1189
- const TAGS_HANDLEBAR = ['{{', '}}']
769
+ function _stringifyObject(obj) {
770
+ return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1: ').replace(/"([^"]+)"/g, '$1').replace(/,/g, ', ')
771
+ }
1190
772
 
1191
773
 
1192
774
 
1193
- ;// ./lib/models/templateCompiler/helpers/_concatIf.js
775
+ ;// ./lib/models/templateCompiler/helpers/_lt.js
1194
776
 
1195
777
 
1196
778
 
1197
779
 
1198
- function _concatIf(data, args) {
1199
- if (typeof data !== 'string') {
1200
- throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string :${data.join(', ')}`)
1201
- }
780
+ function _lt(data, args) {
1202
781
  if (args.length !== 3) {
1203
- throw new TemplateCompilerException(`_concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
782
+ throw new TemplateCompilerException(`_lt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1204
783
  }
1205
784
  if (data === null || (typeof data === 'undefined')) {
1206
785
  return null
1207
786
  }
1208
- const [condition, success, failover] = args
1209
- const validConditions = [_EMPTY, _NOT_EMPTY]
1210
- if (validConditions.includes(condition) || success.length !== 2) {
1211
- throw new TemplateCompilerException(`concatIf: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException}: ${condition}, ${success}`)
1212
- }
1213
- if (data === '' && failover.includes(_HIDE)) {
1214
- return ''
1215
- }
1216
- if (data !== '' && (data !== null || data !== undefined) && failover.includes(_HIDE)) {
1217
- return `${success[0]}${data}${success[success.length - 1]}`
787
+ if (args.includes(_SELF)) {
788
+ args = args.map((arg) => {
789
+ return (arg === _SELF) ? data : arg
790
+ })
1218
791
  }
1219
- return failover
792
+ const expected = args[0]
793
+ return data < expected ? args[1] : args[2]
1220
794
  }
1221
795
 
1222
796
 
1223
797
 
1224
- ;// ./lib/models/templateCompiler/helpers/_eq.js
798
+ ;// ./lib/models/templateCompiler/helpers/_lte.js
1225
799
 
1226
800
 
1227
801
 
1228
802
 
1229
- function _eq(data, args) {
803
+ function _lte(data, args) {
1230
804
  if (args.length !== 3) {
1231
- throw new TemplateCompilerException(`eq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
805
+ throw new TemplateCompilerException(`_lte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1232
806
  }
1233
807
  if (data === null || (typeof data === 'undefined')) {
1234
808
  return null
@@ -1239,490 +813,389 @@ function _eq(data, args) {
1239
813
  })
1240
814
  }
1241
815
  const expected = args[0]
1242
- return data === expected ? args[1] : args[2]
816
+ return data <= expected ? args[1] : args[2]
1243
817
  }
1244
818
 
1245
819
 
1246
820
 
1247
- ;// ./lib/models/templateCompiler/helpers/_exec.js
1248
- function _exec(data, args) {
1249
- try {
1250
- const [methodName, ..._args] = args
1251
- return data[methodName](..._args)
1252
- } catch (e) {
1253
- throw e
1254
- }
1255
- }
1256
-
1257
-
821
+ ;// ./lib/models/templateCompiler/helpers/_map.js
1258
822
 
1259
- ;// ./lib/models/templateCompiler/helpers/_filterAll.js
1260
823
 
1261
824
 
1262
-
1263
- // const DELIMITER = '~~~'
1264
-
1265
- function _filterAll(data, args) {
825
+ function _map(data, args) {
1266
826
  try {
1267
- if (!Array.isArray(args) || args.length === 0) {
827
+ if (args.length === 0) {
1268
828
  throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
1269
829
  }
1270
- if (!Array.isArray(data) || data.length === 0) {
1271
- return []
1272
- }
1273
- if (typeof data[0] === 'object') {
1274
- return _existObject(data, args)
1275
- }
1276
- if (typeof data[0] === 'string' || typeof data[0] === 'number') {
1277
- return _exist(data, args)
830
+ if (data === null || (typeof data === 'undefined')) {
831
+ return null
1278
832
  }
1279
- return []
833
+
834
+ const result = data.reduce((acc, item) => {
835
+ if (args.length === 1 && Array.isArray(args[0])) {
836
+ args = args[0]
837
+ acc.hasFormat = true
838
+ }
839
+ const list = args.map((key) => {
840
+ if (key.includes('.')) {
841
+ const parts = key.split('.')
842
+ const first = parts[0]
843
+ parts.shift()
844
+ const remainingKey = parts.join('.')
845
+ return _get(item[first], remainingKey)
846
+ }
847
+ if (typeof item[key] !== 'undefined') {
848
+ return item[key]
849
+ }
850
+ return null
851
+ })
852
+ if (acc.hasFormat) {
853
+ acc.content.push(list)
854
+ } else {
855
+ acc.content = acc.content.concat(list)
856
+ }
857
+ return acc
858
+ }, {
859
+ content: [],
860
+ hasFormat: false
861
+ })
862
+ return result.content
1280
863
  } catch (e) {
1281
864
  throw e
1282
865
  }
1283
866
  }
1284
867
 
1285
- function _exist(data, args) {
1286
- const _args = args.flat()
1287
- return data.filter((e) => _args.some((arg) => _performOperation(arg, e)))
1288
- }
1289
868
 
1290
- function _existObject(data, args) {
1291
- if (args.length === 1) {
1292
- const arg = args[0]
1293
- return data.filter((e) => {
1294
- if (arg.includes('.')) {
1295
- return getValueByKeys(arg.split('.'), e)
1296
- }
1297
- return Object.prototype.hasOwnProperty.call(e, arg)
1298
- })
1299
- }
1300
869
 
1301
- if (args.length > 2) {
1302
- let res = data
1303
- for (let i = 0; i < args.length; i += 2) {
1304
- const group = [args[i], args[i + 1]]
1305
- res = _existObject(res, group)
1306
- }
1307
- return res
1308
- }
870
+ ;// ./lib/models/templateCompiler/helpers/_neq.js
1309
871
 
1310
- const [key, ..._argsArr] = args
1311
- const _args = _argsArr.flat()
1312
- return data.filter((e) => {
1313
- const value = key.includes('.') ? getValueByKeys(key.split('.'), e) : e[key]
1314
- return _args.some((arg) => _performOperation(arg, value))
1315
- })
1316
- }
1317
872
 
1318
- function _performOperation(arg, value) {
1319
- // the arg is undefined
1320
- if (arg === undefined && value === undefined) return true
1321
873
 
1322
- // the arg is null
1323
- if (arg === null && value === null) return true
1324
874
 
1325
- // the arg is boolean
1326
- if (typeof arg === 'boolean') {
1327
- return arg === value
875
+ function _neq(data, args) {
876
+ if (args.length !== 3) {
877
+ throw new TemplateCompilerException(`_neq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1328
878
  }
1329
-
1330
- // the arg is blank or *: Blank => Empty, * => Not Empty
1331
- if (arg === '' || arg === '*') {
1332
- // null and undefined are not included in either case
1333
- if (value === null || value === undefined) {
1334
- return false
1335
- }
1336
- if (typeof value === 'string') {
1337
- return arg === '' ? value === '' : value !== ''
1338
- }
1339
- if (Array.isArray(value)) {
1340
- return arg === '' ? value.length === 0 : value.length !== 0
1341
- }
1342
- return arg !== ''
879
+ if (data === null || (typeof data === 'undefined')) {
880
+ return null
1343
881
  }
1344
-
1345
- // the arg is alphabetic or number
1346
- if (_isPureStringOrNumber(arg)) {
1347
- return arg === value
882
+ if (args.includes(_SELF)) {
883
+ args = args.map((arg) => {
884
+ return (arg === _SELF) ? data : arg
885
+ })
1348
886
  }
887
+ const expected = args[0]
888
+ return data !== expected ? args[1] : args[2]
889
+ }
1349
890
 
1350
- // the arg is array of [] or [*]: [] => Empty, [*] => Not Empty
1351
- if (arg.startsWith('[') && arg.endsWith(']')) {
1352
- if (arg === '[]') {
1353
- return Array.isArray(value) && value.length === 0
1354
- }
1355
- if (arg === '[*]') {
1356
- return Array.isArray(value) && value.length !== 0
1357
- }
1358
- return false
1359
- }
1360
891
 
1361
- // the arg is 'operator + string | number'
1362
- const { operator, value: argValue } = _splitOperator(arg)
1363
- if (!operator || (argValue !== 0 && !argValue)) {
1364
- return false
892
+
893
+ ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
894
+
895
+
896
+ function _toLowerCase(data, args) {
897
+ if (args !== undefined) {
898
+ throw new TemplateCompilerException(`_toLowerCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1365
899
  }
1366
- switch (operator) {
1367
- case '>':
1368
- return value > argValue
1369
- case '<':
1370
- return value < argValue
1371
- case '!=':
1372
- return value !== argValue
1373
- case '>=':
1374
- return value >= argValue
1375
- case '<=':
1376
- return value <= argValue
1377
- default:
1378
- return false
900
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
901
+ return null
1379
902
  }
903
+ return String(data).toLowerCase()
1380
904
  }
1381
905
 
1382
- function _isPureStringOrNumber(input) {
1383
- if (typeof input === 'string') {
1384
- if (input.startsWith('[') && input.endsWith(']')) {
1385
- return false
1386
- }
1387
- if (/!=|>=|<=|>|</.test(input)) {
1388
- return false
1389
- }
1390
- return true
906
+
907
+
908
+ ;// ./lib/models/templateCompiler/helpers/_toUpperCase.js
909
+
910
+
911
+ function _toUpperCase(data, args) {
912
+ if (typeof data !== 'string') {
913
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string: ${data}`)
1391
914
  }
1392
- return !Number.isNaN(input)
915
+ if (args !== undefined) {
916
+ throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the argument must be empty: ${args.join(', ')}`)
917
+ }
918
+ if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
919
+ return null
920
+ }
921
+ return String(data).toUpperCase()
1393
922
  }
1394
923
 
1395
- function _splitOperator(str) {
1396
- const operators = ['!=', '>=', '<=', '>', '<']
1397
924
 
1398
- const matchedOp = operators.find((op) => str.startsWith(op))
1399
- if (!matchedOp) return { operator: null, value: null }
1400
925
 
1401
- const remaining = str.slice(matchedOp.length)
926
+ ;// ./lib/models/templateCompiler/helpers/index.js
1402
927
 
1403
- // '>Primary' or '<Primary' is invalid
1404
- if (/^[a-zA-Z]*$/.test(remaining) && matchedOp !== '!=') {
1405
- return { operator: null, value: null }
1406
- }
1407
928
 
1408
- // if it is a number it is converted to a number
1409
- const value = (!Number.isNaN(parseFloat(remaining)) && !Number.isNaN(remaining)) ? Number(remaining) : remaining
1410
929
 
1411
- return {
1412
- operator: matchedOp,
1413
- value
1414
- }
1415
- }
1416
930
 
1417
931
 
1418
932
 
1419
- ;// ./lib/models/templateCompiler/helpers/_filterOne.js
1420
933
 
1421
934
 
1422
935
 
1423
- function _filterOne(data, args) {
1424
- try {
1425
- const list = _filterAll(data, args)
1426
- if (list.length === 1) {
1427
- return list[0]
1428
- }
1429
- if (list.length === 0) {
1430
- return null
1431
- }
1432
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.resultMoreThanOneException)
1433
- } catch (e) {
1434
- throw e
1435
- }
1436
- }
1437
936
 
1438
937
 
1439
938
 
1440
- ;// ./lib/models/templateCompiler/helpers/_formatDate.js
1441
939
 
1442
940
 
1443
- function _formatDate(timestamp, format) {
1444
- if (format.length === 0) {
1445
- throw new TemplateCompilerException(`_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: format parts must be not empty array`)
1446
- }
1447
941
 
1448
- if (timestamp === null || timestamp === undefined) {
1449
- return null
1450
- }
1451
942
 
1452
- const date = new Date(timestamp)
1453
943
 
1454
- const partsMap = {
1455
- yyyy: String(date.getFullYear()),
1456
- mm: String(date.getMonth() + 1).padStart(2, '0'),
1457
- dd: String(date.getDate()).padStart(2, '0')
1458
- }
1459
944
 
1460
- // Check for invalid format tokens
1461
- const validTokens = ['yyyy', 'mm', 'dd']
1462
- const invalidTokens = format.filter((part) => part.length > 1 && !validTokens.includes(part))
1463
945
 
1464
- if (invalidTokens.length > 0) {
1465
- throw new TemplateCompilerException(
1466
- `_formateDate: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the format type is not valid: ${format.join(', ')}`
1467
- )
1468
- }
1469
946
 
1470
- // Build the formatted string using reduce
1471
- return format.reduce((result, part) => result + (partsMap[part] || part), '')
1472
- }
1473
947
 
948
+ ;// ./lib/models/templateCompiler/templateCompiler.js
1474
949
 
1475
950
 
1476
- ;// ./lib/models/templateCompiler/helpers/_get.js
1477
951
 
1478
952
 
1479
- function _get(data, key, failover = null) {
1480
- try {
1481
- if (key === null || (typeof key === 'undefined') || key === '') {
1482
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
1483
- }
1484
- if (data === null) {
1485
- return null
953
+ class TemplateCompiler {
954
+ constructor(data) {
955
+ this.data = data
956
+ }
957
+ static init(options) {
958
+ return new this(options)
959
+ }
960
+ static initFromArray(arr = []) {
961
+ if (Array.isArray(arr)) {
962
+ return arr.map((a) => this.init(a))
1486
963
  }
1487
- if (key.includes('.')) {
1488
- const parts = key.split('.')
1489
- if (parts.length > 1) {
1490
- const first = parts.shift()
1491
- const remainingKey = parts.join('.')
1492
- if (typeof data[first] !== 'undefined') {
1493
- return _get(data[first], remainingKey, failover)
1494
- }
1495
- return _handleFailover(key, failover)
1496
- }
1497
- }
1498
- if (typeof data[key] !== 'undefined') {
1499
- return data[key]
1500
- }
1501
- return _handleFailover(key, failover)
1502
- } catch (e) {
1503
- throw e
1504
- }
1505
- }
1506
-
1507
- function _handleFailover(key, failover) {
1508
- if (failover !== null) {
1509
- return failover
964
+ return []
1510
965
  }
1511
- return null
1512
- // throw new TemplateCompilerException(`Key "${key}" does not exist and no failover`)
1513
- }
1514
-
1515
-
1516
-
1517
- ;// ./lib/models/templateCompiler/helpers/_gt.js
1518
-
1519
-
1520
-
1521
-
1522
- function _gt(data, args) {
1523
- if (args.length !== 3) {
1524
- throw new TemplateCompilerException(`_gt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
966
+ static initOnlyValidFromArray(arr = []) {
967
+ return this.initFromArray(arr).filter((i) => i)
1525
968
  }
1526
- if (data === null || (typeof data === 'undefined')) {
1527
- return null
969
+ static concatIf(data, args) {
970
+ return _concatIf(data, args)
1528
971
  }
1529
- if (args.includes(_SELF)) {
1530
- args = args.map((arg) => {
1531
- return (arg === _SELF) ? data : arg
1532
- })
972
+ static eq(data, args) {
973
+ return _eq(data, args)
1533
974
  }
1534
- const expected = args[0]
1535
- return data > expected ? args[1] : args[2]
1536
- }
1537
-
1538
-
1539
-
1540
- ;// ./lib/models/templateCompiler/helpers/_gte.js
1541
-
1542
-
1543
975
 
976
+ static filterAll(data, args) {
977
+ return _filterAll(data, args)
978
+ }
1544
979
 
1545
- function _gte(data, args) {
1546
- if (args.length !== 3) {
1547
- throw new TemplateCompilerException(`_gte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
980
+ static formatDate(data, args) {
981
+ return _formatDate(data, args)
1548
982
  }
1549
- if (data === null || (typeof data === 'undefined')) {
1550
- return null
983
+
984
+ static get(data, key, failover = null) {
985
+ return _get(data, key, failover)
1551
986
  }
1552
- if (args.includes(_SELF)) {
1553
- args = args.map((arg) => {
1554
- return (arg === _SELF) ? data : arg
1555
- })
987
+ static gt(data, args) {
988
+ return _gt(data, args)
1556
989
  }
1557
- const expected = args[0]
1558
- return data >= expected ? args[1] : args[2]
1559
- }
1560
-
1561
-
1562
-
1563
- ;// ./lib/models/templateCompiler/helpers/_isEmpty.js
1564
-
1565
-
1566
-
1567
-
1568
- function _isEmpty(data, args) {
1569
- if (args.length !== 2) {
1570
- throw new TemplateCompilerException(`_isEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
990
+ static gte(data, args) {
991
+ return _gte(data, args)
1571
992
  }
1572
- // if (data === null || (typeof data === 'undefined')) {
1573
- // return null
1574
- // }
1575
- if (args.includes(_SELF)) {
1576
- args = args.map((arg) => {
1577
- return (arg === _SELF) ? data : arg
1578
- })
993
+ static isEmpty(data, args) {
994
+ return _isEmpty(data, args)
1579
995
  }
1580
- if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
1581
- return args[0]
996
+ static isNotEmpty(data, args) {
997
+ return _isNotEmpty(data, args)
1582
998
  }
1583
- return (data === '' || data === null || data === undefined || data.length === 0) ? args[0] : args[1]
1584
- }
1585
-
1586
-
1587
-
1588
- ;// ./lib/models/templateCompiler/helpers/_isNotEmpty.js
1589
-
1590
-
1591
-
1592
-
1593
- function _isNotEmpty(data, args) {
1594
- if (args.length !== 2) {
1595
- throw new TemplateCompilerException(`_isNotEmpty: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
999
+ static join(data, separator = '') {
1000
+ return _join(data, separator)
1596
1001
  }
1597
- // if (data === null || (typeof data === 'undefined')) {
1598
- // return null
1599
- // }
1600
- if (args.includes(_SELF)) {
1601
- args = args.map((arg) => {
1602
- return (arg === _SELF) ? data : arg
1603
- })
1002
+ static lt(data, args) {
1003
+ return _lt(data, args)
1604
1004
  }
1605
- if (data !== null && typeof data === 'object' && Object.keys(data).length === 0) {
1606
- return args[1]
1005
+ static lte(data, args) {
1006
+ return _lte(data, args)
1607
1007
  }
1608
- if (Array.isArray(data) && data.length === 0) {
1609
- return args[1]
1008
+ static map(data, args = []) {
1009
+ return _map(data, args)
1610
1010
  }
1611
- if (typeof data === 'string' && data === '') {
1612
- return args[1]
1011
+ static neq(data, args) {
1012
+ return _neq(data, args)
1613
1013
  }
1614
- if (data === null || data === undefined) {
1615
- return args[1]
1014
+ static toLowerCase(data, args) {
1015
+ return _toLowerCase(data, args)
1016
+ }
1017
+ static toUpperCase(data, args) {
1018
+ return _toUpperCase(data, args)
1019
+ }
1020
+ static parseFunction(expression) {
1021
+ return _parseFunction(expression, _FN_NAMES)
1616
1022
  }
1617
- return args[0]
1618
- }
1619
-
1620
1023
 
1621
- ;// ./lib/models/templateCompiler/helpers/_join.js
1622
- function _join(data, delimiter) {
1623
- try {
1624
- if (data.length === 0) return ''
1625
- if (data.length === 1) return _stringifyObject(data[0])
1626
- return data.map((item) => _stringifyObject(item)).join(delimiter)
1627
- } catch (e) {
1628
- throw e
1024
+ pipe(expression = '') {
1025
+ this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
1026
+ const regex = new RegExp(`${this.delimiters[0]}\\s(.*?)\\s${this.delimiters[1]}`)
1027
+ const match = expression.match(regex)
1028
+ if (match !== null) {
1029
+ try {
1030
+ const functionList = _parseFunction(match[1], _FN_NAMES)
1031
+ return functionList.reduce((acc, fn) => {
1032
+ return _callFunction(acc, fn.name, fn.args)
1033
+ }, this.data)
1034
+ } catch (e) {
1035
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${e.message}`)
1036
+ }
1037
+ }
1038
+ throw new TemplateCompilerException(`TemplateCompiler engine error: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.invalidRegExpException}`)
1629
1039
  }
1630
1040
  }
1631
1041
 
1632
- function _stringifyObject(obj) {
1633
- return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1: ').replace(/"([^"]+)"/g, '$1').replace(/,/g, ', ')
1042
+ function _parseFunction(expression, existFunctionNames) {
1043
+ const regExp = new RegExp(/(\w+)\(([^)]*)\)/)
1044
+ let parts
1045
+ if (expression.includes('|')) {
1046
+ parts = expression.split('|')
1047
+ } else {
1048
+ parts = [expression]
1049
+ }
1050
+ return parts.reduce((acc, part) => {
1051
+ const match = part.match(regExp)
1052
+ if (match !== null) {
1053
+ const functionName = match[1]
1054
+ const parameters = match[2]
1055
+ const paramList = _parseParams(parameters)
1056
+ if (existFunctionNames.includes(functionName)) {
1057
+ acc.push({
1058
+ name: functionName,
1059
+ args: paramList
1060
+ })
1061
+ } else {
1062
+ throw new TemplateCompilerException(`${functionName} is not a valid function`)
1063
+ }
1064
+ }
1065
+ return acc
1066
+ }, [])
1634
1067
  }
1635
1068
 
1636
-
1637
-
1638
- ;// ./lib/models/templateCompiler/helpers/_lt.js
1639
-
1640
-
1641
-
1642
-
1643
- function _lt(data, args) {
1644
- if (args.length !== 3) {
1645
- throw new TemplateCompilerException(`_lt: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1646
- }
1647
- if (data === null || (typeof data === 'undefined')) {
1648
- return null
1069
+ function _parseParams(parameters) {
1070
+ const _parameters = parameters.trim()
1071
+ const regExp = new RegExp(/^[^\w\d\s]+$/)
1072
+ const match = _parameters.match(regExp)
1073
+ if (match !== null) {
1074
+ return [_parameters.substring(1, _parameters.length - 1)]
1649
1075
  }
1650
- if (args.includes(_SELF)) {
1651
- args = args.map((arg) => {
1652
- return (arg === _SELF) ? data : arg
1653
- })
1076
+ if (_parameters.includes(',')) {
1077
+ // 用正则表达式匹配逗号,但忽略方括号中的逗号
1078
+ const parts = _splitIgnoringBrackets(_parameters)
1079
+ return parts.map((part) => _parseSinglePart(part))
1654
1080
  }
1655
- const expected = args[0]
1656
- return data < expected ? args[1] : args[2]
1081
+ return [_parseSinglePart(_parameters)]
1657
1082
  }
1658
1083
 
1084
+ function _splitIgnoringBrackets(input) {
1085
+ const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
1086
+ const regExp = new RegExp(/(?![^\[]*\])\s*,\s*/)
1087
+ const parts = input.split(regExp)
1088
+ return parts.map((part) => {
1089
+ const _part = part.trim()
1090
+ if (_part !== '' && !!_part.match(regExp2)) {
1091
+ // 如果是数字,转换为 num 类型
1092
+ return Number.isNaN(_part) ? _part : parseInt(_part, 10)
1093
+ }
1094
+ // 否则当作字符串处理
1095
+ return _part
1096
+ })
1097
+ }
1659
1098
 
1099
+ function _parseSinglePart(input) {
1100
+ if (typeof input === 'string') {
1101
+ if (input.startsWith('"') && input.endsWith('"')) {
1102
+ // 去掉双引号,返回
1103
+ return input.substring(1, input.length - 1)
1104
+ }
1660
1105
 
1661
- ;// ./lib/models/templateCompiler/helpers/_lte.js
1662
-
1106
+ const _input = _toBasicType(input)
1663
1107
 
1108
+ if (typeof _input !== 'string') {
1109
+ return _input
1110
+ }
1664
1111
 
1112
+ // 如果是一个列表形式(例如 ["p", "d"] 或 [p, d])
1113
+ if (_input.startsWith('[') && _input.endsWith(']')) {
1114
+ const listContent = _input.substring(1, _input.length - 1).trim()
1115
+ if (listContent !== '') {
1116
+ return listContent.split(',').map((item) => {
1117
+ return _toBasicType(item.trim())
1118
+ })
1119
+ }
1120
+ return []
1121
+ }
1122
+ return input
1123
+ }
1124
+ return input
1125
+ }
1665
1126
 
1666
- function _lte(data, args) {
1667
- if (args.length !== 3) {
1668
- throw new TemplateCompilerException(`_lte: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1127
+ function _toBasicType(input) {
1128
+ if (input.startsWith('"') && input.endsWith('"')) {
1129
+ // 去掉双引号,返回
1130
+ return input.substring(1, input.length - 1)
1669
1131
  }
1670
- if (data === null || (typeof data === 'undefined')) {
1132
+ if (input === 'true') {
1133
+ return true
1134
+ }
1135
+ if (input === 'false') {
1136
+ return false
1137
+ }
1138
+ if (input === 'undefined') {
1139
+ return undefined
1140
+ }
1141
+ if (input === 'null') {
1671
1142
  return null
1672
1143
  }
1673
- if (args.includes(_SELF)) {
1674
- args = args.map((arg) => {
1675
- return (arg === _SELF) ? data : arg
1676
- })
1144
+ if (!Number.isNaN(input) && !Number.isNaN(Number.parseFloat(input))) {
1145
+ return Number(input)
1677
1146
  }
1678
- const expected = args[0]
1679
- return data <= expected ? args[1] : args[2]
1147
+ return input
1680
1148
  }
1681
1149
 
1682
-
1683
-
1684
- ;// ./lib/models/templateCompiler/helpers/_map.js
1685
-
1686
-
1687
-
1688
- function _map(data, args) {
1150
+ function _callFunction(data, functionName, parameters) {
1689
1151
  try {
1690
- if (args.length === 0) {
1691
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentEmptyException)
1692
- }
1693
- if (data === null || (typeof data === 'undefined')) {
1694
- return null
1695
- }
1696
-
1697
- const result = data.reduce((acc, item) => {
1698
- if (args.length === 1 && Array.isArray(args[0])) {
1699
- args = args[0]
1700
- acc.hasFormat = true
1701
- }
1702
- const list = args.map((key) => {
1703
- if (key.includes('.')) {
1704
- const parts = key.split('.')
1705
- const first = parts[0]
1706
- parts.shift()
1707
- const remainingKey = parts.join('.')
1708
- return _get(item[first], remainingKey)
1152
+ let failover
1153
+ switch (functionName) {
1154
+ case 'exec':
1155
+ return _exec(data, parameters)
1156
+ case 'get':
1157
+ if (parameters.length > 2) {
1158
+ throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
1709
1159
  }
1710
- if (typeof item[key] !== 'undefined') {
1711
- return item[key]
1160
+ if (parameters.length === 2) {
1161
+ failover = parameters[parameters.length - 1]
1712
1162
  }
1713
- return null
1714
- })
1715
- if (acc.hasFormat) {
1716
- acc.content.push(list)
1717
- } else {
1718
- acc.content = acc.content.concat(list)
1719
- }
1720
- return acc
1721
- }, {
1722
- content: [],
1723
- hasFormat: false
1724
- })
1725
- return result.content
1163
+ return _get(data, parameters[0], failover)
1164
+ case 'join':
1165
+ return _join(data, parameters[0])
1166
+ case 'map':
1167
+ return _map(data, parameters)
1168
+ case 'concatIf':
1169
+ return _concatIf(data, parameters)
1170
+ case 'filterOne':
1171
+ return _filterOne(data, parameters)
1172
+ case 'filterAll':
1173
+ return _filterAll(data, parameters)
1174
+ case 'formatDate':
1175
+ return _formatDate(data, parameters)
1176
+ case 'eq':
1177
+ return _eq(data, parameters)
1178
+ case 'neq':
1179
+ return _neq(data, parameters)
1180
+ case 'gt':
1181
+ return _gt(data, parameters)
1182
+ case 'gte':
1183
+ return _gte(data, parameters)
1184
+ case 'lt':
1185
+ return _lt(data, parameters)
1186
+ case 'lte':
1187
+ return _lte(data, parameters)
1188
+ case 'isEmpty':
1189
+ return _isEmpty(data, parameters)
1190
+ case 'isNotEmpty':
1191
+ return _isNotEmpty(data, parameters)
1192
+ case 'toLowerCase':
1193
+ return _toLowerCase(data)
1194
+ case 'toUpperCase':
1195
+ return _toUpperCase(data)
1196
+ default:
1197
+ throw new Error(`${functionName} is not a valid function`)
1198
+ }
1726
1199
  } catch (e) {
1727
1200
  throw e
1728
1201
  }
@@ -1730,343 +1203,952 @@ function _map(data, args) {
1730
1203
 
1731
1204
 
1732
1205
 
1733
- ;// ./lib/models/templateCompiler/helpers/_neq.js
1206
+ ;// ./lib/models/templateCompiler/index.js
1734
1207
 
1735
1208
 
1736
1209
 
1737
1210
 
1738
- function _neq(data, args) {
1739
- if (args.length !== 3) {
1740
- throw new TemplateCompilerException(`_neq: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1741
- }
1742
- if (data === null || (typeof data === 'undefined')) {
1743
- return null
1744
- }
1745
- if (args.includes(_SELF)) {
1746
- args = args.map((arg) => {
1747
- return (arg === _SELF) ? data : arg
1748
- })
1749
- }
1750
- const expected = args[0]
1751
- return data !== expected ? args[1] : args[2]
1752
- }
1211
+ ;// ./lib/helpers/concatStringByArray/concatStringByArray.js
1753
1212
 
1754
1213
 
1755
1214
 
1756
- ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
1757
1215
 
1758
1216
 
1759
- function _toLowerCase(data, args) {
1760
- if (args !== undefined) {
1761
- throw new TemplateCompilerException(`_toLowerCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: ${args.join(', ')}`)
1762
- }
1763
- if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
1764
- return null
1765
- }
1766
- return String(data).toLowerCase()
1217
+ function concatStringByArray(arrTemplate, data) {
1218
+ return arrTemplate.reduce((acc, item) => {
1219
+ const { type, value = '', restriction, template, format, showMinutes } = item
1220
+ switch (type) {
1221
+ case('label'): {
1222
+ if (getValidation(restriction, data, getValueByKeys)) {
1223
+ acc += (value.toString())
1224
+ }
1225
+ break
1226
+ }
1227
+ case('value'): {
1228
+ if (getValidation(restriction, data, getValueByKeys)) {
1229
+ const _value = getValueByKeys(value.split('.'), data) || ''
1230
+ acc += (_value.toString())
1231
+ }
1232
+ break
1233
+ }
1234
+ case('array'): {
1235
+ if (getValidation(restriction, data, getValueByKeys)) {
1236
+ const _value = getValueByKeys(value.split('.'), data) || []
1237
+ acc += _value.reduce((_acc, item) => {
1238
+ return _acc += concatStringByArray(template, item)
1239
+ }, '')
1240
+ }
1241
+ break
1242
+ }
1243
+ case('ellipsis'): {
1244
+ if (getValidation(restriction, data, getValueByKeys)) {
1245
+ const { maxLength } = item
1246
+ const _value = getValueByKeys(value.split('.'), data) || ''
1247
+ if (_value.length <= maxLength) {
1248
+ acc += (_value.toString())
1249
+ } else {
1250
+ acc += `${_value.substr(0, maxLength)}...`
1251
+ }
1252
+ }
1253
+ break
1254
+ }
1255
+ case ('date'): {
1256
+ if (getValidation(restriction, data, getValueByKeys)) {
1257
+ const _value = getValueByKeys(value.split('.'), data) || ''
1258
+ acc += (formatDate(_value, format).toString())
1259
+ }
1260
+ break
1261
+ }
1262
+ case ('templateCompiler'): {
1263
+ if (getValidation(restriction, data, getValueByKeys)) {
1264
+ const templateCompiler = new TemplateCompiler({ data })
1265
+ acc += templateCompiler.pipe(value)
1266
+ }
1267
+ break
1268
+ }
1269
+ }
1270
+ return acc
1271
+ }, '')
1767
1272
  }
1273
+ /* harmony default export */ const concatStringByArray_concatStringByArray = ({
1274
+ concatStringByArray
1275
+ });
1768
1276
 
1769
1277
 
1770
1278
 
1771
- ;// ./lib/models/templateCompiler/helpers/_toUpperCase.js
1279
+ ;// ./lib/helpers/concatStringByArray/index.js
1772
1280
 
1773
1281
 
1774
- function _toUpperCase(data, args) {
1775
- if (typeof data !== 'string') {
1776
- throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the data must be string: ${data}`)
1777
- }
1778
- if (args !== undefined) {
1779
- throw new TemplateCompilerException(`_toUpperCase: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: the argument must be empty: ${args.join(', ')}`)
1780
- }
1781
- if (data === null || (typeof data === 'undefined') || typeof data !== 'string') {
1782
- return null
1282
+ ;// ./lib/helpers/convertString/convertString.js
1283
+ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByKeys) {
1284
+ if (!string || typeof getValueByKeys !== 'function') {
1285
+ return ''
1783
1286
  }
1784
- return String(data).toUpperCase()
1287
+ const reg = new RegExp(patternMatch, 'g')
1288
+ return string.replace(reg, (match, key) => {
1289
+ const result = getValueByKeys({ keys: key.split('.'), obj: value })
1290
+ if (result === null || result === undefined) {
1291
+ return ''
1292
+ }
1293
+ return typeof result === 'object' ? JSON.stringify(result) : result
1294
+ })
1785
1295
  }
1786
1296
 
1297
+ /* harmony default export */ const convertString_convertString = ({
1298
+ convertString
1299
+ });
1787
1300
 
1788
1301
 
1789
- ;// ./lib/models/templateCompiler/helpers/index.js
1790
-
1791
-
1792
-
1793
-
1794
-
1795
-
1796
-
1797
-
1798
-
1799
-
1800
-
1801
-
1802
-
1803
-
1804
-
1805
-
1806
-
1807
-
1808
-
1809
-
1810
-
1811
- ;// ./lib/models/templateCompiler/templateCompiler.js
1812
-
1813
-
1814
-
1815
-
1816
- class TemplateCompiler {
1817
- constructor(data) {
1818
- this.data = data
1819
- }
1820
- static init(options) {
1821
- return new this(options)
1822
- }
1823
- static initFromArray(arr = []) {
1824
- if (Array.isArray(arr)) {
1825
- return arr.map((a) => this.init(a))
1826
- }
1827
- return []
1828
- }
1829
- static initOnlyValidFromArray(arr = []) {
1830
- return this.initFromArray(arr).filter((i) => i)
1831
- }
1832
- static concatIf(data, args) {
1833
- return _concatIf(data, args)
1834
- }
1835
- static eq(data, args) {
1836
- return _eq(data, args)
1837
- }
1302
+ ;// ./lib/helpers/convertString/index.js
1838
1303
 
1839
- static filterAll(data, args) {
1840
- return _filterAll(data, args)
1841
- }
1842
1304
 
1843
- static formatDate(data, args) {
1844
- return _formatDate(data, args)
1305
+ ;// ./lib/helpers/objectHelper/objectHelper.js
1306
+ const objectHelper = {
1307
+ get(obj, path) {
1308
+ const parts = path.split('.')
1309
+ return parts.reduce((acc, part) => {
1310
+ if (part.endsWith('[]')) {
1311
+ // 处理数组遍历
1312
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
1313
+ if (Array.isArray(acc[key])) {
1314
+ return acc[key] // 返回整个数组
1315
+ }
1316
+ return [] // 如果不是数组,返回空数组
1317
+ }
1318
+ if (part.includes('[') && part.includes(']')) {
1319
+ // 处理数组索引
1320
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
1321
+ if (arrayMatch) {
1322
+ const key = arrayMatch[1]
1323
+ const index = arrayMatch[2]
1324
+ return acc && acc[key] && acc[key][index]
1325
+ }
1326
+ } else if (acc && Array.isArray(acc)) {
1327
+ // 如果当前值是数组,提取每个对象的指定属性
1328
+ return acc.map((item) => item[part])
1329
+ } else {
1330
+ // 处理普通属性
1331
+ return acc && acc[part]
1332
+ }
1333
+ }, obj)
1334
+ },
1335
+ merge,
1336
+ set(obj, path, value) {
1337
+ const parts = path.split('.')
1338
+ let current = obj
1339
+ for (let i = 0; i < parts.length - 1; i++) {
1340
+ const part = parts[i]
1341
+ if (part.endsWith('[]')) {
1342
+ // 处理数组遍历
1343
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
1344
+ if (Array.isArray(current[key])) {
1345
+ current[key].forEach((item) => set(item, parts.slice(i + 1).join('.'), value))
1346
+ }
1347
+ return // 处理完数组后直接返回
1348
+ }
1349
+ if (part.includes('[') && part.includes(']')) {
1350
+ // 处理数组索引
1351
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
1352
+ if (arrayMatch) {
1353
+ const key = arrayMatch[1]
1354
+ const index = arrayMatch[2]
1355
+ if (Array.isArray(current[key]) && current[key][index]) {
1356
+ current = current[key][index]
1357
+ } else {
1358
+ return // 如果数组或索引不存在,直接返回
1359
+ }
1360
+ }
1361
+ } else {
1362
+ // 处理普通属性
1363
+ if (!current[part]) {
1364
+ current[part] = {} // 如果属性不存在,创建一个空对象
1365
+ }
1366
+ current = current[part]
1367
+ }
1368
+ }
1369
+
1370
+ // 设置最终属性值
1371
+ const lastPart = parts[parts.length - 1]
1372
+ current[lastPart] = value
1373
+ }
1374
+ }
1375
+
1376
+ function merge(target, ...sources) {
1377
+ if (!sources.length) return target
1378
+
1379
+ const source = sources.shift() // 取出第一个源对象
1380
+
1381
+ if (_isObject(target) && _isObject(source)) {
1382
+ for (const key in source) {
1383
+ if (_isObject(source[key])) {
1384
+ if (!target[key]) {
1385
+ // 如果目标对象没有该属性,创建一个空对象
1386
+ target[key] = {}
1387
+ }
1388
+ // 递归合并
1389
+ merge(target[key], source[key])
1390
+ } else {
1391
+ // 直接覆盖
1392
+ target[key] = source[key]
1393
+ }
1394
+ }
1395
+ }
1396
+
1397
+ // 继续合并剩余的源对象
1398
+ return merge(target, ...sources)
1399
+ }
1400
+
1401
+ function _isObject(obj) {
1402
+ return obj && typeof obj === 'object' && !Array.isArray(obj)
1403
+ }
1404
+
1405
+
1406
+
1407
+ ;// ./lib/helpers/objectHelper/index.js
1408
+
1409
+
1410
+
1411
+
1412
+ ;// ./lib/helpers/pReduce/pReduce.js
1413
+ async function pReduce(iterable, reducer, initialValue) {
1414
+ return new Promise((resolve, reject) => {
1415
+ const iterator = iterable[Symbol.iterator]()
1416
+ let index = 0
1417
+
1418
+ const next = async total => {
1419
+ const element = iterator.next()
1420
+
1421
+ if (element.done) {
1422
+ resolve(total)
1423
+ return
1424
+ }
1425
+
1426
+ try {
1427
+ const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
1428
+ next(reducer(resolvedTotal, resolvedValue, index++))
1429
+ } catch (error) {
1430
+ reject(error)
1431
+ }
1432
+ }
1433
+
1434
+ next(initialValue)
1435
+ })
1436
+ }
1437
+
1438
+
1439
+
1440
+ ;// ./lib/models/apiResponse/apiResponse.js
1441
+ class ApiResponse {
1442
+ constructor(options = {}) {
1443
+ options = options || {}
1444
+ this._data = options.data || options._data || []
1445
+ this.err = options.err
1446
+ this.isNew = options.isNew || false
1447
+ this.message = options.message
1448
+ this.total = options.total || 0
1449
+ this._instanceBuilder = options._instanceBuilder
1450
+ }
1451
+
1452
+ static init(options = {}) {
1453
+ if (options instanceof this) {
1454
+ return options
1455
+ }
1456
+ const instance = new this(options)
1457
+ return instance
1458
+ }
1459
+ static get _classname() {
1460
+ return 'ApiResponse'
1461
+ }
1462
+ static get _superclass() {
1463
+ return 'ApiResponse'
1464
+ }
1465
+
1466
+ // getters
1467
+ get data() {
1468
+ if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
1469
+ return this._data.map(this._instanceBuilder)
1470
+ }
1471
+ return this._data
1472
+ }
1473
+ }
1474
+
1475
+
1476
+
1477
+ ;// ./lib/models/apiResponse/makeApiResponse.js
1478
+
1479
+
1480
+ function makeApiResponse({ repo, result }) {
1481
+ return ApiResponse.init({
1482
+ ...result,
1483
+ _instanceBuilder: (i) => {
1484
+ return repo.init(i)
1485
+ }
1486
+ })
1487
+ }
1488
+
1489
+
1490
+
1491
+ ;// ./lib/models/apiResponse/index.js
1492
+
1493
+
1494
+
1495
+
1496
+
1497
+ ;// ./lib/models/keyValueObject/keyValueObject.js
1498
+ class KeyValueObject {
1499
+ constructor(options = {}) {
1500
+ options = options || {}
1501
+ this.key = options.key || null
1502
+ this.value = (typeof options.value !== 'undefined') ? options.value : ''
1503
+ }
1504
+
1505
+ // Class methods
1506
+ static init(options = {}) {
1507
+ if (options instanceof this) {
1508
+ return options
1509
+ }
1510
+ const instance = new this(options)
1511
+ return instance.isValid ? instance : null
1512
+ }
1513
+ static initFromArray(arr = []) {
1514
+ if (Array.isArray(arr)) {
1515
+ return arr.map((a) => this.init(a))
1516
+ }
1517
+ return []
1518
+ }
1519
+ static initOnlyValidFromArray(arr = []) {
1520
+ return this.initFromArray(arr).filter((i) => i)
1521
+ }
1522
+ static get _classname() {
1523
+ return 'KeyValueObject'
1524
+ }
1525
+ static get _superclass() {
1526
+ return 'KeyValueObject'
1527
+ }
1528
+
1529
+ static addItem(arr, key, value) {
1530
+ arr.push(this.init({ key, value }))
1531
+ }
1532
+ static addRecord(arr = [], key, value) {
1533
+ if (!this.hasKeyValue(arr, key, value)) {
1534
+ arr.push(this.init({ key, value }))
1535
+ }
1536
+ return arr
1537
+ }
1538
+ static appendRecord(arr = [], key, value) {
1539
+ return arr.map((item) => {
1540
+ if (this.sameKey(item, key)) {
1541
+ item.value = [...item.value, ...value]
1542
+ }
1543
+ return item
1544
+ })
1545
+ }
1546
+ static appendValueArray(arr = [], key, value) {
1547
+ return arr.map((item) => {
1548
+ if (this.sameKey(item, key)) {
1549
+ item.value = [...item.value, ...value]
1550
+ }
1551
+ return item
1552
+ })
1553
+ }
1554
+ static foundByKey(arr = [], key) {
1555
+ const found = arr.find((m) => {
1556
+ return this.sameKey(m, key)
1557
+ })
1558
+ return found || null
1559
+ }
1560
+ static foundValueByKey(arr = [], key) {
1561
+ const found = this.foundByKey(arr, key)
1562
+ return found ? found.value : null
1563
+ }
1564
+ static fromObject(options = {}) {
1565
+ return Object.keys(options).reduce((acc, key) => {
1566
+ acc.push(this.init({ key, value: options[key] }))
1567
+ return acc
1568
+ }, [])
1569
+ }
1570
+ static getValueByKey(arr = [], key) {
1571
+ return this.foundValueByKey(arr, key)
1572
+ }
1573
+ static getValueByKeyFromArray(arr = [], key) {
1574
+ if (arr.length === 0) {
1575
+ return null
1576
+ }
1577
+ const firstArr = arr.shift()
1578
+ const found = firstArr.find((i) => {
1579
+ return this.sameKey(i, key)
1580
+ })
1581
+ if (found && found.value) {
1582
+ return found.value
1583
+ }
1584
+ return this.getValueByKeyFromArray(arr, key)
1585
+ }
1586
+ static getValuesByKey(arr = [], key) {
1587
+ return arr.reduce((acc, item) => {
1588
+ if (this.sameKey(item, key)) {
1589
+ acc.push(item.value)
1590
+ }
1591
+ return acc
1592
+ }, [])
1593
+ }
1594
+ static hasKeyValue(arr = [], key, value) {
1595
+ if (typeof value === 'undefined') {
1596
+ return arr.filter((item) => this.sameKey(item, key)).length > 0
1597
+ }
1598
+ return arr.filter((item) => (this.sameKey(item, key) && _isSame(item.value, value))).length > 0
1599
+ }
1600
+ static insertOrUpdateRecord(arr = [], key, value) {
1601
+ let copy = [...arr]
1602
+ if (!this.hasKeyValue(arr, key)) {
1603
+ copy.push(this.init({ key, value }))
1604
+ } else {
1605
+ copy = this.updateRecord(arr, key, value)
1606
+ }
1607
+ return copy
1608
+ }
1609
+ static keys(arr = []) {
1610
+ if (Array.isArray(arr)) {
1611
+ return arr.reduce((acc, item) => {
1612
+ acc.push(item.key)
1613
+ return acc
1614
+ }, [])
1615
+ }
1616
+ return []
1617
+ }
1618
+ static merge(toArr, fromArr) {
1619
+ (fromArr || []).map((from) => {
1620
+ const found = toArr.find((to) => {
1621
+ return to.key === from.key
1622
+ })
1623
+ if (found) {
1624
+ found.value = (found.value || []).concat(from.value)
1625
+ } else {
1626
+ toArr.push(from)
1627
+ }
1628
+ })
1629
+ return toArr
1630
+ }
1631
+ static removeByKey(arr, key) {
1632
+ return arr.reduce((acc, item) => {
1633
+ if (!this.sameKey(item, key)) {
1634
+ acc.push(item)
1635
+ }
1636
+ return acc
1637
+ }, [])
1638
+ }
1639
+ static sameKey(item, key) {
1640
+ return _isSame(item.key, key)
1641
+ }
1642
+ static toObject(arr = []) {
1643
+ if (Array.isArray(arr)) {
1644
+ return arr.reduce((acc, item) => {
1645
+ acc[item.key] = item.value
1646
+ return acc
1647
+ }, {})
1648
+ }
1649
+ return {}
1650
+ }
1651
+ static toString(arr = [], delimiter = '; ') {
1652
+ if (Array.isArray(arr)) {
1653
+ return arr.reduce((acc, item) => {
1654
+ acc.push(`${item.key}: ${item.value}`)
1655
+ return acc
1656
+ }, []).join(delimiter)
1657
+ }
1658
+ return ''
1659
+ }
1660
+ static updateRecord(arr = [], key, value) {
1661
+ return arr.map((item) => {
1662
+ if (this.sameKey(item, key)) {
1663
+ return {
1664
+ ...item,
1665
+ value
1666
+ }
1667
+ }
1668
+ return item
1669
+ })
1670
+ }
1671
+ static updateOrInsertRecord(arr = [], key, value) {
1672
+ return this.insertOrUpdateRecord(arr, key, value)
1673
+ }
1674
+ static updateRecordsFromArray(arr = [], updateArr = []) {
1675
+ if (Array.isArray(arr) && Array.isArray(updateArr)) {
1676
+ const obj1 = this.toObject(arr)
1677
+ const obj2 = this.toObject(updateArr)
1678
+ return this.fromObject({
1679
+ ...obj1,
1680
+ ...obj2
1681
+ })
1682
+ }
1683
+ return []
1684
+ }
1685
+ static values(arr = []) {
1686
+ if (Array.isArray(arr)) {
1687
+ return arr.reduce((acc, item) => {
1688
+ acc.push(item.value)
1689
+ return acc
1690
+ }, [])
1691
+ }
1692
+ return []
1693
+ }
1694
+
1695
+ // getters
1696
+ get isValid() {
1697
+ return !!this.key
1698
+ }
1699
+
1700
+ get toObject() {
1701
+ const obj = {}
1702
+ if (this.isValid) {
1703
+ obj[this.key] = this.value
1704
+ }
1705
+ return obj
1706
+ }
1707
+ }
1708
+
1709
+ function _isSame(key1, key2) {
1710
+ return key1 === key2
1711
+ }
1712
+
1713
+
1714
+
1715
+ ;// ./lib/models/keyValueObject/index.js
1716
+
1717
+
1718
+
1719
+
1720
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
1721
+ function stringFormatter(str, delimiter = '_') {
1722
+ if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
1723
+ return null
1724
+ }
1725
+ return str.toString()
1726
+ .trim()
1727
+ .toUpperCase()
1728
+ .replace('-', delimiter)
1729
+ .replace(' ', delimiter)
1730
+ }
1731
+
1732
+
1733
+
1734
+ ;// ./lib/models/metadata/metadata.js
1735
+
1736
+
1737
+
1738
+ const DELIMITER = '_'
1739
+
1740
+ class Metadata extends KeyValueObject {
1741
+ static init(options = {}) {
1742
+ if (options instanceof this) {
1743
+ return options
1744
+ }
1745
+ const instance = new this({
1746
+ ...options,
1747
+ key: stringFormatter(options.key, DELIMITER),
1748
+ })
1749
+ return instance.isValid ? instance : null
1750
+ }
1751
+ static get _classname() {
1752
+ return 'Metadata'
1753
+ }
1754
+
1755
+ static merge(toArr, fromArr) {
1756
+ (fromArr || []).map((from) => {
1757
+ const found = toArr.find((to) => {
1758
+ return metadata_isSame(to.key, from.key)
1759
+ })
1760
+ if (found) {
1761
+ found.value = (found.value || []).concat(from.value)
1762
+ } else {
1763
+ toArr.push(from)
1764
+ }
1765
+ })
1766
+ return toArr
1767
+ }
1768
+ static sameKey(item, key) {
1769
+ return metadata_isSame(item.key, key)
1770
+ }
1771
+ }
1772
+
1773
+ function metadata_isSame(key1, key2) {
1774
+ return stringFormatter(key1, DELIMITER) === stringFormatter(key2, DELIMITER)
1775
+ }
1776
+
1777
+
1778
+
1779
+ ;// ./lib/models/metadata/index.js
1780
+
1781
+
1782
+
1783
+
1784
+ ;// ./lib/models/qMeta/qMeta.js
1785
+
1786
+
1787
+ const updateAllowedProps = [
1788
+ 'attributes',
1789
+ 'ref'
1790
+ ]
1791
+
1792
+ class QMeta {
1793
+ constructor(options = {}) {
1794
+ options = options || {}
1795
+ this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
1796
+ this.ref = options.ref || {}
1845
1797
  }
1846
-
1847
- static get(data, key, failover = null) {
1848
- return _get(data, key, failover)
1798
+
1799
+ static get _classname() {
1800
+ return 'QMeta'
1849
1801
  }
1850
- static gt(data, args) {
1851
- return _gt(data, args)
1802
+ static get _superclass() {
1803
+ return 'QMeta'
1852
1804
  }
1853
- static gte(data, args) {
1854
- return _gte(data, args)
1805
+
1806
+ // Class methods
1807
+ static init(options = {}) {
1808
+ if (options instanceof QMeta) {
1809
+ return options
1810
+ }
1811
+ return new QMeta(options)
1855
1812
  }
1856
- static isEmpty(data, args) {
1857
- return _isEmpty(data, args)
1813
+
1814
+ // instance methods
1815
+ addAttribute(obj) {
1816
+ const kvObject = KeyValueObject.init(obj)
1817
+ if (!kvObject) {
1818
+ throw new Error('invalid meta attribute')
1819
+ }
1820
+ this.attributes.push(kvObject)
1821
+ return this
1858
1822
  }
1859
- static isNotEmpty(data, args) {
1860
- return _isNotEmpty(data, args)
1823
+
1824
+ update(obj) {
1825
+ Object.keys(obj).forEach((key) => {
1826
+ if (updateAllowedProps.includes(key)) {
1827
+ if (key === 'attributes') {
1828
+ this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
1829
+ } else {
1830
+ this[key] = obj[key]
1831
+ }
1832
+ }
1833
+ })
1834
+ return this
1861
1835
  }
1862
- static join(data, separator = '') {
1863
- return _join(data, separator)
1836
+ }
1837
+
1838
+
1839
+
1840
+ ;// ./lib/models/qMeta/index.js
1841
+
1842
+
1843
+
1844
+
1845
+ ;// ./lib/models/repo/repo.js
1846
+ class Repo {
1847
+ constructor(options) {
1848
+ options = options || {}
1849
+ this.model = options.model
1850
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1851
+ this._queryOptions = options._queryOptions
1852
+ this._saveOptions = options._saveOptions
1853
+ this._Class = options._constructor && options._constructor._Class
1854
+ ? options._constructor._Class
1855
+ : null
1864
1856
  }
1865
- static lt(data, args) {
1866
- return _lt(data, args)
1857
+ static init(options = {}) {
1858
+ if (options instanceof this) {
1859
+ return options
1860
+ }
1861
+ const instance = new this(options)
1862
+ return instance.isValid ? instance : null
1867
1863
  }
1868
- static lte(data, args) {
1869
- return _lte(data, args)
1864
+ static get _classname() {
1865
+ return 'Repo'
1870
1866
  }
1871
- static map(data, args = []) {
1872
- return _map(data, args)
1867
+ static get _superclass() {
1868
+ return 'Repo'
1873
1869
  }
1874
- static neq(data, args) {
1875
- return _neq(data, args)
1870
+
1871
+ get _classname() {
1872
+ return 'Repo'
1876
1873
  }
1877
- static toLowerCase(data, args) {
1878
- return _toLowerCase(data, args)
1874
+
1875
+ get _superclass() {
1876
+ return 'Repo'
1879
1877
  }
1880
- static toUpperCase(data, args) {
1881
- return _toUpperCase(data, args)
1878
+
1879
+ get isValid() {
1880
+ return this.model
1881
+ && (typeof this.model.deleteOne === 'function')
1882
+ && (typeof this.model.findAll === 'function')
1883
+ && (typeof this.model.saveOne === 'function')
1882
1884
  }
1883
- static parseFunction(expression) {
1884
- return _parseFunction(expression, _FN_NAMES)
1885
+
1886
+ get queryOptions() {
1887
+ return {
1888
+ ...this._sharedOptions,
1889
+ ...this._queryOptions,
1890
+ }
1891
+ }
1892
+
1893
+ get saveOptions() {
1894
+ return {
1895
+ ...this._sharedOptions,
1896
+ ...this._saveOptions,
1897
+ }
1898
+ }
1899
+
1900
+ init(options) {
1901
+ if (this._Class && typeof this._Class.init === 'function') {
1902
+ return this._Class.init(options)
1903
+ }
1904
+ return options
1905
+ }
1906
+
1907
+ async deleteOne({ id }) {
1908
+ try {
1909
+ const result = await this.model.deleteOne({ _id: id })
1910
+ return {
1911
+ ...result, // { message: 'ok', total }
1912
+ isNew: false,
1913
+ data: []
1914
+ }
1915
+ } catch (err) {
1916
+ throw err
1917
+ }
1918
+ }
1919
+
1920
+ // systemLog is optional
1921
+ findAll({ query, systemLog }) {
1922
+ const log = _makeLog({
1923
+ systemLog,
1924
+ label: 'REPO_READ',
1925
+ message: `fn ${this._classname}.prototype.findAll`,
1926
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1927
+ })
1928
+ return new Promise((resolve, reject) => {
1929
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
1930
+ if (err) {
1931
+ log({ level: 'warn', output: err.toString() })
1932
+ reject(err)
1933
+ } else {
1934
+ const result = {
1935
+ isNew: false,
1936
+ data,
1937
+ total: total || data.length
1938
+ }
1939
+ log({ level: 'info', output: { ...result } })
1940
+ resolve(result)
1941
+ }
1942
+ })
1943
+ })
1944
+ }
1945
+
1946
+ findOne({ query, systemLog }) {
1947
+ const log = _makeLog({
1948
+ systemLog,
1949
+ label: 'REPO_READ',
1950
+ message: `fn ${this._classname}.prototype.findOne`,
1951
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1952
+ })
1953
+ return new Promise((resolve, reject) => {
1954
+ this.model.findAll(query, this.queryOptions, (err, data) => {
1955
+ if (err) {
1956
+ reject(err)
1957
+ } else if (data.length === 1) {
1958
+ const result = {
1959
+ isNew: false,
1960
+ data,
1961
+ total: 1
1962
+ }
1963
+ log({ level: 'info', output: { ...result } })
1964
+ resolve(result)
1965
+ } else if (data.length === 0) {
1966
+ reject(new Error('record not found'))
1967
+ } else {
1968
+ reject(new Error('more than one is found'))
1969
+ }
1970
+ })
1971
+ })
1972
+ .catch((err) => {
1973
+ log({ level: 'warn', output: err.toString() })
1974
+ throw err
1975
+ })
1976
+ }
1977
+
1978
+ saveAll({ docs, systemLog }) {
1979
+ let isNew
1980
+ const log = _makeLog({
1981
+ systemLog,
1982
+ label: 'REPO_WRITE',
1983
+ message: `fn ${this._classname}.prototype.saveAll`,
1984
+ input: [{ docs: [...docs], systemLog: { ...systemLog } }]
1985
+ })
1986
+ const promise = typeof this.model.saveAll === 'function'
1987
+ ? this.model.saveAll({ docs })
1988
+ : Promise.all(docs.map(async (doc) => {
1989
+ if (doc) {
1990
+ const result = await this.saveOne({ doc })
1991
+ isNew = result.isNew
1992
+ const _data = result._data || result.data
1993
+ return _data[0]
1994
+ }
1995
+ return null
1996
+ }))
1997
+ return promise.then((savedData) => {
1998
+ if (savedData.length !== 1) isNew = null
1999
+ const result = {
2000
+ data: savedData,
2001
+ isNew,
2002
+ total: savedData.length
2003
+ }
2004
+ log({ level: 'info', output: { ...result } })
2005
+ return result
2006
+ }).catch((err) => {
2007
+ log({ level: 'warn', output: err.toString() })
2008
+ throw err
2009
+ })
2010
+ }
2011
+
2012
+ saveOne({ doc, systemLog }) {
2013
+ const log = _makeLog({
2014
+ systemLog,
2015
+ label: 'REPO_WRITE',
2016
+ message: `fn ${this._classname}.prototype.saveOne`,
2017
+ input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
2018
+ })
2019
+ return new Promise((resolve, reject) => {
2020
+ this.model.saveOne(doc, this.saveOptions, (err, result) => {
2021
+ if (err) {
2022
+ log({ level: 'warn', output: err.toString() })
2023
+ reject(err)
2024
+ } else {
2025
+ log({ level: 'info', output: { ...result } })
2026
+ resolve(result)
2027
+ }
2028
+ })
2029
+ })
1885
2030
  }
2031
+ }
1886
2032
 
1887
- pipe(expression = '') {
1888
- this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
1889
- const regex = new RegExp(`${this.delimiters[0]}\\s(.*?)\\s${this.delimiters[1]}`)
1890
- const match = expression.match(regex)
1891
- if (match !== null) {
1892
- try {
1893
- const functionList = _parseFunction(match[1], _FN_NAMES)
1894
- return functionList.reduce((acc, fn) => {
1895
- return _callFunction(acc, fn.name, fn.args)
1896
- }, this.data)
1897
- } catch (e) {
1898
- throw new TemplateCompilerException(`TemplateCompiler engine error: ${e.message}`)
1899
- }
2033
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
2034
+ return ({ level, messgae: massage2, output } = {}) => {
2035
+ if (systemLog && systemLog.systemLogHelper) {
2036
+ systemLog.systemLogHelper.log({
2037
+ batchId: systemLog.batchId,
2038
+ label,
2039
+ level,
2040
+ message: massage2 || message1,
2041
+ data: {
2042
+ payload: {
2043
+ input,
2044
+ output
2045
+ }
2046
+ }
2047
+ })
1900
2048
  }
1901
- throw new TemplateCompilerException(`TemplateCompiler engine error: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.invalidRegExpException}`)
1902
2049
  }
1903
2050
  }
1904
2051
 
1905
- function _parseFunction(expression, existFunctionNames) {
1906
- const regExp = new RegExp(/(\w+)\(([^)]*)\)/)
1907
- let parts
1908
- if (expression.includes('|')) {
1909
- parts = expression.split('|')
1910
- } else {
1911
- parts = [expression]
1912
- }
1913
- return parts.reduce((acc, part) => {
1914
- const match = part.match(regExp)
1915
- if (match !== null) {
1916
- const functionName = match[1]
1917
- const parameters = match[2]
1918
- const paramList = _parseParams(parameters)
1919
- if (existFunctionNames.includes(functionName)) {
1920
- acc.push({
1921
- name: functionName,
1922
- args: paramList
1923
- })
1924
- } else {
1925
- throw new TemplateCompilerException(`${functionName} is not a valid function`)
1926
- }
1927
- }
1928
- return acc
1929
- }, [])
1930
- }
1931
2052
 
1932
- function _parseParams(parameters) {
1933
- const _parameters = parameters.trim()
1934
- const regExp = new RegExp(/^[^\w\d\s]+$/)
1935
- const match = _parameters.match(regExp)
1936
- if (match !== null) {
1937
- return [_parameters.substring(1, _parameters.length - 1)]
1938
- }
1939
- if (_parameters.includes(',')) {
1940
- // 用正则表达式匹配逗号,但忽略方括号中的逗号
1941
- const parts = _splitIgnoringBrackets(_parameters)
1942
- return parts.map((part) => _parseSinglePart(part))
1943
- }
1944
- return [_parseSinglePart(_parameters)]
1945
- }
1946
2053
 
1947
- function _splitIgnoringBrackets(input) {
1948
- const regExp2 = new RegExp(/^\d+(\.\d+)?$/)
1949
- const regExp = new RegExp(/(?![^\[]*\])\s*,\s*/)
1950
- const parts = input.split(regExp)
1951
- return parts.map((part) => {
1952
- const _part = part.trim()
1953
- if (_part !== '' && !!_part.match(regExp2)) {
1954
- // 如果是数字,转换为 num 类型
1955
- return Number.isNaN(_part) ? _part : parseInt(_part, 10)
1956
- }
1957
- // 否则当作字符串处理
1958
- return _part
1959
- })
1960
- }
2054
+ ;// ./lib/models/repo/index.js
1961
2055
 
1962
- function _parseSinglePart(input) {
1963
- if (typeof input === 'string') {
1964
- if (input.startsWith('"') && input.endsWith('"')) {
1965
- // 去掉双引号,返回
1966
- return input.substring(1, input.length - 1)
1967
- }
1968
2056
 
1969
- const _input = _toBasicType(input)
1970
2057
 
1971
- if (typeof _input !== 'string') {
1972
- return _input
1973
- }
1974
2058
 
1975
- // 如果是一个列表形式(例如 ["p", "d"] 或 [p, d])
1976
- if (_input.startsWith('[') && _input.endsWith(']')) {
1977
- const listContent = _input.substring(1, _input.length - 1).trim()
1978
- if (listContent !== '') {
1979
- return listContent.split(',').map((item) => {
1980
- return _toBasicType(item.trim())
1981
- })
1982
- }
1983
- return []
1984
- }
1985
- return input
2059
+ ;// ./lib/models/service/service.js
2060
+
2061
+
2062
+
2063
+ class Service {
2064
+ constructor({ repo }) {
2065
+ this.repo = repo
1986
2066
  }
1987
- return input
1988
- }
1989
2067
 
1990
- function _toBasicType(input) {
1991
- if (input.startsWith('"') && input.endsWith('"')) {
1992
- // 去掉双引号,返回
1993
- return input.substring(1, input.length - 1)
2068
+ static get _classname() {
2069
+ return 'Service'
1994
2070
  }
1995
- if (input === 'true') {
1996
- return true
2071
+ static get _superclass() {
2072
+ return 'Service'
1997
2073
  }
1998
- if (input === 'false') {
1999
- return false
2074
+
2075
+ deleteOne({ id }) {
2076
+ return this.repo.deleteOne({ id })
2077
+ .catch(() => {
2078
+ throw new Error(`Not found for query: ${id}`)
2079
+ })
2000
2080
  }
2001
- if (input === 'undefined') {
2002
- return undefined
2081
+
2082
+ async findAll({ query = {}, systemLog } = {}) {
2083
+ const result = await this.repo.findAll({ query, systemLog })
2084
+ return makeApiResponse({
2085
+ repo: this.repo,
2086
+ result
2087
+ })
2003
2088
  }
2004
- if (input === 'null') {
2005
- return null
2089
+
2090
+ async findOne({ query = {}, systemLog } = {}) {
2091
+ const result = await this.repo.findOne({ query, systemLog })
2092
+ return makeApiResponse({
2093
+ repo: this.repo,
2094
+ result
2095
+ })
2006
2096
  }
2007
- if (!Number.isNaN(input) && !Number.isNaN(Number.parseFloat(input))) {
2008
- return Number(input)
2097
+
2098
+ init(options) {
2099
+ return this.repo.init(options)
2100
+ }
2101
+ initFromArray(arr = []) {
2102
+ if (Array.isArray(arr)) {
2103
+ return arr.map((a) => this.init(a))
2104
+ }
2105
+ return []
2106
+ }
2107
+ initOnlyValidFromArray(arr = []) {
2108
+ return this.initFromArray(arr).filter((i) => i)
2009
2109
  }
2010
- return input
2011
- }
2012
2110
 
2013
- function _callFunction(data, functionName, parameters) {
2014
- try {
2015
- let failover
2016
- switch (functionName) {
2017
- case 'exec':
2018
- return _exec(data, parameters)
2019
- case 'get':
2020
- if (parameters.length > 2) {
2021
- throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
2022
- }
2023
- if (parameters.length === 2) {
2024
- failover = parameters[parameters.length - 1]
2025
- }
2026
- return _get(data, parameters[0], failover)
2027
- case 'join':
2028
- return _join(data, parameters[0])
2029
- case 'map':
2030
- return _map(data, parameters)
2031
- case 'concatIf':
2032
- return _concatIf(data, parameters)
2033
- case 'filterOne':
2034
- return _filterOne(data, parameters)
2035
- case 'filterAll':
2036
- return _filterAll(data, parameters)
2037
- case 'formatDate':
2038
- return _formatDate(data, parameters)
2039
- case 'eq':
2040
- return _eq(data, parameters)
2041
- case 'neq':
2042
- return _neq(data, parameters)
2043
- case 'gt':
2044
- return _gt(data, parameters)
2045
- case 'gte':
2046
- return _gte(data, parameters)
2047
- case 'lt':
2048
- return _lt(data, parameters)
2049
- case 'lte':
2050
- return _lte(data, parameters)
2051
- case 'isEmpty':
2052
- return _isEmpty(data, parameters)
2053
- case 'isNotEmpty':
2054
- return _isNotEmpty(data, parameters)
2055
- case 'toLowerCase':
2056
- return _toLowerCase(data)
2057
- case 'toUpperCase':
2058
- return _toUpperCase(data)
2059
- default:
2060
- throw new Error(`${functionName} is not a valid function`)
2111
+ async saveAll({ docs = [], systemLog } = {}) {
2112
+ const copies = docs.map((doc) => {
2113
+ return this.init(doc)
2114
+ })
2115
+ const result = await this.repo.saveAll({ docs: copies, systemLog })
2116
+ return makeApiResponse({
2117
+ repo: this.repo,
2118
+ result
2119
+ })
2120
+ }
2121
+
2122
+ async saveOne({ doc = {}, systemLog } = {}) {
2123
+ const copy = this.init(doc)
2124
+ if (copy) {
2125
+ const result = await this.repo.saveOne({ doc: copy, systemLog })
2126
+ return makeApiResponse({
2127
+ repo: this.repo,
2128
+ result
2129
+ })
2061
2130
  }
2062
- } catch (e) {
2063
- throw e
2131
+ return {
2132
+ isNew: null,
2133
+ data: [],
2134
+ err: new Error('doc is not a valid instance')
2135
+ }
2136
+ }
2137
+ }
2138
+
2139
+ function makeService({ repo }) {
2140
+ if (repo === undefined) {
2141
+ throw new Error('repo is required.')
2142
+ }
2143
+ if (repo._superclass !== Repo._superclass) {
2144
+ throw new Error('repo is not an instance of Repo.')
2064
2145
  }
2146
+ return new Service({ repo })
2065
2147
  }
2066
2148
 
2067
2149
 
2068
2150
 
2069
- ;// ./lib/models/templateCompiler/index.js
2151
+ ;// ./lib/models/service/index.js
2070
2152
 
2071
2153
 
2072
2154
 
@@ -2315,6 +2397,7 @@ const stringHelper = {
2315
2397
 
2316
2398
 
2317
2399
 
2400
+
2318
2401
  ;// ./lib/index.js
2319
2402
 
2320
2403