libs/src/compiler/gulpfile.ts   B
last analyzed

Complexity

Total Complexity 45
Complexity/F 4.5

Size

Lines of Code 499
Function Count 10

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 319
dl 0
loc 499
rs 8.8
c 0
b 0
f 0
wmc 45
mnd 35
bc 35
fnc 10
bpm 3.5
cpm 4.5
noi 0

10 Functions

Rating   Name   Duplication   Size   Complexity  
A gulpfile.ts ➔ build 0 22 4
A gulpfile.ts ➔ createApp 0 48 4
A gulpfile.ts ➔ single_tsCompile 0 23 2
A gulpfile.ts ➔ multiMinify 0 7 1
B gulpfile.ts ➔ doc 0 91 1
A gulpfile.ts ➔ reload_gulp 0 22 2
C gulpfile.ts ➔ filter 0 11 11
A gulpfile.ts ➔ views 0 16 1
F gulpfile.ts ➔ compileAssets 0 58 14
B gulpfile.ts ➔ typescriptCompiler 0 36 5

How to fix   Complexity   

Complexity

Complex classes like libs/src/compiler/gulpfile.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 gulp from "gulp";
2
import ts from "gulp-typescript";
3
import * as fs from "fs";
4
import config from "../compiler/config";
5
import upath from "upath";
6
import path from "path";
7
import framework from "../compiler/index";
8
import log from "../compiler/log";
9
import process from "../compiler/process";
10
const root = process.root;
11
import jsdoc from "gulp-jsdoc3";
12
import { exec, ExecException } from "child_process";
13
import { localStorage } from "../node-localstorage/index";
14
import { fixDeps } from "./func";
15
//const spawn = require("child_process").spawn;
16
//const argv = require("yargs").argv;
17
import { spawn } from "child_process";
18
import * as proc from "process";
19
20
localStorage.removeItem("compile");
21
console.clear();
22
23
/**
24
 * Create Documentation of javascripts
25
 */
26
gulp.task("doc", doc);
27
28
/**
29
 * Build to /src/MVC/themes/assets/js/app.js
30
 * Minify Views Assets
31
 */
32
gulp.task("build", function () {
33
  return build();
34
});
35
36
gulp.task("build-clear", function () {
37
  return build(true);
38
});
39
40
/**
41
 * Build Project
42
 * @param withoutApp
43
 */
44
function build(withoutApp?: boolean) {
45
  try {
46
    var packageJson = root + "/package.json";
47
    if (fs.existsSync(packageJson)) {
48
      var json_pkg = JSON.parse(fs.readFileSync(packageJson).toString());
49
      fixDeps(json_pkg).then(function (json) {
50
        fs.writeFileSync(
51
          root + "/package.json",
52
          JSON.stringify(json, null, 2),
53
          {
54
            encoding: "utf-8",
55
          }
56
        );
57
      });
58
    }
59
  } catch (error) {}
60
  return createApp(withoutApp ? true : false);
61
}
62
63
// watch libs/js/**/* and views
64
gulp.task("watch", async function () {
65
  console.clear();
66
  const files = [
67
    "./libs/js/**/*",
68
    "./libs/src/**/*",
69
    "./src/MVC/**/*",
70
    "./etc/**/*",
71
    "./" + config.app.views + "/**/*",
72
  ];
73
74
  log.log(
75
    log.random("Listening ") +
76
      files
77
        .map(function (item) {
78
          return log.random(upath.resolve(item));
79
        })
80
        .join(" ")
81
  );
82
83
  var compiler_runner: any = false;
84
  var run_watch = gulp
85
    .watch(files, null)
86
    .on(
87
      "change",
88
      function (file: string | Buffer | import("url").URL | string[]) {
89
        const trigger = function () {
90
          file = framework.normalize(path.resolve(file.toString()));
91
          /**
92
           * Check is library compiler or source compiler
93
           */
94
          const is_Lib = /libs\/(js|src)\//s.test(framework.normalize(file));
95
          const filename_log = framework.filelog(file);
96
97
          if (is_Lib) {
98
            var isCompiler = file.includes("/libs/compiler/");
99
            var isFramework = /((framework|app)\.(js|js.map)|\.map)$/s.test(
100
              file
101
            );
102
            if (isCompiler || isFramework) return;
103
            //console.log(file, isFramework);
104
            log.log(
105
              log.random("Library compiler triggered by ") +
106
                log.random(framework.filelog(file))
107
            );
108
            log.log(
109
              log
110
                .chalk()
111
                .yellow(
112
                  `start compile ${log.random("src/MVC/themes/assets/js")}`
113
                )
114
            );
115
            if (compiler_runner) {
116
              log.log(log.error("Compiler still running"));
117
            } else {
118
              compiler_runner = setTimeout(function () {
119
                createApp(true);
120
                compiler_runner = null;
121
              }, 5000);
122
            }
123
124
            // run documentation builder
125
            //doc();
126
          } else {
127
            if (/\.(js|scss|css|less)$/s.test(file)) {
128
              if (!/\.min\.(js|css)$/s.test(file)) {
129
                compileAssets(file);
130
              }
131
            } else if (file.endsWith(".ts") && !file.endsWith(".d.ts")) {
132
              if (!/libs\/|libs\\/s.test(file)) {
133
                single_tsCompile(file);
134
              }
135
            } else if (file.endsWith(".browserify")) {
136
              framework.browserify(file);
137
            } else {
138
              var reason = log.error("undefined");
139
              if (/\.(php|log|txt|htaccess|log)$/s.test(filename_log)) {
140
                reason = log.random("Excluded");
141
              } else if (/\.(d\.ts)$/s.test(filename_log)) {
142
                reason = log.random("Typehint");
143
              }
144
              log.log(`[${reason}] cannot modify ${log.random(filename_log)}`);
145
            }
146
          }
147
        };
148
        return trigger();
149
      }
150
    );
151
  return run_watch;
152
});
153
154
gulp.task("assets-compile", function () {
155
  function filter(views: any[]) {
156
    return views
157
      .filter(function (item) {
158
        return (
159
          /\.(js|scss|css|sass|less)$/.test(item) &&
160
          !/\.min\.(js|css)$/.test(item) &&
161
          !/\-ori|\-original|\-backup|\.bak/s.test(item)
162
        );
163
      })
164
      .map(function (asset) {
165
        return framework.normalize(asset);
166
      });
167
  }
168
  var css = framework.readdir(root + "/assets/css");
169
  css = filter(css);
170
  var js = framework.readdir(root + "/assets/js");
171
  js = filter(js);
172
});
173
gulp.task("reload", reload_gulp);
174
gulp.task("default", gulp.series(["build", "watch"]));
175
176
/**
177
 * ```regex
178
 * \\.(jsx|js|ts|tsx|js(doc|x)?)$
179
 * ```
180
 * @param cb function callback
181
 */
182
function doc(cb: any = null) {
183
  /*const config = {
184
    recurseDepth: 10,
185
    opts: {
186
      template: "node_modules/better-docs",
187
    },
188
    tags: {
189
      allowUnknownTags: true,
190
      dictionaries: ["jsdoc", "closure"],
191
    },
192
    plugins: [
193
      "node_modules/better-docs/typescript",
194
      "node_modules/better-docs/category",
195
      "node_modules/better-docs/component",
196
      "plugins/markdown",
197
      "plugins/summarize",
198
    ],
199
    source: {
200
      includePattern: "\\.(jsx|js|ts|tsx|js(doc|x)?)$",
201
      ///include: ["./libs"],
202
      //exclude: ["./src"],
203
    },
204
  };*/
205
  const config = {
206
    tags: {
207
      allowUnknownTags: true,
208
      dictionaries: ["jsdoc", "closure"],
209
    },
210
    source: {
211
      include: ["./libs"],
212
      includePattern: ".js$",
213
      excludePattern: "(node_modules|docs)",
214
    },
215
    plugins: [
216
      "plugins/markdown",
217
      "jsdoc-mermaid",
218
      "node_modules/better-docs/typescript",
219
      "node_modules/better-docs/category",
220
      "node_modules/better-docs/component",
221
      "node_modules/better-docs/typedef-import",
222
    ],
223
    opts: {
224
      encoding: "utf8",
225
      destination: root + "/docs/js/",
226
      readme: "readme.md",
227
      recurse: true,
228
      verbose: true,
229
      //tutorials: "./docs-src/tutorials",
230
      template: "better-docs",
231
    },
232
    templates: {
233
      cleverLinks: false,
234
      monospaceLinks: false,
235
      search: true,
236
      default: {
237
        staticFiles: {
238
          //include: ["./docs-src/statics"],
239
        },
240
      },
241
      "better-docs": {
242
        name: "Universal Framework Javascript Documentation",
243
        //logo: "images/logo.png",
244
        title: "Universal Framework Javascript Documentation", // HTML title
245
        //css: "style.css",
246
        trackingCode: "tracking-code-which-will-go-to-the-HEAD",
247
        hideGenerator: false,
248
        navLinks: [
249
          {
250
            label: "Github",
251
            href: "https://github.com/dimaslanjaka/universal-framework",
252
          },
253
          {
254
            label: "Example Application",
255
            href: "http://github.com/dimaslanjaka/universal-framework",
256
          },
257
        ],
258
      },
259
    },
260
  };
261
  gulp
262
    .src(["./libs/**/*.(js|ts|tsx|js(doc|x)?)$"], {
263
      read: false,
264
    })
265
    .pipe(jsdoc(config, cb));
266
}
267
268
async function reload_gulp(cb: any = null) {
269
  //spawn("gulp", ["watch"], { stdio: "inherit" });
270
  //proc.exit();
271
272
  if (proc.env.process_restarting) {
273
    delete proc.env.process_restarting;
274
    // Give old process one second to shut down before continuing ...
275
    setTimeout(reload_gulp, 1000);
276
    //reload_gulp();
277
    //proc.exit();
278
    return;
279
  }
280
281
  console.log("reloading gulp");
282
  //console.log(proc.argv[0]);
283
  //console.log(proc.argv.slice(1));
284
285
  // Restart process ...
286
  spawn(proc.argv[0], proc.argv.slice(1), {
287
    env: { process_restarting: "1" },
288
    stdio: "ignore",
289
  }).unref();
290
}
291
292
/**
293
 * compile and minify assets
294
 * @param item file full path
295
 */
296
export function compileAssets(item: string | Buffer): any {
297
  const exists = fs.existsSync(item);
298
  if (exists) {
299
    item = item.toString();
300
    var config:
301
      | string
302
      | {
303
          obfuscate: boolean;
304
        } = upath.normalizeSafe(
305
      root + "/src/MVC/config/" + item.replace(framework.root(), "")
306
    );
307
    config = framework.normalize(framework.root() + config);
308
    config = config.replace(/\.(js|css)/s, ".json");
309
    if (fs.existsSync(config)) {
310
      config = require(config);
311
    }
312
313
    if (item.endsWith(".less") && !item.endsWith(".min.less")) {
314
      //console.log(`Compiling LESS ${framework.filelog(item)}`);
315
      framework.less(item);
316
    } else if (item.endsWith(".scss") && !item.endsWith(".min.scss")) {
317
      //console.log(`Compiling SCSS ${framework.filelog(item)}`);
318
      framework.scss(item);
319
    } else if (item.endsWith(".css") && !item.endsWith(".min.css")) {
320
      //console.log(`Minify CSS ${framework.filelog(item)}`);
321
      framework.minCSS(item);
322
    } else if (item.endsWith(".js") && !item.endsWith(".min.js")) {
323
      if (!item.endsWith(".babel.js")) {
324
        //console.log(`Minify JS ${framework.filelog(item)}`);
325
        framework.minJS(item);
326
        var deleteObfuscated = false;
327
        if (typeof config == "object") {
328
          if (config.hasOwnProperty("obfuscate")) {
329
            if (config.obfuscate) {
330
              //console.log(`Obfuscating JS ${framework.filelog(item)}`);
331
              framework.obfuscate(item);
332
            } else {
333
              deleteObfuscated = true;
334
            }
335
          } else {
336
            deleteObfuscated = true;
337
          }
338
        }
339
        if (deleteObfuscated) {
340
          var obfuscatedjs = item.replace(/\.js$/s, ".obfuscated.js");
341
          var obfuscatedminjs = item.replace(/\.js$/s, ".obfuscated.min.js");
342
          framework.unlink(obfuscatedjs);
343
          framework.unlink(obfuscatedminjs);
344
        }
345
      }
346
    } else if (item.endsWith(".ts") && !item.endsWith(".d.ts")) {
347
      if (!/libs\/|libs\\/s.test(item)) {
348
        single_tsCompile(item);
349
      }
350
    }
351
  }
352
}
353
354
/**
355
 * List views folder
356
 */
357
export function views() {
358
  var views = framework.readdir(root + `/${config.app.views}`);
359
  return views
360
    .filter(function (item) {
361
      return (
362
        /\.(js|scss|css|sass|less)$/.test(item) &&
363
        !/\.min\.(js|css)$/.test(item) &&
364
        !/\-ori|\-original|\-backup|\.bak/s.test(item)
365
      );
366
    })
367
    .map(function (asset) {
368
      return framework.normalize(asset);
369
    });
370
}
371
372
/**
373
 * compileAssets multiple assets
374
 * @param assets
375
 */
376
export function multiMinify(assets: any[]): any {
377
  assets.map(compileAssets);
378
}
379
380
localStorage.removeItem("compile");
381
382
var isFirstExecute = true;
383
/**
384
 * Create App.js
385
 * @param withoutView false to not compile views javascripts
386
 */
387
export async function createApp(withoutView: boolean) {
388
  var exists = localStorage.getItem("compile");
389
  if (!exists) {
390
    localStorage.setItem("compile", "running");
391
    var target = upath.normalizeSafe(
392
      upath.resolve(upath.join(root, "src/MVC/themes/assets/js/app.js"))
393
    );
394
    await typescriptCompiler("tsconfig.build.json", root + "/").catch(function (
395
      err
396
    ) {
397
      log.log(log.error(err));
398
    });
399
    await typescriptCompiler("tsconfig.precompiler.json", root + "/").catch(
400
      function (err) {
401
        log.log(log.error(err));
402
      }
403
    );
404
    await typescriptCompiler("tsconfig.compiler.json", root + "/libs/").catch(
405
      function (err) {
406
        log.log(log.error(err));
407
      }
408
    );
409
    //await node2browser(target, path.dirname(target));
410
    await compileAssets(target);
411
    if (!withoutView) {
412
      await multiMinify(views());
413
    }
414
    const appjs = path.join(root, "src/MVC/themes/assets/js/app.js");
415
    exec(`browserify ${appjs} -o ${appjs}`);
416
    localStorage.removeItem("compile");
417
    /*execute(
418
      "browserify --standalone Bundle ./src/MVC/themes/assets/js/app.js -o ./src/MVC/themes/assets/js/app.min.js && browserify --standalone Bundle ./src/MVC/themes/assets/js/app.js -o ./src/MVC/themes/assets/js/app.js"
419
    );*/
420
421
    if (!isFirstExecute) {
422
      // reload gulp
423
      //reload_gulp();
424
    }
425
    isFirstExecute = false;
426
  } else {
427
    log.log(
428
      log.error("Compiler lock process already exists ") +
429
        log.chalk().yellow("node index.js fix") +
430
        log.chalk().green(" to fix it")
431
    );
432
  }
433
}
434
435
/**
436
 * Single Typescript Compiler
437
 * @param target
438
 * @todo universal-framework typescript compiler support
439
 */
440
export function single_tsCompile(target: string) {
441
  var targetlog = log.chalk().magentaBright(framework.filelog(target));
442
  if (target.endsWith(".d.ts")) {
443
    log.log(`${targetlog} is declaration file`);
444
    return;
445
  }
446
  var dest = path.dirname(target);
447
  log.log(
448
    `${targetlog} > ${log
449
      .chalk()
450
      .yellow(framework.filelog(target.replace(/\.ts$/, ".js")))} start`
451
  );
452
  var tsProject = ts.createProject({
453
    declaration: false,
454
    skipLibCheck: true,
455
  });
456
  return gulp.src(target).pipe(tsProject()).pipe(gulp.dest(dest));
457
}
458
459
/**
460
 * Typescript compiler
461
 * @param source
462
 * @param destination
463
 * @param callback
464
 */
465
export function typescriptCompiler(
466
  source: string,
467
  destination: string,
468
  callback: (arg0: any, arg1: any) => void = null
469
) {
470
  return new Promise((resolve, reject) => {
471
    exec(
472
      `tsc -p ${source}`,
473
      function (err: ExecException, stdout: string, stderr: string) {
474
        if (!err) {
475
          if (typeof callback == "function") {
476
            callback(source, destination);
477
          }
478
          if (stdout.trim().length) {
479
            console.log(stdout);
480
          }
481
          if (stderr.trim().length) {
482
            console.log(stderr);
483
          }
484
          log.log(
485
            log.random("successfully compiled ") +
486
              log.success(path.basename(source))
487
          );
488
          resolve(true);
489
        } else {
490
          log.log(
491
            log.random("failed compile ") + log.error(path.basename(source))
492
          );
493
          reject(err.message);
494
        }
495
      }
496
    );
497
  });
498
}
499