Update rules
This commit is contained in:
@ -12,10 +12,10 @@
|
||||
"subject": "chore(deps): update dependency node to v18.20.4 (#309)"
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"hash": "cca288b73a39fa0932a57c02a7a88de68fc971fc",
|
||||
"date": "2024-07-22T02:39:43+01:00",
|
||||
"hash": "a08fbcc502d6a6fa7d01a48c5f0b895c61e8cdd5",
|
||||
"date": "2024-08-22T20:21:57+01:00",
|
||||
"committer": "Jordan Harband",
|
||||
"subject": "[readme] fix typo in shareable config section in readme"
|
||||
"subject": "[Fix] `label-has-associated-control`: ignore undetermined label text"
|
||||
},
|
||||
"eslint-plugin-n": {
|
||||
"hash": "e5e758ea0cd238220127ae7bcbd967f1d8920f28",
|
||||
|
@ -1,8 +1,9 @@
|
||||
import type { Rule } from 'eslint';
|
||||
import type { ESLintUtils } from '@typescript-eslint/utils';
|
||||
import type { Rule } from 'eslint';
|
||||
|
||||
import noEmptyObjectLiteral from './no-empty-object-literal';
|
||||
import noImportDot from './no-import-dot';
|
||||
import noUselessImportAlias from './no-useless-import-alias';
|
||||
import restrictTemplateExpressions from './restrict-template-expressions';
|
||||
|
||||
export const rules: Record<
|
||||
@ -11,5 +12,6 @@ export const rules: Record<
|
||||
> = {
|
||||
'no-empty-object-literal': noEmptyObjectLiteral,
|
||||
'no-import-dot': noImportDot,
|
||||
'no-useless-import-alias': noUselessImportAlias,
|
||||
'restrict-template-expressions': restrictTemplateExpressions,
|
||||
};
|
||||
|
45
src/custom/no-useless-import-alias.ts
Normal file
45
src/custom/no-useless-import-alias.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import type { Rule } from 'eslint';
|
||||
import type { Position } from 'estree';
|
||||
|
||||
const rule: Rule.RuleModule = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
"Ban useless import aliasing like `import { abc as abc } from 'module'`",
|
||||
category: 'Best Practices',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.specifiers.length === 0) return;
|
||||
|
||||
for (const specifier of node.specifiers) {
|
||||
if (specifier.type !== 'ImportSpecifier') continue;
|
||||
|
||||
const { imported, local } = specifier;
|
||||
if (
|
||||
imported.name === local.name &&
|
||||
!arePositionsEqual(imported.loc!.start, local.loc!.start)
|
||||
) {
|
||||
context.report({
|
||||
node: specifier,
|
||||
message: `Useless aliasing of '${imported.name}'?`,
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([imported.range![1], local.range![1]]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const arePositionsEqual = (a: Position, b: Position) =>
|
||||
a.line === b.line && a.column === b.column;
|
||||
|
||||
export default rule;
|
@ -29,8 +29,6 @@ export default createRule<Option[], MessageId>({
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce template literal expressions to be of `string` type',
|
||||
recommended: 'recommended',
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
messages: {
|
||||
invalidType: 'Invalid type "{{type}}" of template literal expression.',
|
||||
@ -55,6 +53,8 @@ export default createRule<Option[], MessageId>({
|
||||
defaultOptions: [defaultOption],
|
||||
create(context, [options]) {
|
||||
const services = getParserServices(context);
|
||||
if (!services.program) return {};
|
||||
|
||||
const checker = services.program.getTypeChecker();
|
||||
const allowed = new Set(options.allow);
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { resolve } from 'node:path';
|
||||
|
||||
import type { Middleware } from './middleware';
|
||||
import { jsdoc } from './presets/jsdoc';
|
||||
import { reactQuery, storybook } from './presets/misc';
|
||||
import { reactQuery, storybook, vitest } from './presets/misc';
|
||||
import { react, reactRefresh } from './presets/react';
|
||||
import { tailwind } from './presets/tailwind';
|
||||
import { testingLibrary } from './presets/testing-library';
|
||||
@ -16,6 +16,7 @@ const middlewares = {
|
||||
reactQuery,
|
||||
testingLibrary,
|
||||
jsdoc,
|
||||
vitest,
|
||||
};
|
||||
|
||||
export const envs: {
|
||||
@ -29,7 +30,6 @@ export const envs: {
|
||||
},
|
||||
{
|
||||
dependency: '@vitejs/plugin-react',
|
||||
eslintPlugin: 'eslint-plugin-react-refresh',
|
||||
middleware: 'reactRefresh',
|
||||
},
|
||||
{
|
||||
@ -52,6 +52,11 @@ export const envs: {
|
||||
eslintPlugin: 'eslint-plugin-testing-library',
|
||||
middleware: 'testingLibrary',
|
||||
},
|
||||
{
|
||||
dependency: 'vitest',
|
||||
eslintPlugin: 'eslint-plugin-vitest',
|
||||
middleware: 'vitest',
|
||||
},
|
||||
];
|
||||
|
||||
export function getProjectDependencies() {
|
||||
|
@ -50,6 +50,8 @@ export interface LocalRuleOptions {
|
||||
'custom/restrict-template-expressions': RuleEntry<{ allow: string[] }>;
|
||||
/** Ban assignment of empty object literals `{}` and replace them with `Object.create(null)` */
|
||||
'custom/no-empty-object-literal': RuleEntry<unknown>;
|
||||
/** Ban useless import alias */
|
||||
'custom/no-useless-import-alias': RuleEntry<unknown>;
|
||||
}
|
||||
|
||||
export type RuleOptions = Rules & Partial<LocalRuleOptions>;
|
||||
@ -76,6 +78,8 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
|
||||
* Glob pattern to find paths to custom rule files in JavaScript or TypeScript.
|
||||
* Note this must be a string literal or an array of string literals since
|
||||
* this is statically analyzed.
|
||||
*
|
||||
* Rules are prefixed with `custom/` and the file name is used as the rule name.
|
||||
*/
|
||||
customRuleFiles?: string | string[];
|
||||
|
||||
@ -161,7 +165,7 @@ export function extendConfig(
|
||||
{ files: ['repl.ts', 'scripts/**/*.ts'], rules: { 'no-console': off } },
|
||||
...(overrides ?? []),
|
||||
],
|
||||
rules: { ...eslintRules, ...rules },
|
||||
rules: { ...eslintRules },
|
||||
...rest,
|
||||
};
|
||||
|
||||
@ -181,5 +185,7 @@ export function extendConfig(
|
||||
result.plugins = unique(result.plugins);
|
||||
result.extends = unique(result.extends);
|
||||
|
||||
Object.assign(result.rules, rules);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ const transpilers = [
|
||||
function tryRequire() {
|
||||
for (const candidate of transpilers) {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require(candidate);
|
||||
return;
|
||||
} catch {}
|
||||
@ -70,6 +71,7 @@ function main() {
|
||||
if (!isAbsolute(file)) {
|
||||
file = resolve(rootDir, file);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const module = unwrapDefault(require(file));
|
||||
const name = module.name ?? basename(file, extname(file));
|
||||
plugin.rules![name] = module;
|
||||
|
@ -4,9 +4,15 @@ import { defineMiddleware } from '../middleware';
|
||||
|
||||
const customRules: Partial<LocalRuleOptions> = {
|
||||
'custom/no-import-dot': error,
|
||||
'custom/restrict-template-expressions': error,
|
||||
'custom/no-useless-import-alias': error,
|
||||
};
|
||||
|
||||
export const custom = defineMiddleware((_, { addRules }) => {
|
||||
export const custom = defineMiddleware((config, { addRules }) => {
|
||||
addRules(customRules);
|
||||
config.overrides.push({
|
||||
files: ['*.ts', '!*.d.ts'],
|
||||
rules: {
|
||||
'custom/restrict-template-expressions': error,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -7,3 +7,7 @@ export const storybook = defineMiddleware(config => {
|
||||
export const reactQuery = defineMiddleware(config => {
|
||||
config.extends.push('plugin:@tanstack/eslint-plugin-query/recommended');
|
||||
});
|
||||
|
||||
export const vitest = defineMiddleware(config => {
|
||||
config.extends.push('plugin:vitest/recommended');
|
||||
});
|
||||
|
@ -7,22 +7,13 @@ import { defineMiddleware } from '../middleware';
|
||||
const importRules: Partial<ImportXRulesObject> = {
|
||||
'import-x/first': error,
|
||||
'import-x/no-absolute-path': error,
|
||||
'import-x/no-duplicates': error,
|
||||
'import-x/no-duplicates': warn,
|
||||
'import-x/no-useless-path-segments': error,
|
||||
'import-x/order': [
|
||||
error,
|
||||
warn,
|
||||
{
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
'sibling',
|
||||
'index',
|
||||
'object',
|
||||
'type',
|
||||
],
|
||||
'newlines-between': 'always-and-inside-groups',
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object'],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: { order: 'asc', caseInsensitive: true },
|
||||
},
|
||||
],
|
||||
@ -83,18 +74,19 @@ export const importTypeScript = defineMiddleware((config, { addRules, addSetting
|
||||
});
|
||||
config.overrides.push(
|
||||
{
|
||||
files: ['.eslintrc.js', '.eslintrc.cjs', '*.config.js', 'index.js'],
|
||||
files: ['.eslintrc.js', '*.config.js', '*.cjs', '*.mjs'],
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
rules: {
|
||||
'import-x/no-commonjs': off,
|
||||
'import-x/unambiguous': off,
|
||||
'@typescript-eslint/no-require-imports': off,
|
||||
'rules/restrict-template-expressions': off,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.d.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-imports': off,
|
||||
'import-x/unambiguous': off,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable unicorn/string-content */
|
||||
import type { UnicornRulesObject } from '@aet/eslint-define-config/src/rules/unicorn';
|
||||
|
||||
import { error, warn } from '../constants';
|
||||
import { error, off, warn } from '../constants';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
const suggest = (suggest: string) => ({ suggest, fix: false });
|
||||
@ -86,10 +86,13 @@ const unicornRules: Partial<UnicornRulesObject> = {
|
||||
'<=>': suggest('⇔'),
|
||||
'\\.\\.\\.': suggest('…'),
|
||||
"'s ": suggest('’s '),
|
||||
"'d ": suggest('’d '),
|
||||
"'t ": suggest('’t '),
|
||||
"l'": suggest('l’'),
|
||||
"d'": suggest('d’'),
|
||||
'?!': suggest('⁈'),
|
||||
'!?': suggest('⁉'),
|
||||
"qu'": suggest('qu’'),
|
||||
'\\?!': suggest('⁈'),
|
||||
'!\\?': suggest('⁉'),
|
||||
},
|
||||
},
|
||||
],
|
||||
@ -99,4 +102,10 @@ const unicornRules: Partial<UnicornRulesObject> = {
|
||||
export const unicorn = defineMiddleware((config, { addRules }) => {
|
||||
config.plugins.push('unicorn');
|
||||
addRules(unicornRules);
|
||||
config.overrides.push({
|
||||
files: ['*.test.ts', '*.test.tsx'],
|
||||
rules: {
|
||||
'unicorn/no-useless-undefined': off,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user