find-up通过查找父目录来查找文件或者目录,官方给的说明是:Find a file or directory by walking up parent directories 安装
$ npm install find-up
使用示例
example.js
const path = require('path');
const findUp = require('find-up');
(async () => {
console.log(await findUp('unicorn.png'));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(['rainbow.png', 'unicorn.png']));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(async directory => {
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();
话不多说,直接上干货,源码:
'use strict';
const path = require('path');
const locatePath = require('locate-path');
const pathExists = require('path-exists');
const stop = Symbol('findUp.stop');
module.exports = async (name, options = {}) => {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const paths = [].concat(name);
const runMatcher = async locateOptions => {
if (typeof name !== 'function') {
return locatePath(paths, locateOptions);
}
const foundPath = await name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath([foundPath], locateOptions);
}
return foundPath;
};
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line no-await-in-loop
const foundPath = await runMatcher({...options, cwd: directory});
if (foundPath === stop) {
return;
}
if (foundPath) {
return path.resolve(directory, foundPath);
}
if (directory === root) {
return;
}
directory = path.dirname(directory);
}
};
module.exports.sync = (name, options = {}) => {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const paths = [].concat(name);
const runMatcher = locateOptions => {
if (typeof name !== 'function') {
return locatePath.sync(paths, locateOptions);
}
const foundPath = name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath.sync([foundPath], locateOptions);
}
return foundPath;
};
// eslint-disable-next-line no-constant-condition
while (true) {
const foundPath = runMatcher({...options, cwd: directory});
if (foundPath === stop) {
return;
}
if (foundPath) {
return path.resolve(directory, foundPath);
}
if (directory === root) {
return;
}
directory = path.dirname(directory);
}
};
module.exports.exists = pathExists;
module.exports.sync.exists = pathExists.sync;
module.exports.stop = stop;
我们看到,总共导出了5个方法,我们逐句分析:
- 模块引入:
- path:Node.js的内置模块,提供了处理文件和目录路径的功能。
- locatePath:用于查找给定路径数组中的第一个存在的路径。
- pathExists:用于检测路径是否存在。
- stop符号:
- 定义了一个特殊符号stop,用于在查找过程中停止查找操作。
- 异步查找函数:
- module.exports = async (name, options = {}) => { ... }:导出了一个异步函数,这个函数需要两个参数:name(需要查找的文件或路径名称)和 options(可选配置)。
- let directory = path.resolve(options.cwd || ''):将当前工作目录解析为绝对路径。
- const {root} = path.parse(directory):从当前目录中获取文件系统的根目录。
- 路径查找的主要逻辑:
- const paths = [].cancat(name):将name包装为数组,支持单个字符串和数组形式的输入。
- 定义了一个异步函数runMatcher,用于匹配路径。如果name不是一个函数,则调用locatePath来查找路径;如果是函数,则调用该函数并传入当前工作目录以获取路径。
- 使用无限循环while(true)来逐层查找路径,直到找到符合条件的路径或到达根目录。
- 查找过程:
- 在循环中,调用 runMatcher 来查找当前目录的路径。
- 如果找到的路径为 stop,则终止查找。
- 如果找到有效路径,则返回该路径;如果当前目录是根目录且仍未找到,则返回 undefined。
- 若未找到,则将目录更改为其父目录,持续进行查找。
整体来看,该模块实现了一个向上查找文件或路径的功能,支持通过异步方式进行查找,便于在文件系统中寻找特定的文件或目录。