aboutsummaryrefslogtreecommitdiff
path: root/node_modules/cosmiconfig/dist/createExplorer.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/cosmiconfig/dist/createExplorer.js')
-rw-r--r--node_modules/cosmiconfig/dist/createExplorer.js318
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';
+}