You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							166 lines
						
					
					
						
							4.2 KiB
						
					
					
				
			
		
		
	
	
							166 lines
						
					
					
						
							4.2 KiB
						
					
					
				'use strict'; | 
						|
 | 
						|
const fs = require('fs'); | 
						|
const path = require('path'); | 
						|
const {promisify} = require('util'); | 
						|
const camelcase = require('camelcase'); | 
						|
const findUp = require('find-up'); | 
						|
const resolveFrom = require('resolve-from'); | 
						|
const getPackageType = require('get-package-type'); | 
						|
 | 
						|
const readFile = promisify(fs.readFile); | 
						|
 | 
						|
let loadActive = false; | 
						|
 | 
						|
function isLoading() { | 
						|
	return loadActive; | 
						|
} | 
						|
 | 
						|
const standardConfigFiles = [ | 
						|
	'.nycrc', | 
						|
	'.nycrc.json', | 
						|
	'.nycrc.yml', | 
						|
	'.nycrc.yaml', | 
						|
	'nyc.config.js', | 
						|
	'nyc.config.cjs', | 
						|
	'nyc.config.mjs' | 
						|
]; | 
						|
 | 
						|
function camelcasedConfig(config) { | 
						|
	const results = {}; | 
						|
	for (const [field, value] of Object.entries(config)) { | 
						|
		results[camelcase(field)] = value; | 
						|
	} | 
						|
 | 
						|
	return results; | 
						|
} | 
						|
 | 
						|
async function findPackage(options) { | 
						|
	const cwd = options.cwd || process.env.NYC_CWD || process.cwd(); | 
						|
	const pkgPath = await findUp('package.json', {cwd}); | 
						|
	if (pkgPath) { | 
						|
		const pkgConfig = JSON.parse(await readFile(pkgPath, 'utf8')).nyc || {}; | 
						|
		if ('cwd' in pkgConfig) { | 
						|
			pkgConfig.cwd = path.resolve(path.dirname(pkgPath), pkgConfig.cwd); | 
						|
		} | 
						|
 | 
						|
		return { | 
						|
			cwd: path.dirname(pkgPath), | 
						|
			pkgConfig | 
						|
		}; | 
						|
	} | 
						|
 | 
						|
	return { | 
						|
		cwd, | 
						|
		pkgConfig: {} | 
						|
	}; | 
						|
} | 
						|
 | 
						|
async function actualLoad(configFile) { | 
						|
	if (!configFile) { | 
						|
		return {}; | 
						|
	} | 
						|
 | 
						|
	const configExt = path.extname(configFile).toLowerCase(); | 
						|
	switch (configExt) { | 
						|
		case '.js': | 
						|
			/* istanbul ignore next: coverage for 13.2.0+ is shown in load-esm.js */ | 
						|
			if (await getPackageType(configFile) === 'module') { | 
						|
				return require('./load-esm')(configFile); | 
						|
			} | 
						|
 | 
						|
			/* fallthrough */ | 
						|
		case '.cjs': | 
						|
			return require(configFile); | 
						|
		/* istanbul ignore next: coverage for 13.2.0+ is shown in load-esm.js */ | 
						|
		case '.mjs': | 
						|
			return require('./load-esm')(configFile); | 
						|
		case '.yml': | 
						|
		case '.yaml': | 
						|
			return require('js-yaml').load(await readFile(configFile, 'utf8')); | 
						|
		default: | 
						|
			return JSON.parse(await readFile(configFile, 'utf8')); | 
						|
	} | 
						|
} | 
						|
 | 
						|
async function loadFile(configFile) { | 
						|
	/* This lets @istanbuljs/esm-loader-hook avoid circular initialization when loading | 
						|
	 * configuration.  This should generally only happen when the loader hook is active | 
						|
	 * on the main nyc process. */ | 
						|
	loadActive = true; | 
						|
 | 
						|
	try { | 
						|
		return await actualLoad(configFile); | 
						|
	} finally { | 
						|
		loadActive = false; | 
						|
	} | 
						|
} | 
						|
 | 
						|
async function applyExtends(config, filename, loopCheck = new Set()) { | 
						|
	config = camelcasedConfig(config); | 
						|
	if ('extends' in config) { | 
						|
		const extConfigs = [].concat(config.extends); | 
						|
		if (extConfigs.some(e => typeof e !== 'string')) { | 
						|
			throw new TypeError(`${filename} contains an invalid 'extends' option`); | 
						|
		} | 
						|
 | 
						|
		delete config.extends; | 
						|
		const filePath = path.dirname(filename); | 
						|
		for (const extConfig of extConfigs) { | 
						|
			const configFile = resolveFrom.silent(filePath, extConfig) || | 
						|
				resolveFrom.silent(filePath, './' + extConfig); | 
						|
			if (!configFile) { | 
						|
				throw new Error(`Could not resolve configuration file ${extConfig} from ${path.dirname(filename)}.`); | 
						|
			} | 
						|
 | 
						|
			if (loopCheck.has(configFile)) { | 
						|
				throw new Error(`Circular extended configurations: '${configFile}'.`); | 
						|
			} | 
						|
 | 
						|
			loopCheck.add(configFile); | 
						|
 | 
						|
			// eslint-disable-next-line no-await-in-loop | 
						|
			const configLoaded = await loadFile(configFile); | 
						|
			if ('cwd' in configLoaded) { | 
						|
				configLoaded.cwd = path.resolve(path.dirname(configFile), configLoaded.cwd); | 
						|
			} | 
						|
 | 
						|
			Object.assign( | 
						|
				config, | 
						|
				// eslint-disable-next-line no-await-in-loop | 
						|
				await applyExtends(configLoaded, configFile, loopCheck) | 
						|
			); | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	return config; | 
						|
} | 
						|
 | 
						|
async function loadNycConfig(options = {}) { | 
						|
	const {cwd, pkgConfig} = await findPackage(options); | 
						|
	const configFiles = [].concat(options.nycrcPath || standardConfigFiles); | 
						|
	const configFile = await findUp(configFiles, {cwd}); | 
						|
	if (options.nycrcPath && !configFile) { | 
						|
		throw new Error(`Requested configuration file ${options.nycrcPath} not found`); | 
						|
	} | 
						|
 | 
						|
	const config = { | 
						|
		cwd, | 
						|
		...(await applyExtends(pkgConfig, path.join(cwd, 'package.json'))), | 
						|
		...(await applyExtends(await loadFile(configFile), configFile)) | 
						|
	}; | 
						|
 | 
						|
	const arrayFields = ['require', 'extension', 'exclude', 'include']; | 
						|
	for (const arrayField of arrayFields) { | 
						|
		if (config[arrayField]) { | 
						|
			config[arrayField] = [].concat(config[arrayField]); | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	return config; | 
						|
} | 
						|
 | 
						|
module.exports = { | 
						|
	loadNycConfig, | 
						|
	isLoading | 
						|
};
 | 
						|
 |