160 lines
4.3 KiB
JavaScript
160 lines
4.3 KiB
JavaScript
//
|
|
'use strict';
|
|
|
|
const path = require('path');
|
|
const loadPackageProp = require('./loadPackageProp');
|
|
const loadRc = require('./loadRc');
|
|
const loadJs = require('./loadJs');
|
|
const loadDefinedFile = require('./loadDefinedFile');
|
|
const funcRunner = require('./funcRunner');
|
|
const getDirectory = require('./getDirectory');
|
|
|
|
module.exports = function createExplorer(options
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
) {
|
|
// When `options.sync` is `false` (default),
|
|
// these cache Promises that resolve with results, not the results themselves.
|
|
const fileCache = options.cache ? new Map() : null;
|
|
const directoryCache = options.cache ? new Map() : null;
|
|
const transform = options.transform || identity;
|
|
const packageProp = options.packageProp;
|
|
|
|
function clearFileCache() {
|
|
if (fileCache) fileCache.clear();
|
|
}
|
|
|
|
function clearDirectoryCache() {
|
|
if (directoryCache) directoryCache.clear();
|
|
}
|
|
|
|
function clearCaches() {
|
|
clearFileCache();
|
|
clearDirectoryCache();
|
|
}
|
|
|
|
function throwError(error) {
|
|
if (options.sync) {
|
|
throw error;
|
|
} else {
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
|
|
function load(
|
|
searchPath ,
|
|
configPath
|
|
) {
|
|
if (!searchPath) searchPath = process.cwd();
|
|
if (!configPath && options.configPath) configPath = options.configPath;
|
|
|
|
if (configPath) {
|
|
const absoluteConfigPath = path.resolve(process.cwd(), configPath);
|
|
if (fileCache && fileCache.has(absoluteConfigPath)) {
|
|
return fileCache.get(absoluteConfigPath);
|
|
}
|
|
|
|
let load;
|
|
if (path.basename(absoluteConfigPath) === 'package.json') {
|
|
if (!packageProp) {
|
|
return throwError(
|
|
new Error(
|
|
'Please specify the packageProp option. The configPath argument cannot point to a package.json file if packageProp is false.'
|
|
)
|
|
);
|
|
}
|
|
load = () =>
|
|
loadPackageProp(path.dirname(absoluteConfigPath), {
|
|
packageProp,
|
|
sync: options.sync,
|
|
});
|
|
} else {
|
|
load = () =>
|
|
loadDefinedFile(absoluteConfigPath, {
|
|
sync: options.sync,
|
|
format: options.format,
|
|
});
|
|
}
|
|
|
|
const loadResult = load();
|
|
const result =
|
|
loadResult instanceof Promise
|
|
? loadResult.then(transform)
|
|
: transform(loadResult);
|
|
if (fileCache) fileCache.set(absoluteConfigPath, result);
|
|
return result;
|
|
}
|
|
|
|
const absoluteSearchPath = path.resolve(process.cwd(), searchPath);
|
|
const searchPathDir = getDirectory(absoluteSearchPath, options.sync);
|
|
|
|
return searchPathDir instanceof Promise
|
|
? searchPathDir.then(searchDirectory)
|
|
: searchDirectory(searchPathDir);
|
|
}
|
|
|
|
function searchDirectory(
|
|
directory
|
|
) {
|
|
if (directoryCache && directoryCache.has(directory)) {
|
|
return directoryCache.get(directory);
|
|
}
|
|
|
|
const result = funcRunner(!options.sync ? Promise.resolve() : undefined, [
|
|
() => {
|
|
if (!packageProp) return;
|
|
return loadPackageProp(directory, {
|
|
packageProp,
|
|
sync: options.sync,
|
|
});
|
|
},
|
|
result => {
|
|
if (result || !options.rc) return result;
|
|
return loadRc(path.join(directory, options.rc), {
|
|
sync: options.sync,
|
|
rcStrictJson: options.rcStrictJson,
|
|
rcExtensions: options.rcExtensions,
|
|
});
|
|
},
|
|
result => {
|
|
if (result || !options.js) return result;
|
|
return loadJs(path.join(directory, options.js), { sync: options.sync });
|
|
},
|
|
result => {
|
|
if (result) return result;
|
|
|
|
const nextDirectory = path.dirname(directory);
|
|
|
|
if (nextDirectory === directory || directory === options.stopDir)
|
|
return null;
|
|
|
|
return searchDirectory(nextDirectory);
|
|
},
|
|
transform,
|
|
]);
|
|
|
|
if (directoryCache) directoryCache.set(directory, result);
|
|
return result;
|
|
}
|
|
|
|
return {
|
|
load,
|
|
clearFileCache,
|
|
clearDirectoryCache,
|
|
clearCaches,
|
|
};
|
|
};
|
|
|
|
function identity(x) {
|
|
return x;
|
|
}
|