Repository: eslint/eslint
File: lib/config/rule-validator.js (JavaScript)

Code before:
            }

            // Precompile and cache validator the first time
            if (!this.validators.has(rule)) {
                try {
                    const schema = getRuleOptionsSchema(rule);

                    if (schema) {
                        this.validators.set(rule, ajv.compile(schema));
                    }
                } catch (err) {
                    throw new InvalidRuleOptionsSchemaError(ruleId, err);
                }
            }

            const validateRule = this.validators.get(rule);

            if (validateRule) {

                validateRule(ruleOptions.slice(1));

                if (validateRule.errors) {
                    throw new Error(`Key "rules": Key "${ruleId}": ${
                        validateRule.errors.map(
                            error => {
                                if (error.keyword === "additionalProperties" && error.schema === false) {
                                    const expectedProperties = Object.keys(error.parentSchema.properties).map(property => `"${property}"`);

                                    return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n\tUnexpected property "${error.params.additionalProperty}". Expected properties: ${expectedProperties.join(", ")}.\n`;
                                }

                                return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`;
                            }
                        ).join("")
                    }`);
                }
            }
        }
    }
}

exports.RuleValidator = RuleValidator;


Review comment (bug):
```suggestion
                                if (error.keyword === "additionalProperties" && error.schema === false && typeof error.parentSchema?.properties === "object" && typeof error.params?.additionalProperty === "string") {
```

It might be good to check if all expected data is there so that this doesn't crash in case Ajv doesn't always return everything we're expecting here.

Code after:
            }

            // Precompile and cache validator the first time
            if (!this.validators.has(rule)) {
                try {
                    const schema = getRuleOptionsSchema(rule);

                    if (schema) {
                        this.validators.set(rule, ajv.compile(schema));
                    }
                } catch (err) {
                    throw new InvalidRuleOptionsSchemaError(ruleId, err);
                }
            }

            const validateRule = this.validators.get(rule);

            if (validateRule) {

                validateRule(ruleOptions.slice(1));

                if (validateRule.errors) {
                    throw new Error(`Key "rules": Key "${ruleId}":\n${
                        validateRule.errors.map(
                            error => {
                                if (
                                    error.keyword === "additionalProperties" &&
                                    error.schema === false &&
                                    typeof error.parentSchema?.properties === "object" &&
                                    typeof error.params?.additionalProperty === "string"
                                ) {
                                    const expectedProperties = Object.keys(error.parentSchema.properties).map(property => `"${property}"`);

                                    return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n\t\tUnexpected property "${error.params.additionalProperty}". Expected properties: ${expectedProperties.join(", ")}.\n`;
                                }

                                return `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`;
                            }
                        ).join("")
                    }`);
                }
            }
        }
    }
}

exports.RuleValidator = RuleValidator;