eslint-doc-generator
Version:
Automatic documentation generator for ESLint plugins and rules.
130 lines (129 loc) • 6.53 kB
JavaScript
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.
[]: true,
[]: true,
[]: true,
[]: true,
[]: true,
[]: true,
[]: false, // Optional, consolidated column.
[]: true,
[]: false,
[]: true,
[]: false,
[]: 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.
[]: true,
[]: true, // Most important.
[]: true,
[]: false,
[]: true, // Default, consolidated notice.
[]: false,
[]: false,
[]: true,
[]: 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 = {
[]: false,
[]: [],
[]: DEFAULT_CONFIG_FORMAT,
[]: [],
[]: false,
[]: false,
[]: join('docs', 'rules', '{name}.md'),
[]: ['README.md'],
[]: (content) => content,
[]: Object.entries(NOTICE_TYPE_DEFAULT_PRESENCE_AND_ORDERING)
.filter(([_col, enabled]) => enabled)
.map(([col]) => col),
[]: [],
[]: [],
[]: true,
[]: DEFAULT_RULE_DOC_TITLE_FORMAT,
[]: Object.entries(COLUMN_TYPE_DEFAULT_PRESENCE_AND_ORDERING)
.filter(([_col, enabled]) => enabled)
.map(([col]) => col),
[]: [],
[]: undefined,
[]: 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;
}