Fragment |
fragment |
none |
, , ,
div |
element |
className={styles.checkboxListArea} |
, |
em |
element |
none |
text: "Config Group (", {CONFIG_EMOJI}, text: ")" |
ul |
element |
className={clsx('clean-list', styles.checkboxList)} |
, , |
RuleFilterCheckBox |
component |
label={${RECOMMENDED_CONFIG_EMOJI} recommended}, mode={filters.recommended}... |
none |
RuleFilterCheckBox |
component |
label={${STRICT_CONFIG_EMOJI} strict}, mode={filters.strict}, setMode={(new... |
none |
RuleFilterCheckBox |
component |
label={${STYLISTIC_CONFIG_EMOJI} stylistic}, mode={filters.stylistic}, setM... |
none |
div |
element |
className={styles.checkboxListArea} |
, |
em |
element |
none |
text: "Metadata" |
ul |
element |
className={clsx('clean-list', styles.checkboxList)} |
, , , <RuleFilter... |
RuleFilterCheckBox |
component |
label={${FIXABLE_EMOJI} fixable}, mode={filters.fixable}, setMode={(newMode... |
none |
RuleFilterCheckBox |
component |
label={${SUGGESTIONS_EMOJI} has suggestions}, mode={filters.suggestions}, s... |
none |
RuleFilterCheckBox |
component |
label={${TYPE_INFORMATION_EMOJI} type checked}, mode={filters.typeInformati... |
none |
RuleFilterCheckBox |
component |
label={${EXTENSION_RULE_EMOJI} extension}, mode={filters.extension}, setMod... |
none |
RuleFilterCheckBox |
component |
label={${DEPRECATED_RULE_EMOJI} deprecated}, mode={filters.deprecated}, set... |
none |
p |
element |
none |
text: "(These categories are explained in", {' '}, , text: ".)" |
a |
element |
href="#filtering" |
text: "more detail below" |
table |
element |
className={styles.rulesTable} |
, |
thead |
element |
none |
|
tr |
element |
none |
| , | , | , | , | , |
|
th |
element |
className={styles.ruleCol} |
text: "Rule" |
th |
element |
className={styles.attrCol} |
|
div |
element |
title="The config group that the rule belongs to, if any." |
{CONFIG_EMOJI} |
th |
element |
className={styles.attrCol} |
|
div |
element |
title="Whether the rule has an auto-fixer and/or has suggestions." |
{FIXABLE_EMOJI} |
th |
element |
className={styles.attrCol} |
|
div |
element |
title="Whether the rule requires type information from the TypeScript compiler." |
{TYPE_INFORMATION_EMOJI} |
th |
element |
className={styles.attrCol} |
|
div |
element |
title="Whether the rule is an extension rule (i.e. based on a core ESLint rul... |
{EXTENSION_RULE_EMOJI} |
th |
element |
className={styles.attrCol} |
|
div |
element |
title="Whether the rule is deprecated." |
{DEPRECATED_RULE_EMOJI} |
tbody |
element |
none |
{relevantRules.map(rule => ( ))} |
RuleRow |
component |
key={rule.name}, rule={rule} |
none |
Functions
RulesTable(): React.JSX.Element
Returns: React.JSX.Element
Calls:
useRulesFilters
useRulesMeta (from @site/src/hooks/useRulesMeta)
useMemo (from react)
rules.filter
getActualRecommended
[
match(filters.recommended, actualRecommended === 'recommended'),
match(
filters.strict,
actualRecommended === 'recommended' ||
actualRecommended === 'strict',
),
match(filters.stylistic, actualRecommended === 'stylistic'),
match(filters.fixable, !!r.fixable),
match(filters.suggestions, !!r.hasSuggestions),
match(filters.typeInformation, !!r.docs.requiresTypeChecking),
match(filters.extension, !!r.docs.extendsBaseRule),
match(filters.deprecated, !!r.deprecated),
].filter
match
opinions.every
clsx (from clsx)
changeFilter
relevantRules.map
Internal Comments:
// eslint-disable-next-line @typescript-eslint/internal/eqeq-nullish (x2)
Code
export default function RulesTable(): React.JSX.Element {
const [filters, changeFilter] = useRulesFilters();
const rules = useRulesMeta();
const relevantRules = useMemo(
() =>
rules.filter(r => {
const actualRecommended = getActualRecommended(r)[1];
const opinions = [
match(filters.recommended, actualRecommended === 'recommended'),
match(
filters.strict,
actualRecommended === 'recommended' ||
actualRecommended === 'strict',
),
match(filters.stylistic, actualRecommended === 'stylistic'),
match(filters.fixable, !!r.fixable),
match(filters.suggestions, !!r.hasSuggestions),
match(filters.typeInformation, !!r.docs.requiresTypeChecking),
match(filters.extension, !!r.docs.extendsBaseRule),
match(filters.deprecated, !!r.deprecated),
].filter(
(o): o is boolean =>
// eslint-disable-next-line @typescript-eslint/internal/eqeq-nullish
o !== undefined,
);
return opinions.every(o => o);
}),
[rules, filters],
);
return (
<>
<div className={styles.checkboxListArea}>
<em>Config Group ({CONFIG_EMOJI})</em>
<ul className={clsx('clean-list', styles.checkboxList)}>
<RuleFilterCheckBox
label={`${RECOMMENDED_CONFIG_EMOJI} recommended`}
mode={filters.recommended}
setMode={(newMode): void => changeFilter('recommended', newMode)}
/>
<RuleFilterCheckBox
label={`${STRICT_CONFIG_EMOJI} strict`}
mode={filters.strict}
setMode={(newMode): void => changeFilter('strict', newMode)}
/>
<RuleFilterCheckBox
label={`${STYLISTIC_CONFIG_EMOJI} stylistic`}
mode={filters.stylistic}
setMode={(newMode): void => changeFilter('stylistic', newMode)}
/>
</ul>
</div>
<div className={styles.checkboxListArea}>
<em>Metadata</em>
<ul className={clsx('clean-list', styles.checkboxList)}>
<RuleFilterCheckBox
label={`${FIXABLE_EMOJI} fixable`}
mode={filters.fixable}
setMode={(newMode): void => changeFilter('fixable', newMode)}
/>
<RuleFilterCheckBox
label={`${SUGGESTIONS_EMOJI} has suggestions`}
mode={filters.suggestions}
setMode={(newMode): void => changeFilter('suggestions', newMode)}
/>
<RuleFilterCheckBox
label={`${TYPE_INFORMATION_EMOJI} type checked`}
mode={filters.typeInformation}
setMode={(newMode): void =>
changeFilter('typeInformation', newMode)
}
/>
<RuleFilterCheckBox
label={`${EXTENSION_RULE_EMOJI} extension`}
mode={filters.extension}
setMode={(newMode): void => changeFilter('extension', newMode)}
/>
<RuleFilterCheckBox
label={`${DEPRECATED_RULE_EMOJI} deprecated`}
mode={filters.deprecated}
setMode={(newMode): void => changeFilter('deprecated', newMode)}
/>
</ul>
</div>
<p>
(These categories are explained in{' '}
<a href="#filtering">more detail below</a>.)
</p>
<table className={styles.rulesTable}>
<thead>
<tr>
<th className={styles.ruleCol}>Rule</th>
<th className={styles.attrCol}>
<div title="The config group that the rule belongs to, if any.">
{CONFIG_EMOJI}
</div>
</th>
<th className={styles.attrCol}>
<div title="Whether the rule has an auto-fixer and/or has suggestions.">
{FIXABLE_EMOJI}
</div>
</th>
<th className={styles.attrCol}>
<div title="Whether the rule requires type information from the TypeScript compiler.">
{TYPE_INFORMATION_EMOJI}
</div>
</th>
<th className={styles.attrCol}>
<div title="Whether the rule is an extension rule (i.e. based on a core ESLint rule).">
{EXTENSION_RULE_EMOJI}
</div>
</th>
<th className={styles.attrCol}>
<div title="Whether the rule is deprecated.">
{DEPRECATED_RULE_EMOJI}
</div>
</th>
</tr>
</thead>
<tbody>
{relevantRules.map(rule => (
<RuleRow key={rule.name} rule={rule} />
))}
</tbody>
</table>
</>
);
}
interpolateCode(text: string): string | (string | React.JSX.Element)[]
Parameters:
Returns: string | (string | React.JSX.Element)[]
Calls:
Code
function interpolateCode(
text: string,
): string | (string | React.JSX.Element)[] {
const fragments = text.split(/`(.*?)`/);
if (fragments.length === 1) {
return text;
}
return fragments.map((v, i) => (i % 2 === 0 ? v : <code key={i}>{v}</code>));
}
Parameters:
{
docs,
} RulesMeta[number]
Returns: ['', ''] | [string, RuleRecommendation]
Calls:
getRecommendationWithEmoji (from ../../theme/MDXComponents/RuleAttributes)
Code
function getActualRecommended({
docs,
}: RulesMeta[number]): ['', ''] | [string, RuleRecommendation] {
const recommended = docs.recommended;
return recommended ? getRecommendationWithEmoji(recommended) : ['', ''];
}
Parameters:
{
rule,
} {
rule: RulesMeta[number];
}
Returns: React.JSX.Element | null
Calls:
getActualRecommended
interpolateCode
Code
function RuleRow({
rule,
}: {
rule: RulesMeta[number];
}): React.JSX.Element | null {
if (!rule.docs.url) {
return null;
}
const { deprecated, fixable, hasSuggestions } = rule;
const { extendsBaseRule, requiresTypeChecking } = rule.docs;
const [emoji, actualRecommended] = getActualRecommended(rule);
return (
<tr>
<td>
<div className={styles.ruleNameWrapper}>
<Link to={new URL(rule.docs.url).pathname}>
<code>@typescript-eslint/{rule.name}</code>
</Link>
{rule.docs.frozen && <span>❄️</span>}
</div>
<br />
{interpolateCode(rule.docs.description)}
</td>
<td className={styles.attrCol} title={actualRecommended}>
{emoji}
</td>
<td
className={styles.attrCol}
title={
fixable && hasSuggestions
? 'fixable and has suggestions'
: fixable
? 'fixable'
: hasSuggestions
? 'has suggestions'
: undefined
}
>
{fixable ? FIXABLE_EMOJI : ''}
{fixable && hasSuggestions ? <br /> : ''}
{hasSuggestions ? SUGGESTIONS_EMOJI : ''}
</td>
<td
className={styles.attrCol}
title={requiresTypeChecking ? 'requires type information' : undefined}
>
{requiresTypeChecking ? TYPE_INFORMATION_EMOJI : ''}
</td>
<td
className={styles.attrCol}
title={extendsBaseRule ? 'extends base rule' : undefined}
>
{extendsBaseRule ? EXTENSION_RULE_EMOJI : ''}
</td>
<td
className={styles.attrCol}
title={deprecated ? 'deprecated' : undefined}
>
{deprecated ? DEPRECATED_RULE_EMOJI : ''}
</td>
</tr>
);
}
RuleFilterCheckBox({ label, mode, setMode, }: { label: string; mode: FilterMode; setM…): React.JSX.Element
Parameters:
{
label,
mode,
setMode,
} {
label: string;
mode: FilterMode;
setMode: (mode: FilterMode) => void;
}
Returns: React.JSX.Element
Calls:
setMode
filterModes.indexOf
clsx (from clsx)
toNextMode
Code
function RuleFilterCheckBox({
label,
mode,
setMode,
}: {
label: string;
mode: FilterMode;
setMode: (mode: FilterMode) => void;
}): React.JSX.Element {
const toNextMode = (): void =>
setMode(filterModes[(filterModes.indexOf(mode) + 1) % filterModes.length]);
return (
<li className={styles.checkboxListItem}>
<button
aria-label={`Toggle the filter mode. Current: ${mode}`}
className={clsx(
styles.checkboxLabel,
mode === 'include' && styles.activated,
mode === 'exclude' && styles.deactivated,
)}
onClick={toNextMode}
onKeyDown={(e): void => {
if (e.key === 'Enter') {
toNextMode();
}
}}
type="button"
>
<div
aria-hidden
className={clsx(styles.visual, styles[`visual-${mode}`])}
/>
{label}
</button>
</li>
);
}
match(mode: FilterMode, value: boolean): boolean | undefined
Parameters:
mode FilterMode
value boolean
Returns: boolean | undefined
Code
function match(mode: FilterMode, value: boolean): boolean | undefined {
if (mode === 'exclude') {
return !value;
}
if (mode === 'include') {
return value;
}
return undefined;
}
selectSearch(history: H.History): any
Parameters:
Returns: any
Code
history =>
history.location.search
getServerSnapshot(): string
Returns: string
Code
Parameters:
paramsKey any: Optional. Whether to include rules that match the particular
search filter. Defaults to an empty string, which matches all rules.
Raw JSDoc
/**
* @param paramsKey Optional. Whether to include rules that match the particular
* search filter. Defaults to an empty string, which matches all rules.
*/
Calls:
useHistory (from @docusaurus/router)
useHistorySelector (from ../../hooks/useHistorySelector)
new URLSearchParams(search).get
useMemo (from react)
parseFiltersState
stringifyFiltersState
searchParams.set
searchParams.delete
history.replace
searchParams.toString
Internal Comments:
// We can't compute this in selectSearch, because we need the snapshot to be (x2)
// comparable by value. (x2)
Code
function useRulesFilters(
paramsKey = '',
): [FiltersState, (category: FilterCategory, mode: FilterMode) => void] {
const history = useHistory();
const search = useHistorySelector(selectSearch, getServerSnapshot);
const paramValue = new URLSearchParams(search).get(paramsKey) ?? '';
// We can't compute this in selectSearch, because we need the snapshot to be
// comparable by value.
const filtersState = useMemo(
() => parseFiltersState(paramValue),
[paramValue],
);
const changeFilter = (category: FilterCategory, mode: FilterMode): void => {
const newState = { ...filtersState, [category]: mode };
if (
category === 'strict' &&
mode === 'include' &&
filtersState.recommended === 'include'
) {
newState.recommended = 'exclude';
} else if (
category === 'recommended' &&
mode === 'include' &&
filtersState.strict === 'include'
) {
newState.strict = 'exclude';
}
const searchParams = new URLSearchParams(history.location.search);
const filtersString = stringifyFiltersState(newState);
if (filtersString) {
searchParams.set(paramsKey, filtersString);
} else {
searchParams.delete(paramsKey);
}
history.replace({ search: searchParams.toString() });
};
return [filtersState, changeFilter];
}
Parameters:
Returns: string
Calls:
Object.entries(filters)
.map(([key, value]) =>
value === 'include'
? key
: value === 'exclude'
?${NEGATION_SYMBOL}${key}: '',
)
.filter(Boolean)
.join
Code
function stringifyFiltersState(filters: FiltersState): string {
return Object.entries(filters)
.map(([key, value]) =>
value === 'include'
? key
: value === 'exclude'
? `${NEGATION_SYMBOL}${key}`
: '',
)
.filter(Boolean)
.join('-');
}
Parameters:
Returns: FiltersState
Calls:
str.split
part.startsWith
part.slice
Object.hasOwn
Code
function parseFiltersState(str: string): FiltersState {
const res: FiltersState = { ...neutralFiltersState };
for (const part of str.split('-')) {
const exclude = part.startsWith(NEGATION_SYMBOL);
const key = exclude ? part.slice(1) : part;
if (Object.hasOwn(neutralFiltersState, key)) {
res[key as keyof typeof neutralFiltersState] = exclude
? 'exclude'
: 'include';
}
}
return res;
}
Internal helpers
Declared inside another function in this file.
toNextMode(): void
Returns: void
Calls:
Code
(): void =>
setMode(filterModes[(filterModes.indexOf(mode) + 1) % filterModes.length])
changeFilter(category: FilterCategory, mode: FilterMode): void
Parameters:
category FilterCategory
mode FilterMode
Returns: void
Calls:
stringifyFiltersState
searchParams.set
searchParams.delete
history.replace
searchParams.toString
Code
(category: FilterCategory, mode: FilterMode): void => {
const newState = { ...filtersState, [category]: mode };
if (
category === 'strict' &&
mode === 'include' &&
filtersState.recommended === 'include'
) {
newState.recommended = 'exclude';
} else if (
category === 'recommended' &&
mode === 'include' &&
filtersState.strict === 'include'
) {
newState.strict = 'exclude';
}
const searchParams = new URLSearchParams(history.location.search);
const filtersString = stringifyFiltersState(newState);
if (filtersString) {
searchParams.set(paramsKey, filtersString);
} else {
searchParams.delete(paramsKey);
}
history.replace({ search: searchParams.toString() });
}
Type Aliases
FilterMode
type FilterMode = (typeof filterModes)[number];
FilterCategory
type FilterCategory = | 'deprecated'
| 'extension'
| 'fixable'
| 'recommended'
| 'strict'
| 'stylistic'
| 'suggestions'
| 'typeInformation';
type FiltersState = Record<FilterCategory, FilterMode>;
Generated by Syntax Scribe
|