From 5022ea4f2026d2fccd7f5185b50744eec2e5315c Mon Sep 17 00:00:00 2001 From: Bryan Mishkin <698306+bmish@users.noreply.github.com> Date: Tue, 1 Nov 2022 13:47:45 -0400 Subject: [PATCH] fix: Ensure notation for config that warns/disables a rule does not wrap to separate line (attempt 2) --- README.md | 4 +- lib/configs.ts | 17 +-- lib/rule-list.ts | 125 +++++++++--------- lib/types.ts | 8 ++ test/lib/__snapshots__/generator-test.ts.snap | 32 ++--- 5 files changed, 94 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 52b970f2..064885fc 100644 --- a/README.md +++ b/README.md @@ -219,11 +219,11 @@ If you have a build step for your code like [Babel](https://babeljs.io/) or [Typ ### markdownlint -The output of this tool should be compatible with [markdownlint](https://github.com/DavidAnson/markdownlint) which you might use to lint your markdown. However, if any of your ESLint configs disable your rules or set them to warn, you'll need to exempt some elements used for the emoji superscript from [no-inline-html](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md033---inline-html): +The output of this tool should be compatible with [markdownlint](https://github.com/DavidAnson/markdownlint) which you might use to lint your markdown. However, if any of your ESLint configs disable your rules or set them to warn, you'll need to exempt some elements used for emoji superscripts from [no-inline-html](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md033---inline-html): ```json { - "no-inline-html": { "allowed_elements": ["span", "sup"] } + "no-inline-html": { "allowed_elements": ["br", "sup"] } } ``` diff --git a/lib/configs.ts b/lib/configs.ts index 5e44ab1e..75f98948 100644 --- a/lib/configs.ts +++ b/lib/configs.ts @@ -98,19 +98,12 @@ export function parseConfigEmojiOptions( return configEmojis; } -function emojiWithSuperscript( - emoji: string, - superscriptEmoji: string, - noWrap = false -) { +function emojiWithSuperscript(emoji: string, superscriptEmoji: string) { if (emoji === superscriptEmoji) { // Avoid double emoji. return emoji; } - // Style is to ensure superscript doesn't wrap to separate line, useful in constrained spaces. - return noWrap - ? `${emoji}${superscriptEmoji}` - : `${emoji}${superscriptEmoji}`; + return `${emoji}${superscriptEmoji}`; } /** @@ -120,7 +113,6 @@ function emojiWithSuperscript( * @param options * @param options.severity - if present, decorate the config's emoji for the given severity level * @param options.fallback - if true and no emoji is found, choose whether to fallback to a generic config emoji or a badge - * @param options.noWrap - whether to add styling to ensure the superscript doesn't wrap to a separate line when used in constrained spaces * @returns the string to display for the config */ export function findConfigEmoji( @@ -129,7 +121,6 @@ export function findConfigEmoji( options?: { severity?: SEVERITY_TYPE; fallback?: 'badge' | 'emoji'; - noWrap?: boolean; } ) { let emoji = configEmojis.find( @@ -148,9 +139,9 @@ export function findConfigEmoji( switch (options?.severity) { case 'warn': - return emojiWithSuperscript(emoji, EMOJI_CONFIG_WARN, options.noWrap); + return emojiWithSuperscript(emoji, EMOJI_CONFIG_WARN); case 'off': - return emojiWithSuperscript(emoji, EMOJI_CONFIG_OFF, options.noWrap); + return emojiWithSuperscript(emoji, EMOJI_CONFIG_OFF); default: return emoji; } diff --git a/lib/rule-list.ts b/lib/rule-list.ts index 8829c96b..c6cc987c 100644 --- a/lib/rule-list.ts +++ b/lib/rule-list.ts @@ -11,13 +11,7 @@ import { findSectionHeader } from './markdown.js'; import { getPluginRoot } from './package-json.js'; import { generateLegend } from './legend.js'; import { relative } from 'node:path'; -import { - COLUMN_TYPE, - SEVERITY_ERROR, - SEVERITY_WARN, - SEVERITY_OFF, - SEVERITY_TYPE, -} from './types.js'; +import { COLUMN_TYPE, SEVERITY_TYPE, SEVERITY_TYPE_TO_SET } from './types.js'; import { markdownTable } from 'markdown-table'; import camelCase from 'camelcase'; import type { @@ -65,6 +59,42 @@ function getPropertyFromRule( return result; } +/** + * Get the emojis for the configs that set a rule to a certain severity. + */ +function getEmojisForConfigsSettingRuleToSeverity( + ruleName: string, + configsToRulesWithoutIgnored: ConfigsToRules, + pluginPrefix: string, + configEmojis: ConfigEmojis, + severityType: SEVERITY_TYPE +) { + const severity = SEVERITY_TYPE_TO_SET[severityType]; + const configsOfThisSeverity = getConfigsForRule( + ruleName, + configsToRulesWithoutIgnored, + pluginPrefix, + severity + ); + + const emojis: string[] = []; + for (const configName of configsOfThisSeverity) { + // Find the emoji for each config or otherwise use a badge that can be defined in markdown. + const emoji = findConfigEmoji(configEmojis, configName, { + severity: severityType, + fallback: 'badge', + }); + /* istanbul ignore next -- this shouldn't happen */ + if (typeof emoji !== 'string') { + throw new TypeError('Emoji will always be a string thanks to fallback'); + } + // For emojis with a superscript, add a newline first to ensure we don't end up with a linebreak between the emoji and the superscript. + emojis.push(emoji.includes('') ? `
${emoji}` : emoji); + } + + return emojis; +} + function getConfigurationColumnValueForRule( rule: RuleDetails, configsToRules: ConfigsToRules, @@ -72,7 +102,7 @@ function getConfigurationColumnValueForRule( configEmojis: ConfigEmojis, ignoreConfig: string[] ): string { - const badges: string[] = []; + const emojis: string[] = []; const configsToRulesWithoutIgnored = Object.fromEntries( Object.entries(configsToRules).filter( @@ -80,63 +110,36 @@ function getConfigurationColumnValueForRule( ) ); - const configsEnabled = getConfigsForRule( - rule.name, - configsToRulesWithoutIgnored, - pluginPrefix, - SEVERITY_ERROR - ); - - const configsWarn = getConfigsForRule( - rule.name, - configsToRulesWithoutIgnored, - pluginPrefix, - SEVERITY_WARN - ); - - const configsOff = getConfigsForRule( - rule.name, - configsToRulesWithoutIgnored, - pluginPrefix, - SEVERITY_OFF + // Collect the emojis for the configs that set the rule to each severity level. + emojis.push( + ...getEmojisForConfigsSettingRuleToSeverity( + rule.name, + configsToRulesWithoutIgnored, + pluginPrefix, + configEmojis, + SEVERITY_TYPE.error + ), + ...getEmojisForConfigsSettingRuleToSeverity( + rule.name, + configsToRulesWithoutIgnored, + pluginPrefix, + configEmojis, + SEVERITY_TYPE.warn + ), + ...getEmojisForConfigsSettingRuleToSeverity( + rule.name, + configsToRulesWithoutIgnored, + pluginPrefix, + configEmojis, + SEVERITY_TYPE.off + ) ); - // Find the emoji for each config or otherwise use a badge that can be defined in markdown. - - for (const configName of configsEnabled) { - badges.push( - // @ts-expect-error -- will always be a string thanks to fallback - findConfigEmoji(configEmojis, configName, { - severity: SEVERITY_TYPE.error, - fallback: 'badge', - noWrap: true, - }) - ); - } - - for (const configName of configsWarn) { - badges.push( - // @ts-expect-error -- will always be a string thanks to fallback - findConfigEmoji(configEmojis, configName, { - severity: SEVERITY_TYPE.warn, - fallback: 'badge', - noWrap: true, - }) - ); - } - - for (const configName of configsOff) { - badges.push( - // @ts-expect-error -- will always be a string thanks to fallback - findConfigEmoji(configEmojis, configName, { - severity: SEVERITY_TYPE.off, - fallback: 'badge', - noWrap: true, - }) - ); + if (emojis.length > 0 && emojis[0].startsWith('
')) { + emojis[0] = emojis[0].slice(4); // Avoid any leading linebreak. Linebreak only necessary after emojis and before emojis with superscripts. } - return badges.join(' '); + return emojis.join(' '); } function buildRuleRow( diff --git a/lib/types.ts b/lib/types.ts index 2c112148..862736d1 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -24,6 +24,14 @@ export enum SEVERITY_TYPE { 'off' = 'off', } +export const SEVERITY_TYPE_TO_SET: { + [key in SEVERITY_TYPE]: Set; +} = { + [SEVERITY_TYPE.error]: SEVERITY_ERROR, + [SEVERITY_TYPE.warn]: SEVERITY_WARN, + [SEVERITY_TYPE.off]: SEVERITY_OFF, +}; + export type ConfigsToRules = Record; export interface RuleDetails { diff --git a/test/lib/__snapshots__/generator-test.ts.snap b/test/lib/__snapshots__/generator-test.ts.snap index f66b92c7..545e2e07 100644 --- a/test/lib/__snapshots__/generator-test.ts.snap +++ b/test/lib/__snapshots__/generator-test.ts.snap @@ -615,15 +615,15 @@ exports[`generator #generate rules that are disabled or set to warn generates th ✅⚠️ Warns in the \`recommended\` configuration.\\ ✅🚫 Disabled in the \`recommended\` configuration. -| Name | Description | 💼 | -| :----------------------------- | :--------------------- | :--------------------------------------------------------------------------------------------------------------------- | -| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | ![other][]🚫 🚫 | -| [no-baz](docs/rules/no-baz.md) | Description of no-baz. | ✅ ![other][]🚫 | -| [no-bez](docs/rules/no-bez.md) | Description of no-bez. | ![other][]⚠️ | -| [no-biz](docs/rules/no-biz.md) | Description of no-biz. | ![other][]🚫 | -| [no-boz](docs/rules/no-boz.md) | Description of no-boz. | ⚠️ | -| [no-buz](docs/rules/no-buz.md) | Description of no-buz. | ![other][]⚠️ ⚠️ | -| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | 🚫 | +| Name | Description | 💼 | +| :----------------------------- | :--------------------- | :----------------------------------------- | +| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | ![other][]🚫
🚫 | +| [no-baz](docs/rules/no-baz.md) | Description of no-baz. | ✅
![other][]🚫 | +| [no-bez](docs/rules/no-bez.md) | Description of no-bez. | ![other][]⚠️ | +| [no-biz](docs/rules/no-biz.md) | Description of no-biz. | ![other][]🚫 | +| [no-boz](docs/rules/no-boz.md) | Description of no-boz. | ✅⚠️ | +| [no-buz](docs/rules/no-buz.md) | Description of no-buz. | ![other][]⚠️
⚠️ | +| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅🚫 | " @@ -699,10 +699,10 @@ exports[`generator #generate rules that are disabled or set to warn, only one co ✅⚠️ Warns in the \`recommended\` configuration.\\ ✅🚫 Disabled in the \`recommended\` configuration. -| Name | Description | ✅ | -| :----------------------------- | :--------------------- | :----------------------------------------------------- | -| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | 🚫 | -| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ⚠️ | +| Name | Description | ✅ | +| :----------------------------- | :--------------------- | :------------- | +| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | ✅🚫 | +| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅⚠️ | " @@ -734,9 +734,9 @@ exports[`generator #generate rules that are disabled or set to warn, two configs ✅⚠️ Warns in the \`recommended\` configuration.\\ ⌨️🚫 Disabled in the \`typescript\` configuration. -| Name | Description | 💼 | -| :----------------------------- | :--------------------- | :------------------------------------------------------------------------------------------------------------- | -| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ⚠️ ⌨️🚫 | +| Name | Description | 💼 | +| :----------------------------- | :--------------------- | :--------------------------------- | +| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅⚠️
⌨️🚫 | "