chore: migrate to ESLint flat config (#26583)

This commit is contained in:
Luke Nelson 2024-04-03 21:46:58 +01:00 committed by GitHub
parent 2abc1a5815
commit a3a28a913e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 331 additions and 228 deletions

224
.eslintrc
View File

@ -1,224 +0,0 @@
{
"$schema": "https://json.schemastore.org/eslintrc",
"ignorePatterns": [
"dist",
"public",
"node_modules",
"packages/schema/schema"
],
"globals": {
"NodeJS": true,
"$fetch": true
},
"plugins": ["jsdoc", "import", "unicorn", "no-only-tests"],
"extends": [
"standard",
"plugin:jsdoc/recommended",
"@nuxt/eslint-config",
"plugin:import/typescript"
],
"rules": {
// Imports should come first
"import/first": "error",
// Other import rules
"import/no-mutable-exports": "error",
// Allow unresolved imports
"import/no-unresolved": "off",
// Allow paren-less arrow functions only when there's no braces
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
// Allow async-await
"generator-star-spacing": "off",
// Prefer const over let
"prefer-const": ["error", { "destructuring": "any", "ignoreReadBeforeAssign": false }],
// No single if in an "else" block
"no-lonely-if": "error",
// Force curly braces for control flow,
// including if blocks with a single statement
"curly": ["error", "all"
],
// No async function without await
"require-await": "error",
// Force dot notation when possible
"dot-notation": "error",
"no-var": "error",
// Force object shorthand where possible
"object-shorthand": "error",
// No useless destructuring/importing/exporting renames
"no-useless-rename": "error",
/**********************/
/* Unicorn Rules */
/**********************/
// Pass error message when throwing errors
"unicorn/error-message": "error",
// Uppercase regex escapes
"unicorn/escape-case": "error",
// Array.isArray instead of instanceof
"unicorn/no-array-instanceof": "error",
// Prevent deprecated `new Buffer()`
"unicorn/no-new-buffer": "error",
// Keep regex literals safe!
"unicorn/no-unsafe-regex": "off",
// Lowercase number formatting for octal, hex, binary (0x12 instead of 0X12)
"unicorn/number-literal-case": "error",
// ** instead of Math.pow()
"unicorn/prefer-exponentiation-operator": "error",
// includes over indexOf when checking for existence
"unicorn/prefer-includes": "error",
// String methods startsWith/endsWith instead of more complicated stuff
"unicorn/prefer-starts-ends-with": "error",
// textContent instead of innerText
"unicorn/prefer-text-content": "error",
// Enforce throwing type error when throwing error while checking typeof
"unicorn/prefer-type-error": "error",
// Use new when throwing error
"unicorn/throw-new-error": "error",
"sort-imports": [
"error",
{
"ignoreDeclarationSort": true
}
],
"no-only-tests/no-only-tests": "error",
"unicorn/prefer-node-protocol": "error",
"no-console": "warn",
"vue/one-component-per-file": "off",
"vue/require-default-prop": "off",
// Vue stylistic rules from `@antfu/eslint-config`
"vue/array-bracket-spacing": ["error", "never"],
"vue/arrow-spacing": ["error", { "after": true, "before": true }],
"vue/block-spacing": ["error", "always"],
"vue/block-tag-newline": [
"error",
{
"multiline": "always",
"singleline": "always"
}
],
"vue/brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
"vue/comma-dangle": ["error", "always-multiline"],
"vue/comma-spacing": ["error", { "after": true, "before": false }],
"vue/comma-style": ["error", "last"],
"vue/html-comment-content-spacing": [
"error",
"always",
{
"exceptions": ["-"]
}
],
"vue/key-spacing": ["error", { "afterColon": true, "beforeColon": false }],
"vue/keyword-spacing": ["error", { "after": true, "before": true }],
"vue/object-curly-newline": "off",
"vue/object-curly-spacing": ["error", "always"],
"vue/object-property-newline": [
"error",
{ "allowMultiplePropertiesPerLine": true }
],
"vue/operator-linebreak": ["error", "before"],
"vue/padding-line-between-blocks": ["error", "always"],
"vue/quote-props": ["error", "consistent-as-needed"],
"vue/space-in-parens": ["error", "never"],
"vue/template-curly-spacing": "error",
"jsdoc/require-jsdoc": "off",
"jsdoc/require-param": "off",
"jsdoc/require-returns": "off",
"jsdoc/require-param-type": "off",
"import/order": [
"error",
{
"pathGroups": [
{
"pattern": "#vue-router",
"group": "external"
}
]
}
],
"import/no-restricted-paths": [
"error",
{
"zones": [
{
"from": "packages/nuxt/src/!(core)/**/*",
"target": "packages/nuxt/src/core",
"message": "core should not directly import from modules."
},
{
"from": "packages/nuxt/src/!(app)/**/*",
"target": "packages/nuxt/src/app",
"message": "app should not directly import from modules."
},
{
"from": "packages/nuxt/src/app/**/index.ts",
"target": "packages/nuxt/src",
"message": "should not import from barrel/index files"
},
{
"from": "packages/nitro",
"target": "packages/!(nitro)/**/*",
"message": "nitro should not directly import other packages."
}
]
}
],
"@typescript-eslint/consistent-type-imports": [
"error",
{
"disallowTypeAnnotations": false
}
],
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-expect-error": "allow-with-description",
"ts-ignore": true
}
],
"@typescript-eslint/prefer-ts-expect-error": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
],
"jsdoc/check-tag-names": [
"error",
{
"definedTags": ["__NO_SIDE_EFFECTS__"]
}
]
},
"overrides": [
{
"files": ["packages/schema/**"],
"rules": {
"jsdoc/valid-types": "off",
"jsdoc/check-tag-names": [
"error",
{
"definedTags": ["experimental"]
}
]
}
},
{
"files": ["packages/nuxt/src/app/**", "test/**", "**/runtime/**"],
"rules": {
"no-console": "off"
}
}
],
"settings": {
"jsdoc": {
"ignoreInternal": true,
"tagNamePreference": {
"warning": "warning",
"note": "note"
}
}
}
}

280
eslint.config.mjs Normal file
View File

@ -0,0 +1,280 @@
// Configs
// import standard from "eslint-config-standard"
// import nuxt from '@nuxt/eslint-config'
// Plugins
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import jsdoc from 'eslint-plugin-jsdoc'
import esImport from 'eslint-plugin-import'
import unicorn from 'eslint-plugin-unicorn'
import noOnlyTests from 'eslint-plugin-no-only-tests'
/**
* eslintrc compatibility
* @see https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config
* @see https://github.com/eslint/eslintrc#usage-esm
*/
import { FlatCompat } from '@eslint/eslintrc'
import js from '@eslint/js'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended
})
// TODO: Type definition?
export default [
{
ignores: [
'**/dist/**',
'**/.nuxt/**',
'**/.nuxt-*/**',
'**/.output/**',
'**/.output-*/**',
'**/public/**',
'**/node_modules/**',
'packages/schema/schema',
// TODO: remove when fully migrated to flat config
'**/*.d.mts'
]
},
// standard,
...compat.extends('eslint-config-standard'),
jsdoc.configs['flat/recommended'],
// nuxt,
...compat.extends('@nuxt/eslint-config'),
esImport.configs.typescript,
{
rules: {
'import/export': 'off'
}
},
{
files: ['**/*.vue', '**/*.ts', '**/*.mts', '**/*.js', '**/*.cjs', '**/*.mjs'],
languageOptions: {
globals: {
NodeJS: 'readonly',
$fetch: 'readonly'
}
},
plugins: {
jsdoc,
import: esImport,
unicorn,
'no-only-tests': noOnlyTests
},
rules: {
// Imports should come first
'import/first': 'error',
// Other import rules
'import/no-mutable-exports': 'error',
// Allow unresolved imports
'import/no-unresolved': 'off',
// Allow paren-less arrow functions only when there's no braces
'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }],
// Allow async-await
'generator-star-spacing': 'off',
// Prefer const over let
'prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: false }],
// No single if in an "else" block
'no-lonely-if': 'error',
// Force curly braces for control flow,
// including if blocks with a single statement
curly: ['error', 'all'],
// No async function without await
'require-await': 'error',
// Force dot notation when possible
'dot-notation': 'error',
'no-var': 'error',
// Force object shorthand where possible
'object-shorthand': 'error',
// No useless destructuring/importing/exporting renames
'no-useless-rename': 'error',
/**********************/
/* Unicorn Rules */
/**********************/
// Pass error message when throwing errors
'unicorn/error-message': 'error',
// Uppercase regex escapes
'unicorn/escape-case': 'error',
// Array.isArray instead of instanceof
'unicorn/no-array-instanceof': 'error',
// Prevent deprecated `new Buffer()`
'unicorn/no-new-buffer': 'error',
// Keep regex literals safe!
'unicorn/no-unsafe-regex': 'off',
// Lowercase number formatting for octal, hex, binary (0x12 instead of 0X12)
'unicorn/number-literal-case': 'error',
// ** instead of Math.pow()
'unicorn/prefer-exponentiation-operator': 'error',
// includes over indexOf when checking for existence
'unicorn/prefer-includes': 'error',
// String methods startsWith/endsWith instead of more complicated stuff
'unicorn/prefer-starts-ends-with': 'error',
// textContent instead of innerText
'unicorn/prefer-text-content': 'error',
// Enforce throwing type error when throwing error while checking typeof
'unicorn/prefer-type-error': 'error',
// Use new when throwing error
'unicorn/throw-new-error': 'error',
'sort-imports': [
'error',
{
ignoreDeclarationSort: true
}
],
'no-only-tests/no-only-tests': 'error',
'unicorn/prefer-node-protocol': 'error',
'no-console': ['warn', { allow: ['warn', 'error', 'debug'] }],
'vue/one-component-per-file': 'off',
'vue/require-default-prop': 'off',
// Vue stylistic rules from `@antfu/eslint-config`
'vue/array-bracket-spacing': ['error', 'never'],
'vue/arrow-spacing': ['error', { after: true, before: true }],
'vue/block-spacing': ['error', 'always'],
'vue/block-tag-newline': [
'error',
{
multiline: 'always',
singleline: 'always'
}
],
'vue/brace-style': ['error', 'stroustrup', { allowSingleLine: true }],
'vue/comma-dangle': ['error', 'always-multiline'],
'vue/comma-spacing': ['error', { after: true, before: false }],
'vue/comma-style': ['error', 'last'],
'vue/html-comment-content-spacing': [
'error',
'always',
{
exceptions: ['-']
}
],
'vue/key-spacing': ['error', { afterColon: true, beforeColon: false }],
'vue/keyword-spacing': ['error', { after: true, before: true }],
'vue/object-curly-newline': 'off',
'vue/object-curly-spacing': ['error', 'always'],
'vue/object-property-newline': [
'error',
{ allowMultiplePropertiesPerLine: true }
],
'vue/operator-linebreak': ['error', 'before'],
'vue/padding-line-between-blocks': ['error', 'always'],
'vue/quote-props': ['error', 'consistent-as-needed'],
'vue/space-in-parens': ['error', 'never'],
'vue/template-curly-spacing': 'error',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-param': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/require-param-type': 'off',
'import/order': [
'error',
{
pathGroups: [
{
pattern: '#vue-router',
group: 'external'
}
]
}
],
'import/no-restricted-paths': [
'error',
{
zones: [
{
from: 'packages/nuxt/src/!(core)/**/*',
target: 'packages/nuxt/src/core',
message: 'core should not directly import from modules.'
},
{
from: 'packages/nuxt/src/!(app)/**/*',
target: 'packages/nuxt/src/app',
message: 'app should not directly import from modules.'
},
{
from: 'packages/nuxt/src/app/**/index.ts',
target: 'packages/nuxt/src',
message: 'should not import from barrel/index files'
},
{
from: 'packages/nitro',
target: 'packages/!(nitro)/**/*',
message: 'nitro should not directly import other packages.'
}
]
}
],
'@typescript-eslint/consistent-type-imports': [
'error',
{
disallowTypeAnnotations: false
}
],
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
'ts-ignore': true
}
],
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true
}
],
'jsdoc/check-tag-names': [
'error',
{
definedTags: ['__NO_SIDE_EFFECTS__']
}
]
},
settings: {
jsdoc: {
ignoreInternal: true,
tagNamePreference: {
warning: 'warning',
note: 'note'
}
}
}
},
{
files: ['packages/schema/**'],
rules: {
'jsdoc/valid-types': 'off',
'jsdoc/check-tag-names': [
'error',
{
definedTags: ['experimental']
}
]
}
},
{
files: ['packages/nuxt/src/app/**', 'test/**', '**/runtime/**', '**/*.test.ts'],
rules: {
'no-console': 'off'
}
},
{
files: ['test/fixtures/**'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'vue/valid-v-for': 'off'
}
}
]

View File

@ -13,8 +13,8 @@
"cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'", "cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'",
"dev": "pnpm play", "dev": "pnpm play",
"dev:prepare": "pnpm --filter './packages/**' prepack --stub", "dev:prepare": "pnpm --filter './packages/**' prepack --stub",
"lint": "eslint --ext .vue,.ts,.js,.mjs .", "lint": "eslint .",
"lint:fix": "eslint --ext .vue,.ts,.js,.mjs . --fix", "lint:fix": "eslint . --fix",
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md", "lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md",
"lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' *.md --fix", "lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' *.md --fix",
"lint:knip": "pnpx knip", "lint:knip": "pnpx knip",
@ -44,6 +44,8 @@
"magic-string": "^0.30.8" "magic-string": "^0.30.8"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "3.0.2",
"@eslint/js": "8.57.0",
"@nuxt/eslint-config": "0.2.0", "@nuxt/eslint-config": "0.2.0",
"@nuxt/kit": "workspace:*", "@nuxt/kit": "workspace:*",
"@nuxt/test-utils": "3.12.0", "@nuxt/test-utils": "3.12.0",

View File

@ -1,3 +1,4 @@
/* eslint-disable jsdoc/require-jsdoc */
function defineNuxtConfig (config) { function defineNuxtConfig (config) {
return config return config
} }

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line import/export
export * from 'vue' export * from 'vue'
export const install = () => {} export const install = () => {}

View File

@ -220,7 +220,7 @@ function isComponentNotCalledInSetup (codeAst: Node, name: string): string | voi
/** /**
* retrieve the component identifier being used on ssrRender callExpression * retrieve the component identifier being used on ssrRender callExpression
* @param {CallExpression} ssrRenderNode - ssrRender callExpression * @param ssrRenderNode - ssrRender callExpression
*/ */
function getComponentName (ssrRenderNode: AcornNode<CallExpression>): string { function getComponentName (ssrRenderNode: AcornNode<CallExpression>): string {
const componentCall = ssrRenderNode.arguments[0] as Identifier | MemberExpression | CallExpression const componentCall = ssrRenderNode.arguments[0] as Identifier | MemberExpression | CallExpression

View File

@ -1,5 +1,4 @@
/// <reference types="nitropack" /> /// <reference types="nitropack" />
export * from './dist/index.js'
import type { DefineNuxtConfig } from 'nuxt/config' import type { DefineNuxtConfig } from 'nuxt/config'
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema' import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
@ -7,6 +6,8 @@ import type { H3Event } from 'h3'
import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from './dist/app/types.js' import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from './dist/app/types.js'
import type { LogObject } from 'consola' import type { LogObject } from 'consola'
export * from './dist/index.js'
declare global { declare global {
const defineNuxtConfig: DefineNuxtConfig const defineNuxtConfig: DefineNuxtConfig
const defineNuxtSchema: (schema: SchemaDefinition) => SchemaDefinition const defineNuxtSchema: (schema: SchemaDefinition) => SchemaDefinition

View File

@ -19,6 +19,12 @@ importers:
.: .:
devDependencies: devDependencies:
'@eslint/eslintrc':
specifier: 3.0.2
version: 3.0.2
'@eslint/js':
specifier: 8.57.0
version: 8.57.0
'@nuxt/eslint-config': '@nuxt/eslint-config':
specifier: 0.2.0 specifier: 0.2.0
version: 0.2.0(eslint@8.57.0) version: 0.2.0(eslint@8.57.0)
@ -1919,6 +1925,23 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/@eslint/eslintrc@3.0.2:
resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4
espree: 10.0.1
globals: 14.0.0
ignore: 5.3.1
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
dev: true
/@eslint/js@8.57.0: /@eslint/js@8.57.0:
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -6145,6 +6168,11 @@ packages:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
/eslint-visitor-keys@4.0.0:
resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dev: true
/eslint@8.57.0: /eslint@8.57.0:
resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -6191,6 +6219,15 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/espree@10.0.1:
resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dependencies:
acorn: 8.11.3
acorn-jsx: 5.3.2(acorn@8.11.3)
eslint-visitor-keys: 4.0.0
dev: true
/espree@9.6.1: /espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -6702,6 +6739,11 @@ packages:
dependencies: dependencies:
type-fest: 0.20.2 type-fest: 0.20.2
/globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
dev: true
/globalthis@1.0.3: /globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}