UNPKG

40.1 kBPlain TextView Raw
1import * as fs from 'fs-extra';
2import * as path from 'path';
3
4import { ts } from 'ts-morph';
5
6import { Application } from './app/application';
7import Configuration from './app/configuration';
8import FileEngine from './app/engines/file.engine';
9import I18nEngine from './app/engines/i18n.engine';
10
11import { ConfigurationFileInterface } from './app/interfaces/configuration-file.interface';
12import AngularVersionUtil from './utils/angular-version.util';
13import { COMPODOC_DEFAULTS } from './utils/defaults';
14import { logger } from './utils/logger';
15import { ParserUtil } from './utils/parser.util.class';
16import { readConfig, ignoreDirectory } from './utils/utils';
17
18import { cosmiconfigSync } from 'cosmiconfig';
19
20const os = require('os');
21const osName = require('os-name');
22const pkg = require('../package.json');
23const program = require('commander');
24
25const cosmiconfigModuleName = 'compodoc';
26
27let scannedFiles = [];
28let excludeFiles;
29let includeFiles;
30let cwd = process.cwd();
31
32process.setMaxListeners(0);
33
34export class CliApplication extends Application {
35 /**
36 * Run compodoc from the command line.
37 */
38 protected start(): any {
39 function list(val) {
40 return val.split(',');
41 }
42
43 program
44 .version(pkg.version)
45 .usage('<src> [options]')
46 .option(
47 '-c, --config [config]',
48 'A configuration file : .compodocrc, .compodocrc.json, .compodocrc.yaml or compodoc property in package.json'
49 )
50 .option('-p, --tsconfig [config]', 'A tsconfig.json file')
51 .option(
52 '-d, --output [folder]',
53 'Where to store the generated documentation',
54 COMPODOC_DEFAULTS.folder
55 )
56 .option('-y, --extTheme [file]', 'External styling theme file')
57 .option('-n, --name [name]', 'Title documentation', COMPODOC_DEFAULTS.title)
58 .option(
59 '-a, --assetsFolder [folder]',
60 'External assets folder to copy in generated documentation folder'
61 )
62 .option('-o, --open [value]', 'Open the generated documentation')
63 .option(
64 '-t, --silent',
65 "In silent mode, log messages aren't logged in the console",
66 false
67 )
68 .option(
69 '-s, --serve',
70 'Serve generated documentation (default http://localhost:8080/)',
71 false
72 )
73 .option('--host [host]', 'Change default host address')
74 .option('-r, --port [port]', 'Change default serving port', COMPODOC_DEFAULTS.port)
75 .option(
76 '-w, --watch',
77 'Watch source files after serve and force documentation rebuild',
78 false
79 )
80 .option(
81 '-e, --exportFormat [format]',
82 'Export in specified format (json, html)',
83 COMPODOC_DEFAULTS.exportFormat
84 )
85 .option('--files [files]', 'Files provided by external tool, used for coverage test')
86 .option(
87 '--language [language]',
88 'Language used for the generated documentation (de-DE, en-US, es-ES, fr-FR, hu-HU, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-BR, sk-SK, zh-CN, zh-TW)',
89 COMPODOC_DEFAULTS.language
90 )
91 .option(
92 '--theme [theme]',
93 "Choose one of available themes, default is 'gitbook' (laravel, original, material, postmark, readthedocs, stripe, vagrant)"
94 )
95 .option(
96 '--hideGenerator',
97 'Do not print the Compodoc link at the bottom of the page',
98 false
99 )
100 .option(
101 '--hideDarkModeToggle',
102 'Do not show dark mode toggle button at the top right position of the page',
103 false
104 )
105 .option(
106 '--toggleMenuItems <items>',
107 "Close by default items in the menu values : ['all'] or one of these ['modules','components','directives','controllers','entities','classes','injectables','guards','interfaces','interceptors','pipes','miscellaneous','additionalPages']",
108 list,
109 COMPODOC_DEFAULTS.toggleMenuItems
110 )
111 .option(
112 '--navTabConfig <tab configs>',
113 `List navigation tab objects in the desired order with two string properties ("id" and "label"). \
114Double-quotes must be escaped with '\\'. \
115Available tab IDs are "info", "readme", "source", "templateData", "styleData", "tree", and "example". \
116Note: Certain tabs will only be shown if applicable to a given dependency`,
117 list,
118 JSON.stringify(COMPODOC_DEFAULTS.navTabConfig)
119 )
120 .option(
121 '--templates [folder]',
122 'Path to directory of Handlebars templates to override built-in templates'
123 )
124 .option('--includes [path]', 'Path of external markdown files to include')
125 .option(
126 '--includesName [name]',
127 'Name of item menu of externals markdown files',
128 COMPODOC_DEFAULTS.additionalEntryName
129 )
130 .option(
131 '--coverageTest [threshold]',
132 'Test command of documentation coverage with a threshold (default 70)'
133 )
134 .option(
135 '--coverageMinimumPerFile [minimum]',
136 'Test command of documentation coverage per file with a minimum (default 0)'
137 )
138 .option(
139 '--coverageTestThresholdFail [true|false]',
140 'Test command of documentation coverage (global or per file) will fail with error or just warn user (true: error, false: warn)',
141 COMPODOC_DEFAULTS.coverageTestThresholdFail
142 )
143 .option('--coverageTestShowOnlyFailed', 'Display only failed files for a coverage test')
144 .option(
145 '--unitTestCoverage [json-summary]',
146 'To include unit test coverage, specify istanbul JSON coverage summary file'
147 )
148 .option(
149 '--disableSourceCode',
150 'Do not add source code tab and links to source code',
151 false
152 )
153 .option('--disableDomTree', 'Do not add dom tree tab', false)
154 .option('--disableTemplateTab', 'Do not add template tab', false)
155 .option('--disableStyleTab', 'Do not add style tab', false)
156 .option('--disableGraph', 'Do not add the dependency graph', false)
157 .option('--disableCoverage', 'Do not add the documentation coverage report', false)
158 .option('--disablePrivate', 'Do not show private in generated documentation', false)
159 .option('--disableProtected', 'Do not show protected in generated documentation', false)
160 .option('--disableInternal', 'Do not show @internal in generated documentation', false)
161 .option(
162 '--disableLifeCycleHooks',
163 'Do not show Angular lifecycle hooks in generated documentation',
164 false
165 )
166 .option(
167 '--disableRoutesGraph',
168 'Do not add the routes graph',
169 COMPODOC_DEFAULTS.disableRoutesGraph
170 )
171 .option('--disableSearch', 'Do not add the search input', false)
172 .option(
173 '--disableDependencies',
174 'Do not add the dependencies list',
175 COMPODOC_DEFAULTS.disableDependencies
176 )
177 .option(
178 '--disableProperties',
179 'Do not add the properties list',
180 COMPODOC_DEFAULTS.disableProperties
181 )
182 .option(
183 '--minimal',
184 'Minimal mode with only documentation. No search, no graph, no coverage.',
185 false
186 )
187 .option('--customFavicon [path]', 'Use a custom favicon')
188 .option('--customLogo [path]', 'Use a custom logo')
189 .option('--gaID [id]', 'Google Analytics tracking ID')
190 .option('--gaSite [site]', 'Google Analytics site name', COMPODOC_DEFAULTS.gaSite)
191 .option(
192 '--maxSearchResults [maxSearchResults]',
193 'Max search results on the results page. To show all results, set to 0',
194 COMPODOC_DEFAULTS.maxSearchResults
195 )
196 .parse(process.argv);
197
198 let outputHelp = () => {
199 program.outputHelp();
200 process.exit(1);
201 };
202
203 const configExplorer = cosmiconfigSync(cosmiconfigModuleName);
204
205 let configExplorerResult;
206
207 let configFile: ConfigurationFileInterface = {};
208
209 const programOptions = program.opts();
210
211 if (programOptions.config) {
212 let configFilePath = programOptions.config;
213 let testConfigFilePath = configFilePath.match(process.cwd());
214 if (testConfigFilePath && testConfigFilePath.length > 0) {
215 configFilePath = configFilePath.replace(process.cwd() + path.sep, '');
216 }
217 configExplorerResult = configExplorer.load(path.resolve(configFilePath));
218 } else {
219 configExplorerResult = configExplorer.search();
220 }
221
222 if (configExplorerResult) {
223 if (typeof configExplorerResult.config !== 'undefined') {
224 configFile = configExplorerResult.config;
225 }
226 }
227
228 if (configFile.output) {
229 Configuration.mainData.output = configFile.output;
230 }
231 if (programOptions.output && programOptions.output !== COMPODOC_DEFAULTS.folder) {
232 Configuration.mainData.output = programOptions.output;
233 }
234
235 if (configFile.extTheme) {
236 Configuration.mainData.extTheme = configFile.extTheme;
237 }
238 if (programOptions.extTheme) {
239 Configuration.mainData.extTheme = programOptions.extTheme;
240 }
241
242 if (configFile.language) {
243 Configuration.mainData.language = configFile.language;
244 }
245 if (programOptions.language) {
246 Configuration.mainData.language = programOptions.language;
247 }
248
249 if (configFile.theme) {
250 Configuration.mainData.theme = configFile.theme;
251 }
252 if (programOptions.theme) {
253 Configuration.mainData.theme = programOptions.theme;
254 }
255
256 if (configFile.name) {
257 Configuration.mainData.documentationMainName = configFile.name;
258 }
259 if (programOptions.name && programOptions.name !== COMPODOC_DEFAULTS.title) {
260 Configuration.mainData.documentationMainName = programOptions.name;
261 }
262
263 if (configFile.assetsFolder) {
264 Configuration.mainData.assetsFolder = configFile.assetsFolder;
265 }
266 if (programOptions.assetsFolder) {
267 Configuration.mainData.assetsFolder = programOptions.assetsFolder;
268 }
269
270 if (configFile.open) {
271 Configuration.mainData.open = configFile.open;
272 }
273 if (programOptions.open) {
274 Configuration.mainData.open = programOptions.open;
275 }
276
277 if (configFile.toggleMenuItems) {
278 Configuration.mainData.toggleMenuItems = configFile.toggleMenuItems;
279 }
280 if (
281 programOptions.toggleMenuItems &&
282 programOptions.toggleMenuItems !== COMPODOC_DEFAULTS.toggleMenuItems
283 ) {
284 Configuration.mainData.toggleMenuItems = programOptions.toggleMenuItems;
285 }
286
287 if (configFile.templates) {
288 Configuration.mainData.templates = configFile.templates;
289 }
290 if (programOptions.templates) {
291 Configuration.mainData.templates = programOptions.templates;
292 }
293
294 if (configFile.navTabConfig) {
295 Configuration.mainData.navTabConfig = configFile.navTabConfig;
296 }
297 if (
298 programOptions.navTabConfig &&
299 JSON.parse(programOptions.navTabConfig).length !== COMPODOC_DEFAULTS.navTabConfig.length
300 ) {
301 Configuration.mainData.navTabConfig = JSON.parse(programOptions.navTabConfig);
302 }
303
304 if (configFile.includes) {
305 Configuration.mainData.includes = configFile.includes;
306 }
307 if (programOptions.includes) {
308 Configuration.mainData.includes = programOptions.includes;
309 }
310
311 if (configFile.includesName) {
312 Configuration.mainData.includesName = configFile.includesName;
313 }
314 if (
315 programOptions.includesName &&
316 programOptions.includesName !== COMPODOC_DEFAULTS.additionalEntryName
317 ) {
318 Configuration.mainData.includesName = programOptions.includesName;
319 }
320
321 if (configFile.silent) {
322 logger.silent = false;
323 }
324 if (programOptions.silent) {
325 logger.silent = false;
326 }
327
328 if (configFile.serve) {
329 Configuration.mainData.serve = configFile.serve;
330 }
331 if (programOptions.serve) {
332 Configuration.mainData.serve = programOptions.serve;
333 }
334
335 if (configFile.host) {
336 Configuration.mainData.host = configFile.host;
337 Configuration.mainData.hostname = configFile.host;
338 }
339 if (programOptions.host) {
340 Configuration.mainData.host = programOptions.host;
341 Configuration.mainData.hostname = programOptions.host;
342 }
343
344 if (configFile.port) {
345 Configuration.mainData.port = configFile.port;
346 }
347 if (programOptions.port && programOptions.port !== COMPODOC_DEFAULTS.port) {
348 Configuration.mainData.port = programOptions.port;
349 }
350
351 if (configFile.watch) {
352 Configuration.mainData.watch = configFile.watch;
353 }
354 if (programOptions.watch) {
355 Configuration.mainData.watch = programOptions.watch;
356 }
357
358 if (configFile.exportFormat) {
359 Configuration.mainData.exportFormat = configFile.exportFormat;
360 }
361 if (
362 programOptions.exportFormat &&
363 programOptions.exportFormat !== COMPODOC_DEFAULTS.exportFormat
364 ) {
365 Configuration.mainData.exportFormat = programOptions.exportFormat;
366 }
367
368 if (configFile.hideGenerator) {
369 Configuration.mainData.hideGenerator = configFile.hideGenerator;
370 }
371 if (programOptions.hideGenerator) {
372 Configuration.mainData.hideGenerator = programOptions.hideGenerator;
373 }
374
375 if (configFile.hideDarkModeToggle) {
376 Configuration.mainData.hideDarkModeToggle = configFile.hideDarkModeToggle;
377 }
378 if (programOptions.hideDarkModeToggle) {
379 Configuration.mainData.hideDarkModeToggle = programOptions.hideDarkModeToggle;
380 }
381
382 if (configFile.coverageTest) {
383 Configuration.mainData.coverageTest = true;
384 Configuration.mainData.coverageTestThreshold =
385 typeof configFile.coverageTest === 'string'
386 ? parseInt(configFile.coverageTest, 10)
387 : COMPODOC_DEFAULTS.defaultCoverageThreshold;
388 }
389 if (programOptions.coverageTest) {
390 Configuration.mainData.coverageTest = true;
391 Configuration.mainData.coverageTestThreshold =
392 typeof programOptions.coverageTest === 'string'
393 ? parseInt(programOptions.coverageTest, 10)
394 : COMPODOC_DEFAULTS.defaultCoverageThreshold;
395 }
396
397 if (configFile.coverageMinimumPerFile) {
398 Configuration.mainData.coverageTestPerFile = true;
399 Configuration.mainData.coverageMinimumPerFile =
400 typeof configFile.coverageMinimumPerFile === 'string'
401 ? parseInt(configFile.coverageMinimumPerFile, 10)
402 : COMPODOC_DEFAULTS.defaultCoverageMinimumPerFile;
403 }
404 if (programOptions.coverageMinimumPerFile) {
405 Configuration.mainData.coverageTestPerFile = true;
406 Configuration.mainData.coverageMinimumPerFile =
407 typeof programOptions.coverageMinimumPerFile === 'string'
408 ? parseInt(programOptions.coverageMinimumPerFile, 10)
409 : COMPODOC_DEFAULTS.defaultCoverageMinimumPerFile;
410 }
411
412 if (configFile.coverageTestThresholdFail) {
413 Configuration.mainData.coverageTestThresholdFail =
414 configFile.coverageTestThresholdFail === 'false' ? false : true;
415 }
416 if (programOptions.coverageTestThresholdFail) {
417 Configuration.mainData.coverageTestThresholdFail =
418 programOptions.coverageTestThresholdFail === 'false' ? false : true;
419 }
420
421 if (configFile.coverageTestShowOnlyFailed) {
422 Configuration.mainData.coverageTestShowOnlyFailed =
423 configFile.coverageTestShowOnlyFailed;
424 }
425 if (programOptions.coverageTestShowOnlyFailed) {
426 Configuration.mainData.coverageTestShowOnlyFailed =
427 programOptions.coverageTestShowOnlyFailed;
428 }
429
430 if (configFile.unitTestCoverage) {
431 Configuration.mainData.unitTestCoverage = configFile.unitTestCoverage;
432 }
433 if (programOptions.unitTestCoverage) {
434 Configuration.mainData.unitTestCoverage = programOptions.unitTestCoverage;
435 }
436
437 if (configFile.disableSourceCode) {
438 Configuration.mainData.disableSourceCode = configFile.disableSourceCode;
439 }
440 if (programOptions.disableSourceCode) {
441 Configuration.mainData.disableSourceCode = programOptions.disableSourceCode;
442 }
443
444 if (configFile.disableDomTree) {
445 Configuration.mainData.disableDomTree = configFile.disableDomTree;
446 }
447 if (programOptions.disableDomTree) {
448 Configuration.mainData.disableDomTree = programOptions.disableDomTree;
449 }
450
451 if (configFile.disableTemplateTab) {
452 Configuration.mainData.disableTemplateTab = configFile.disableTemplateTab;
453 }
454 if (programOptions.disableTemplateTab) {
455 Configuration.mainData.disableTemplateTab = programOptions.disableTemplateTab;
456 }
457
458 if (configFile.disableStyleTab) {
459 Configuration.mainData.disableStyleTab = configFile.disableStyleTab;
460 }
461 if (programOptions.disableStyleTab) {
462 Configuration.mainData.disableStyleTab = programOptions.disableStyleTab;
463 }
464
465 if (configFile.disableGraph) {
466 Configuration.mainData.disableGraph = configFile.disableGraph;
467 }
468 if (programOptions.disableGraph) {
469 Configuration.mainData.disableGraph = programOptions.disableGraph;
470 }
471
472 if (configFile.disableCoverage) {
473 Configuration.mainData.disableCoverage = configFile.disableCoverage;
474 }
475 if (programOptions.disableCoverage) {
476 Configuration.mainData.disableCoverage = programOptions.disableCoverage;
477 }
478
479 if (configFile.disablePrivate) {
480 Configuration.mainData.disablePrivate = configFile.disablePrivate;
481 }
482 if (programOptions.disablePrivate) {
483 Configuration.mainData.disablePrivate = programOptions.disablePrivate;
484 }
485
486 if (configFile.disableProtected) {
487 Configuration.mainData.disableProtected = configFile.disableProtected;
488 }
489 if (programOptions.disableProtected) {
490 Configuration.mainData.disableProtected = programOptions.disableProtected;
491 }
492
493 if (configFile.disableInternal) {
494 Configuration.mainData.disableInternal = configFile.disableInternal;
495 }
496 if (programOptions.disableInternal) {
497 Configuration.mainData.disableInternal = programOptions.disableInternal;
498 }
499
500 if (configFile.disableLifeCycleHooks) {
501 Configuration.mainData.disableLifeCycleHooks = configFile.disableLifeCycleHooks;
502 }
503 if (programOptions.disableLifeCycleHooks) {
504 Configuration.mainData.disableLifeCycleHooks = programOptions.disableLifeCycleHooks;
505 }
506
507 if (configFile.disableRoutesGraph) {
508 Configuration.mainData.disableRoutesGraph = configFile.disableRoutesGraph;
509 }
510 if (programOptions.disableRoutesGraph) {
511 Configuration.mainData.disableRoutesGraph = programOptions.disableRoutesGraph;
512 }
513
514 if (configFile.disableSearch) {
515 Configuration.mainData.disableSearch = configFile.disableSearch;
516 }
517 if (programOptions.disableSearch) {
518 Configuration.mainData.disableSearch = programOptions.disableSearch;
519 }
520
521 if (configFile.disableDependencies) {
522 Configuration.mainData.disableDependencies = configFile.disableDependencies;
523 }
524 if (programOptions.disableDependencies) {
525 Configuration.mainData.disableDependencies = programOptions.disableDependencies;
526 }
527
528 if (configFile.disableProperties) {
529 Configuration.mainData.disableProperties = configFile.disableProperties;
530 }
531 if (programOptions.disableProperties) {
532 Configuration.mainData.disableProperties = programOptions.disableProperties;
533 }
534
535 if (configFile.minimal) {
536 Configuration.mainData.disableSearch = true;
537 Configuration.mainData.disableRoutesGraph = true;
538 Configuration.mainData.disableGraph = true;
539 Configuration.mainData.disableCoverage = true;
540 }
541 if (programOptions.minimal) {
542 Configuration.mainData.disableSearch = true;
543 Configuration.mainData.disableRoutesGraph = true;
544 Configuration.mainData.disableGraph = true;
545 Configuration.mainData.disableCoverage = true;
546 }
547
548 if (configFile.customFavicon) {
549 Configuration.mainData.customFavicon = configFile.customFavicon;
550 }
551 if (programOptions.customFavicon) {
552 Configuration.mainData.customFavicon = programOptions.customFavicon;
553 }
554
555 if (configFile.customLogo) {
556 Configuration.mainData.customLogo = configFile.customLogo;
557 }
558 if (programOptions.customLogo) {
559 Configuration.mainData.customLogo = programOptions.customLogo;
560 }
561
562 if (configFile.gaID) {
563 Configuration.mainData.gaID = configFile.gaID;
564 }
565 if (programOptions.gaID) {
566 Configuration.mainData.gaID = programOptions.gaID;
567 }
568
569 if (configFile.gaSite) {
570 Configuration.mainData.gaSite = configFile.gaSite;
571 }
572 if (programOptions.gaSite && programOptions.gaSite !== COMPODOC_DEFAULTS.gaSite) {
573 Configuration.mainData.gaSite = programOptions.gaSite;
574 }
575
576 if (!this.isWatching) {
577 if (!logger.silent) {
578 console.log(`Compodoc v${pkg.version}`);
579 } else {
580 console.log(fs.readFileSync(path.join(__dirname, '../src/banner')).toString());
581 console.log(pkg.version);
582 console.log('');
583 console.log(`TypeScript version used by Compodoc : ${ts.version}`);
584 console.log('');
585
586 if (FileEngine.existsSync(cwd + path.sep + 'package.json')) {
587 const packageData = FileEngine.getSync(cwd + path.sep + 'package.json');
588 if (packageData) {
589 const parsedData = JSON.parse(packageData);
590 const projectDevDependencies = parsedData.devDependencies;
591 if (projectDevDependencies && projectDevDependencies.typescript) {
592 const tsProjectVersion = AngularVersionUtil.cleanVersion(
593 projectDevDependencies.typescript
594 );
595 console.log(
596 `TypeScript version of current project : ${tsProjectVersion}`
597 );
598 console.log('');
599 }
600 }
601 }
602 console.log(`Node.js version : ${process.version}`);
603 console.log('');
604 console.log(`Operating system : ${osName(os.platform(), os.release())}`);
605 console.log('');
606 }
607 }
608
609 if (configExplorerResult) {
610 if (typeof configExplorerResult.config !== 'undefined') {
611 logger.info(`Using configuration file : ${configExplorerResult.filepath}`);
612 }
613 }
614
615 if (!configExplorerResult) {
616 logger.warn(`No configuration file found, switching to CLI flags.`);
617 }
618
619 if (programOptions.language && !I18nEngine.supportLanguage(programOptions.language)) {
620 logger.warn(
621 `The language ${programOptions.language} is not available, falling back to ${I18nEngine.fallbackLanguage}`
622 );
623 }
624
625 if (programOptions.tsconfig && typeof programOptions.tsconfig === 'boolean') {
626 logger.error(`Please provide a tsconfig file.`);
627 process.exit(1);
628 }
629
630 if (configFile.tsconfig) {
631 Configuration.mainData.tsconfig = configFile.tsconfig;
632 }
633 if (programOptions.tsconfig) {
634 Configuration.mainData.tsconfig = programOptions.tsconfig;
635 }
636
637 if (programOptions.maxSearchResults) {
638 Configuration.mainData.maxSearchResults = programOptions.maxSearchResults;
639 }
640
641 if (configFile.files) {
642 scannedFiles = configFile.files;
643 }
644 if (configFile.exclude) {
645 excludeFiles = configFile.exclude;
646 }
647 if (configFile.include) {
648 includeFiles = configFile.include;
649 }
650
651 /**
652 * Check --files argument call
653 */
654 const argv = require('minimist')(process.argv.slice(2));
655 if (argv && argv.files) {
656 Configuration.mainData.hasFilesToCoverage = true;
657 if (typeof argv.files === 'string') {
658 super.setFiles([argv.files]);
659 } else {
660 super.setFiles(argv.files);
661 }
662 }
663
664 if (programOptions.serve && !Configuration.mainData.tsconfig && programOptions.output) {
665 // if -s & -d, serve it
666 if (!FileEngine.existsSync(Configuration.mainData.output)) {
667 logger.error(`${Configuration.mainData.output} folder doesn't exist`);
668 process.exit(1);
669 } else {
670 logger.info(
671 `Serving documentation from ${Configuration.mainData.output} at http://${Configuration.mainData.hostname}:${programOptions.port}`
672 );
673 super.runWebServer(Configuration.mainData.output);
674 }
675 } else if (
676 programOptions.serve &&
677 !Configuration.mainData.tsconfig &&
678 !programOptions.output
679 ) {
680 // if only -s find ./documentation, if ok serve, else error provide -d
681 if (!FileEngine.existsSync(Configuration.mainData.output)) {
682 logger.error('Provide output generated folder with -d flag');
683 process.exit(1);
684 } else {
685 logger.info(
686 `Serving documentation from ${Configuration.mainData.output} at http://${Configuration.mainData.hostname}:${programOptions.port}`
687 );
688 super.runWebServer(Configuration.mainData.output);
689 }
690 } else if (Configuration.mainData.hasFilesToCoverage) {
691 if (programOptions.coverageMinimumPerFile) {
692 logger.info('Run documentation coverage test for files');
693 super.testCoverage();
694 } else {
695 logger.error('Missing coverage configuration');
696 }
697 } else {
698 if (programOptions.hideGenerator) {
699 Configuration.mainData.hideGenerator = true;
700 }
701
702 if (Configuration.mainData.tsconfig && program.args.length === 0) {
703 /**
704 * tsconfig file provided only
705 */
706 let testTsConfigPath = Configuration.mainData.tsconfig.indexOf(process.cwd());
707 if (testTsConfigPath !== -1) {
708 Configuration.mainData.tsconfig = Configuration.mainData.tsconfig.replace(
709 process.cwd() + path.sep,
710 ''
711 );
712 }
713
714 if (!FileEngine.existsSync(Configuration.mainData.tsconfig)) {
715 logger.error(
716 `"${Configuration.mainData.tsconfig}" file was not found in the current directory`
717 );
718 process.exit(1);
719 } else {
720 let _file = path.join(
721 path.join(process.cwd(), path.dirname(Configuration.mainData.tsconfig)),
722 path.basename(Configuration.mainData.tsconfig)
723 );
724 // use the current directory of tsconfig.json as a working directory
725 cwd = _file.split(path.sep).slice(0, -1).join(path.sep);
726 logger.info('Using tsconfig file ', _file);
727
728 let tsConfigFile = readConfig(_file);
729 if (tsConfigFile.files) {
730 scannedFiles = tsConfigFile.files;
731 // Normalize path of these files
732 scannedFiles = scannedFiles.map(scannedFile => {
733 return cwd + path.sep + scannedFile;
734 });
735 }
736
737 // even if files are supplied with "files" attributes, enhance the array with includes
738 excludeFiles = tsConfigFile.exclude || [];
739 includeFiles = tsConfigFile.include || [];
740
741 if (scannedFiles.length > 0) {
742 includeFiles = [...includeFiles, ...scannedFiles];
743 }
744
745 let excludeParser = new ParserUtil(),
746 includeParser = new ParserUtil();
747
748 excludeParser.init(excludeFiles, cwd);
749 includeParser.init(includeFiles, cwd);
750
751 let startCwd = cwd;
752
753 let excludeParserTestFilesWithCwdDepth = excludeParser.testFilesWithCwdDepth();
754 if (!excludeParserTestFilesWithCwdDepth.status) {
755 startCwd = excludeParser.updateCwd(
756 cwd,
757 excludeParserTestFilesWithCwdDepth.level
758 );
759 }
760 let includeParserTestFilesWithCwdDepth = includeParser.testFilesWithCwdDepth();
761 if (!includeParser.testFilesWithCwdDepth().status) {
762 startCwd = includeParser.updateCwd(
763 cwd,
764 includeParserTestFilesWithCwdDepth.level
765 );
766 }
767
768 let finder = require('findit2')(startCwd || '.');
769
770 finder.on('directory', function (dir, stat, stop) {
771 if (ignoreDirectory(dir)) {
772 stop();
773 }
774 });
775
776 finder.on('file', (file, stat) => {
777 if (/(spec|\.d)\.ts/.test(file)) {
778 logger.warn('Ignoring', file);
779 } else if (
780 excludeParser.testFile(file) &&
781 (path.extname(file) === '.ts' || path.extname(file) === '.tsx')
782 ) {
783 logger.warn('Excluding', file);
784 } else if (includeFiles.length > 0) {
785 /**
786 * If include provided in tsconfig, use only this source,
787 * and not files found with global findit scan in working directory
788 */
789 if (
790 (path.extname(file) === '.ts' || path.extname(file) === '.tsx') &&
791 includeParser.testFile(file)
792 ) {
793 logger.debug('Including', file);
794 scannedFiles.push(file);
795 } else {
796 if (path.extname(file) === '.ts' || path.extname(file) === '.tsx') {
797 logger.warn('Excluding', file);
798 }
799 }
800 } else {
801 logger.debug('Including', file);
802 scannedFiles.push(file);
803 }
804 });
805
806 finder.on('end', () => {
807 super.setFiles(scannedFiles);
808 if (programOptions.coverageTest || programOptions.coverageTestPerFile) {
809 logger.info('Run documentation coverage test');
810 super.testCoverage();
811 } else {
812 super.generate();
813 }
814 });
815 }
816 } else if (Configuration.mainData.tsconfig && program.args.length > 0) {
817 /**
818 * tsconfig file provided with source folder in arg
819 */
820 let testTsConfigPath = Configuration.mainData.tsconfig.indexOf(process.cwd());
821 if (testTsConfigPath !== -1) {
822 Configuration.mainData.tsconfig = Configuration.mainData.tsconfig.replace(
823 process.cwd() + path.sep,
824 ''
825 );
826 }
827
828 let sourceFolder = program.args[0];
829 if (!FileEngine.existsSync(sourceFolder)) {
830 logger.error(
831 `Provided source folder ${sourceFolder} was not found in the current directory`
832 );
833 process.exit(1);
834 } else {
835 logger.info('Using provided source folder');
836
837 if (!FileEngine.existsSync(Configuration.mainData.tsconfig)) {
838 logger.error(
839 `"${Configuration.mainData.tsconfig}" file was not found in the current directory`
840 );
841 process.exit(1);
842 } else {
843 let _file = path.join(
844 path.join(process.cwd(), path.dirname(Configuration.mainData.tsconfig)),
845 path.basename(Configuration.mainData.tsconfig)
846 );
847 // use the current directory of tsconfig.json as a working directory
848 cwd = _file.split(path.sep).slice(0, -1).join(path.sep);
849 logger.info('Using tsconfig file ', _file);
850
851 let tsConfigFile = readConfig(_file);
852 if (tsConfigFile.files) {
853 scannedFiles = tsConfigFile.files;
854 // Normalize path of these files
855 scannedFiles = scannedFiles.map(scannedFile => {
856 return cwd + path.sep + scannedFile;
857 });
858 }
859
860 // even if files are supplied with "files" attributes, enhance the array with includes
861 excludeFiles = tsConfigFile.exclude || [];
862 includeFiles = tsConfigFile.include || [];
863
864 if (scannedFiles.length > 0) {
865 includeFiles = [...includeFiles, ...scannedFiles];
866 }
867
868 let excludeParser = new ParserUtil(),
869 includeParser = new ParserUtil();
870
871 excludeParser.init(excludeFiles, cwd);
872 includeParser.init(includeFiles, cwd);
873
874 let startCwd = sourceFolder;
875
876 let excludeParserTestFilesWithCwdDepth =
877 excludeParser.testFilesWithCwdDepth();
878 if (!excludeParserTestFilesWithCwdDepth.status) {
879 startCwd = excludeParser.updateCwd(
880 cwd,
881 excludeParserTestFilesWithCwdDepth.level
882 );
883 }
884 let includeParserTestFilesWithCwdDepth =
885 includeParser.testFilesWithCwdDepth();
886 if (!includeParser.testFilesWithCwdDepth().status) {
887 startCwd = includeParser.updateCwd(
888 cwd,
889 includeParserTestFilesWithCwdDepth.level
890 );
891 }
892
893 let finder = require('findit2')(path.resolve(startCwd));
894
895 finder.on('directory', function (dir, stat, stop) {
896 if (ignoreDirectory(dir)) {
897 stop();
898 }
899 });
900
901 finder.on('file', (file, stat) => {
902 if (/(spec|\.d)\.ts/.test(file)) {
903 logger.warn('Ignoring', file);
904 } else if (excludeParser.testFile(file)) {
905 logger.warn('Excluding', file);
906 } else if (includeFiles.length > 0) {
907 /**
908 * If include provided in tsconfig, use only this source,
909 * and not files found with global findit scan in working directory
910 */
911 if (path.extname(file) === '.ts' && includeParser.testFile(file)) {
912 logger.debug('Including', file);
913 scannedFiles.push(file);
914 } else {
915 if (path.extname(file) === '.ts') {
916 logger.warn('Excluding', file);
917 }
918 }
919 } else {
920 logger.debug('Including', file);
921 scannedFiles.push(file);
922 }
923 });
924
925 finder.on('end', () => {
926 super.setFiles(scannedFiles);
927 if (programOptions.coverageTest || programOptions.coverageTestPerFile) {
928 logger.info('Run documentation coverage test');
929 super.testCoverage();
930 } else {
931 super.generate();
932 }
933 });
934 }
935 }
936 } else {
937 logger.error('tsconfig.json file was not found, please use -p flag');
938 outputHelp();
939 }
940 }
941 }
942}