Skip to content

Commit

Permalink
Merge pull request #203 from bmish/superscript-break-2
Browse files Browse the repository at this point in the history
  • Loading branch information
bmish committed Nov 1, 2022
2 parents 9738528 + 5022ea4 commit 97125af
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 92 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -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"] }
}
```

Expand Down
17 changes: 4 additions & 13 deletions lib/configs.ts
Expand Up @@ -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
? `<span style="white-space:nowrap">${emoji}<sup>${superscriptEmoji}</sup></span>`
: `${emoji}<sup>${superscriptEmoji}</sup>`;
return `${emoji}<sup>${superscriptEmoji}</sup>`;
}

/**
Expand All @@ -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(
Expand All @@ -129,7 +121,6 @@ export function findConfigEmoji(
options?: {
severity?: SEVERITY_TYPE;
fallback?: 'badge' | 'emoji';
noWrap?: boolean;
}
) {
let emoji = configEmojis.find(
Expand All @@ -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;
}
Expand Down
125 changes: 64 additions & 61 deletions lib/rule-list.ts
Expand Up @@ -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 {
Expand Down Expand Up @@ -65,78 +59,87 @@ 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('<sup>') ? `<br>${emoji}` : emoji);
}

return emojis;
}

function getConfigurationColumnValueForRule(
rule: RuleDetails,
configsToRules: ConfigsToRules,
pluginPrefix: string,
configEmojis: ConfigEmojis,
ignoreConfig: string[]
): string {
const badges: string[] = [];
const emojis: string[] = [];

const configsToRulesWithoutIgnored = Object.fromEntries(
Object.entries(configsToRules).filter(
([configName]) => !ignoreConfig?.includes(configName)
)
);

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('<br>')) {
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(
Expand Down
8 changes: 8 additions & 0 deletions lib/types.ts
Expand Up @@ -24,6 +24,14 @@ export enum SEVERITY_TYPE {
'off' = 'off',
}

export const SEVERITY_TYPE_TO_SET: {
[key in SEVERITY_TYPE]: Set<TSESLint.Linter.RuleLevel>;
} = {
[SEVERITY_TYPE.error]: SEVERITY_ERROR,
[SEVERITY_TYPE.warn]: SEVERITY_WARN,
[SEVERITY_TYPE.off]: SEVERITY_OFF,
};

export type ConfigsToRules = Record<string, Rules>;

export interface RuleDetails {
Expand Down
32 changes: 16 additions & 16 deletions test/lib/__snapshots__/generator-test.ts.snap
Expand Up @@ -615,15 +615,15 @@ exports[`generator #generate rules that are disabled or set to warn generates th
✅<sup>⚠️</sup> Warns in the \`recommended\` configuration.\\
✅<sup>🚫</sup> Disabled in the \`recommended\` configuration.
| Name | Description | 💼 |
| :----------------------------- | :--------------------- | :--------------------------------------------------------------------------------------------------------------------- |
| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | <span style="white-space:nowrap">![other][]<sup>🚫</sup></span> <span style="white-space:nowrap">✅<sup>🚫</sup></span> |
| [no-baz](docs/rules/no-baz.md) | Description of no-baz. | ✅ <span style="white-space:nowrap">![other][]<sup>🚫</sup></span> |
| [no-bez](docs/rules/no-bez.md) | Description of no-bez. | <span style="white-space:nowrap">![other][]<sup>⚠️</sup></span> |
| [no-biz](docs/rules/no-biz.md) | Description of no-biz. | <span style="white-space:nowrap">![other][]<sup>🚫</sup></span> |
| [no-boz](docs/rules/no-boz.md) | Description of no-boz. | <span style="white-space:nowrap">✅<sup>⚠️</sup></span> |
| [no-buz](docs/rules/no-buz.md) | Description of no-buz. | <span style="white-space:nowrap">![other][]<sup>⚠️</sup></span> <span style="white-space:nowrap">✅<sup>⚠️</sup></span> |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | <span style="white-space:nowrap">✅<sup>🚫</sup></span> |
| Name | Description | 💼 |
| :----------------------------- | :--------------------- | :----------------------------------------- |
| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | ![other][]<sup>🚫</sup> <br>✅<sup>🚫</sup> |
| [no-baz](docs/rules/no-baz.md) | Description of no-baz. | ✅ <br>![other][]<sup>🚫</sup> |
| [no-bez](docs/rules/no-bez.md) | Description of no-bez. | ![other][]<sup>⚠️</sup> |
| [no-biz](docs/rules/no-biz.md) | Description of no-biz. | ![other][]<sup>🚫</sup> |
| [no-boz](docs/rules/no-boz.md) | Description of no-boz. | ✅<sup>⚠️</sup> |
| [no-buz](docs/rules/no-buz.md) | Description of no-buz. | ![other][]<sup>⚠️</sup> <br>✅<sup>⚠️</sup> |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅<sup>🚫</sup> |
<!-- end auto-generated rules list -->
"
Expand Down Expand Up @@ -699,10 +699,10 @@ exports[`generator #generate rules that are disabled or set to warn, only one co
✅<sup>⚠️</sup> Warns in the \`recommended\` configuration.\\
✅<sup>🚫</sup> Disabled in the \`recommended\` configuration.
| Name | Description | ✅ |
| :----------------------------- | :--------------------- | :----------------------------------------------------- |
| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | <span style="white-space:nowrap">✅<sup>🚫</sup></span> |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | <span style="white-space:nowrap">✅<sup>⚠️</sup></span> |
| Name | Description | ✅ |
| :----------------------------- | :--------------------- | :------------- |
| [no-bar](docs/rules/no-bar.md) | Description of no-bar. | ✅<sup>🚫</sup> |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅<sup>⚠️</sup> |
<!-- end auto-generated rules list -->
"
Expand Down Expand Up @@ -734,9 +734,9 @@ exports[`generator #generate rules that are disabled or set to warn, two configs
✅<sup>⚠️</sup> Warns in the \`recommended\` configuration.\\
⌨️<sup>🚫</sup> Disabled in the \`typescript\` configuration.
| Name | Description | 💼 |
| :----------------------------- | :--------------------- | :------------------------------------------------------------------------------------------------------------- |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | <span style="white-space:nowrap">✅<sup>⚠️</sup></span> <span style="white-space:nowrap">⌨️<sup>🚫</sup></span> |
| Name | Description | 💼 |
| :----------------------------- | :--------------------- | :--------------------------------- |
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. | ✅<sup>⚠️</sup> <br>⌨️<sup>🚫</sup> |
<!-- end auto-generated rules list -->
"
Expand Down

0 comments on commit 97125af

Please sign in to comment.