eslint-doc-generator
Advanced tools
Comparing version 0.13.0 to 0.14.0
@@ -1,6 +0,6 @@ | ||
import type { Plugin, ConfigsToRules, ConfigEmojis } from './types.js'; | ||
import type { Plugin, ConfigsToRules, ConfigEmojis, RuleSeverity } from './types.js'; | ||
/** | ||
* Get config names that a given rule belongs to. | ||
*/ | ||
export declare function getConfigsForRule(ruleName: string, configsToRules: ConfigsToRules, pluginPrefix: string): string[]; | ||
export declare function getConfigsForRule(ruleName: string, configsToRules: ConfigsToRules, pluginPrefix: string, severity: Set<RuleSeverity>): string[]; | ||
/** | ||
@@ -7,0 +7,0 @@ * Parse the options, check for errors, and set defaults. |
import { EMOJI_CONFIGS } from './emojis.js'; | ||
const SEVERITY_ENABLED = new Set([2, 'error']); | ||
/** | ||
* Get config names that a given rule belongs to. | ||
*/ | ||
export function getConfigsForRule(ruleName, configsToRules, pluginPrefix) { | ||
export function getConfigsForRule(ruleName, configsToRules, pluginPrefix, severity) { | ||
const configNames = []; | ||
@@ -12,7 +11,7 @@ for (const configName in configsToRules) { | ||
const isEnabled = ((typeof value === 'string' || typeof value === 'number') && | ||
SEVERITY_ENABLED.has(value)) || | ||
severity.has(value)) || | ||
(typeof value === 'object' && | ||
Array.isArray(value) && | ||
value.length > 0 && | ||
SEVERITY_ENABLED.has(value[0])); | ||
severity.has(value[0])); | ||
if (isEnabled) { | ||
@@ -19,0 +18,0 @@ configNames.push(configName); |
@@ -1,2 +0,2 @@ | ||
import { COLUMN_TYPE, ConfigEmojis, Plugin } from './types.js'; | ||
export declare function generateLegend(columns: Record<COLUMN_TYPE, boolean>, plugin: Plugin, configEmojis: ConfigEmojis, ignoreConfig: string[], urlConfigs?: string): string; | ||
import { COLUMN_TYPE, ConfigEmojis, Plugin, ConfigsToRules } from './types.js'; | ||
export declare function generateLegend(columns: Record<COLUMN_TYPE, boolean>, plugin: Plugin, configsToRules: ConfigsToRules, configEmojis: ConfigEmojis, pluginPrefix: string, ignoreConfig: string[], urlConfigs?: string): string; |
import { EMOJI_DEPRECATED, EMOJI_FIXABLE, EMOJI_HAS_SUGGESTIONS, EMOJI_CONFIG, EMOJI_REQUIRES_TYPE_CHECKING, EMOJI_TYPE, } from './emojis.js'; | ||
import { COLUMN_TYPE } from './types.js'; | ||
import { getConfigsForRule } from './configs.js'; | ||
import { COLUMN_TYPE, SEVERITY_ERROR, } from './types.js'; | ||
import { RULE_TYPE_MESSAGES_LEGEND, RULE_TYPES } from './rule-type.js'; | ||
@@ -9,8 +10,7 @@ /** | ||
// Legends are included for each config. A generic config legend is also included if there are multiple configs. | ||
[COLUMN_TYPE.CONFIGS]: ({ plugin, configEmojis, urlConfigs, ignoreConfig, }) => { | ||
[COLUMN_TYPE.CONFIGS]: ({ plugin, configsToRules, configEmojis, pluginPrefix, urlConfigs, ignoreConfig, }) => { | ||
/* istanbul ignore next -- this shouldn't happen */ | ||
if (!plugin.configs) { | ||
throw new Error('Should not be attempting to display configs column when there are no configs.'); | ||
if (!plugin.configs || !plugin.rules) { | ||
throw new Error('Should not be attempting to display configs column when there are no configs/rules.'); | ||
} | ||
const configNames = Object.keys(plugin.configs); | ||
// Add link to configs documentation if provided. | ||
@@ -23,6 +23,14 @@ const configsLinkOrWord = urlConfigs | ||
: 'configuration'; | ||
const configNamesWithoutIgnored = configNames.filter((configName) => !ignoreConfig?.includes(configName)); | ||
const ruleNames = Object.keys(plugin.rules); | ||
const configsThatEnableAnyRule = Object.entries(configsToRules) | ||
.filter(([configName, _config]) => ruleNames.some((ruleName) => getConfigsForRule(ruleName, configsToRules, pluginPrefix, SEVERITY_ERROR).includes(configName))) | ||
.map(([configName, _config]) => configName); | ||
const configNamesWithoutIgnored = configsThatEnableAnyRule.filter((configName) => !ignoreConfig?.includes(configName)); | ||
const legends = []; | ||
if (configNamesWithoutIgnored.length > 1 || | ||
!configEmojis.find((configEmoji) => configNamesWithoutIgnored?.includes(configEmoji.config))?.emoji) { | ||
if ((configNamesWithoutIgnored.length > 1 || | ||
!configEmojis.find((configEmoji) => configNamesWithoutIgnored?.includes(configEmoji.config))?.emoji) && | ||
// If any configs are using the generic config emoji, then don't display the generic config legend. | ||
!configEmojis | ||
.filter(({ config }) => !ignoreConfig?.includes(config)) | ||
.some((configEmoji) => configEmoji.emoji === EMOJI_CONFIG)) { | ||
// Generic config emoji will be used if the plugin has multiple configs or the sole config has no emoji. | ||
@@ -73,3 +81,3 @@ legends.push(`${EMOJI_CONFIG} ${configsLinkOrWord} enabled in.`); | ||
}; | ||
export function generateLegend(columns, plugin, configEmojis, ignoreConfig, urlConfigs) { | ||
export function generateLegend(columns, plugin, configsToRules, configEmojis, pluginPrefix, ignoreConfig, urlConfigs) { | ||
return Object.entries(columns) | ||
@@ -89,3 +97,5 @@ .flatMap(([columnType, enabled]) => { | ||
plugin, | ||
configsToRules, | ||
configEmojis, | ||
pluginPrefix, | ||
urlConfigs, | ||
@@ -92,0 +102,0 @@ ignoreConfig, |
@@ -1,3 +0,3 @@ | ||
export declare const BEGIN_RULE_LIST_MARKER = "<!-- begin rules list -->"; | ||
export declare const END_RULE_LIST_MARKER = "<!-- end rules list -->"; | ||
export declare const END_RULE_HEADER_MARKER = "<!-- end rule header -->"; | ||
export declare const BEGIN_RULE_LIST_MARKER = "<!-- begin auto-generated rules list -->"; | ||
export declare const END_RULE_LIST_MARKER = "<!-- end auto-generated rules list -->"; | ||
export declare const END_RULE_HEADER_MARKER = "<!-- end auto-generated rule header -->"; |
// Markers so that the README rules list can be automatically updated. | ||
export const BEGIN_RULE_LIST_MARKER = '<!-- begin rules list -->'; | ||
export const END_RULE_LIST_MARKER = '<!-- end rules list -->'; | ||
export const BEGIN_RULE_LIST_MARKER = '<!-- begin auto-generated rules list -->'; | ||
export const END_RULE_LIST_MARKER = '<!-- end auto-generated rules list -->'; | ||
// Marker so that rule doc header (title/notices) can be automatically updated. | ||
export const END_RULE_HEADER_MARKER = '<!-- end rule header -->'; | ||
export const END_RULE_HEADER_MARKER = '<!-- end auto-generated rule header -->'; |
@@ -9,12 +9,9 @@ import { BEGIN_RULE_LIST_MARKER, END_RULE_LIST_MARKER } from './markers.js'; | ||
import { relative } from 'node:path'; | ||
import { COLUMN_TYPE } from './types.js'; | ||
import { COLUMN_TYPE, SEVERITY_ERROR } from './types.js'; | ||
import { markdownTable } from 'markdown-table'; | ||
import { EMOJIS_TYPE } from './rule-type.js'; | ||
function getConfigurationColumnValueForRule(rule, configsToRules, pluginPrefix, configEmojis, ignoreConfig) { | ||
const badges = []; | ||
const configs = getConfigsForRule(rule.name, configsToRules, pluginPrefix); | ||
for (const configName of configs) { | ||
if (ignoreConfig?.includes(configName)) { | ||
// Ignore config. | ||
continue; | ||
} | ||
const configsEnabled = getConfigsForRule(rule.name, configsToRules, pluginPrefix, SEVERITY_ERROR).filter((configName) => !ignoreConfig?.includes(configName)); | ||
for (const configName of configsEnabled) { | ||
// Find the emoji for the config or otherwise use a badge that can be defined in markdown. | ||
@@ -53,6 +50,10 @@ const emoji = configEmojis.find((configEmoji) => configEmoji.config === configName)?.emoji; | ||
const headerStrOrFn = COLUMN_HEADER[columnType]; | ||
const ruleNames = details.map((rule) => rule.name); | ||
const configsThatEnableAnyRule = Object.entries(configsToRules) | ||
.filter(([configName, _config]) => ruleNames.some((ruleName) => getConfigsForRule(ruleName, configsToRules, pluginPrefix, SEVERITY_ERROR).includes(configName))) | ||
.map(([configName, _config]) => configName); | ||
return [ | ||
typeof headerStrOrFn === 'function' | ||
? headerStrOrFn({ | ||
configNames: Object.keys(configsToRules), | ||
configNames: configsThatEnableAnyRule, | ||
configEmojis, | ||
@@ -65,12 +66,9 @@ ignoreConfig, | ||
}); | ||
const listSpacerRow = Array.from({ length: listHeaderRow.length }).fill(':--'); // Left-align header with colon. | ||
return [ | ||
return markdownTable([ | ||
listHeaderRow, | ||
listSpacerRow, | ||
...details | ||
.sort(({ name: a }, { name: b }) => a.localeCompare(b)) | ||
.map((rule) => buildRuleRow(columns, rule, configsToRules, pluginPrefix, configEmojis, ignoreConfig)), | ||
] | ||
.map((column) => [...column, ' '].join('|')) | ||
.join('\n'); | ||
], { align: 'l' } // Left-align headers. | ||
); | ||
} | ||
@@ -105,3 +103,3 @@ export async function updateRulesList(details, markdown, plugin, configsToRules, pluginPrefix, pathToReadme, pathToPlugin, configEmojis, ignoreConfig, ruleListColumns, urlConfigs) { | ||
// New legend. | ||
const legend = generateLegend(columns, plugin, configEmojis, ignoreConfig, urlConfigs); | ||
const legend = generateLegend(columns, plugin, configsToRules, configEmojis, pluginPrefix, ignoreConfig, urlConfigs); | ||
// New rule list. | ||
@@ -108,0 +106,0 @@ const list = generateRulesListMarkdown(columns, details, configsToRules, pluginPrefix, configEmojis, ignoreConfig); |
@@ -6,3 +6,3 @@ import { END_RULE_HEADER_MARKER } from './markers.js'; | ||
import { RULE_DOC_TITLE_FORMAT_DEFAULT, } from './rule-doc-title-format.js'; | ||
import { NOTICE_TYPE } from './types.js'; | ||
import { NOTICE_TYPE, SEVERITY_ERROR, SEVERITY_OFF } from './types.js'; | ||
export const NOTICE_TYPE_DEFAULT_PRESENCE_AND_ORDERING = { | ||
@@ -24,3 +24,3 @@ // Object keys ordered in display order. | ||
// Configs notice varies based on whether the rule is enabled in one or more configs. | ||
[NOTICE_TYPE.CONFIGS]: ({ configsEnabled, configEmojis, urlConfigs }) => { | ||
[NOTICE_TYPE.CONFIGS]: ({ configsEnabled, configsDisabled, configEmojis, urlConfigs, }) => { | ||
// Add link to configs documentation if provided. | ||
@@ -32,20 +32,47 @@ const configsLinkOrWord = urlConfigs | ||
/* istanbul ignore next -- this shouldn't happen */ | ||
if (!configsEnabled || configsEnabled.length === 0) { | ||
throw new Error('Should not be trying to display config notice for rule not enabled in any configs.'); | ||
if ((!configsEnabled || configsEnabled.length === 0) && | ||
(!configsDisabled || configsDisabled.length === 0)) { | ||
throw new Error('Should not be trying to display config notice for rule not enabled/disabled in any configs.'); | ||
} | ||
if (configsEnabled.length > 1) { | ||
// Rule is enabled in multiple configs. | ||
const configs = configsEnabled | ||
.map((configEnabled) => { | ||
const emoji = configEmojis.find((configEmoji) => configEmoji.config === configEnabled)?.emoji; | ||
return `${emoji ? `${emoji} ` : ''}\`${configEnabled}\``; | ||
}) | ||
.join(', '); | ||
return `${EMOJI_CONFIG} This rule is enabled in the following ${configsLinkOrWord}: ${configs}.`; | ||
// If one applicable config with an emoji, use the emoji for that config, otherwise use the general config emoji. | ||
let emoji = ''; | ||
if (configsEnabled.length + configsDisabled.length > 1) { | ||
emoji = EMOJI_CONFIG; | ||
} | ||
else { | ||
// Rule only enabled in one config. | ||
const emoji = configEmojis.find((configEmoji) => configEmoji.config === configsEnabled?.[0])?.emoji ?? EMOJI_CONFIG; | ||
return `${emoji} This rule is enabled in the \`${configsEnabled?.[0]}\` ${configLinkOrWord}.`; | ||
else if (configsEnabled.length > 0) { | ||
emoji = | ||
configEmojis.find((configEmoji) => configEmoji.config === configsEnabled[0])?.emoji ?? EMOJI_CONFIG; | ||
} | ||
else if (configsDisabled.length > 0) { | ||
emoji = | ||
configEmojis.find((configEmoji) => configEmoji.config === configsDisabled[0])?.emoji ?? EMOJI_CONFIG; | ||
} | ||
// List of configs that enable the rule. | ||
const configsEnabledCSV = configsEnabled | ||
.map((configEnabled) => { | ||
const emoji = configEmojis.find((configEmoji) => configEmoji.config === configEnabled)?.emoji; | ||
return `${emoji ? `${emoji} ` : ''}\`${configEnabled}\``; | ||
}) | ||
.join(', '); | ||
// List of configs that disable the rule. | ||
const configsDisabledCSV = configsDisabled | ||
.map((configDisabled) => { | ||
const emoji = configEmojis.find((configEmoji) => configEmoji.config === configDisabled)?.emoji; | ||
return `${emoji ? `${emoji} ` : ''}\`${configDisabled}\``; | ||
}) | ||
.join(', '); | ||
// Complete sentence for configs that enable the rule. | ||
const SENTENCE_ENABLED = configsEnabled.length > 1 | ||
? `This rule is enabled in the following ${configsLinkOrWord}: ${configsEnabledCSV}.` | ||
: configsEnabled.length === 1 | ||
? `This rule is enabled in the \`${configsEnabled?.[0]}\` ${configLinkOrWord}.` | ||
: ''; | ||
// Complete sentence for configs that disable the rule. | ||
const SENTENCE_DISABLED = configsDisabled.length > 1 | ||
? `This rule is _disabled_ in the following ${configsLinkOrWord}: ${configsDisabledCSV}.` | ||
: configsDisabled.length === 1 | ||
? `This rule is _disabled_ in the \`${configsDisabled?.[0]}\` ${configLinkOrWord}.` | ||
: ''; | ||
return `${emoji} ${SENTENCE_ENABLED}${SENTENCE_ENABLED && SENTENCE_DISABLED ? ' ' : '' // Space if two sentences. | ||
}${SENTENCE_DISABLED}`; | ||
}, | ||
@@ -74,3 +101,3 @@ // Deprecated notice has optional "replaced by" rules list. | ||
return ruleNames | ||
.map((ruleName) => `[${ruleName}](${ruleName}.md)`) | ||
.map((ruleName) => `[\`${ruleName}\`](${ruleName}.md)`) | ||
.join(', '); | ||
@@ -81,6 +108,6 @@ } | ||
*/ | ||
function getNoticesForRule(rule, configsEnabled, ruleDocNotices) { | ||
function getNoticesForRule(rule, configsEnabled, configsDisabled, ruleDocNotices) { | ||
const notices = { | ||
// Alphabetical order. | ||
[NOTICE_TYPE.CONFIGS]: configsEnabled.length > 0, | ||
[NOTICE_TYPE.CONFIGS]: configsEnabled.length > 0 || configsDisabled.length > 0, | ||
[NOTICE_TYPE.DEPRECATED]: rule.meta.deprecated || false, | ||
@@ -117,4 +144,5 @@ // FIXABLE_AND_HAS_SUGGESTIONS potentially replaces FIXABLE and HAS_SUGGESTIONS. | ||
} | ||
const configsEnabled = getConfigsForRule(ruleName, configsToRules, pluginPrefix).filter((config) => !ignoreConfig?.includes(config)); | ||
const notices = getNoticesForRule(rule, configsEnabled, ruleDocNotices); | ||
const configsEnabled = getConfigsForRule(ruleName, configsToRules, pluginPrefix, SEVERITY_ERROR).filter((configName) => !ignoreConfig?.includes(configName)); | ||
const configsDisabled = getConfigsForRule(ruleName, configsToRules, pluginPrefix, SEVERITY_OFF).filter((configName) => !ignoreConfig?.includes(configName)); | ||
const notices = getNoticesForRule(rule, configsEnabled, configsDisabled, ruleDocNotices); | ||
let noticeType; | ||
@@ -137,2 +165,3 @@ for (noticeType in notices) { | ||
configsEnabled, | ||
configsDisabled, | ||
configEmojis, | ||
@@ -139,0 +168,0 @@ urlConfigs, |
import type { TSESLint, JSONSchema } from '@typescript-eslint/utils'; | ||
export declare type RuleModule = TSESLint.RuleModule<string, unknown[]>; | ||
export declare type Rules = TSESLint.Linter.RulesRecord; | ||
export declare type RuleSeverity = TSESLint.Linter.RuleLevel; | ||
export declare type Config = TSESLint.Linter.Config; | ||
export declare type Plugin = TSESLint.Linter.Plugin; | ||
export declare const SEVERITY_ERROR: Set<TSESLint.Linter.RuleLevel>; | ||
export declare const SEVERITY_OFF: Set<TSESLint.Linter.RuleLevel>; | ||
export declare type ConfigsToRules = Record<string, Rules>; | ||
@@ -7,0 +10,0 @@ export interface RuleDetails { |
@@ -0,1 +1,4 @@ | ||
// Custom types. | ||
export const SEVERITY_ERROR = new Set([2, 'error']); | ||
export const SEVERITY_OFF = new Set([0, 'off']); | ||
/** | ||
@@ -2,0 +5,0 @@ * Rule doc notices. |
{ | ||
"name": "eslint-doc-generator", | ||
"version": "0.13.0", | ||
"version": "0.14.0", | ||
"description": "Automatic documentation generator for ESLint plugins and rules.", | ||
@@ -48,2 +48,3 @@ "keywords": [ | ||
"commander": "^9.4.0", | ||
"markdown-table": "^3.0.2", | ||
"type-fest": "^3.0.0" | ||
@@ -50,0 +51,0 @@ }, |
@@ -48,4 +48,4 @@ # eslint-doc-generator | ||
```md | ||
<!-- begin rules list --> | ||
<!-- end rules list --> | ||
<!-- begin auto-generated rules list --> | ||
<!-- end auto-generated rules list --> | ||
``` | ||
@@ -74,2 +74,4 @@ | ||
🎨 This rule is _disabled_ in the `stylistic` config. | ||
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix). | ||
@@ -79,2 +81,4 @@ | ||
🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). | ||
💭 This rule requires type information. | ||
@@ -90,3 +94,3 @@ | ||
<!-- end rule header --> | ||
<!-- end auto-generated rule header --> | ||
@@ -109,3 +113,3 @@ Description. | ||
<!-- begin rules list --> | ||
<!-- begin auto-generated rules list --> | ||
@@ -130,3 +134,3 @@ 💼 Configurations enabled in.\ | ||
<!-- end rules list --> | ||
<!-- end auto-generated rules list --> | ||
@@ -133,0 +137,0 @@ ... |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
74453
1337
188
6
+ Addedmarkdown-table@^3.0.2
+ Addedmarkdown-table@3.0.4(transitive)