UNPKG

eslint-doc-generator

Version:

Automatic documentation generator for ESLint plugins and rules.

130 lines (129 loc) 6.53 kB
import { join } from 'node:path'; import { COLUMN_TYPE, NOTICE_TYPE, OPTION_TYPE } from './types.js'; import { parseConfigEmojiOptions, parseRuleDocNoticesOption, parseRuleListColumnsOption, } from './option-parsers.js'; export const COLUMN_TYPE_DEFAULT_PRESENCE_AND_ORDERING = { // Object keys ordered in display order. // Object values indicate whether the column is displayed by default. [COLUMN_TYPE.NAME]: true, [COLUMN_TYPE.DESCRIPTION]: true, [COLUMN_TYPE.CONFIGS_ERROR]: true, [COLUMN_TYPE.CONFIGS_WARN]: true, [COLUMN_TYPE.CONFIGS_OFF]: true, [COLUMN_TYPE.FIXABLE]: true, [COLUMN_TYPE.FIXABLE_AND_HAS_SUGGESTIONS]: false, // Optional, consolidated column. [COLUMN_TYPE.HAS_SUGGESTIONS]: true, [COLUMN_TYPE.OPTIONS]: false, [COLUMN_TYPE.REQUIRES_TYPE_CHECKING]: true, [COLUMN_TYPE.TYPE]: false, [COLUMN_TYPE.DEPRECATED]: true, }; export const NOTICE_TYPE_DEFAULT_PRESENCE_AND_ORDERING = { // Object keys ordered in display order. // Object values indicate whether the column is displayed by default. [NOTICE_TYPE.DESCRIPTION]: true, [NOTICE_TYPE.DEPRECATED]: true, // Most important. [NOTICE_TYPE.CONFIGS]: true, [NOTICE_TYPE.FIXABLE]: false, [NOTICE_TYPE.FIXABLE_AND_HAS_SUGGESTIONS]: true, // Default, consolidated notice. [NOTICE_TYPE.HAS_SUGGESTIONS]: false, [NOTICE_TYPE.OPTIONS]: false, [NOTICE_TYPE.REQUIRES_TYPE_CHECKING]: true, [NOTICE_TYPE.TYPE]: false, }; // Using these variables ensures they have the correct type (not just a plain string). const DEFAULT_RULE_DOC_TITLE_FORMAT = 'prefix-name'; const DEFAULT_CONFIG_FORMAT = 'name'; export const OPTION_DEFAULTS = { [OPTION_TYPE.CHECK]: false, [OPTION_TYPE.CONFIG_EMOJI]: [], [OPTION_TYPE.CONFIG_FORMAT]: DEFAULT_CONFIG_FORMAT, [OPTION_TYPE.IGNORE_CONFIG]: [], [OPTION_TYPE.IGNORE_DEPRECATED_RULES]: false, [OPTION_TYPE.INIT_RULE_DOCS]: false, [OPTION_TYPE.PATH_RULE_DOC]: join('docs', 'rules', '{name}.md'), [OPTION_TYPE.PATH_RULE_LIST]: ['README.md'], [OPTION_TYPE.POSTPROCESS]: (content) => content, [OPTION_TYPE.RULE_DOC_NOTICES]: Object.entries(NOTICE_TYPE_DEFAULT_PRESENCE_AND_ORDERING) .filter(([_col, enabled]) => enabled) .map(([col]) => col), [OPTION_TYPE.RULE_DOC_SECTION_EXCLUDE]: [], [OPTION_TYPE.RULE_DOC_SECTION_INCLUDE]: [], [OPTION_TYPE.RULE_DOC_SECTION_OPTIONS]: true, [OPTION_TYPE.RULE_DOC_TITLE_FORMAT]: DEFAULT_RULE_DOC_TITLE_FORMAT, [OPTION_TYPE.RULE_LIST_COLUMNS]: Object.entries(COLUMN_TYPE_DEFAULT_PRESENCE_AND_ORDERING) .filter(([_col, enabled]) => enabled) .map(([col]) => col), [OPTION_TYPE.RULE_LIST_SPLIT]: [], [OPTION_TYPE.URL_CONFIGS]: undefined, [OPTION_TYPE.URL_RULE_DOC]: undefined, }; // Satisfies is used to ensure all options are included without losing type information. /** * Combines user-provided options with default options. Additionally, this performs some basic * normalization, like converting "foo" to "[foo]" for options that are lists. */ export function getResolvedOptions(plugin, userOptions = {}) { const check = userOptions.check ?? OPTION_DEFAULTS[OPTION_TYPE.CHECK]; const configEmoji = userOptions.configEmoji ?? OPTION_DEFAULTS[OPTION_TYPE.CONFIG_EMOJI]; const configEmojis = parseConfigEmojiOptions(plugin, configEmoji); const configFormat = userOptions.configFormat ?? OPTION_DEFAULTS[OPTION_TYPE.CONFIG_FORMAT]; const ignoreConfig = stringOrArrayWithFallback(userOptions.ignoreConfig, OPTION_DEFAULTS[OPTION_TYPE.IGNORE_CONFIG]); const ignoreDeprecatedRules = userOptions.ignoreDeprecatedRules ?? OPTION_DEFAULTS[OPTION_TYPE.IGNORE_DEPRECATED_RULES]; const initRuleDocs = userOptions.initRuleDocs ?? OPTION_DEFAULTS[OPTION_TYPE.INIT_RULE_DOCS]; const pathRuleDoc = userOptions.pathRuleDoc ?? OPTION_DEFAULTS[OPTION_TYPE.PATH_RULE_DOC]; const pathRuleList = stringOrArrayToArrayWithFallback(userOptions.pathRuleList, OPTION_DEFAULTS[OPTION_TYPE.PATH_RULE_LIST]); const postprocess = userOptions.postprocess ?? OPTION_DEFAULTS[OPTION_TYPE.POSTPROCESS]; const ruleDocNotices = parseRuleDocNoticesOption(userOptions.ruleDocNotices); const ruleDocSectionExclude = stringOrArrayWithFallback(userOptions.ruleDocSectionExclude, OPTION_DEFAULTS[OPTION_TYPE.RULE_DOC_SECTION_EXCLUDE]); const ruleDocSectionInclude = stringOrArrayWithFallback(userOptions.ruleDocSectionInclude, OPTION_DEFAULTS[OPTION_TYPE.RULE_DOC_SECTION_INCLUDE]); const ruleDocSectionOptions = userOptions.ruleDocSectionOptions ?? OPTION_DEFAULTS[OPTION_TYPE.RULE_DOC_SECTION_OPTIONS]; const ruleDocTitleFormat = userOptions.ruleDocTitleFormat ?? OPTION_DEFAULTS[OPTION_TYPE.RULE_DOC_TITLE_FORMAT]; const ruleListColumns = parseRuleListColumnsOption(userOptions.ruleListColumns); const ruleListSplit = typeof userOptions.ruleListSplit === 'function' ? userOptions.ruleListSplit : stringOrArrayToArrayWithFallback(userOptions.ruleListSplit, OPTION_DEFAULTS[OPTION_TYPE.RULE_LIST_SPLIT]); const urlConfigs = userOptions.urlConfigs ?? OPTION_DEFAULTS[OPTION_TYPE.URL_CONFIGS]; const urlRuleDoc = userOptions.urlRuleDoc ?? OPTION_DEFAULTS[OPTION_TYPE.URL_RULE_DOC]; return { check, configEmojis, configFormat, ignoreConfig, ignoreDeprecatedRules, initRuleDocs, pathRuleDoc, pathRuleList, postprocess, ruleDocNotices, ruleDocSectionExclude, ruleDocSectionInclude, ruleDocSectionOptions, ruleDocTitleFormat, ruleListColumns, ruleListSplit, urlConfigs, urlRuleDoc, }; } function stringOrArrayWithFallback(stringOrArray, fallback) { return stringOrArray !== undefined && stringOrArray.length > 0 ? stringOrArray : fallback; } function stringOrArrayToArrayWithFallback(stringOrArray, fallback) { const asArray = // Using the "Array.isArray" method loses type information about the array. // eslint-disable-next-line unicorn/no-instanceof-builtins stringOrArray instanceof Array ? stringOrArray : stringOrArray ? [stringOrArray] : []; const csvStringItem = asArray.find((item) => item.includes(',')); if (csvStringItem !== undefined) { throw new Error(`Provide property as array, not a CSV string: ${csvStringItem}`); } return asArray.length > 0 ? asArray : fallback; }