1 | #!/usr/bin/env node
|
2 |
|
3 | const fs = require('fs');
|
4 | const fn = require('funclib');
|
5 | const path = require('path');
|
6 | const program = require('commander');
|
7 | const package = require('../package.json');
|
8 | const parser = require('../src/dir-parser');
|
9 |
|
10 | program.version(package.version)
|
11 | .option('-v, --version', 'output the version number')
|
12 | .option('-c, --config [config]', 'config file, Optional.')
|
13 | .option('-i, --input <input>', 'target directory', './')
|
14 | .option('-o, --output <output>', 'output path', './')
|
15 | .option('-d, --depth <depth>', 'depth of a parse process, 0 means no limit', 0)
|
16 | .option('-l, --lineType <lineType>', 'line type of tree, "dash" or "solid"', 'solid')
|
17 | .option('-e, --excludes <excludes..>', 'exclude some directories or files by name.')
|
18 | .option('-x, --excPaths <excPaths..>', 'exclude directories or files by path.')
|
19 | .option('-p, --patterns <patterns...>', 'filter directories or files by RegExp.')
|
20 | .option('-g, --generate [fileName]', 'generate a dir-info file to the output path, "dir-info.txt" is default.')
|
21 | .option('-r, --reverse', 'reverse the parsed dir-tree nodes.')
|
22 | .option('-s, --silent', 'not show the parsed dir-tree in terminal.')
|
23 | .option('-f, --fileFirst', 'print files first, before directories.')
|
24 | .option('-F, --fileOnly', 'pase files only.')
|
25 | .option('-D, --dirOnly', 'pase directories only, and it only takes effect when fileOnly is false.')
|
26 | .option('-I, --ignores <ignores..>', 'ignore some directories or files by name.')
|
27 | .option('-N, --no-dirInfo', 'hide file and directory number info on the result top.')
|
28 | .option('-G, --glob <glob>', 'filter files with glob patterns.')
|
29 | .option('--paths <paths..>', 'filter directories or files by path.')
|
30 | .option('--includes <includes..>', 'filter directories or files by name.')
|
31 | .option('--excPatterns <excPatterns...>', 'exclude directories or files by RegExp.')
|
32 | .option('-H, --Help', 'output chinese usage information.(打印中文帮助信息.)')
|
33 | .parse(process.argv);
|
34 |
|
35 | if (program.Help) {
|
36 | console.log(`用例: parser [参数options]
|
37 |
|
38 | 参数 Options:
|
39 | -V, --version 打印输出版本号。
|
40 | -v, --version 打印输出版本号。
|
41 | -c, --config [config] 根据配置文件解析,可选。
|
42 | -i, --input <input> 指定个目标文件夹,(默认: "./")。
|
43 | -o, --output <output> 解析结果输出目录,(默认: "./")。
|
44 | -d, --depth <depth> 解析深度,0表示不限制。(默认: 0)。
|
45 | -l, --lineType <lineType> 生成的文件树线型, "dash" 或 "solid",(默认: "solid")。
|
46 | -e, --excludes <excludes..> 根据名称排除文件夹或文件。
|
47 | -x, --excPaths <excPaths..> 根据路径排除文件夹或文件。
|
48 | -p, --patterns <patterns...> 根据正则解析文件夹或文件。
|
49 | -g, --generate [fileName] 生成一个解析结果的文件,默认文件名为"dir-info.txt"。
|
50 | -r, --reverse 生成节点逆序的文件树。
|
51 | -s, --silent 静默解析,不在控制台输出解析结果。
|
52 | -f, --fileFirst 先输出文件节点,先于文件夹节点。
|
53 | -F, --fileOnly 只解析文件。
|
54 | -D, --dirOnly 只解析文件夹,只有当fileOnly为false时才生效。
|
55 | -I, --ignores <ignores..> 根据名称忽略一些文件夹或文件。
|
56 | -N, --no-dirInfo 不在解析结果中显示文件夹和文件的数量信息。
|
57 | -G, --glob <glob> 使用glob语法过虑文件.
|
58 | --paths <paths..> 根据路径解析文件夹或文件。
|
59 | --includes <includes..> 根据名称解析文件夹或文件。
|
60 | --excPatterns <excPatterns...> 根据正则排队文件夹或文件。
|
61 | -H, --Help 打印中文帮助信息。
|
62 | -h, --help 打印英语帮助信息。(output usage information)`);
|
63 | return process.exit(0);
|
64 | }
|
65 |
|
66 | let config = {};
|
67 | if (program.config) {
|
68 | config = require(path.resolve(program.config));
|
69 | }
|
70 |
|
71 | const target = rmQuote(program.input || fn.get(config, 'input', 'str') || path.resolve('./'));
|
72 | const output = rmQuote(program.output || fn.get(config, 'output', 'str') || path.resolve('./'));
|
73 | const lineType = program.lineType || fn.get(config, 'lineType', 'str') || 'solid';
|
74 | const depth = parseInt(program.depth) || parseInt(fn.get(config, 'depth', 'str')) || 0;
|
75 | const excludes = matchHandler(program.excludes || fn.get(config, 'excludes', 'arr') || [], 'excludes');
|
76 | const excPaths = matchHandler(program.excPaths || fn.get(config, 'excPaths', 'arr') || [], 'excPaths');
|
77 | const excPatterns = matchHandler(program.excPatterns || fn.get(config, 'excPatterns', 'arr') || [], 'excPatterns');
|
78 | const ignores = matchHandler(program.ignores || fn.get(config, 'ignores', 'arr') || [], 'ignores');
|
79 | const includes = matchHandler(program.includes || fn.get(config, 'includes', 'arr') || [], 'includes');
|
80 | const paths = matchHandler(program.paths || fn.get(config, 'paths', 'arr') || [], 'paths');
|
81 | const patterns = matchHandler(program.patterns || fn.get(config, 'patterns', 'arr') || [], 'patterns');
|
82 | const glob = program.glob || fn.get(config, 'glob', 'str') || '';
|
83 | const generate = program.generate || fn.get(config, 'generate');
|
84 | const reverse = program.reverse || fn.get(config, 'reverse', 'bol');
|
85 | const silent = program.silent || fn.get(config, 'silent', 'bol');
|
86 | const fileFirst = program.fileFirst || fn.get(config, 'fileFirst', 'bol');
|
87 | const fileOnly = program.fileOnly || fn.get(config, 'fileOnly', 'bol');
|
88 | const dirOnly = program.dirOnly || fn.get(config, 'dirOnly', 'bol');
|
89 | const dInfo = program.dirInfo || fn.get(config, 'dirInfo', 'bol');
|
90 | const dirInfo = fn.isBol(dInfo) ? dInfo : true;
|
91 | const outputName = fn.isStr(generate) && generate || 'dir-info.txt';
|
92 |
|
93 | if (!fs.statSync(target).isDirectory()) {
|
94 | throw new Error('Target must be a directory!')
|
95 | }
|
96 | const outputStat = fs.statSync(output);
|
97 | if (!outputStat.isDirectory() && !outputStat.isFile()) {
|
98 | throw new Error('Output must be a file or a directory!')
|
99 | }
|
100 | if (outputStat.isDirectory()) {
|
101 | outputFile = path.join(output, outputName)
|
102 | }
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | function rmQuote(str) {
|
109 | return str.replace(/^['"`]|['"`]$/mg, '');
|
110 | }
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | function matchHandler(match, type_) {
|
116 | if (fn.typeOf(match, 'str')) {
|
117 | match = rmQuote(match);
|
118 | if (match.startsWith('[')) {
|
119 | try {
|
120 | eval('match =' + match);
|
121 | } catch (e) {
|
122 | match = fn.get(config, type_, 'arr') || [];
|
123 | }
|
124 | } else {
|
125 | match = match.replace(/,/mg, ' ').split(' ');
|
126 | }
|
127 | }
|
128 | return fn.toArr(match);
|
129 | }
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 | parser(target, {
|
143 | depth, reverse, lineType, excludes, excPaths, excPatterns, ignores,
|
144 | includes, paths, patterns, dirInfo, fileFirst, fileOnly, dirOnly, glob,
|
145 | }).then(
|
146 | parsed => {
|
147 | if (!silent) console.log(parsed.dirTree);
|
148 | if (generate || silent) fn.wt(outputFile, parsed.dirTree);
|
149 | },
|
150 | error => {
|
151 | console.log(fn.chalk(error.message, 'red'));
|
152 | }
|
153 | );
|