@kurateh/eslint-plugin 2.0.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +77 -0
- package/README.md +74 -5
- package/dist/{index.mjs → index.cjs} +92 -65
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +2 -12
- package/dist/index.js +78 -76
- package/package.json +30 -18
- package/dist/index.d.mts +0 -15
package/README.ko.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @kurateh/eslint-plugin
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | 한국어
|
|
4
|
+
|
|
5
|
+
개인적인 ESLint 규칙과 권장 설정을 포함하는 플러그인입니다.
|
|
6
|
+
|
|
7
|
+
## 환경 요구 사항
|
|
8
|
+
- **NodeJS**: >=22
|
|
9
|
+
- **ESLint**: >= 9 (Flat Config 전용)
|
|
10
|
+
- **TypeScript**: >= 5.7.2
|
|
11
|
+
|
|
12
|
+
## 1. 사용법
|
|
13
|
+
|
|
14
|
+
### 설치
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add -D @kurateh/eslint-plugin
|
|
17
|
+
# 또는
|
|
18
|
+
npm install --save-dev @kurateh/eslint-plugin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### ESLint 설정 (`eslint.config.mjs`)
|
|
22
|
+
이 플러그인은 ESLint Flat Config를 지원합니다. 다음과 같이 설정을 추가할 수 있습니다.
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import kuratehPlugin from "@kurateh/eslint-plugin";
|
|
26
|
+
|
|
27
|
+
export default [
|
|
28
|
+
// 권장 설정 적용
|
|
29
|
+
kuratehPlugin.configs.recommended,
|
|
30
|
+
|
|
31
|
+
// React 환경인 경우 추가 설정 적용
|
|
32
|
+
kuratehPlugin.configs.react,
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
plugins: {
|
|
36
|
+
"@kurateh": kuratehPlugin,
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
// 특정 규칙을 커스텀하고 싶은 경우
|
|
40
|
+
"@kurateh/import-path": "error",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 제공되는 설정
|
|
47
|
+
- `configs.recommended`: 일반적인 TypeScript 프로젝트를 위한 권장 설정 (Prettier 포함).
|
|
48
|
+
- `configs.react`: React 프로젝트를 위한 추가 설정 (Hooks 규칙 포함).
|
|
49
|
+
|
|
50
|
+
## 2. GitHub Actions를 통한 배포 방법
|
|
51
|
+
|
|
52
|
+
이 프로젝트는 GitHub Actions를 통해 NPM 저장소에 자동으로 배포됩니다.
|
|
53
|
+
|
|
54
|
+
### 배포 절차
|
|
55
|
+
1. **CHANGELOG.md 작성**: 배포 전에 `CHANGELOG.md`의 `## [Unreleased]` 섹션 아래에 이번 버전에 포함된 변경 사항을 기록합니다.
|
|
56
|
+
* **작성 예시**:
|
|
57
|
+
```markdown
|
|
58
|
+
## [Unreleased]
|
|
59
|
+
### Added
|
|
60
|
+
- 새로운 규칙 `@kurateh/new-rule` 추가
|
|
61
|
+
### Fixed
|
|
62
|
+
- `import-path` 규칙의 오탐 문제 수정
|
|
63
|
+
```
|
|
64
|
+
2. GitHub 저장소의 **Actions** 탭으로 이동합니다.
|
|
65
|
+
3. 왼쪽 워크플로우 목록에서 **Release package**를 선택합니다.
|
|
66
|
+
4. **Run workflow** 버튼을 클릭합니다.
|
|
67
|
+
5. 다음 옵션 중 하나를 선택하거나 입력합니다:
|
|
68
|
+
- **Release type**: `patch`, `minor`, `major` 중 하나를 선택하여 버전을 올립니다.
|
|
69
|
+
- **Custom version (선택 사항)**: 특정 버전으로 바로 배포하고 싶을 때 입력합니다 (예: `10.0.0`). 이 값을 입력하면 `Release type`은 무시됩니다.
|
|
70
|
+
6. **Run workflow**를 클릭하면 다음 과정이 자동으로 진행됩니다:
|
|
71
|
+
- 빌드 및 테스트 수행
|
|
72
|
+
- `CHANGELOG.md`의 `[Unreleased]` 섹션이 새 버전 번호로 업데이트됨
|
|
73
|
+
- `package.json` 버전 업데이트 및 변경 사항 커밋/태그 생성
|
|
74
|
+
- NPM 배포 및 GitHub Release 생성 (Changelog 내용이 Release 노트로 포함됨)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
**주의**: 배포를 위해서는 `NPMJS_ACCESS_TOKEN`이 GitHub Secrets에 등록되어 있어야 합니다.
|
package/README.md
CHANGED
|
@@ -1,8 +1,77 @@
|
|
|
1
1
|
# @kurateh/eslint-plugin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
- NodeJS: >=22
|
|
5
|
-
- ESLint: >= 9 (Flat Config)
|
|
6
|
-
- Typescript: >= 5.7.2
|
|
3
|
+
English | [한국어](./README.ko.md)
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
An ESLint plugin containing personal ESLint rules and recommended configurations.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
- **NodeJS**: >=22
|
|
9
|
+
- **ESLint**: >= 9 (Flat Config only)
|
|
10
|
+
- **TypeScript**: >= 5.7.2
|
|
11
|
+
|
|
12
|
+
## 1. Usage
|
|
13
|
+
|
|
14
|
+
### Installation
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add -D @kurateh/eslint-plugin
|
|
17
|
+
# or
|
|
18
|
+
npm install --save-dev @kurateh/eslint-plugin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### ESLint Configuration (`eslint.config.mjs`)
|
|
22
|
+
This plugin supports ESLint Flat Config. You can add configurations as follows:
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import kuratehPlugin from "@kurateh/eslint-plugin";
|
|
26
|
+
|
|
27
|
+
export default [
|
|
28
|
+
// Apply recommended configuration
|
|
29
|
+
kuratehPlugin.configs.recommended,
|
|
30
|
+
|
|
31
|
+
// Apply additional configuration for React environments
|
|
32
|
+
kuratehPlugin.configs.react,
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
plugins: {
|
|
36
|
+
"@kurateh": kuratehPlugin,
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
// Customize specific rules if needed
|
|
40
|
+
"@kurateh/import-path": "error",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Provided Configurations
|
|
47
|
+
- `configs.recommended`: Recommended configuration for general TypeScript projects (includes Prettier).
|
|
48
|
+
- `configs.react`: Additional configuration for React projects (includes React Hooks rules).
|
|
49
|
+
|
|
50
|
+
## 2. Deployment via GitHub Actions
|
|
51
|
+
|
|
52
|
+
This project is automatically deployed to the NPM registry via GitHub Actions.
|
|
53
|
+
|
|
54
|
+
### Deployment Process
|
|
55
|
+
1. **Update CHANGELOG.md**: Before deployment, record the changes for the new version under the `## [Unreleased]` section in `CHANGELOG.md`.
|
|
56
|
+
* **Writing Example**:
|
|
57
|
+
```markdown
|
|
58
|
+
## [Unreleased]
|
|
59
|
+
### Added
|
|
60
|
+
- New rule `@kurateh/new-rule`
|
|
61
|
+
### Fixed
|
|
62
|
+
- Fixed false positive in `import-path` rule
|
|
63
|
+
```
|
|
64
|
+
2. Go to the **Actions** tab of the GitHub repository.
|
|
65
|
+
3. Select **Release package** from the workflow list on the left.
|
|
66
|
+
4. Click the **Run workflow** button.
|
|
67
|
+
5. Select or enter one of the following options:
|
|
68
|
+
- **Release type**: Select one of `patch`, `minor`, `major` to bump the version.
|
|
69
|
+
- **Custom version (Optional)**: Enter a specific version to deploy immediately (e.g., `10.0.0`). If provided, `Release type` is ignored.
|
|
70
|
+
6. Click **Run workflow** to trigger the following automated steps:
|
|
71
|
+
- Run build and tests.
|
|
72
|
+
- Update the `[Unreleased]` section in `CHANGELOG.md` to the new version number.
|
|
73
|
+
- Update the version in `package.json`, commit changes, and create a tag.
|
|
74
|
+
- Publish to NPM and create a GitHub Release (Changelog content will be used as Release notes).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
**Note**: `NPMJS_ACCESS_TOKEN` must be registered in GitHub Secrets for successful deployment.
|
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
import react from 'eslint-plugin-react';
|
|
3
|
-
import reactHooks from 'eslint-plugin-react-hooks';
|
|
4
|
-
import globals from 'globals';
|
|
5
|
-
import js from '@eslint/js';
|
|
6
|
-
import importPlugin from 'eslint-plugin-import';
|
|
7
|
-
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
8
|
-
import unusedImportsPlugin from 'eslint-plugin-unused-imports';
|
|
9
|
-
import tseslint from 'typescript-eslint';
|
|
10
|
-
import { readFileSync, existsSync } from 'fs';
|
|
11
|
-
import { join, dirname, relative } from 'path';
|
|
12
|
-
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
1
|
+
'use strict';
|
|
13
2
|
|
|
14
|
-
|
|
15
|
-
var
|
|
16
|
-
var
|
|
17
|
-
var
|
|
18
|
-
var
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
var
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var react = require('eslint-plugin-react');
|
|
5
|
+
var reactHooks = require('eslint-plugin-react-hooks');
|
|
6
|
+
var globals = require('globals');
|
|
7
|
+
var js = require('@eslint/js');
|
|
8
|
+
var importPlugin = require('eslint-plugin-import');
|
|
9
|
+
var eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
|
|
10
|
+
var unusedImportsPlugin = require('eslint-plugin-unused-imports');
|
|
11
|
+
var tseslint = require('typescript-eslint');
|
|
12
|
+
var path = require('path');
|
|
13
|
+
var utils = require('@typescript-eslint/utils');
|
|
14
|
+
|
|
15
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
16
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
|
+
|
|
18
|
+
var react__default = /*#__PURE__*/_interopDefault(react);
|
|
19
|
+
var reactHooks__default = /*#__PURE__*/_interopDefault(reactHooks);
|
|
20
|
+
var globals__default = /*#__PURE__*/_interopDefault(globals);
|
|
21
|
+
var js__default = /*#__PURE__*/_interopDefault(js);
|
|
22
|
+
var importPlugin__default = /*#__PURE__*/_interopDefault(importPlugin);
|
|
23
|
+
var eslintPluginPrettierRecommended__default = /*#__PURE__*/_interopDefault(eslintPluginPrettierRecommended);
|
|
24
|
+
var unusedImportsPlugin__default = /*#__PURE__*/_interopDefault(unusedImportsPlugin);
|
|
25
|
+
var tseslint__default = /*#__PURE__*/_interopDefault(tseslint);
|
|
26
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
27
|
+
|
|
28
|
+
// src/index.ts
|
|
29
|
+
var createRule = utils.ESLintUtils.RuleCreator.withoutDocs;
|
|
32
30
|
|
|
33
31
|
// src/rules/import-path.ts
|
|
32
|
+
var posix = path__default.default.posix;
|
|
34
33
|
var TS_CONFIG_FILE_NAMES = ["tsconfig.path.json", "tsconfig.json"];
|
|
35
|
-
var has = (map,
|
|
34
|
+
var has = (map, path2) => {
|
|
36
35
|
let inner = map;
|
|
37
|
-
for (const step of
|
|
36
|
+
for (const step of path2.split(".")) {
|
|
38
37
|
inner = inner[step];
|
|
39
38
|
if (inner === void 0) {
|
|
40
39
|
return false;
|
|
@@ -42,28 +41,35 @@ var has = (map, path) => {
|
|
|
42
41
|
}
|
|
43
42
|
return true;
|
|
44
43
|
};
|
|
44
|
+
var normalizePath = (p) => p.replace(/\\/g, "/");
|
|
45
45
|
var findFilePath = (filename, initialPath) => {
|
|
46
46
|
let dir = initialPath;
|
|
47
|
+
let lastDir;
|
|
47
48
|
do {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
lastDir = dir;
|
|
50
|
+
dir = posix.dirname(dir);
|
|
51
|
+
} while (!fs.existsSync(path.join(dir, filename)) && dir !== lastDir);
|
|
52
|
+
const filePath = path.join(dir, filename);
|
|
53
|
+
if (!fs.existsSync(filePath)) {
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
|
-
return filePath;
|
|
56
|
+
return normalizePath(filePath);
|
|
55
57
|
};
|
|
56
58
|
var getAbsolutePathInfo = (fileName) => {
|
|
59
|
+
const normalizedFileName = normalizePath(fileName);
|
|
57
60
|
for (const configPath of TS_CONFIG_FILE_NAMES) {
|
|
58
|
-
const filePath = findFilePath(configPath,
|
|
61
|
+
const filePath = findFilePath(configPath, normalizedFileName);
|
|
59
62
|
if (filePath === void 0) {
|
|
60
63
|
continue;
|
|
61
64
|
}
|
|
62
|
-
const baseDir = dirname(filePath);
|
|
65
|
+
const baseDir = normalizePath(posix.dirname(filePath));
|
|
63
66
|
const tsPathConfig = JSON.parse(
|
|
64
|
-
readFileSync(filePath, {
|
|
67
|
+
fs.readFileSync(filePath, {
|
|
65
68
|
encoding: "utf-8"
|
|
66
|
-
}).replace(
|
|
69
|
+
}).replace(
|
|
70
|
+
/("(?:[^"\\]|\\.)*")|\/\/.*/g,
|
|
71
|
+
(_, string) => string || ""
|
|
72
|
+
).replace(
|
|
67
73
|
/("(?:[^"\\]|\\.)*")|\/\*[\s\S]*?\*\//g,
|
|
68
74
|
(_, string) => string || ""
|
|
69
75
|
).replace(/,(?=\s*[\]}])/g, "")
|
|
@@ -73,14 +79,18 @@ var getAbsolutePathInfo = (fileName) => {
|
|
|
73
79
|
paths: {}
|
|
74
80
|
};
|
|
75
81
|
if (has(tsPathConfig, "compilerOptions.baseUrl")) {
|
|
76
|
-
result.baseUrl =
|
|
82
|
+
result.baseUrl = normalizePath(
|
|
83
|
+
posix.join(baseDir, tsPathConfig.compilerOptions.baseUrl)
|
|
84
|
+
);
|
|
77
85
|
}
|
|
78
86
|
if (has(tsPathConfig, "compilerOptions.paths")) {
|
|
79
87
|
result.paths = Object.fromEntries(
|
|
80
88
|
Object.entries(tsPathConfig.compilerOptions.paths).map(
|
|
81
89
|
([key, value]) => [
|
|
82
90
|
key.replace(/\/\*$/, "/"),
|
|
83
|
-
value.map(
|
|
91
|
+
value.map(
|
|
92
|
+
(path2) => normalizePath(posix.join(baseDir, path2)).replace(/\/\*$/, "/")
|
|
93
|
+
)
|
|
84
94
|
]
|
|
85
95
|
)
|
|
86
96
|
);
|
|
@@ -104,20 +114,22 @@ var import_path_default = createRule({
|
|
|
104
114
|
},
|
|
105
115
|
defaultOptions: [],
|
|
106
116
|
create: (context) => {
|
|
117
|
+
const fileName = normalizePath(context.filename);
|
|
118
|
+
const absolutePathInfo = getAbsolutePathInfo(fileName);
|
|
107
119
|
return {
|
|
108
120
|
ImportDeclaration: (node) => {
|
|
109
|
-
const fileName = context.filename;
|
|
110
|
-
const absolutePathInfo = getAbsolutePathInfo(fileName);
|
|
111
121
|
if (absolutePathInfo === void 0) {
|
|
112
122
|
return;
|
|
113
123
|
}
|
|
114
124
|
const source = node.source.value;
|
|
115
125
|
if (source.startsWith("..")) {
|
|
116
|
-
const sourceAbsolutePath2 =
|
|
126
|
+
const sourceAbsolutePath2 = normalizePath(
|
|
127
|
+
posix.join(posix.dirname(fileName), source)
|
|
128
|
+
);
|
|
117
129
|
for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
|
|
118
|
-
for (const
|
|
119
|
-
if (sourceAbsolutePath2.startsWith(
|
|
120
|
-
const expectedPath2 = sourceAbsolutePath2.replace(
|
|
130
|
+
for (const path2 of paths) {
|
|
131
|
+
if (sourceAbsolutePath2.startsWith(path2)) {
|
|
132
|
+
const expectedPath2 = sourceAbsolutePath2.replace(path2, alias);
|
|
121
133
|
context.report({
|
|
122
134
|
node,
|
|
123
135
|
messageId: "shouldBeAbsolutePath",
|
|
@@ -137,9 +149,11 @@ var import_path_default = createRule({
|
|
|
137
149
|
}
|
|
138
150
|
let sourceAbsolutePath;
|
|
139
151
|
for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
|
|
140
|
-
for (const
|
|
152
|
+
for (const path2 of paths) {
|
|
141
153
|
if (source.startsWith(alias)) {
|
|
142
|
-
sourceAbsolutePath =
|
|
154
|
+
sourceAbsolutePath = normalizePath(
|
|
155
|
+
posix.join(path2, source.replace(alias, ""))
|
|
156
|
+
);
|
|
143
157
|
break;
|
|
144
158
|
}
|
|
145
159
|
}
|
|
@@ -150,9 +164,8 @@ var import_path_default = createRule({
|
|
|
150
164
|
if (sourceAbsolutePath === void 0) {
|
|
151
165
|
return;
|
|
152
166
|
}
|
|
153
|
-
const sourceRelativePath =
|
|
154
|
-
dirname(fileName),
|
|
155
|
-
sourceAbsolutePath
|
|
167
|
+
const sourceRelativePath = normalizePath(
|
|
168
|
+
posix.relative(posix.dirname(fileName), sourceAbsolutePath)
|
|
156
169
|
);
|
|
157
170
|
if (sourceRelativePath.startsWith("..")) {
|
|
158
171
|
return;
|
|
@@ -182,11 +195,11 @@ var rules_default = {
|
|
|
182
195
|
|
|
183
196
|
// src/configs/recommended.ts
|
|
184
197
|
var config = [
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
...
|
|
189
|
-
|
|
198
|
+
js__default.default.configs.recommended,
|
|
199
|
+
importPlugin__default.default.flatConfigs.recommended,
|
|
200
|
+
eslintPluginPrettierRecommended__default.default,
|
|
201
|
+
...tseslint__default.default.configs.recommended,
|
|
202
|
+
importPlugin__default.default.flatConfigs.typescript,
|
|
190
203
|
{
|
|
191
204
|
// ESLint config block에 file이 있으면 해당 파일을 검사할 차례가 와서야 plugin이 적용됨
|
|
192
205
|
// 따라서 이 Plugin을 끄려면 Config File에서 file: "~~"을 넣어야 됨
|
|
@@ -222,12 +235,16 @@ var config = [
|
|
|
222
235
|
}
|
|
223
236
|
},
|
|
224
237
|
plugins: {
|
|
225
|
-
"unused-imports":
|
|
238
|
+
"unused-imports": unusedImportsPlugin__default.default
|
|
226
239
|
},
|
|
227
240
|
languageOptions: {
|
|
228
241
|
ecmaVersion: "latest",
|
|
229
242
|
sourceType: "module",
|
|
230
|
-
globals:
|
|
243
|
+
globals: {
|
|
244
|
+
...globals__default.default.es2017,
|
|
245
|
+
...globals__default.default.browser,
|
|
246
|
+
...globals__default.default.node
|
|
247
|
+
}
|
|
231
248
|
},
|
|
232
249
|
rules: {
|
|
233
250
|
// eslint
|
|
@@ -323,8 +340,8 @@ var recommended_default = config;
|
|
|
323
340
|
// src/configs/react.ts
|
|
324
341
|
var config2 = [
|
|
325
342
|
...recommended_default,
|
|
326
|
-
|
|
327
|
-
|
|
343
|
+
react__default.default.configs.flat.recommended,
|
|
344
|
+
reactHooks__default.default.configs.flat.recommended,
|
|
328
345
|
{
|
|
329
346
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
330
347
|
languageOptions: {
|
|
@@ -333,7 +350,9 @@ var config2 = [
|
|
|
333
350
|
jsx: true
|
|
334
351
|
}
|
|
335
352
|
},
|
|
336
|
-
globals:
|
|
353
|
+
globals: {
|
|
354
|
+
...globals__default.default.browser
|
|
355
|
+
}
|
|
337
356
|
},
|
|
338
357
|
rules: {
|
|
339
358
|
"react/react-in-jsx-scope": 0,
|
|
@@ -361,7 +380,15 @@ var config2 = [
|
|
|
361
380
|
var react_default = config2;
|
|
362
381
|
|
|
363
382
|
// src/index.ts
|
|
383
|
+
var pkg = JSON.parse(
|
|
384
|
+
fs.readFileSync(new URL("../package.json", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))), "utf-8")
|
|
385
|
+
);
|
|
364
386
|
var plugin = {
|
|
387
|
+
meta: {
|
|
388
|
+
name: "eslint-plugin",
|
|
389
|
+
namespace: "@kurateh",
|
|
390
|
+
version: pkg.version
|
|
391
|
+
},
|
|
365
392
|
configs: {
|
|
366
393
|
recommended: recommended_default,
|
|
367
394
|
react: react_default
|
|
@@ -370,4 +397,4 @@ var plugin = {
|
|
|
370
397
|
};
|
|
371
398
|
var index_default = plugin;
|
|
372
399
|
|
|
373
|
-
|
|
400
|
+
module.exports = index_default;
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ESLint } from 'eslint';
|
|
2
2
|
|
|
3
|
-
declare const plugin:
|
|
4
|
-
configs: {
|
|
5
|
-
recommended: (eslint.Linter.Config<eslint.Linter.RulesRecord> | {
|
|
6
|
-
readonly rules: Readonly<eslint.Linter.RulesRecord>;
|
|
7
|
-
})[];
|
|
8
|
-
react: (eslint.Linter.Config<eslint.Linter.RulesRecord> | {
|
|
9
|
-
readonly rules: Readonly<eslint.Linter.RulesRecord>;
|
|
10
|
-
})[];
|
|
11
|
-
};
|
|
12
|
-
rules: Record<string, eslint.Rule.RuleModule>;
|
|
13
|
-
};
|
|
3
|
+
declare const plugin: ESLint.Plugin;
|
|
14
4
|
|
|
15
5
|
export { plugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1,51 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { readFileSync, existsSync } from 'fs';
|
|
3
|
+
import react from 'eslint-plugin-react';
|
|
4
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
5
|
+
import globals from 'globals';
|
|
6
|
+
import js from '@eslint/js';
|
|
7
|
+
import importPlugin from 'eslint-plugin-import';
|
|
8
|
+
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
|
9
|
+
import unusedImportsPlugin from 'eslint-plugin-unused-imports';
|
|
10
|
+
import tseslint from 'typescript-eslint';
|
|
11
|
+
import path, { join } from 'path';
|
|
12
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
13
|
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var globals = require('globals');
|
|
6
|
-
var js = require('@eslint/js');
|
|
7
|
-
var importPlugin = require('eslint-plugin-import');
|
|
8
|
-
var eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
|
|
9
|
-
var unusedImportsPlugin = require('eslint-plugin-unused-imports');
|
|
10
|
-
var tseslint = require('typescript-eslint');
|
|
11
|
-
var fs = require('fs');
|
|
12
|
-
var path = require('path');
|
|
13
|
-
var utils = require('@typescript-eslint/utils');
|
|
14
|
-
|
|
15
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
-
|
|
17
|
-
var react__default = /*#__PURE__*/_interopDefault(react);
|
|
18
|
-
var reactHooks__default = /*#__PURE__*/_interopDefault(reactHooks);
|
|
19
|
-
var globals__default = /*#__PURE__*/_interopDefault(globals);
|
|
20
|
-
var js__default = /*#__PURE__*/_interopDefault(js);
|
|
21
|
-
var importPlugin__default = /*#__PURE__*/_interopDefault(importPlugin);
|
|
22
|
-
var eslintPluginPrettierRecommended__default = /*#__PURE__*/_interopDefault(eslintPluginPrettierRecommended);
|
|
23
|
-
var unusedImportsPlugin__default = /*#__PURE__*/_interopDefault(unusedImportsPlugin);
|
|
24
|
-
var tseslint__default = /*#__PURE__*/_interopDefault(tseslint);
|
|
25
|
-
|
|
26
|
-
var __defProp = Object.defineProperty;
|
|
27
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
28
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
29
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
30
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
31
|
-
var __spreadValues = (a, b) => {
|
|
32
|
-
for (var prop in b || (b = {}))
|
|
33
|
-
if (__hasOwnProp.call(b, prop))
|
|
34
|
-
__defNormalProp(a, prop, b[prop]);
|
|
35
|
-
if (__getOwnPropSymbols)
|
|
36
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
37
|
-
if (__propIsEnum.call(b, prop))
|
|
38
|
-
__defNormalProp(a, prop, b[prop]);
|
|
39
|
-
}
|
|
40
|
-
return a;
|
|
41
|
-
};
|
|
42
|
-
var createRule = utils.ESLintUtils.RuleCreator.withoutDocs;
|
|
14
|
+
createRequire(import.meta.url);
|
|
15
|
+
var createRule = ESLintUtils.RuleCreator.withoutDocs;
|
|
43
16
|
|
|
44
17
|
// src/rules/import-path.ts
|
|
18
|
+
var posix = path.posix;
|
|
45
19
|
var TS_CONFIG_FILE_NAMES = ["tsconfig.path.json", "tsconfig.json"];
|
|
46
|
-
var has = (map,
|
|
20
|
+
var has = (map, path2) => {
|
|
47
21
|
let inner = map;
|
|
48
|
-
for (const step of
|
|
22
|
+
for (const step of path2.split(".")) {
|
|
49
23
|
inner = inner[step];
|
|
50
24
|
if (inner === void 0) {
|
|
51
25
|
return false;
|
|
@@ -53,28 +27,35 @@ var has = (map, path) => {
|
|
|
53
27
|
}
|
|
54
28
|
return true;
|
|
55
29
|
};
|
|
30
|
+
var normalizePath = (p) => p.replace(/\\/g, "/");
|
|
56
31
|
var findFilePath = (filename, initialPath) => {
|
|
57
32
|
let dir = initialPath;
|
|
33
|
+
let lastDir;
|
|
58
34
|
do {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
35
|
+
lastDir = dir;
|
|
36
|
+
dir = posix.dirname(dir);
|
|
37
|
+
} while (!existsSync(join(dir, filename)) && dir !== lastDir);
|
|
38
|
+
const filePath = join(dir, filename);
|
|
39
|
+
if (!existsSync(filePath)) {
|
|
63
40
|
return;
|
|
64
41
|
}
|
|
65
|
-
return filePath;
|
|
42
|
+
return normalizePath(filePath);
|
|
66
43
|
};
|
|
67
44
|
var getAbsolutePathInfo = (fileName) => {
|
|
45
|
+
const normalizedFileName = normalizePath(fileName);
|
|
68
46
|
for (const configPath of TS_CONFIG_FILE_NAMES) {
|
|
69
|
-
const filePath = findFilePath(configPath,
|
|
47
|
+
const filePath = findFilePath(configPath, normalizedFileName);
|
|
70
48
|
if (filePath === void 0) {
|
|
71
49
|
continue;
|
|
72
50
|
}
|
|
73
|
-
const baseDir =
|
|
51
|
+
const baseDir = normalizePath(posix.dirname(filePath));
|
|
74
52
|
const tsPathConfig = JSON.parse(
|
|
75
|
-
|
|
53
|
+
readFileSync(filePath, {
|
|
76
54
|
encoding: "utf-8"
|
|
77
|
-
}).replace(
|
|
55
|
+
}).replace(
|
|
56
|
+
/("(?:[^"\\]|\\.)*")|\/\/.*/g,
|
|
57
|
+
(_, string) => string || ""
|
|
58
|
+
).replace(
|
|
78
59
|
/("(?:[^"\\]|\\.)*")|\/\*[\s\S]*?\*\//g,
|
|
79
60
|
(_, string) => string || ""
|
|
80
61
|
).replace(/,(?=\s*[\]}])/g, "")
|
|
@@ -84,14 +65,18 @@ var getAbsolutePathInfo = (fileName) => {
|
|
|
84
65
|
paths: {}
|
|
85
66
|
};
|
|
86
67
|
if (has(tsPathConfig, "compilerOptions.baseUrl")) {
|
|
87
|
-
result.baseUrl =
|
|
68
|
+
result.baseUrl = normalizePath(
|
|
69
|
+
posix.join(baseDir, tsPathConfig.compilerOptions.baseUrl)
|
|
70
|
+
);
|
|
88
71
|
}
|
|
89
72
|
if (has(tsPathConfig, "compilerOptions.paths")) {
|
|
90
73
|
result.paths = Object.fromEntries(
|
|
91
74
|
Object.entries(tsPathConfig.compilerOptions.paths).map(
|
|
92
75
|
([key, value]) => [
|
|
93
76
|
key.replace(/\/\*$/, "/"),
|
|
94
|
-
value.map(
|
|
77
|
+
value.map(
|
|
78
|
+
(path2) => normalizePath(posix.join(baseDir, path2)).replace(/\/\*$/, "/")
|
|
79
|
+
)
|
|
95
80
|
]
|
|
96
81
|
)
|
|
97
82
|
);
|
|
@@ -115,20 +100,22 @@ var import_path_default = createRule({
|
|
|
115
100
|
},
|
|
116
101
|
defaultOptions: [],
|
|
117
102
|
create: (context) => {
|
|
103
|
+
const fileName = normalizePath(context.filename);
|
|
104
|
+
const absolutePathInfo = getAbsolutePathInfo(fileName);
|
|
118
105
|
return {
|
|
119
106
|
ImportDeclaration: (node) => {
|
|
120
|
-
const fileName = context.filename;
|
|
121
|
-
const absolutePathInfo = getAbsolutePathInfo(fileName);
|
|
122
107
|
if (absolutePathInfo === void 0) {
|
|
123
108
|
return;
|
|
124
109
|
}
|
|
125
110
|
const source = node.source.value;
|
|
126
111
|
if (source.startsWith("..")) {
|
|
127
|
-
const sourceAbsolutePath2 =
|
|
112
|
+
const sourceAbsolutePath2 = normalizePath(
|
|
113
|
+
posix.join(posix.dirname(fileName), source)
|
|
114
|
+
);
|
|
128
115
|
for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
|
|
129
|
-
for (const
|
|
130
|
-
if (sourceAbsolutePath2.startsWith(
|
|
131
|
-
const expectedPath2 = sourceAbsolutePath2.replace(
|
|
116
|
+
for (const path2 of paths) {
|
|
117
|
+
if (sourceAbsolutePath2.startsWith(path2)) {
|
|
118
|
+
const expectedPath2 = sourceAbsolutePath2.replace(path2, alias);
|
|
132
119
|
context.report({
|
|
133
120
|
node,
|
|
134
121
|
messageId: "shouldBeAbsolutePath",
|
|
@@ -148,9 +135,11 @@ var import_path_default = createRule({
|
|
|
148
135
|
}
|
|
149
136
|
let sourceAbsolutePath;
|
|
150
137
|
for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
|
|
151
|
-
for (const
|
|
138
|
+
for (const path2 of paths) {
|
|
152
139
|
if (source.startsWith(alias)) {
|
|
153
|
-
sourceAbsolutePath =
|
|
140
|
+
sourceAbsolutePath = normalizePath(
|
|
141
|
+
posix.join(path2, source.replace(alias, ""))
|
|
142
|
+
);
|
|
154
143
|
break;
|
|
155
144
|
}
|
|
156
145
|
}
|
|
@@ -161,9 +150,8 @@ var import_path_default = createRule({
|
|
|
161
150
|
if (sourceAbsolutePath === void 0) {
|
|
162
151
|
return;
|
|
163
152
|
}
|
|
164
|
-
const sourceRelativePath =
|
|
165
|
-
|
|
166
|
-
sourceAbsolutePath
|
|
153
|
+
const sourceRelativePath = normalizePath(
|
|
154
|
+
posix.relative(posix.dirname(fileName), sourceAbsolutePath)
|
|
167
155
|
);
|
|
168
156
|
if (sourceRelativePath.startsWith("..")) {
|
|
169
157
|
return;
|
|
@@ -193,11 +181,11 @@ var rules_default = {
|
|
|
193
181
|
|
|
194
182
|
// src/configs/recommended.ts
|
|
195
183
|
var config = [
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
...
|
|
200
|
-
|
|
184
|
+
js.configs.recommended,
|
|
185
|
+
importPlugin.flatConfigs.recommended,
|
|
186
|
+
eslintPluginPrettierRecommended,
|
|
187
|
+
...tseslint.configs.recommended,
|
|
188
|
+
importPlugin.flatConfigs.typescript,
|
|
201
189
|
{
|
|
202
190
|
// ESLint config block에 file이 있으면 해당 파일을 검사할 차례가 와서야 plugin이 적용됨
|
|
203
191
|
// 따라서 이 Plugin을 끄려면 Config File에서 file: "~~"을 넣어야 됨
|
|
@@ -233,12 +221,16 @@ var config = [
|
|
|
233
221
|
}
|
|
234
222
|
},
|
|
235
223
|
plugins: {
|
|
236
|
-
"unused-imports":
|
|
224
|
+
"unused-imports": unusedImportsPlugin
|
|
237
225
|
},
|
|
238
226
|
languageOptions: {
|
|
239
227
|
ecmaVersion: "latest",
|
|
240
228
|
sourceType: "module",
|
|
241
|
-
globals:
|
|
229
|
+
globals: {
|
|
230
|
+
...globals.es2017,
|
|
231
|
+
...globals.browser,
|
|
232
|
+
...globals.node
|
|
233
|
+
}
|
|
242
234
|
},
|
|
243
235
|
rules: {
|
|
244
236
|
// eslint
|
|
@@ -334,8 +326,8 @@ var recommended_default = config;
|
|
|
334
326
|
// src/configs/react.ts
|
|
335
327
|
var config2 = [
|
|
336
328
|
...recommended_default,
|
|
337
|
-
|
|
338
|
-
|
|
329
|
+
react.configs.flat.recommended,
|
|
330
|
+
reactHooks.configs.flat.recommended,
|
|
339
331
|
{
|
|
340
332
|
files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
|
|
341
333
|
languageOptions: {
|
|
@@ -344,7 +336,9 @@ var config2 = [
|
|
|
344
336
|
jsx: true
|
|
345
337
|
}
|
|
346
338
|
},
|
|
347
|
-
globals:
|
|
339
|
+
globals: {
|
|
340
|
+
...globals.browser
|
|
341
|
+
}
|
|
348
342
|
},
|
|
349
343
|
rules: {
|
|
350
344
|
"react/react-in-jsx-scope": 0,
|
|
@@ -372,7 +366,15 @@ var config2 = [
|
|
|
372
366
|
var react_default = config2;
|
|
373
367
|
|
|
374
368
|
// src/index.ts
|
|
369
|
+
var pkg = JSON.parse(
|
|
370
|
+
readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
371
|
+
);
|
|
375
372
|
var plugin = {
|
|
373
|
+
meta: {
|
|
374
|
+
name: "eslint-plugin",
|
|
375
|
+
namespace: "@kurateh",
|
|
376
|
+
version: pkg.version
|
|
377
|
+
},
|
|
376
378
|
configs: {
|
|
377
379
|
recommended: recommended_default,
|
|
378
380
|
react: react_default
|
|
@@ -381,4 +383,4 @@ var plugin = {
|
|
|
381
383
|
};
|
|
382
384
|
var index_default = plugin;
|
|
383
385
|
|
|
384
|
-
|
|
386
|
+
export { index_default as default };
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kurateh/eslint-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "kurateh",
|
|
7
|
+
"email": "me@kurateh.com"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"url": "https://github.com/kurateh/eslint-plugin"
|
|
11
|
+
},
|
|
4
12
|
"exports": {
|
|
5
13
|
".": {
|
|
6
|
-
"import": "./dist/index.
|
|
7
|
-
"require": "./dist/index.
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
8
16
|
}
|
|
9
17
|
},
|
|
10
18
|
"files": [
|
|
@@ -20,28 +28,30 @@
|
|
|
20
28
|
},
|
|
21
29
|
"devDependencies": {
|
|
22
30
|
"@kurateh/eslint-plugin": "file:",
|
|
23
|
-
"@types/node": "
|
|
24
|
-
"@types/react": "^19.2.
|
|
25
|
-
"eslint": "
|
|
26
|
-
"
|
|
27
|
-
"
|
|
31
|
+
"@types/node": "~24",
|
|
32
|
+
"@types/react": "^19.2.14",
|
|
33
|
+
"@typescript-eslint/rule-tester": "^8.59.0",
|
|
34
|
+
"eslint": "~10.2.1",
|
|
35
|
+
"prettier": "^3.8.3",
|
|
36
|
+
"react": "^19.2.5",
|
|
28
37
|
"tsup": "^8.5.1",
|
|
29
|
-
"typescript": "^
|
|
38
|
+
"typescript": "^6.0.3",
|
|
39
|
+
"vitest": "^4.1.5"
|
|
30
40
|
},
|
|
31
41
|
"dependencies": {
|
|
32
|
-
"@eslint/js": "^
|
|
33
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
34
|
-
"@typescript-eslint/parser": "^8.
|
|
35
|
-
"@typescript-eslint/utils": "^8.
|
|
42
|
+
"@eslint/js": "^10.0.1",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
44
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
45
|
+
"@typescript-eslint/utils": "^8.59.0",
|
|
36
46
|
"eslint-config-prettier": "^10.1.8",
|
|
37
47
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
38
48
|
"eslint-plugin-import": "^2.32.0",
|
|
39
|
-
"eslint-plugin-prettier": "^5.5.
|
|
49
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
40
50
|
"eslint-plugin-react": "^7.37.5",
|
|
41
|
-
"eslint-plugin-react-hooks": "^7.
|
|
42
|
-
"eslint-plugin-unused-imports": "^4.
|
|
43
|
-
"globals": "^
|
|
44
|
-
"typescript-eslint": "^8.
|
|
51
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
52
|
+
"eslint-plugin-unused-imports": "^4.4.1",
|
|
53
|
+
"globals": "^17.5.0",
|
|
54
|
+
"typescript-eslint": "^8.59.0"
|
|
45
55
|
},
|
|
46
56
|
"peerDependencies": {
|
|
47
57
|
"eslint": ">=9"
|
|
@@ -49,7 +59,9 @@
|
|
|
49
59
|
"scripts": {
|
|
50
60
|
"build": "tsup",
|
|
51
61
|
"lint": "eslint .",
|
|
62
|
+
"format": "prettier --write .",
|
|
52
63
|
"type-check": "tsc --noEmit",
|
|
64
|
+
"test": "vitest run",
|
|
53
65
|
"version": "npm version"
|
|
54
66
|
}
|
|
55
67
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as eslint from 'eslint';
|
|
2
|
-
|
|
3
|
-
declare const plugin: {
|
|
4
|
-
configs: {
|
|
5
|
-
recommended: (eslint.Linter.Config<eslint.Linter.RulesRecord> | {
|
|
6
|
-
readonly rules: Readonly<eslint.Linter.RulesRecord>;
|
|
7
|
-
})[];
|
|
8
|
-
react: (eslint.Linter.Config<eslint.Linter.RulesRecord> | {
|
|
9
|
-
readonly rules: Readonly<eslint.Linter.RulesRecord>;
|
|
10
|
-
})[];
|
|
11
|
-
};
|
|
12
|
-
rules: Record<string, eslint.Rule.RuleModule>;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export { plugin as default };
|