@danwithabox/eslint-entree
Version:
An appetizer for linting 🥂
756 lines (745 loc) • 23 kB
JavaScript
import gitignore from "eslint-config-flat-gitignore";
import { defineConfig, defineConfig as defineConfig$1 } from "eslint/config";
import plugin_stylistic from "@stylistic/eslint-plugin";
import tseslint from "typescript-eslint";
import plugin_vue from "eslint-plugin-vue";
import plugin_vue_processor from "eslint-plugin-vue/lib/processor.js";
import parser_vue from "vue-eslint-parser";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
//#region rolldown:runtime
var __defProp = Object.defineProperty;
var __export = (all) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
return target;
};
//#endregion
//#region src/eslint-sample-js/config-typescript.entree.js
/**
* Provides the needed plugin and parser config for TypeScript.
*
* @template { import("eslint").Linter.RulesRecord } T
* @param { T } rules
*/
function config_typescript(rules) {
return defineConfig$1({
files: [...["**/*.?([cm])[jt]s"]],
plugins: {
"@stylistic": plugin_stylistic,
"@typescript-eslint": tseslint.plugin
},
languageOptions: {
parser: tseslint.parser,
parserOptions: { sourceType: "module" }
},
rules
});
}
//#endregion
//#region src/eslint-sample-js/config-vue3.entree.js
/**
* Provides the needed plugin and parser config for Vue 3 with:
* - TypeScript support in `<script>` blocks and template expressions
* - Single File Components
* - Composition API
* - and `<script setup>`
*
* https://eslint.vuejs.org/
*
* @template { import("eslint").Linter.RulesRecord } T
* @param { T } rules
*/
function config_vue(rules) {
const GLOB_VUE = ["*.vue", "**/*.vue"];
const GLOB_SVG_VUE = ["**/*.svg.vue"];
return defineConfig$1({
files: [...GLOB_VUE],
ignores: [...GLOB_SVG_VUE],
plugins: {
"@stylistic": plugin_stylistic,
"@typescript-eslint": tseslint.plugin,
vue: plugin_vue
},
languageOptions: {
parser: parser_vue,
sourceType: "module",
parserOptions: {
parser: tseslint.parser,
sourceType: "module",
ecmaFeatures: { jsx: false },
extraFileExtensions: [".vue"]
}
},
processor: plugin_vue_processor,
rules
});
}
//#endregion
//#region src/eslint-sample-js/config-react.entree.js
/**
* Provides the needed plugin and parser config for React.
*
* @template { import("eslint").Linter.RulesRecord } T
* @param { T } rules
*/
function config_react(rules) {
return defineConfig$1({
files: [...["**/*.[jt]sx"]],
plugins: {
"@stylistic": plugin_stylistic,
"@typescript-eslint": tseslint.plugin,
"react-hooks": reactHooks,
"react-refresh": reactRefresh
},
languageOptions: {
globals: { ...globals.browser },
parser: tseslint.parser,
parserOptions: {
ecmaFeatures: { jsx: true },
extraFileExtensions: [".tsx"],
sourceType: "module"
}
},
rules
});
}
//#endregion
//#region src/entree-configs.ts
/**
* ESLint config for TypeScript + .gitignore file support from `eslint-config-flat-gitignore`.
*/
function typeScript$1(config) {
const { typeScriptRules, gitignore: _gitignore } = config;
return defineConfig$1([..._gitignore ? [gitignore()] : [], config_typescript(typeScriptRules)]);
}
/**
* ESLint config for TypeScript & Vue 3 + .gitignore file support from `eslint-config-flat-gitignore`.
*
* Vue 3 support is focused on Single File Components with Composition API and `<script setup>`
*/
function vue3$1(config) {
const { typeScriptRules, vue3Rules, gitignore: _gitignore } = config;
return defineConfig$1([
..._gitignore ? [gitignore()] : [],
config_typescript(typeScriptRules),
config_vue({
...typeScriptRules,
...vue3Rules
})
]);
}
/**
* ESLint config for TypeScript & React + .gitignore file support from `eslint-config-flat-gitignore`.
*/
function react$1(config) {
const { typeScriptRules, reactRules, gitignore: _gitignore } = config;
return defineConfig$1([
..._gitignore ? [gitignore()] : [],
config_typescript(typeScriptRules),
config_react({
...typeScriptRules,
...reactRules
})
]);
}
/**
* Configs bundled with the library.
*/
const entreeConfigs = {
typeScript: typeScript$1,
vue3: vue3$1,
react: react$1
};
//#endregion
//#region src/entree-utils.ts
/**
* A simple helper to make working with rules in `@ts-check`-enabled files easier
* by returning a narrowly typed object with explicitly known keys.
*
* Needed for {@link entreeFilterRules} to work correctly.
*
* Is not not needed for ESLint otherwise.
*/
function entreeDefineRules(rules) {
return rules;
}
/**
* Provide a rules object to receive a getter function that returns the option of the given rule.
*
* Useful for sharing options between a base rule, and a rule that extends the base rule,
* e.g. in the case of `eslint-plugin-vue` extension rules and the corresponding base `@stylistic` rules.
*/
function entreeAdoptOptionsFromRules(rules) {
function getOptionsOf(keyOfRule) {
const rule = rules[keyOfRule];
if (!rule) console.warn(`[entree-utils.ts] Unexpectedly missing rule: "${String(keyOfRule)}". Rules:`, rules);
return rule;
}
return { getOptionsOf };
}
/**
* Filter rules for adoption or debugging purposes by excluding and picking rules.
*
* ---
*
* Filtering is meant to help in the adoption process.
*
* Ideally, the filtering is entirely removed after processing the whole codebase, and all rules are fully covering the code.
*
* - `exclude` is used to cut down on the printed result of eslint, to set aside rules that overwhelm the output
* - `pick` is used to select from the remaining results the ones you currently want to fix, and to verify their adoption
*
* After the rule(s) in `pick` are done, run eslint again, and pick again from the results.
*
* After everything you picked is done, process the rules that you previously excluded, if there were any.
*/
function entreeFilterRules(rules, opts) {
if (opts === void 0) return rules;
const { exclude, pick, debug = false } = opts;
const rulesFiltered = {};
if (pick !== void 0) for (const key_picked of pick) rulesFiltered[key_picked] = rules[key_picked];
else {
for (const [key, rule] of Object.entries(rules)) rulesFiltered[key] = rule;
for (const key_excluded of exclude) delete rulesFiltered[key_excluded];
}
if (debug) {
const count_rules = Object.keys(rules).length;
const count_filtered = Object.keys(rulesFiltered).length;
console.info(`Filtered ${count_rules} rules down to ${count_filtered}. Result:`, rulesFiltered);
}
return rulesFiltered;
}
//#endregion
//#region src/eslint-sample-js/rules-typescript.entree.js
var rules_typescript_entree_exports = /* @__PURE__ */ __export({
typeScript: () => typeScript,
typeScript_eslint: () => typeScript_eslint,
typeScript_filteredBy_miscellaneous: () => typeScript_filteredBy_miscellaneous,
typeScript_filteredBy_recommended: () => typeScript_filteredBy_recommended,
typeScript_filteredBy_strict: () => typeScript_filteredBy_strict,
typeScript_filteredBy_tsStylistic: () => typeScript_filteredBy_tsStylistic,
typeScript_stylistic: () => typeScript_stylistic
});
/**
* Combines all hand-picked rule collections for TypeScript.
*
* https://typescript-eslint.io/
*/
function typeScript() {
return entreeDefineRules({
...typeScript_eslint(),
...typeScript_stylistic(),
...typeScript_filteredBy_recommended(),
...typeScript_filteredBy_tsStylistic(),
...typeScript_filteredBy_strict(),
...typeScript_filteredBy_miscellaneous()
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://eslint.org/docs/latest/rules/
*/
function typeScript_eslint() {
return entreeDefineRules({
"no-compare-neg-zero": ["error"],
"no-debugger": ["error"],
"no-irregular-whitespace": ["error", {
skipComments: true,
skipJSXText: true,
skipRegExps: true,
skipStrings: true,
skipTemplates: true
}],
"no-promise-executor-return": ["warn", { allowVoid: true }],
"no-self-assign": ["warn", { props: true }],
"no-self-compare": ["warn"],
"require-atomic-updates": ["error", { allowProperties: true }],
"use-isnan": ["warn", {
enforceForSwitchCase: true,
enforceForIndexOf: true
}],
"no-caller": ["error"],
"eqeqeq": [
"warn",
"always",
{ null: "always" }
],
"default-case-last": ["warn"],
"default-case": ["warn", { commentPattern: "^skip\\sdefault" }],
"no-implicit-coercion": ["warn", {
boolean: true,
number: true,
string: true,
disallowTemplateShorthand: false,
allow: []
}],
"no-octal": ["warn"],
"no-nonoctal-decimal-escape": ["warn"],
"no-throw-literal": ["warn"],
"no-undefined": ["warn"],
"no-useless-escape": ["warn"],
"no-useless-rename": ["warn", {
ignoreImport: false,
ignoreExport: false,
ignoreDestructuring: false
}],
"no-var": ["warn"],
"prefer-const": ["warn", {
destructuring: "all",
ignoreReadBeforeAssign: false
}],
"prefer-promise-reject-errors": ["warn", { allowEmptyReject: false }],
"prefer-template": ["warn"],
"require-unicode-regexp": ["warn"],
"symbol-description": ["warn"]
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://eslint.style/packages/default
*/
function typeScript_stylistic() {
return entreeDefineRules({
"@stylistic/type-annotation-spacing": ["warn", {
before: false,
after: true,
overrides: { arrow: {
before: true,
after: true
} }
}],
"@stylistic/space-before-function-paren": ["warn", {
anonymous: "always",
named: "never",
asyncArrow: "always"
}],
"@stylistic/semi": ["warn", "always"],
"@stylistic/no-extra-semi": ["warn"],
"@stylistic/no-trailing-spaces": ["warn", { ignoreComments: true }],
"@stylistic/space-infix-ops": ["warn", { int32Hint: true }],
"@stylistic/object-curly-spacing": [
"warn",
"always",
{
arraysInObjects: false,
objectsInObjects: false
}
],
"@stylistic/comma-spacing": ["warn", {
before: false,
after: true
}],
"@stylistic/keyword-spacing": ["warn", {
before: true,
after: true
}],
"@stylistic/quotes": [
"warn",
"double",
{
avoidEscape: true,
allowTemplateLiterals: true
}
],
"@stylistic/space-in-parens": ["warn", "never"],
"@stylistic/array-bracket-spacing": ["warn", "never"],
"@stylistic/arrow-spacing": ["warn"],
"@stylistic/eol-last": ["warn", "always"],
"@stylistic/comma-dangle": ["warn", {
arrays: "always-multiline",
objects: "always",
imports: "never",
exports: "always-multiline",
functions: "always-multiline"
}],
"@stylistic/member-delimiter-style": ["warn", {
singleline: {
delimiter: "comma",
requireLast: true
},
multiline: {
delimiter: "comma",
requireLast: true
},
multilineDetection: "brackets"
}],
"@stylistic/key-spacing": ["warn", {
singleLine: {
beforeColon: false,
afterColon: true
},
multiLine: {
beforeColon: false,
afterColon: true
},
align: {
beforeColon: false,
afterColon: true,
on: "value"
}
}]
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://typescript-eslint.io/rules/?=recommended-xtypeInformation
*/
function typeScript_filteredBy_recommended() {
return entreeDefineRules({
"@typescript-eslint/ban-ts-comment": ["error", {
"ts-expect-error": "allow-with-description",
"ts-ignore": "allow-with-description",
"ts-nocheck": "allow-with-description",
"ts-check": false
}],
"@typescript-eslint/no-empty-object-type": ["error", {
allowInterfaces: "never",
allowObjectTypes: "never"
}],
"@typescript-eslint/no-unsafe-function-type": ["error"],
"@typescript-eslint/no-wrapper-object-types": ["error"],
"@typescript-eslint/no-duplicate-enum-values": ["error"],
"no-loss-of-precision": ["off"],
"@typescript-eslint/no-loss-of-precision": ["error"],
"@typescript-eslint/no-misused-new": ["error"],
"@typescript-eslint/no-namespace": ["warn", {
allowDeclarations: false,
allowDefinitionFiles: true
}],
"@typescript-eslint/no-unnecessary-type-constraint": ["error"],
"@typescript-eslint/no-unsafe-declaration-merging": ["error"],
"@typescript-eslint/prefer-as-const": ["error"]
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://typescript-eslint.io/rules/?=stylistic-xtypeInformation
*/
function typeScript_filteredBy_tsStylistic() {
return entreeDefineRules({
"@typescript-eslint/consistent-type-assertions": ["warn", {
assertionStyle: "as",
objectLiteralTypeAssertions: "allow-as-parameter"
}],
"@typescript-eslint/no-confusing-non-null-assertion": ["warn"]
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://typescript-eslint.io/rules/?=xrecommended-strict-xstylistic-xtypeInformation
*/
function typeScript_filteredBy_strict() {
return entreeDefineRules({
"@typescript-eslint/no-invalid-void-type": ["warn", {
allowInGenericTypeArguments: true,
allowAsThisParameter: true
}],
"@typescript-eslint/no-non-null-assertion": ["error"],
"@typescript-eslint/prefer-ts-expect-error": ["error"]
});
}
/**
* You may want to use the full set of rules provided by `typeScript()`: {@link typeScript}
*
* Subset selected from https://typescript-eslint.io/rules/?=xrecommended-xstrict-xstylistic-xtypeInformation-xdeprecated
*/
function typeScript_filteredBy_miscellaneous() {
return entreeDefineRules({
"@typescript-eslint/no-import-type-side-effects": ["warn"],
"no-unused-expressions": ["off"],
"@typescript-eslint/no-unused-expressions": ["warn", {
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true
}],
"@typescript-eslint/no-useless-empty-export": ["error"]
});
}
//#endregion
//#region src/eslint-sample-js/rules-vue3.entree.js
var rules_vue3_entree_exports = /* @__PURE__ */ __export({
vue3: () => vue3,
vue3_base: () => vue3_base,
vue3_essential: () => vue3_essential,
vue3_extension_rules_forTemplateExpressions: () => vue3_extension_rules_forTemplateExpressions,
vue3_recommended: () => vue3_recommended,
vue3_strongly_recommended: () => vue3_strongly_recommended,
vue3_uncategorized: () => vue3_uncategorized
});
/**
* Combines all hand-picked rule collections for Vue 3.
*
* https://eslint.vuejs.org/rules/
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3() {
return entreeDefineRules({
...vue3_base(),
...vue3_essential(),
...vue3_strongly_recommended(),
...vue3_recommended(),
...vue3_uncategorized(),
...vue3_extension_rules_forTemplateExpressions()
});
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#base-rules-enabling-correct-eslint-parsing
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_base() {
return entreeDefineRules({ "vue/comment-directive": ["error"] });
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_essential() {
return entreeDefineRules({
"vue/no-dupe-keys": ["error"],
"vue/no-side-effects-in-computed-properties": ["error"],
"vue/no-ref-as-operand": ["error"],
"vue/no-async-in-computed-properties": ["error"],
"vue/no-child-content": ["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-reserved-keys": ["error"],
"vue/no-reserved-props": ["error"],
"vue/no-template-key": ["error"],
"vue/no-textarea-mustache": ["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-render-return": ["error"],
"vue/require-toggle-inside-transition": ["error"],
"vue/use-v-on-exact": ["error"],
"vue/valid-attribute-name": ["error"],
"vue/valid-define-emits": ["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-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"]
});
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#priority-b-strongly-recommended-improving-readability
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_strongly_recommended() {
return entreeDefineRules({
"vue/attribute-hyphenation": ["warn"],
"vue/html-closing-bracket-spacing": ["warn"],
"vue/html-self-closing": ["warn", {
html: {
void: "never",
normal: "never",
component: "any"
},
svg: "any",
math: "any"
}],
"vue/html-quotes": [
"warn",
"double",
{ avoidEscape: true }
],
"vue/mustache-interpolation-spacing": ["warn", "always"],
"vue/no-multi-spaces": ["warn", { ignoreProperties: true }],
"vue/no-spaces-around-equal-signs-in-attribute": ["warn"],
"vue/no-template-shadow": ["warn"],
"vue/v-bind-style": ["warn", "shorthand"],
"vue/v-on-event-hyphenation": [
"warn",
"always",
{ autofix: true }
],
"vue/v-on-style": ["warn", "shorthand"],
"vue/v-slot-style": ["warn", {
atComponent: "shorthand",
default: "shorthand",
named: "shorthand"
}]
});
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#priority-c-recommended-potentially-dangerous-patterns
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_recommended() {
return entreeDefineRules({
"vue/attributes-order": ["warn", {
order: [
"DEFINITION",
"SLOT",
"LIST_RENDERING",
"CONDITIONALS",
"RENDER_MODIFIERS",
"UNIQUE",
"GLOBAL",
"OTHER_DIRECTIVES",
"ATTR_SHORTHAND_BOOL",
"ATTR_STATIC",
"TWO_WAY_BINDING",
"ATTR_DYNAMIC",
"EVENTS",
"CONTENT"
],
alphabetical: false
}],
"vue/no-lone-template": ["warn", { ignoreAccessible: true }],
"vue/no-multiple-slot-args": ["warn"],
"vue/no-v-html": ["warn"]
});
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#uncategorized
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_uncategorized() {
const globalComponents = ["RouterView", "RouterLink"];
return entreeDefineRules({
"vue/block-order": ["warn", { order: [
"template",
"script:not([setup])",
"script[setup]",
"style[scoped]",
"style:not([scoped])"
] }],
"vue/no-duplicate-attr-inheritance": ["error"],
"vue/no-required-prop-with-default": ["warn", { autofix: true }],
"vue/no-restricted-v-bind": ["error", {
argument: "/^v-/",
message: "Using `:v-xxx` is not allowed. Instead, remove `:` and use it as directive."
}],
"vue/no-undef-components": ["error", { ignorePatterns: [...globalComponents] }],
"vue/no-unused-refs": ["error"],
"vue/padding-line-between-blocks": ["warn", "always"],
"vue/prefer-define-options": ["warn"],
"vue/prefer-separate-static-class": ["warn"],
"vue/require-macro-variable-name": ["error", {
defineProps: "props",
defineEmits: "emit",
defineSlots: "slots",
useSlots: "slots",
useAttrs: "attrs"
}],
"vue/require-typed-ref": ["error"],
"vue/v-for-delimiter-style": ["warn", "in"],
"vue/valid-define-options": ["error"],
"vue/block-lang": ["error", { script: { lang: "ts" } }],
"vue/component-api-style": ["error", ["script-setup"]],
"vue/component-name-in-template-casing": [
"warn",
"PascalCase",
{
registeredComponentsOnly: true,
ignores: [],
globals: [...globalComponents]
}
],
"vue/custom-event-name-casing": [
"warn",
"camelCase",
{ ignores: [] }
],
"vue/define-emits-declaration": ["warn", "type-literal"],
"vue/define-props-declaration": ["warn", "type-based"],
"vue/html-button-has-type": ["warn", {
button: true,
submit: false,
reset: false
}]
});
}
/**
* You may want to use the full set of rules provided by `vue3()`: {@link vue3}
*
* Subset selected from https://eslint.vuejs.org/rules/#extension-rules
*
* All rules checked as of eslint-plugin-vue@9.19.2
*/
function vue3_extension_rules_forTemplateExpressions() {
const { getOptionsOf: getOptionsOf_stylistic } = entreeAdoptOptionsFromRules(typeScript_stylistic());
return entreeDefineRules({
"vue/array-bracket-spacing": getOptionsOf_stylistic("@stylistic/array-bracket-spacing"),
"vue/arrow-spacing": getOptionsOf_stylistic("@stylistic/arrow-spacing"),
"vue/comma-dangle": getOptionsOf_stylistic("@stylistic/comma-dangle"),
"vue/comma-spacing": getOptionsOf_stylistic("@stylistic/comma-spacing"),
"vue/key-spacing": getOptionsOf_stylistic("@stylistic/key-spacing"),
"vue/keyword-spacing": getOptionsOf_stylistic("@stylistic/keyword-spacing"),
"vue/object-curly-spacing": getOptionsOf_stylistic("@stylistic/object-curly-spacing"),
"vue/space-in-parens": getOptionsOf_stylistic("@stylistic/space-in-parens"),
"vue/space-infix-ops": getOptionsOf_stylistic("@stylistic/space-infix-ops")
});
}
//#endregion
//#region src/eslint-sample-js/rules-react.entree.js
var rules_react_entree_exports = /* @__PURE__ */ __export({ react: () => react });
/**
* WIP. For now, only the rules generated by `npm create vite@latest ./ -- --template react-ts` are added.
*/
function react() {
return entreeDefineRules({
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }]
});
}
//#endregion
//#region src/entree-rules.ts
/**
* Every collection of hand-picked rules.
*/
const entreeRules = {
...rules_typescript_entree_exports,
...rules_vue3_entree_exports,
...rules_react_entree_exports
};
//#endregion
export { defineConfig, entreeAdoptOptionsFromRules, entreeConfigs, entreeDefineRules, entreeFilterRules, entreeRules, gitignore };
//# sourceMappingURL=index.js.map