beech-api 3.9.0-beta.9-rc → 3.9.75
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.
- package/LICENSE +21 -21
- package/README.md +1715 -1649
- package/index.js +2 -2
- package/package.json +92 -84
- package/packages/cli/beech +9 -10
- package/packages/cli/bin/beech-app.js +390 -390
- package/packages/cli/bin/beech-service.js +263 -170
- package/packages/cli/core/auth/Credentials.js +174 -174
- package/packages/cli/core/auth/Passport.js +664 -664
- package/packages/cli/core/auth/_Request.js +12 -12
- package/packages/cli/core/configure/_gitignore +16 -15
- package/packages/cli/core/configure/_sequelizerc +9 -9
- package/packages/cli/core/configure/app.config-basic.js +55 -55
- package/packages/cli/core/configure/app.config-sequelize.js +88 -88
- package/packages/cli/core/configure/beech.config.js +9 -9
- package/packages/cli/core/configure/global.config-basic.js +8 -8
- package/packages/cli/core/configure/global.config-sequelize.js +8 -8
- package/packages/cli/core/configure/jest.config.js +6 -6
- package/packages/cli/core/configure/jsconfig.json +8 -7
- package/packages/cli/core/configure/passport.config.js +97 -97
- package/packages/cli/core/databases/mysql.js +94 -95
- package/packages/cli/core/databases/sequelize.js +187 -188
- package/packages/cli/core/databases/test.js +250 -255
- package/packages/cli/core/file-walk/file-walk.js +35 -35
- package/packages/cli/core/generator/_endpoints +15 -15
- package/packages/cli/core/generator/_endpoints_basic +42 -42
- package/packages/cli/core/generator/_help +26 -18
- package/packages/cli/core/generator/_help_create +10 -10
- package/packages/cli/core/generator/_help_service +10 -10
- package/packages/cli/core/generator/_helpers +9 -9
- package/packages/cli/core/generator/_helpers_basic +22 -22
- package/packages/cli/core/generator/_models +6 -6
- package/packages/cli/core/generator/_models_basic +13 -13
- package/packages/cli/core/generator/_package +23 -19
- package/packages/cli/core/generator/_scheduler +32 -32
- package/packages/cli/core/generator/_spec +29 -29
- package/packages/cli/core/generator/index.js +1081 -992
- package/packages/cli/core/helpers/2fa.js +106 -106
- package/packages/cli/core/helpers/math.js +115 -115
- package/packages/cli/core/helpers/poolEntity.js +103 -103
- package/packages/cli/core/index.js +264 -266
- package/packages/cli/core/middleware/express/duplicateRequest.js +16 -16
- package/packages/cli/core/middleware/express/jwtCheckAllow.js +85 -85
- package/packages/cli/core/middleware/express/rateLimit.js +29 -29
- package/packages/cli/core/middleware/express/slowDown.js +2 -2
- package/packages/cli/core/middleware/index.js +6 -6
- package/packages/cli/core/middleware/origin/guard/advance.js +75 -75
- package/packages/cli/core/middleware/origin/whitelist/cors.js +94 -94
- package/packages/cli/core/services/http.express.js +481 -481
- package/packages/cli/core/test/check-node.js +21 -21
- package/packages/cli/core/test/utils.js +7 -7
- package/packages/cli/entry +10 -0
- package/packages/lib/index.js +6 -6
- package/packages/lib/src/endpoint.js +947 -885
- package/packages/lib/src/guard.js +60 -60
- package/packages/lib/src/salt.js +3 -3
- package/packages/lib/src/schema.js +96 -96
- package/packages/lib/src/specificExpress.js +7 -7
- package/packages/lib/src/user.js +271 -271
|
@@ -1,993 +1,1082 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const logUpdate = require("log-update");
|
|
3
|
-
const inquirer = require('inquirer');
|
|
4
|
-
const walk = require("walk");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
walker.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
resolve([
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
let
|
|
106
|
-
let
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
modelName =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
modelName =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.
|
|
254
|
-
.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
let
|
|
278
|
-
let
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
.then(this.
|
|
362
|
-
|
|
363
|
-
'
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if (
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const logUpdate = require("log-update");
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const walk = require("walk");
|
|
5
|
+
const recast = require("recast");
|
|
6
|
+
const { builders } = require("ast-types");
|
|
7
|
+
const { connectForGenerateModel } = require("../databases/test");
|
|
8
|
+
|
|
9
|
+
class Generator {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.embed(process.argv)
|
|
12
|
+
.then(() => this.init()
|
|
13
|
+
.then(status => console.log(status))
|
|
14
|
+
.catch(err => {
|
|
15
|
+
throw err;
|
|
16
|
+
})
|
|
17
|
+
)
|
|
18
|
+
.catch(err => {
|
|
19
|
+
throw err
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
init() {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
try {
|
|
26
|
+
if (this.option == '-v' || this.option == '--version') {
|
|
27
|
+
// check beech version
|
|
28
|
+
resolve("v" + require(__dirname + "/../../../../package.json").version);
|
|
29
|
+
} else if (this.option == '-h' || this.option == '?' || this.option == '--help') {
|
|
30
|
+
// help for see avaliable command
|
|
31
|
+
this.help()
|
|
32
|
+
.then(help => resolve(help))
|
|
33
|
+
.catch(err => reject(err));
|
|
34
|
+
} else if (this.option == 'make') {
|
|
35
|
+
// generate endpoint
|
|
36
|
+
if (!this.argument) {
|
|
37
|
+
resolve("\n[103m[90m Warning [0m[0m Please specify endpoints name.");
|
|
38
|
+
} else {
|
|
39
|
+
if (!this.special || this.special == 'undefined') {
|
|
40
|
+
this.make()
|
|
41
|
+
.then(make => resolve(make))
|
|
42
|
+
.catch(err => reject(err));
|
|
43
|
+
} else if (this.special == '--require' || this.special == '-R') {
|
|
44
|
+
// walking model files
|
|
45
|
+
const walkModelPromise = new Promise((resolve) => {
|
|
46
|
+
let walker = walk.walk("./src/models", { followLinks: false });
|
|
47
|
+
let modelFiles = [];
|
|
48
|
+
walker.on("file", (root, stat, next) => {
|
|
49
|
+
let subFolderModel = root.split("src/models\\")[1];
|
|
50
|
+
modelFiles.push((subFolderModel ? subFolderModel + "/" : "") + stat.name.split('.')[0]);
|
|
51
|
+
next();
|
|
52
|
+
});
|
|
53
|
+
walker.on("end", () => {
|
|
54
|
+
if(modelFiles.length) {
|
|
55
|
+
inquirer.prompt([ {
|
|
56
|
+
type: "checkbox",
|
|
57
|
+
name: "selectModel",
|
|
58
|
+
message: "[93mPlease select Models:[0m",
|
|
59
|
+
choices: modelFiles.map(e => e.replace(/\\/g, "/")),
|
|
60
|
+
} ]).then(selected => {
|
|
61
|
+
resolve(selected.selectModel);
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
// model file not found, Only create endpoint
|
|
65
|
+
resolve();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
Promise.all([walkModelPromise]).then((modelSelected) => {
|
|
70
|
+
let myModel = modelSelected[0];
|
|
71
|
+
// check require model exists
|
|
72
|
+
const modelExistsPromise = new Promise((resolve, reject) => {
|
|
73
|
+
this.isModelFound(myModel)
|
|
74
|
+
.then(existsModel => {
|
|
75
|
+
// check exists model
|
|
76
|
+
if (existsModel == false) {
|
|
77
|
+
inquirer.prompt([ {
|
|
78
|
+
type: "confirm",
|
|
79
|
+
name: "confirmModelNF",
|
|
80
|
+
message: "[93mModel is not found, Do you only create Endpoint ?:[0m",
|
|
81
|
+
} ]).then(confirm => {
|
|
82
|
+
if(confirm.confirmModelNF) {
|
|
83
|
+
resolve([true, []]);
|
|
84
|
+
} else {
|
|
85
|
+
resolve([false, []]);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
resolve([true, myModel]);
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.catch(err => reject(err));
|
|
93
|
+
});
|
|
94
|
+
// promise all check choose model(s)
|
|
95
|
+
Promise.all([modelExistsPromise]).then((modelRes) => {
|
|
96
|
+
// Say Yes, Making...
|
|
97
|
+
if(modelRes[0][0]) {
|
|
98
|
+
const poolBasePromise = new Promise((resolve) => {
|
|
99
|
+
// Check global config for prepare tmp endpoint
|
|
100
|
+
this.fs.readFile("./global.config.js", 'utf8', (err, data) => {
|
|
101
|
+
if (err) {
|
|
102
|
+
console.log("\n[101m Fatal [0m Can't read `global.config.js` file.\n", err);
|
|
103
|
+
return; // break;
|
|
104
|
+
} else {
|
|
105
|
+
let buffer = Buffer.from(data);
|
|
106
|
+
let buf2str = buffer.toString();
|
|
107
|
+
let buf2json = JSON.parse(JSON.stringify(buf2str));
|
|
108
|
+
let pool_base = /global.pool_base\s+=\s+(?:"|')([^"]+)(?:"|')(?:\r|\n|$|;|\r)/i.exec(buf2json);
|
|
109
|
+
if (pool_base) {
|
|
110
|
+
let myRequire = modelRes[0][1];
|
|
111
|
+
if (pool_base[ 1 ] == "basic") {
|
|
112
|
+
if(myRequire.length) {
|
|
113
|
+
// declare basic require model file
|
|
114
|
+
let rqr = "";
|
|
115
|
+
myRequire.map((data, key) => {
|
|
116
|
+
let modelName = data.split('/');
|
|
117
|
+
let modelFolder = "";
|
|
118
|
+
modelName = modelName.pop();
|
|
119
|
+
modelName = modelName.charAt(0).toUpperCase() + modelName.slice(1);
|
|
120
|
+
let newModel = modelName.split("_").map(e => e.charAt(0).toUpperCase() + e.slice(1)).join("");
|
|
121
|
+
modelFolder = data.substring(0, data.lastIndexOf('/') + 1).replace(/\\/g, "/");
|
|
122
|
+
rqr += `const ${newModel} = require(\"@/models/${modelFolder + modelName}\");\n`;
|
|
123
|
+
if(myRequire.length == key+1) {
|
|
124
|
+
resolve([[rqr], myRequire]);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
resolve([[]]);
|
|
129
|
+
}
|
|
130
|
+
} else if (pool_base[ 1 ] == "sequelize") {
|
|
131
|
+
// check null require resolve it
|
|
132
|
+
if(myRequire.length) {
|
|
133
|
+
// declare basic require model file
|
|
134
|
+
let rqr = "";
|
|
135
|
+
myRequire.map((data, key) => {
|
|
136
|
+
let modelName = data.split('/');
|
|
137
|
+
let modelFolder = "";
|
|
138
|
+
modelName = modelName.pop();
|
|
139
|
+
modelName = modelName.charAt(0).toUpperCase() + modelName.slice(1);
|
|
140
|
+
let newModel = modelName.split("_").map(e => e.charAt(0).toUpperCase() + e.slice(1)).join("");
|
|
141
|
+
modelFolder = data.substring(0, data.lastIndexOf('/') + 1).replace(/\\/g, "/");
|
|
142
|
+
rqr += `const { ${newModel} } = require(\"@/models/${modelFolder + modelName}\");\n`;
|
|
143
|
+
if(myRequire.length == key+1) {
|
|
144
|
+
resolve([[rqr], myRequire]);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
resolve([[]]);
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
console.log("\n[101m Fatal [0m The pool_base in `global.config.js` file does not match the specific.");
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
console.log("\n[101m Fatal [0m The pool_base in `global.config.js` file is not found.");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
// Final promise for make
|
|
160
|
+
Promise.all([poolBasePromise]).then((rqrRes) => {
|
|
161
|
+
// make with require model file
|
|
162
|
+
this.make(rqrRes[0])
|
|
163
|
+
.then(make => resolve(make))
|
|
164
|
+
.catch(err => reject(err));
|
|
165
|
+
});
|
|
166
|
+
} else {
|
|
167
|
+
// Say No, Nothing...
|
|
168
|
+
resolve(": Say no.");
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
} else if (this.special == '--model' || this.special == '-M') {
|
|
173
|
+
this.makeModel()
|
|
174
|
+
.then(make => resolve(make))
|
|
175
|
+
.catch(err => reject(err));
|
|
176
|
+
} else if (this.special == '--helper') {
|
|
177
|
+
this.makeHelper()
|
|
178
|
+
.then(make => resolve(make))
|
|
179
|
+
.catch(err => reject(err));
|
|
180
|
+
} else {
|
|
181
|
+
resolve("\n[101m Fatal [0m commnad it's not available.");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} else if (this.option == 'update') {
|
|
185
|
+
if(this.argument == 'model') {
|
|
186
|
+
if(this.special) {
|
|
187
|
+
if (!this.special) {
|
|
188
|
+
resolve("\n[103m[90m Warning [0m[0m Please specify model name to update.");
|
|
189
|
+
} else {
|
|
190
|
+
let extra = this.extra || undefined;
|
|
191
|
+
this.updateModel(extra)
|
|
192
|
+
.then(res => resolve(res))
|
|
193
|
+
.catch(err => reject(err));
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
resolve("\n[103m[90m Warning [0m[0m Please specify model name to update.");
|
|
197
|
+
}
|
|
198
|
+
} else if(this.argument != 'model') {
|
|
199
|
+
resolve("\n[101m Fatal [0m commnad it's not available.");
|
|
200
|
+
} else {
|
|
201
|
+
resolve("\n[103m[90m Warning [0m[0m Please specify what you want to update.");
|
|
202
|
+
}
|
|
203
|
+
} else if (this.option == 'passport') {
|
|
204
|
+
if (this.argument == "init") {
|
|
205
|
+
this.makePassportInit()
|
|
206
|
+
.then(make => resolve(make))
|
|
207
|
+
.catch(err => reject(err));
|
|
208
|
+
} else {
|
|
209
|
+
resolve("\n[103m[90m Warning [0m[0m Using `passport init` for initiate passport-jwt.");
|
|
210
|
+
}
|
|
211
|
+
} else if (this.option == "key:generate" || this.option == "key:gen") {
|
|
212
|
+
this.generateKeyConfigFile()
|
|
213
|
+
.then(resGenKey => resolve(resGenKey))
|
|
214
|
+
.catch(err => reject(err));
|
|
215
|
+
} else if (this.option && this.option.slice(0, 5) == "hash:") {
|
|
216
|
+
const { HashIt, Z } = require(__dirname + "/../helpers/math");
|
|
217
|
+
if(this.option.length > 5) {
|
|
218
|
+
Z((err, ak) => {
|
|
219
|
+
if(err) {
|
|
220
|
+
logUpdate(err);
|
|
221
|
+
} else {
|
|
222
|
+
let txt = this.option.split(":");
|
|
223
|
+
HashIt(txt, ak, null, (5).toString().length, (hashed) => {
|
|
224
|
+
logUpdate("\n" + hashed);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
} else {
|
|
229
|
+
inquirer.prompt([ {
|
|
230
|
+
type: "confirm",
|
|
231
|
+
name: "confirmHashNoText",
|
|
232
|
+
message: "[93mNo text to hash, Do you want to continue ?:[0m",
|
|
233
|
+
} ]).then(confirm => {
|
|
234
|
+
if(confirm.confirmHashNoText) {
|
|
235
|
+
Z((err, ak) => {
|
|
236
|
+
if(err) {
|
|
237
|
+
logUpdate(err);
|
|
238
|
+
} else {
|
|
239
|
+
let txt = this.option.split(":");
|
|
240
|
+
HashIt(txt, ak, null, (5).toString().length, (hashed) => {
|
|
241
|
+
logUpdate("\n" + hashed);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
} else {
|
|
246
|
+
// no text to hash say no.
|
|
247
|
+
resolve(": Say no.");
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
} else if (this.option == "skd") {
|
|
253
|
+
if (this.argument == "init") {
|
|
254
|
+
this.makeAddOnInit()
|
|
255
|
+
.then(make => resolve(make))
|
|
256
|
+
.catch(err => reject(err));
|
|
257
|
+
} else {
|
|
258
|
+
resolve("\n[103m[90m Warning [0m[0m Using `skd init` for initiate Job Scheduler.");
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
// help for see avaliable command
|
|
262
|
+
this.help()
|
|
263
|
+
.then(help => resolve(help))
|
|
264
|
+
.catch(err => reject(err));
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
reject(error);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
make(rq = null) {
|
|
273
|
+
return new Promise((resolve, reject) => {
|
|
274
|
+
try {
|
|
275
|
+
// prepare data
|
|
276
|
+
let tmpEndpointsPath = __dirname;
|
|
277
|
+
let tmpSpecPath = __dirname + '/_spec';
|
|
278
|
+
let endpointsPath = './src/endpoints/';
|
|
279
|
+
let testPath = './__tests__/unit/endpoints/';
|
|
280
|
+
// argument join `slash`
|
|
281
|
+
let arg = this.argument.replace(/^\/+|\/+$/g, '');
|
|
282
|
+
arg = arg.split('/');
|
|
283
|
+
let endpoints = arg.pop();
|
|
284
|
+
let subFolder = arg.join('/');
|
|
285
|
+
// endpoints file
|
|
286
|
+
let fullEndpoints = endpointsPath + subFolder.concat('/') + endpoints.concat('-endpoints.js');
|
|
287
|
+
let routeEndpoints = ((arg.length > 0) ? '/' : '') + subFolder.concat('/') + endpoints;
|
|
288
|
+
// test file
|
|
289
|
+
let fullTest = testPath + subFolder + '/' + endpoints.concat('-endpoints.spec.js');
|
|
290
|
+
|
|
291
|
+
// Check exists endpoint file
|
|
292
|
+
if (!this.fs.existsSync(fullEndpoints)) {
|
|
293
|
+
// STEP 0 : Check global config for prepare tmp endpoint
|
|
294
|
+
const promise0 = new Promise((resolve) => {
|
|
295
|
+
this.fs.readFile("./global.config.js", 'utf8', (err, data) => {
|
|
296
|
+
if (err) {
|
|
297
|
+
console.log("\n[101m Fatal [0m Can't read `global.config.js` file.", err);
|
|
298
|
+
resolve([false, null, null]);
|
|
299
|
+
} else {
|
|
300
|
+
let buffer = Buffer.from(data);
|
|
301
|
+
let buf2str = buffer.toString();
|
|
302
|
+
let buf2json = JSON.parse(JSON.stringify(buf2str));
|
|
303
|
+
let pool_base = /global.pool_base\s+=\s+(?:"|')([^"]+)(?:"|')(?:\r|\n|$|;|\r)/i.exec(buf2json);
|
|
304
|
+
if (pool_base) {
|
|
305
|
+
if (pool_base[ 1 ] == "basic") {
|
|
306
|
+
resolve([true, tmpEndpointsPath += '/_endpoints_basic', pool_base[ 1 ]]);
|
|
307
|
+
} else if (pool_base[ 1 ] == "sequelize") {
|
|
308
|
+
resolve([true, tmpEndpointsPath += '/_endpoints', pool_base[ 1 ]]);
|
|
309
|
+
} else {
|
|
310
|
+
console.log("\n[101m Fatal [0m The pool_base in `global.config.js` file does not match the specific.");
|
|
311
|
+
resolve([false, null, null]);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
console.log("\n[101m Fatal [0m The pool_base in `global.config.js` file is not found.");
|
|
315
|
+
resolve([false, null, null]);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// STEP 1 : Format Require model file
|
|
322
|
+
const promise1 = new Promise((resolve) => {
|
|
323
|
+
// prepare state require file if `rq[0]` not exists
|
|
324
|
+
let requireFile = '// You can require something \n';
|
|
325
|
+
// check exists requrie files
|
|
326
|
+
if(rq) {
|
|
327
|
+
if (rq[0].length) {
|
|
328
|
+
requireFile = '';
|
|
329
|
+
// make require multiples line
|
|
330
|
+
rq[0].map((data, key) => {
|
|
331
|
+
requireFile += data;
|
|
332
|
+
if(rq[0].length == key+1) {
|
|
333
|
+
resolve(requireFile);
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
} else {
|
|
337
|
+
resolve(requireFile);
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
resolve(requireFile);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
// promise all generate endpoint with require(s)
|
|
344
|
+
Promise.all([promise0, promise1]).then((rqFileRes) => {
|
|
345
|
+
/**
|
|
346
|
+
* @return
|
|
347
|
+
*
|
|
348
|
+
* rqFileRes[0] : Array[0 = global file true, 1 = tmp endpoint file, 2 = pool_base type ]
|
|
349
|
+
* rqFileRes[1] : Text require file
|
|
350
|
+
*
|
|
351
|
+
*/
|
|
352
|
+
// check global file exists.
|
|
353
|
+
if(rqFileRes[0][0]) {
|
|
354
|
+
logUpdate(": Initialize...");
|
|
355
|
+
// check for remove first slash/backslash and replace / or \ or multiple slash/backslash to one slash for route endpoint name
|
|
356
|
+
routeEndpoints = routeEndpoints.replace(/^[\\\/]+/, "").replace(/[\\\/]+/g, "/");
|
|
357
|
+
// timeout generate endpoint and replace content
|
|
358
|
+
setTimeout(() => {
|
|
359
|
+
// generater endpoint
|
|
360
|
+
this.makeFolder(endpointsPath + subFolder)
|
|
361
|
+
.then(this.copy.bind(this, tmpEndpointsPath, fullEndpoints))
|
|
362
|
+
.then(this.contentReplace.bind(this, fullEndpoints, {
|
|
363
|
+
'endpoint': routeEndpoints,
|
|
364
|
+
'endpointName': endpoints,
|
|
365
|
+
'rq': rqFileRes[1],
|
|
366
|
+
}))
|
|
367
|
+
// generater test
|
|
368
|
+
.then(this.makeFolder.bind(this, testPath + subFolder))
|
|
369
|
+
.then(this.copy.bind(this, tmpSpecPath, fullTest))
|
|
370
|
+
.then(this.contentReplace.bind(this, fullTest, {
|
|
371
|
+
'endpoint': routeEndpoints,
|
|
372
|
+
'endpointName': endpoints
|
|
373
|
+
}))
|
|
374
|
+
.then(logUpdate("\n[104m [37mProcessing [0m [0m The endpoint `" + endpoints + "` it's generating..."))
|
|
375
|
+
.then(generated => logUpdate(generated))
|
|
376
|
+
.catch(err => {
|
|
377
|
+
throw err;
|
|
378
|
+
});
|
|
379
|
+
}, 2000);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
resolve("\n[103m[90m Warning [0m[0m The endpoint `" + endpoints + "` it's duplicated.");
|
|
384
|
+
}
|
|
385
|
+
} catch (error) {
|
|
386
|
+
reject(error);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
isModelFound(modelArr) {
|
|
392
|
+
return new Promise((resolve, reject) => {
|
|
393
|
+
try {
|
|
394
|
+
if(modelArr !== undefined) {
|
|
395
|
+
if(modelArr.length) {
|
|
396
|
+
modelArr.map((data, key) => {
|
|
397
|
+
if (!this.fs.existsSync('./src/models/' + data.concat('.js'))) {
|
|
398
|
+
resolve(data);
|
|
399
|
+
}
|
|
400
|
+
if (modelArr.length == key+1) {
|
|
401
|
+
resolve(true);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
} else {
|
|
405
|
+
resolve(false);
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
resolve(false);
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
reject(error);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
makeModel() {
|
|
417
|
+
return new Promise((resolve, reject) => {
|
|
418
|
+
try {
|
|
419
|
+
// declare path model file
|
|
420
|
+
let tmpModelsPath = __dirname;
|
|
421
|
+
// read global.config.js file for check pool_base for generate model file
|
|
422
|
+
this.fs.readFile("./global.config.js", 'utf8', (err, data) => {
|
|
423
|
+
if (err) {
|
|
424
|
+
resolve("\n[101m Fatal [0m Can't read `global.config.js` file.", err);
|
|
425
|
+
} else {
|
|
426
|
+
let buffer = Buffer.from(data);
|
|
427
|
+
let buf2str = buffer.toString();
|
|
428
|
+
let buf2json = JSON.parse(JSON.stringify(buf2str));
|
|
429
|
+
let pool_base = /global.pool_base\s+=\s+(?:"|')([^"]+)(?:"|')(?:\r|\n|$|;|\r)/i.exec(buf2json);
|
|
430
|
+
if (pool_base) {
|
|
431
|
+
// read app.config.js file for get db connect name
|
|
432
|
+
this.fs.readFile("./app.config.js", 'utf8', (appErr, appData) => {
|
|
433
|
+
if (appErr) {
|
|
434
|
+
resolve("\n[101m Fatal [0m Can't read `app.config.js` file.", appErr);
|
|
435
|
+
} else {
|
|
436
|
+
let appBuffer = Buffer.from(appData);
|
|
437
|
+
let appBuf2str = appBuffer.toString();
|
|
438
|
+
let appBuf2json = JSON.parse(JSON.stringify(appBuf2str));
|
|
439
|
+
let appBuf2eval = eval(appBuf2json);
|
|
440
|
+
// choose one of database connect name
|
|
441
|
+
inquirer.prompt([ {
|
|
442
|
+
type: "list",
|
|
443
|
+
name: "selectDbConnect",
|
|
444
|
+
message: "[93mPlease select database connect name:[0m",
|
|
445
|
+
choices: appBuf2eval.database_config.map(e => e.name),
|
|
446
|
+
} ]).then(dbSelected => {
|
|
447
|
+
// check pool_base
|
|
448
|
+
if (pool_base[ 1 ] == "basic") {
|
|
449
|
+
tmpModelsPath += '/_models_basic';
|
|
450
|
+
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect, appBuf2eval, pool_base[1])
|
|
451
|
+
.then(console.log)
|
|
452
|
+
.catch(console.log);
|
|
453
|
+
} else if (pool_base[ 1 ] == "sequelize") {
|
|
454
|
+
tmpModelsPath += '/_models';
|
|
455
|
+
this.generateModel(tmpModelsPath, dbSelected.selectDbConnect, appBuf2eval, pool_base[1])
|
|
456
|
+
.then(console.log)
|
|
457
|
+
.catch(console.log);
|
|
458
|
+
} else {
|
|
459
|
+
resolve("\n[101m Fatal [0m The pool_base in `global.config.js` file does not match the specific.");
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
} else {
|
|
465
|
+
resolve("\n[101m Fatal [0m The pool_base in `global.config.js` file is not found.");
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
} catch (error) {
|
|
470
|
+
reject(error);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
updateModel(extra) {
|
|
476
|
+
return new Promise((resolve, reject) => {
|
|
477
|
+
try {
|
|
478
|
+
this.fs.readFile("./global.config.js", 'utf8', (err, globalData) => {
|
|
479
|
+
if (err) return resolve("\n[101m Fatal [0m Can't read `global.config.js` file.");
|
|
480
|
+
this.fs.readFile("./app.config.js", 'utf8', (appErr, appData) => {
|
|
481
|
+
if (appErr) return resolve("\n[101m Fatal [0m Can't read `app.config.js` file.");
|
|
482
|
+
const appConfig = eval(appData);
|
|
483
|
+
const rawSpecial = this.special; // "fruit/tropical/banana"
|
|
484
|
+
const pathParts = rawSpecial.split('/');
|
|
485
|
+
const modelName = pathParts[pathParts.length - 1];
|
|
486
|
+
const subFolder = pathParts.slice(0, pathParts.length - 1).join('/');
|
|
487
|
+
const folderPrefix = subFolder ? `${subFolder}/` : '';
|
|
488
|
+
const modelFileName = modelName.charAt(0).toUpperCase() + modelName.slice(1);
|
|
489
|
+
const modelPath = `./src/models/${folderPrefix}${modelFileName}.js`;
|
|
490
|
+
if (!this.fs.existsSync(modelPath)) {
|
|
491
|
+
return resolve(`\n[103m[90m Warning [0m[0m Model file \`${modelFileName}\` not found.`);
|
|
492
|
+
}
|
|
493
|
+
// Choose connection for new schema
|
|
494
|
+
inquirer.prompt([{
|
|
495
|
+
type: "list",
|
|
496
|
+
name: "selectDbConnect",
|
|
497
|
+
message: "[33mSelect database connection to sync schema:[0m",
|
|
498
|
+
choices: appConfig.database_config.map(e => e.name),
|
|
499
|
+
}]).then(dbSelected => {
|
|
500
|
+
const { connectForGenerateModel } = require("../databases/test");
|
|
501
|
+
// pull new schema from database
|
|
502
|
+
connectForGenerateModel(dbSelected.selectDbConnect, modelName, appConfig.database_config, (dbErr, tableSchema, tableName) => {
|
|
503
|
+
if (dbErr) return reject(dbErr);
|
|
504
|
+
// read current model file for AST
|
|
505
|
+
this.fs.readFile(modelPath, 'utf8', (readErr, code) => {
|
|
506
|
+
if (readErr) return reject(readErr);
|
|
507
|
+
const ast = recast.parse(code);
|
|
508
|
+
let isUpdated = false;
|
|
509
|
+
// Function for map raw database type to Sequelize DataTypes AST Node
|
|
510
|
+
const getDataTypeNode = (rawType) => {
|
|
511
|
+
const type = rawType.toUpperCase();
|
|
512
|
+
if (type.includes('INT')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('INTEGER'));
|
|
513
|
+
if (type.includes('BIGINT')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('BIGINT'));
|
|
514
|
+
if (type.includes('FLOAT')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('FLOAT'));
|
|
515
|
+
if (type.includes('DOUBLE')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('DOUBLE'));
|
|
516
|
+
if (type.includes('DECIMAL')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('DECIMAL'));
|
|
517
|
+
if (type.includes('BOOLEAN') || type === 'TINYINT(1)') return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('BOOLEAN'));
|
|
518
|
+
if (type.includes('CHAR') || type.includes('VARCHAR')) {
|
|
519
|
+
const match = type.match(/\((\d+)\)/);
|
|
520
|
+
const length = match ? match[1] : '255';
|
|
521
|
+
return builders.callExpression(
|
|
522
|
+
builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('STRING')),
|
|
523
|
+
[builders.literal(parseInt(length))]
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
if (type.includes('TEXT')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('TEXT'));
|
|
527
|
+
if (type.includes('DATE')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('DATE'));
|
|
528
|
+
if (type.includes('TIME')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('TIME'));
|
|
529
|
+
if (type.includes('JSON')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('JSON'));
|
|
530
|
+
if (type.includes('UUID')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('UUID'));
|
|
531
|
+
if (type.includes('BLOB')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('BLOB'));
|
|
532
|
+
if (type.includes('ENUM')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('ENUM'));
|
|
533
|
+
if (type.includes('GEOMETRY')) return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('GEOMETRY'));
|
|
534
|
+
return builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('STRING'));
|
|
535
|
+
};
|
|
536
|
+
// recast.visit for find position of Schema(...).define() and update fields
|
|
537
|
+
recast.visit(ast, {
|
|
538
|
+
visitCallExpression(path) {
|
|
539
|
+
const node = path.node;
|
|
540
|
+
if (node.callee.property && node.callee.property.name === 'define' && node.arguments[1] && node.arguments[1].type === 'ObjectExpression') {
|
|
541
|
+
const fieldsObject = node.arguments[1];
|
|
542
|
+
const newFieldNames = Object.keys(tableSchema);
|
|
543
|
+
const updatedProperties = [];
|
|
544
|
+
newFieldNames.forEach(dbFieldName => {
|
|
545
|
+
const dbFieldData = tableSchema[dbFieldName];
|
|
546
|
+
let existingProperty = fieldsObject.properties.find(p => {
|
|
547
|
+
const propName = p.key.name || p.key.value;
|
|
548
|
+
if (propName === dbFieldName) return true;
|
|
549
|
+
if (p.value && p.value.properties) {
|
|
550
|
+
const hasFieldMapping = p.value.properties.find(
|
|
551
|
+
innerP => (innerP.key.name === 'field' || innerP.key.value === 'field') &&
|
|
552
|
+
(innerP.value.value === dbFieldName)
|
|
553
|
+
);
|
|
554
|
+
if (hasFieldMapping) return true;
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
});
|
|
558
|
+
const latestFieldProps = [];
|
|
559
|
+
// Prepare properties from Table DB (Type, PK, AI, Default, etc.)
|
|
560
|
+
latestFieldProps.push(builders.property('init', builders.identifier('type'), getDataTypeNode(dbFieldData.type)));
|
|
561
|
+
latestFieldProps.push(builders.property('init', builders.identifier('allowNull'), builders.literal(dbFieldData.allowNull === 'YES' || dbFieldData.allowNull === true)));
|
|
562
|
+
if (dbFieldData.primaryKey) latestFieldProps.push(builders.property('init', builders.identifier('primaryKey'), builders.literal(true)));
|
|
563
|
+
if (dbFieldData.autoIncrement) latestFieldProps.push(builders.property('init', builders.identifier('autoIncrement'), builders.literal(true)));
|
|
564
|
+
if (dbFieldData.unique) latestFieldProps.push(builders.property('init', builders.identifier('unique'), builders.literal(true)));
|
|
565
|
+
// Check if not have variable extra '--no-comment' to raw add comment
|
|
566
|
+
if (extra !== '--no-comment') {
|
|
567
|
+
if (dbFieldData.comment) latestFieldProps.push(builders.property('init', builders.identifier('comment'), builders.literal(dbFieldData.comment)));
|
|
568
|
+
}
|
|
569
|
+
if (dbFieldData.defaultValue !== null && dbFieldData.defaultValue !== undefined) {
|
|
570
|
+
const dVal = String(dbFieldData.defaultValue).toUpperCase();
|
|
571
|
+
const defaultNode = (dVal === 'CURRENT_TIMESTAMP' || dVal === 'NOW()')
|
|
572
|
+
? builders.memberExpression(builders.identifier('DataTypes'), builders.identifier('NOW'))
|
|
573
|
+
: builders.literal(dbFieldData.defaultValue);
|
|
574
|
+
latestFieldProps.push(builders.property('init', builders.identifier('defaultValue'), defaultNode));
|
|
575
|
+
}
|
|
576
|
+
if (!existingProperty) {
|
|
577
|
+
existingProperty = builders.property('init', builders.identifier(dbFieldName), builders.objectExpression(latestFieldProps));
|
|
578
|
+
isUpdated = true;
|
|
579
|
+
} else {
|
|
580
|
+
const currentProps = existingProperty.value.properties;
|
|
581
|
+
latestFieldProps.forEach(newProp => {
|
|
582
|
+
const oldProp = currentProps.find(p => p.key.name === newProp.key.name);
|
|
583
|
+
if (!oldProp || recast.print(oldProp.value).code !== recast.print(newProp.value).code) {
|
|
584
|
+
isUpdated = true;
|
|
585
|
+
if (!oldProp) currentProps.push(newProp); else oldProp.value = newProp.value;
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
const latestPropNames = latestFieldProps.map(p => p.key.name);
|
|
589
|
+
latestPropNames.push('field');
|
|
590
|
+
existingProperty.value.properties = currentProps.filter(p => latestPropNames.includes(p.key.name));
|
|
591
|
+
}
|
|
592
|
+
updatedProperties.push(existingProperty);
|
|
593
|
+
});
|
|
594
|
+
const currentOrder = fieldsObject.properties.map(p => p.key.name || p.key.value).join(',');
|
|
595
|
+
const newOrder = updatedProperties.map(p => p.key.name || p.key.value).join(',');
|
|
596
|
+
if (currentOrder !== newOrder || fieldsObject.properties.length !== updatedProperties.length) isUpdated = true;
|
|
597
|
+
fieldsObject.properties = updatedProperties;
|
|
598
|
+
}
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
// Write back updated AST, Shout updated
|
|
603
|
+
if (isUpdated) {
|
|
604
|
+
// Write updated AST back to file
|
|
605
|
+
const output = recast.print(ast).code;
|
|
606
|
+
this.fs.writeFile(modelPath, output, 'utf8', (writeErr) => {
|
|
607
|
+
if (writeErr) return reject(writeErr);
|
|
608
|
+
resolve(`\n[102m[90m Updated [0m[0m The model \`${modelFileName}\` has been updated via AST.`);
|
|
609
|
+
});
|
|
610
|
+
} else {
|
|
611
|
+
resolve(`\n[103m[90m Warning [0m[0m No new fields found to update for \`${modelFileName}\`.`);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
} catch (error) {
|
|
619
|
+
reject(error);
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
generateModel(tmpModelsPath, dbSelected, appBuf2eval, pool_base) {
|
|
625
|
+
return new Promise((resolve, reject) => {
|
|
626
|
+
try {
|
|
627
|
+
// Show generating msg
|
|
628
|
+
const frames = [
|
|
629
|
+
'\n[36m[-] Generating[0m',
|
|
630
|
+
'\n[36m[\\] Generating.[0m',
|
|
631
|
+
'\n[36m[|] Generating..[0m',
|
|
632
|
+
'\n[36m[/] Generating...[0m'
|
|
633
|
+
];
|
|
634
|
+
let i = 0;
|
|
635
|
+
var refreshGenerateIntervalId = null;
|
|
636
|
+
// Save model folder
|
|
637
|
+
let modelPath = './src/models/';
|
|
638
|
+
// Argument join `slash`
|
|
639
|
+
let arg = this.argument.replace(/^\/+|\/+$/g, '');
|
|
640
|
+
arg = arg.split('/');
|
|
641
|
+
let models = arg.pop();
|
|
642
|
+
let oriModelsName = models.slice(0);
|
|
643
|
+
models = models.charAt(0).toUpperCase() + models.slice(1);
|
|
644
|
+
let newModel = models.split("_").map(e => e.charAt(0).toUpperCase() + e.slice(1)).join("");
|
|
645
|
+
let subFolder = arg.join('/');
|
|
646
|
+
// Declare models
|
|
647
|
+
let fullModels = modelPath + subFolder.concat('/') + models.concat('.js');
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* All properties
|
|
651
|
+
*
|
|
652
|
+
* @tmpModelPath String : path to keep generate model file
|
|
653
|
+
* @dbSelect String : database connection name
|
|
654
|
+
* @appBug2eval Object : database connection object
|
|
655
|
+
* @pool_base Object : pool base connection
|
|
656
|
+
*
|
|
657
|
+
* @i Number : loop count running...
|
|
658
|
+
* @refreshGenerateIntervalId Object : for clear interval id
|
|
659
|
+
*
|
|
660
|
+
* @arg String : argument from typing
|
|
661
|
+
* @models String : model name
|
|
662
|
+
* @oriModelsName String : original model name from typing
|
|
663
|
+
* @newModel String : model first upper case
|
|
664
|
+
* @subFolder String : agument sub folder
|
|
665
|
+
* @fullModels String : full model path and model file name
|
|
666
|
+
*
|
|
667
|
+
*/
|
|
668
|
+
// Check file exists
|
|
669
|
+
if (!this.fs.existsSync(fullModels)) {
|
|
670
|
+
// Check pool base is basic|sequelize
|
|
671
|
+
if(pool_base == "basic") {
|
|
672
|
+
// Generate basic model
|
|
673
|
+
this.makeFolder(modelPath + subFolder)
|
|
674
|
+
.then(this.copy.bind(this, tmpModelsPath, fullModels))
|
|
675
|
+
.then(this.modelContentReplace.bind(this, fullModels, {
|
|
676
|
+
'modelName': oriModelsName,
|
|
677
|
+
'dbSelected': dbSelected,
|
|
678
|
+
}))
|
|
679
|
+
.then(
|
|
680
|
+
refreshGenerateIntervalId = setInterval(() => {
|
|
681
|
+
const frame = frames[i = ++i % frames.length];
|
|
682
|
+
logUpdate(`${frame}`);
|
|
683
|
+
}, 300)
|
|
684
|
+
)
|
|
685
|
+
.then(generated => {
|
|
686
|
+
logUpdate(generated);
|
|
687
|
+
clearInterval(refreshGenerateIntervalId);
|
|
688
|
+
})
|
|
689
|
+
.catch(err => {
|
|
690
|
+
throw err;
|
|
691
|
+
});
|
|
692
|
+
} else if(pool_base == "sequelize") {
|
|
693
|
+
// Gether table schema
|
|
694
|
+
connectForGenerateModel(dbSelected, oriModelsName, appBuf2eval.database_config, (err, tableSchema, tableName) => {
|
|
695
|
+
if(err) {
|
|
696
|
+
throw logUpdate("\n[101m Fatal [0m", String(err), "\n");
|
|
697
|
+
} else {
|
|
698
|
+
// Raw model schema
|
|
699
|
+
this.rawSchemaTable(dbSelected, newModel, tableName, tableSchema, this.extra || undefined, (SchemaErr, rawSchema) => {
|
|
700
|
+
if(err) {
|
|
701
|
+
throw logUpdate("\n[101m Fatal [0m RAW Schema ERR:", String(SchemaErr), "\n");
|
|
702
|
+
} else {
|
|
703
|
+
// Generate sequelize model
|
|
704
|
+
this.makeFolder(modelPath + subFolder)
|
|
705
|
+
.then(this.copy.bind(this, tmpModelsPath, fullModels))
|
|
706
|
+
.then(this.modelContentReplace.bind(this, fullModels, {
|
|
707
|
+
'modelName': oriModelsName,
|
|
708
|
+
'modelNameUppercase': newModel,
|
|
709
|
+
'modelStructure': rawSchema,
|
|
710
|
+
}))
|
|
711
|
+
.then(
|
|
712
|
+
refreshGenerateIntervalId = setInterval(() => {
|
|
713
|
+
const frame = frames[i = ++i % frames.length];
|
|
714
|
+
logUpdate(`${frame}`);
|
|
715
|
+
}, 300)
|
|
716
|
+
)
|
|
717
|
+
.then(generated => {
|
|
718
|
+
logUpdate(generated);
|
|
719
|
+
clearInterval(refreshGenerateIntervalId);
|
|
720
|
+
})
|
|
721
|
+
.catch(err => {
|
|
722
|
+
throw err;
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
} else {
|
|
729
|
+
// Fallback (When Accident)
|
|
730
|
+
resolve("\n[101m Fatal [0m The pool_base in `global.config.js` file does not match the specific.");
|
|
731
|
+
}
|
|
732
|
+
} else {
|
|
733
|
+
resolve("\n[103m[90m Warning [0m[0m The model `" + models + "` it's duplicated.");
|
|
734
|
+
}
|
|
735
|
+
} catch (error) {
|
|
736
|
+
reject(error);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
rawSchemaTable(dbNameSelected, newModelName, tableName, modelSchema, extra, cb) {
|
|
742
|
+
try {
|
|
743
|
+
// Function map type
|
|
744
|
+
const mapToSequelizeType = (rawType) => {
|
|
745
|
+
const type = rawType.toUpperCase();
|
|
746
|
+
// Assign all conditions
|
|
747
|
+
if (type.includes('INT')) return 'DataTypes.INTEGER';
|
|
748
|
+
if (type.includes('BIGINT')) return 'DataTypes.BIGINT';
|
|
749
|
+
if (type.includes('FLOAT')) return 'DataTypes.FLOAT';
|
|
750
|
+
if (type.includes('DOUBLE')) return 'DataTypes.DOUBLE';
|
|
751
|
+
if (type.includes('DECIMAL')) return 'DataTypes.DECIMAL';
|
|
752
|
+
if (type.includes('BOOLEAN') || type === 'TINYINT(1)') return 'DataTypes.BOOLEAN';
|
|
753
|
+
if (type.includes('CHAR')) {
|
|
754
|
+
const match = type.match(/\((\d+)\)/);
|
|
755
|
+
const length = match ? match[1] : '255';
|
|
756
|
+
return `DataTypes.STRING(${length})`;
|
|
757
|
+
}
|
|
758
|
+
if (type.includes('VARCHAR')) {
|
|
759
|
+
const match = type.match(/\((\d+)\)/);
|
|
760
|
+
const length = match ? match[1] : '255';
|
|
761
|
+
return `DataTypes.STRING(${length})`;
|
|
762
|
+
}
|
|
763
|
+
if (type.includes('TEXT')) return 'DataTypes.TEXT';
|
|
764
|
+
if (type.includes('DATE')) return 'DataTypes.DATE';
|
|
765
|
+
if (type.includes('TIME')) return 'DataTypes.TIME';
|
|
766
|
+
if (type.includes('JSON')) return 'DataTypes.JSON';
|
|
767
|
+
if (type.includes('UUID')) return 'DataTypes.UUID';
|
|
768
|
+
if (type.includes('BLOB')) return 'DataTypes.BLOB';
|
|
769
|
+
if (type.includes('ENUM')) return 'DataTypes.ENUM'; // Needs manual values
|
|
770
|
+
if (type.includes('GEOMETRY')) return 'DataTypes.GEOMETRY';
|
|
771
|
+
// Fallback
|
|
772
|
+
return `DataTypes.STRING`;
|
|
773
|
+
};
|
|
774
|
+
// Looping key fields
|
|
775
|
+
const fields = Object.entries(modelSchema).map(([name, props]) => {
|
|
776
|
+
// Declare line
|
|
777
|
+
const lines = [];
|
|
778
|
+
// Push line and assign space for beautiful
|
|
779
|
+
lines.push(` type: ${mapToSequelizeType(props.type)},`);
|
|
780
|
+
lines.push(` allowNull: ${props.allowNull},`);
|
|
781
|
+
// Check is primary key
|
|
782
|
+
if (props.primaryKey) lines.push(` primaryKey: true,`);
|
|
783
|
+
if (props.autoIncrement) lines.push(` autoIncrement: true,`);
|
|
784
|
+
// Check <extra> for comment, because some database have extra comment in field but it's not comment for field, so we need to check it first before assign to comment
|
|
785
|
+
if(extra != '--no-comment') {
|
|
786
|
+
if (props.comment) lines.push(` comment: "${props.comment}",`);
|
|
787
|
+
}
|
|
788
|
+
// Handle defaultValue
|
|
789
|
+
if (props.defaultValue !== null && props.defaultValue !== undefined) {
|
|
790
|
+
const defaultVal = String(props.defaultValue).toUpperCase();
|
|
791
|
+
if (defaultVal === 'CURRENT_TIMESTAMP' || defaultVal === 'NOW()' || defaultVal.includes('CURRENT_TIMESTAMP')) {
|
|
792
|
+
lines.push(` defaultValue: DataTypes.NOW,`);
|
|
793
|
+
} else if (defaultVal === 'UUID()' || defaultVal === 'uuid()' || defaultVal === 'UUID') {
|
|
794
|
+
lines.push(` defaultValue: DataTypes.UUIDV4,`);
|
|
795
|
+
} else if (typeof props.defaultValue === 'string') {
|
|
796
|
+
lines.push(` defaultValue: "${props.defaultValue}",`);
|
|
797
|
+
} else {
|
|
798
|
+
lines.push(` defaultValue: ${props.defaultValue},`);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
// Finally
|
|
802
|
+
return ` ${name}: {\n${lines.join('\n')}\n }`;
|
|
803
|
+
});
|
|
804
|
+
// Callback
|
|
805
|
+
cb(null, `const ${newModelName} = Schema(sql.${dbNameSelected}).define("${tableName}", {\n${fields.join(',\n')}\n});`);
|
|
806
|
+
} catch (error) {
|
|
807
|
+
cb(error, null);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
makeHelper() {
|
|
812
|
+
return new Promise((resolve, reject) => {
|
|
813
|
+
try {
|
|
814
|
+
let tmpHelpersPath = __dirname + '/_helpers';
|
|
815
|
+
let helperPath = './src/helpers/';
|
|
816
|
+
// argument join `slash`
|
|
817
|
+
let arg = this.argument.replace(/^\/+|\/+$/g, '');
|
|
818
|
+
arg = arg.split('/');
|
|
819
|
+
let helpers = arg.pop();
|
|
820
|
+
helpers = helpers.charAt(0).toUpperCase() + helpers.slice(1);
|
|
821
|
+
let subFolder = arg.join('/');
|
|
822
|
+
// helpers
|
|
823
|
+
let fullHelpers = helperPath + subFolder.concat('/') + helpers.concat('.js');
|
|
824
|
+
// check file exists
|
|
825
|
+
if (!this.fs.existsSync(fullHelpers)) {
|
|
826
|
+
// generater model
|
|
827
|
+
this.makeFolder(helperPath + subFolder)
|
|
828
|
+
.then(this.copy.bind(this, tmpHelpersPath, fullHelpers))
|
|
829
|
+
.then(logUpdate("\n[104m [37mProcessing[0m [0m The helper `" + helpers + "` it's generating..."))
|
|
830
|
+
.then(logUpdate("\n[102m[90m Passed [0m[0m The helper `" + helpers + "` it's generated."))
|
|
831
|
+
.catch(err => {
|
|
832
|
+
throw err;
|
|
833
|
+
});
|
|
834
|
+
} else {
|
|
835
|
+
resolve("\n[103m[90m Warning [0m[0m The helper `" + helpers + "` it's duplicated.");
|
|
836
|
+
}
|
|
837
|
+
} catch (error) {
|
|
838
|
+
reject(error);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
makeFolder(path) {
|
|
844
|
+
/**
|
|
845
|
+
* @param path path to make
|
|
846
|
+
*
|
|
847
|
+
* @return new full path
|
|
848
|
+
*
|
|
849
|
+
*/
|
|
850
|
+
return new Promise((resolve, reject) => {
|
|
851
|
+
try {
|
|
852
|
+
const mkdirp = require("mkdirp");
|
|
853
|
+
mkdirp(path)
|
|
854
|
+
.then(p => resolve(p))
|
|
855
|
+
.catch(err => reject(err));
|
|
856
|
+
} catch (error) {
|
|
857
|
+
reject(error);
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
makePassportInit() {
|
|
863
|
+
return new Promise((resolve, reject) => {
|
|
864
|
+
try {
|
|
865
|
+
let passport_config_file = __dirname + '/../configure/passport.config.js';
|
|
866
|
+
let passport_config_paste_point = "./passport.config.js";
|
|
867
|
+
if (!this.fs.existsSync(passport_config_paste_point)) {
|
|
868
|
+
this.copy(passport_config_file, passport_config_paste_point)
|
|
869
|
+
.then(resolve("\n[102m[90m Passed [0m[0m The `passport-jwt` is initialized."))
|
|
870
|
+
.catch(err => console.log(err));
|
|
871
|
+
} else {
|
|
872
|
+
resolve("\n[103m[90m Warning [0m[0m The `passport-jwt` already is initialized.");
|
|
873
|
+
}
|
|
874
|
+
} catch (error) {
|
|
875
|
+
reject(error);
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
makeAddOnInit() {
|
|
881
|
+
return new Promise((resolve, reject) => {
|
|
882
|
+
try {
|
|
883
|
+
let tmpEndpointsPath = __dirname + '/_scheduler';
|
|
884
|
+
let add_on_paste_point = "Scheduler.js";
|
|
885
|
+
let folder_add_on = "./src/";
|
|
886
|
+
if (!this.fs.existsSync(folder_add_on + add_on_paste_point)) {
|
|
887
|
+
this.makeFolder(folder_add_on)
|
|
888
|
+
.then(this.copy.bind(this, tmpEndpointsPath, folder_add_on + add_on_paste_point))
|
|
889
|
+
.then(resolve("\n[102m[90m Passed [0m[0m The `Scheduler` is initialized."))
|
|
890
|
+
.catch(err => console.log(err));
|
|
891
|
+
} else {
|
|
892
|
+
resolve("\n[103m[90m Warning [0m[0m The `Scheduler` already is initialized.");
|
|
893
|
+
}
|
|
894
|
+
} catch (error) {
|
|
895
|
+
reject(error);
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
copy(path, to) {
|
|
901
|
+
/**
|
|
902
|
+
* @param path old path file
|
|
903
|
+
* @param to save to new path file
|
|
904
|
+
*
|
|
905
|
+
* @return new path file
|
|
906
|
+
*/
|
|
907
|
+
return new Promise((resolve, reject) => {
|
|
908
|
+
try {
|
|
909
|
+
if (!this.fs.existsSync(to)) {
|
|
910
|
+
if (this.fs.ReadStream(path).pipe(this.fs.createWriteStream(to))) {
|
|
911
|
+
resolve(to);
|
|
912
|
+
} else {
|
|
913
|
+
throw err;
|
|
914
|
+
}
|
|
915
|
+
} else {
|
|
916
|
+
resolve(to);
|
|
917
|
+
}
|
|
918
|
+
} catch (error) {
|
|
919
|
+
reject(error);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
contentReplace(pathFile, textCondition) {
|
|
925
|
+
return new Promise((resolve, reject) => {
|
|
926
|
+
try {
|
|
927
|
+
let endpoint = textCondition.endpoint;
|
|
928
|
+
let endpointName = textCondition.endpointName;
|
|
929
|
+
let rq = textCondition.rq;
|
|
930
|
+
let modelName = textCondition.modelName;
|
|
931
|
+
// delay for generator
|
|
932
|
+
setTimeout(() => {
|
|
933
|
+
this.fs.readFile(pathFile, 'utf8', (err, data) => {
|
|
934
|
+
if (err) {
|
|
935
|
+
throw err;
|
|
936
|
+
} else {
|
|
937
|
+
// content replace
|
|
938
|
+
let text = data.replace(new RegExp('{{endpoint}}', 'g'), endpoint);
|
|
939
|
+
text = text.replace(new RegExp('{{endpointName}}', 'g'), endpointName);
|
|
940
|
+
text = text.replace(new RegExp('{{requireSomething}}', 'g'), rq);
|
|
941
|
+
text = text.replace(new RegExp('{{modelName}}', 'g'), modelName);
|
|
942
|
+
setTimeout(() => {
|
|
943
|
+
// writing the file
|
|
944
|
+
this.fs.writeFile(pathFile, text, 'utf8', (err) => {
|
|
945
|
+
if (err) {
|
|
946
|
+
throw err;
|
|
947
|
+
} else {
|
|
948
|
+
resolve("\n[102m[90m Passed [0m[0m The endpoint `" + endpointName + "` it's generated.");
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
}, 1000);
|
|
952
|
+
}
|
|
953
|
+
})
|
|
954
|
+
}, 1000);
|
|
955
|
+
} catch (error) {
|
|
956
|
+
reject(error);
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
modelContentReplace(pathFile, textCondition) {
|
|
962
|
+
return new Promise((resolve, reject) => {
|
|
963
|
+
try {
|
|
964
|
+
let modelName = textCondition.modelName;
|
|
965
|
+
// delay for generator
|
|
966
|
+
setTimeout(() => {
|
|
967
|
+
this.fs.readFile(pathFile, 'utf8', (err, data) => {
|
|
968
|
+
if (err) {
|
|
969
|
+
throw err;
|
|
970
|
+
} else {
|
|
971
|
+
// content replace
|
|
972
|
+
let text = data.replace(new RegExp('{{modelName}}', 'g'), modelName);
|
|
973
|
+
text = text.replace(new RegExp('{{dbSelected}}', 'g'), textCondition.dbSelected);
|
|
974
|
+
// check add model name text uppercase
|
|
975
|
+
if (Object.keys(textCondition).length > 1) {
|
|
976
|
+
text = text.replace(new RegExp('{{modelStructure}}', 'g'), textCondition.modelStructure);
|
|
977
|
+
text = text.replace(new RegExp('{{modelNameUppercase}}', 'g'), textCondition.modelNameUppercase);
|
|
978
|
+
}
|
|
979
|
+
// writing the file
|
|
980
|
+
this.fs.writeFile(pathFile, text, 'utf8', (err) => {
|
|
981
|
+
if (err) {
|
|
982
|
+
throw err;
|
|
983
|
+
} else {
|
|
984
|
+
resolve("\n[102m[90m Passed [0m[0m The model `" + modelName + "` it's generated.");
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
})
|
|
989
|
+
}, 2000);
|
|
990
|
+
} catch (error) {
|
|
991
|
+
reject(error);
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
appKeyGenerator(length) {
|
|
997
|
+
return new Promise((resolve, reject) => {
|
|
998
|
+
try {
|
|
999
|
+
let md5 = require("md5");
|
|
1000
|
+
let secret = require(__dirname + "/../../../lib/src/salt").salt;
|
|
1001
|
+
let result = '';
|
|
1002
|
+
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
1003
|
+
let charactersLength = characters.length;
|
|
1004
|
+
for (var i = 0; i < length; i++) {
|
|
1005
|
+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
1006
|
+
}
|
|
1007
|
+
resolve(md5(result + secret));
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
reject(error);
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
generateKeyConfigFile() {
|
|
1015
|
+
return new Promise((resolve, reject) => {
|
|
1016
|
+
try {
|
|
1017
|
+
this.fs.readFile("app.config.js", 'utf8', (err, data) => {
|
|
1018
|
+
if (err) {
|
|
1019
|
+
throw err;
|
|
1020
|
+
} else {
|
|
1021
|
+
// edit or add property
|
|
1022
|
+
let buffer = Buffer.from(data);
|
|
1023
|
+
let buf2str = buffer.toString();
|
|
1024
|
+
let buf2json = JSON.parse(JSON.stringify(buf2str));
|
|
1025
|
+
let buf2eval = eval(buf2json);
|
|
1026
|
+
let oldSecret = buf2eval.main_config.app_key;
|
|
1027
|
+
// generate new key secret
|
|
1028
|
+
this.appKeyGenerator(8).then(newAppSecret => {
|
|
1029
|
+
// content replace
|
|
1030
|
+
let text = data.replace(new RegExp(oldSecret, 'g'), newAppSecret);
|
|
1031
|
+
// writing the file
|
|
1032
|
+
this.fs.writeFile("app.config.js", text, 'utf8', (err) => {
|
|
1033
|
+
if (err) {
|
|
1034
|
+
throw err;
|
|
1035
|
+
} else {
|
|
1036
|
+
resolve("\n[102m[90m Passed [0m[0m App secret it's new generated.");
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
reject(error);
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
help() {
|
|
1049
|
+
return new Promise((resolve, reject) => {
|
|
1050
|
+
try {
|
|
1051
|
+
this.fs.readFile(__dirname + "/_help", 'utf8', function (err, data) {
|
|
1052
|
+
if (err) {
|
|
1053
|
+
throw err;
|
|
1054
|
+
}
|
|
1055
|
+
resolve(data);
|
|
1056
|
+
});
|
|
1057
|
+
} catch (error) {
|
|
1058
|
+
reject(err);
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
embed(argv) {
|
|
1064
|
+
return new Promise((resolve, reject) => {
|
|
1065
|
+
try {
|
|
1066
|
+
this.fs = require('fs');
|
|
1067
|
+
this.cmd = require('node-cmd');
|
|
1068
|
+
this.argv = argv;
|
|
1069
|
+
this.option = argv[ 2 ];
|
|
1070
|
+
this.argument = argv[ 3 ];
|
|
1071
|
+
this.special = argv[ 4 ];
|
|
1072
|
+
this.extra = argv[ 5 ];
|
|
1073
|
+
this.more = argv[ 6 ];
|
|
1074
|
+
resolve(this);
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
reject(err);
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
993
1082
|
new Generator();
|