Test Failed
Push — master ( 40c64c...4518ff )
by Dimas
09:34
created

libs/src/compiler/core.ts   D

Complexity

Total Complexity 58
Complexity/F 2.9

Size

Lines of Code 531
Function Count 20

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 332
dl 0
loc 531
rs 4.5599
c 0
b 0
f 0
wmc 58
mnd 38
bc 38
fnc 20
bpm 1.9
cpm 2.9
noi 0

20 Functions

Rating   Name   Duplication   Size   Complexity  
A core.localStorage 0 5 1
A core.normalize 0 10 2
A core.compileLESS 0 13 2
A core.isNode 0 10 2
A core.exists 0 3 1
C core.minJS 0 102 8
A core.config 0 5 1
A core.unlink 0 7 1
B core.readdir 0 42 6
A core.obfuscate 0 30 4
B core.scss 0 48 6
A core.less 0 29 2
B core.minCSS 0 56 6
A core.array_filter 0 7 1
A core.root 0 13 2
A core.filelog 0 11 1
A core.async 0 10 2
A core.composer 0 22 4
A core.isWin 0 6 1
A core.minify_folder 0 22 5

How to fix   Complexity   

Complexity

Complex classes like libs/src/compiler/core.ts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import * as fs from "fs";
2
import * as Terser from "terser";
3
import * as path from "path";
4
import slash from "slash";
5
import * as JavaScriptObfuscator from "javascript-obfuscator";
6
import log from "./log";
7
import * as uglifycss from "uglifycss";
8
import * as sass from "sass";
9
import { exec } from "child_process";
10
import { LocalStorage } from "../node-localstorage/index";
11
import configuration from "./config";
12
import * as framework from "./framework";
13
import filemanager from "./filemanager";
14
import less from "less";
15
16
/**
17
 * @class Core compiler
18
 * @author Dimas Lanjaka <[email protected]>
19
 */
20
class core {
21
  static log = log;
22
  log = log;
23
  /**
24
   * config.json
25
   */
26
  static config() {
27
    return configuration;
28
  }
29
  /**
30
   * filter array after deletion
31
   * @param arr
32
   */
33
  static array_filter(arr: any[]) {
34
    return arr.filter(function (el) {
35
      return el != null;
36
    });
37
  }
38
  /**
39
   * return Asynchronous function (Promise)
40
   * @param callback
41
   */
42
  static async(callback: Function) {
43
    return new Promise(function (resolve) {
44
      if (typeof callback == "function") {
45
        callback();
46
      }
47
      resolve();
48
    });
49
  }
50
  /**
51
   * localStorage NodeJS Version
52
   */
53
  static localStorage() {
54
    return new LocalStorage(`${this.root()}/tmp/storage`);
55
  }
56
  /**
57
   * Composer
58
   * @param dir directory has composer.json
59
   * @param type
60
   */
61
  static composer(
62
    dir: string,
63
    type: "update" | "install" | "validate" | "upgrade" | "self-update"
64
  ) {
65
    if (type) {
66
      exec(
67
        `cd ${dir} && php libs/bin/composer/composer.phar ${type}`,
68
        (error: { message: any }, stdout: any, stderr: any) => {
69
          if (error) {
70
            log.log(log.error(`error: ${error.message}`));
71
            return;
72
          }
73
          if (stderr) {
74
            log.log(`stderr: ${stderr}`);
75
            return;
76
          }
77
          log.log(`stdout: ${stdout}`);
78
        }
79
      );
80
    }
81
  }
82
83
  /**
84
   * @param dir
85
   * @param [filelist]
86
   * @return
87
   */
88
  static readdir(
89
    dir: string,
90
    filelist: string[] = null,
91
    exclude: Array<string | RegExp> = null
92
  ): Array<any> {
93
    if (!dir) return null;
94
    var self = this;
95
    if (!dir.toString().endsWith("/")) {
96
      dir += "/";
97
    }
98
    var files = fs.readdirSync(dir);
99
    filelist = filelist || [];
100
    files.forEach(function (file) {
101
      if (fs.statSync(dir + file).isDirectory()) {
102
        filelist = self.readdir(dir + file + "/", filelist, exclude);
103
      } else {
104
        filelist.push(path.resolve(dir + file));
105
      }
106
    });
107
    if (exclude && exclude.length) {
108
      exclude.forEach(function (ex) {
109
        filelist = filelist.filter(function (item) {
110
          var allow = null;
111
          if (ex instanceof RegExp) {
112
            allow = !ex.test(item);
113
          } else {
114
            var matches = item.indexOf(ex) !== -1;
115
            allow = !matches;
116
          }
117
          //console.log(allow, ex);
118
          return allow;
119
        });
120
      });
121
    }
122
123
    return filelist;
124
  }
125
126
  /**
127
   * Is Node or CommonJS Browser
128
   */
129
  static isNode() {
130
    var isNode = false;
131
    if (typeof module !== "undefined" && module.exports) {
132
      isNode = true;
133
    }
134
    return isNode;
135
  }
136
137
  /**
138
   * File Log Output Console
139
   * @param file
140
   */
141
  static filelog(file: string) {
142
    return path.join(
143
      core
144
        .normalize(path.dirname(file))
145
        .replace(core.normalize(process.cwd()), ""),
146
      path.basename(file)
147
    );
148
  }
149
150
  /**
151
   * Compile filename.scss to filename.css and filename.min.css
152
   * @param filename
153
   */
154
  static scss(filename: string) {
155
    const self = this;
156
    const exists = fs.existsSync(filename);
157
    if (exists) {
158
      if (exists) {
159
        var output = filename.toString().replace(/\.scss/s, ".css");
160
        var outputcss = output;
161
        if (
162
          /\.scss$/s.test(filename.toString()) &&
163
          !/\.min\.scss$/s.test(filename.toString())
164
        ) {
165
          sass.render(
166
            {
167
              file: filename.toString(),
168
              outputStyle: "expanded",
169
              outFile: output,
170
            },
171
            function (err, result) {
172
              if (!err) {
173
                fs.writeFile(outputcss, result.css.toString(), function (err) {
174
                  if (!err) {
175
                    log.log(
176
                      `${log
177
                        .chalk()
178
                        .red(
179
                          self.filelog(filename.toString())
180
                        )} > ${log
181
                        .chalk()
182
                        .blueBright(self.filelog(outputcss))} ${log.success(
183
                        "success"
184
                      )}`
185
                    );
186
                    core.minCSS(output, null);
187
                  } else {
188
                    log.log(log.error(err.message));
189
                  }
190
                });
191
              }
192
            }
193
          );
194
        }
195
      } else {
196
        console.error(`${filename} not found`);
197
      }
198
    }
199
  }
200
201
  static exists(filename: string): boolean {
202
    return fs.existsSync(filename);
203
  }
204
205
  static less(filename: string) {
206
    const self = this;
207
    const exists = fs.existsSync(filename);
208
    if (exists) {
209
      var outputcss = filename.toString().replace(/\.less/s, ".css");
210
      var source = fs.readFileSync(filename).toString();
211
      less
212
        .render(source, { sourceMap: { sourceMapFileInline: true } })
213
        .then(function (output) {
214
          fs.writeFileSync(outputcss, output.css, { encoding: "utf-8" });
215
          console.log(
216
            `${log
217
              .chalk()
218
              .hex("#1d365d")
219
              .bgWhite(self.filelog(filename))} > ${log
220
              .chalk()
221
              .blueBright(self.filelog(outputcss))} ${log.success("success")}`
222
          );
223
        })
224
        .catch(function (e) {
225
          console.log(
226
            `${log.chalk().hex("#1d365d")(
227
              self.filelog(filename)
228
            )} > ${log
229
              .chalk()
230
              .blueBright(self.filelog(outputcss))} ${log
231
              .chalk()
232
              .redBright("failed")}`
233
          );
234
        });
235
    }
236
  }
237
238
  /**
239
   * Compile LESS to CSS
240
   * @param from less path file
241
   * @param to to css path file
242
   * @example compileLESS('src/test.less', 'dist/test.css')
243
   */
244
  static compileLESS(from: string, to: string) {
245
    from = path.join(__dirname, from);
246
    to = path.join(__dirname, to);
247
    var self = this;
248
    fs.readFile(from, function (err, data) {
249
      if (err) return;
250
    });
251
  }
252
253
  /**
254
   * Get root path
255
   * @returns {string} posix/unix path format
256
   */
257
  static root(): string {
258
    var appDir = slash(path.dirname(require.main.filename)).toString();
259
    if (/\/libs\/compiler$/s.test(appDir)) {
260
      var split = appDir.split("/");
261
      split = split.slice(0, -2);
262
      appDir = split.join("/");
263
    }
264
    return appDir;
265
  }
266
267
  /**
268
   * Minify all js file to format *.min.js
269
   * @param {string} folder
270
   */
271
  static minify_folder(folder: string) {
272
    var self = this;
273
    var js = new Array();
274
    fs.exists(folder, function (exists) {
275
      if (exists && fs.lstatSync(folder).isDirectory()) {
276
        var read = self.readdir(folder, [], []);
277
        if (Array.isArray(read)) {
278
          read.forEach((file) => {
279
            if (!/\.min\.js$/s.test(file) && /\.js$/s.test(file)) {
280
              js.push(file);
281
              //log(file);
282
            }
283
          });
284
          js.filter(function (el) {
285
            return el != null;
286
          }).forEach(function (file: string) {
287
            if (file) self.minJS(file);
288
          });
289
        }
290
      }
291
    });
292
  }
293
294
  /**
295
   * Obfuscate Javascript
296
   * @param {string} filejs
297
   */
298
  static obfuscate(filejs: string) {
299
    const self = this;
300
    if (!/\.obfuscated\.js$/s.test(filejs) && filejs.endsWith(".js")) {
301
      var output = filejs.replace(/\.js/s, ".obfuscated.js");
302
      fs.readFile(
303
        filejs,
304
        {
305
          encoding: "utf-8",
306
        },
307
        function (err, data) {
308
          if (!err) {
309
            var obfuscationResult = JavaScriptObfuscator.obfuscate(data, {
310
              compact: true,
311
              controlFlowFlattening: true,
312
            });
313
314
            fs.writeFile(
315
              output,
316
              obfuscationResult.getObfuscatedCode(),
317
              function (err) {
318
                if (!err) {
319
                  log.log(
320
                    `${self.filelog(filejs)} > ${self.filelog(
321
                      output
322
                    )} ${log.success("success")}`
323
                  );
324
                }
325
              }
326
            );
327
          }
328
        }
329
      );
330
    }
331
  }
332
333
  /**
334
   * Minify JS into *.min.js version
335
   * @param {string} file
336
   */
337
  static minJS(file: string) {
338
    const self = this;
339
    if (!file) {
340
      return;
341
    }
342
343
    if (/\.min\.js$/s.test(file) || !/\.js$/s.test(file)) {
344
      log.log(log.error(`${file} minJS Not Allowed`));
345
      return;
346
    }
347
    var min = file.replace(/\.js$/s, ".min.js");
348
    //log(min);
349
    if (!fs.existsSync(file)) {
350
      log.log(log.random(file) + log.error(" not found"));
351
      return null;
352
    }
353
    fs.readFile(
354
      file,
355
      {
356
        encoding: "utf-8",
357
      },
358
      function (err, data) {
359
        if (!err) {
360
          fs.writeFile(min, data, function (err) {
361
            if (err) {
362
              console.error(err);
363
            } else {
364
              const terserResult = Terser.minify(fs.readFileSync(min, "utf8"), {
365
                parse: {
366
                  ecma: 8,
367
                },
368
                compress: {
369
                  ecma: 5,
370
                  warnings: false,
371
                  arrows: false,
372
                  collapse_vars: false,
373
                  comparisons: false,
374
                  computed_props: false,
375
                  hoist_funs: false,
376
                  hoist_props: false,
377
                  hoist_vars: false,
378
                  inline: false,
379
                  loops: false,
380
                  negate_iife: false,
381
                  properties: false,
382
                  reduce_funcs: false,
383
                  reduce_vars: false,
384
                  switches: false,
385
                  toplevel: false,
386
                  typeofs: false,
387
                  booleans: true,
388
                  if_return: true,
389
                  sequences: true,
390
                  unused: true,
391
                  conditionals: true,
392
                  dead_code: true,
393
                  evaluate: true,
394
                },
395
                mangle: {
396
                  safari10: true,
397
                },
398
                output: {
399
                  ecma: 5,
400
                  comments: false,
401
                  ascii_only: true,
402
                },
403
              });
404
405
              var input = self.filelog(file);
406
              var output = self.filelog(min);
407
              if (terserResult.error) {
408
                log.log(
409
                  `${log.chalk().yellow(input)} > ${log
410
                    .chalk()
411
                    .yellowBright(output)} ${log.chalk().red("fail")}`
412
                );
413
                fs.exists(min, function (ex) {
414
                  if (ex) {
415
                    filemanager.unlink(min, false);
416
                    log.log(
417
                      log.chalk().yellowBright(core.filelog(min)) +
418
                        log.chalk().redBright(" deleted")
419
                    );
420
                  }
421
                });
422
              } else {
423
                fs.writeFileSync(min, terserResult.code, "utf8");
424
                log.log(
425
                  `${log.chalk().yellow(input)} > ${log
426
                    .chalk()
427
                    .yellowBright(output)} ${log.success("success")}`
428
                );
429
              }
430
            }
431
          });
432
        } else {
433
          log.log(err);
434
        }
435
      }
436
    );
437
  }
438
439
  /**
440
   * smart delete file
441
   * @param {string} file
442
   */
443
  static unlink(file: string) {
444
    return filemanager.unlink(file, false);
445
  }
446
447
  /**
448
   * format path to unix path
449
   * @param {string} path
450
   * @returns {string|null}
451
   */
452
  static normalize(path: string): string | null {
453
    return typeof slash(path) == "string"
454
      ? slash(path).replace(/\/{2,99}/s, "/")
455
      : null;
456
  }
457
458
  /**
459
   * Determine OS is windows
460
   */
461
  static isWin() {
462
    return process.platform === "win32";
463
  }
464
465
  /**
466
   * minify css to *.min.css version
467
   * @param file
468
   * @param callback
469
   */
470
  static minCSS(file: string, callback: Function | null = null) {
471
    const self = this;
472
    fs.exists(file, function (exists) {
473
      if (exists && !/\.min\.css$/s.test(file) && /\.css$/s.test(file)) {
474
        var min = file.replace(/\.css/s, ".min.css");
475
        fs.readFile(
476
          file,
477
          {
478
            encoding: "utf-8",
479
          },
480
          function (err, data) {
481
            if (!err) {
482
              fs.writeFile(min, data, function (err) {
483
                if (!err) {
484
                  var minified = uglifycss.processFiles([min], {
485
                    maxLineLen: 500,
486
                    expandVars: true,
487
                  });
488
                  fs.writeFile(
489
                    min,
490
                    minified,
491
                    {
492
                      encoding: "utf-8",
493
                    },
494
                    function (err) {
495
                      if (!err) {
496
                        if (typeof callback != "function") {
497
                          log.log(
498
                            `${log
499
                              .chalk()
500
                              .blueBright(
501
                                self.filelog(file)
502
                              )} > ${log
503
                              .chalk()
504
                              .blueBright(
505
                                self.filelog(min)
506
                              )} ${log.chalk().green("success")}`
507
                          );
508
                        } else {
509
                          callback(true, file, min);
510
                        }
511
                      }
512
                    }
513
                  );
514
                } else {
515
                  log.log(log.chalk().red(err));
516
                }
517
              });
518
            } else {
519
              log.log(log.chalk().red(err));
520
            }
521
          }
522
        );
523
      }
524
    });
525
  }
526
}
527
528
Object.assign(core, filemanager, framework.dimas);
529
530
export = core;
531