This commit is contained in:
Alex
2023-11-10 20:29:53 -05:00
parent ee3e7e4203
commit 60b1b8fde3
17 changed files with 539 additions and 128 deletions

View File

@ -1,6 +1,7 @@
#!/bin/bash
./src/build-local-rules.ts
npx dts-bundle-generator "./src/index.ts" -o "./dist/index.d.ts" --project "./tsconfig.build.json" --no-check
# printf "\nimport './types.d';" >> "./dist/index.d.ts"
./esbuild.ts
sed -i '' '/import.*redirect.*;/d' "dist/index.d.ts"

38
dist/index.d.ts vendored
View File

@ -1,10 +1,44 @@
// Generated by dts-bundle-generator v8.1.2
import { ESLintConfig } from 'eslint-define-config';
import { ESLintConfig, Rules } from 'eslint-define-config';
export declare const error = "error";
export declare const warn = "warn";
export declare const off = "off";
export declare function extendConfig({ plugins, settings, rules, extends: _extends, overrides, ...rest }?: ESLintConfig): ESLintConfig;
export type RuleLevel = "error" | "warn" | "off" | 0 | 1 | 2;
export type RuleEntry<Options> = RuleLevel | [
RuleLevel,
Partial<Options>
];
export interface LocalRuleOptions {
/** Bans import from the specifier '.' and '..' and replaces it with '.+/index' */
"rules/no-import-dot": RuleEntry<unknown>;
/**
* Enforce template literal expressions to be of `string` type
* @see [restrict-template-expressions](https://typescript-eslint.io/rules/restrict-template-expressions)
*/
"rules/restrict-template-expressions": RuleEntry<{
allow: string[];
}>;
}
export type RuleOptions = Rules & Partial<LocalRuleOptions>;
/**
* ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
*/
export type Config = Omit<ESLintConfig, "rules"> & {
/**
* Rules.
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: RuleOptions;
};
/**
* Returns a ESLint config object.
*
* By default, it includes `["@typescript-eslint", "import", "prettier"]` configs.
* Additional bundled plugins include `["react", "react-refresh", "jsx-a11y", "unicorn"]`.
*/
export declare function extendConfig({ plugins, settings, rules, extends: _extends, overrides, ...rest }?: Config): ESLintConfig;
export {};

11
dist/package.json vendored
View File

@ -1,15 +1,18 @@
{
"name": "@aet/eslint-rules",
"version": "0.0.3",
"version": "0.0.5",
"license": "UNLICENSED",
"peerDependencies": {
"eslint": "^8.53.0",
"typescript": "^5.2.2"
},
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/eslint": "^8.44.7",
"@typescript-eslint/eslint-plugin": "6.10.0",
"@typescript-eslint/parser": "6.10.0",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@typescript-eslint/type-utils": "^6.10.0",
"@typescript-eslint/utils": "^6.10.0",
"aria-query": "^5.3.0",
"axe-core": "4.8.2",
"axobject-query": "^4.0.0",
@ -22,11 +25,13 @@
"eslint-define-config": "^1.24.1",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.8.0",
"eslint-plugin-es-x": "7.3.0",
"eslint-plugin-unicorn": "^49.0.0",
"estraverse": "^5.3.0",
"fast-glob": "^3.3.2",
"get-tsconfig": "^4.7.2",
"ignore": "^5.2.4",
"is-builtin-module": "^3.2.1",
"is-core-module": "^2.13.1",
"is-glob": "^4.0.3",
"language-tags": "^1.0.9",

View File

@ -273,5 +273,6 @@ main('./packages/eslint-plugin-jsx-a11y/src/index.js');
main('./packages/eslint-plugin-react-hooks/index.ts');
main('./packages/eslint-plugin-n/lib/index.js');
main('./packages/eslint-import-resolver-typescript/src/index.ts');
main('./src/rules/index.ts', './dist/rules/index.js');
main('./src/rules/index.ts', './dist/eslint-plugin-rules/index.js');
main('./src/local/index.ts', './dist/eslint-plugin-local/index.js');
main('./src/index.ts', './dist/index.js');

View File

@ -9,23 +9,27 @@
"@babel/core": "^7.23.2",
"@babel/plugin-transform-flow-strip-types": "^7.22.5",
"@babel/preset-env": "^7.23.2",
"@types/babel-plugin-macros": "^3.1.2",
"@types/babel__core": "^7.20.3",
"@types/eslint": "^8.44.6",
"@types/estree": "^1.0.4",
"@types/estree-jsx": "^1.0.2",
"@types/lodash": "^4.14.200",
"@types/node": "^20.8.10",
"@typescript-eslint/types": "^6.9.1",
"@types/babel-plugin-macros": "^3.1.3",
"@types/babel__core": "^7.20.4",
"@types/eslint": "^8.44.7",
"@types/estree": "^1.0.5",
"@types/estree-jsx": "^1.0.3",
"@types/lodash": "^4.14.201",
"@types/node": "^20.9.0",
"@typescript-eslint/eslint-plugin": "6.10.0",
"@typescript-eslint/type-utils": "^6.10.0",
"@typescript-eslint/types": "^6.10.0",
"@typescript-eslint/typescript-estree": "^6.10.0",
"@typescript-eslint/utils": "^6.10.0",
"babel-plugin-macros": "^3.1.0",
"dts-bundle-generator": "^8.1.2",
"esbin": "0.0.3",
"esbin": "0.0.4",
"esbuild": "0.19.5",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "8.52.0",
"eslint-config-prettier": "9.0.0",
"eslint": "8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-define-config": "^1.24.1",
"fast-glob": "^3.3.1",
"fast-glob": "^3.3.2",
"json-schema-to-ts": "^2.9.2",
"lodash": "^4.17.21",
"minimatch": "^9.0.3",

View File

@ -237,24 +237,10 @@ index 64bbc8d5..b5e9c803 100644
const isCreateElement = require('../util/isCreateElement');
const report = require('../util/report');
diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js
index fc573366..74bc36f6 100644
index 069596d7..c155e777 100644
--- a/lib/rules/no-unknown-property.js
+++ b/lib/rules/no-unknown-property.js
@@ -516,6 +516,13 @@ module.exports = {
type: 'string',
},
},
+ extends: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: ['next', 'emotion'],
+ },
+ }
},
additionalProperties: false,
}],
@@ -523,14 +530,18 @@ module.exports = {
@@ -539,7 +539,7 @@ module.exports = {
create(context) {
function getIgnoreConfig() {
@ -262,11 +248,8 @@ index fc573366..74bc36f6 100644
+ return context.options[0]?.ignore || DEFAULTS.ignore;
}
+ const extensions = /** @type {string[]} */ (context.options[0]?.extends || []);
+ const hasEmotion = extensions.includes('emotion');
+ const hasNext = extensions.includes('next');
+
return {
function getRequireDataLowercase() {
@@ -552,7 +552,7 @@ module.exports = {
JSXAttribute(node) {
const ignoreNames = getIgnoreConfig();
const actualName = context.getSourceCode().getText(node.name);
@ -275,7 +258,7 @@ index fc573366..74bc36f6 100644
return;
}
const name = normalizeAttributeCase(actualName);
@@ -546,6 +557,15 @@ module.exports = {
@@ -580,6 +580,15 @@ module.exports = {
const tagName = getTagName(node);

319
pnpm-lock.yaml generated
View File

@ -15,29 +15,41 @@ devDependencies:
specifier: ^7.23.2
version: 7.23.2(@babel/core@7.23.2)
'@types/babel-plugin-macros':
specifier: ^3.1.2
version: 3.1.2
specifier: ^3.1.3
version: 3.1.3
'@types/babel__core':
specifier: ^7.20.3
version: 7.20.3
specifier: ^7.20.4
version: 7.20.4
'@types/eslint':
specifier: ^8.44.6
version: 8.44.6
specifier: ^8.44.7
version: 8.44.7
'@types/estree':
specifier: ^1.0.4
version: 1.0.4
specifier: ^1.0.5
version: 1.0.5
'@types/estree-jsx':
specifier: ^1.0.2
version: 1.0.2
specifier: ^1.0.3
version: 1.0.3
'@types/lodash':
specifier: ^4.14.200
version: 4.14.200
specifier: ^4.14.201
version: 4.14.201
'@types/node':
specifier: ^20.8.10
version: 20.8.10
specifier: ^20.9.0
version: 20.9.0
'@typescript-eslint/eslint-plugin':
specifier: 6.10.0
version: 6.10.0(@typescript-eslint/parser@6.10.0)(eslint@8.53.0)(typescript@5.2.2)
'@typescript-eslint/type-utils':
specifier: ^6.10.0
version: 6.10.0(eslint@8.53.0)(typescript@5.2.2)
'@typescript-eslint/types':
specifier: ^6.9.1
version: 6.9.1
specifier: ^6.10.0
version: 6.10.0
'@typescript-eslint/typescript-estree':
specifier: ^6.10.0
version: 6.10.0(typescript@5.2.2)
'@typescript-eslint/utils':
specifier: ^6.10.0
version: 6.10.0(eslint@8.53.0)(typescript@5.2.2)
babel-plugin-macros:
specifier: ^3.1.0
version: 3.1.0
@ -45,8 +57,8 @@ devDependencies:
specifier: ^8.1.2
version: 8.1.2
esbin:
specifier: 0.0.3
version: 0.0.3(esbuild@0.19.5)
specifier: 0.0.4
version: 0.0.4(esbuild@0.19.5)
esbuild:
specifier: 0.19.5
version: 0.19.5
@ -54,17 +66,17 @@ devDependencies:
specifier: ^0.2.1
version: 0.2.1
eslint:
specifier: 8.52.0
version: 8.52.0
specifier: 8.53.0
version: 8.53.0
eslint-config-prettier:
specifier: 9.0.0
version: 9.0.0(eslint@8.52.0)
specifier: ^9.0.0
version: 9.0.0(eslint@8.53.0)
eslint-define-config:
specifier: ^1.24.1
version: 1.24.1
fast-glob:
specifier: ^3.3.1
version: 3.3.1
specifier: ^3.3.2
version: 3.3.2
json-schema-to-ts:
specifier: ^2.9.2
version: 2.9.2
@ -1475,13 +1487,13 @@ packages:
dev: true
optional: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.52.0):
/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies:
eslint: 8.52.0
eslint: 8.53.0
eslint-visitor-keys: 3.4.3
dev: true
@ -1490,8 +1502,8 @@ packages:
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
dev: true
/@eslint/eslintrc@2.1.2:
resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==}
/@eslint/eslintrc@2.1.3:
resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
ajv: 6.12.6
@ -1507,8 +1519,8 @@ packages:
- supports-color
dev: true
/@eslint/js@8.52.0:
resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==}
/@eslint/js@8.53.0:
resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
@ -1583,14 +1595,14 @@ packages:
fastq: 1.15.0
dev: true
/@types/babel-plugin-macros@3.1.2:
resolution: {integrity: sha512-reO/Op5+rVgMPajMQslgFtoBtUMkkVVUkcXmsz8hLEHq1A2gr3JyHmrs+s2rJjhPKJIi2S2p/fj0q6BYP111Uw==}
/@types/babel-plugin-macros@3.1.3:
resolution: {integrity: sha512-JU+MgpsHK3taY18mBETy5XlwY6LVngte7QXYzUuXEaaX0CN8dBqbjXtADe+gJmkSQE1FJHufzPj++OWZlhRmGw==}
dependencies:
'@types/babel__core': 7.20.3
'@types/babel__core': 7.20.4
dev: true
/@types/babel__core@7.20.3:
resolution: {integrity: sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==}
/@types/babel__core@7.20.4:
resolution: {integrity: sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==}
dependencies:
'@babel/parser': 7.23.0
'@babel/types': 7.23.0
@ -1618,33 +1630,33 @@ packages:
'@babel/types': 7.23.0
dev: true
/@types/eslint@8.44.6:
resolution: {integrity: sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==}
/@types/eslint@8.44.7:
resolution: {integrity: sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==}
dependencies:
'@types/estree': 1.0.4
'@types/estree': 1.0.5
'@types/json-schema': 7.0.13
dev: true
/@types/estree-jsx@1.0.2:
resolution: {integrity: sha512-GNBWlGBMjiiiL5TSkvPtOteuXsiVitw5MYGY1UYlrAq0SKyczsls6sCD7TZ8fsjRsvCVxml7EbyjJezPb3DrSA==}
/@types/estree-jsx@1.0.3:
resolution: {integrity: sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==}
dependencies:
'@types/estree': 1.0.4
'@types/estree': 1.0.5
dev: true
/@types/estree@1.0.4:
resolution: {integrity: sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==}
/@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
dev: true
/@types/json-schema@7.0.13:
resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==}
dev: true
/@types/lodash@4.14.200:
resolution: {integrity: sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==}
/@types/lodash@4.14.201:
resolution: {integrity: sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==}
dev: true
/@types/node@20.8.10:
resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==}
/@types/node@20.9.0:
resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==}
dependencies:
undici-types: 5.26.5
dev: true
@ -1653,9 +1665,139 @@ packages:
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
dev: true
/@typescript-eslint/types@6.9.1:
resolution: {integrity: sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==}
/@types/semver@7.5.5:
resolution: {integrity: sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==}
dev: true
/@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0)(eslint@8.53.0)(typescript@5.2.2):
resolution: {integrity: sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@eslint-community/regexpp': 4.9.1
'@typescript-eslint/parser': 6.10.0(eslint@8.53.0)(typescript@5.2.2)
'@typescript-eslint/scope-manager': 6.10.0
'@typescript-eslint/type-utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2)
'@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.10.0
debug: 4.3.4
eslint: 8.53.0
graphemer: 1.4.0
ignore: 5.2.4
natural-compare: 1.4.0
semver: 7.5.4
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2):
resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 6.10.0
'@typescript-eslint/types': 6.10.0
'@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.10.0
debug: 4.3.4
eslint: 8.53.0
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/scope-manager@6.10.0:
resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.10.0
'@typescript-eslint/visitor-keys': 6.10.0
dev: true
/@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.2.2):
resolution: {integrity: sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2)
'@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2)
debug: 4.3.4
eslint: 8.53.0
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/types@6.10.0:
resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==}
engines: {node: ^16.0.0 || >=18.0.0}
dev: true
/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2):
resolution: {integrity: sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 6.10.0
'@typescript-eslint/visitor-keys': 6.10.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.4
ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2):
resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
'@types/json-schema': 7.0.13
'@types/semver': 7.5.5
'@typescript-eslint/scope-manager': 6.10.0
'@typescript-eslint/types': 6.10.0
'@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2)
eslint: 8.53.0
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/visitor-keys@6.10.0:
resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.10.0
eslint-visitor-keys: 3.4.3
dev: true
/@ungap/structured-clone@1.2.0:
@ -1708,6 +1850,11 @@ packages:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
dev: true
/babel-plugin-macros@3.1.0:
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
engines: {node: '>=10', npm: '>=6'}
@ -1894,6 +2041,13 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
dependencies:
path-type: 4.0.0
dev: true
/doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
@ -1924,8 +2078,8 @@ packages:
is-arrayish: 0.2.1
dev: true
/esbin@0.0.3(esbuild@0.19.5):
resolution: {integrity: sha512-nuPK5e7DEIUlfPoemO4HPOQ0vyYoXstp3zxIUnDOwDtlaUA6Lrj6t+ACQsUyugVSwS7RkBV+egRVdd4s0CaxHA==}
/esbin@0.0.4(esbuild@0.19.5):
resolution: {integrity: sha512-X2+hwSY96Y7AXUa02szm9KPomIEg8QhxdwOXy/fyq0i8tqT34A6gYrZTqrhuhiPh6W775krUoqXIwsP344VW4g==}
hasBin: true
peerDependencies:
esbuild: '>=0.19 <1'
@ -1987,13 +2141,13 @@ packages:
engines: {node: '>=10'}
dev: true
/eslint-config-prettier@9.0.0(eslint@8.52.0):
/eslint-config-prettier@9.0.0(eslint@8.53.0):
resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
eslint: 8.52.0
eslint: 8.53.0
dev: true
/eslint-define-config@1.24.1:
@ -2014,15 +2168,15 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/eslint@8.52.0:
resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==}
/eslint@8.53.0:
resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0)
'@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0)
'@eslint-community/regexpp': 4.9.1
'@eslint/eslintrc': 2.1.2
'@eslint/js': 8.52.0
'@eslint/eslintrc': 2.1.3
'@eslint/js': 8.53.0
'@humanwhocodes/config-array': 0.11.13
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
@ -2098,8 +2252,8 @@ packages:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
@ -2209,6 +2363,18 @@ packages:
type-fest: 0.20.2
dev: true
/globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.2
ignore: 5.2.4
merge2: 1.4.1
slash: 3.0.0
dev: true
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: true
@ -2401,6 +2567,13 @@ packages:
yallist: 3.1.1
dev: true
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -2649,6 +2822,14 @@ packages:
hasBin: true
dev: true
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@ -2661,6 +2842,11 @@ packages:
engines: {node: '>=8'}
dev: true
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@ -2726,6 +2912,15 @@ packages:
resolution: {integrity: sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==}
dev: true
/ts-api-utils@1.0.3(typescript@5.2.2):
resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
engines: {node: '>=16.13.0'}
peerDependencies:
typescript: '>=4.2.0'
dependencies:
typescript: 5.2.2
dev: true
/tsconfig-paths@4.2.0:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
engines: {node: '>=6'}
@ -2827,6 +3022,10 @@ packages:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: true
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
/yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}

View File

@ -7,14 +7,18 @@ const files = readdirSync('./src/rules')
.filter(file => file !== 'index.ts')
.map(file => file.slice(0, -3));
const entryFile = `
const entryFile = /* js */ `
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
${files.map(file => `import ${camelCase(file)} from "./${file}"`).join(';\n')}
${files.map(file => `import ${camelCase(file)} from './${file}';`).join('\n')}
export const rules: Record<string, Rule.RuleModule> = {
${files.map(file => `"${file}": ${camelCase(file)}`).join(',\n ')}
export const rules: Record<
string,
Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>
> = {
${files.map(file => `'${file}': ${camelCase(file)},`).join('\n ')}
};
`.trim();
writeFileSync('./src/rules/index.ts', entryFile);
writeFileSync('./src/rules/index.ts', entryFile + '\n');

View File

@ -1,9 +1,10 @@
import './redirect';
import type { ESLintConfig } from 'eslint-define-config';
import type { ESLintConfig, Rules } from 'eslint-define-config';
import { typescriptRules } from './presets/typescript';
import { unicornRules } from './presets/unicorn';
import { eslintRules } from './presets/eslint';
import { reactRules } from './presets/react';
import { importRules } from './presets/import';
import { error, warn, off } from './constants';
// @ts-expect-error
const { name } = (0, require)('./package.json');
@ -14,12 +15,39 @@ const unique = <T>(arr: T[]): T[] => [...new Set(arr)];
const ensureArray = <T>(value?: T | T[]): T[] =>
value == null ? [] : Array.isArray(value) ? value : [value];
type RuleLevel = 'error' | 'warn' | 'off' | 0 | 1 | 2;
type RuleEntry<Options> = RuleLevel | [RuleLevel, Partial<Options>];
declare module 'eslint-define-config/src/rules/react/no-unknown-property.d.ts' {
export interface NoUnknownPropertyOption {
extends: ('next' | 'emotion')[];
}
}
export interface LocalRuleOptions {
/** Bans import from the specifier '.' and '..' and replaces it with '.+/index' */
'rules/no-import-dot': RuleEntry<unknown>;
/**
* Enforce template literal expressions to be of `string` type
* @see [restrict-template-expressions](https://typescript-eslint.io/rules/restrict-template-expressions)
*/
'rules/restrict-template-expressions': RuleEntry<{ allow: string[] }>;
}
export type RuleOptions = Rules & Partial<LocalRuleOptions>;
/**
* ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
*/
type Config = Omit<ESLintConfig, 'rules'> & {
/**
* Rules.
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: RuleOptions;
};
/**
* Returns a ESLint config object.
*
@ -33,16 +61,16 @@ export function extendConfig({
extends: _extends,
overrides,
...rest
}: ESLintConfig = {}): ESLintConfig {
}: Config = {}): ESLintConfig {
const hasReact = plugins?.includes('react');
const hasReactRefresh = plugins?.includes('react-refresh');
const hasUnicorn = plugins?.includes('unicorn');
const hasNext = ensureArray(_extends).some(name => name.includes(':@next/next'));
const result: ESLintConfig = {
const result: Config = {
root: true,
parser: '@typescript-eslint/parser',
plugins: unique(['@typescript-eslint', 'import', ...(plugins ?? [])]),
plugins: unique(['@typescript-eslint', 'import', 'rules', ...(plugins ?? [])]),
env: { node: true, browser: true, es2023: true },
reportUnusedDisableDirectives: true,
parserOptions: {
@ -99,9 +127,7 @@ export function extendConfig({
rules: {
...eslintRules,
...typescriptRules,
'import/export': off,
'import/no-duplicates': error,
'import/order': [error, { groups: ['builtin', 'external'] }],
...importRules,
...(hasReact && {
...reactRules,
'react/no-unknown-property': [
@ -113,6 +139,8 @@ export function extendConfig({
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
}),
...(hasUnicorn && unicornRules),
'rules/no-import-dot': error,
'rules/restrict-template-expressions': error,
...rules,
},
...rest,

8
src/presets/import.ts Normal file
View File

@ -0,0 +1,8 @@
import { error, off } from '../constants';
import { ImportRules } from 'eslint-define-config/src/rules/import';
export const importRules: Partial<ImportRules> = {
'import/export': off,
'import/no-duplicates': error,
'import/order': [error, { groups: ['builtin', 'external'] }],
};

6
src/presets/local.ts Normal file
View File

@ -0,0 +1,6 @@
import { error, off } from '../constants';
import type { CustomRuleOptions } from 'eslint-define-config';
export const importRules: Partial<CustomRuleOptions> = {
'local/no-import-dot': error,
};

View File

@ -33,6 +33,7 @@ export const typescriptRules: Partial<TypeScriptRules> = {
],
'@typescript-eslint/no-use-before-define': off,
'@typescript-eslint/no-var-requires': off,
'@typescript-eslint/restrict-template-expressions': off,
'@typescript-eslint/triple-slash-reference': off,
'@typescript-eslint/unbound-method': off,
};

View File

@ -1,7 +1,13 @@
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
import noImportDot from "./no-import-dot"
import noImportDot from './no-import-dot';
import restrictTemplateExpressions from './restrict-template-expressions';
export const rules: Record<string, Rule.RuleModule> = {
"no-import-dot": noImportDot
export const rules: Record<
string,
Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>
> = {
'no-import-dot': noImportDot,
'restrict-template-expressions': restrictTemplateExpressions,
};

View File

@ -1,19 +1,19 @@
import type { Rule } from "eslint";
import type { Rule } from 'eslint';
const rule: Rule.RuleModule = {
meta: {
type: "problem",
type: 'problem',
docs: {
description:
"Bans import from the specifier '.' and '..' and replaces it with '.+/index'",
category: "Best Practices",
category: 'Best Practices',
recommended: true,
},
fixable: "code",
fixable: 'code',
},
create: context => ({
ImportDeclaration(node) {
if (node.source.value === ".") {
if (node.source.value === '.') {
context.report({
node: node.source,
message:
@ -22,7 +22,7 @@ const rule: Rule.RuleModule = {
return fixer.replaceText(node.source, '"./index"');
},
});
} else if (node.source.value === "..") {
} else if (node.source.value === '..') {
context.report({
node: node.source,
message:

View File

@ -0,0 +1,122 @@
// https://github.com/typescript-eslint/typescript-eslint/blob/75c128856b1ce05a4fec799bfa6de03b3dab03d0/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
import * as ts from 'typescript';
import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
import {
getTypeName,
isTypeAnyType,
isTypeFlagSet,
isTypeNeverType,
getConstrainedTypeAtLocation,
} from '@typescript-eslint/type-utils';
import { getParserServices } from '@typescript-eslint/utils/eslint-utils';
const createRule = ESLintUtils.RuleCreator(
name => `https://typescript-eslint.io/rules/${name}`,
);
interface Option {
allow: string[];
}
const defaultOption: Option = {
allow: ['any', 'boolean', 'null', 'undefined', 'number', 'RegExp', 'URLSearchParams'],
};
type MessageId = 'invalidType';
export default createRule<Option[], MessageId>({
name: 'restrict-template-expressions',
meta: {
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.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
allow: {
type: 'array',
items: {
type: 'string',
},
description: 'Allow specific types',
uniqueItems: true,
},
},
},
],
},
defaultOptions: [defaultOption],
create(context, [options]) {
const services = getParserServices(context);
const checker = services.program!.getTypeChecker();
const allowed = new Set(options.allow);
const { StringLike, NumberLike, BigIntLike, BooleanLike, Null, Undefined } =
ts.TypeFlags;
function isUnderlyingTypePrimitive(type: ts.Type): boolean {
return (
isTypeFlagSet(type, StringLike) ||
(allowed.has('number') && isTypeFlagSet(type, NumberLike | BigIntLike)) ||
(allowed.has('boolean') && isTypeFlagSet(type, BooleanLike)) ||
(allowed.has('any') && isTypeAnyType(type)) ||
allowed.has(getTypeName(checker, type)) ||
(allowed.has('null') && isTypeFlagSet(type, Null)) ||
(allowed.has('undefined') && isTypeFlagSet(type, Undefined)) ||
(allowed.has('never') && isTypeNeverType(type))
);
}
return {
TemplateLiteral(node: TSESTree.TemplateLiteral): void {
// don't check tagged template literals
if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) {
return;
}
for (const expression of node.expressions) {
const expressionType = getConstrainedTypeAtLocation(services, expression);
if (
!isInnerUnionOrIntersectionConformingTo(
expressionType,
isUnderlyingTypePrimitive,
)
) {
context.report({
node: expression,
messageId: 'invalidType',
data: { type: checker.typeToString(expressionType) },
});
}
}
},
};
function isInnerUnionOrIntersectionConformingTo(
type: ts.Type,
predicate: (underlyingType: ts.Type) => boolean,
): boolean {
return rec(type);
function rec(innerType: ts.Type): boolean {
if (innerType.isUnion()) {
return innerType.types.every(rec);
}
if (innerType.isIntersection()) {
return innerType.types.some(rec);
}
return predicate(innerType);
}
}
},
});

15
src/types.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
declare module '@typescript-eslint/utils' {
export * from '@typescript-eslint/utils/dist/index';
}
declare module '@typescript-eslint/typescript-estree' {
export * from '@typescript-eslint/typescript-estree/dist/index';
}
declare module '@typescript-eslint/type-utils' {
export * from '@typescript-eslint/type-utils/dist/index';
}
declare module '@typescript-eslint/utils/eslint-utils' {
export * from '@typescript-eslint/utils/dist/eslint-utils';
}
declare module '@typescript-eslint/utils/json-schema' {
export * from '@typescript-eslint/utils/dist/json-schema';
}

View File

@ -17,11 +17,5 @@
"stripInternal": true,
"target": "esnext",
"useUnknownInCatchVariables": false
},
"ts-node": {
"transpileOnly": true,
"compilerOptions": {
"module": "commonjs"
}
}
}