UNPKG

dir-parser

Version:

Parse a directory and generate it's structure tree.

160 lines (149 loc) 7.1 kB
#!/usr/bin/env node const fs = require('fs') const fn = require('funclib') const path = require('path') const program = require('commander') const pkg = require('../package.json') const dirParser = require('../src/dir-parser') program .version(pkg.version) .option('-v, --version', 'output the version number') .option('-c, --config [config]', 'config file, Optional.') .option('-i, --input <input>', 'target directory', './') .option('-o, --output <output>', 'output path', './') .option('-d, --depth <depth>', 'depth of a parse process, 0 means no limit', 0) .option('-l, --lineType <lineType>', 'line type, "s(solid) | d(dash) | ss(short-solid) | sd(short-dash)"', 's') .option('-e, --excludes <excludes..>', 'exclude some directories or files by name.') .option('-x, --excPaths <excPaths..>', 'exclude directories or files by path.') .option('-p, --patterns <patterns...>', 'filter directories or files by RegExp.') .option('-g, --generate [fileName]', 'generate a dir-info file to the output path, "dir-info.txt" is default.') .option('-r, --reverse', 'reverse the parsed dir-tree nodes.') .option('-s, --silent', 'not show the parsed dir-tree in terminal.') .option('-f, --fileFirst', 'print files first, before directories.') .option('-F, --fileOnly', 'pase files only.') .option('-D, --dirOnly', 'pase directories only, and it only takes effect when fileOnly is false.') .option('-I, --ignores <ignores..>', 'ignore some directories or files by name.') .option('-N, --no-dirInfo', 'hide file and directory number info on the result top.') .option('-G, --glob <glob>', 'filter files with glob patterns.') .option('--paths <paths..>', 'filter directories or files by path.') .option('--includes <includes..>', 'filter directories or files by name.') .option('--excPatterns <excPatterns...>', 'exclude directories or files by RegExp.') .option('-H, --Help', 'output chinese usage information.(打印中文帮助信息.)') .parse(process.argv) if (program.Help) { console.log(`用例: dp [参数options] 参数 Options: -V, --version 打印输出版本号。 -v, --version 打印输出版本号。 -c, --config [config] 根据配置文件解析,可选。 -i, --input <input> 指定个目标文件夹,(默认: "./")。 -o, --output <output> 解析结果输出目录,(默认: "./")。 -d, --depth <depth> 解析深度,0表示不限制。(默认: 0)。 -l, --lineType <lineType> 文件树线型, s(solid)、d(dash)、ss(short-solid)、sd(short-dash),(默认: "s")。 -e, --excludes <excludes..> 根据名称排除文件夹或文件。 -x, --excPaths <excPaths..> 根据路径排除文件夹或文件。 -p, --patterns <patterns...> 根据正则解析文件夹或文件。 -g, --generate [fileName] 生成一个解析结果的文件,默认文件名为"dir-info.txt"。 -r, --reverse 生成节点逆序的文件树。 -s, --silent 静默解析,不在控制台输出解析结果。 -f, --fileFirst 先输出文件节点,先于文件夹节点。 -F, --fileOnly 只解析文件。 -D, --dirOnly 只解析文件夹,只有当fileOnly为false时才生效。 -I, --ignores <ignores..> 根据名称忽略一些文件夹或文件。 -N, --no-dirInfo 不在解析结果中显示文件夹和文件的数量信息。 -G, --glob <glob> 使用glob语法过虑文件. --paths <paths..> 根据路径解析文件夹或文件。 --includes <includes..> 根据名称解析文件夹或文件。 --excPatterns <excPatterns...> 根据正则排队文件夹或文件。 -H, --Help 打印中文帮助信息。 -h, --help 打印英语帮助信息。(output usage information)`) return process.exit(0) } let config = {} if (program.config) { config = require(path.resolve(program.config)) } const target = rmQuote(program.input || fn.get(config, 'input', 'str') || path.resolve('./')) const output = rmQuote(program.output || fn.get(config, 'output', 'str') || path.resolve('./')) const lineType = program.lineType || fn.get(config, 'lineType', 'str') || 's' const depth = parseInt(program.depth) || parseInt(fn.get(config, 'depth', 'str')) || 0 const excludes = matchHandler(program.excludes || fn.get(config, 'excludes', 'arr') || [], 'excludes') const excPaths = matchHandler(program.excPaths || fn.get(config, 'excPaths', 'arr') || [], 'excPaths') const excPatterns = matchHandler(program.excPatterns || fn.get(config, 'excPatterns', 'arr') || [], 'excPatterns') const ignores = matchHandler(program.ignores || fn.get(config, 'ignores', 'arr') || [], 'ignores') const includes = matchHandler(program.includes || fn.get(config, 'includes', 'arr') || [], 'includes') const paths = matchHandler(program.paths || fn.get(config, 'paths', 'arr') || [], 'paths') const patterns = matchHandler(program.patterns || fn.get(config, 'patterns', 'arr') || [], 'patterns') const glob = program.glob || fn.get(config, 'glob', 'str') || '' const generate = program.generate || fn.get(config, 'generate') const reverse = program.reverse || fn.get(config, 'reverse', 'bol') const silent = program.silent || fn.get(config, 'silent', 'bol') const fileFirst = program.fileFirst || fn.get(config, 'fileFirst', 'bol') const fileOnly = program.fileOnly || fn.get(config, 'fileOnly', 'bol') const dirOnly = program.dirOnly || fn.get(config, 'dirOnly', 'bol') const dInfo = program.dirInfo || fn.get(config, 'dirInfo', 'bol') const dirInfo = fn.isBol(dInfo) ? dInfo : true const outputName = (fn.isStr(generate) && generate) || 'dir-info.txt' if (!fs.statSync(target).isDirectory()) { throw new Error('Target must be a directory!') } const outputStat = fs.statSync(output) if (!outputStat.isDirectory() && !outputStat.isFile()) { throw new Error('Output must be a file or a directory!') } if (outputStat.isDirectory()) { outputFile = path.join(output, outputName) } // excPaths.push(outputFile); /** * Format the target and output */ function rmQuote(str) { return str.replace(/^['"`]|['"`]$/gm, '') } /** * Format the matchs */ function matchHandler(match, type_) { if (fn.typeOf(match, 'str')) { match = rmQuote(match) if (match.startsWith('[')) { try { eval('match =' + match) } catch (e) { match = fn.get(config, type_, 'arr') || [] } } else { match = match.replace(/,/gm, ' ').split(' ') } } return fn.toArr(match) } /** * Parse target dir by options */ dirParser(target, { depth, reverse, lineType, excludes, excPaths, excPatterns, ignores, includes, paths, patterns, dirInfo, fileFirst, fileOnly, dirOnly, glob, }).then( (parsed) => { if (!silent) console.log(parsed.dirTree) if (generate || silent) fn.wt(outputFile, parsed.dirTree) }, (error) => { console.log(fn.chalk(error.message, 'red')) } )