@humanwhocodes/config-array
Advanced tools
Comparing version 0.9.5 to 0.10.0
370
api.js
@@ -283,10 +283,13 @@ 'use strict'; | ||
* @param {Object} config The config object to check. | ||
* @param {string} [mode="implicit"] When set to "implicit", any config | ||
* without a `files` property will match; when set to "explicit", | ||
* any config without a `files` property will not match. | ||
* @returns {boolean} True if the file path is matched by the config, | ||
* false if not. | ||
*/ | ||
function pathMatches(filePath, basePath, config) { | ||
function pathMatches(filePath, basePath, config, mode = "implicit") { | ||
// a config without `files` field always match | ||
// a config without `files` field always match implicitly | ||
if (!config.files) { | ||
return true; | ||
return mode === "implicit"; | ||
} | ||
@@ -403,26 +406,25 @@ | ||
*/ | ||
constructor(configs, | ||
{ | ||
basePath = '', | ||
normalized = false, | ||
schema: customSchema, | ||
extraConfigTypes = [] | ||
} = {} | ||
) { | ||
constructor(configs,{ | ||
basePath = '', | ||
normalized = false, | ||
schema: customSchema, | ||
extraConfigTypes = [] | ||
} = {} | ||
) { | ||
super(); | ||
/** | ||
* Tracks if the array has been normalized. | ||
* @property isNormalized | ||
* @type boolean | ||
* @private | ||
*/ | ||
* Tracks if the array has been normalized. | ||
* @property isNormalized | ||
* @type boolean | ||
* @private | ||
*/ | ||
this[ConfigArraySymbol.isNormalized] = normalized; | ||
/** | ||
* The schema used for validating and merging configs. | ||
* @property schema | ||
* @type ObjectSchema | ||
* @private | ||
*/ | ||
* The schema used for validating and merging configs. | ||
* @property schema | ||
* @type ObjectSchema | ||
* @private | ||
*/ | ||
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema({ | ||
@@ -434,7 +436,7 @@ ...customSchema, | ||
/** | ||
* The path of the config file that this array was loaded from. | ||
* This is used to calculate filename matches. | ||
* @property basePath | ||
* @type string | ||
*/ | ||
* The path of the config file that this array was loaded from. | ||
* This is used to calculate filename matches. | ||
* @property basePath | ||
* @type string | ||
*/ | ||
this.basePath = basePath; | ||
@@ -445,24 +447,24 @@ | ||
/** | ||
* The supported config types. | ||
* @property configTypes | ||
* @type Array<string> | ||
*/ | ||
* The supported config types. | ||
* @property configTypes | ||
* @type Array<string> | ||
*/ | ||
this.extraConfigTypes = Object.freeze([...extraConfigTypes]); | ||
/** | ||
* A cache to store calculated configs for faster repeat lookup. | ||
* @property configCache | ||
* @type Map | ||
* @private | ||
*/ | ||
* A cache to store calculated configs for faster repeat lookup. | ||
* @property configCache | ||
* @type Map | ||
* @private | ||
*/ | ||
this[ConfigArraySymbol.configCache] = new Map(); | ||
// init cache | ||
dataCache.set(this, {}); | ||
dataCache.set(this, { explicitMatches: new Map() }); | ||
// load the configs into this array | ||
if (Array.isArray(configs)) { | ||
this.push(...configs); | ||
this.push(...configs); | ||
} else { | ||
this.push(configs); | ||
this.push(configs); | ||
} | ||
@@ -472,3 +474,3 @@ | ||
/** | ||
/** | ||
* Prevent normal array methods from creating a new `ConfigArray` instance. | ||
@@ -480,7 +482,7 @@ * This is to ensure that methods such as `slice()` won't try to create a | ||
*/ | ||
static get [Symbol.species]() { | ||
return Array; | ||
} | ||
static get [Symbol.species]() { | ||
return Array; | ||
} | ||
/** | ||
/** | ||
* Returns the `files` globs from every config object in the array. | ||
@@ -492,33 +494,33 @@ * This can be used to determine which files will be matched by a | ||
*/ | ||
get files() { | ||
get files() { | ||
assertNormalized(this); | ||
assertNormalized(this); | ||
// if this data has been cached, retrieve it | ||
const cache = dataCache.get(this); | ||
// if this data has been cached, retrieve it | ||
const cache = dataCache.get(this); | ||
if (cache.files) { | ||
return cache.files; | ||
} | ||
if (cache.files) { | ||
return cache.files; | ||
} | ||
// otherwise calculate it | ||
// otherwise calculate it | ||
const result = []; | ||
const result = []; | ||
for (const config of this) { | ||
if (config.files) { | ||
config.files.forEach(filePattern => { | ||
result.push(filePattern); | ||
}); | ||
for (const config of this) { | ||
if (config.files) { | ||
config.files.forEach(filePattern => { | ||
result.push(filePattern); | ||
}); | ||
} | ||
} | ||
} | ||
// store result | ||
cache.files = result; | ||
dataCache.set(this, cache); | ||
// store result | ||
cache.files = result; | ||
dataCache.set(this, cache); | ||
return result; | ||
} | ||
return result; | ||
} | ||
/** | ||
/** | ||
* Returns ignore matchers that should always be ignored regardless of | ||
@@ -530,39 +532,39 @@ * the matching `files` fields in any configs. This is necessary to mimic | ||
*/ | ||
get ignores() { | ||
get ignores() { | ||
assertNormalized(this); | ||
assertNormalized(this); | ||
// if this data has been cached, retrieve it | ||
const cache = dataCache.get(this); | ||
// if this data has been cached, retrieve it | ||
const cache = dataCache.get(this); | ||
if (cache.ignores) { | ||
return cache.ignores; | ||
} | ||
if (cache.ignores) { | ||
return cache.ignores; | ||
} | ||
// otherwise calculate it | ||
// otherwise calculate it | ||
const result = []; | ||
const result = []; | ||
for (const config of this) { | ||
if (config.ignores && !config.files) { | ||
result.push(...config.ignores); | ||
for (const config of this) { | ||
if (config.ignores && !config.files) { | ||
result.push(...config.ignores); | ||
} | ||
} | ||
} | ||
// store result | ||
cache.ignores = result; | ||
dataCache.set(this, cache); | ||
// store result | ||
cache.ignores = result; | ||
dataCache.set(this, cache); | ||
return result; | ||
} | ||
return result; | ||
} | ||
/** | ||
/** | ||
* Indicates if the config array has been normalized. | ||
* @returns {boolean} True if the config array is normalized, false if not. | ||
*/ | ||
isNormalized() { | ||
return this[ConfigArraySymbol.isNormalized]; | ||
} | ||
isNormalized() { | ||
return this[ConfigArraySymbol.isNormalized]; | ||
} | ||
/** | ||
/** | ||
* Normalizes a config array by flattening embedded arrays and executing | ||
@@ -573,18 +575,18 @@ * config functions. | ||
*/ | ||
async normalize(context = {}) { | ||
async normalize(context = {}) { | ||
if (!this.isNormalized()) { | ||
const normalizedConfigs = await normalize(this, context, this.extraConfigTypes); | ||
this.length = 0; | ||
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this))); | ||
this[ConfigArraySymbol.isNormalized] = true; | ||
if (!this.isNormalized()) { | ||
const normalizedConfigs = await normalize(this, context, this.extraConfigTypes); | ||
this.length = 0; | ||
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this))); | ||
this[ConfigArraySymbol.isNormalized] = true; | ||
// prevent further changes | ||
Object.freeze(this); | ||
// prevent further changes | ||
Object.freeze(this); | ||
} | ||
return this; | ||
} | ||
return this; | ||
} | ||
/** | ||
/** | ||
* Normalizes a config array by flattening embedded arrays and executing | ||
@@ -595,18 +597,18 @@ * config functions. | ||
*/ | ||
normalizeSync(context = {}) { | ||
normalizeSync(context = {}) { | ||
if (!this.isNormalized()) { | ||
const normalizedConfigs = normalizeSync(this, context, this.extraConfigTypes); | ||
this.length = 0; | ||
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig])); | ||
this[ConfigArraySymbol.isNormalized] = true; | ||
if (!this.isNormalized()) { | ||
const normalizedConfigs = normalizeSync(this, context, this.extraConfigTypes); | ||
this.length = 0; | ||
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig])); | ||
this[ConfigArraySymbol.isNormalized] = true; | ||
// prevent further changes | ||
Object.freeze(this); | ||
// prevent further changes | ||
Object.freeze(this); | ||
} | ||
return this; | ||
} | ||
return this; | ||
} | ||
/** | ||
/** | ||
* Finalizes the state of a config before being cached and returned by | ||
@@ -618,7 +620,7 @@ * `getConfig()`. Does nothing by default but is provided to be | ||
*/ | ||
[ConfigArraySymbol.finalizeConfig](config) { | ||
return config; | ||
} | ||
[ConfigArraySymbol.finalizeConfig](config) { | ||
return config; | ||
} | ||
/** | ||
/** | ||
* Preprocesses a config during the normalization process. This is the | ||
@@ -631,7 +633,54 @@ * method to override if you want to convert an array item before it is | ||
*/ | ||
[ConfigArraySymbol.preprocessConfig](config) { | ||
return config; | ||
} | ||
[ConfigArraySymbol.preprocessConfig](config) { | ||
return config; | ||
} | ||
/** | ||
/** | ||
* Determines if a given file path explicitly matches a `files` entry | ||
* and also doesn't match an `ignores` entry. Configs that don't have | ||
* a `files` property are not considered an explicit match. | ||
* @param {string} filePath The complete path of a file to check. | ||
* @returns {boolean} True if the file path matches a `files` entry | ||
* or false if not. | ||
*/ | ||
isExplicitMatch(filePath) { | ||
assertNormalized(this); | ||
const cache = dataCache.get(this); | ||
// first check the cache to avoid duplicate work | ||
let result = cache.explicitMatches.get(filePath); | ||
if (typeof result == "boolean") { | ||
return result; | ||
} | ||
// TODO: Maybe move elsewhere? Maybe combine with getConfig() logic? | ||
const relativeFilePath = path.relative(this.basePath, filePath); | ||
if (shouldIgnoreFilePath(this.ignores, filePath, relativeFilePath)) { | ||
debug(`Ignoring ${filePath}`); | ||
// cache and return result | ||
cache.explicitMatches.set(filePath, false); | ||
return false; | ||
} | ||
// filePath isn't automatically ignored, so try to find a match | ||
for (const config of this) { | ||
if (pathMatches(filePath, this.basePath, config, "explicit")) { | ||
debug(`Matching config found for ${filePath}`); | ||
cache.explicitMatches.set(filePath, true); | ||
return true; | ||
} else { | ||
debug(`No matching config found for ${filePath}`); | ||
} | ||
} | ||
return false; | ||
} | ||
/** | ||
* Returns the config object for a given file path. | ||
@@ -641,57 +690,58 @@ * @param {string} filePath The complete path of a file to get a config for. | ||
*/ | ||
getConfig(filePath) { | ||
getConfig(filePath) { | ||
assertNormalized(this); | ||
assertNormalized(this); | ||
// first check the cache to avoid duplicate work | ||
let finalConfig = this[ConfigArraySymbol.configCache].get(filePath); | ||
// first check the cache to avoid duplicate work | ||
let finalConfig = this[ConfigArraySymbol.configCache].get(filePath); | ||
if (finalConfig) { | ||
return finalConfig; | ||
} | ||
if (finalConfig) { | ||
return finalConfig; | ||
} | ||
// TODO: Maybe move elsewhere? | ||
const relativeFilePath = path.relative(this.basePath, filePath); | ||
// TODO: Maybe move elsewhere? | ||
const relativeFilePath = path.relative(this.basePath, filePath); | ||
if (shouldIgnoreFilePath(this.ignores, filePath, relativeFilePath)) { | ||
if (shouldIgnoreFilePath(this.ignores, filePath, relativeFilePath)) { | ||
debug(`Ignoring ${filePath}`); | ||
// cache and return result - finalConfig is undefined at this point | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
return finalConfig; | ||
} | ||
// cache and return result - finalConfig is undefined at this point | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
return finalConfig; | ||
} | ||
// filePath isn't automatically ignored, so try to construct config | ||
// filePath isn't automatically ignored, so try to construct config | ||
const matchingConfigs = []; | ||
const matchingConfigs = []; | ||
for (const config of this) { | ||
if (pathMatches(filePath, this.basePath, config)) { | ||
debug(`Matching config found for ${filePath}`); | ||
matchingConfigs.push(config); | ||
} else { | ||
debug(`No matching config found for ${filePath}`); | ||
for (const config of this) { | ||
if (pathMatches(filePath, this.basePath, config)) { | ||
debug(`Matching config found for ${filePath}`); | ||
matchingConfigs.push(config); | ||
} else { | ||
debug(`No matching config found for ${filePath}`); | ||
} | ||
} | ||
} | ||
// if matching both files and ignores, there will be no config to create | ||
if (matchingConfigs.length === 0) { | ||
// cache and return result - finalConfig is undefined at this point | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
return finalConfig; | ||
} | ||
// if matching both files and ignores, there will be no config to create | ||
if (matchingConfigs.length === 0) { | ||
// cache and return result - finalConfig is undefined at this point | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
return finalConfig; | ||
} | ||
// otherwise construct the config | ||
// otherwise construct the config | ||
finalConfig = matchingConfigs.reduce((result, config) => { | ||
return this[ConfigArraySymbol.schema].merge(result, config); | ||
}, {}, this); | ||
finalConfig = matchingConfigs.reduce((result, config) => { | ||
return this[ConfigArraySymbol.schema].merge(result, config); | ||
}, {}, this); | ||
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig); | ||
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig); | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig); | ||
return finalConfig; | ||
} | ||
return finalConfig; | ||
} | ||
/** | ||
/** | ||
* Determines if the given filepath is ignored based on the configs. | ||
@@ -701,5 +751,5 @@ * @param {string} filePath The complete path of a file to check. | ||
*/ | ||
isIgnored(filePath) { | ||
return this.getConfig(filePath) === undefined; | ||
} | ||
isIgnored(filePath) { | ||
return this.getConfig(filePath) === undefined; | ||
} | ||
@@ -706,0 +756,0 @@ } |
# Changelog | ||
## [0.10.0](https://www.github.com/humanwhocodes/config-array/compare/v0.9.5...v0.10.0) (2022-03-01) | ||
### Features | ||
* Add isExplicitMatch() method ([9ecd90e](https://www.github.com/humanwhocodes/config-array/commit/9ecd90e2a3e984633f535daa4da3cbfb96964fdd)) | ||
### [0.9.5](https://www.github.com/humanwhocodes/config-array/compare/v0.9.4...v0.9.5) (2022-02-23) | ||
@@ -4,0 +11,0 @@ |
{ | ||
"name": "@humanwhocodes/config-array", | ||
"version": "0.9.5", | ||
"version": "0.10.0", | ||
"description": "Glob-based configuration matching.", | ||
@@ -5,0 +5,0 @@ "author": "Nicholas C. Zakas", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47610
612