Skip to content

Commit

Permalink
chore(tasks/lint_rules): Arrange UI (#2187)
Browse files Browse the repository at this point in the history
Part of #2020

- [x] rule counters
- [x] show two tables
- [x] omit all the deprecated rules

Eventually I decided to split them into 3 tables.

In order to be aware of the newly deprecated rules in the future, the
deprecated rules are hidden by default, rather than omitted altogether.
  • Loading branch information
leaysgur authored Jan 28, 2024
1 parent 87b9978 commit 41fb7ef
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 35 deletions.
3 changes: 3 additions & 0 deletions tasks/lint_rules/src/eslint-rules.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ const loadPluginTypeScriptRules = (linter) => {

const prefixedName = `typescript/${name}`;

// Presented but type is `string | false`
rule.meta.docs.recommended = typeof rule.meta.docs.recommended === "string";

linter.defineRule(prefixedName, rule);
}
};
Expand Down
169 changes: 134 additions & 35 deletions tasks/lint_rules/src/markdown-renderer.cjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
/**
* @param {string} pluginName
* @param {import("./eslint-rules.cjs").TargetPluginMeta} pluginMeta
* @param {string} listPart
* @typedef {({ name: string } & import("./oxlint-rules.cjs").RuleEntry)} RuleEntryView
* @typedef {{ isImplemented: number; isNotSupported: number; total: number }} CounterView
*/
const renderLayout = (pluginName, pluginMeta, listPart) => `

/** @param {{ npm: string; }} props */
const renderIntroduction = ({ npm }) => `
> [!WARNING]
> This comment is maintained by CI. Do not edit this comment directly.
> To update comment template, see https://github.com/oxc-project/oxc/tree/main/tasks/lint_rules
This is tracking issue for \`${pluginMeta.npm}\`.
This is tracking issue for \`${npm}\`.
`;

## Rules
${listPart}
/**
* @param {{
* counters: {
* recommended: CounterView;
* notRecommended: CounterView;
* deprecated: CounterView;
* };
* }} props
*/
const renderCounters = ({
counters: { recommended, notRecommended, deprecated },
}) => {
const recommendedTodos =
recommended.total -
(recommended.isImplemented + recommended.isNotSupported);
const notRecommendedTodos =
notRecommended.total -
(notRecommended.isImplemented + notRecommended.isNotSupported);

## Getting started
const countersList = [
`- ${recommendedTodos}/${recommended.total} recommended rules are remaining as TODO`,
recommendedTodos === 0 && ` - All done! 🎉`,
`- ${notRecommendedTodos}/${notRecommended.total} not recommended rules are remaining as TODO`,
notRecommendedTodos === 0 && ` - All done! 🎉`,
]
.filter(Boolean)
.join("\n");

return `
There are ${recommended.total + notRecommended.total}(+ ${deprecated.total} deprecated) rules.
${countersList}
`;
};

/** @param {{ pluginName: string }} props */
const renderGettingStarted = ({ pluginName }) => `
To get started, run the following command:
\`\`\`sh
just new-${pluginName}-rule <RULE_NAME>
Expand All @@ -22,43 +58,106 @@ just new-${pluginName}-rule <RULE_NAME>
Then register the rule in \`crates/oxc_linter/src/rules.rs\` and also \`declare_all_lint_rules\` at the bottom.
`;

/** @param {[string, import("./oxlint-rules.cjs").RuleEntry][]} ruleEntries */
const renderRulesList = (ruleEntries) => {
/* prettier-ignore */
const list = [
"| Name | Kind | Status | Docs |",
"| :--- | :--: | :----: | :--- |",
];

for (const [name, entry] of ruleEntries) {
// These should be exclusive, but show it for sure...
let kind = "";
if (entry.isRecommended) kind += "🍀";
if (entry.isDeprecated) kind += "⚠️";
/**
* @param {{
* title: string;
* counters: CounterView;
* views: RuleEntryView[];
* defaultOpen?: boolean;
* }} props */
const renderRulesList = ({ title, counters, views, defaultOpen = true }) => `
## ${title}
let status = "";
if (entry.isImplemented) status += "✨";
if (entry.isNotSupported) status += "🚫";
<details ${defaultOpen ? "open" : ""}>
<summary>
✨: ${counters.isImplemented}, 🚫: ${counters.isNotSupported} / total: ${counters.total}
</summary>
list.push(`| ${name} | ${kind} | ${status} | ${entry.docsUrl} |`);
}
| Status | Name | Docs |
| :----: | :--- | :--- |
${views
.map(
(v) =>
`| ${v.isImplemented ? "✨" : ""}${v.isNotSupported ? "🚫" : ""} | ${v.name} | ${v.docsUrl} |`,
)
.join("\n")}
return `
- Kind: 🍀 = recommended | ⚠️ = deprecated
- Status: ✨ = implemented | 🚫 = not supported
✨ = Implemented, 🚫 = Not supported
${list.join("\n")}
</details>
`;
};

/**
* @param {string} pluginName
* @param {import("./eslint-rules.cjs").TargetPluginMeta} pluginMeta
* @param {import("./oxlint-rules.cjs").RuleEntries} ruleEntries
*/
exports.renderMarkdown = (pluginName, pluginMeta, ruleEntries) => {
const pluginRules = Array.from(ruleEntries).filter(([name]) =>
name.startsWith(`${pluginName}/`),
);
return renderLayout(pluginName, pluginMeta, renderRulesList(pluginRules));
/** @type {Record<string, RuleEntryView[]>} */
const views = {
deprecated: [],
recommended: [],
notRecommended: [],
};
const counters = {
deprecated: { isImplemented: 0, isNotSupported: 0, total: 0 },
recommended: { isImplemented: 0, isNotSupported: 0, total: 0 },
notRecommended: { isImplemented: 0, isNotSupported: 0, total: 0 },
};

for (const [name, entry] of ruleEntries) {
if (!name.startsWith(`${pluginName}/`)) continue;

let viewsRef, counterRef;

switch (true) {
case entry.isDeprecated: {
viewsRef = views.deprecated;
counterRef = counters.deprecated;
break;
}
case entry.isRecommended: {
viewsRef = views.recommended;
counterRef = counters.recommended;
break;
}
default: {
viewsRef = views.notRecommended;
counterRef = counters.notRecommended;
}
}

viewsRef.push({ name, ...entry });

if (entry.isImplemented) counterRef.isImplemented++;
if (entry.isNotSupported) counterRef.isNotSupported++;
counterRef.total++;
}

return [
renderIntroduction({ npm: pluginMeta.npm }),
renderCounters({ counters }),
renderGettingStarted({ pluginName }),
0 < views.recommended.length &&
renderRulesList({
title: "Recommended rules",
counters: counters.recommended,
views: views.recommended,
}),
0 < views.notRecommended.length &&
renderRulesList({
title: "Not recommended rules",
counters: counters.notRecommended,
views: views.notRecommended,
}),
0 < views.deprecated.length &&
renderRulesList({
title: "Deprecated rules",
counters: counters.deprecated,
views: views.deprecated,
defaultOpen: false,
}),
]
.filter(Boolean)
.join("\n");
};

0 comments on commit 41fb7ef

Please sign in to comment.