Compare commits

...

41 Commits

Author SHA1 Message Date
a275b5bd94 chore: release v0.40.11 2023-08-15 19:42:00 +08:00
15b1011230 chore: release v0.40.10 2023-08-15 19:40:53 +08:00
0ba93481db chore: release v0.40.9 2023-08-15 19:40:30 +08:00
1296d158c9 chore: release v0.40.8 2023-08-15 19:39:42 +08:00
8b98365ad0 chore: release v0.40.7 2023-08-15 19:39:00 +08:00
4d6dd79325 chore: release v0.40.6 2023-08-15 19:36:52 +08:00
bc0a817dd1 chore: release v0.40.5 2023-08-15 19:36:08 +08:00
6bf6d00b90 chore: release v0.40.4 2023-08-15 19:34:09 +08:00
13796c251c chore: release v0.40.3 2023-08-15 19:31:18 +08:00
f80fdbe613 去掉 markdown lint 2023-08-15 19:28:35 +08:00
toryz
1ae6ec8527
fix(basic): ignore vitepress cache files (#233) 2023-08-11 20:12:47 +02:00
Anthony Fu
c22a36bbec chore: release v0.40.2 2023-08-07 15:57:18 +02:00
Anthony Fu
71e8f0c3b2 chore: upgrade eslint-plugin-i 2023-08-07 15:57:14 +02:00
Anthony Fu
e0071450be chore: release v0.40.1 2023-08-07 15:41:59 +02:00
Anthony Fu
bfa0e2bb80 chore: lint 2023-08-07 15:41:55 +02:00
Anthony Fu
49b9b7f7db chore: update deps, migrate tests 2023-08-07 15:41:19 +02:00
Anthony Fu
3a2c549110 fix(plugin): named-tuple-spacing handling, close #232 2023-08-07 15:41:02 +02:00
Anthony Fu
59308e8e36 chore: release v0.40.0 2023-08-01 17:00:05 +02:00
曾明健
cf1240c847
feat: add rule no-import-node-modules-by-path (#219) 2023-08-01 16:59:19 +02:00
Ted Xu
0ff5e45fdd
feat: format for named tuple (#229) 2023-08-01 16:58:56 +02:00
Anthony Fu
effc708692 feat: add default in exports 2023-08-01 16:58:10 +02:00
Anthony Fu
ea307c91e5 fix: put import before require in exports 2023-08-01 16:56:25 +02:00
曾明健
b7ce1614d8
docs: make config correct (#224) 2023-07-20 14:44:19 +02:00
Cloyd Lau
bf390b0693
docs: add code style badge (#220)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-07-17 16:53:38 +02:00
Anthony Fu
500fe9df8d chore: release v0.39.8 2023-07-16 00:20:35 +02:00
Anthony Fu
5be2b3fd39 chore: update deps 2023-07-16 00:20:31 +02:00
三咲智子 Kevin Deng
5821926148
fix(plugin): allow empty type import (#218) 2023-07-16 00:18:20 +02:00
曾明健
3ef955d56f
feat(basic): prefer non global process object (#214) 2023-07-12 12:39:07 +02:00
Marshall Thompson
1b25322bf5
docs: VS Code config example (#215) 2023-07-10 03:02:20 +02:00
曾明健
2ed8536b85
feat(basic): ban self import (#213) 2023-07-05 11:50:02 +02:00
Anthony Fu
4edff9cd15 chore: release v0.39.7 2023-07-04 11:32:56 +02:00
Anthony Fu
f245939bfa chore: update deps 2023-07-04 11:32:40 +02:00
曾明健
be5bc8009c
feat: ban new Array (#209) 2023-07-04 10:52:53 +02:00
曾明健
d4a9ebcc17
feat(ts): enable @typescript-eslint/ban-types (#210) 2023-07-03 21:19:59 +02:00
Anthony Fu
c1355234c0 chore: release v0.39.6 2023-06-28 14:10:34 +02:00
Julian Meinking
6dfc773b05
docs: add eslint.validate to enable linting for supported filetypes with VSCode ESLint (#204)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-06-28 14:10:01 +02:00
曾明健
2bf0c8d727
feat(ts): ban const enum (#201) 2023-06-28 14:05:23 +02:00
arily
504de8392a
feat: switch to eslint-plugin-i (#205) 2023-06-28 14:04:55 +02:00
Mert
6cf4794985
docs: update organizeImports config for VS Code (#202) 2023-06-18 12:42:25 +02:00
曾明健
bbed70b969
refactor: use existing rules (#198) 2023-06-06 18:01:05 +02:00
Kirk Lin
f553c519f6
feat(vue): enforce order of define macros (#196) 2023-06-06 11:32:33 +02:00
37 changed files with 1232 additions and 940 deletions

View File

@ -1,6 +1,6 @@
# @antfu/eslint-config
[![npm](https://img.shields.io/npm/v/@antfu/eslint-config?color=a1b858&label=)](https://npmjs.com/package/@antfu/eslint-config)
[![npm](https://img.shields.io/npm/v/@antfu/eslint-config?color=444&label=)](https://npmjs.com/package/@antfu/eslint-config) [![code style](https://antfu.me/badge-code-style.svg)](https://github.com/antfu/eslint-config)
- Single quotes, no semi
- Auto fix for formatting (aimed to be used standalone **without** Prettier)
@ -41,26 +41,48 @@ For example:
}
```
### Config VS Code auto fix
### VS Code support (auto fix)
Install [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and create `.vscode/settings.json`
Install [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
```json
Add the following settings to your `settings.json`:
```jsonc
{
"prettier.enable": false,
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
"source.fixAll.eslint": true,
"source.organizeImports": false
},
// The following is optional.
// It's better to put under project setting `.vscode/settings.json`
// to avoid conflicts with working with different eslint configs
// that does not support all formats.
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
]
}
```
### TypeScript Aware Rules
Type aware rules are enabled when a `tsconfig.eslint.json` is found in the project root, which will introduce some stricter rules into your project. If you want to enable it while have no `tsconfig.eslint.json` in the project root, you can change tsconfig name by modifying `ESLINT_TSCONFIG` env.
Type aware rules are enabled when a `tsconfig.eslint.json` is found in the project root, which will introduce some stricter rules into your project. If you want to enable it while have no `tsconfig.eslint.json` in the project root, you can change tsconfig name by modifying `ESLINT_TSCONFIG` env.
```js
// .eslintrc.js
const process = require('node:process')
process.env.ESLINT_TSCONFIG = 'tsconfig.json'
module.exports = {
@ -89,6 +111,16 @@ and then
npm i -D lint-staged simple-git-hooks
```
## Badge
If you enjoy this code style, and would like to mention it in your project, here is the badge you can use:
```md
[![code style](https://antfu.me/badge-code-style.svg)](https://github.com/antfu/eslint-config)
```
[![code style](https://antfu.me/badge-code-style.svg)](https://github.com/antfu/eslint-config)
## FAQ
### Prettier?

View File

@ -1,7 +1,7 @@
{
"type": "module",
"private": true,
"packageManager": "pnpm@8.5.1",
"packageManager": "pnpm@8.6.12",
"scripts": {
"build": "vite-ssg build",
"dev": "vite --port 3333 --open",
@ -15,48 +15,48 @@
"up": "taze major -I"
},
"dependencies": {
"@unocss/reset": "^0.52.1",
"@vueuse/core": "^10.1.2",
"@unocss/reset": "^0.54.2",
"@vueuse/core": "^10.3.0",
"@vueuse/head": "^1.1.26",
"nprogress": "^0.2.0",
"pinia": "^2.1.3",
"pinia": "^2.1.6",
"vue": "^3.3.4",
"vue-demi": "^0.14.5",
"vue-i18n": "^9.2.2",
"vue-router": "^4.2.1"
"vue-router": "^4.2.4"
},
"devDependencies": {
"@antfu/eslint-config": "^0.39.1",
"@iconify-json/carbon": "^1.1.16",
"@antfu/eslint-config": "^0.40.0",
"@iconify-json/carbon": "^1.1.19",
"@intlify/vite-plugin-vue-i18n": "^7.0.0",
"@types/markdown-it-link-attributes": "^3.0.1",
"@types/nprogress": "^0.2.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/test-utils": "^2.3.2",
"critters": "^0.0.16",
"@vue/test-utils": "^2.4.1",
"critters": "^0.0.20",
"cross-env": "^7.0.3",
"cypress": "^12.12.0",
"eslint": "^8.41.0",
"cypress": "^12.17.3",
"eslint": "^8.46.0",
"eslint-plugin-cypress": "^2.13.3",
"https-localhost": "^4.7.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-shiki": "^0.9.0",
"pnpm": "^8.5.1",
"shiki": "^0.14.2",
"taze": "^0.10.1",
"typescript": "^5.0.4",
"unocss": "^0.52.1",
"unplugin-auto-import": "^0.16.2",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.3.8",
"vite-plugin-inspect": "^0.7.26",
"vite-plugin-pages": "^0.30.1",
"vite-plugin-pwa": "^0.15.0",
"pnpm": "^8.6.12",
"shiki": "^0.14.3",
"taze": "^0.11.2",
"typescript": "^5.1.6",
"unocss": "^0.54.2",
"unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.9",
"vite-plugin-inspect": "^0.7.35",
"vite-plugin-pages": "^0.31.0",
"vite-plugin-pwa": "^0.16.4",
"vite-plugin-vue-layouts": "^0.8.0",
"vite-plugin-vue-markdown": "^0.23.5",
"vite-ssg": "^0.22.2",
"vite-plugin-vue-markdown": "^0.23.7",
"vite-ssg": "^0.23.1",
"vite-ssg-sitemap": "^0.5.1",
"vitest": "^0.31.1",
"vue-tsc": "^1.6.5"
"vitest": "^0.34.1",
"vue-tsc": "^1.8.8"
}
}

View File

@ -1,8 +1,8 @@
{
"name": "@antfu/eslint-config-monorepo",
"version": "0.39.5",
"name": "@taoyaal/eslint-config-monorepo",
"version": "0.40.11",
"private": true,
"packageManager": "pnpm@8.5.1",
"packageManager": "pnpm@8.6.12",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
"scripts": {
@ -14,10 +14,10 @@
},
"devDependencies": {
"@antfu/eslint-config": "workspace:*",
"bumpp": "^9.1.0",
"eslint": "^8.41.0",
"bumpp": "^9.1.1",
"eslint": "^8.46.0",
"eslint-plugin-antfu": "link:./packages/eslint-plugin-antfu",
"rimraf": "^5.0.1",
"typescript": "^5.0.4"
"typescript": "^5.1.6"
}
}

View File

@ -11,7 +11,6 @@ module.exports = {
'plugin:eslint-comments/recommended',
'plugin:jsonc/recommended-with-jsonc',
'plugin:yml/standard',
'plugin:markdown/recommended',
],
ignorePatterns: [
'*.min.*',
@ -43,7 +42,7 @@ module.exports = {
'!.vitepress',
'!.vscode',
// force exclude
'.vitepress/cache',
'**/.vitepress/cache',
],
plugins: [
'html',
@ -142,8 +141,9 @@ module.exports = {
pathPattern: '^exports.*$',
order: [
'types',
'require',
'import',
'require',
'default',
],
},
],
@ -181,31 +181,6 @@ module.exports = {
'no-only-tests/no-only-tests': 'error',
},
},
{
// Code blocks in markdown file
files: ['**/*.md/*.*'],
rules: {
'@typescript-eslint/no-redeclare': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/comma-dangle': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-require-imports': 'off',
'import/no-unresolved': 'off',
'unused-imports/no-unused-imports': 'off',
'unused-imports/no-unused-vars': 'off',
'no-alert': 'off',
'no-console': 'off',
'no-restricted-imports': 'off',
'no-undef': 'off',
'no-unused-expressions': 'off',
'no-unused-vars': 'off',
'antfu/no-cjs-exports': 'off',
'antfu/no-ts-export-equal': 'off',
},
},
],
rules: {
// import
@ -215,6 +190,7 @@ module.exports = {
'import/no-unresolved': 'off',
'import/no-absolute-path': 'off',
'import/newline-after-import': ['error', { count: 1, considerComments: true }],
'import/no-self-import': 'error',
// Common
'semi': ['error', 'never'],
@ -263,23 +239,10 @@ module.exports = {
'error',
{ name: 'global', message: 'Use `globalThis` instead.' },
{ name: 'self', message: 'Use `globalThis` instead.' },
{ name: 'isNaN', message: 'Use `Number.isNaN` instead.' },
{ name: 'isFinite', message: 'Use `Number.isFinite` instead.' },
{ name: 'parseFloat', message: 'Use `Number.parseFloat` instead.' },
{ name: 'parseInt', message: 'Use `Number.parseInt` instead.' },
],
'no-restricted-properties': [
'error',
{ object: 'globalThis', property: 'isNaN', message: 'Use `Number.isNaN` instead.' },
{ object: 'globalThis', property: 'isFinite', message: 'Use `Number.isFinite` instead.' },
{ object: 'globalThis', property: 'parseFloat', message: 'Use `Number.parseFloat` instead.' },
{ object: 'globalThis', property: 'parseInt', message: 'Use `Number.parseInt` instead.' },
{ object: 'window', property: 'isNaN', message: 'Use `Number.isNaN` instead.' },
{ object: 'window', property: 'isFinite', message: 'Use `Number.isFinite` instead.' },
{ object: 'window', property: 'parseFloat', message: 'Use `Number.parseFloat` instead.' },
{ object: 'window', property: 'parseInt', message: 'Use `Number.parseInt` instead.' },
{ object: 'Math', property: 'pow', message: 'Use the exponentiation operator (**) instead.' },
{ property: '__proto__', message: 'Use `Object.getPrototypeOf` instead.' },
{ property: '__proto__', message: 'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.' },
{ property: '__defineGetter__', message: 'Use `Object.defineProperty` instead.' },
{ property: '__defineSetter__', message: 'Use `Object.defineProperty` instead.' },
{ property: '__lookupGetter__', message: 'Use `Object.getOwnPropertyDescriptor` instead.' },
@ -350,7 +313,7 @@ module.exports = {
'max-statements-per-line': ['error', { max: 1 }],
// node
// 'n/prefer-global/process': ['error', 'never'], // Not sure if we need it as we are using `process.env.NODE_ENV` a lot in front-end.
'n/prefer-global/process': ['error', 'never'],
'n/prefer-global/buffer': ['error', 'never'],
'n/no-callback-literal': 'off',
@ -379,6 +342,10 @@ module.exports = {
'unicorn/throw-new-error': 'error',
// Prefer using the node: protocol
'unicorn/prefer-node-protocol': 'error',
// Prefer using number properties like `Number.isNaN` rather than `isNaN`
'unicorn/prefer-number-properties': 'error',
// Ban `new Array` as `Array` constructor's params are ambiguous
'unicorn/no-new-array': 'error',
'no-use-before-define': ['error', { functions: false, classes: false, variables: true }],
'eslint-comments/disable-enable-pair': 'off',
@ -402,6 +369,7 @@ module.exports = {
'yml/no-empty-document': 'off',
// antfu
'antfu/no-import-node-modules-by-path': 'error',
'antfu/if-newline': 'error',
'antfu/import-dedupe': 'error',
'antfu/top-level-function': 'error',

View File

@ -1,10 +1,10 @@
{
"name": "@antfu/eslint-config-basic",
"version": "0.39.5",
"version": "0.40.11",
"description": "",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
"homepage": "https://github.com/antfu/eslint-config",
"homepage": "https://git.taoya.art/taolin/eslint-config.git",
"keywords": [
"eslint-config"
],
@ -22,19 +22,18 @@
"eslint-plugin-antfu": "workspace:*",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsonc": "^2.8.0",
"eslint-plugin-markdown": "^3.0.0",
"eslint-plugin-n": "^16.0.0",
"eslint-plugin-import": "npm:eslint-plugin-i@2.28.0-2",
"eslint-plugin-jsonc": "^2.9.0",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-unicorn": "^47.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"eslint-plugin-yml": "^1.7.0",
"eslint-plugin-unicorn": "^48.0.1",
"eslint-plugin-unused-imports": "^3.0.0",
"eslint-plugin-yml": "^1.8.0",
"jsonc-eslint-parser": "^2.3.0",
"yaml-eslint-parser": "^1.2.2"
},
"devDependencies": {
"eslint": "^8.41.0"
"eslint": "^8.46.0"
}
}

View File

@ -1,10 +1,10 @@
{
"name": "@antfu/eslint-config-react",
"version": "0.39.5",
"version": "0.40.11",
"description": "",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
"homepage": "https://github.com/antfu/eslint-config",
"homepage": "https://git.taoya.art/taolin/eslint-config.git",
"keywords": [
"eslint-config"
],
@ -20,12 +20,12 @@
},
"dependencies": {
"@antfu/eslint-config-ts": "workspace:*",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react": "^7.33.1",
"eslint-plugin-react-hooks": "^4.6.0"
},
"devDependencies": {
"eslint": "^8.41.0",
"eslint": "^8.46.0",
"react": "^18.2.0",
"typescript": "^5.0.4"
"typescript": "^5.1.6"
}
}

View File

@ -1,5 +1,6 @@
const fs = require('node:fs')
const { join } = require('node:path')
const process = require('node:process')
const basic = require('@antfu/eslint-config-basic')
const tsconfig = process.env.ESLINT_TSCONFIG || 'tsconfig.eslint.json'
@ -159,6 +160,8 @@ module.exports = {
'antfu/generic-spacing': 'error',
'antfu/no-cjs-exports': 'error',
'antfu/no-ts-export-equal': 'error',
'antfu/no-const-enum': 'error',
'antfu/named-tuple-spacing': 'error',
// off
'@typescript-eslint/consistent-indexed-object-style': 'off',
@ -172,7 +175,6 @@ module.exports = {
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/triple-slash-reference': 'off',
// handled by unused-imports/no-unused-imports
'@typescript-eslint/no-unused-vars': 'off',

View File

@ -1,10 +1,10 @@
{
"name": "@antfu/eslint-config-ts",
"version": "0.39.5",
"version": "0.40.11",
"description": "",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
"homepage": "https://github.com/antfu/eslint-config",
"homepage": "https://git.taoya.art/taolin/eslint-config.git",
"keywords": [
"eslint-config"
],
@ -18,11 +18,11 @@
},
"dependencies": {
"@antfu/eslint-config-basic": "workspace:*",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"eslint-plugin-jest": "^27.2.1"
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint-plugin-jest": "^27.2.3"
},
"devDependencies": {
"eslint": "^8.41.0"
"eslint": "^8.46.0"
}
}

View File

@ -52,7 +52,7 @@ module.exports = {
'vue/component-options-name-casing': ['error', 'PascalCase'],
'vue/custom-event-name-casing': ['error', 'camelCase'],
'vue/define-macros-order': ['error', {
order: ['defineProps', 'defineEmits'],
order: ['defineOptions', 'defineProps', 'defineEmits', 'defineSlots'],
}],
'vue/html-comment-content-spacing': ['error', 'always', {
exceptions: ['-'],

View File

@ -1,6 +1,6 @@
{
"name": "@antfu/eslint-config-vue",
"version": "0.39.5",
"version": "0.40.11",
"description": "",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
@ -17,10 +17,10 @@
"dependencies": {
"@antfu/eslint-config-basic": "workspace:*",
"@antfu/eslint-config-ts": "workspace:*",
"eslint-plugin-vue": "^9.14.0",
"eslint-plugin-vue": "^9.16.1",
"local-pkg": "^0.4.3"
},
"devDependencies": {
"eslint": "^8.41.0"
"eslint": "^8.46.0"
}
}

View File

@ -1,10 +1,10 @@
{
"name": "@antfu/eslint-config",
"version": "0.39.5",
"name": "@taoyaal/eslint-config",
"version": "0.40.11",
"description": "Anthony's ESLint config",
"author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
"license": "MIT",
"homepage": "https://github.com/antfu/eslint-config",
"homepage": "https://git.taoya.art/taolin/eslint-config.git",
"keywords": [
"eslint-config"
],
@ -17,21 +17,21 @@
},
"dependencies": {
"@antfu/eslint-config-vue": "workspace:*",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsonc": "^2.8.0",
"eslint-plugin-n": "^16.0.0",
"eslint-plugin-import": "npm:eslint-plugin-i@2.28.0-2",
"eslint-plugin-jsonc": "^2.9.0",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-unicorn": "^47.0.0",
"eslint-plugin-vue": "^9.14.0",
"eslint-plugin-yml": "^1.7.0",
"eslint-plugin-unicorn": "^48.0.1",
"eslint-plugin-vue": "^9.16.1",
"eslint-plugin-yml": "^1.8.0",
"jsonc-eslint-parser": "^2.3.0",
"yaml-eslint-parser": "^1.2.2"
},
"devDependencies": {
"eslint": "^8.41.0"
"eslint": "^8.46.0"
}
}

View File

@ -4,7 +4,7 @@ export default defineBuildConfig({
entries: [
'src/index',
],
declaration: true,
declaration: false,
clean: true,
rollup: {
emitCJS: true,

View File

@ -1,11 +1,10 @@
{
"name": "eslint-plugin-antfu",
"version": "0.39.5",
"version": "0.40.11",
"license": "MIT",
"homepage": "https://github.com/antfu/eslint-config",
"homepage": "https://git.taoya.art/taolin/eslint-config.git",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
@ -16,11 +15,12 @@
"prepublishOnly": "nr build"
},
"dependencies": {
"@typescript-eslint/utils": "^5.59.7"
"@typescript-eslint/utils": "^6.2.1"
},
"devDependencies": {
"@types/node": "^20.2.3",
"@types/node": "^20.4.8",
"@typescript-eslint/rule-tester": "^6.2.1",
"unbuild": "^1.2.1",
"vitest": "^0.31.1"
"vitest": "^0.34.1"
}
}

View File

@ -3,8 +3,11 @@ import ifNewline from './rules/if-newline'
import importDedupe from './rules/import-dedupe'
import preferInlineTypeImport from './rules/prefer-inline-type-import'
import topLevelFunction from './rules/top-level-function'
import noImportNodeModulesByPath from './rules/no-import-node-modules-by-path'
import noTsExportEqual from './rules/no-ts-export-equal'
import noCjsExports from './rules/no-cjs-exports'
import noConstEnum from './rules/no-const-enum'
import namedTupleSpacing from './rules/named-tuple-spacing'
export default {
rules: {
@ -13,7 +16,10 @@ export default {
'prefer-inline-type-import': preferInlineTypeImport,
'generic-spacing': genericSpacing,
'top-level-function': topLevelFunction,
'no-import-node-modules-by-path': noImportNodeModulesByPath,
'no-cjs-exports': noCjsExports,
'no-ts-export-equal': noTsExportEqual,
'no-const-enum': noConstEnum,
'named-tuple-spacing': namedTupleSpacing,
},
}

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './generic-spacing'
const valids = [
@ -36,17 +35,15 @@ const invalids = [
}`],
] as const
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1].trim(),
errors: Array.from({ length: i[2] || 1 }, () => ({ messageId: 'genericSpacingMismatch' })),
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1].trim(),
errors: Array.from({ length: i[2] || 1 }, () => ({ messageId: 'genericSpacingMismatch' })),
})),
})

View File

@ -10,7 +10,7 @@ export default createEslintRule<Options, MessageIds>({
type: 'suggestion',
docs: {
description: 'Spaces around generic type parameters',
recommended: 'error',
recommended: 'stylistic',
},
fixable: 'code',
schema: [],

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './if-newline'
const valids = [
@ -14,17 +13,15 @@ const invalids = [
['if (true) console.log(\'hello\')', 'if (true) \nconsole.log(\'hello\')'],
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'missingIfNewline' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'missingIfNewline' }],
})),
})

View File

@ -10,7 +10,7 @@ export default createEslintRule<Options, MessageIds>({
type: 'problem',
docs: {
description: 'Newline after if',
recommended: 'error',
recommended: 'stylistic',
},
fixable: 'code',
schema: [],

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './import-dedupe'
const valids = [
@ -12,17 +11,15 @@ const invalids = [
],
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'importDedupe' }, { messageId: 'importDedupe' }, { messageId: 'importDedupe' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'importDedupe' }, { messageId: 'importDedupe' }, { messageId: 'importDedupe' }],
})),
})

View File

@ -10,7 +10,7 @@ export default createEslintRule<Options, MessageIds>({
type: 'problem',
docs: {
description: 'Fix duplication in imports',
recommended: 'error',
recommended: 'strict',
},
fixable: 'code',
schema: [],

View File

@ -0,0 +1,98 @@
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './named-tuple-spacing'
const valids = [
'type T = [i: number]',
'type T = [i?: number]',
'type T = [i: number, j: number]',
'type T = [i: number, j: () => string]',
`const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()`,
]
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: [
{
code: 'type T = [i:number]',
output: 'type T = [i: number]',
errors: [{ messageId: 'expectedSpaceAfter' }],
},
{
code: 'type T = [i: number]',
output: 'type T = [i: number]',
errors: [{ messageId: 'expectedSpaceAfter' }],
},
{
code: 'type T = [i?:number]',
output: 'type T = [i?: number]',
errors: [{ messageId: 'expectedSpaceAfter' }],
},
{
code: 'type T = [i? :number]',
output: 'type T = [i?: number]',
errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'expectedSpaceAfter' }],
},
{
code: 'type T = [i : number]',
output: 'type T = [i: number]',
errors: [{ messageId: 'unexpectedSpaceBefore' }],
},
{
code: 'type T = [i : number]',
output: 'type T = [i: number]',
errors: [{ messageId: 'unexpectedSpaceBefore' }],
},
{
code: 'type T = [i ? : number]',
output: 'type T = [i?: number]',
errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'unexpectedSpaceBefore' }],
},
{
code: 'type T = [i:number, j:number]',
output: 'type T = [i: number, j: number]',
errors: [{ messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }],
},
{
code: 'type T = [i:()=>void, j:number]',
output: 'type T = [i: ()=>void, j: number]',
errors: [{ messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }],
},
{
code: `
const emit = defineEmits<{
change: [id:number]
update: [value:string]
}>()
`,
output: `
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
`,
errors: [{ messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }],
},
{
code: `
const emit = defineEmits<{
change: [id? :number]
update: [value:string]
}>()
`,
output: `
const emit = defineEmits<{
change: [id?: number]
update: [value: string]
}>()
`,
errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }],
},
],
})

View File

@ -0,0 +1,83 @@
import { createEslintRule } from '../utils'
export const RULE_NAME = 'named-tuple-spacing'
export type MessageIds = 'expectedSpaceAfter' | 'unexpectedSpaceBetween' | 'unexpectedSpaceBefore'
export type Options = []
const RE = /^([\w_$]+)(\s*)(\?\s*)?:(\s*)(.*)$/
export default createEslintRule<Options, MessageIds>({
name: RULE_NAME,
meta: {
type: 'suggestion',
docs: {
description: 'Expect space before type declaration in named tuple',
recommended: 'stylistic',
},
fixable: 'code',
schema: [],
messages: {
expectedSpaceAfter: 'Expected a space after the \':\'.',
unexpectedSpaceBetween: 'Unexpected space between \'?\' and the \':\'.',
unexpectedSpaceBefore: 'Unexpected space before the \':\'.',
},
},
defaultOptions: [],
create: (context) => {
const sourceCode = context.getSourceCode()
return {
TSNamedTupleMember: (node: any) => {
const code = sourceCode.text.slice(node.range[0], node.range[1])
const match = code.match(RE)
if (!match)
return
const labelName = node.label.name
const spaceBeforeColon = match[2]
const optionalMark = match[3]
const spacesAfterColon = match[4]
const elementType = match[5]
function getReplaceValue() {
let ret = labelName
if (node.optional)
ret += '?'
ret += ': '
ret += elementType
return ret
}
if (optionalMark?.length > 1) {
context.report({
node,
messageId: 'unexpectedSpaceBetween',
*fix(fixer) {
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()))
},
})
}
if (spaceBeforeColon?.length) {
context.report({
node,
messageId: 'unexpectedSpaceBefore',
*fix(fixer) {
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()))
},
})
}
if (spacesAfterColon != null && spacesAfterColon.length !== 1) {
context.report({
node,
messageId: 'expectedSpaceAfter',
*fix(fixer) {
yield fixer.replaceTextRange(node.range, code.replace(RE, getReplaceValue()))
},
})
}
},
}
},
})

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './no-cjs-exports'
const valids = [
@ -13,16 +12,14 @@ const invalids = [
{ code: 'module.exports.a = {}', filename: 'test.ts' },
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
...i,
errors: [{ messageId: 'noCjsExports' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
...i,
errors: [{ messageId: 'noCjsExports' }],
})),
})

View File

@ -10,7 +10,6 @@ export default createEslintRule<Options, MessageIds>({
type: 'problem',
docs: {
description: 'Do not use CJS exports',
recommended: false,
},
schema: [],
messages: {

View File

@ -0,0 +1,22 @@
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './no-const-enum'
const valids = [
'enum E {}',
]
const invalids = [
'const enum E {}',
]
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i,
errors: [{ messageId: 'noConstEnum' }],
})),
})

View File

@ -0,0 +1,33 @@
import { createEslintRule } from '../utils'
export const RULE_NAME = 'no-const-enum'
export type MessageIds = 'noConstEnum'
export type Options = []
export default createEslintRule<Options, MessageIds>({
name: RULE_NAME,
meta: {
type: 'problem',
docs: {
description: 'Disallow using `const enum` expression',
recommended: 'recommended',
},
schema: [],
messages: {
noConstEnum: 'Do not use `const enum` expression',
},
},
defaultOptions: [],
create: (context) => {
return {
TSEnumDeclaration: (node) => {
if (node.const) {
context.report({
node,
messageId: 'noConstEnum',
})
}
},
}
},
})

View File

@ -0,0 +1,28 @@
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './no-import-node-modules-by-path'
const valids = [
'import xxx from "a"',
'import "b"',
'const c = require("c")',
'require("d")',
]
const invalids = [
'import a from "../node_modules/a"',
'import "../node_modules/b"',
'const c = require("../node_modules/c")',
'require("../node_modules/d")',
]
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i,
errors: [{ messageId: 'noImportNodeModulesByPath' }],
})),
})

View File

@ -0,0 +1,42 @@
import { createEslintRule } from '../utils'
export const RULE_NAME = 'no-import-node-modules-by-path'
export type MessageIds = 'noImportNodeModulesByPath'
export type Options = []
export default createEslintRule<Options, MessageIds>({
name: RULE_NAME,
meta: {
type: 'problem',
docs: {
description: 'Prevent importing modules in `node_modules` folder by relative or absolute path',
recommended: 'recommended',
},
schema: [],
messages: {
noImportNodeModulesByPath: 'Do not import modules in `node_modules` folder by path',
},
},
defaultOptions: [],
create: (context) => {
return {
'ImportDeclaration': (node) => {
if (node.source.value.includes('/node_modules/')) {
context.report({
node,
messageId: 'noImportNodeModulesByPath',
})
}
},
'CallExpression[callee.name="require"]': (node: any) => {
const value = node.arguments[0]?.value
if (typeof value === 'string' && value.includes('/node_modules/')) {
context.report({
node,
messageId: 'noImportNodeModulesByPath',
})
}
},
}
},
})

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './no-ts-export-equal'
const valids = [
@ -11,16 +10,14 @@ const invalids = [
{ code: 'export = {}', filename: 'test.ts' },
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
...i,
errors: [{ messageId: 'noTsExportEqual' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
...i,
errors: [{ messageId: 'noTsExportEqual' }],
})),
})

View File

@ -10,7 +10,7 @@ export default createEslintRule<Options, MessageIds>({
type: 'problem',
docs: {
description: 'Do not use `exports =`',
recommended: false,
recommended: 'recommended',
},
schema: [],
messages: {

View File

@ -1,27 +1,25 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './prefer-inline-type-import'
const valids = [
'import { type Foo } from \'foo\'',
'import type Foo from \'foo\'',
'import type * as Foo from \'foo\'',
'import type {} from \'foo\'',
]
const invalids = [
['import type { Foo } from \'foo\'', 'import { type Foo } from \'foo\''],
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1].trim(),
errors: [{ messageId: 'preferInlineTypeImport' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1].trim(),
errors: [{ messageId: 'preferInlineTypeImport' }],
})),
})

View File

@ -1,7 +1,7 @@
// Ported from https://github.com/gajus/eslint-plugin-canonical/blob/master/src/rules/preferInlineTypeImport.js
// by Gajus Kuizinas https://github.com/gajus
import type { TSESTree } from '@typescript-eslint/utils'
import type { RuleFixer, SourceCode } from '@typescript-eslint/utils/dist/ts-eslint'
import type { RuleFixer, SourceCode } from '@typescript-eslint/utils/ts-eslint'
import { createEslintRule } from '../utils'
export const RULE_NAME = 'prefer-inline-type-import'
@ -14,7 +14,6 @@ export default createEslintRule<Options, MessageIds>({
type: 'suggestion',
docs: {
description: 'Inline type import',
recommended: 'error',
},
fixable: 'code',
schema: [],
@ -30,7 +29,7 @@ export default createEslintRule<Options, MessageIds>({
// ignore bare type imports
if (node.specifiers.length === 1 && ['ImportNamespaceSpecifier', 'ImportDefaultSpecifier'].includes(node.specifiers[0].type))
return
if (node.importKind === 'type') {
if (node.importKind === 'type' && node.specifiers.length > 0) {
context.report({
*fix(fixer) {
yield * removeTypeSpecifier(fixer, sourceCode, node)

View File

@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import { RuleTester } from '@typescript-eslint/rule-tester'
import rule, { RULE_NAME } from './top-level-function'
const valids = [
@ -51,17 +50,15 @@ const invalids = [
],
]
it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'topLevelFunctionDeclaration' }],
})),
})
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})
ruleTester.run(RULE_NAME, rule as any, {
valid: valids,
invalid: invalids.map(i => ({
code: i[0],
output: i[1],
errors: [{ messageId: 'topLevelFunctionDeclaration' }],
})),
})

View File

@ -10,7 +10,7 @@ export default createEslintRule<Options, MessageIds>({
type: 'problem',
docs: {
description: 'Enforce top-level functions to be declared with function keyword',
recommended: 'error',
recommended: 'stylistic',
},
fixable: 'code',
schema: [],

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
},
})

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,8 @@
"baseUrl": ".",
"target": "es2020",
"module": "es2020",
"moduleResolution": "node"
"moduleResolution": "Bundler",
"esModuleInterop": true
},
"include": [
"./packages/**/*.ts"