diff --git a/src/config.js b/src/config.js new file mode 100644 index 0000000..664c6f9 --- /dev/null +++ b/src/config.js @@ -0,0 +1,15 @@ +const emoji = { + directory: '📁', + file: '📄', +} +const characters = { + border: '|', + contain: '├', + line: '─', + last: '└' +} + +module.exports = { + emoji, + characters, +} \ No newline at end of file diff --git a/src/generate.js b/src/generate.js new file mode 100644 index 0000000..19d60f3 --- /dev/null +++ b/src/generate.js @@ -0,0 +1,28 @@ +const { emoji, characters } = require('./config') +const { isNumber } = require('./utils') + +function generate(data, options = {}, deep = 0) { + if (isNumber(options.level) && deep >= options.level) { + return '' + } + let output = '' + + data.forEach((item, index) => { + const borderPrefix = (characters.border + ' '.repeat(3)).repeat(deep) + let contentPrefix = index === data.length - 1 ? characters.last : characters.contain + contentPrefix += characters.line.repeat(2) + const content = options.icon ? `${emoji[item.type]}${item.name}` : `${item.name}` + + let currentLineStr = `${borderPrefix}${contentPrefix}${content}` + currentLineStr += '\n' + output += currentLineStr + + if (item.children) { // directory + output += generate(item.children, options, deep + 1) + } + }) + + return output +} + +module.exports = generate \ No newline at end of file diff --git a/src/index.js b/src/index.js index 1d38bea..f92cfa6 100644 --- a/src/index.js +++ b/src/index.js @@ -2,20 +2,11 @@ const fs = require('fs') const { program } = require('commander') -const { fileExistSync, isDirectory } = require('./utils') +const { fileExistSync } = require('./utils') +const toTree = require('./toTree') +const generate = require('./generate') const package = require('../package.json') -const map = { - directory: '📁', - file: '📄', -} -const characters = { - border: '|', - contain: '├', - line: '─', - last: '└' -} - program .name('treei') .version(package.version) @@ -30,85 +21,34 @@ program const options = program.opts() -let ignoreList = [] -if (options.ignore) { - ignoreList = options.ignore.replace(/\s*/g, '').split(/,|\|/) -} - -// The difference between statSync and lstatSync -// https://stackoverflow.com/questions/32478698/what-is-the-different-between-stat-fstat-and-lstat-functions-in-node-js +const onExits = [] -function toTree(path, deep = 0) { - if (isDirectory(path)) { - let dir = fs.readdirSync(path) - - if (ignoreList.length) { - dir = dir.filter(child => !ignoreList.includes(child)) - } - if (options.onlyFolder) { - dir = dir.filter(child => isDirectory(`${path}/${child}`)) - } - const children = dir.map(child => toTree(`${path}/${child}`, deep + 1)) - const dirName = path.split('/').pop() - - return { - type: 'directory', - name: dirName, - children, - } - } else { - return { - type: 'file', - name: path.split('/').pop(), - } +function handleOptions() { + if (options.ignore) { + options.ignore = options.ignore.replace(/\s*/g, '').split(/,|\|/) + } + if (options.level && !Number.isNaN(parseInt(options.level))) { + options.level = parseInt(options.level) + } + if (options.output) { + onExits.push((result) => { + let outputString = result + if (fileExistSync(options.output)) { // appending mode + outputString = '\n' + result + } + fs.appendFile(options.output, outputString, (err) => { + if (err) throw err + }) + }) } } -const root = toTree(options.directory) - -let level -if (options.level && !Number.isNaN(parseInt(options.level))) { - level = parseInt(options.level) -} - -function isReachedDepth(deep) { - return typeof level === 'number' && deep >= level -} - -let output = '' - -function generateTreeStructure(data, deep = 0) { - if (isReachedDepth(deep)) return +handleOptions() - data.forEach((item, index) => { - const borderPrefix = (characters.border + ' '.repeat(3)).repeat(deep) - let contentPrefix = index === data.length - 1 ? characters.last : characters.contain - contentPrefix += characters.line.repeat(2) - const content = options.icon ? `${map[item.type]}${item.name}` : `${item.name}` - let currentLineStr = `${borderPrefix}${contentPrefix}${content}` +const root = toTree(options.directory, options) +const result = generate(root.children, options) - currentLineStr += '\n' - - if (item.children) { // directory - output += currentLineStr - generateTreeStructure(item.children, deep + 1) - } else { // file - output += currentLineStr - } - }) -} - -generateTreeStructure(root.children) - -if (options.output) { - let outputString = output - if (fileExistSync(options.output)) { // appending mode - outputString = '\n' + output - } - fs.appendFile(options.output, outputString, (err) => { - if (err) throw err - }) -} +onExits.forEach(onExit => onExit(result)) console.log(root.name) -console.log(output) \ No newline at end of file +console.log(result) \ No newline at end of file diff --git a/src/toTree.js b/src/toTree.js new file mode 100644 index 0000000..a279501 --- /dev/null +++ b/src/toTree.js @@ -0,0 +1,34 @@ +const fs = require('fs') +const { isDirectory } = require('./utils') + +// The difference between statSync and lstatSync +// https://stackoverflow.com/questions/32478698/what-is-the-different-between-stat-fstat-and-lstat-functions-in-node-js + +function toTree(path, options = {}) { + if (isDirectory(path)) { + let dir = fs.readdirSync(path) + const ignoreList = options.ignore || [] + + if (ignoreList.length) { + dir = dir.filter(child => !ignoreList.includes(child)) + } + if (options.onlyFolder) { + dir = dir.filter(child => isDirectory(`${path}/${child}`)) + } + const children = dir.map(child => toTree(`${path}/${child}`)) + const dirName = path.split('/').pop() + + return { + type: 'directory', + name: dirName, + children, + } + } else { + return { + type: 'file', + name: path.split('/').pop(), + } + } +} + +module.exports = toTree \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index 82256f4..da28ccf 100644 --- a/src/utils.js +++ b/src/utils.js @@ -15,7 +15,12 @@ function isDirectory(path) { return stats.isDirectory() } +function isNumber(value) { + return typeof value === 'number' +} + module.exports = { fileExistSync, isDirectory, + isNumber, } \ No newline at end of file