// Assertions
//-----------------------------------------------------------------------------
+/**
+ * The error type when a rule's options are configured with an invalid type.
+ */
+class InvalidRuleOptionsError extends Error {
+
+ /**
+ * @param {string} ruleId Rule name being configured.
+ * @param {any} value The invalid value.
+ */
+ constructor(ruleId, value) {
+ super(`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`);
+ this.messageTemplate = "invalid-rule-options";
+ this.messageData = { ruleId, value };
+ }
+}
+
/**
* Validates that a value is a valid rule options entry.
+ * @param {string} ruleId Rule name being configured.
* @param {any} value The value to check.
* @returns {void}
- * @throws {TypeError} If the value isn't a valid rule options.
+ * @throws {InvalidRuleOptionsError} If the value isn't a valid rule options.
*/
-function assertIsRuleOptions(value) {
-
+function assertIsRuleOptions(ruleId, value) {
if (typeof value !== "string" && typeof value !== "number" && !Array.isArray(value)) {
- throw new TypeError("Expected a string, number, or array.");
+ throw new InvalidRuleOptionsError(ruleId, value);
+ }
+}
+
+/**
+ * The error type when a rule's severity is invalid.
+ */
+class InvalidRuleSeverityError extends Error {
+
+ /**
+ * @param {string} ruleId Rule name being configured.
+ * @param {any} value The invalid value.
+ */
+ constructor(ruleId, value) {
+ super(`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`);
+ this.messageTemplate = "invalid-rule-severity";
+ this.messageData = { ruleId, value };
}
}
/**
* Validates that a value is valid rule severity.
+ * @param {string} ruleId Rule name being configured.
* @param {any} value The value to check.
* @returns {void}
- * @throws {TypeError} If the value isn't a valid rule severity.
+ * @throws {InvalidRuleSeverityError} If the value isn't a valid rule severity.
*/
-function assertIsRuleSeverity(value) {
+function assertIsRuleSeverity(ruleId, value) {
const severity = typeof value === "string"
? ruleSeverities.get(value.toLowerCase())
: ruleSeverities.get(value);
if (typeof severity === "undefined") {
- throw new TypeError("Expected severity of \"off\", 0, \"warn\", 1, \"error\", or 2.");
+ throw new InvalidRuleSeverityError(ruleId, value);
}
}
}
}
-/**
- * Validates that a value is an object or a string.
- * @param {any} value The value to check.
- * @returns {void}
- * @throws {TypeError} If the value isn't an object or a string.
- */
-function assertIsObjectOrString(value) {
- if ((!value || typeof value !== "object") && typeof value !== "string") {
- throw new TypeError("Expected an object or string.");
- }
-}
-
//-----------------------------------------------------------------------------
// Low-Level Schemas
//-----------------------------------------------------------------------------
const parserSchema = {
merge: "replace",
validate(value) {
- assertIsObjectOrString(value);
- if (typeof value === "object" && typeof value.parse !== "function" && typeof value.parseForESLint !== "function") {
- throw new TypeError("Expected object to have a parse() or parseForESLint() method.");
+ if (!value || typeof value !== "object" ||
+ (typeof value.parse !== "function" && typeof value.parseForESLint !== "function")
+ ) {
+ throw new TypeError("Expected object with parse() or parseForESLint() method.");
}
- if (typeof value === "string") {
- assertIsPluginMemberName(value);
- }
}
};
validate(value) {
assertIsObject(value);
- let lastRuleId;
-
- // Performance: One try-catch has less overhead than one per loop iteration
- try {
+ /*
+ * We are not checking the rule schema here because there is no
+ * guarantee that the rule definition is present at this point. Instead
+ * we wait and check the rule schema during the finalization step
+ * of calculating a config.
+ */
+ for (const ruleId of Object.keys(value)) {
- /*
- * We are not checking the rule schema here because there is no
- * guarantee that the rule definition is present at this point. Instead
- * we wait and check the rule schema during the finalization step
- * of calculating a config.
- */
- for (const ruleId of Object.keys(value)) {
-
- // avoid hairy edge case
- if (ruleId === "__proto__") {
- continue;
- }
-
- lastRuleId = ruleId;
+ // avoid hairy edge case
+ if (ruleId === "__proto__") {
+ continue;
+ }
- const ruleOptions = value[ruleId];
+ const ruleOptions = value[ruleId];
- assertIsRuleOptions(ruleOptions);
+ assertIsRuleOptions(ruleId, ruleOptions);
- if (Array.isArray(ruleOptions)) {
- assertIsRuleSeverity(ruleOptions[0]);
- } else {
- assertIsRuleSeverity(ruleOptions);
- }
+ if (Array.isArray(ruleOptions)) {
+ assertIsRuleSeverity(ruleId, ruleOptions[0]);
+ } else {
+ assertIsRuleSeverity(ruleId, ruleOptions);
}
- } catch (error) {
- error.message = `Key "${lastRuleId}": ${error.message}`;
- throw error;
}
}
};