Skip to content

⬅️ Back to Table of Contents

📄 config-validator

📊 Analysis Summary

Metric Count
🔧 Functions 7
📦 Imports 13
📊 Variables & Constants 3
📑 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;... const { error: 2, off: 0, warn: 1, } as const

Functions

validate(config: TesterConfigWithDefaults, source: string, getAdditionalRule: GetAdditionalRule): void

Validates an entire config object.

Parameters:

  • config any: The config object to validate.
  • source any: The name of the configuration source to report in any errors.
  • getAdditionalRule any: A map from strings to loaded rules.
Raw JSDoc
/**
 * Validates an entire config object.
 * @param config The config object to validate.
 * @param source The name of the configuration source to report in any errors.
 * @param getAdditionalRule A map from strings to loaded rules.
 */

Calls:

  • validateConfigSchema
  • validateRules
Code
export function validate(
  config: TesterConfigWithDefaults,
  source: string,
  getAdditionalRule: GetAdditionalRule,
): void {
  validateConfigSchema(config, source);
  validateRules(config.rules, source, getAdditionalRule);
}

validateRuleSeverity(options: Linter.RuleEntry): number | string

Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.

Parameters:

  • options any: The given options for the rule.

Throws:

  • Error: Wrong severity value.
Raw JSDoc
/**
 * Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
 * @param options The given options for the rule.
 * @throws {Error} Wrong severity value.
 */

Calls:

  • Array.isArray
  • severity.toLowerCase
  • util .inspect(severity) .replaceAll("'", '"') .replaceAll
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`,
  );
}

validateRuleSchema(rule: AnyRuleModule, localOptions: unknown[]): void

Validates the non-severity options passed to a rule, based on its schema.

Parameters:

  • rule any: The rule to validate
  • localOptions any: The options for the rule, excluding severity

Throws:

  • Error: Any rule validation errors.
Raw JSDoc
/**
 * Validates the non-severity options passed to a rule, based on its schema.
 * @param rule The rule to validate
 * @param localOptions The options for the rule, excluding severity
 * @throws {Error} Any rule validation errors.
 */

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
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(''),
      );
    }
  }
}

validateRuleOptions(rule: AnyRuleModule, ruleId: string, options: Linter.RuleEntry, source: string | null): void

Validates a rule's options against its schema.

Parameters:

  • rule any: The rule that the config is being validated for
  • ruleId any: The rule's unique name.
  • options any: The given options for the rule.
  • source any: 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.
Raw 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.
 */

Calls:

  • validateRuleSeverity
  • validateRuleSchema
  • Array.isArray
  • options.slice
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}`, { cause: err });
    } else {
      throw new Error(enhancedMessage, { cause: err });
    }
  }
}

validateRules(rulesConfig: Linter.RulesRecord | undefined, source: string, getAdditionalRule: GetAdditionalRule): void

Validates a rules config object

Parameters:

  • rulesConfig any: The rules config object to validate.
  • source any: The name of the configuration source to report in any errors.
  • getAdditionalRule any: A map from strings to loaded rules
Raw JSDoc
/**
 * Validates a rules config object
 * @param rulesConfig The rules config object to validate.
 * @param source The name of the configuration source to report in any errors.
 * @param getAdditionalRule A map from strings to loaded rules
 */

Calls:

  • Object.keys(rulesConfig).forEach
  • getAdditionalRule
  • builtinRules.get
  • validateRuleOptions

Internal Comments:

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion (x3)

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);
  });
}

formatErrors(errors: AjvErrorObject[]): string

Formats an array of schema validation errors.

Raw JSDoc
/**
 * Formats an array of schema validation errors.
 */

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:

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment (x2)

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('');
}

validateConfigSchema(config: TesterConfigWithDefaults, source: string): void

Validates the top level properties of the config object.

Parameters:

  • config any: The config object to validate.
  • source any: The name of the configuration source to report in any errors.

Throws:

  • Error: For any config invalid per the schema.
Raw JSDoc
/**
 * Validates the top level properties of the config object.
 * @param config The config object to validate.
 * @param source The name of the configuration source to report in any errors.
 * @throws {Error} For any config invalid per the schema.
 */

Calls:

  • ajv.compile
  • validateSchema
  • formatErrors
  • hasOwnProperty (from ./hasOwnProperty)
  • emitDeprecationWarning (from ./deprecation-warnings)

Internal Comments:

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion (x3)
// @ts-expect-error -- intentional deprecated check

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');
  }
}

Type Aliases

GetAdditionalRule

type GetAdditionalRule = (ruleId: string) => AnyRuleModule | null;

Generated by Syntax Scribe