@qes-test/eslint-config
Version:
ESLint configuration for QES projects
1,164 lines (1,144 loc) • 33.9 kB
JavaScript
import createCommand from 'eslint-plugin-command/config';
import * as pluginImport from 'eslint-plugin-import-x';
import js from '@eslint/js';
import pluginUnusedImports from 'eslint-plugin-unused-imports';
import globals from 'globals';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
async function command() {
return [
{
...createCommand()
}
];
}
async function interopDefault(m) {
const resolved = await m;
return resolved.default || resolved;
}
async function comments() {
const [pluginComments] = await Promise.all([
// @ts-expect-error - no types
interopDefault(import('eslint-plugin-eslint-comments'))
]);
return [
{
plugins: {
"eslint-comments": pluginComments
},
rules: {
"eslint-comments/no-aggregating-enable": "error",
"eslint-comments/no-duplicate-disable": "error",
"eslint-comments/no-unlimited-disable": "error",
"eslint-comments/no-unused-enable": "error"
}
}
];
}
async function disableds() {
return [
{
files: ["**/__tests__/**/*.?([cm])[jt]s?(x)"],
name: "disables/test",
rules: {
"@typescript-eslint/ban-ts-comment": "off",
"no-console": "off"
}
},
{
files: ["**/*.d.ts"],
name: "disables/dts",
rules: {
"@typescript-eslint/triple-slash-reference": "off"
}
},
{
files: ["**/*.js", "**/*.mjs", "**/*.cjs"],
name: "disables/js",
rules: {
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}
];
}
async function ignores() {
return [
{
ignores: [
"**/node_modules",
"**/dist",
"**/dist-*",
"**/*-dist",
"**/.husky",
"**/.nitro",
"**/.output",
"**/Dockerfile",
"**/package-lock.json",
"**/yarn.lock",
"**/pnpm-lock.yaml",
"**/bun.lockb",
"**/output",
"**/coverage",
"**/temp",
"**/.temp",
"**/tmp",
"**/.tmp",
"**/.history",
"**/.turbo",
"**/.nuxt",
"**/.next",
"**/.vercel",
"**/.changeset",
"**/.idea",
"**/.cache",
"**/.output",
"**/.vite-inspect",
"**/CHANGELOG*.md",
"**/*.min.*",
"**/LICENSE*",
"**/__snapshots__",
"**/*.snap",
"**/fixtures/**",
"**/.vitepress/cache/**",
"**/auto-import?(s).d.ts",
"**/components.d.ts",
"**/vite.config.mts.*",
"**/*.sh",
"**/*.ttf",
"**/*.woff"
]
}
];
}
async function importPluginConfig() {
return [
{
plugins: {
// @ts-expect-error - This is a dynamic import
import: pluginImport
},
rules: {
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
"import/no-mutable-exports": "error",
"import/no-named-default": "error",
"import/no-self-import": "error",
"import/no-unresolved": "off",
"import/no-webpack-loader-syntax": "error"
}
}
];
}
async function javascript() {
return [
{
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
document: "readonly",
navigator: "readonly",
window: "readonly"
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: "latest",
sourceType: "module"
},
sourceType: "module"
},
linterOptions: {
reportUnusedDisableDirectives: true
},
plugins: {
"unused-imports": pluginUnusedImports
},
rules: {
...js.configs.recommended.rules,
"accessor-pairs": [
"error",
{ enforceForClassMembers: true, setWithoutGet: true }
],
"array-callback-return": "error",
"block-scoped-var": "error",
"constructor-super": "error",
"default-case-last": "error",
"dot-notation": ["error", { allowKeywords: true }],
eqeqeq: ["error", "always"],
"keyword-spacing": "off",
"new-cap": [
"error",
{ capIsNew: false, newIsCap: true, properties: true }
],
"no-alert": "off",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-caller": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": ["error", "always"],
"no-console": ["error", { allow: ["warn", "error"] }],
"no-const-assign": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": ["error", { allowEmptyCatch: true }],
"no-empty-character-class": "error",
"no-empty-function": "off",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-labels": ["error", { allowLoop: false, allowSwitch: false }],
"no-lone-blocks": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-multi-str": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-proto": "error",
"no-prototype-builtins": "error",
"no-redeclare": ["error", { builtinGlobals: false }],
"no-regex-spaces": "error",
"no-restricted-globals": [
"error",
{ message: "Use `globalThis` instead.", name: "global" },
{ message: "Use `globalThis` instead.", name: "self" }
],
"no-restricted-properties": [
"error",
{
message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.",
property: "__proto__"
},
{
message: "Use `Object.defineProperty` instead.",
property: "__defineGetter__"
},
{
message: "Use `Object.defineProperty` instead.",
property: "__defineSetter__"
},
{
message: "Use `Object.getOwnPropertyDescriptor` instead.",
property: "__lookupGetter__"
},
{
message: "Use `Object.getOwnPropertyDescriptor` instead.",
property: "__lookupSetter__"
}
],
"no-restricted-syntax": [
"error",
"DebuggerStatement",
"LabeledStatement",
"WithStatement",
"TSEnumDeclaration[const=true]",
"TSExportAssignment"
],
"no-self-assign": ["error", { props: true }],
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-undef": "off",
"no-undef-init": "error",
"no-unexpected-multiline": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": ["error", { defaultAssignment: false }],
"no-unreachable": "error",
"no-unreachable-loop": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": [
"error",
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}
],
"no-unused-vars": "off",
"no-use-before-define": [
"error",
{ classes: false, functions: false, variables: false }
],
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-with": "error",
"object-shorthand": [
"error",
"always",
{ avoidQuotes: true, ignoreConstructors: false }
],
"one-var": ["error", { initialized: "never" }],
"prefer-arrow-callback": [
"error",
{
allowNamedFunctions: false,
allowUnboundThis: true
}
],
"prefer-const": [
"error",
{
destructuring: "all",
ignoreReadBeforeAssign: true
}
],
"prefer-exponentiation-operator": "error",
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
"prefer-rest-params": "error",
"prefer-template": "error",
"space-before-function-paren": "off",
"spaced-comment": "error",
"symbol-description": "error",
"unicode-bom": ["error", "never"],
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"error",
{
vars: "all",
varsIgnorePattern: "^_",
args: "all",
argsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_"
}
],
"use-isnan": [
"error",
{ enforceForIndexOf: true, enforceForSwitchCase: true }
],
"valid-typeof": ["error", { requireStringLiterals: true }],
"vars-on-top": "error",
yoda: ["error", "never"]
}
}
];
}
async function jsdoc() {
const [pluginJsdoc] = await Promise.all([
interopDefault(import('eslint-plugin-jsdoc'))
]);
return [
{
plugins: {
jsdoc: pluginJsdoc
},
rules: {
"jsdoc/check-access": "warn",
"jsdoc/check-param-names": "warn",
"jsdoc/check-property-names": "warn",
"jsdoc/check-types": "warn",
"jsdoc/empty-tags": "warn",
"jsdoc/implements-on-classes": "warn",
"jsdoc/no-defaults": "warn",
"jsdoc/no-multi-asterisks": "warn",
"jsdoc/require-param-name": "warn",
"jsdoc/require-property": "warn",
"jsdoc/require-property-description": "warn",
"jsdoc/require-property-name": "warn",
"jsdoc/require-returns-check": "warn",
"jsdoc/require-returns-description": "warn",
"jsdoc/require-yields-check": "warn"
}
}
];
}
async function jsonc() {
const [pluginJsonc, parserJsonc] = await Promise.all([
interopDefault(import('eslint-plugin-jsonc')),
interopDefault(import('jsonc-eslint-parser'))
]);
return [
{
files: ["**/*.json", "**/*.json5", "**/*.jsonc", "*.code-workspace"],
languageOptions: {
parser: parserJsonc
},
plugins: {
jsonc: pluginJsonc
},
rules: {
"jsonc/no-bigint-literals": "error",
"jsonc/no-binary-expression": "error",
"jsonc/no-binary-numeric-literals": "error",
"jsonc/no-dupe-keys": "error",
"jsonc/no-escape-sequence-in-identifier": "error",
"jsonc/no-floating-decimal": "error",
"jsonc/no-hexadecimal-numeric-literals": "error",
"jsonc/no-infinity": "error",
"jsonc/no-multi-str": "error",
"jsonc/no-nan": "error",
"jsonc/no-number-props": "error",
"jsonc/no-numeric-separators": "error",
"jsonc/no-octal": "error",
"jsonc/no-octal-escape": "error",
"jsonc/no-octal-numeric-literals": "error",
"jsonc/no-parenthesized": "error",
"jsonc/no-plus-sign": "error",
"jsonc/no-regexp-literals": "error",
"jsonc/no-sparse-arrays": "error",
"jsonc/no-template-literals": "error",
"jsonc/no-undefined-value": "error",
"jsonc/no-unicode-codepoint-escapes": "error",
"jsonc/no-useless-escape": "error",
"jsonc/space-unary-ops": "error",
"jsonc/valid-json-number": "error",
"jsonc/vue-custom-block/no-parsing-error": "error"
}
},
sortTsconfig(),
sortPackageJson()
];
}
function sortPackageJson() {
return {
files: ["**/package.json"],
rules: {
"jsonc/sort-array-values": [
"error",
{
order: { type: "asc" },
pathPattern: "^files$|^pnpm.neverBuiltDependencies$"
}
],
"jsonc/sort-keys": [
"error",
{
order: [
"name",
"version",
"description",
"private",
"keywords",
"homepage",
"bugs",
"repository",
"license",
"author",
"contributors",
"categories",
"funding",
"type",
"scripts",
"files",
"sideEffects",
"bin",
"main",
"module",
"unpkg",
"jsdelivr",
"types",
"typesVersions",
"imports",
"exports",
"publishConfig",
"icon",
"activationEvents",
"contributes",
"peerDependencies",
"peerDependenciesMeta",
"dependencies",
"optionalDependencies",
"devDependencies",
"engines",
"packageManager",
"pnpm",
"overrides",
"resolutions",
"husky",
"simple-git-hooks",
"lint-staged",
"eslintConfig"
],
pathPattern: "^$"
},
{
order: { type: "asc" },
pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$"
},
{
order: { type: "asc" },
pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$"
},
{
order: ["types", "import", "require", "default"],
pathPattern: "^exports.*$"
}
]
}
};
}
function sortTsconfig() {
return {
files: [
"**/tsconfig.json",
"**/tsconfig.*.json",
"internal/tsconfig/*.json"
],
rules: {
"jsonc/sort-keys": [
"error",
{
order: [
"extends",
"compilerOptions",
"references",
"files",
"include",
"exclude"
],
pathPattern: "^$"
},
{
order: [
/* Projects */
"incremental",
"composite",
"tsBuildInfoFile",
"disableSourceOfProjectReferenceRedirect",
"disableSolutionSearching",
"disableReferencedProjectLoad",
/* Language and Environment */
"target",
"jsx",
"jsxFactory",
"jsxFragmentFactory",
"jsxImportSource",
"lib",
"moduleDetection",
"noLib",
"reactNamespace",
"useDefineForClassFields",
"emitDecoratorMetadata",
"experimentalDecorators",
/* Modules */
"baseUrl",
"rootDir",
"rootDirs",
"customConditions",
"module",
"moduleResolution",
"moduleSuffixes",
"noResolve",
"paths",
"resolveJsonModule",
"resolvePackageJsonExports",
"resolvePackageJsonImports",
"typeRoots",
"types",
"allowArbitraryExtensions",
"allowImportingTsExtensions",
"allowUmdGlobalAccess",
/* JavaScript Support */
"allowJs",
"checkJs",
"maxNodeModuleJsDepth",
/* Type Checking */
"strict",
"strictBindCallApply",
"strictFunctionTypes",
"strictNullChecks",
"strictPropertyInitialization",
"allowUnreachableCode",
"allowUnusedLabels",
"alwaysStrict",
"exactOptionalPropertyTypes",
"noFallthroughCasesInSwitch",
"noImplicitAny",
"noImplicitOverride",
"noImplicitReturns",
"noImplicitThis",
"noPropertyAccessFromIndexSignature",
"noUncheckedIndexedAccess",
"noUnusedLocals",
"noUnusedParameters",
"useUnknownInCatchVariables",
/* Emit */
"declaration",
"declarationDir",
"declarationMap",
"downlevelIteration",
"emitBOM",
"emitDeclarationOnly",
"importHelpers",
"importsNotUsedAsValues",
"inlineSourceMap",
"inlineSources",
"mapRoot",
"newLine",
"noEmit",
"noEmitHelpers",
"noEmitOnError",
"outDir",
"outFile",
"preserveConstEnums",
"preserveValueImports",
"removeComments",
"sourceMap",
"sourceRoot",
"stripInternal",
/* Interop Constraints */
"allowSyntheticDefaultImports",
"esModuleInterop",
"forceConsistentCasingInFileNames",
"isolatedModules",
"preserveSymlinks",
"verbatimModuleSyntax",
/* Completeness */
"skipDefaultLibCheck",
"skipLibCheck"
],
pathPattern: "^compilerOptions$"
}
]
}
};
}
async function node() {
const pluginNode = await interopDefault(import('eslint-plugin-n'));
return [
{
plugins: {
n: pluginNode
},
rules: {
"n/handle-callback-err": ["error", "^(err|error)$"],
"n/no-deprecated-api": "error",
"n/no-exports-assign": "error",
"n/no-extraneous-import": [
"error",
{
allowModules: [
"unbuild",
"@qes/vite-config",
"vitest",
"vite",
"@vue/test-utils",
"@qes/tailwind-config",
"@playwright/test"
]
}
],
"n/no-new-require": "error",
"n/no-path-concat": "error",
// 'n/no-unpublished-import': 'off',
"n/no-unsupported-features/es-syntax": [
"error",
{
ignores: [],
version: ">=18.0.0"
}
],
"n/prefer-global/buffer": ["error", "never"],
// 'n/no-missing-import': 'off',
"n/prefer-global/process": ["error", "never"],
"n/process-exit-as-throw": "error"
}
},
{
files: [
"scripts/**/*.?([cm])[jt]s?(x)",
"internal/**/*.?([cm])[jt]s?(x)"
],
rules: {
"n/prefer-global/process": "off"
}
}
];
}
async function perfectionist() {
const perfectionistPlugin = await interopDefault(
import('eslint-plugin-perfectionist')
);
return [
perfectionistPlugin.configs["recommended-natural"],
{
rules: {
"perfectionist/sort-exports": [
"error",
{
order: "asc",
type: "natural"
}
],
"perfectionist/sort-imports": [
"error",
{
customGroups: {
type: {
"qes-core-type": ["^@qes-core/.+"],
"qes-type": ["^@qes/.+"],
"vue-type": ["^vue$", "^vue-.+", "^@vue/.+"]
},
value: {
qes: ["^@qes/.+"],
"qes-core": ["^@qes-core/.+"],
vue: ["^vue$", "^vue-.+", "^@vue/.+"]
}
},
environment: "node",
groups: [
["external-type", "builtin-type", "type"],
"vue-type",
"qes-type",
"qes-core-type",
["parent-type", "sibling-type", "index-type"],
["internal-type"],
"builtin",
"vue",
"qes",
"qes-core",
"external",
"internal",
["parent", "sibling", "index"],
"side-effect",
"side-effect-style",
"style",
"object",
"unknown"
],
internalPattern: ["^#/.+"],
newlinesBetween: "always",
order: "asc",
type: "natural"
}
],
"perfectionist/sort-modules": "off",
"perfectionist/sort-named-exports": [
"error",
{
order: "asc",
type: "natural"
}
],
"perfectionist/sort-objects": [
"off",
{
customGroups: {
items: "items",
list: "list",
children: "children"
},
groups: ["unknown", "items", "list", "children"],
ignorePattern: ["children"],
order: "asc",
type: "natural"
}
]
}
}
];
}
async function prettier() {
const [pluginPrettier] = await Promise.all([
interopDefault(import('eslint-plugin-prettier'))
]);
return [
{
plugins: {
prettier: pluginPrettier
},
rules: {
"prettier/prettier": "error"
}
}
];
}
async function regexp() {
const [pluginRegexp] = await Promise.all([
interopDefault(import('eslint-plugin-regexp'))
]);
return [
{
plugins: {
regexp: pluginRegexp
},
rules: {
...pluginRegexp.configs.recommended.rules
}
}
];
}
async function test() {
const [pluginTest, pluginNoOnlyTests] = await Promise.all([
interopDefault(import('eslint-plugin-vitest')),
// @ts-expect-error - no types
interopDefault(import('eslint-plugin-no-only-tests'))
]);
return [
{
files: [
`**/__tests__/**/*.?([cm])[jt]s?(x)`,
`**/*.spec.?([cm])[jt]s?(x)`,
`**/*.test.?([cm])[jt]s?(x)`,
`**/*.bench.?([cm])[jt]s?(x)`,
`**/*.benchmark.?([cm])[jt]s?(x)`
],
plugins: {
test: {
...pluginTest,
rules: {
...pluginTest.rules,
...pluginNoOnlyTests.rules
}
}
},
rules: {
"no-console": "off",
"node/prefer-global/process": "off",
"test/consistent-test-it": [
"error",
{ fn: "it", withinDescribe: "it" }
],
"test/no-identical-title": "error",
"test/no-import-node-test": "error",
"test/no-only-tests": "error",
"test/prefer-hooks-in-order": "error",
"test/prefer-lowercase-title": "error"
}
}
];
}
async function typescript() {
const [pluginTs, parserTs] = await Promise.all([
interopDefault(import('@typescript-eslint/eslint-plugin')),
// @ts-expect-error missing types
interopDefault(import('@typescript-eslint/parser'))
]);
return [
{
files: ["**/*.?([cm])[jt]s?(x)"],
languageOptions: {
parser: parserTs,
parserOptions: {
createDefaultProgram: false,
ecmaFeatures: {
jsx: true
},
ecmaVersion: "latest",
extraFileExtensions: [".vue"],
jsxPragma: "React",
project: "./tsconfig.*.json",
sourceType: "module"
}
},
plugins: {
"@typescript-eslint": pluginTs
},
rules: {
...pluginTs.configs["eslint-recommended"].overrides?.[0].rules,
...pluginTs.configs.strict.rules,
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-check": false,
"ts-expect-error": "allow-with-description",
"ts-ignore": "allow-with-description",
"ts-nocheck": "allow-with-description"
}
],
// '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions", "functions", "methods"]
}
],
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_"
}
],
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-literal-enum-member": "off",
"@typescript-eslint/no-duplicate-enum-values": "off",
"@typescript-eslint/no-extraneous-class": "off",
"unused-imports/no-unused-vars": "off"
}
}
];
}
async function vue() {
const [
pluginVue,
parserVue,
parserTs,
vuejsAccessibility,
checkMessageOrigin
] = await Promise.all([
interopDefault(import('eslint-plugin-vue')),
interopDefault(import('vue-eslint-parser')),
// @ts-expect-error missing types
interopDefault(import('@typescript-eslint/parser')),
interopDefault(import('eslint-plugin-vuejs-accessibility')),
interopDefault(import('./chunks/index.mjs'))
]);
const flatEssential = pluginVue.configs?.["flat/essential"] || [];
const flatStronglyRecommended = pluginVue.configs?.["flat/strongly-recommended"] || [];
const flatRecommended = pluginVue.configs?.["flat/recommended"] || [];
return [
...flatEssential,
...flatStronglyRecommended,
...flatRecommended,
{
files: ["**/*.vue"],
languageOptions: {
// globals: {
// computed: 'readonly',
// defineEmits: 'readonly',
// defineExpose: 'readonly',
// defineProps: 'readonly',
// onMounted: 'readonly',
// onUnmounted: 'readonly',
// reactive: 'readonly',
// ref: 'readonly',
// shallowReactive: 'readonly',
// shallowRef: 'readonly',
// toRef: 'readonly',
// toRefs: 'readonly',
// watch: 'readonly',
// watchEffect: 'readonly',
// },
parser: parserVue,
parserOptions: {
ecmaFeatures: {
jsx: true
},
extraFileExtensions: [".vue"],
parser: parserTs,
sourceType: "module"
}
},
plugins: {
vue: pluginVue,
"vuejs-accessibility": vuejsAccessibility,
"custom-message": checkMessageOrigin
},
processor: pluginVue.processors?.[".vue"],
rules: {
...pluginVue.configs?.base?.rules,
"vue/attribute-hyphenation": [
"error",
"always",
{
ignore: []
}
],
"vue/attributes-order": "off",
"vue/block-order": "off",
"vue/component-name-in-template-casing": ["error", "PascalCase"],
"vue/component-options-name-casing": ["error", "PascalCase"],
"vue/custom-event-name-casing": ["error", "camelCase"],
"vue/define-macros-order": [
"error",
{
order: [
"defineOptions",
"defineProps",
"defineEmits",
"defineSlots"
]
}
],
"vue/dot-location": ["error", "property"],
"vue/dot-notation": ["error", { allowKeywords: true }],
"vue/eqeqeq": ["error", "smart"],
"vue/html-closing-bracket-newline": "error",
"vue/html-indent": "off",
// 'vue/html-indent': ['error', 2],
"vue/html-quotes": ["error", "double"],
"vue/html-self-closing": [
"error",
{
html: {
component: "always",
normal: "never",
void: "always"
},
math: "always",
svg: "always"
}
],
"vue/max-attributes-per-line": "off",
"vue/multi-word-component-names": "off",
"vue/multiline-html-element-content-newline": "error",
"vue/no-empty-pattern": "off",
"vue/no-extra-parens": ["error", "functions"],
"vue/no-irregular-whitespace": "error",
"vue/no-loss-of-precision": "error",
"vue/no-reserved-component-names": "off",
"vue/no-restricted-syntax": [
"error",
"DebuggerStatement",
"LabeledStatement",
"WithStatement",
// 验证table相关属性
{
selector: 'VElement[name="table"]:not(:has(VAttribute[key.name="aria-describedby"]))',
message: "<table> \u5FC5\u987B\u5305\u542B aria-describedby \u5C5E\u6027"
},
{
selector: 'VElement[name="th"]:not(:has(VAttribute[key.name="scope"]))',
message: "<th> \u5FC5\u987B\u5305\u542B scope \u5C5E\u6027"
},
{
selector: 'VElement[name="a"]:has(VAttribute[key.name="target"][value.value="_blank"]):not(:has(VAttribute[key.name="rel"]))',
message: 'a\u6807\u7B7E \u4F7F\u7528 target="_blank" \u65F6\u5FC5\u987B\u6DFB\u52A0 rel \u5C5E\u6027'
},
{
selector: 'VElement[name="a"]:has(VAttribute[key.name="target"][value.value="_blank"]):has(VAttribute[key.name="rel"]):not(:has(VAttribute[key.name="rel"][value.value="noopener"])):not(:has(VAttribute[key.name="rel"][value.value="noreferrer"])):not(:has(VAttribute[key.name="rel"][value.value="noopener noreferrer"])):not(:has(VAttribute[key.name="rel"][value.value="noreferrer noopener"]))',
message: 'a\u6807\u7B7E \u4F7F\u7528 target="_blank" \u65F6\uFF0Crel \u5C5E\u6027\u5FC5\u987B\u5305\u542B "noopener" \u6216 "noreferrer"'
}
],
"vue/no-restricted-v-bind": ["error", "/^v-/"],
"vue/no-sparse-arrays": "error",
"vue/no-unused-refs": "error",
"vue/no-useless-v-bind": "warn",
"vue/object-shorthand": [
"error",
"always",
{
avoidQuotes: true,
ignoreConstructors: false
}
],
"vue/one-component-per-file": "error",
"vue/prefer-import-from-vue": "error",
"vue/prefer-separate-static-class": "error",
"vue/prefer-template": "error",
"vue/prop-name-casing": ["error", "camelCase"],
"vue/require-default-prop": "error",
"vue/require-explicit-emits": "error",
"vue/require-prop-types": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/space-infix-ops": "error",
"vue/no-undef-properties": "error",
"vue/space-unary-ops": ["error", { nonwords: false, words: true }],
"vue/v-on-event-hyphenation": [
"error",
"always",
{
autofix: true,
ignore: []
}
],
// vuejs-accessibility
"vuejs-accessibility/alt-text": "error",
"vuejs-accessibility/iframe-has-title": "error",
"vuejs-accessibility/aria-props": "error",
"vuejs-accessibility/no-redundant-roles": "error",
// custom plugins
"custom-message/check-message-origin": "error"
}
}
];
}
const restrictedImportIgnores = ["**/vite.config.ts"];
const customConfig = [
{
files: ["packages/**/**"],
ignores: restrictedImportIgnores,
rules: {
"perfectionist/sort-interfaces": "off",
"perfectionist/sort-objects": "off",
"prefer-spread": "off",
"eslint-comments/no-unlimited-disable": "off"
}
},
{
files: ["**/**.vue"],
ignores: restrictedImportIgnores,
rules: {
"perfectionist/sort-objects": "off"
}
},
{
files: ["**/**.vue", "**/**.ts"],
ignores: restrictedImportIgnores,
plugins: {
"@typescript-eslint": typescriptEslint
},
rules: {
"@typescript-eslint/no-explicit-any": "warn"
}
},
{
files: ["internal/**/**", "scripts/**/**"],
rules: {
"no-console": "off"
}
}
];
async function defineConfig(config = []) {
const configs = [
vue(),
javascript(),
ignores(),
prettier(),
typescript(),
jsonc(),
disableds(),
importPluginConfig(),
node(),
perfectionist(),
comments(),
jsdoc(),
test(),
regexp(),
command(),
// turbo(), // 暂时移除,因为有兼容性问题
...customConfig,
...config
];
const resolved = await Promise.all(configs);
return resolved.flat();
}
export { defineConfig };