Skip to content

Instantly share code, notes, and snippets.

@HotCherryPie
Created November 2, 2024 13:22
Show Gist options
  • Save HotCherryPie/7e86eeb46271c23a239b95a5c43c66b6 to your computer and use it in GitHub Desktop.
Save HotCherryPie/7e86eeb46271c23a239b95a5c43c66b6 to your computer and use it in GitHub Desktop.
/* eslint-disable unicorn/no-array-reduce */
import js from '@eslint/js';
import {
parser as tsParser,
plugin as ts,
configs as tsPredefinedConfigs,
} from 'typescript-eslint';
import vue from 'eslint-plugin-vue';
import vueParser from 'vue-eslint-parser';
import unicorn from 'eslint-plugin-unicorn';
import sonarjs from 'eslint-plugin-sonarjs';
import eslintConfigPrettier from 'eslint-config-prettier';
// https://typescript-eslint.io/packages/parser/#projectservice
// https://github.com/vuejs/vue-eslint-parser/issues/104
// https://github.com/ota-meshi/typescript-eslint-parser-for-extra-files/issues/95
const jsConfig = {
plugins: {
unicorn,
sonarjs,
},
rules: {
...js.configs.recommended.rules,
...unicorn.configs['flat/recommended'].rules,
...sonarjs.configs.recommended.rules,
/* Updates of rules form predefined configs */
'sonarjs/todo-tag': 'off',
'unicorn/prevent-abbreviations': [
'error',
{ allowList: { env: true, props: true } },
],
},
};
const tsConfig = {
plugins: {
...jsConfig.plugins,
'@typescript-eslint': ts,
},
rules: {
...jsConfig.rules,
...tsPredefinedConfigs.eslintRecommended.rules,
...tsPredefinedConfigs.recommended.find(
(it) => it.name === 'typescript-eslint/recommended',
).rules,
...tsPredefinedConfigs.strict.find(
(it) => it.name === 'typescript-eslint/strict',
).rules,
// ...tsPredefinedConfigs.strictTypeChecked.find((it) => it.name === 'typescript-eslint/strict-type-checked').rules,
/* Enables of uncategorized rules */
'@typescript-eslint/no-import-type-side-effects': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'variable',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
},
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
},
{
selector: 'parameter',
format: ['camelCase', 'PascalCase'],
},
{
selector: 'parameter',
modifiers: ['unused'],
format: ['camelCase', 'PascalCase'],
filter: { match: true, regex: '^_.*' },
leadingUnderscore: 'require',
},
{
selector: 'typeLike',
format: ['PascalCase'],
custom: {
regex: '^[IT][A-Z]',
match: false,
},
},
{
selector: 'typeParameter',
format: ['PascalCase'],
custom: {
regex: '^[T]([A-Z]|$)',
match: true,
},
},
],
},
};
const vueConfig = {
plugins: {
...tsConfig.plugins,
vue,
},
rules: {
...tsConfig.rules,
...vue.configs['flat/recommended']
.flatMap((it) => it.rules)
.reduce((a, b) => ({ ...a, ...b }), {}),
/* Updates of rules form predefined configs */
'vue/multi-word-component-names': 'off',
'vue/no-reserved-component-names': 'off',
/* Enables of uncategorized rules */
'vue/block-lang': ['error', { script: { lang: 'ts' } }],
'vue/block-order': [
'error',
{
order: ['script', 'template', 'style'],
},
],
'vue/component-api-style': ['error', ['script-setup']],
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/custom-event-name-casing': ['error', 'camelCase'],
'vue/define-emits-declaration': ['error', 'type-based'],
'vue/define-props-declaration': ['error', 'type-based'],
'vue/enforce-style-attribute': ['error', { allow: ['module'] }],
'vue/html-button-has-type': 'error',
'vue/html-comment-content-newline': 'error',
'vue/html-comment-content-spacing': 'error',
'vue/html-comment-indent': 'error',
'vue/no-duplicate-attr-inheritance': 'error',
'vue/no-empty-component-block': 'error',
'vue/no-ref-object-reactivity-loss': 'error',
'vue/no-required-prop-with-default': 'error',
'vue/no-setup-props-reactivity-loss': 'error',
'vue/no-undef-components': 'error',
'vue/no-undef-properties': 'error',
'vue/no-unused-emit-declarations': 'error',
'vue/no-unused-properties': 'error',
'vue/no-unused-refs': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/no-useless-mustaches': 'error',
'vue/no-useless-v-bind': 'error',
'vue/no-v-text': 'error',
'vue/padding-line-between-blocks': ['error', 'always'],
'vue/prefer-define-options': 'error',
'vue/prefer-prop-type-boolean-first': 'error',
'vue/require-explicit-slots': 'error',
'vue/require-macro-variable-name': [
'error',
{
defineProps: 'props',
defineEmits: 'emit',
defineSlots: 'slots',
useSlots: 'slots',
useAttrs: 'attrs',
},
],
'vue/require-typed-ref': 'error',
'vue/require-default-prop': 'off',
'vue/valid-define-options': 'error',
'vue/attribute-hyphenation': ['error', 'never'],
'vue/v-on-event-hyphenation': ['error', 'never'],
},
};
/** @type {import('eslint').Linter.Config} */
export default [
/* LANG: JS */
{
name: 'lang/js',
files: ['**/*.{js,mjs,cjs}'],
languageOptions: {
sourceType: 'module',
},
plugins: jsConfig.plugins,
rules: jsConfig.rules,
},
/* LANG: TS */
{
name: 'lang/ts',
files: ['**/*.{ts,mts,cts}'],
languageOptions: {
parser: tsParser,
sourceType: 'module',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: tsConfig.plugins,
rules: tsConfig.rules,
},
/* LANG: Vue */
{
name: 'lang/vue',
files: ['**/*.vue'],
processor: vue.processors.vue,
languageOptions: {
parser: vueParser,
sourceType: 'module',
parserOptions: {
parser: tsParser,
projectService: true,
tsconfigRootDir: import.meta.dirname,
extraFileExtensions: ['.vue'],
},
},
plugins: vueConfig.plugins,
rules: vueConfig.rules,
},
/* COMPAT: Prettier */
// NOTE: ideally this should always be at the end of config.
// Or all related rules should be disabled by configuration above.
{
name: 'compatibility/prettier',
rules: {
...eslintConfigPrettier.rules,
},
},
];
import globals from 'globals';
import baseConfig from './eslint.config.base.js';
/** @type {import('eslint').Linter.Config} */
export default [
...baseConfig,
/* ENV: Node */
{
name: 'env/node',
files: ['eslint.config.js', 'vite.config.ts'],
languageOptions: { globals: globals.node },
},
/* ENV: Browser */
{
name: 'env/browser',
files: ['lib/**/*.*'],
languageOptions: { globals: globals.browser },
},
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment