Skip to content

Commit

Permalink
Update local ESLint config to match shared config + apply new rules (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante authored Feb 28, 2024
1 parent 09f3178 commit cbd7760
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 276 deletions.
102 changes: 48 additions & 54 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
const { readFileSync } = require("fs");
const { resolve } = require("path");
const noRestrictedImports = require("eslint-config-pixiebrix/no-restricted-imports");

function extendNoRestrictedImports({ patterns = [], paths = [] }) {
// Clone object to avoid modifying the original
const customized = structuredClone(noRestrictedImports);
customized.patterns.push(...patterns);
customized.paths.push(...paths);
return customized;
}

const boundaries = [
"background",
Expand All @@ -26,8 +35,8 @@ module.exports = {
"local-rules/noInvalidDataTestId": "error",
"local-rules/noExpressionLiterals": "error",
"local-rules/notBothLabelAndLockableProps": "error",
"local-rules/preferNullish": "warn",
"local-rules/preferNullishable": "warn",
"local-rules/preferNullish": "error",
"local-rules/preferNullishable": "error",
"local-rules/noCrossBoundaryImports": [
"warn",
{
Expand Down Expand Up @@ -60,67 +69,35 @@ module.exports = {
"@typescript-eslint/no-unsafe-assignment": "warn",
"@typescript-eslint/no-unsafe-member-access": "warn",
"@typescript-eslint/no-unsafe-return": "warn",

"no-restricted-imports": [
"error",
// If they're not specific to the extension, add them to the shared config instead:
// https://github.com/pixiebrix/eslint-config-pixiebrix/blob/main/no-restricted-imports.js
extendNoRestrictedImports({
patterns: [
{
group: ["react-shadow/emotion"],
message:
'Use this instead: import EmotionShadowRoot from "@/components/EmotionShadowRoot"',
},
],
}),
],

"no-restricted-syntax": [
"error",
{
selector:
"TSTypeReference[typeName.name='Record'][typeParameters.params.0.type=TSStringKeyword][typeParameters.params.1.type=TSUnknownKeyword]",
message: "Use `UnknownObject` instead of `Record<string, unknown>`",
},
{
selector: "CallExpression[callee.property.name='allSettled']",
message:
'For safety and convenience, use this instead: import { allSettled } from "@/utils/promiseUtils";',
},
{
message:
"Bootstrap columns should not be used if there's a single column. Use a plain `div` or drop the wrapper altogether if not needed. You might also consider using one of the classes 'max-550', 'max-750', or 'max-950' to limit the width of the body.",
selector:
"JSXElement[openingElement.name.name='Row'] > JSXText:first-child + JSXElement:nth-last-child(2)",
},
{
message:
"Use the `uuid` module instead because crypto.randomUUID is not available in http: contexts",
selector: 'MemberExpression > Identifier[name="randomUUID"]',
},
// If they're not specific to the extension, add them to the shared config instead:
// https://github.com/pixiebrix/eslint-config-pixiebrix/blob/main/no-restricted-syntax.js
...require("eslint-config-pixiebrix/no-restricted-syntax"),
{
message:
'Use `getExtensionConsoleUrl` instead of `browser.runtime.getURL("options.html")` because it automatically handles paths/routes',
selector:
"CallExpression[callee.object.property.name='runtime'][callee.property.name='getURL'][arguments.0.value='options.html']",
},
{
message: "Use `jest.mocked(fn)` instead of `fn as jest.Mock`.",
selector: "TSAsExpression TSQualifiedName[right.name='Mock']",
},
{
message:
"Use `jest.mocked(fn)` instead of `fn as jest.MockedFunction`.",
selector: "TSAsExpression TSQualifiedName[right.name='MockedFunction']",
},
{
message:
"Unless the code is using .then(), calling `.mockResolvedValue(undefined)` is the same as leaving it out",
selector:
"CallExpression[callee.property.name='mockResolvedValue'][arguments.0.name='undefined'][arguments.0.type='Identifier']",
},
// NOTE: If you add more rules, add the tests to eslint-local-rules/noRestrictedSyntax.ts
],

// We want to have a default case to check for `never`
"@typescript-eslint/switch-exhaustiveness-check": [
"error",
{
allowDefaultCaseForExhaustiveSwitch: true,
requireDefaultForNonUnion: true,
},
],

// Rules that depend on https://github.com/pixiebrix/pixiebrix-extension/issues/775
"@typescript-eslint/restrict-template-expressions": [
"error",
{ allowNever: true },
],
},
overrides: [
{
Expand Down Expand Up @@ -183,7 +160,7 @@ module.exports = {
},
},
{
// Settings for regular ts files that should only apply to react component rests
// Settings for regular ts files that should only apply to react component tests
files: ["**/!(*.test)*.ts?(x)", "**/*.ts"],
rules: {
"testing-library/render-result-naming-convention": "off",
Expand All @@ -200,6 +177,23 @@ module.exports = {
"@typescript-eslint/no-unsafe-return": "off",
},
},
{
files: ["./src/*"],
rules: {
"no-restricted-imports": [
"error",
extendNoRestrictedImports({
patterns: [
{
group: ["./*"],
message:
'Use root-based imports (`import "@/something"`) instead of relative imports.',
},
],
}),
],
},
},
],
};

Expand Down
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# https://pre-commit.com/hooks.html

# The hooks can be updated with:
# pre-commit autoupdate
#
# And then run updated hooks against all files with:
# pre-commit run --all-files
exclude: __snapshots__/|package-lock.json
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
15 changes: 0 additions & 15 deletions eslint-local-rules/noRestrictedSyntax.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
/** @file File that verifies rules in `no-restricted-syntax`. Each line MUST be preceded by `eslint-disable-next-line` */

// eslint-disable-next-line no-restricted-syntax
export const id = crypto.randomUUID();

// eslint-disable-next-line no-restricted-syntax
export const url = browser.runtime.getURL("options.html");

// eslint-disable-next-line no-restricted-syntax
export const alertMock = alert as jest.Mock<typeof alert>;

// eslint-disable-next-line no-restricted-syntax
export const alertMockedFunction = alert as jest.MockedFunction<typeof alert>;

// eslint-disable-next-line no-restricted-syntax
export const mockPromise = jest.fn().mockResolvedValue(undefined);

// eslint-disable-next-line no-restricted-syntax
void Promise.allSettled([Promise.resolve(), Promise.reject()]);

// eslint-disable-next-line no-restricted-syntax
export type MyObject = Record<string, unknown>;
Loading

0 comments on commit cbd7760

Please sign in to comment.