ESLint
Lint the project with MeoCord's ESLint config, add rules of your own, and catch import cycles as you write.
You'll learn
- Extend MeoCord's ESLint config with your own rules and plugins
- Catch import cycles before the bot refuses to start over one
Before this
meocord/eslint exports a base ESLint config for a MeoCord project. It lints your TypeScript, meocord.config.ts
included, with type information from the project's tsconfig files. A new project's eslint.config.ts uses it, and its
lint script runs ESLint and both typechecks.
When to use it
Keep it on in every MeoCord project, and run npm run lint in CI. Replace it only to lint the project with a config you
maintain yourself; you then lose the import-cycle warning and the floating-promise check below unless you add them.
Example
// eslint.config.ts
import meocordEslint, { typescriptConfig } from 'meocord/eslint'
export default [
...meocordEslint,
{
...typescriptConfig,
rules: {
...typescriptConfig.rules,
// Your own rules, on top of MeoCord's
'no-console': 'warn',
},
},
]typescriptConfig is MeoCord's own entry in the default export: its parser, plugins and rules for TypeScript, applied
after typescript-eslint's recommended and stylistic sets. Spread it, and add your rules over its own.
How it works
The config reads type information from tsconfig.json, tsconfig.test.json and tsconfig.eslint.json, whichever
includes the file. A file ESLint reports as not included in any of them needs listing in one: a script at the root, for
instance, goes in tsconfig.eslint.json.
Plugins go in the same object, spread over typescriptConfig.plugins, as a new project's config does for
eslint-plugin-unused-imports.
Import cycles
Two classes that import each other can't be injected: whichever file loads second records the other's constructor type
before that class exists, and the bot refuses to start. meocord/eslint warns about the cycle with import-x/no-cycle
as you write it. Type-only imports are ignored, since they're gone at runtime.
The check follows imports through @src with eslint-import-resolver-typescript, which new projects include. A
project without it gets no cycle warning, and the rest of its lint is unchanged; add it to turn the check on:
npm install --save-dev eslint-import-resolver-typescriptbun add -d eslint-import-resolver-typescriptpnpm add -D eslint-import-resolver-typescriptyarn add -D eslint-import-resolver-typescriptServices covers the fix: move what both need into a third service.
Promises nothing waits for
meocord/eslint turns on @typescript-eslint/no-floating-promises. A promise nothing awaits, such as
respond(interaction).send() or a database write left without await, rejects outside every handler MeoCord runs, so
its error reaches no exception filter and can end the bot. An interceptor's next.handle()
left that way runs the code after it before the handler finishes, so that code never sees the handler's result or
error. For each one it reports, either:
awaitit, orreturnit, where the code after it should wait, as an interceptor'snext.handle()always should;- or write
voidbefore it where it's meant to run on its own, and handle its failure with.catch().
Gotchas
- A warning doesn't fail
lint. To hold cycles out of the main branch, runnpx eslint --max-warnings=0in CI; passed throughnpm run lint --, the flag reachestsc, which rejects it. - A file in no tsconfig fails to lint with type information. List it in
tsconfig.eslint.json.