diff options
Diffstat (limited to 'node_modules/cosmiconfig/dist/createExplorer.js')
| -rw-r--r-- | node_modules/cosmiconfig/dist/createExplorer.js | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/node_modules/cosmiconfig/dist/createExplorer.js b/node_modules/cosmiconfig/dist/createExplorer.js new file mode 100644 index 00000000..2cca5e7c --- /dev/null +++ b/node_modules/cosmiconfig/dist/createExplorer.js @@ -0,0 +1,318 @@ +// +'use strict'; + +const path = require('path'); +const loaders = require('./loaders'); +const readFile = require('./readFile'); +const cacheWrapper = require('./cacheWrapper'); +const getDirectory = require('./getDirectory'); + +const MODE_SYNC = 'sync'; + +// An object value represents a config object. +// null represents that the loader did not find anything relevant. +// undefined represents that the loader found something relevant +// but it was empty. + + +class Explorer { + + + + + + + constructor(options ) { + this.loadCache = options.cache ? new Map() : null; + this.loadSyncCache = options.cache ? new Map() : null; + this.searchCache = options.cache ? new Map() : null; + this.searchSyncCache = options.cache ? new Map() : null; + this.config = options; + this.validateConfig(); + } + + clearLoadCache() { + if (this.loadCache) { + this.loadCache.clear(); + } + if (this.loadSyncCache) { + this.loadSyncCache.clear(); + } + } + + clearSearchCache() { + if (this.searchCache) { + this.searchCache.clear(); + } + if (this.searchSyncCache) { + this.searchSyncCache.clear(); + } + } + + clearCaches() { + this.clearLoadCache(); + this.clearSearchCache(); + } + + validateConfig() { + const config = this.config; + + config.searchPlaces.forEach(place => { + const loaderKey = path.extname(place) || 'noExt'; + const loader = config.loaders[loaderKey]; + if (!loader) { + throw new Error( + `No loader specified for ${getExtensionDescription( + place + )}, so searchPlaces item "${place}" is invalid` + ); + } + }); + } + + search(searchFrom ) { + searchFrom = searchFrom || process.cwd(); + return getDirectory(searchFrom).then(dir => { + return this.searchFromDirectory(dir); + }); + } + + searchFromDirectory(dir ) { + const absoluteDir = path.resolve(process.cwd(), dir); + const run = () => { + return this.searchDirectory(absoluteDir).then(result => { + const nextDir = this.nextDirectoryToSearch(absoluteDir, result); + if (nextDir) { + return this.searchFromDirectory(nextDir); + } + return this.config.transform(result); + }); + }; + + if (this.searchCache) { + return cacheWrapper(this.searchCache, absoluteDir, run); + } + return run(); + } + + searchSync(searchFrom ) { + searchFrom = searchFrom || process.cwd(); + const dir = getDirectory.sync(searchFrom); + return this.searchFromDirectorySync(dir); + } + + searchFromDirectorySync(dir ) { + const absoluteDir = path.resolve(process.cwd(), dir); + const run = () => { + const result = this.searchDirectorySync(absoluteDir); + const nextDir = this.nextDirectoryToSearch(absoluteDir, result); + if (nextDir) { + return this.searchFromDirectorySync(nextDir); + } + return this.config.transform(result); + }; + + if (this.searchSyncCache) { + return cacheWrapper(this.searchSyncCache, absoluteDir, run); + } + return run(); + } + + searchDirectory(dir ) { + return this.config.searchPlaces.reduce((prevResultPromise, place) => { + return prevResultPromise.then(prevResult => { + if (this.shouldSearchStopWithResult(prevResult)) { + return prevResult; + } + return this.loadSearchPlace(dir, place); + }); + }, Promise.resolve(null)); + } + + searchDirectorySync(dir ) { + let result = null; + for (const place of this.config.searchPlaces) { + result = this.loadSearchPlaceSync(dir, place); + if (this.shouldSearchStopWithResult(result)) break; + } + return result; + } + + shouldSearchStopWithResult(result ) { + if (result === null) return false; + if (result.isEmpty && this.config.ignoreEmptySearchPlaces) return false; + return true; + } + + loadSearchPlace(dir , place ) { + const filepath = path.join(dir, place); + return readFile(filepath).then(content => { + return this.createCosmiconfigResult(filepath, content); + }); + } + + loadSearchPlaceSync(dir , place ) { + const filepath = path.join(dir, place); + const content = readFile.sync(filepath); + return this.createCosmiconfigResultSync(filepath, content); + } + + nextDirectoryToSearch( + currentDir , + currentResult + ) { + if (this.shouldSearchStopWithResult(currentResult)) { + return null; + } + const nextDir = nextDirUp(currentDir); + if (nextDir === currentDir || currentDir === this.config.stopDir) { + return null; + } + return nextDir; + } + + loadPackageProp(filepath , content ) { + const parsedContent = loaders.loadJson(filepath, content); + const packagePropValue = parsedContent[this.config.packageProp]; + return packagePropValue || null; + } + + getLoaderEntryForFile(filepath ) { + if (path.basename(filepath) === 'package.json') { + const loader = this.loadPackageProp.bind(this); + return { sync: loader, async: loader }; + } + + const loaderKey = path.extname(filepath) || 'noExt'; + return this.config.loaders[loaderKey] || {}; + } + + getSyncLoaderForFile(filepath ) { + const entry = this.getLoaderEntryForFile(filepath); + if (!entry.sync) { + throw new Error( + `No sync loader specified for ${getExtensionDescription(filepath)}` + ); + } + return entry.sync; + } + + getAsyncLoaderForFile(filepath ) { + const entry = this.getLoaderEntryForFile(filepath); + const loader = entry.async || entry.sync; + if (!loader) { + throw new Error( + `No async loader specified for ${getExtensionDescription(filepath)}` + ); + } + return loader; + } + + loadFileContent( + mode , + filepath , + content + ) { + if (content === null) { + return null; + } + if (content.trim() === '') { + return undefined; + } + const loader = + mode === MODE_SYNC + ? this.getSyncLoaderForFile(filepath) + : this.getAsyncLoaderForFile(filepath); + return loader(filepath, content); + } + + loadedContentToCosmiconfigResult( + filepath , + loadedContent + ) { + if (loadedContent === null) { + return null; + } + if (loadedContent === undefined) { + return { filepath, config: undefined, isEmpty: true }; + } + return { config: loadedContent, filepath }; + } + + createCosmiconfigResult( + filepath , + content + ) { + return Promise.resolve() + .then(() => { + return this.loadFileContent('async', filepath, content); + }) + .then(loaderResult => { + return this.loadedContentToCosmiconfigResult(filepath, loaderResult); + }); + } + + createCosmiconfigResultSync( + filepath , + content + ) { + const loaderResult = this.loadFileContent('sync', filepath, content); + return this.loadedContentToCosmiconfigResult(filepath, loaderResult); + } + + validateFilePath(filepath ) { + if (!filepath) { + throw new Error('load and loadSync must pass a non-empty string'); + } + } + + load(filepath ) { + return Promise.resolve().then(() => { + this.validateFilePath(filepath); + const absoluteFilePath = path.resolve(process.cwd(), filepath); + return cacheWrapper(this.loadCache, absoluteFilePath, () => { + return readFile(absoluteFilePath, { throwNotFound: true }) + .then(content => { + return this.createCosmiconfigResult(absoluteFilePath, content); + }) + .then(this.config.transform); + }); + }); + } + + loadSync(filepath ) { + this.validateFilePath(filepath); + const absoluteFilePath = path.resolve(process.cwd(), filepath); + return cacheWrapper(this.loadSyncCache, absoluteFilePath, () => { + const content = readFile.sync(absoluteFilePath, { throwNotFound: true }); + const result = this.createCosmiconfigResultSync( + absoluteFilePath, + content + ); + return this.config.transform(result); + }); + } +} + +module.exports = function createExplorer(options ) { + const explorer = new Explorer(options); + + return { + search: explorer.search.bind(explorer), + searchSync: explorer.searchSync.bind(explorer), + load: explorer.load.bind(explorer), + loadSync: explorer.loadSync.bind(explorer), + clearLoadCache: explorer.clearLoadCache.bind(explorer), + clearSearchCache: explorer.clearSearchCache.bind(explorer), + clearCaches: explorer.clearCaches.bind(explorer), + }; +}; + +function nextDirUp(dir ) { + return path.dirname(dir); +} + +function getExtensionDescription(filepath ) { + const ext = path.extname(filepath); + return ext ? `extension "${ext}"` : 'files without extensions'; +} |
