2024-08-09 12:04:48 +00:00
/ * *
* @ fileoverview Flat Config Array
* @ author Nicholas C . Zakas
* /
"use strict" ;
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
const { ConfigArray , ConfigArraySymbol } = require ( "@humanwhocodes/config-array" ) ;
const { flatConfigSchema } = require ( "./flat-config-schema" ) ;
const { RuleValidator } = require ( "./rule-validator" ) ;
const { defaultConfig } = require ( "./default-config" ) ;
2024-08-21 06:34:30 +00:00
const jsPlugin = require ( "@eslint/js" ) ;
2024-08-09 12:04:48 +00:00
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const ruleValidator = new RuleValidator ( ) ;
/ * *
* Splits a plugin identifier in the form a / b / c into two parts : a / b and c .
* @ param { string } identifier The identifier to parse .
* @ returns { { objectName : string , pluginName : string } } The parts of the plugin
* name .
* /
function splitPluginIdentifier ( identifier ) {
const parts = identifier . split ( "/" ) ;
return {
objectName : parts . pop ( ) ,
pluginName : parts . join ( "/" )
} ;
}
2024-08-21 06:34:30 +00:00
/ * *
* Returns the name of an object in the config by reading its ` meta ` key .
* @ param { Object } object The object to check .
* @ returns { string ? } The name of the object if found or ` null ` if there
* is no name .
* /
function getObjectId ( object ) {
// first check old-style name
let name = object . name ;
if ( ! name ) {
if ( ! object . meta ) {
return null ;
}
name = object . meta . name ;
if ( ! name ) {
return null ;
}
}
// now check for old-style version
let version = object . version ;
if ( ! version ) {
version = object . meta && object . meta . version ;
}
// if there's a version then append that
if ( version ) {
return ` ${ name } @ ${ version } ` ;
}
return name ;
}
const originalBaseConfig = Symbol ( "originalBaseConfig" ) ;
2024-08-09 12:04:48 +00:00
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/ * *
* Represents an array containing configuration information for ESLint .
* /
class FlatConfigArray extends ConfigArray {
/ * *
* Creates a new instance .
* @ param { * [ ] } configs An array of configuration information .
2024-08-21 06:34:30 +00:00
* @ param { { basePath : string , shouldIgnore : boolean , baseConfig : FlatConfig } } options The options
2024-08-09 12:04:48 +00:00
* to use for the config array instance .
* /
2024-08-21 06:34:30 +00:00
constructor ( configs , {
basePath ,
shouldIgnore = true ,
baseConfig = defaultConfig
} = { } ) {
2024-08-09 12:04:48 +00:00
super ( configs , {
basePath ,
schema : flatConfigSchema
} ) ;
2024-08-21 06:34:30 +00:00
if ( baseConfig [ Symbol . iterator ] ) {
this . unshift ( ... baseConfig ) ;
} else {
this . unshift ( baseConfig ) ;
}
/ * *
* The base config used to build the config array .
* @ type { Array < FlatConfig > }
* /
this [ originalBaseConfig ] = baseConfig ;
Object . defineProperty ( this , originalBaseConfig , { writable : false } ) ;
/ * *
* Determines if ` ignores ` fields should be honored .
* If true , then all ` ignores ` fields are honored .
* if false , then only ` ignores ` fields in the baseConfig are honored .
* @ type { boolean }
* /
this . shouldIgnore = shouldIgnore ;
Object . defineProperty ( this , "shouldIgnore" , { writable : false } ) ;
2024-08-09 12:04:48 +00:00
}
2024-08-21 06:34:30 +00:00
/* eslint-disable class-methods-use-this -- Desired as instance method */
2024-08-09 12:04:48 +00:00
/ * *
* Replaces a config with another config to allow us to put strings
* in the config array that will be replaced by objects before
* normalization .
* @ param { Object } config The config to preprocess .
* @ returns { Object } The preprocessed config .
* /
[ ConfigArraySymbol . preprocessConfig ] ( config ) {
if ( config === "eslint:recommended" ) {
2024-08-21 06:34:30 +00:00
// if we are in a Node.js environment warn the user
if ( typeof process !== "undefined" && process . emitWarning ) {
process . emitWarning ( "The 'eslint:recommended' string configuration is deprecated and will be replaced by the @eslint/js package's 'recommended' config." ) ;
}
return jsPlugin . configs . recommended ;
2024-08-09 12:04:48 +00:00
}
if ( config === "eslint:all" ) {
2024-08-21 06:34:30 +00:00
// if we are in a Node.js environment warn the user
if ( typeof process !== "undefined" && process . emitWarning ) {
process . emitWarning ( "The 'eslint:all' string configuration is deprecated and will be replaced by the @eslint/js package's 'all' config." ) ;
}
return jsPlugin . configs . all ;
}
/ *
* If ` shouldIgnore ` is false , we remove any ignore patterns specified
* in the config so long as it 's not a default config and it doesn' t
* have a ` files ` entry .
* /
if (
! this . shouldIgnore &&
! this [ originalBaseConfig ] . includes ( config ) &&
config . ignores &&
! config . files
) {
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
const { ignores , ... otherKeys } = config ;
return otherKeys ;
2024-08-09 12:04:48 +00:00
}
return config ;
}
/ * *
* Finalizes the config by replacing plugin references with their objects
* and validating rule option schemas .
* @ param { Object } config The config to finalize .
* @ returns { Object } The finalized config .
* @ throws { TypeError } If the config is invalid .
* /
[ ConfigArraySymbol . finalizeConfig ] ( config ) {
const { plugins , languageOptions , processor } = config ;
2024-08-21 06:34:30 +00:00
let parserName , processorName ;
let invalidParser = false ,
invalidProcessor = false ;
2024-08-09 12:04:48 +00:00
// Check parser value
2024-08-21 06:34:30 +00:00
if ( languageOptions && languageOptions . parser ) {
const { parser } = languageOptions ;
2024-08-09 12:04:48 +00:00
2024-08-21 06:34:30 +00:00
if ( typeof parser === "object" ) {
parserName = getObjectId ( parser ) ;
if ( ! parserName ) {
invalidParser = true ;
}
2024-08-09 12:04:48 +00:00
2024-08-21 06:34:30 +00:00
} else {
invalidParser = true ;
}
2024-08-09 12:04:48 +00:00
}
// Check processor value
2024-08-21 06:34:30 +00:00
if ( processor ) {
if ( typeof processor === "string" ) {
const { pluginName , objectName : localProcessorName } = splitPluginIdentifier ( processor ) ;
2024-08-09 12:04:48 +00:00
2024-08-21 06:34:30 +00:00
processorName = processor ;
if ( ! plugins || ! plugins [ pluginName ] || ! plugins [ pluginName ] . processors || ! plugins [ pluginName ] . processors [ localProcessorName ] ) {
throw new TypeError ( ` Key "processor": Could not find " ${ localProcessorName } " in plugin " ${ pluginName } ". ` ) ;
}
2024-08-09 12:04:48 +00:00
2024-08-21 06:34:30 +00:00
config . processor = plugins [ pluginName ] . processors [ localProcessorName ] ;
} else if ( typeof processor === "object" ) {
processorName = getObjectId ( processor ) ;
if ( ! processorName ) {
invalidProcessor = true ;
}
} else {
invalidProcessor = true ;
}
2024-08-09 12:04:48 +00:00
}
ruleValidator . validate ( config ) ;
2024-08-21 06:34:30 +00:00
// apply special logic for serialization into JSON
/* eslint-disable object-shorthand -- shorthand would change "this" value */
Object . defineProperty ( config , "toJSON" , {
value : function ( ) {
if ( invalidParser ) {
throw new Error ( "Could not serialize parser object (missing 'meta' object)." ) ;
}
if ( invalidProcessor ) {
throw new Error ( "Could not serialize processor object (missing 'meta' object)." ) ;
}
return {
... this ,
plugins : Object . entries ( plugins ) . map ( ( [ namespace , plugin ] ) => {
const pluginId = getObjectId ( plugin ) ;
if ( ! pluginId ) {
return namespace ;
}
return ` ${ namespace } : ${ pluginId } ` ;
} ) ,
languageOptions : {
... languageOptions ,
parser : parserName
} ,
processor : processorName
} ;
}
} ) ;
/* eslint-enable object-shorthand -- ok to enable now */
2024-08-09 12:04:48 +00:00
return config ;
}
2024-08-21 06:34:30 +00:00
/* eslint-enable class-methods-use-this -- Desired as instance method */
2024-08-09 12:04:48 +00:00
}
exports . FlatConfigArray = FlatConfigArray ;