UNPKG

@wise/eslint-config

Version:
183 lines (125 loc) 6.25 kB
# @wise/eslint-config A modular ESLint config used at [Wise](https://wise.com/). [![npm (scoped)](https://img.shields.io/npm/v/@wise/eslint-config)](https://www.npmjs.com/package/@wise/eslint-config) ## Usage 1. Install the package as a dev dependency along with ESLint: ```sh pnpm add --save-dev @wise/eslint-config ``` 2. Extend your ESLint configuration as follows: ```js // .eslint.config.js import baseStrict from '@wise/eslint-config/base-strict'; import react from '@wise/eslint-config/react'; import next from '@wise/eslint-config/next'; import jest from '@wise/eslint-config/jest'; import cypress from '@wise/eslint-config/cypress'; import storybook from '@wise/eslint-config/storybook'; import testingLibrary from '@wise/eslint-config/testing-library-react'; export default [ /* Recommended for all projects, includes TypeScript rules. */ ...baseStrict, // you can import from '@wise/esltin-config/base' instead /* Uncomment lines in the order below as you adopt each technology */ // ...react, // ...next, // ...jest, // ...cypress, // ...storybook, // ...testingLibrary, ]; ``` 3. If you’re using a monorepo with TypeScript, please set `parserOptions.projectService = true` [as per the docs of typescript-eslint](https://typescript-eslint.io/troubleshooting/typed-linting/monorepos/). ## Script setup Set up your package.json scripts to run the linting on the CLI. We recommend adhering to [ESLint’s package.json conventions](https://eslint.org/docs/latest/contribute/package-json-conventions) for naming scripts. ```jsonc // package.json { "scripts": { /* TypeScript-specific logic may be enabled as hinted by comments below */ "lint": "pnpm run lint:js+ts && pnpm run lint:format", // && pnpm run lint:types "lint:js+ts": "eslint '**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}'", "lint:format": "prettier \"**/*\" --check --ignore-unknown", // "lint:types": "tsc --noEmit", "lint:fix": "pnpm run lint:fix:js+ts && pnpm run lint:fix:format", "lint:fix:js+ts": "pnpm run lint:js+ts --fix", "lint:fix:format": "prettier \"**/*\" --write --ignore-unknown", }, } ``` ## Compatibility with Prettier Stylistic linting rules which may conflict with Prettier are turned off. We encourage developers to **use Prettier’s opinionated defaults** with no additional configuration. ## Lint and format on commit 1. Install packages as follows: ```sh pnpm add --save-dev husky nano-staged ``` 2. Configure scripts to be run on staged files: ```jsonc // package.json "nano-staged": { "*": "prettier --write --ignore-unknown", "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": "eslint --fix", } ``` 3. Configure git hooks via Husky: ```sh pnpm exec husky echo "pnpm exec nano-staged" > .husky/pre-commit npm pkg set scripts.prepare="husky || cd ." ``` _The `|| cd .` part sets the exit code to zero [in a cross-platform manner](https://stackoverflow.com/a/62817845) when `husky` isn’t found, e.g. when `devDependencies` aren’t installed._ ## Auto-fix on save in your IDE ### VS Code Extend your editor configuration as follows: ```jsonc // .vscode/settings.json { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", }, } ``` ## Contributing If you think a rule should be added or changed, please create a pull request. Releases are managed via [Changesets](https://github.com/changesets/changesets) and follow [Semantic Versioning](https://semver.org/) conventions. ## Troubleshooting **Rules of our configs shouldn’t be turned off or overridden in general.** When encountering a false-positive, please disable it via `eslint-disable-next-line` or `eslint-disable` and consider filing an issue to the Web Guild. ### Import issues The first time you integrate with the config, you might get a lot of import issues. ``` 1:1 warning Run autofix to sort these imports! simple-import-sort/imports ``` This error is auto-fixable using the `--fix` option. #### Unable to resolve path to module (`import/no-unresolved`) When trying to import from a `.d.ts` file, `import type` should be used over `import`, e.g.: ```diff - import { AlertType } from "@transferwise/components/build/types/alert/Alert"; + import type { AlertType } from "@transferwise/components/build/types/alert/Alert"; ``` Furthermore, setting [`verbatimModuleSyntax` in TSConfig](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax) is recommended to avoid these issues and deal with side-effects explicitly. #### Using TypeScript When using multiple configuration files in `tsconfig.json`, e.g. `extends: ["array", "of", "tsconfigs"]`, the following error may occur: > TypeError: The "path" argument must be of type string. Received an instance of Array This happens because [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) doesn’t support the array `extends` syntax introduced by TypeScript 5. Please don’t extend from multiple TSConfigs at this time. ### Parsing error When linting JavaScript without types, the following error may occur: > You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously This happens if your [Babel configuration](https://babeljs.io/docs/configuration#javascript-configuration-files) uses ECMAScript module syntax. By migrating to JSON or using CommonJS, the issue can be mitigated, e.g.: ```diff // babel.config.js - export default { /* … */ }; + module.exports = { /* … */ }; ``` ### ESLint couldn't determine the plugin uniquely Sometimes, if you integrate, you might see an error similar to this ``` Oops! Something went wrong! :( ESLint: 9.13.0 ConfigError: Config (unnamed): Key "plugins": Cannot redefine plugin "import". ... ``` Most of the time, removing the offending plugin (in this case, `import`) in your config file should solve the issue. What this means is that the said plugin is already imported by a previous config. Importing them again will cause the issue.