@1stg/eslint-config
Version:
Personal but Shareable ESLint Configuration for all 1stG.me projects
253 lines (230 loc) • 6.32 kB
JavaScript
// @ts-check
/** @import { TSESLint } from '@typescript-eslint/utils' */
import { jsoncFiles, nonJsonRcFiles, preferPrettier } from '@1stg/config'
import { isPkgAvailable } from '@pkgr/utils'
import * as eslintMdx from 'eslint-mdx'
import jsonc_ from 'eslint-plugin-jsonc'
import * as markup_ from 'eslint-plugin-markup'
import * as mdx_ from 'eslint-plugin-mdx'
import toml_ from 'eslint-plugin-toml'
import yml_ from 'eslint-plugin-yml'
import tseslint from 'typescript-eslint'
import {
isReactPluginAvailable,
isTsAvailable,
magicNumbers,
nonSourceRules,
prettierExtends,
} from './_util.js'
import { jsBase } from './js-base.js'
import { js } from './js.js'
import { test } from './test.js'
import { resolveSettings, tsBase } from './ts-base.js'
export const ts = tseslint.config(
tsBase,
{
name: '@1stg/code-block',
files: ['**/*.{md,mdx}/**/*.{cts,mts,ts,tsx}'],
languageOptions: {
parserOptions: {
project: null,
},
},
},
{
name: '@1stg/ts',
files: ['**/*.{cts,mts,ts,tsx}'],
ignores: [
'**/*.{md,mdx}/**/*.{cts,mts,ts,tsx}',
'*.d.{cts,mts,ts}',
'*.d.*.{cts,mts,ts}',
],
extends: [tseslint.configs.recommendedTypeChecked],
rules: {
'@typescript-eslint/no-floating-promises': [2, { ignoreVoid: true }],
'@typescript-eslint/no-magic-numbers': [
2,
{
enforceConst: true,
ignore: magicNumbers,
ignoreArrayIndexes: true,
ignoreEnums: true,
ignoreNumericLiteralTypes: true,
ignoreReadonlyClassProperties: true,
},
],
'@typescript-eslint/no-unnecessary-condition': 2,
'@typescript-eslint/no-unnecessary-qualifier': 2,
'@typescript-eslint/no-unnecessary-type-arguments': 2,
'@typescript-eslint/prefer-optional-chain': 2,
'@typescript-eslint/prefer-readonly': 2,
'@typescript-eslint/prefer-reduce-type-parameter': 2,
'@typescript-eslint/prefer-string-starts-ends-with': 2,
'@typescript-eslint/require-array-sort-compare': [
2,
{ ignoreStringArrays: true },
],
'@typescript-eslint/restrict-plus-operands': 2,
'no-constant-condition': 0,
'no-magic-numbers': 0,
},
},
{
files: ['**/*.cts'],
rules: {
'@typescript-eslint/no-require-imports': 0,
},
},
)
/** @satisfies {TSESLint.FlatConfig.Config} */
export const dTs = {
name: '@1stg/d-ts',
files: ['**/*.d.{cts,mts,ts}', '**/*.d.*.{cts,mts,ts}'],
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-extraneous-class': 0,
'@typescript-eslint/no-namespace': 0,
'@typescript-eslint/no-unused-vars': 0,
'import-x/no-duplicates': 0,
'import-x/order': 0,
},
}
export const markup = tseslint.config(
{
name: '@1stg/markup-html',
files: ['**/*.html'],
extends: [markup_.configs.flatRecommended],
rules: {
'prettier/prettier': [preferPrettier ? 0 : 2, { parser: 'html' }],
},
},
{
name: '@1stg/markup-pug',
files: ['**/*.pug'],
extends: [markup_.configs.flatRecommended, ...prettierExtends],
},
)
export const md = tseslint.config(
{
name: '@1stg/md',
files: ['**/*.md'],
extends: [mdx_.configs.flat],
rules: {
'prettier/prettier': preferPrettier ? 0 : 2,
},
},
mdx_.configs.flatCodeBlocks,
)
const react = isReactPluginAvailable ? await import('./react.js') : undefined
export const mdx = tseslint.config(
{
name: '@1stg/mdx',
files: ['**/*.mdx'],
extends: [react?.reactJsx, mdx_.configs.flat].filter(Boolean),
languageOptions: {
...jsBase.languageOptions,
parser: eslintMdx,
},
settings: react?.reactJsx
? { ...react.reactJsx[0].settings, ...resolveSettings }
: resolveSettings,
rules: {
'prettier/prettier': preferPrettier ? 0 : 2,
},
},
mdx_.configs.flatCodeBlocks,
)
/** @satisfies {TSESLint.FlatConfig.Config} */
export const script = {
name: '@1stg/script',
files: ['**/scripts/**/*'],
rules: nonSourceRules,
}
export const scripts = script
/** @satisfies {TSESLint.FlatConfig.Config} */
export const story = {
name: '@1stg/story',
files: ['**/.storybook/**/*', '**/stories/**/*'],
rules: nonSourceRules,
}
export const stories = story
/** @satisfies {TSESLint.FlatConfig.Config} */
export const config = {
name: '@1stg/config',
files: ['**/.*.js', '**/*.config.{js,ts}'],
rules: nonSourceRules,
}
export const configs = config
export const json = tseslint.config({
name: '@1stg/json',
files: ['**/.*rc', '**/*.json'],
ignores: [...nonJsonRcFiles, ...jsoncFiles],
extends: [
jsonc_.configs['flat/recommended-with-json'],
jsonc_.configs['flat/prettier'],
],
})
export const jsonc = tseslint.config({
name: '@1stg/jsonc',
files: jsoncFiles,
extends: [
jsonc_.configs['flat/recommended-with-jsonc'],
jsonc_.configs['flat/prettier'],
],
})
export const json5 = tseslint.config({
name: '@1stg/json5',
files: ['**/*.json5'],
extends: [
jsonc_.configs['flat/recommended-with-json5'],
jsonc_.configs['flat/prettier'],
],
})
export const toml = tseslint.config({
name: '@1stg/toml',
files: ['**/*.toml'],
extends: [toml_.configs['flat/recommended']],
})
export const yaml = tseslint.config({
files: ['**/*.yml', '**/*.yaml'],
extends: [yml_.configs['flat/recommended'], yml_.configs['flat/prettier']],
})
export const yml = yaml
export const overrides = tseslint.config(
js,
isTsAvailable ? ts : [],
react?.react || [],
// The order matters, the later should to be preferred
markup,
isPkgAvailable('eslint-plugin-vue')
? await import('./vue.js').then(({ vue }) => vue)
: [],
isPkgAvailable('angular-eslint')
? await import('./angular.js').then(({ angular }) => angular)
: [],
md,
mdx,
isPkgAvailable('eslint-plugin-jest')
? await import('./jest.js').then(({ jest }) => jest)
: [],
isPkgAvailable('@vitest/eslint-plugin')
? await import('./vitest.js').then(({ vitest }) => vitest)
: [],
test,
scripts,
stories,
configs,
dTs,
json,
jsonc,
json5,
toml,
yaml,
// https://github.com/prettier/eslint-config-prettier#curly
{
name: '@1stg/prettier',
rules: {
curly: [2, 'all'],
},
},
)