📄 config-validator.ts
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 7 |
📦 Imports | 13 |
📊 Variables & Constants | 11 |
📑 Type Aliases | 1 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/rule-tester/src/utils/config-validator.ts
📦 Imports¶
Name | Source |
---|---|
AnyRuleModule |
@typescript-eslint/utils/ts-eslint |
Linter |
@typescript-eslint/utils/ts-eslint |
AdditionalPropertiesParams |
ajv |
AjvErrorObject |
ajv |
ValidateFunction |
ajv |
builtinRules |
eslint/use-at-your-own-risk |
util |
node:util |
TesterConfigWithDefaults |
../types |
ajvBuilder |
./ajv |
emitDeprecationWarning |
./deprecation-warnings |
flatConfigSchema |
./flat-config-schema |
getRuleOptionsSchema |
./getRuleOptionsSchema |
hasOwnProperty |
./hasOwnProperty |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
ruleValidators |
WeakMap<AnyRuleModule, ValidateFunction> |
const | new WeakMap<AnyRuleModule, ValidateFunction>() |
✗ |
validateSchema |
ValidateFunction | undefined |
let/var | *not shown* |
✗ |
severityMap |
{ readonly error: 2; readonly off: 0; readonly warn: 1; } |
const | `{ | |
error: 2, | ||||
off: 0, | ||||
warn: 1, | ||||
} as const` | ✗ | |||
severity |
any |
const | Array.isArray(options) ? options[0] : options |
✗ |
normSeverity |
number |
const | `typeof severity === 'string' | |
? (severityMap[severity.toLowerCase() as Linter.SeverityString] as | ||||
number | ||||
undefined) | ||||
: (severity as number)` | ✗ | |||
enhancedMessage |
string |
const | ``Configuration for rule "${ruleId}" is invalid:\n${ | |
(err as Error).message | ||||
}`` | ✗ | |||
rule |
any |
const | getAdditionalRule(id) ?? builtinRules.get(id) ?? null |
✗ |
params |
AdditionalPropertiesParams |
const | error.params as AdditionalPropertiesParams |
✗ |
formattedPropertyPath |
any |
const | `error.dataPath.length | |
? ${error.dataPath.slice(1)}.${params.additionalProperty} |
||||
: params.additionalProperty` | ✗ | |||
formattedExpectedType |
any |
const | `Array.isArray(error.schema) | |
? error.schema.join('/') | ||||
: error.schema` | ✗ | |||
field |
any |
const | error.dataPath[0] === '.' ? error.dataPath.slice(1) : error.dataPath |
✗ |
Functions¶
validateRuleSeverity(options: Linter.RuleEntry): number | string
¶
Code
function validateRuleSeverity(options: Linter.RuleEntry): number | string {
const severity = Array.isArray(options) ? options[0] : options;
const normSeverity =
typeof severity === 'string'
? (severityMap[severity.toLowerCase() as Linter.SeverityString] as
| number
| undefined)
: (severity as number);
if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
return normSeverity;
}
throw new Error(
`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util
.inspect(severity)
.replaceAll("'", '"')
.replaceAll('\n', '')}').\n`,
);
}
-
JSDoc:
-
Parameters:
options: Linter.RuleEntry
- Return Type:
number | string
- Calls:
Array.isArray
severity.toLowerCase
util .inspect(severity) .replaceAll("'", '"') .replaceAll
validateRuleSchema(rule: AnyRuleModule, localOptions: unknown[]): void
¶
Code
function validateRuleSchema(
rule: AnyRuleModule,
localOptions: unknown[],
): void {
if (!ruleValidators.has(rule)) {
const schema = getRuleOptionsSchema(rule);
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
}
const validateRule = ruleValidators.get(rule);
if (validateRule) {
void validateRule(localOptions);
if (validateRule.errors) {
throw new Error(
validateRule.errors
.map(
error =>
`\tValue ${JSON.stringify(error.data)} ${error.message}.\n`,
)
.join(''),
);
}
}
}
-
JSDoc:
-
Parameters:
rule: AnyRuleModule
localOptions: unknown[]
- Return Type:
void
- Calls:
ruleValidators.has
getRuleOptionsSchema (from ./getRuleOptionsSchema)
ruleValidators.set
ajv.compile
ruleValidators.get
validateRule
validateRule.errors .map( error =>
\tValue ${JSON.stringify(error.data)} ${error.message}.\n, ) .join
validateRuleOptions(rule: AnyRuleModule, ruleId: string, options: Linter.RuleEntry, source: string | null): void
¶
Code
function validateRuleOptions(
rule: AnyRuleModule,
ruleId: string,
options: Linter.RuleEntry,
source: string | null = null,
): void {
try {
const severity = validateRuleSeverity(options);
if (severity !== 0) {
validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
}
} catch (err) {
const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${
(err as Error).message
}`;
if (typeof source === 'string') {
throw new Error(`${source}:\n\t${enhancedMessage}`);
} else {
throw new Error(enhancedMessage);
}
}
}
-
JSDoc:
/** * Validates a rule's options against its schema. * @param rule The rule that the config is being validated for * @param ruleId The rule's unique name. * @param options The given options for the rule. * @param source The name of the configuration source to report in any errors. If null or undefined, * no source is prepended to the message. * @throws {Error} Upon any bad rule configuration. */
-
Parameters:
rule: AnyRuleModule
ruleId: string
options: Linter.RuleEntry
source: string | null
- Return Type:
void
- Calls:
validateRuleSeverity
validateRuleSchema
Array.isArray
options.slice
validateRules(rulesConfig: Linter.RulesRecord | undefined, source: string, getAdditionalRule: GetAdditionalRule): void
¶
Code
function validateRules(
rulesConfig: Linter.RulesRecord | undefined,
source: string,
getAdditionalRule: GetAdditionalRule,
): void {
if (!rulesConfig) {
return;
}
Object.keys(rulesConfig).forEach(id => {
const rule = getAdditionalRule(id) ?? builtinRules.get(id) ?? null;
if (rule == null) {
return;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
validateRuleOptions(rule, id, rulesConfig[id]!, source);
});
}
-
JSDoc:
-
Parameters:
rulesConfig: Linter.RulesRecord | undefined
source: string
getAdditionalRule: GetAdditionalRule
- Return Type:
void
- Calls:
Object.keys(rulesConfig).forEach
getAdditionalRule
builtinRules.get
validateRuleOptions
- Internal Comments:
formatErrors(errors: AjvErrorObject[]): string
¶
Code
function formatErrors(errors: AjvErrorObject[]): string {
return errors
.map(error => {
if (error.keyword === 'additionalProperties') {
const params = error.params as AdditionalPropertiesParams;
const formattedPropertyPath = error.dataPath.length
? `${error.dataPath.slice(1)}.${params.additionalProperty}`
: params.additionalProperty;
return `Unexpected top-level property "${formattedPropertyPath}"`;
}
if (error.keyword === 'type') {
const formattedField = error.dataPath.slice(1);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const formattedExpectedType = Array.isArray(error.schema)
? error.schema.join('/')
: error.schema;
const formattedValue = JSON.stringify(error.data);
return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
}
const field =
error.dataPath[0] === '.' ? error.dataPath.slice(1) : error.dataPath;
return `"${field}" ${error.message}. Value: ${JSON.stringify(
error.data,
)}`;
})
.map(message => `\t- ${message}.\n`)
.join('');
}
-
JSDoc:
-
Parameters:
errors: AjvErrorObject[]
- Return Type:
string
- Calls:
-
errors .map(error => { if (error.keyword === 'additionalProperties') { const params = error.params as AdditionalPropertiesParams; const formattedPropertyPath = error.dataPath.length ?
${error.dataPath.slice(1)}.${params.additionalProperty}` : params.additionalProperty;return `Unexpected top-level property "${formattedPropertyPath}"`;
} if (error.keyword === 'type') { const formattedField = error.dataPath.slice(1); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join('/') : error.schema; const formattedValue = JSON.stringify(error.data);
return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
}
const field = error.dataPath[0] === '.' ? error.dataPath.slice(1) : error.dataPath;
return
"${field}" ${error.message}. Value: ${JSON.stringify( error.data, )}
; }) .map(message =>\t- ${message}.\n
) .join` - Internal Comments:
validateConfigSchema(config: TesterConfigWithDefaults, source: string): void
¶
Code
function validateConfigSchema(
config: TesterConfigWithDefaults,
source: string,
): void {
validateSchema ??= ajv.compile(flatConfigSchema);
if (!validateSchema(config)) {
throw new Error(
`ESLint configuration in ${source} is invalid:\n${formatErrors(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
validateSchema.errors!,
)}`,
);
}
// @ts-expect-error -- intentional deprecated check
if (hasOwnProperty(config, 'ecmaFeatures')) {
emitDeprecationWarning(source, 'ESLINT_LEGACY_ECMAFEATURES');
}
}
-
JSDoc:
-
Parameters:
config: TesterConfigWithDefaults
source: string
- Return Type:
void
- Calls:
ajv.compile
validateSchema
formatErrors
hasOwnProperty (from ./hasOwnProperty)
emitDeprecationWarning (from ./deprecation-warnings)
- Internal Comments:
validate(config: TesterConfigWithDefaults, source: string, getAdditionalRule: GetAdditionalRule): void
¶
Code
-
JSDoc:
-
Parameters:
config: TesterConfigWithDefaults
source: string
getAdditionalRule: GetAdditionalRule
- Return Type:
void
- Calls:
validateConfigSchema
validateRules