eslint-doc-generator
Version:
Automatic documentation generator for ESLint plugins and rules.
91 lines (90 loc) • 2.82 kB
JavaScript
import * as nodeEmoji from 'node-emoji';
import { EMOJI_CONFIGS, RESERVED_EMOJI_SET } from './emojis.js';
const FALLBACK_EMOJIS = [
'🔴',
'🟠',
'🟡',
'🟢',
'🔵',
'🟣',
'🟤',
'⚫',
'⚪',
'🟥',
'🟧',
'🟨',
'🟩',
'🟦',
'🟪',
'🟫',
'⬛',
'⬜',
];
function tokenizeConfigName(configName) {
const normalized = configName
.replaceAll(/([a-z])([A-Z])/gu, '$1 $2')
.replaceAll(/[^a-zA-Z0-9]+/gu, ' ')
.toLowerCase()
.trim();
if (!normalized) {
return [];
}
return normalized.split(/\s+/u);
}
function canUseEmoji(candidate, usedEmojis) {
return !RESERVED_EMOJI_SET.has(candidate) && !usedEmojis.has(candidate);
}
function tryUseEmoji(candidate, usedEmojis) {
return candidate && canUseEmoji(candidate, usedEmojis)
? candidate
: undefined;
}
function getDefaultEmojiForConfig(configNameLower) {
if (!(configNameLower in EMOJI_CONFIGS)) {
return undefined;
}
return EMOJI_CONFIGS[configNameLower];
}
function suggestEmojiLocally(configName, usedEmojis) {
const configNameLower = configName.toLowerCase();
const tokens = tokenizeConfigName(configName);
const exactDefault = tryUseEmoji(getDefaultEmojiForConfig(configNameLower), usedEmojis);
if (exactDefault) {
return exactDefault;
}
for (const token of tokens) {
const tokenKeywordEmoji = tryUseEmoji(getDefaultEmojiForConfig(token), usedEmojis);
if (tokenKeywordEmoji) {
return tokenKeywordEmoji;
}
}
for (const term of [configNameLower, ...tokens]) {
const matches = nodeEmoji.search(term);
for (const match of matches) {
const fromSearch = tryUseEmoji(match.emoji, usedEmojis);
if (fromSearch) {
return fromSearch;
}
}
}
const fallback = FALLBACK_EMOJIS.find((emoji) => canUseEmoji(emoji, usedEmojis)) ??
FALLBACK_EMOJIS[0];
return fallback;
}
function sortCaseInsensitive(values) {
return values.toSorted((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
}
export function getBuiltinEmojiSuggestions(context) {
const configNames = sortCaseInsensitive(Object.keys(context.plugin.configs ?? {}));
if (configNames.length === 0) {
throw new Error('Could not find exported `configs` object in ESLint plugin to suggest emojis for.');
}
const emojiByConfig = new Map();
const usedEmojis = new Set();
for (const configName of configNames) {
const localSuggestion = suggestEmojiLocally(configName, usedEmojis);
emojiByConfig.set(configName, localSuggestion);
usedEmojis.add(localSuggestion);
}
return { configNames, emojiByConfig };
}