@shayanthenerd/eslint-config
Version:
A modern, flexible ESLint configuration for enforcing best practices and maintaining a consistent coding style
413 lines (412 loc) • 17.1 kB
JavaScript
import { isTruthy } from "../utils/isTruthy.mjs";
import { isEnabled } from "../utils/isEnabled.mjs";
import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
import { getRestrictedVueInputs } from "../helpers/vue/getRestrictedVueInputs.mjs";
import { getRestrictedVueElements } from "../helpers/vue/getRestrictedVueElements.mjs";
//#region src/rules/vue.ts
function getVueRules(options) {
const { typescript, stylistic, vue, nuxt } = options.configs;
const { indent, trailingComma, maxLineLength, maxAttributesPerLine, maxConsecutiveEmptyLines, selfCloseVoidHtmlElements } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
const { blockLang, blocksOrder, macrosOrder, attributesOrder, destructureProps, vForDelimiterStyle, attributeHyphenation, templateMaxLineLength, allowedStyleAttributes, preferVBindTrueShorthand, componentNameCaseInTemplate, preferVBindSameNameShorthand, restrictedElements: userRestrictedElements, ignoredUndefinedComponents: userIgnoredUndefinedComponents, restrictedStaticAttributes: userRestrictedStaticAttributes } = isEnabled(vue) ? vue : defaultOptions.configs.vue;
const { imageComponents: userImageComponents, anchorComponents: userAnchorComponents, accessibleChildComponents: userAccessibleChildComponents } = isEnabled(vue) && isEnabled(vue.accessibility) ? vue.accessibility : defaultOptions.configs.vue.accessibility;
const isNuxtEnabled = isEnabled(nuxt);
const isNuxtImageEnabled = isNuxtEnabled ? nuxt.image : void 0;
const isNuxtUIEnabled = isNuxtEnabled ? nuxt.ui : void 0;
const nuxtUIPrefix = isNuxtEnabled && isEnabled(nuxt.ui) ? nuxt.ui.prefix : defaultOptions.configs.nuxt.ui.prefix;
const isNuxtIconEnabled = isNuxtEnabled ? nuxt.icon : void 0;
const nuxtIconComponent = isNuxtEnabled && isEnabled(nuxt.icon) ? nuxt.icon.component : defaultOptions.configs.nuxt.icon.component;
const restrictedVueElements = isNuxtUIEnabled ? getRestrictedVueElements(nuxtUIPrefix) : [];
const restrictedVueInputs = isNuxtUIEnabled ? getRestrictedVueInputs(nuxtUIPrefix) : [];
const isScriptLangTS = blockLang.script === "ts";
const isStyleLangImplicit = blockLang.style === "implicit";
const vueAccessibilityRules = {
"vuejs-accessibility/alt-text": ["error", { img: userImageComponents }],
"vuejs-accessibility/anchor-has-content": ["error", {
components: userAnchorComponents,
accessibleChildren: userAccessibleChildComponents
}],
"vuejs-accessibility/aria-props": "error",
"vuejs-accessibility/aria-role": "error",
"vuejs-accessibility/aria-unsupported-elements": "error",
"vuejs-accessibility/form-control-has-label": ["error", { labelComponents: isNuxtUIEnabled ? [`${nuxtUIPrefix}FormField`] : void 0 }],
"vuejs-accessibility/heading-has-content": "error",
"vuejs-accessibility/iframe-has-title": "error",
"vuejs-accessibility/interactive-supports-focus": "error",
"vuejs-accessibility/label-has-for": ["error", {
allowChildren: true,
required: { some: ["nesting", "id"] },
controlComponents: [
"input",
"output",
"meter",
"select",
"textarea",
"progress"
]
}],
"vuejs-accessibility/media-has-caption": "error",
"vuejs-accessibility/no-access-key": "warn",
"vuejs-accessibility/no-aria-hidden-on-focusable": "error",
"vuejs-accessibility/no-autofocus": "warn",
"vuejs-accessibility/no-distracting-elements": "warn",
"vuejs-accessibility/no-redundant-roles": "warn",
"vuejs-accessibility/no-role-presentation-on-focusable": "error",
"vuejs-accessibility/no-static-element-interactions": "error",
"vuejs-accessibility/role-has-required-aria-props": "error",
"vuejs-accessibility/tabindex-no-positive": "error"
};
const vueRules = {
"@typescript-eslint/no-useless-default-assignment": "off",
"vue/jsx-uses-vars": "error",
"vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
"vue/multi-word-component-names": "error",
"vue/no-arrow-functions-in-watch": "warn",
"vue/no-async-in-computed-properties": ["error", { ignoredObjectNames: ["z", "zod"] }],
"vue/no-child-content": "error",
"vue/no-computed-properties-in-data": "error",
"vue/no-deprecated-data-object-declaration": "error",
"vue/no-deprecated-delete-set": "error",
"vue/no-deprecated-destroyed-lifecycle": "error",
"vue/no-deprecated-dollar-listeners-api": "error",
"vue/no-deprecated-dollar-scopedslots-api": "error",
"vue/no-deprecated-events-api": "error",
"vue/no-deprecated-filter": "error",
"vue/no-deprecated-functional-template": "error",
"vue/no-deprecated-html-element-is": "error",
"vue/no-deprecated-inline-template": "error",
"vue/no-deprecated-model-definition": ["error", { allowVue3Compat: true }],
"vue/no-deprecated-props-default-this": "error",
"vue/no-deprecated-router-link-tag-prop": "error",
"vue/no-deprecated-scope-attribute": "error",
"vue/no-deprecated-slot-attribute": "error",
"vue/no-deprecated-slot-scope-attribute": "error",
"vue/no-deprecated-v-bind-sync": "error",
"vue/no-deprecated-v-is": "error",
"vue/no-deprecated-v-on-native-modifier": "error",
"vue/no-deprecated-v-on-number-modifiers": "error",
"vue/no-deprecated-vue-config-keycodes": "error",
"vue/no-dupe-keys": "error",
"vue/no-dupe-v-else-if": "error",
"vue/no-duplicate-attributes": "error",
"vue/no-export-in-script-setup": "error",
"vue/no-expose-after-await": "error",
"vue/no-lifecycle-after-await": "error",
"vue/no-mutating-props": "error",
"vue/no-parsing-error": "error",
"vue/no-ref-as-operand": "error",
"vue/no-reserved-component-names": "error",
"vue/no-reserved-keys": "error",
"vue/no-reserved-props": "error",
"vue/no-shared-component-data": "error",
"vue/no-side-effects-in-computed-properties": "error",
"vue/no-template-key": "error",
"vue/no-textarea-mustache": "error",
"vue/no-unused-components": "error",
"vue/no-unused-vars": "error",
"vue/no-use-computed-property-like-method": "error",
"vue/no-use-v-if-with-v-for": "error",
"vue/no-useless-template-attributes": "error",
"vue/no-v-for-template-key-on-child": "error",
"vue/no-v-text-v-html-on-component": "error",
"vue/no-watch-after-await": "error",
"vue/prefer-import-from-vue": "error",
"vue/require-component-is": "error",
"vue/require-prop-type-constructor": "error",
"vue/require-render-return": "error",
"vue/require-slots-as-functions": "error",
"vue/require-toggle-inside-transition": "error",
"vue/require-v-for-key": "error",
"vue/require-valid-default-prop": "error",
"vue/return-in-computed-property": "error",
"vue/return-in-emits-validator": "error",
"vue/use-v-on-exact": "error",
"vue/valid-attribute-name": "error",
"vue/valid-define-emits": "error",
"vue/valid-define-options": "error",
"vue/valid-define-props": "error",
"vue/valid-next-tick": "error",
"vue/valid-template-root": "error",
"vue/valid-v-bind": "error",
"vue/valid-v-cloak": "error",
"vue/valid-v-else-if": "error",
"vue/valid-v-else": "error",
"vue/valid-v-for": ["error", { allowEmptyAlias: true }],
"vue/valid-v-html": "error",
"vue/valid-v-if": "error",
"vue/valid-v-is": "error",
"vue/valid-v-memo": "error",
"vue/valid-v-model": "error",
"vue/valid-v-on": "error",
"vue/valid-v-once": "error",
"vue/valid-v-pre": "error",
"vue/valid-v-show": "error",
"vue/valid-v-slot": "error",
"vue/valid-v-text": "error",
"vue/attribute-hyphenation": ["warn", attributeHyphenation],
"vue/component-definition-name-casing": "warn",
"vue/first-attribute-linebreak": isEnabled(stylistic) ? "warn" : "off",
"vue/html-closing-bracket-newline": isEnabled(stylistic) ? "warn" : "off",
"vue/html-closing-bracket-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/html-end-tags": "warn",
"vue/html-indent": isEnabled(stylistic) ? ["warn", indent] : "off",
"vue/html-quotes": isEnabled(stylistic) ? "warn" : "off",
"vue/html-self-closing": isEnabled(stylistic) ? ["error", { html: {
normal: "never",
void: selfCloseVoidHtmlElements
} }] : "off",
"vue/max-attributes-per-line": isEnabled(stylistic) ? ["warn", { singleline: { max: maxAttributesPerLine } }] : "off",
"vue/multiline-html-element-content-newline": isEnabled(stylistic) ? "warn" : "off",
"vue/mustache-interpolation-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/no-multi-spaces": isEnabled(stylistic) ? "warn" : "off",
"vue/no-spaces-around-equal-signs-in-attribute": isEnabled(stylistic) ? "warn" : "off",
"vue/no-template-shadow": "error",
"vue/one-component-per-file": "error",
"vue/prop-name-casing": "warn",
"vue/v-bind-style": [
"warn",
"shorthand",
{ sameNameShorthand: preferVBindSameNameShorthand }
],
"vue/v-on-event-hyphenation": [
"warn",
attributeHyphenation,
{ autofix: true }
],
"vue/v-on-style": "warn",
"vue/v-slot-style": ["warn", { atComponent: "shorthand" }],
"vue/attributes-order": ["warn", { order: attributesOrder }],
"vue/block-order": ["warn", { order: blocksOrder }],
"vue/no-lone-template": "error",
"vue/no-multiple-slot-args": "error",
"vue/no-required-prop-with-default": ["error", { autofix: true }],
"vue/no-v-html": ["warn", { ignorePattern: "^html" }],
"vue/order-in-components": "warn",
"vue/this-in-template": "warn",
"vue/array-bracket-newline": isEnabled(stylistic) ? ["warn", "consistent"] : "off",
"vue/array-bracket-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/arrow-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/block-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/brace-style": isEnabled(stylistic) ? [
"warn",
"1tbs",
{ allowSingleLine: true }
] : "off",
"vue/camelcase": ["warn", {
properties: "never",
ignoreImports: true,
ignoreDestructuring: true
}],
"vue/comma-dangle": isEnabled(stylistic) ? ["warn", trailingComma] : "off",
"vue/comma-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/comma-style": isEnabled(stylistic) ? "warn" : "off",
"vue/dot-notation": "warn",
"vue/eqeqeq": "error",
"vue/func-call-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/key-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/keyword-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/max-len": isEnabled(stylistic) ? ["warn", {
tabWidth: indent,
code: maxLineLength,
template: templateMaxLineLength,
comments: templateMaxLineLength,
ignoreUrls: true,
ignoreStrings: true,
ignoreComments: true,
ignoreRegExpLiterals: true,
ignoreTrailingComments: true,
ignoreTemplateLiterals: true,
ignoreHTMLTextContents: true,
ignoreHTMLAttributeValues: true
}] : "off",
"vue/multiline-ternary": isEnabled(stylistic) ? ["warn", "always-multiline"] : "off",
"vue/no-console": ["warn", { allow: [
"info",
"warn",
"error",
"table",
"group",
"groupEnd",
"groupCollapsed"
] }],
"vue/no-constant-condition": "warn",
"vue/no-empty-pattern": "warn",
"vue/no-implicit-coercion": "warn",
"vue/no-irregular-whitespace": "warn",
"vue/no-loss-of-precision": "error",
"vue/no-sparse-arrays": "error",
"vue/no-useless-concat": "error",
"vue/object-curly-newline": isEnabled(stylistic) ? ["warn", {
multiline: true,
consistent: true
}] : "off",
"vue/object-curly-spacing": isEnabled(stylistic) ? ["warn", "always"] : "off",
"vue/object-property-newline": isEnabled(stylistic) ? ["warn", { allowAllPropertiesOnSameLine: true }] : "off",
"vue/object-shorthand": "warn",
"vue/operator-linebreak": isEnabled(stylistic) ? [
"warn",
"none",
{ overrides: {
"=": "after",
"?": "before",
":": "before",
"|": "before",
"&": "before"
} }
] : "off",
"vue/prefer-template": "warn",
"vue/quote-props": isEnabled(stylistic) ? ["warn", "consistent-as-needed"] : "off",
"vue/space-in-parens": isEnabled(stylistic) ? "warn" : "off",
"vue/space-infix-ops": isEnabled(stylistic) ? "warn" : "off",
"vue/space-unary-ops": isEnabled(stylistic) ? "warn" : "off",
"vue/template-curly-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/block-lang": ["error", {
script: { lang: blockLang.script },
style: {
lang: isStyleLangImplicit ? void 0 : blockLang.style,
allowNoLang: isStyleLangImplicit
}
}],
"vue/block-tag-newline": ["warn", {
singleline: "always",
maxEmptyLines: maxConsecutiveEmptyLines ? maxConsecutiveEmptyLines - 1 : 0
}],
"vue/component-api-style": "error",
"vue/component-name-in-template-casing": [
"warn",
componentNameCaseInTemplate,
{
ignores: ["/^\\w+(\\.\\w+)+$/"],
registeredComponentsOnly: false
}
],
"vue/component-options-name-casing": "warn",
"vue/custom-event-name-casing": "warn",
"vue/define-emits-declaration": ["warn", isScriptLangTS ? "type-based" : "runtime"],
"vue/define-macros-order": ["warn", { order: macrosOrder }],
"vue/define-props-declaration": ["error", isScriptLangTS ? "type-based" : "runtime"],
"vue/define-props-destructuring": ["warn", { destructure: destructureProps }],
"vue/enforce-style-attribute": ["error", { allow: allowedStyleAttributes }],
"vue/html-button-has-type": "error",
"vue/html-comment-content-newline": isEnabled(stylistic) ? "warn" : "off",
"vue/html-comment-content-spacing": isEnabled(stylistic) ? "warn" : "off",
"vue/html-comment-indent": isEnabled(stylistic) ? ["warn", indent] : "off",
"vue/match-component-file-name": ["error", {
shouldMatchCase: true,
extensions: isEnabled(typescript) ? [
"vue",
"js",
"jsx",
"ts",
"tsx"
] : [
"vue",
"js",
"jsx"
]
}],
"vue/match-component-import-name": "warn",
"vue/next-tick-style": "warn",
"vue/no-duplicate-attr-inheritance": "error",
"vue/no-duplicate-class-names": "warn",
"vue/no-empty-component-block": "error",
"vue/no-import-compiler-macros": "error",
"vue/no-multiple-objects-in-class": "warn",
"vue/no-negated-v-if-condition": "warn",
"vue/no-ref-object-reactivity-loss": "error",
"vue/no-restricted-html-elements": [
"error",
{
element: isNuxtEnabled ? "time" : "",
message: "Use `<NuxtTime>`."
},
{
element: isNuxtImageEnabled ? "img" : "",
message: "Use `<NuxtImg>`."
},
{
element: isNuxtUIEnabled ? [
"a",
"RouterLink",
"NuxtLink"
] : "",
message: isNuxtUIEnabled ? `Use \`<${nuxtUIPrefix}Link>\`.` : void 0
},
{
element: ["a", isNuxtEnabled ? "RouterLink" : ""],
message: `Use \`<${isNuxtEnabled ? "NuxtLink" : "RouterLink"}>\`.`
},
...restrictedVueElements,
...userRestrictedElements
],
"vue/no-restricted-static-attribute": [
"error",
...restrictedVueInputs,
isNuxtUIEnabled ? {
key: "href",
element: `${nuxtUIPrefix}Link`,
message: "Use `v-bind:to=\"\"`."
} : { key: "" },
isNuxtUIEnabled ? {
key: "href",
element: `${nuxtUIPrefix}Button`,
message: "Use `v-bind:to=\"\"`."
} : { key: " " },
...userRestrictedStaticAttributes
],
"vue/no-root-v-if": "warn",
"vue/no-setup-props-reactivity-loss": "error",
"vue/no-static-inline-styles": ["warn", { allowBinding: true }],
"vue/no-this-in-before-route-enter": "error",
"vue/no-undef-components": ["error", { ignorePatterns: [
isNuxtEnabled && "^Nuxt",
isNuxtEnabled && "^(Html|Head|Title|Base|Meta|Link|Style|Body|NoScript|ClientOnly|DevOnly)$",
isNuxtIconEnabled && `^${nuxtIconComponent}$`,
isNuxtUIEnabled && `^${nuxtUIPrefix}`,
...userIgnoredUndefinedComponents
].filter(isTruthy) }],
"vue/no-undef-directives": isNuxtEnabled ? "off" : "error",
"vue/no-unused-emit-declarations": "error",
"vue/no-unused-properties": ["error", {
groups: [
"setup",
"props",
"data",
"inject",
"asyncData",
"computed",
"methods"
],
deepData: true,
unreferencedOptions: ["returnAsUnreferenced"]
}],
"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": "warn",
"vue/prefer-define-options": "warn",
"vue/prefer-prop-type-boolean-first": "warn",
"vue/prefer-separate-static-class": "warn",
"vue/prefer-single-event-payload": "warn",
"vue/prefer-true-attribute-shorthand": ["warn", preferVBindTrueShorthand],
"vue/prefer-use-template-ref": "warn",
"vue/prefer-v-model": "warn",
"vue/require-default-export": "error",
"vue/require-emit-validator": "error",
"vue/require-expose": "error",
"vue/require-macro-variable-name": "warn",
"vue/require-typed-object-prop": isScriptLangTS ? "error" : "off",
"vue/require-typed-ref": isScriptLangTS ? "error" : "off",
"vue/slot-name-casing": "warn",
"vue/v-for-delimiter-style": ["warn", vForDelimiterStyle]
};
if (isEnabled(stylistic)) vueRules["@stylistic/max-len"] = "off";
const isVueAccessibilityEnabled = isEnabled(vue) && isEnabled(vue.accessibility);
return {
...vueRules,
...isVueAccessibilityEnabled && vueAccessibilityRules
};
}
//#endregion
export { getVueRules };