UNPKG

hiproxy

Version:

hiproxy - lightweight and powerful proxy tool for front-end developer based on Node.js.

147 lines (119 loc) 4.81 kB
/** * @file find file by file name pattern * @author zdying */ 'use strict'; var fs = require('fs'); var path = require('path'); /** * 通过文件路径模式查找文件 * 语法支持的通配符:`*`, `?`, `[abc]`, `[a-z]`, `[^a-z]`, `[!a-z]` * 不支持:`**` * https://en.wikipedia.org/wiki/Glob_(programming) * * @param {Array|String} patterns 要匹配的模式 * @param {String} [root=process.cwd()] 相对路径的根目录 * @param {Boolean} [ignoreCase=false] 是否忽略大小写,默认区分大小写 * @returns {Array} 满足条件的文件列表 */ module.exports = function (patterns, root, ignoreCase) { var result = []; root = root || process.cwd(); if (!Array.isArray(patterns)) { result = glob(patterns, root, ignoreCase); } else { result = [].concat.apply([], patterns.map(function (pattern) { return glob(pattern, root, ignoreCase); })); } var uniqueResult = []; result.forEach(function (res) { if (uniqueResult.indexOf(res) === -1) { uniqueResult.push(res); } }); return uniqueResult; }; function glob (pattern, root, ignoreCase) { if (pattern.charAt(pattern.length - 1) === '/') { throw Error('File pattern should not be directory.'); } pattern = path.resolve(root, pattern); pattern = pattern // 里面的`.(){}`一定是`.(){}`这些字符 .replace(/([.(){}])/g, '\\$1') // * ==> 一个或者多个字符 .replace(/\*/g, '.+') // ? ==> 一个字符 .replace(/\?/g, '.') // [!xyz] ==> [^xyz],`!`等价于`^` .replace(/\[!([^\]]+)\]/, '[^$1]'); var dirname = pattern; var basename = ''; // 第一个存在的目录 var start = ''; // start后面的剩下的basename数组 var basenames = []; // 首先找到第一个实际存在的目录,以`/Users/zdying/github/*/*.md`为例: // 第一个存在的目录为: `/Users/zdying/github/` // 剩下的basename数组为: `['.+', '.+.md']`(已经转换成正则表达式了,原内容为`['*', '*.md']`) // // 然后在第一个存在的目录里面开始文件查找,查找到的文件根据层级,跟basenames对比,比如: // `/Users/zdying/github/`下存在:`docs`/`guides`/`LICENSE.md`,前两个为目录,后一个为文件。 // 首先把目录`docs`跟`.+`比较,看是否匹配,如果匹配继续遍历。假设`docs`下存在`get_start.md`, // 然后将`get_start.md`跟`.+.md`比较,如果匹配,那么`get_start.md`为满足条件的文件。 // +---------------------------------------------+ // | /Users/zdying/github/ * / *.md | // +--------------------------+--------+---------+ // | | // +--------------------------v--------v---------+ // | /Users/zdying/github/ docs / get_start.md | // +---------------------------------------------+ while (true) { basename = path.basename(dirname); dirname = path.dirname(dirname); basenames.unshift(basename); if (dirname === '/') { break; } if (fs.existsSync(dirname)) { start = dirname; break; } } function walk (startDir, deep) { var files = fs.readdirSync(startDir); var matched = []; files.forEach(function (file) { var currPath = path.join(startDir, file); var state = fs.statSync(currPath); // 是否是文件模式(最后一个basename) var isFilePattern = deep === basenames.length - 1; var reg = new RegExp('^' + basenames[deep] + '$', ignoreCase ? 'i' : ''); if (!isFilePattern && state.isDirectory() && reg.test(file)) { // 当前`文件`是目录,并且不是文件模式,并且匹配当前的basename,继续遍历目录 matched = matched.concat(walk(currPath, deep + 1)); } else if (isFilePattern && state.isFile() && reg.test(file)) { // 当前`文件`是文件,并且是文件模式,并且匹配当前的basename,放到结果中 matched.push(currPath); } }); return matched; } var result = walk(start, 0); // console.log({ // start: start, // basenames: basenames, // result: result // }); return result; } // console.log(module.exports('/Users/zdy/github/hiproxy/*/*.Md', null, true)); // console.log(module.exports('/Users/zdy/github/hiproxy/*/[^_0-9]+.md')); // console.log(module.exports('/Users/zdy/github/hiproxy/*/[!_0-9]+.md')); // console.log(module.exports('./*/*.Md', null, true)); // console.log(module.exports('./*/[^_0-9]+.md')); // console.log(module.exports('../hiproxy/*/[!_0-9]+.md')); // console.log(module.exports('./doc/[_a-z]+.md')); // console.log(module.exports(['./*/*.md', './.*'])); // console.log(module.exports(['README.md', './*.md', './test/testServer.js', './doc/*.js', './.*'], './'));