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