@bfra.me/eslint-config
Version:
Shared ESLint configuration for bfra.me
1,651 lines • 53.2 kB
JavaScript
import {createRequire} from 'node:module';const require=createRequire(import.meta.url);
// src/define-config.ts
import { isPackageExists as isPackageExists3 } from "local-pkg";
// src/compose-config.ts
import { composer } from "eslint-flat-config-utils";
var composeConfig = (...configs) => composer(...configs);
// src/require-of.ts
import { isPackageExists } from "local-pkg";
var packageExistsCache = /* @__PURE__ */ new Map();
var has = (name) => {
if (!packageExistsCache.has(name)) {
packageExistsCache.set(name, isPackageExists(name));
}
return packageExistsCache.get(name);
};
async function requireOf(names, getConfig, fallback2) {
const missingList = names.filter((n) => n !== "" && !has(n));
if (missingList.length) {
return fallback2(missingList);
}
return getConfig();
}
// src/utils.ts
// @__NO_SIDE_EFFECTS__
async function interopDefault(m) {
const resolved = await m;
return typeof resolved === "object" && resolved !== null && "default" in resolved ? /* @__PURE__ */ interopDefault(resolved.default) : resolved;
}
// src/configs/fallback.ts
async function fallback(missingList, options) {
const rules = await interopDefault(import("./missing-module-for-config-YSY2AGPQ.js"));
const pluginName = `@bfra.me${missingList.length > 0 ? `/missing-modules-${missingList.map((m) => m.replaceAll(/[^a-z0-9]/gi, "-").toLowerCase()).join("-")}` : ""}`;
return [
{
plugins: {
[pluginName]: {
rules: {
"missing-module-for-config": rules
}
}
},
rules: {
[`${pluginName}/missing-module-for-config`]: ["error", missingList]
},
...options ?? {}
}
];
}
// src/configs/command.ts
async function command() {
return requireOf(
["eslint-plugin-command"],
async () => {
const config2 = await interopDefault(import("eslint-plugin-command/config"));
return [
{
...config2(),
name: "@bfra.me/command"
}
];
},
fallback
);
}
// src/globs.ts
var GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
var GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
var GLOB_JSX = "**/*.?([cm])jsx";
var GLOB_TS = "**/*.?([cm])ts";
var GLOB_TSX = "**/*.tsx";
var GLOB_JSON = "**/*.json";
var GLOB_JSON5 = "**/*.json5";
var GLOB_JSONC = "**/*.jsonc";
var GLOB_TOML = "**/*.toml";
var GLOB_YAML = "**/*.y?(a)ml";
var GLOB_MARKDOWN = "**/*.md";
var GLOB_MARKDOWN_IN_MARKDOWN = "**/*.md/*.md";
var GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
var GLOB_TESTS = [
`**/__tests__/**/*.${GLOB_SRC_EXT}`,
`**/*.spec.${GLOB_SRC_EXT}`,
`**/*.test.${GLOB_SRC_EXT}`,
`**/*.bench.${GLOB_SRC_EXT}`,
`**/*.benchmark.${GLOB_SRC_EXT}`
];
var GLOB_EXCLUDE = [
"**/node_modules",
"**/dist",
"**/coverage",
"**/out",
"**/temp",
"**/.idea",
"**/.next",
"**/.nuxt",
"**/.output",
"**/.svelte-kit",
"**/.tsup",
"**/.vercel",
"**/.vitepress/cache",
"**/.vite-inspect",
"**/.yarn",
"**/__snapshots__",
"**/test/fixtures",
"**/auto-import?(s).d.ts",
"**/.changeset/*.md",
"**/CHANGELOG*.md",
"**/changelog*.md",
"**/components.d.ts",
"**/devcontainer-lock.json",
"**/LICENSE*",
"**/license*",
"**/*.min.*",
"**/package-lock.json",
"**/pnpm-lock.yaml",
"**/typed-router.d.ts",
"**/yarn.lock",
"**/bun.lockb"
];
// src/configs/epilogue.ts
async function epilogue() {
return [
{
name: "@bfra.me/epilogue/cli",
files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"no-console": "off"
}
},
{
name: "@bfra.me/epilogue/configs",
files: [`**/*.config.${GLOB_SRC_EXT}`, `**/*.config.*.${GLOB_SRC_EXT}`],
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"no-console": "off"
}
},
{
name: "@bfra.me/epilogue/scripts",
files: [`**/scripts/${GLOB_SRC}`],
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"no-console": "off"
}
},
{
name: "@bfra.me/epilogue/commonjs",
files: ["**/*.js", "**/*.cjs"],
rules: {
"@typescript-eslint/no-require-imports": "off"
}
},
{
name: "@bfra.me/epilogue/dts",
files: ["**/*.d.?([cm])ts"],
rules: {
"eslint-comments/no-unlimited-disable": "off",
"import-x/no-duplicates": "off",
"no-restricted-syntax": "off",
"unused-imports/no-unused-vars": "off"
}
},
{
name: "@bfra.me/epilogue"
}
];
}
// src/configs/eslint-comments.ts
import pluginEslintComments from "@eslint-community/eslint-plugin-eslint-comments";
function eslintComments() {
return [
{
name: "@bfra.me/eslint-comments/rules",
plugins: { "eslint-comments": pluginEslintComments },
rules: {
"eslint-comments/disable-enable-pair": ["error", { allowWholeFile: true }],
"eslint-comments/no-aggregating-enable": "error",
"eslint-comments/no-duplicate-disable": "error",
"eslint-comments/no-unlimited-disable": "error",
"eslint-comments/no-unused-disable": "error",
"eslint-comments/no-unused-enable": "error"
}
}
];
}
// src/configs/ignores.ts
async function ignores(ignores2 = []) {
return [
{
name: "@bfra.me/ignores",
ignores: [...GLOB_EXCLUDE, ...ignores2]
}
];
}
// src/configs/imports.ts
async function imports() {
return requireOf(
["eslint-plugin-import-x"],
async () => {
const pluginImportX = await interopDefault(import("eslint-plugin-import-x"));
return [
{
name: "@bfra.me/imports",
plugins: {
"import-x": pluginImportX
},
rules: {
"import-x/no-named-default": "error",
"import-x/first": "error",
"import-x/no-duplicates": "error",
"import-x/no-mutable-exports": "error",
"import-x/no-self-import": "error",
"import-x/no-useless-path-segments": "error",
"import-x/no-webpack-loader-syntax": "error"
}
}
];
},
fallback
);
}
// src/configs/javascript.ts
import globals from "globals";
async function javascript(options = {}) {
const { isInEditor: isInEditor2 = false, jsx = true, overrides = {} } = options;
return requireOf(
["eslint-plugin-unused-imports"],
async () => {
const pluginUnusedImports = await interopDefault(import("eslint-plugin-unused-imports"));
return [
{
name: "@bfra.me/javascript/options",
languageOptions: {
ecmaVersion: 2022,
globals: {
...globals.browser,
...globals.es2021,
...globals.node
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 2022,
sourceType: "module"
},
sourceType: "module"
},
linterOptions: {
reportUnusedDisableDirectives: true
}
},
{
name: "@bfra.me/javascript/rules",
plugins: {
"unused-imports": pluginUnusedImports
},
rules: {
"no-shadow-restricted-names": "error",
"no-useless-rename": "error",
"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",
eqeqeq: ["error", "smart"],
"new-cap": ["error", { capIsNew: false, newIsCap: true, properties: true }],
"no-alert": "error",
"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": ["warn", { 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-duplicate-imports": ["error", { allowSeparateTypeImports: true }],
"no-empty": ["error", { allowEmptyCatch: true }],
"no-empty-character-class": "error",
"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": ["warn", { commentPattern: String.raw`break[\s\w]*omitted` }],
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-import-assign": "error",
"no-inner-declarations": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-labels": ["error", { allowLoop: false, allowSwitch: false }],
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-multi-str": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-native-nonconstructor": "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",
{ name: "global", message: "Use `globalThis` instead." },
{ name: "self", message: "Use `globalThis` instead." }
],
"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",
"TSEnumDeclaration[const=true]",
"TSExportAssignment",
"ForInStatement",
"LabeledStatement",
"WithStatement"
],
"no-self-assign": ["error", { props: true }],
"no-self-compare": "error",
"no-sequences": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-undef": "error",
"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-unused-expressions": [
"error",
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}
],
"no-unused-vars": [
"error",
{
args: "none",
caughtErrors: "none",
ignoreRestSiblings: true,
vars: "all"
}
],
"no-use-before-define": ["error", { classes: false, functions: false, variables: true }],
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-return": "error",
"no-var": "error",
"no-void": "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-spread": "error",
"prefer-template": "error",
"symbol-description": "error",
"unicode-bom": ["error", "never"],
"unused-imports/no-unused-imports": isInEditor2 ? "off" : "error",
"unused-imports/no-unused-vars": [
"error",
{
args: "after-used",
argsIgnorePattern: "^_",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^_"
}
],
"use-isnan": ["error", { enforceForIndexOf: true, enforceForSwitchCase: true }],
"valid-typeof": ["error", { requireStringLiterals: true }],
"vars-on-top": "error",
...overrides
}
},
...jsx ? [
{
name: "@bfra.me/jsx",
files: [GLOB_JSX, GLOB_TSX],
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
}
}
] : []
];
},
fallback
);
}
// src/configs/jsdoc.ts
async function jsdoc() {
return requireOf(
["eslint-plugin-jsdoc"],
async () => [
{
name: "@bfra.me/jsdoc",
plugins: { jsdoc: await interopDefault(import("eslint-plugin-jsdoc")) },
rules: {
"jsdoc/check-param-names": "warn",
"jsdoc/check-property-names": "warn",
"jsdoc/require-param-name": "warn",
"jsdoc/require-property-name": "warn",
"jsdoc/check-access": "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-property": "warn",
"jsdoc/require-property-description": "warn",
"jsdoc/require-returns-check": "warn",
"jsdoc/require-returns-description": "warn",
"jsdoc/require-yields-check": "warn"
}
}
],
fallback
);
}
// src/parsers/any-parser.ts
import { fileURLToPath } from "url";
// package.json
var version = "0.26.0";
// src/parsers/any-parser.ts
var lineBreakPattern = /\r\n|[\n\r\u2028\u2029]/u;
var meta = {
name: fileURLToPath(import.meta.url),
version
};
function parseForESLint(text) {
const lines = text.split(lineBreakPattern);
return {
ast: {
body: [],
comments: [],
loc: {
end: {
column: lines.at(-1)?.length ?? 0,
line: lines.length
},
start: {
column: 0,
line: 1
}
},
range: [0, text.length],
sourceType: "module",
tokens: [],
type: "Program"
}
};
}
var anyParser = { meta, parseForESLint };
// src/configs/json-schema.ts
async function jsonSchema(name, files) {
return requireOf(
["eslint-plugin-json-schema-validator"],
async () => {
const pluginJsonSchemaValidator = await interopDefault(
import("eslint-plugin-json-schema-validator")
);
return [
...pluginJsonSchemaValidator.configs["flat/recommended"].map((config2) => {
if (config2.files == null) {
return { ...config2, files };
}
if (config2.files.flat().some((file) => files.some((suffix) => file.endsWith(suffix)))) {
return config2;
}
return {};
}).filter((o) => Object.keys(o).length > 0).map((config2, index) => ({
...config2,
name: config2.plugins ? `@bfra.me/${name}/json-schema/plugins` : `@bfra.me/${name}/json-schema/${(config2.name ?? "") || `unnamed${index}`}`
})),
{
name: `@bfra.me/${name}/json-schema`,
files,
rules: {
"json-schema-validator/no-invalid": [
"error",
{
schemas: [
{
fileMatch: [".eslintrc.js"],
schema: "https://json.schemastore.org/eslintrc"
},
{
fileMatch: [".prettierrc.toml"],
schema: "https://json.schemastore.org/prettierrc"
},
{
fileMatch: [
"stylelint.config.js",
"stylelint.config.cjs",
".stylelintrc.js",
".stylelintrc.yaml",
".stylelintrc.yml"
],
schema: "https://json.schemastore.org/stylelintrc"
}
],
useSchemastoreCatalog: true
}
]
}
}
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: { parser: anyParser }
})
);
}
// src/configs/jsonc.ts
var jsoncFiles = ["*.json", "*.json5", "*.jsonc"].flatMap((p) => [p, `**/${p}`]);
async function jsonc(options = {}) {
const { files = jsoncFiles, overrides = {} } = options;
return requireOf(
["eslint-plugin-jsonc"],
async () => {
const pluginJsonc = await interopDefault(import("eslint-plugin-jsonc"));
return [
...pluginJsonc.configs["flat/base"].map(
(config2, index) => ({
...config2,
name: config2.plugins ? `@bfra.me/jsonc/plugins` : `@bfra.me/${(config2.name ?? "") || `jsonc/unnamed${index}`}`
})
),
...await jsonSchema("jsonc", files),
{
name: "@bfra.me/jsonc",
files,
rules: {
...overrides
}
}
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: { parser: anyParser }
})
);
}
// src/configs/markdown.ts
import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
// src/parsers/plain-parser.ts
import { fileURLToPath as fileURLToPath2 } from "url";
var plainParser = {
meta: {
name: fileURLToPath2(import.meta.url),
version
},
parseForESLint: (code) => ({
ast: {
body: [],
comments: [],
loc: { end: code.length, start: 0 },
range: [0, code.length],
tokens: [],
type: "Program"
},
scopeManager: null,
services: { isPlain: true },
visitorKeys: {
Program: []
}
})
};
// src/configs/markdown.ts
var mdFiles = [`*.md`].flatMap((p) => [p, `**/${p}`]);
var codeInMdFiles = mdFiles.flatMap((p) => [
`${p}/*.js`,
`${p}/*.jsx`,
`${p}/*.cjs`,
`${p}/*.mjs`,
`${p}/*.ts`,
`${p}/*.tsx`,
`${p}/*.cts`,
`${p}/*.mts`
]);
var extInMdFiles = [
...codeInMdFiles,
...mdFiles.flatMap((p) => [
`${p}/*.json`,
`${p}/*.json5`,
`${p}/*.jsonc`,
`${p}/*.toml`,
`${p}/*.yml`,
`${p}/*.yaml`,
`${p}/*.vue`,
`${p}/*.svelte`,
`${p}/*.astro`
])
];
async function markdown(options = {}) {
const { files = [GLOB_MARKDOWN], overrides = {} } = options;
return requireOf(
["@eslint/markdown"],
async () => {
const markdown2 = await interopDefault(import("@eslint/markdown"));
return [
{
name: "@bfra.me/markdown/plugin",
plugins: {
markdown: markdown2
}
},
{
name: "@bfra.me/markdown/processor",
files,
ignores: [GLOB_MARKDOWN_IN_MARKDOWN],
// `eslint-plugin-markdown` only creates virtual files for code blocks,
// but not the markdown file itself. We use `eslint-merge-processors` to
// add a pass-through processor for the markdown file itself.
processor: mergeProcessors([markdown2.processors.markdown, processorPassThrough])
},
{
name: "@bfra.me/markdown/code-blocks",
files,
languageOptions: {
parser: plainParser
}
},
{
name: "@bfra.me/markdown/disabled",
files,
rules: {
"unicorn/filename-case": "off"
}
},
{
name: "@bfra.me/markdown/overrides",
files: [GLOB_MARKDOWN_CODE],
languageOptions: {
parserOptions: {
ecmaFeatures: {
impliedStrict: true
},
// Explicitly disable project for these files to prevent type-aware linting
project: false
}
},
rules: {
// Only disable non-type-aware rules we want to skip for markdown code blocks
"@typescript-eslint/consistent-type-imports": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-redeclare": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-var-requires": "off",
"import-x/newline-after-import": "off",
"jsdoc/require-returns-check": "off",
"no-alert": "off",
"no-console": "off",
"no-labels": "off",
"no-lone-blocks": "off",
"no-restricted-imports": "off",
"no-restricted-syntax": "off",
"no-undef": "off",
"no-unused-expressions": "off",
"no-unused-labels": "off",
"no-unused-vars": "off",
"node/prefer-global/process": "off",
"unicode-bom": "off",
"unused-imports/no-unused-imports": "off",
"unused-imports/no-unused-vars": "off",
...overrides
}
}
];
},
fallback
);
}
// src/configs/node.ts
async function node() {
return requireOf(
["eslint-plugin-n"],
async () => {
const pluginNode = await interopDefault(import("eslint-plugin-n"));
return [
{
name: "@bfra.me/node",
plugins: {
node: pluginNode
},
rules: {
"node/handle-callback-err": ["error", "^(err|error)$"],
"node/no-deprecated-api": "error",
"node/no-exports-assign": "error",
"node/no-new-require": "error",
"node/no-path-concat": "error",
"node/no-unsupported-features/es-builtins": "error",
"node/prefer-global/buffer": ["error", "never"],
"node/prefer-global/process": ["error", "never"],
"node/process-exit-as-throw": "error"
}
}
];
},
fallback
);
}
// src/configs/package-json.ts
var packageJsonFiles = ["package.json", "package.json5", "package.jsonc"].flatMap((file) => [
file,
`**/${file}`
]);
async function packageJson(options = {}) {
const { files = packageJsonFiles } = options;
return requireOf(
["eslint-plugin-node-dependencies"],
async () => {
const pluginNodeDependencies = await interopDefault(import("eslint-plugin-node-dependencies"));
return [
...pluginNodeDependencies.configs["flat/recommended"].map(
(config2, index) => ({
...config2,
name: config2.plugins ? `@bfra.me/package-json/plugins` : `@bfra.me/${(config2.name ?? "") || `package-json/unnamed${index}`}`,
files
})
),
...await jsonSchema("package-json", files)
];
},
async (missingList) => fallback(missingList, {
name: "@bfra.me/package-json/fallback",
files,
languageOptions: { parser: anyParser }
})
);
}
// src/configs/perfectionist.ts
async function perfectionist(options = {}) {
const {
isInEditor: isInEditor2 = false,
overrides = {},
sortExports = true,
sortImports = true,
sortNamedExports = true,
sortNamedImports = true
} = options;
return requireOf(
["eslint-plugin-perfectionist"],
async () => {
const pluginPerfectionist = await interopDefault(import("eslint-plugin-perfectionist"));
return [
{
name: "@bfra.me/perfectionist",
plugins: {
perfectionist: pluginPerfectionist
},
rules: {
...sortNamedExports && {
"perfectionist/sort-named-exports": [
isInEditor2 ? "warn" : "error",
{ groupKind: "values-first", type: "natural" }
]
},
...sortNamedImports && {
"perfectionist/sort-named-imports": [
isInEditor2 ? "warn" : "error",
{ groupKind: "values-first", type: "natural" }
]
},
...sortExports && {
"perfectionist/sort-exports": [isInEditor2 ? "warn" : "error", { type: "natural" }]
},
...sortImports && {
"perfectionist/sort-imports": [
isInEditor2 ? "warn" : "error",
{
groups: [
"type",
["parent-type", "sibling-type", "index-type"],
"builtin",
"external",
["internal", "internal-type"],
["parent", "sibling", "index"],
"object",
"side-effect",
"side-effect-style"
],
internalPattern: ["^[~#]/.*"],
newlinesBetween: "ignore",
type: "natural"
}
]
},
...overrides
}
}
];
},
fallback
);
}
// src/configs/pnpm.ts
async function pnpm() {
return requireOf(
["eslint-plugin-jsonc", "eslint-plugin-pnpm", "eslint-plugin-yml"],
async () => {
const [pluginJsonc, pluginPnpm, pluginYaml] = await Promise.all([
interopDefault(import("eslint-plugin-jsonc")),
interopDefault(import("eslint-plugin-pnpm")),
interopDefault(import("eslint-plugin-yml"))
]);
return [
{
name: "@bfra.me/pnpm/package-json",
files: ["package.json", "**/package.json"],
languageOptions: { parser: pluginJsonc },
plugins: {
pnpm: pluginPnpm
},
rules: {
"pnpm/json-enforce-catalog": "error",
"pnpm/json-prefer-workspace-settings": "error",
"pnpm/json-valid-catalog": "error"
}
},
{
name: "@bfra.me/pnpm/pnpm-workspace-yaml",
files: ["pnpm-workspace.yaml"],
languageOptions: { parser: pluginYaml },
plugins: {
pnpm: pluginPnpm
},
rules: {
"pnpm/yaml-no-duplicate-catalog-item": "error",
"pnpm/yaml-no-unused-catalog-item": "error"
}
}
];
},
fallback
);
}
// src/configs/prettier.ts
import process from "process";
import { isPackageExists as isPackageExists2 } from "local-pkg";
// src/configs/toml.ts
var tomlFiles = ["*.toml"].flatMap((p) => [p, `**/${p}`]);
async function toml(options = {}) {
const { files = tomlFiles, overrides = {} } = options;
return requireOf(
["eslint-plugin-toml"],
async () => {
const pluginToml = await interopDefault(import("eslint-plugin-toml"));
return [
...pluginToml.configs["flat/standard"].map((config2, index) => ({
...config2,
name: config2.plugins ? `@bfra.me/toml/plugins` : `@bfra.me/${(config2.name ?? "") || `toml/unnamed${index}`}`
})),
...await jsonSchema("toml", files),
{
name: "@bfra.me/toml",
files,
rules: {
...overrides
}
}
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: { parser: anyParser }
})
);
}
// src/configs/prettier.ts
async function prettier(options = {}) {
const { isInEditor: isInEditor2, overrides } = options;
return requireOf(
["eslint-config-prettier", "eslint-plugin-prettier", "prettier"],
async () => {
process.env.ESLINT_CONFIG_PRETTIER_NO_DEPRECATED ??= "true";
const [configPrettier, pluginPrettier, pluginJsonc, pluginYaml] = await Promise.all([
interopDefault(import("eslint-config-prettier")),
interopDefault(import("eslint-plugin-prettier")),
isPackageExists2("eslint-plugin-jsonc") ? interopDefault(import("eslint-plugin-jsonc")) : void 0,
isPackageExists2("eslint-plugin-yml") ? interopDefault(import("eslint-plugin-yml")) : void 0
]);
return [
{
name: "@bfra.me/prettier",
plugins: {
prettier: pluginPrettier
},
rules: {
"prettier/prettier": isInEditor2 ? "warn" : "error",
...configPrettier.rules,
...pluginJsonc?.configs.prettier.rules,
"toml/array-bracket-newline": "off",
"toml/array-bracket-spacing": "off",
"toml/array-element-newline": "off",
"toml/indent": "off",
"toml/inline-table-curly-spacing": "off",
"toml/key-spacing": "off",
"toml/table-bracket-spacing": "off",
...pluginYaml?.configs.prettier.rules,
...overrides
}
},
{
name: "@bfra.me/prettier/markdown",
files: mdFiles,
rules: {
"prettier/prettier": [
"error",
{
embeddedLanguageFormatting: "off",
parser: "markdown"
}
]
}
},
{
name: "@bfra.me/prettier/toml",
files: tomlFiles,
rules: {
// TODO: Detect if the TOML plugin for Prettier is installed
// and if so, use the Prettier rules
"prettier/prettier": "off"
}
},
{
name: "@bfra.me/prettier/overrides",
files: extInMdFiles,
rules: {
"prettier/prettier": "off"
}
}
];
},
fallback
);
}
// src/configs/regexp.ts
async function regexp(options = {}) {
return requireOf(
["eslint-plugin-regexp"],
async () => {
const { configs } = await interopDefault(import("eslint-plugin-regexp"));
const config2 = configs["flat/recommended"];
return [
{
...config2,
name: "@bfra.me/regexp",
rules: {
...config2.rules,
...options.overrides
}
}
];
},
fallback
);
}
// src/configs/typescript.ts
import process2 from "process";
var TypeAwareRules = {
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-implied-eval": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unsafe-argument": "error",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
"@typescript-eslint/no-unsafe-return": "error",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-readonly": "error",
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/restrict-template-expressions": "error",
"@typescript-eslint/return-await": ["error", "in-try-catch"],
"@typescript-eslint/strict-boolean-expressions": [
"error",
{ allowNullableBoolean: true, allowNullableObject: true }
],
"@typescript-eslint/switch-exhaustiveness-check": "error",
"@typescript-eslint/unbound-method": "error",
"dot-notation": "off",
"no-implied-eval": "off"
};
async function typescript(options = {}) {
const { overrides = {}, parserOptions = {}, typeAware = { overrides: {} } } = options;
const files = options.files ?? [GLOB_TS, GLOB_TSX];
const typeAwareFiles = typeAware.files ?? [GLOB_TS, GLOB_TSX];
const typeAwareIgnores = typeAware.ignores ?? [`${GLOB_MARKDOWN}/**`, "**/*.astro/*.ts"];
const tsconfigPath = options.tsconfigPath ?? void 0;
const isTypeAware = Boolean(tsconfigPath);
return requireOf(
["typescript-eslint"],
async () => {
const tselint = await interopDefault(import("typescript-eslint"));
const generateTsConfig = (kind, files2, ignores2) => ({
name: `@bfra.me/typescript/${kind === "type-aware" ? "type-aware-" : ""}parser`,
files: files2,
...ignores2 ? { ignores: ignores2 } : {},
languageOptions: {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
parser: tselint.parser,
parserOptions: {
sourceType: "module",
...kind === "type-aware" ? {
projectService: {
allowDefaultProject: ["./*.js"],
defaultProject: tsconfigPath
},
tsconfigRootDir: process2.cwd()
} : {},
...parserOptions
}
}
});
return [
{
name: "@bfra.me/typescript/plugins",
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
plugins: { "@typescript-eslint": tselint.plugin }
},
...isTypeAware ? [
generateTsConfig("default", files, typeAwareFiles),
generateTsConfig("type-aware", typeAwareFiles, typeAwareIgnores)
] : [generateTsConfig("default", files)],
{
name: "@bfra.me/typescript/rules",
files,
rules: {
...tselint.configs.eslintRecommended.rules,
...tselint.configs.strict.map((config2) => config2.rules).reduce((acc, rules) => ({ ...acc, ...rules }), {}),
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/ban-ts-comment": [
"error",
{ "ts-expect-error": "allow-with-description" }
],
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/consistent-type-definitions": ["error", "interface"],
"@typescript-eslint/consistent-type-imports": [
"error",
{ disallowTypeAnnotations: false, fixStyle: "inline-type-imports" }
],
"@typescript-eslint/explicit-function-return-type": [
"error",
{
allowExpressions: true,
allowFunctionsWithoutTypeParameters: true,
allowHigherOrderFunctions: true,
allowIIFEs: true
}
],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
accessibility: "no-public"
}
],
"@typescript-eslint/member-ordering": [
"error",
{
default: [
"signature",
"public-static-field",
"protected-static-field",
"private-static-field",
"public-instance-field",
"protected-instance-field",
"private-instance-field",
"public-constructor",
"protected-constructor",
"private-constructor",
"public-static-method",
"protected-static-method",
"private-static-method",
"public-instance-method",
"protected-instance-method",
"private-instance-method"
]
}
],
"@typescript-eslint/method-signature-style": ["error", "property"],
"@typescript-eslint/naming-convention": [
"error",
{
format: ["camelCase", "PascalCase", "UPPER_CASE"],
selector: "variableLike"
},
{
format: ["PascalCase"],
selector: "typeLike"
},
{
format: ["camelCase"],
leadingUnderscore: "allow",
selector: "parameter"
},
{
format: ["PascalCase"],
selector: "class"
},
{
custom: {
match: false,
regex: "^I[A-Z]"
},
format: ["PascalCase"],
selector: "interface"
}
],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-dupe-class-members": "error",
"@typescript-eslint/no-dynamic-delete": "off",
"@typescript-eslint/no-empty-object-type": ["error", { allowInterfaces: "always" }],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-invalid-this": "error",
"@typescript-eslint/no-invalid-void-type": "off",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-redeclare": ["error", { builtinGlobals: false }],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/no-unused-expressions": [
"error",
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}
],
// This is reported by `unused-imports/no-unused-vars`
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-use-before-define": [
"error",
{ classes: false, functions: false, variables: true }
],
"@typescript-eslint/no-useless-constructor": "off",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/triple-slash-reference": "off",
"@typescript-eslint/unified-signatures": "off",
"no-dupe-class-members": "off",
"no-invalid-this": "off",
"no-redeclare": "off",
"no-use-before-define": "off",
"no-useless-constructor": "off",
...overrides
}
},
...isTypeAware ? [
{
name: "@bfra.me/typescript/type-aware-rules",
files: typeAwareFiles,
ignores: typeAwareIgnores,
rules: { ...TypeAwareRules, ...typeAware?.overrides }
}
] : []
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: {
parser: anyParser
}
})
);
}
// src/configs/unicorn.ts
async function unicorn(options = {}) {
const { overrides = {} } = options;
return requireOf(
["eslint-plugin-unicorn"],
async () => {
const pluginUnicorn = await interopDefault(import("eslint-plugin-unicorn"));
return [
{
name: "@bfra.me/unicorn",
plugins: {
unicorn: pluginUnicorn
},
rules: {
"unicorn/catch-error-name": "error",
"unicorn/filename-case": [
"error",
{
cases: { kebabCase: true, pascalCase: true },
ignore: [/^[A-Z]+\..*$/, /import_map\.json/]
}
],
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-existence-index-check": "error",
"unicorn/consistent-function-scoping": ["error", { checkArrowFunctions: false }],
"unicorn/error-message": "error",
"unicorn/escape-case": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-array-method-this-argument": "error",
"unicorn/no-array-push-push": "error",
"unicorn/no-await-in-promise-methods": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-for-loop": "error",
"unicorn/no-hex-escape": "error",
"unicorn/no-instanceof-array": "error",
"unicorn/no-invalid-remove-event-listener": "error",
"unicorn/no-lonely-if": "error",
"unicorn/no-negated-condition": "error",
"unicorn/no-negation-in-equality-check": "error",
"unicorn/no-new-array": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-single-promise-in-promise-methods": "error",
"unicorn/no-static-only-class": "error",
"unicorn/no-typeof-undefined": "error",
"unicorn/no-unnecessary-await": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/number-literal-case": "error",
"unicorn/prefer-add-event-listener": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn/prefer-blob-reading-methods": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-dom-node-dataset": "error",
"unicorn/prefer-dom-node-remove": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-math-trunc": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-modern-math-apis": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-query-selector": "error",
"unicorn/prefer-reflect-apply": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-string-raw": "error",
"unicorn/prefer-string-replace-all": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-string-trim-start-end": "error",
"unicorn/prefer-type-error": "error",
"unicorn/throw-new-error": "error",
...overrides
}
}
];
},
fallback
);
}
// src/configs/vitest.ts
async function vitest(options = {}) {
const { files = GLOB_TESTS, isInEditor: isInEditor2 = false, overrides = {} } = options;
return requireOf(
["@vitest/eslint-plugin"],
async () => {
const vitest2 = await interopDefault(import("@vitest/eslint-plugin"));
return [
{
name: "@bfra.me/vitest/plugins",
plugins: {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
vitest: vitest2
},
settings: {
vitest: {
typecheck: true
}
}
},
{
...vitest2.configs?.env ?? {},
name: "@bfra.me/vitest",
files,
rules: {
...vitest2.configs?.recommended.rules ?? {},
"vitest/consistent-test-it": ["error", { fn: "it", withinDescribe: "it" }],
"vitest/no-focused-tests": isInEditor2 ? "off" : ["error", { fixable: true }],
"vitest/no-import-node-test": "error",
"vitest/prefer-hooks-in-order": "error",
"vitest/prefer-lowercase-title": "error",
// @ts-expect-error - @vitest/eslint-plugin types are incorrect
"vitest/valid-title": ["error", { allowArguments: true }],
// Disabled rules
...{
"@typescript-eslint/explicit-function-return-type": "off",
"no-unused-expressions": "off",
"node/prefer-global/process": "off"
},
...overrides
}
}
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: {
parser: anyParser
}
})
);
}
// src/configs/yaml.ts
var yamlFiles = ["*.yaml", "*.yml"].flatMap((p) => [p, `**/${p}`]);
async function yaml(options = {}) {
const { files = yamlFiles, overrides = {} } = options;
return requireOf(
["eslint-plugin-yml"],
async () => {
const pluginYaml = await interopDefault(import("eslint-plugin-yml"));
return [
...pluginYaml.configs["flat/standard"].map((config2, index) => ({
...config2,
name: config2.plugins ? `@bfra.me/yaml/plugins` : `@bfra.me/${(config2.name ?? "") || `yaml/unnamed${index}`}`
})),
...await jsonSchema("yaml", files),
{
name: "@bfra.me/yaml",
files,
rules: {
"yml/no-empty-mapping-value": "off",
...overrides
}
}
];
},
async (missingList) => fallback(missingList, {
files,
languageOptions: { parser: anyParser }
})
);
}
// src/env.ts
import { env } from "process";
import isInCI from "is-in-ci";
var isInGitLifecycle = !!(typeof env.GIT_PARAMS === "string" && env.GIT_PARAMS.length > 0 || typeof env.VSCODE_GIT_COMMAND === "string" && env.VSCODE_GIT_COMMAND.length > 0 || env.npm_lifecycle_script?.startsWith("lint-staged"));
var isInEditor = !isInCI && !isInGitLifecycle && Boolean(
typeof env.VSCODE_PID === "string" && env.VSCODE_PID.length > 0 || typeof env.VSCODE_CWD === "string" && env.VSCODE_CWD.length > 0 || typeof env.JETBRAINS_IDE === "string" && env.JETBRAINS_IDE.length > 0 || typeof env.VIM === "string" && env.VIM.length > 0 || typeof env.NVIM === "string" && env.NVIM.length > 0
);
// src/define-config.ts
var AllowedConfigPropertiesForOptions = [
"name",
"ignores",
"language",
"languageOptions",
"linterOptions",
"plugins",
"processor",
"rules",
"settings"
];
async function defineConfig(options = {}, ...userConfigs) {
const {
gitignore: enableGitignore = true,
jsx: enableJsx = true,
packageJson: enablePackageJson = false,
perfectionist: enablePerfectionist = true,
pnpm: enableCatalogs = false,
prettier: enablePrettier = isPackageExists3("prettier"),
regexp: enableRegexp = true,
typescript: enableTypeScript = isPackageExists3("typescript"),
unicorn: enableUnicorn = true
} = options;
const isInEditor2 = options.isInEditor ?? isInEditor;
if (isInEditor2)
console.log(
"[@bfra.me/eslint-config] Editor specific config is enabled. Some rules may be disabled."
);
const configs = [];
if (enableGitignore) {
const gitignoreOptions = enableGitignore === true ? { strict: false } : enableGitignore;
configs.push(
interopDefault(import("eslint-config-flat-gitignore")).then((ignore) => [
ignore({
name: "@bfra.me/gitignore",
...gitignoreOptions
})
])
);
}
configs.push(
ignores(options.ignores),
javascript({ isInEditor: isInEditor2, jsx: enableJsx, overrides: getOverrides(options, "javascript") }),
eslintComments(),
node(),
jsdoc(),
imports(),
command()
);
if (enablePackageJson) {
configs.push(packageJson(resolveSubOptions(options, "packageJson")));
}
if (enablePerfectionist) {
configs.push(
perfectionist({
isInEditor: isInEditor2,
overrides: getOverrides(options, "perfectionist"),
...resolveSubOptions(options, "perfectionist")
})
);
}
if (enableUnicorn) {
configs.push(unicorn({ overrides: getOverrides(options, "unicorn") }));
}
const typescriptOptions = resolveSubOptions(options, "typescript");
if (enableTypeScript) {
configs.push(
typescript({
...typescriptOptions,
overrides: getOverrides(options, "typescript")
})
);
}
if (enableRegexp) {
configs.push(regexp({ overrides: getOverrides(options, "regexp") }));
}
if (options.vitest) {
configs.push(
vitest({
overrides: getOverrides(options, "vitest")
})
);
}
if (options.jsonc ?? true) {
configs.push(jsonc({ overrides: getOverrides(options, "jsonc") }));
}
if (enableCatalogs) {
configs.push(pnpm());
}
if (options.toml ?? true) {
configs.push(
toml({
overrides: getOverrides(options, "toml")
})
);
}
if (options.yaml ?? true) {
configs.push(
yaml({
overrides: getOverrides(options, "yaml")
})
);
}
if (options.markdown ?? true) {
configs.push(
markdown({
overrides: getOverrides(options, "markdown")
})
);
}
if (enablePrettier) {
configs.push(
prettier({
isInEditor: isInEditor2,
overrides: getOverrides(options, "prettier")
})
);
}
configs.push(epilogue());
const optionsConfig = AllowedConfigPropertiesForOptions.reduce(
(config2, key) => ({
...config2,
...key in options ? { [key]: options[key] } : {}
}),
{}
);
if (Object.keys(optionsConfig).length) {
configs.push([optionsConfig]);
}
return composeConfig(...configs, ...userConfigs);
}
function resolveSubOptions(options, key) {
return typeof options[key] === "boolean" ? {} : options[key] ?? {};
}
function getOverrides(options, key) {
const sub = resolveSubOptions(options, key);
return "overrides" in sub ? sub.overrides : {};
}
// src/index.ts
var config = defineConfig();
var index_default = config;
export {
GLOB_EXCLUDE,
GLOB_JSON,
GLOB_JSON5,
GLOB_JSONC,
GLOB_JSX,
GLOB_MARKDOWN,
GLOB_MARKDOWN_CODE,
GLOB_MARKDOWN_IN_MARKDOWN,
GLOB_SRC,
GLOB_SRC_EXT,
GLOB_TESTS,
GLOB_TOML,
GLOB_TS,
GLOB_TSX,
GLOB_YAML,
codeInMdFiles,
command,
composeConfig,
config,
index_default as default,
defineConfig,
epilogue,
eslintComments,
extInMdFiles,
fallback,
ignores,
imports,
isInEditor,
isInGitLifecycle,
javascript,
jsdoc,
jsonc,
jsoncFiles,
markdown,
mdFiles,
node,
packageJson,
packageJsonFiles,
perfectionist,
pnpm,
prettier,
regexp,
toml,
tomlFiles,
typescript,
unicorn,
vitest,
yaml,
yamlFiles
};
//# sourceMappingURL=index.js.map