flat-config-helpers.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /**
  2. * @fileoverview Shared functions to work with configs.
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Typedefs
  8. //------------------------------------------------------------------------------
  9. /** @typedef {import("../shared/types").Rule} Rule */
  10. //------------------------------------------------------------------------------
  11. // Private Members
  12. //------------------------------------------------------------------------------
  13. // JSON schema that disallows passing any options
  14. const noOptionsSchema = Object.freeze({
  15. type: "array",
  16. minItems: 0,
  17. maxItems: 0
  18. });
  19. //-----------------------------------------------------------------------------
  20. // Functions
  21. //-----------------------------------------------------------------------------
  22. /**
  23. * Parses a ruleId into its plugin and rule parts.
  24. * @param {string} ruleId The rule ID to parse.
  25. * @returns {{pluginName:string,ruleName:string}} The plugin and rule
  26. * parts of the ruleId;
  27. */
  28. function parseRuleId(ruleId) {
  29. let pluginName, ruleName;
  30. // distinguish between core rules and plugin rules
  31. if (ruleId.includes("/")) {
  32. // mimic scoped npm packages
  33. if (ruleId.startsWith("@")) {
  34. pluginName = ruleId.slice(0, ruleId.lastIndexOf("/"));
  35. } else {
  36. pluginName = ruleId.slice(0, ruleId.indexOf("/"));
  37. }
  38. ruleName = ruleId.slice(pluginName.length + 1);
  39. } else {
  40. pluginName = "@";
  41. ruleName = ruleId;
  42. }
  43. return {
  44. pluginName,
  45. ruleName
  46. };
  47. }
  48. /**
  49. * Retrieves a rule instance from a given config based on the ruleId.
  50. * @param {string} ruleId The rule ID to look for.
  51. * @param {FlatConfig} config The config to search.
  52. * @returns {import("../shared/types").Rule|undefined} The rule if found
  53. * or undefined if not.
  54. */
  55. function getRuleFromConfig(ruleId, config) {
  56. const { pluginName, ruleName } = parseRuleId(ruleId);
  57. return config.plugins?.[pluginName]?.rules?.[ruleName];
  58. }
  59. /**
  60. * Gets a complete options schema for a rule.
  61. * @param {Rule} rule A rule object
  62. * @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
  63. * @returns {Object|null} JSON Schema for the rule's options. `null` if `meta.schema` is `false`.
  64. */
  65. function getRuleOptionsSchema(rule) {
  66. if (!rule.meta) {
  67. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  68. }
  69. const schema = rule.meta.schema;
  70. if (typeof schema === "undefined") {
  71. return { ...noOptionsSchema }; // default if `meta.schema` is not specified
  72. }
  73. // `schema:false` is an allowed explicit opt-out of options validation for the rule
  74. if (schema === false) {
  75. return null;
  76. }
  77. if (typeof schema !== "object" || schema === null) {
  78. throw new TypeError("Rule's `meta.schema` must be an array or object");
  79. }
  80. // ESLint-specific array form needs to be converted into a valid JSON Schema definition
  81. if (Array.isArray(schema)) {
  82. if (schema.length) {
  83. return {
  84. type: "array",
  85. items: schema,
  86. minItems: 0,
  87. maxItems: schema.length
  88. };
  89. }
  90. // `schema:[]` is an explicit way to specify that the rule does not accept any options
  91. return { ...noOptionsSchema };
  92. }
  93. // `schema:<object>` is assumed to be a valid JSON Schema definition
  94. return schema;
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Exports
  98. //-----------------------------------------------------------------------------
  99. module.exports = {
  100. parseRuleId,
  101. getRuleFromConfig,
  102. getRuleOptionsSchema
  103. };