Skip to content

Instantly share code, notes, and snippets.

@kvnxiao
Last active April 3, 2025 02:11
Show Gist options
  • Save kvnxiao/d31ed05260ff5b97dfb58202a7139db3 to your computer and use it in GitHub Desktop.
Save kvnxiao/d31ed05260ff5b97dfb58202a7139db3 to your computer and use it in GitHub Desktop.
Groups Biome.js rules into recommended vs. non-recommended from the Biome rules page (https://biomejs.dev/linter/rules)
/* Run the following script in the console of the Biome rules page
https://biomejs.dev/linter/rules
const rules = Array.from(document.querySelectorAll("tbody")).flatMap(
(table) => {
const trs = table.querySelectorAll("tr");
return Array.from(trs).map((tr) => {
const tds = Array.from(tr.querySelectorAll("td"));
const ruleName = tds[0].textContent;
const isRecommended =
tds.at(-1).childNodes[0].title === "This rule is recommended";
return {
ruleName,
isRecommended,
};
});
},
);
const recommendedRules = rules
.filter((rule) => rule.isRecommended)
.map((rule) => rule.ruleName);
const nonRecommendedRules = rules
.filter((rule) => !rule.isRecommended)
.map((rule) => rule.ruleName);
console.log(JSON.stringify({
recommended: recommendedRules,
nonRecommended: nonRecommendedRules,
}, null, 2));
*/
// Copy-pasted output from the above script (2025-04-02, Biome.js v1.9.4)
const linterRules = {
recommended: [
"noAccessKey",
"noAriaHiddenOnFocusable",
"noAriaUnsupportedElements",
"noAutofocus",
"noBlankTarget",
"noDistractingElements",
"noHeaderScope",
"noInteractiveElementToNoninteractiveRole",
"noLabelWithoutControl",
"noNoninteractiveElementToInteractiveRole",
"noNoninteractiveTabindex",
"noPositiveTabindex",
"noRedundantAlt",
"noRedundantRoles",
"noSvgWithoutTitle",
"useAltText",
"useAnchorContent",
"useAriaActivedescendantWithTabindex",
"useAriaPropsForRole",
"useButtonType",
"useFocusableInteractive",
"useGenericFontNames",
"useHeadingContent",
"useHtmlLang",
"useIframeTitle",
"useKeyWithClickEvents",
"useKeyWithMouseEvents",
"useMediaCaption",
"useSemanticElements",
"useValidAnchor",
"useValidAriaProps",
"useValidAriaRole",
"useValidAriaValues",
"useValidLang",
"noBannedTypes",
"noEmptyTypeParameters",
"noExcessiveNestedTestSuites",
"noExtraBooleanCast",
"noForEach",
"noMultipleSpacesInRegularExpressionLiterals",
"noStaticOnlyClass",
"noThisInStatic",
"noUselessCatch",
"noUselessConstructor",
"noUselessEmptyExport",
"noUselessFragments",
"noUselessLabel",
"noUselessLoneBlockStatements",
"noUselessRename",
"noUselessSwitchCase",
"noUselessTernary",
"noUselessThisAlias",
"noUselessTypeConstraint",
"noWith",
"useArrowFunction",
"useFlatMap",
"useLiteralKeys",
"useOptionalChain",
"useRegexLiterals",
"useSimpleNumberKeys",
"noChildrenProp",
"noConstAssign",
"noConstantCondition",
"noConstructorReturn",
"noEmptyCharacterClassInRegex",
"noEmptyPattern",
"noFlatMapIdentity",
"noGlobalObjectCalls",
"noInnerDeclarations",
"noInvalidBuiltinInstantiation",
"noInvalidConstructorSuper",
"noInvalidDirectionInLinearGradient",
"noInvalidGridAreas",
"noInvalidPositionAtImportRule",
"noInvalidUseBeforeDeclaration",
"noNonoctalDecimalEscape",
"noPrecisionLoss",
"noRenderReturnValue",
"noSelfAssign",
"noSetterReturn",
"noStringCaseMismatch",
"noSwitchDeclarations",
"noUnknownFunction",
"noUnknownMediaFeatureName",
"noUnknownProperty",
"noUnknownUnit",
"noUnmatchableAnbSelector",
"noUnnecessaryContinue",
"noUnreachable",
"noUnreachableSuper",
"noUnsafeFinally",
"noUnsafeOptionalChaining",
"noUnusedLabels",
"noVoidElementsWithChildren",
"noVoidTypeReturn",
"useExhaustiveDependencies",
"useIsNan",
"useJsxKeyInIterable",
"useValidForDirection",
"useYield",
"noAccumulatingSpread",
"noDelete",
"noDangerouslySetInnerHtml",
"noDangerouslySetInnerHtmlWithChildren",
"noGlobalEval",
"noArguments",
"noCommaOperator",
"noInferrableTypes",
"noNonNullAssertion",
"noParameterAssign",
"noUnusedTemplateLiteral",
"noUselessElse",
"noVar",
"useAsConstAssertion",
"useConst",
"useDefaultParameterLast",
"useEnumInitializers",
"useExponentiationOperator",
"useExportType",
"useImportType",
"useLiteralEnumMembers",
"useNodejsImportProtocol",
"useNumberNamespace",
"useNumericLiterals",
"useSelfClosingElements",
"useShorthandFunctionType",
"useSingleVarDeclarator",
"useTemplate",
"useWhile",
"noApproximativeNumericConstant",
"noArrayIndexKey",
"noAssignInExpressions",
"noAsyncPromiseExecutor",
"noCatchAssign",
"noClassAssign",
"noCommentText",
"noCompareNegZero",
"noConfusingLabels",
"noConfusingVoidType",
"noConstEnum",
"noControlCharactersInRegex",
"noDebugger",
"noDoubleEquals",
"noDuplicateAtImportRules",
"noDuplicateCase",
"noDuplicateClassMembers",
"noDuplicateFontNames",
"noDuplicateJsxProps",
"noDuplicateObjectKeys",
"noDuplicateObjectKeys",
"noDuplicateParameters",
"noDuplicateSelectorsKeyframeBlock",
"noDuplicateTestHooks",
"noEmptyBlock",
"noEmptyInterface",
"noExplicitAny",
"noExportsInTest",
"noExtraNonNullAssertion",
"noFallthroughSwitchClause",
"noFocusedTests",
"noFunctionAssign",
"noGlobalAssign",
"noGlobalIsFinite",
"noGlobalIsNan",
"noImplicitAnyLet",
"noImportAssign",
"noImportantInKeyframe",
"noLabelVar",
"noMisleadingCharacterClass",
"noMisleadingInstantiator",
"noMisrefactoredShorthandAssign",
"noPrototypeBuiltins",
"noRedeclare",
"noRedundantUseStrict",
"noSelfCompare",
"noShadowRestrictedNames",
"noShorthandPropertyOverrides",
"noSparseArray",
"noSuspiciousSemicolonInJsx",
"noThenProperty",
"noUnsafeDeclarationMerging",
"noUnsafeNegation",
"useDefaultSwitchClauseLast",
"useGetterReturn",
"useIsArray",
"useNamespaceKeyword",
"useValidTypeof",
],
nonRecommended: [
"noExcessiveCognitiveComplexity",
"noUselessStringConcat",
"noUselessUndefinedInitialization",
"noVoid",
"useDateNow",
"useSimplifiedLogicExpression",
"noConstantMathMinMaxClamp",
"noInvalidNewBuiltin",
"noNewSymbol",
"noNodejsModules",
"noUndeclaredDependencies",
"noUndeclaredVariables",
"noUnusedFunctionParameters",
"noUnusedImports",
"noUnusedPrivateClassMembers",
"noUnusedVariables",
"useArrayLiterals",
"useHookAtTopLevel",
"useImportExtensions",
"noCommonJs",
"noDescendingSpecificity",
"noDocumentCookie",
"noDocumentImportInPage",
"noDuplicateCustomProperties",
"noDuplicateElseIf",
"noDuplicateProperties",
"noDuplicatedFields",
"noDynamicNamespaceImportAccess",
"noEnum",
"noExportedImports",
"noHeadElement",
"noHeadImportInDocument",
"noImgElement",
"noIrregularWhitespace",
"noIrregularWhitespace",
"noMissingVarFunction",
"noNestedTernary",
"noOctalEscape",
"noProcessEnv",
"noRestrictedImports",
"noRestrictedTypes",
"noSecrets",
"noStaticElementInteractions",
"noSubstr",
"noTemplateCurlyInString",
"noUnknownPseudoClass",
"noUnknownPseudoElement",
"noUnknownTypeSelector",
"noUselessEscapeInRegex",
"noUselessStringRaw",
"noValueAtRule",
"useAdjacentOverloadSignatures",
"useAriaPropsSupportedByRole",
"useAtIndex",
"useCollapsedIf",
"useComponentExportOnlyModules",
"useConsistentCurlyBraces",
"useConsistentMemberAccessibility",
"useDeprecatedReason",
"useExplicitType",
"useGoogleFontDisplay",
"useGuardForIn",
"useImportRestrictions",
"useSortedClasses",
"useStrictMode",
"useTrimStartEnd",
"useValidAutocomplete",
"noBarrelFile",
"noReExportAll",
"useTopLevelRegex",
"noDefaultExport",
"noDoneCallback",
"noImplicitBoolean",
"noNamespace",
"noNamespaceImport",
"noNegationElse",
"noParameterProperties",
"noRestrictedGlobals",
"noShoutyConstants",
"noYodaExpression",
"useBlockStatements",
"useCollapsedElseIf",
"useConsistentArrayType",
"useConsistentBuiltinInstantiation",
"useDefaultSwitchClause",
"useExplicitLengthCheck",
"useFilenamingConvention",
"useForOf",
"useFragmentSyntax",
"useNamingConvention",
"useNodeAssertStrict",
"useShorthandArrayType",
"useShorthandAssign",
"useSingleCaseStatement",
"useThrowNewError",
"useThrowOnlyError",
"noConsole",
"noConsoleLog",
"noEmptyBlockStatements",
"noEvolvingTypes",
"noMisplacedAssertion",
"noReactSpecificProps",
"noSkippedTests",
"useAwait",
"useErrorMessage",
"useNumberToFixedDigitsArgument",
],
};
import fs from "node:fs";
import path from "node:path";
// Assuming that this script is in the "scripts/" folder
const biomeJson = JSON.parse(fs.readFileSync(path.join(import.meta.dirname, "..", "biome.json"), "utf-8"));
const ruleTypes = ["complexity", "performance", "security", "style", "suspicious", "correctness", "nursery", "a11y"]
for (const ruleType of ruleTypes) {
const rules = biomeJson.linter.rules[ruleType];
if (!rules) {
continue;
}
for (const entry of Object.keys(rules)) {
if (linterRules.recommended.includes(entry)) {
console.log(entry);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment