55
66/* eslint class-methods-use-this: "off" */
77
8+ //------------------------------------------------------------------------------
9+ // Typedefs
10+ //------------------------------------------------------------------------------
11+
12+ /** @typedef {import("../shared/types").Rule } Rule */
13+
814//------------------------------------------------------------------------------
915// Requirements
1016//------------------------------------------------------------------------------
@@ -33,6 +39,13 @@ const severityMap = {
3339
3440const validated = new WeakSet ( ) ;
3541
42+ // JSON schema that disallows passing any options
43+ const noOptionsSchema = Object . freeze ( {
44+ type : "array" ,
45+ minItems : 0 ,
46+ maxItems : 0
47+ } ) ;
48+
3649//-----------------------------------------------------------------------------
3750// Exports
3851//-----------------------------------------------------------------------------
@@ -44,17 +57,36 @@ export default class ConfigValidator {
4457
4558 /**
4659 * Gets a complete options schema for a rule.
47- * @param {{create: Function, schema: (Array|null)} } rule A new-style rule object
48- * @returns {Object } JSON Schema for the rule's options.
60+ * @param {Rule } rule A rule object
61+ * @throws {TypeError } If `meta.schema` is specified but is not an array, object or `false`.
62+ * @returns {Object|null } JSON Schema for the rule's options.
63+ * `null` if rule wasn't passed or its `meta.schema` is `false`.
4964 */
5065 getRuleOptionsSchema ( rule ) {
5166 if ( ! rule ) {
5267 return null ;
5368 }
5469
55- const schema = rule . schema || rule . meta && rule . meta . schema ;
70+ if ( ! rule . meta ) {
71+ return { ...noOptionsSchema } ; // default if `meta.schema` is not specified
72+ }
5673
57- // Given a tuple of schemas, insert warning level at the beginning
74+ const schema = rule . meta . schema ;
75+
76+ if ( typeof schema === "undefined" ) {
77+ return { ...noOptionsSchema } ; // default if `meta.schema` is not specified
78+ }
79+
80+ // `schema:false` is an allowed explicit opt-out of options validation for the rule
81+ if ( schema === false ) {
82+ return null ;
83+ }
84+
85+ if ( typeof schema !== "object" || schema === null ) {
86+ throw new TypeError ( "Rule's `meta.schema` must be an array or object" ) ;
87+ }
88+
89+ // ESLint-specific array form needs to be converted into a valid JSON Schema definition
5890 if ( Array . isArray ( schema ) ) {
5991 if ( schema . length ) {
6092 return {
@@ -64,16 +96,13 @@ export default class ConfigValidator {
6496 maxItems : schema . length
6597 } ;
6698 }
67- return {
68- type : "array" ,
69- minItems : 0 ,
70- maxItems : 0
71- } ;
7299
100+ // `schema:[]` is an explicit way to specify that the rule does not accept any options
101+ return { ...noOptionsSchema } ;
73102 }
74103
75- // Given a full schema, leave it alone
76- return schema || null ;
104+ // `schema:<object>` is assumed to be a valid JSON Schema definition
105+ return schema ;
77106 }
78107
79108 /**
@@ -101,10 +130,18 @@ export default class ConfigValidator {
101130 */
102131 validateRuleSchema ( rule , localOptions ) {
103132 if ( ! ruleValidators . has ( rule ) ) {
104- const schema = this . getRuleOptionsSchema ( rule ) ;
133+ try {
134+ const schema = this . getRuleOptionsSchema ( rule ) ;
135+
136+ if ( schema ) {
137+ ruleValidators . set ( rule , ajv . compile ( schema ) ) ;
138+ }
139+ } catch ( err ) {
140+ const errorWithCode = new Error ( err . message , { cause : err } ) ;
105141
106- if ( schema ) {
107- ruleValidators . set ( rule , ajv . compile ( schema ) ) ;
142+ errorWithCode . code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA" ;
143+
144+ throw errorWithCode ;
108145 }
109146 }
110147
@@ -137,13 +174,21 @@ export default class ConfigValidator {
137174 this . validateRuleSchema ( rule , Array . isArray ( options ) ? options . slice ( 1 ) : [ ] ) ;
138175 }
139176 } catch ( err ) {
140- const enhancedMessage = `Configuration for rule "${ ruleId } " is invalid:\n${ err . message } ` ;
177+ let enhancedMessage = err . code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
178+ ? `Error while processing options validation schema of rule '${ ruleId } ': ${ err . message } `
179+ : `Configuration for rule "${ ruleId } " is invalid:\n${ err . message } ` ;
141180
142181 if ( typeof source === "string" ) {
143- throw new Error ( `${ source } :\n\t${ enhancedMessage } ` ) ;
144- } else {
145- throw new Error ( enhancedMessage ) ;
182+ enhancedMessage = `${ source } :\n\t${ enhancedMessage } ` ;
146183 }
184+
185+ const enhancedError = new Error ( enhancedMessage , { cause : err } ) ;
186+
187+ if ( err . code ) {
188+ enhancedError . code = err . code ;
189+ }
190+
191+ throw enhancedError ;
147192 }
148193 }
149194
0 commit comments