Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ The configuration is based on the recommended rulesets from [ESLint](https://esl

It also includes [ESLint Stylistic](https://eslint.style/) which replaces deprecated rules from eslint and typescript-eslint.

Currently, it uses ESLint v8 and typescript-eslint v6. (nodejs v16.10+ required)
The upgrade to ESLint v9 and typescript-eslint v8 is planned for the next major release.
Currently, it uses ESLint v9 and typescript-eslint v8. (nodejs v18.18+ required)
If you need to use this package on older nodejs v16, you may switch to older v2.x version, which is based on ESLint v8 (nodejs v16.10+ required)


`@ovos-media/coding-standard/eslint` exports a function that accepts an object with the following options:
Expand Down
78 changes: 30 additions & 48 deletions eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type CustomizeOptions = {

// shared settings - for js + ts equivalent rules
const shared: Linter.RulesRecord = {
'no-unused-vars': ['error', { varsIgnorePattern: '^_', args: 'none' }],
'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
'no-unused-vars': ['error', { varsIgnorePattern: '^_', args: 'none', caughtErrors: 'none' }],
};

/**
Expand Down Expand Up @@ -91,7 +92,7 @@ function customize(options: CustomizeOptions = {}) {
parser: tsParser,
parserOptions: {
// https://typescript-eslint.io/packages/parser/
project: true,
projectService: true,
},
},
plugins: {
Expand Down Expand Up @@ -121,7 +122,7 @@ function customize(options: CustomizeOptions = {}) {
'*.setup.ts',
...disableTypeChecked,
],
languageOptions: { parserOptions: { project: null } }, // this is what basically the 'disable-type-checked' config does, when 'recommended-type-checked' is not used
languageOptions: { parserOptions: { projectService: null } }, // this is what basically the 'disable-type-checked' config does, when 'recommended-type-checked' is not used
},
];

Expand All @@ -132,6 +133,7 @@ function customize(options: CustomizeOptions = {}) {
files: ['**/*.?(m|c)js?(x)'],
rules: {
// ** eslint:recommended overrides:
'no-unused-expressions': shared['no-unused-expressions'],
'no-unused-vars': shared['no-unused-vars'],
// ** end eslint:recommended overrides

Expand All @@ -158,10 +160,14 @@ function customize(options: CustomizeOptions = {}) {
'@typescript-eslint/no-explicit-any': 'off',
// allow @ts-ignore
'@typescript-eslint/ban-ts-comment': 'off',
// even though `no-unused-vars` is already reconfigured, this needs to be reconfigured again for typescript files, with the same options repeated
'@typescript-eslint/no-unused-vars': shared['no-unused-vars'],
// we still sometimes want to use dynamic, sync `require()` instead of `await import()`
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-require-imports': 'off',
// allow `interface I extends Base<Param> {}` syntax
'@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }],
// even though the rules blow are already reconfigured for eslint:recommended,
// they need to be reconfigured again for typescript files, with the same options repeated
'@typescript-eslint/no-unused-expressions': shared['no-unused-expressions'],
'@typescript-eslint/no-unused-vars': shared['no-unused-vars'],
// ** end typescript-eslint:recommended overrides

// additional rules
Expand Down Expand Up @@ -248,50 +254,30 @@ function customize(options: CustomizeOptions = {}) {
indent,
{
SwitchCase: 1,
// indenting parameters on multiline function calls is sometimes broken
CallExpression: { arguments: 'off' },
// @typescript-eslint/indent is broken and unmaintained,
// but there is no other, better option available at the moment. (except the prettier itself?)
// Eslint cuts ties with stylistic lints while leaving them in broken state
// https://github.com/eslint/eslint/issues/17522
// Maybe it'll be fixed one day at https://github.com/eslint-stylistic/eslint-stylistic/ 🙄
//
// Apply workarounds posted in https://github.com/typescript-eslint/typescript-eslint/issues/1824 et al.
// only enable when 'indent' is 2 spaces, as it's broken otherwise -> https://github.com/eslint-stylistic/eslint-stylistic/issues/514
offsetTernaryExpressions: indent === 2,
ignoredNodes: [
// https://github.com/typescript-eslint/typescript-eslint/issues/1824#issuecomment-1378327382
'PropertyDefinition[decorators]',
'FunctionExpression[params]:has(Identifier[decorators])',
// copied list of ignoredNodes from https://github.com/eslint-stylistic/eslint-stylistic/blob/main/packages/eslint-plugin/configs/customize.ts
// which just disables indent rules for cases not properly supported by the plugin
// (issues have been carried over from the original indent and @typescript-eslint/indent rules
// and now are being addressed occasionally, one by one, in eslint-stylistic)
'TSUnionType',
'TSIntersectionType',
// https://github.com/typescript-eslint/typescript-eslint/issues/1824#issuecomment-943783564
// Generics are not properly indented
'TSTypeParameterInstantiation',
'FunctionExpression > .params[decorators.length > 0]',
'FunctionExpression > .params > :matches(Decorator, :not(:first-child))',
// some more exclusions are needed:
// does not indent multiline interface extends (conflicts with prettier)
'TSInterfaceHeritage',
// checking indentation of multiline ternary expression is broken
// https://github.com/eslint/eslint/issues/14058
'.superTypeArguments',
// multiline generic type parameters in function calls
'CallExpression > .typeArguments',
// checking indentation of multiline ternary expression is broken in some cases (i.a. nested function calls)
'ConditionalExpression *',
// breaking on nested arrow functions
// still breaking on nested (chained) arrow functions () => () => {}
'ArrowFunctionExpression',
// https://stackoverflow.com/questions/52178093/ignore-the-indentation-in-a-template-literal-with-the-eslint-indent-rule
'TemplateLiteral *',
// ignore jsx indentation - copied from https://github.com/eslint-stylistic/eslint-stylistic/blob/main/packages/eslint-plugin/configs/customize.ts
// use jsx-indent rule instead
'JSXElement',
'JSXElement > *',
'JSXAttribute',
'JSXIdentifier',
'JSXNamespacedName',
'JSXMemberExpression',
'JSXSpreadAttribute',
'JSXExpressionContainer',
'JSXOpeningElement',
'JSXClosingElement',
'JSXFragment',
'JSXOpeningFragment',
'JSXClosingFragment',
'JSXText',
'JSXEmptyExpression',
'JSXSpreadChild',
'TemplateLiteral *', // even after some fixes in @stylistic, still not handling multiline expressions in template literals properly
],
},
],
Expand Down Expand Up @@ -390,10 +376,7 @@ function customize(options: CustomizeOptions = {}) {
rules: {
// allow i.a. `type Props = {}` in react components
// https://github.com/typescript-eslint/typescript-eslint/issues/2063#issuecomment-675156492
'@typescript-eslint/ban-types': [
'error',
{ extendDefaults: true, types: { '{}': false } },
],
'@typescript-eslint/no-empty-object-type': ['error', { allowWithName: 'Props$' }],
},
},
// our rules and overrides (react 2/2: jsx+tsx)
Expand Down Expand Up @@ -429,7 +412,6 @@ function customize(options: CustomizeOptions = {}) {
'@stylistic/jsx-equals-spacing': 'error',
'@stylistic/jsx-first-prop-new-line': 'error',
'@stylistic/jsx-function-call-newline': 'error',
'@stylistic/jsx-indent': ['error', indent],
'@stylistic/jsx-indent-props': ['error', indent],
'@stylistic/jsx-props-no-multi-spaces': 'error',
'@stylistic/jsx-quotes': 'error',
Expand Down Expand Up @@ -540,7 +522,7 @@ function customize(options: CustomizeOptions = {}) {
}

if (vitest) {
const vitestPlugin = require('eslint-plugin-vitest');
const vitestPlugin = require('@vitest/eslint-plugin');
config.push({
name: 'vitest',
files: [
Expand Down
47 changes: 23 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ovos-media/coding-standard",
"version": "2.0.2",
"version": "3.0.0-rc.0",
"description": "ovos-media coding standard",
"main": "index.js",
"types": "index.d.ts",
Expand All @@ -9,35 +9,34 @@
"repository": "https://github.com/ovos/coding-standard",
"homepage": "https://github.com/ovos/coding-standard",
"scripts": {
"prepublish": "yarn run build",
"lint": "yarn run eslint .",
"build": "tsc -p ./tsconfig.json",
"release": "standard-version"
"prepublish": "yarn build",
"lint": "eslint .",
"build": "tsc -p ./tsconfig.json"
},
"dependencies": {
"@stylistic/eslint-plugin": "^1.8.1",
"@types/eslint": "8.56.10",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-check-file": "2.6.2",
"eslint-plugin-cypress": "^3.3.0",
"eslint-plugin-import": "npm:[email protected]",
"eslint-plugin-jest": "28.4.0",
"eslint-plugin-mocha": "^10.4.3",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-vitest": "0.3.10",
"globals": "^13.24.0"
"@stylistic/eslint-plugin": "^2.12.1",
"@types/eslint": "^9.6.1",
"@typescript-eslint/eslint-plugin": "^8.19.1",
"@typescript-eslint/parser": "^8.19.1",
"@typescript-eslint/utils": "^8.19.1",
"@vitest/eslint-plugin": "^1.1.24",
"eslint": "^9.17.0",
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-check-file": "^2.8.0",
"eslint-plugin-cypress": "^4.1.0",
"eslint-plugin-import": "npm:eslint-plugin-import-x@^4.6.1",
"eslint-plugin-jest": "^28.10.0",
"eslint-plugin-mocha": "^10.5.0",
"eslint-plugin-react": "^7.37.3",
"eslint-plugin-react-hooks": "^5.1.0",
"globals": "^15.14.0"
},
"devDependencies": {
"@types/eslint-plugin-mocha": "10.4.0",
"@types/eslint__js": "8.42.3",
"@types/node": "20.14.1",
"@types/node": "20.17.10",
"@types/prettier": "3.0.0",
"prettier": "3.3.0",
"typescript": "5.4.5"
"prettier": "3.4.2",
"typescript": "5.7.2"
},
"engines": {
"node": ">=16.10"
Expand Down