@rebeccastevens/eslint-config
Version:
My ESLint shareable config.
1,308 lines (1,294 loc) • 166 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var path = require('node:path');
var localPkg = require('local-pkg');
var fs = require('node:fs/promises');
var globals = require('globals');
var semver = require('semver');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
async function interopDefault(value) {
const resolved = await value;
// eslint-disable-next-line ts/no-unsafe-return, ts/no-explicit-any, ts/no-unsafe-member-access
return resolved.default ?? resolved;
}
const parserPlain = {
meta: {
name: "parser-plain",
},
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: [],
},
}),
};
async function loadPackages(packageIds) {
const missing = packageIds.filter((id) => !localPkg.isPackageExists(id));
if (missing.length > 0) {
await installPackages(missing);
}
// eslint-disable-next-line ts/no-explicit-any, ts/no-unsafe-return
return Promise.all(packageIds.map((id) => interopDefault(import(__rewriteRelativeImportExtension(id)))));
}
const mut_installPackagesToLoad = new Set();
let mut_installPackagesAction = null;
let mut_installPackagesActionResolver = null;
let mut_installPackagesTimeout = null;
/* eslint-disable functional/no-loop-statements */
async function installPackages(packages) {
for (const p of packages) {
mut_installPackagesToLoad.add(p);
}
if (mut_installPackagesTimeout !== null) {
clearTimeout(mut_installPackagesTimeout);
}
mut_installPackagesTimeout = setTimeout(() => {
const allPackages = [...mut_installPackagesToLoad.values()];
mut_installPackagesTimeout = null;
mut_installPackagesToLoad.clear();
mut_installPackagesAction = null;
mut_installPackagesActionResolver(allPackages);
mut_installPackagesActionResolver = null;
}, 100);
if (mut_installPackagesAction === null) {
mut_installPackagesAction = new Promise((resolve) => {
mut_installPackagesActionResolver = resolve;
}).then(async (allPackages) => {
const allPackagesString = allPackages.join(", ");
if (Boolean(process.env["CI"]) || !process.stdout.isTTY) {
throw new Error(`Missing packages: ${allPackagesString}`);
}
const prompt = await import('@clack/prompts');
const result = await prompt.confirm({
message: allPackages.length === 1
? `${allPackages[0]} is required for this config. Do you want to install it?`
: `Packages are required for this config: ${allPackagesString}.\nDo you want to install them?`,
});
if (result !== false) {
await import('@antfu/install-pkg').then(({ installPackage }) => installPackage(allPackages, { dev: true }));
}
});
}
return mut_installPackagesAction;
}
/* eslint-enable functional/no-loop-statements */
async function comments() {
const [pluginComments] = (await loadPackages(["eslint-plugin-eslint-comments"]));
return [
{
name: "rs:comments",
plugins: {
comments: pluginComments,
},
rules: {
"comments/no-aggregating-enable": "error",
"comments/no-duplicate-disable": "error",
"comments/no-unlimited-disable": "error",
"comments/no-unused-enable": "error",
"comments/disable-enable-pair": ["error", { allowWholeFile: true }],
},
},
];
}
const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
const GLOB_SRC = "**/?(.)*.?([cm])[jt]s?(x)";
const GLOB_JS = "**/?(.)*.?([cm])js";
const GLOB_JSX = "**/?(.)*.?([cm])jsx";
const GLOB_TS = "**/?(.)*.?([cm])ts";
const GLOB_TSX = "**/?(.)*.?([cm])tsx";
const GLOB_DTS = "**/?(.)*.d.?([cm])ts";
const GLOB_ROOT_JS = "./?(.)*.?([cm])js";
const GLOB_ROOT_JSX = "./?(.)*.?([cm])jsx";
const GLOB_ROOT_TS = "./?(.)*.?([cm])ts";
const GLOB_ROOT_TSX = "./?(.)*.?([cm])tsx";
const GLOB_ROOT_DTS = "./?(.)*.d.?([cm])ts";
const GLOB_TYPINGS = "typings/**/?(.)*.?([cm])ts";
const GLOB_MJS = "**/?(.)*.mjs";
const GLOB_MTS = "**/?(.)*.mts";
const GLOB_CJS = "**/?(.)*.cjs";
const GLOB_CTS = "**/?(.)*.cts";
// cspell:disable-next-line
const GLOB_STYLE = "**/?(.)*.{c,le,sc,pc,postc}ss";
const GLOB_CSS = "**/?(.)*.css";
const GLOB_POSTCSS = "**/?(.)*.{p,post}css";
const GLOB_LESS = "**/?(.)*.less";
const GLOB_SCSS = "**/?(.)*.scss";
const GLOB_JSON = "**/?(.)*.json";
const GLOB_JSON5 = "**/?(.)*.json5";
const GLOB_JSONC = "**/?(.)*.jsonc";
const GLOB_MARKDOWN = "**/?(.)*.md";
const GLOB_MARKDOWN_IN_MARKDOWN = "**/?(.)*.md/?(.)*.md";
const GLOB_VUE = "**/?(.)*.vue";
const GLOB_YAML = "**/?(.)*.y?(a)ml";
const GLOB_TOML = "**/?(.)*.toml";
const GLOB_HTML = "**/?(.)*.htm?(l)";
const GLOB_GRAPHQL = "**/?(.)*.{g,graph}ql";
const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
const GLOB_TESTS = [
`**/__tests__/**/?(.)*.${GLOB_SRC_EXT}`,
`**/?(.)*.spec.${GLOB_SRC_EXT}`,
`**/?(.)*.test.${GLOB_SRC_EXT}`,
`**/?(.)*.bench.${GLOB_SRC_EXT}`,
`**/?(.)*.benchmark.${GLOB_SRC_EXT}`,
];
const GLOB_ALL_SRC = [
GLOB_SRC,
GLOB_STYLE,
GLOB_JSON,
GLOB_JSON5,
GLOB_JSONC,
GLOB_MARKDOWN,
GLOB_VUE,
GLOB_YAML,
GLOB_HTML,
GLOB_TOML,
GLOB_GRAPHQL,
];
const GLOB_EXCLUDE = [
"**/node_modules",
"**/dist",
"**/lib",
"**/package-lock.json",
"**/yarn.lock",
"**/pnpm-lock.yaml",
"**/bun.lockb",
"**/output",
"**/coverage",
"**/temp",
"**/.temp",
"**/tmp",
"**/.tmp",
"**/.history",
"**/.vitepress/cache",
"**/.nuxt",
"**/.next",
"**/.vercel",
"**/.changeset",
"**/.idea",
"**/.cache",
"**/.output",
"**/.vite-inspect",
"**/.yarn",
"**/CHANGELOG*.md",
"**/?(.)*.min.*",
"**/LICENSE*",
"**/__snapshots__",
"**/auto-import.ts",
"**/auto-import.d.ts",
"**/auto-imports.ts",
"**/auto-imports.d.ts",
"**/components.ts",
"**/components.d.ts",
"**/typegen.ts",
"**/typegen.d.ts",
];
async function formatters(opts, stylistic) {
const options = opts === true
? {
js: true,
ts: true,
dts: false,
json: true,
yaml: true,
css: true,
graphql: true,
html: true,
markdown: true,
slidev: localPkg.isPackageExists("@slidev/cli"),
tailwind: localPkg.isPackageExists("tailwindcss"),
}
: opts;
if (options.slidev !== false && options.slidev !== undefined && options.markdown !== true) {
throw new Error("`slidev` option only works when `markdown` is enabled with `prettier`");
}
const { indent, printWidth, quotes, semi } = stylistic;
const prettierOptions = Object.assign({
endOfLine: "lf",
printWidth: printWidth ?? 120,
semi: semi ?? true,
singleQuote: quotes === "single",
tabWidth: typeof indent === "number" ? indent : 2,
trailingComma: "all",
useTabs: indent === "tab",
}, options.prettierOptions ?? {});
const packages = loadPackages([
"eslint-plugin-format",
"eslint-config-prettier",
"sort-package-json",
"eslint-formatting-reporter",
"prettier",
]);
const prettierPluginTailwindcssPromise = (((options.js !== undefined && options.js) || (options.ts !== undefined && options.ts)) &&
options.tailwind !== undefined &&
options.tailwind
? loadPackages(["prettier-plugin-tailwindcss"])
: [undefined]);
const [[pluginFormat, configPrettier, sortPackageJson, formattingReporter], [prettierPluginTailwindcss]] = await Promise.all([packages, prettierPluginTailwindcssPromise]);
const turnOffRulesForPrettier = {
...Object.fromEntries(Object.entries(configPrettier.rules ?? {}).filter(([, value]) => value === "off")),
// curly: "off",
"no-unexpected-multiline": "off",
// "style/lines-around-comment": "off",
"style/max-len": "off",
"style/no-confusing-arrow": "off",
"style/no-mixed-operators": "off",
"style/no-tabs": "off",
"style/quotes": "off",
// "style/js/lines-around-comment": "off",
// "style/js/max-len": "off",
"style/js/no-confusing-arrow": "off",
"style/js/no-mixed-operators": "off",
"style/js/no-tabs": "off",
"style/js/quotes": "off",
// "style/ts/lines-around-comment": "off",
"style/ts/quotes": "off",
"ts/lines-around-comment": "off",
"ts/quotes": "off",
// "babel/quotes": "off",
// "unicorn/template-indent": "off",
"vue/html-self-closing": "off",
"vue/max-len": "off",
// other
"no-irregular-whitespace": "off",
"yaml/block-sequence-hyphen-indicator-newline": "off",
};
const mut_configs = [
{
name: "rs:formatters:setup",
plugins: {
format: pluginFormat,
},
},
];
if (options.js !== undefined && options.js) {
mut_configs.push({
name: "rs:formatter:javascript",
files: [GLOB_JS, GLOB_JSX],
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "babel",
...(options.tailwind !== undefined && options.tailwind
? {
plugins: [
...(prettierOptions.plugins ?? []),
...(prettierPluginTailwindcss === undefined ? [] : ["prettier-plugin-tailwindcss"]),
],
}
: {}),
},
],
},
});
}
if (options.ts !== undefined && options.ts) {
mut_configs.push({
name: "rs:formatter:typescript",
files: [GLOB_TS, GLOB_TSX],
ignores: options.dts === true ? [] : [GLOB_DTS],
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "typescript",
...(options.tailwind !== undefined && options.tailwind
? {
plugins: [
...(prettierOptions.plugins ?? []),
...(prettierPluginTailwindcss === undefined ? [] : ["prettier-plugin-tailwindcss"]),
],
}
: {}),
},
],
},
});
}
if (options.yaml !== undefined && options.yaml) {
mut_configs.push({
name: "rs:formatter:yaml",
files: [GLOB_YAML],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "yaml",
},
],
},
});
}
if (options.json !== undefined && options.json) {
mut_configs.push({
name: "rs:formatter:json",
files: [GLOB_JSON],
ignores: ["**/package.json"],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "json",
},
],
},
}, {
name: "rs:formatter:jsonc",
files: [GLOB_JSONC],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "jsonc",
},
],
},
}, {
name: "rs:formatter:json5",
files: [GLOB_JSON5],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "json5",
},
],
},
}, {
name: "rs:formatter:packagejson",
files: ["**/package.json"],
languageOptions: {
parser: parserPlain,
},
plugins: {
"package-json": {
meta: {
name: "rs:formatter:packagejson",
},
rules: {
sort: {
meta: {
type: "layout",
fixable: "whitespace",
messages: formattingReporter.messages,
schema: [
{
type: "object",
properties: {
parser: {
type: "string",
required: true,
},
},
additionalProperties: true,
},
],
},
create(context) {
return {
Program() {
if (!("text" in context.sourceCode)) {
return;
}
const sourceCode = context.sourceCode.text;
try {
const formatted = sortPackageJson(sourceCode);
formattingReporter.reportDifferences(context, sourceCode, formatted);
}
catch (error) {
console.error(error);
context.report({
loc: {
start: { line: 1, column: 0 },
end: { line: 1, column: 0 },
},
message: "Failed to format package.json",
});
}
},
};
},
},
},
},
},
rules: {
"package-json/sort": "error",
},
});
}
if (options.css !== undefined && options.css) {
mut_configs.push({
name: "rs:formatter:css",
files: [GLOB_CSS, GLOB_POSTCSS],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "css",
},
],
},
}, {
name: "rs:formatter:scss",
files: [GLOB_SCSS],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "scss",
},
],
},
}, {
name: "rs:formatter:less",
files: [GLOB_LESS],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "less",
},
],
},
});
}
if (options.html !== undefined && options.html) {
mut_configs.push({
name: "rs:formatter:html",
files: ["**/*.html"],
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "html",
},
],
},
});
}
if (options.markdown !== undefined && options.markdown) {
const GLOB_SLIDEV = options.slidev === undefined || options.slidev === false
? []
: options.slidev === true
? ["**/slides.md"]
: (options.slidev.files ?? []);
mut_configs.push({
name: "rs:formatter:markdown",
files: [GLOB_MARKDOWN],
ignores: GLOB_SLIDEV,
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
embeddedLanguageFormatting: "off",
parser: "markdown",
},
],
},
});
if (options.slidev !== undefined && options.slidev !== false) {
mut_configs.push({
name: "rs:formatter:slidev",
files: GLOB_SLIDEV,
languageOptions: {
parser: parserPlain,
},
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
embeddedLanguageFormatting: "off",
parser: "slidev",
plugins: ["prettier-plugin-slidev"],
},
],
},
});
}
}
if (options.graphql !== undefined && options.graphql) {
mut_configs.push({
files: [GLOB_GRAPHQL],
languageOptions: {
parser: parserPlain,
},
name: "rs:formatter:graphql",
rules: {
...turnOffRulesForPrettier,
"format/prettier": [
"error",
{
...prettierOptions,
parser: "graphql",
},
],
},
});
}
return mut_configs;
}
async function functional(options) {
const { mode, overrides, stylistic, filesTypeAware, functionalEnforcement, ignoreNamePattern,
// ignoreTypePattern,
} = options;
const [pluginFunctional] = (await loadPackages(["eslint-plugin-functional"]));
const strictRules = {
"functional/functional-parameters": "error",
"functional/no-throw-statements": "error",
"functional/no-try-statements": "error",
"functional/no-let": "error",
"functional/no-class-inheritance": "error",
"functional/no-this-expressions": "error",
"functional/no-loop-statements": "error",
"functional/immutable-data": "error",
"functional/prefer-immutable-types": "error",
"functional/type-declaration-immutability": "error",
"functional/no-mixed-types": "error",
"functional/no-conditional-statements": [
"error",
{
ignoreCodePattern: ["import.meta.vitest"],
},
],
"functional/no-expression-statements": "error",
"functional/no-return-void": "error",
"functional/prefer-property-signatures": stylistic === false ? "off" : "error",
"functional/prefer-tacit": stylistic === false ? "off" : "warn",
"functional/readonly-type": stylistic === false ? "off" : "error",
};
const recommendedRules = {
"functional/functional-parameters": [
"error",
{
allowRestParameter: true,
enforceParameterCount: false,
},
],
"functional/no-let": [
"error",
{
allowInForLoopInit: true,
ignoreIdentifierPattern: ignoreNamePattern,
},
],
"functional/no-loop-statements": "error",
"functional/no-throw-statements": [
"error",
{
allowToRejectPromises: true,
},
],
"functional/immutable-data": [
"error",
{
ignoreAccessorPattern: ["**.mut_*.**"],
ignoreClasses: "fieldsOnly",
ignoreImmediateMutation: true,
ignoreNonConstDeclarations: true,
},
],
"functional/no-conditional-statements": [
"error",
{
allowReturningBranches: true,
ignoreCodePattern: ["import.meta.vitest"],
},
],
"functional/no-expression-statements": [
"error",
{
ignoreCodePattern: "^assert",
ignoreSelfReturning: true,
ignoreVoid: true,
},
],
"functional/no-return-void": mode === "library" ? "error" : "off",
"ts/prefer-readonly-parameter-types": "off",
"functional/prefer-immutable-types": [
mode === "library" ? "warn" : "off",
{
enforcement: "None",
overrides: [
{
specifiers: [
{
from: "file",
},
{
from: "lib",
},
],
options: {
ignoreInferredTypes: true,
ignoreNamePattern,
parameters: { enforcement: "ReadonlyShallow" },
},
},
],
suggestions: {
ReadonlyShallow: [
[
{
pattern: "^([_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*\\[\\])$",
replace: "readonly $1",
message: "Prepend with readonly.",
},
{
pattern: "^(Array|Map|Set)<(.+)>$",
replace: "Readonly$1<$2>",
message: "Use Readonly$1 instead of $1.",
},
],
[
{
pattern: "^(.+)$",
replace: "Readonly<$1>",
message: "Surround with Readonly.",
},
],
],
ReadonlyDeep: [
[
{
pattern: "^(?:Readonly<(.+)>|(.+))$",
replace: "ReadonlyDeep<$1$2>",
message: "Surround with ReadonlyDeep.",
},
],
],
Immutable: [
[
{
pattern: "^(?:Readonly(?:Deep)?<(.+)>|(.+))$",
replace: "Immutable<$1$2>",
message: "Surround with Immutable.",
},
],
],
},
},
],
"functional/type-declaration-immutability": [
"error",
{
rules: [
{
identifiers: "I?Immutable.+",
immutability: "Immutable",
comparator: "AtLeast",
},
{
identifiers: "I?ReadonlyDeep.+",
immutability: "ReadonlyDeep",
comparator: "AtLeast",
},
{
identifiers: "I?Readonly.+",
immutability: "ReadonlyShallow",
comparator: "AtLeast",
fixer: [
{
pattern: "^([_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*\\[\\])$",
replace: "readonly $1",
},
{
pattern: "^(Array|Map|Set)<(.+)>$",
replace: "Readonly$1<$2>",
},
{
pattern: "^(.+)$",
replace: "Readonly<$1>",
},
],
},
{
identifiers: "I?Mutable.+",
immutability: "Mutable",
comparator: "AtMost",
fixer: [
{
pattern: "^Readonly(Array|Map|Set)<(.+)>$",
replace: "$1<$2>",
},
{
pattern: "^Readonly<(.+)>$",
replace: "$1",
},
],
},
],
},
],
"functional/prefer-property-signatures": stylistic === false ? "off" : "error",
"functional/prefer-tacit": stylistic === false ? "off" : "warn",
"functional/readonly-type": stylistic === false ? "off" : "error",
};
const liteRules = {
...recommendedRules,
"functional/no-conditional-statements": "off",
"functional/no-expression-statements": "off",
"functional/no-return-void": "off",
"functional/prefer-immutable-types": [
mode === "library" ? "warn" : "off",
{
...recommendedRules["functional/prefer-immutable-types"][1],
overrides: [
{
...recommendedRules["functional/prefer-immutable-types"][1].overrides[0],
specifiers: [
{
from: "file",
},
],
},
],
},
],
};
const noneLibraryRules = {
"functional/prefer-immutable-types": liteRules["functional/prefer-immutable-types"],
"functional/type-declaration-immutability": ["warn", liteRules["functional/type-declaration-immutability"][1]],
};
return [
{
name: "rs:functional",
plugins: {
functional: pluginFunctional,
},
settings: {
immutability: {
overrides: [
{ type: "^Readonly<.+>$", to: "ReadonlyShallow" },
{ type: "^ReadonlyDeep<.+>$", to: "ReadonlyDeep" },
{ type: "^Immutable<.+>$", to: "Immutable" },
],
},
},
rules: {
...pluginFunctional.configs.off.rules,
...(functionalEnforcement === "none"
? mode === "library"
? noneLibraryRules
: {}
: functionalEnforcement === "lite"
? liteRules
: functionalEnforcement === "strict"
? strictRules
: recommendedRules),
...overrides,
},
},
{
name: "rs:functional:disable-type-aware",
ignores: filesTypeAware,
rules: pluginFunctional.configs.disableTypeChecked.rules,
},
];
}
async function ignores(options) {
const { ignoreFiles, ignores: ignoresOptions, projectRoot } = options;
const includeIgnoreFile = ignoreFiles.length === 0
? undefined
: await loadPackages(["@eslint/compat"]).then(([p]) => p.includeIgnoreFile);
const [extend, files] = Array.isArray(ignoresOptions)
? [true, ignoresOptions]
: [ignoresOptions.extend, ignoresOptions.files];
const ignoreConfig = {
ignores: extend ? [...GLOB_EXCLUDE, ...files] : [...files],
};
const ignoreFileConfigs = await Promise.all(ignoreFiles.map((file) => {
const filePath = path.resolve(projectRoot, file);
return fs
.access(filePath)
.then(() => includeIgnoreFile(filePath))
.catch(() => {
console.warn(`Ignore file "${filePath}" not found.`);
return null;
});
}));
return [ignoreConfig, ...ignoreFileConfigs.filter((v) => v !== null)];
}
async function imports(options) {
const { stylistic, parserOptions, typescript } = options;
const [pluginImport] = (await loadPackages(typescript
? [
"eslint-plugin-import-x",
"eslint-import-resolver-typescript", // make sure it exists - we only implicitly use it
]
: ["eslint-plugin-import-x"]));
return [
{
name: "rs:imports",
plugins: {
import: pluginImport,
},
settings: {
"import-x/external-module-folders": ["node_modules", "node_modules/@types"],
"import-x/internal-regex": "^(?:#|(?:@|~)\\/).*",
"import-x/extensions": [".ts", ".tsx", ".js", ".jsx"],
"import-x/parsers": {
...(typescript
? {
"@typescript-eslint/parser": [".ts", ".tsx", ".cts", ".mts"],
}
: undefined),
},
"import-x/resolver": {
node: {
extensions: [".ts", ".tsx", ".js", ".jsx"],
},
...(typescript
? {
typescript: {
alwaysTryTypes: true,
projectService: parserOptions.projectService,
},
}
: undefined),
},
},
rules: {
// "import/consistent-type-specifier-style": ["error", "prefer-inline"], -- using ts/consistent-type-imports instead
"import/default": "error",
// "import/dynamic-import-chunkname": "off",
"import/export": "error",
// "import/exports-last": "off",
// "import/extensions": "off",
"import/first": "error",
// "import/group-exports": "off",
// "import/max-dependencies": [
// "off",
// {
// max: 10,
// },
// ],
"import/named": "error",
"import/namespace": [
"error",
{
allowComputed: true,
},
],
"import/no-absolute-path": "error",
"import/no-amd": "error",
// "import/no-anonymous-default-export": "off",
// "import/no-commonjs": "off",
// "import/no-cycle": "off",
// "import/no-default-export": "off",
// "import/no-deprecated": "warn",
"import/no-duplicates": ["error", { "prefer-inline": true }],
// "import/no-dynamic-require": "off",
"import/no-empty-named-blocks": "error",
// "import/no-internal-modules": "off",
"import/no-mutable-exports": "error",
// "import/no-named-as-default": "off",
// "import/no-named-as-default-member": "off",
"import/no-named-default": "error",
// "import/no-named-export": "off",
// "import/no-namespace": "off",
// "import/no-nodejs-modules": "off",
// "import/no-relative-parent-imports": "off",
// "import/no-restricted-paths": "off",
"import/no-self-import": "error",
"import/no-unassigned-import": "error",
// "import/no-unused-modules": "off",
// "import/no-unresolved": "off",
"import/no-useless-path-segments": [
"error",
{
commonjs: true,
noUselessIndex: true,
},
],
"import/no-webpack-loader-syntax": "error",
// "import/prefer-default-export": "off",
// "import/unambiguous": "off",
"import/newline-after-import": [stylistic === false ? "off" : "error", { count: 1 }],
"import/order": [
stylistic === false ? "off" : "error",
{
alphabetize: {
caseInsensitive: false,
order: "asc",
},
groups: ["builtin", "external", "internal", "parent", "sibling", "index"],
"newlines-between": "always",
},
],
},
},
{
files: [GLOB_MJS, GLOB_MTS],
rules: {
"import/no-commonjs": "error",
"import/no-dynamic-require": "error",
},
},
...(typescript
? [
{
files: [GLOB_TS, GLOB_TSX, GLOB_DTS],
rules: {
"import/no-unresolved": "off",
"import/named": "off",
"import/default": "off",
"import/namespace": "off",
"ts/no-import-type-side-effects": "error",
"ts/consistent-type-imports": [
stylistic === false ? "off" : "error",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
disallowTypeAnnotations: false,
},
],
},
},
]
: []),
...(options.mode === "library"
? [
{
files: [GLOB_SRC],
rules: {
// Use non-sloppy imports. See: https://jsr.io/docs/publishing-packages#relative-imports
"import/extensions": [
"error",
"always",
{
checkTypeImports: true,
ignorePackages: true,
},
],
"import/no-useless-path-segments": ["error", { noUselessIndex: false }],
"import/no-extraneous-dependencies": [
"error",
{
bundledDependencies: true,
devDependencies: [
`?(.)*.${GLOB_SRC_EXT}`,
`?(.)config?(s)/**`,
"**/?(.)script?(s)/**",
"**/spec/**",
"**/test?(s)/**",
"**/__mocks__/**",
"**/__tests__/**",
`**/*{.,_}{test,spec}.${GLOB_SRC_EXT}`,
`**/Gruntfile{,.${GLOB_SRC_EXT}`,
`**/gulpfile.${GLOB_SRC_EXT}`,
`**/gulpfile.*.${GLOB_SRC_EXT}`,
`**/jest.config.${GLOB_SRC_EXT}`,
`**/jest.setup.${GLOB_SRC_EXT}`,
`**/karma.conf.${GLOB_SRC_EXT}`,
`**/postcss.config.${GLOB_SRC_EXT}`,
`**/protractor.conf.${GLOB_SRC_EXT}`,
`**/protractor.conf.*.${GLOB_SRC_EXT}`,
`**/rollup.config.${GLOB_SRC_EXT}`,
`**/rollup.config.*.${GLOB_SRC_EXT}`,
`**/tailwind.config.${GLOB_SRC_EXT}`,
`**/tailwind.config.*.${GLOB_SRC_EXT}`,
`**/vite.config.${GLOB_SRC_EXT}`,
`**/vitest.config.${GLOB_SRC_EXT}`,
`**/vue.config.${GLOB_SRC_EXT}`,
`**/webpack.config.${GLOB_SRC_EXT}`,
`**/webpack.config.*.${GLOB_SRC_EXT}`,
],
optionalDependencies: true,
peerDependencies: true,
},
],
},
},
]
: options.mode === "application"
? [
{
files: [GLOB_SRC],
rules: {
"import/no-unassigned-import": [
"error",
{
allow: ["**/*.?(s)css"],
},
],
},
},
]
: []),
];
}
function inEditor() {
return [
{
name: "rs:in-editor",
rules: {
"no-console": "off",
"no-debugger": "off",
"prefer-const": "off",
"sonar/no-all-duplicated-branches": "off",
"sonar/no-collapsible-if": "off",
"sonar/no-collection-size-mischeck": "off",
"sonar/no-duplicated-branches": "off",
"sonar/no-element-overwrite": "off",
"sonar/no-empty-collection": "off",
"sonar/no-extra-arguments": "off",
"sonar/no-gratuitous-expressions": "off",
"sonar/no-identical-conditions": "off",
"sonar/no-identical-expressions": "off",
"sonar/no-identical-functions": "off",
"sonar/no-ignored-return": "off",
"sonar/no-inverted-boolean-check": "off",
"sonar/no-nested-switch": "off",
"sonar/no-nested-template-literals": "off",
"sonar/no-one-iteration-loop": "off",
"sonar/no-redundant-boolean": "off",
"sonar/no-redundant-jump": "off",
"sonar/no-same-line-conditional": "off",
"sonar/no-unused-collection": "off",
"sonar/no-use-of-empty-return-value": "off",
"sonar/no-useless-catch": "off",
"sonar/non-existent-operator": "off",
"sonar/prefer-immediate-return": "off",
"sonar/prefer-object-literal": "off",
"sonar/prefer-single-boolean-return": "off",
"sonar/prefer-while": "off",
"test/no-only-tests": "off",
"unicorn/no-lonely-if": "off",
},
},
];
}
const useNumberIsFinite = "Please use Number.isFinite instead";
const useNumberIsNan = "Please use Number.isNaN instead";
const useObjectDefineProperty = "Please use Object.defineProperty instead.";
function javascript(options) {
const { functionalEnforcement, overrides } = options;
return [
{
name: "rs:javascript",
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,
},
rules: {
"accessor-pairs": "error",
"array-callback-return": "error",
"arrow-body-style": ["error", "as-needed"],
"block-scoped-var": "error",
"class-methods-use-this": "error",
"consistent-return": ["error", { treatUndefinedAsUnspecified: false }],
"constructor-super": "error",
curly: ["error", "all"],
"default-case-last": "error",
"dot-notation": ["error", { allowKeywords: true }],
eqeqeq: ["error", "always", { null: "always" }],
"for-direction": "error",
"func-name-matching": "error",
"func-names": ["error", "as-needed"],
"func-style": ["error", "declaration", { allowArrowFunctions: true }],
"getter-return": "error",
"grouped-accessor-pairs": "error",
"guard-for-in": "error",
"logical-assignment-operators": "error",
"max-depth": ["error", 10],
"new-cap": [
"error",
{
capIsNew: false,
newIsCap: true,
properties: true,
},
],
"no-alert": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-await-in-loop": "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-constant-binary-expression": "error",
// "no-constant-condition": "error",
"no-constructor-return": "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-else-return": ["error", { allowElseIf: false }],
"no-empty-pattern": "error",
"no-empty": ["error", { allowEmptyCatch: true }],
"no-eq-null": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-import-assign": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-this": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": ["error", { allowLoop: true, allowSwitch: true }],
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-multi-assign": "error",
"no-multi-str": "error",
"no-new-func": "error",
"no-object-constructor": "error",
"no-new-native-nonconstructor": "error",
"no-new-wrappers": "error",
"no-new": "error",
"no-obj-calls": "error",
"no-octal-escape": "error",
"no-octal": "error",
"no-promise-executor-return": [
"error",
{
allowVoid: true,
},
],
"no-proto": "error",
"no-prototype-builtins": "error",
"no-redeclare": ["error", { builtinGlobals: false }],
"no-regex-spaces": "error",
"no-restricted-globals": [
"error",
{ name: "event", message: "Use local parameter instead." },
{ name: "global", message: "Use `globalThis` instead." },
{ name: "self", message: "Use `globalThis` instead." },
{ name: "window", message: "Use `globalThis` instead." },
],
"no-restricted-properties": [
"error",
{
property: "__proto__",
message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.",
},
{
property: "__lookupGetter__",
message: "Use `Object.getOwnPropertyDescriptor` instead.",
},
{
property: "__lookupSetter__",
message: "Use `Object.getOwnPropertyDescriptor` instead.",
},
{
object: "arguments",
property: "callee",
message: "arguments.callee is deprecated",
},
{
object: "global",
property: "isFinite",
message: useNumberIsFinite,
},