@simplysm/lint 13.0.85 → 13.0.86

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.
Files changed (2) hide show
  1. package/README.md +222 -96
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,164 +1,290 @@
1
1
  # @simplysm/lint
2
2
 
3
- Shared ESLint configuration and custom ESLint plugin for the Simplysm monorepo. Provides a recommended flat config with rules for TypeScript, SolidJS, Tailwind CSS, and import hygiene, plus three custom rules.
3
+ Simplysm 프로젝트용 ESLint 설정과 커스텀 규칙 패키지. ESLint v9 flat config 기반.
4
4
 
5
- ## Installation
5
+ ## 설치
6
6
 
7
7
  ```bash
8
- npm install @simplysm/lint
9
- # or
10
8
  pnpm add @simplysm/lint
11
9
  ```
12
10
 
13
- ### Peer Dependencies
11
+ ## 엔트리포인트
14
12
 
15
- This package depends on the following (installed as direct dependencies):
16
-
17
- - `eslint` >= 9
18
- - `typescript` >= 5
19
- - `typescript-eslint` >= 8
20
-
21
- ## Exports
22
-
23
- | Export path | Description |
13
+ | Export 경로 | 설명 |
24
14
  |---|---|
25
- | `@simplysm/lint/eslint-plugin` | Custom ESLint plugin object (`rules` map) |
26
- | `@simplysm/lint/eslint-recommended` | Ready-to-use ESLint flat config array |
27
-
28
- ---
15
+ | `@simplysm/lint/eslint-recommended` | 권장 ESLint flat config 배열 (규칙 프리셋) |
16
+ | `@simplysm/lint/eslint-plugin` | 커스텀 ESLint 플러그인 (`@simplysm/*` 규칙) |
29
17
 
30
- ## Recommended Config
18
+ ## 사용법
31
19
 
32
- **`@simplysm/lint/eslint-recommended`**
20
+ ### 권장 설정 적용 (eslint-recommended)
33
21
 
34
- A complete ESLint flat config (compatible with ESLint v9 flat config format) that you can spread directly into your `eslint.config.ts`.
22
+ 프로젝트의 `eslint.config.js`에서 가져와 사용한다.
35
23
 
36
24
  ```typescript
37
- // eslint.config.ts
38
- import recommended from "@simplysm/lint/eslint-recommended";
25
+ // eslint.config.js
26
+ import eslintRecommended from "@simplysm/lint/eslint-recommended";
39
27
 
40
28
  export default [
41
- ...recommended,
42
- // your project-specific overrides
29
+ ...eslintRecommended,
30
+ // 추가 설정 오버라이드
43
31
  ];
44
32
  ```
45
33
 
46
- ### What it includes
34
+ 설정에는 아래의 모든 규칙이 사전 구성되어 있으므로 별도로 플러그인을 등록할 필요가 없다.
47
35
 
48
- #### Global ignores
36
+ ### 플러그인 단독 사용 (eslint-plugin)
49
37
 
50
- Ignores `node_modules/`, `dist/`, dotfile directories (`.*`), and underscore-prefixed directories (`_*`).
38
+ 커스텀 규칙만 개별적으로 사용하려면 플러그인을 직접 등록한다.
51
39
 
52
- #### JS / JSX files (`**/*.js`, `**/*.jsx`)
40
+ ```typescript
41
+ import plugin from "@simplysm/lint/eslint-plugin";
53
42
 
54
- - **Common rules**: `no-console`, `eqeqeq` (strict equality, `== null` allowed), `no-self-compare`, `array-callback-return`, `no-warning-comments` (warn on TODO/FIXME).
55
- - **Unused imports**: Auto-removes unused imports; allows `_`-prefixed unused variables.
56
- - **Import hygiene**: `import/no-extraneous-dependencies` with dev-dependency exceptions for config files.
57
- - **Custom rules**: `@simplysm/no-hard-private` (error), `@simplysm/no-subpath-imports-from-simplysm` (error).
58
- - **Node built-in restrictions**: Prohibits `Buffer` (use `Uint8Array`), `events`/`eventemitter3` (use `@simplysm/core-common` EventEmitter).
43
+ export default [
44
+ {
45
+ plugins: {
46
+ "@simplysm": plugin,
47
+ },
48
+ rules: {
49
+ "@simplysm/no-hard-private": "error",
50
+ "@simplysm/no-subpath-imports-from-simplysm": "error",
51
+ "@simplysm/ts-no-throw-not-implemented-error": "warn",
52
+ },
53
+ },
54
+ ];
55
+ ```
59
56
 
60
- #### TS / TSX files (`**/*.ts`, `**/*.tsx`)
57
+ ## 권장 설정 구성 (eslint-recommended)
61
58
 
62
- Includes all JS rules above, plus:
59
+ `eslint-recommended`는 `defineConfig()`으로 구성된 flat config 배열이다. 파일 타입별로 다른 규칙 세트가 적용된다.
63
60
 
64
- - **TypeScript-specific rules** (via `typescript-eslint`):
65
- - `require-await`, `await-thenable`, `return-await` (in try-catch), `no-floating-promises`
66
- - `no-shadow`, `no-unnecessary-condition`, `no-unnecessary-type-assertion`
67
- - `prefer-reduce-type-parameter`, `prefer-return-this-type`, `prefer-readonly`
68
- - `strict-boolean-expressions` (nullable boolean/object allowed)
69
- - `no-misused-promises` (void return arguments and attributes allowed)
70
- - `only-throw-error`, `no-array-delete`, `no-unused-expressions`
71
- - `ban-ts-comment` (`ts-expect-error` allowed with description >= 3 chars)
72
- - **Custom rules**: All JS custom rules plus `@simplysm/ts-no-throw-not-implemented-error` (warn).
61
+ ### 글로벌 무시 패턴
73
62
 
74
- #### Test files (`**/tests/**`, `**/tests-e2e/**`)
63
+ ```
64
+ **/node_modules/**, **/dist/**, **/.*/**, **/_*/**
65
+ ```
75
66
 
76
- Relaxes some rules for test code:
67
+ ### 공통 규칙 (JS/TS 모두 적용)
68
+
69
+ | 규칙 | 수준 | 설명 |
70
+ |---|---|---|
71
+ | `no-console` | error | `console.*` 사용 금지 |
72
+ | `no-warning-comments` | warn | TODO/FIXME 주석 경고 |
73
+ | `eqeqeq` | error | `===` 강제 (`== null`만 허용) |
74
+ | `no-self-compare` | error | 자기 자신과의 비교 방지 |
75
+ | `array-callback-return` | error | map/filter 콜백에서 return 누락 방지 |
76
+
77
+ ### Node 빌트인 제한 규칙
78
+
79
+ | 규칙 | 대상 | 대안 |
80
+ |---|---|---|
81
+ | `Buffer` 전역 변수 | `no-restricted-globals` | `Uint8Array` 또는 `BytesUtils` 사용 |
82
+ | `buffer` 모듈 import | `no-restricted-imports` | `Uint8Array` 또는 `BytesUtils` 사용 |
83
+ | `events` 모듈 import | `no-restricted-imports` | `@simplysm/core-common`의 `EventEmitter` 사용 |
84
+ | `eventemitter3` import | `no-restricted-imports` | `@simplysm/core-common`의 `EventEmitter` 사용 |
85
+
86
+ ### JS 전용 규칙 (*.js, *.jsx)
87
+
88
+ 공통 규칙에 추가로 `require-await`, `no-shadow`, `no-duplicate-imports`, `no-unused-expressions`, `no-undef`가 적용된다.
89
+
90
+ ### TypeScript 전용 규칙 (*.ts, *.tsx)
91
+
92
+ 공통 규칙에 추가로 TypeScript 전용 규칙이 적용된다. `typescript-eslint` 파서를 사용하며 프로젝트 타입 정보가 필요하다 (`project: true`).
93
+
94
+ | 규칙 | 수준 | 설명 |
95
+ |---|---|---|
96
+ | `@typescript-eslint/require-await` | error | async 함수에 await 필수 |
97
+ | `@typescript-eslint/await-thenable` | error | thenable이 아닌 값에 await 금지 |
98
+ | `@typescript-eslint/return-await` | error | try-catch 내에서만 return await 허용 |
99
+ | `@typescript-eslint/no-floating-promises` | error | Promise를 반드시 await 또는 void 처리 |
100
+ | `@typescript-eslint/no-shadow` | error | 변수 섀도잉 금지 |
101
+ | `@typescript-eslint/no-unnecessary-condition` | error | 불필요한 조건 검사 금지 (상수 루프 허용) |
102
+ | `@typescript-eslint/no-unnecessary-type-assertion` | error | 불필요한 타입 단언 금지 |
103
+ | `@typescript-eslint/prefer-reduce-type-parameter` | error | reduce 타입 파라미터 사용 권장 |
104
+ | `@typescript-eslint/prefer-return-this-type` | error | this 반환 타입 사용 권장 |
105
+ | `@typescript-eslint/no-unused-expressions` | error | 미사용 표현식 금지 |
106
+ | `@typescript-eslint/strict-boolean-expressions` | error | 엄격한 boolean 표현식 (nullable boolean/object 허용) |
107
+ | `@typescript-eslint/ban-ts-comment` | error | `@ts-expect-error`만 설명 포함 시 허용 |
108
+ | `@typescript-eslint/prefer-readonly` | error | 재할당하지 않는 속성에 readonly 강제 |
109
+ | `@typescript-eslint/no-misused-promises` | error | void 콜백에 async 함수 전달 방지 (arguments/attributes 제외) |
110
+ | `@typescript-eslint/only-throw-error` | error | Error 객체만 throw 허용 |
111
+ | `@typescript-eslint/no-array-delete` | error | 배열에 delete 사용 금지 |
112
+
113
+ ### 미사용 import 규칙
114
+
115
+ | 규칙 | 수준 | 설명 |
116
+ |---|---|---|
117
+ | `unused-imports/no-unused-imports` | error | 미사용 import 자동 제거 |
118
+ | `unused-imports/no-unused-vars` | error | 미사용 변수 금지 (`_` 접두사 허용) |
119
+
120
+ ### SolidJS 규칙 (*.ts, *.tsx)
121
+
122
+ | 규칙 | 수준 | 설명 |
123
+ |---|---|---|
124
+ | `solid/no-destructure` | error | Props 구조분해 금지 (반응성 손실 방지) |
125
+ | `solid/components-return-once` | error | 컴포넌트 단일 반환 강제 |
126
+ | `solid/jsx-no-duplicate-props` | error | 중복 props 금지 |
127
+ | `solid/jsx-no-undef` | error | 미정의 변수 참조 금지 (TS 지원) |
128
+ | `solid/no-react-deps` | error | React 의존성 배열 패턴 금지 |
129
+ | `solid/no-react-specific-props` | error | React 전용 props 금지 (className 등) |
130
+ | `solid/no-innerhtml` | error | innerHTML 사용 금지 (XSS 방지) |
131
+ | `solid/jsx-no-script-url` | error | `javascript:` URL 금지 |
132
+ | `solid/jsx-uses-vars` | error | JSX 변수 사용 추적 |
133
+ | `solid/prefer-for` | error | `.map()` 대신 `<For>` 컴포넌트 사용 |
134
+ | `solid/event-handlers` | error | 이벤트 핸들러 네이밍 규칙 |
135
+ | `solid/imports` | error | import 일관성 |
136
+ | `solid/style-prop` | error | style prop 형식 |
137
+ | `solid/self-closing-comp` | error | 셀프 클로징 태그 |
138
+
139
+ ### Tailwind CSS 규칙 (*.ts, *.tsx)
140
+
141
+ `clsx` 템플릿 리터럴 태그를 지원한다.
142
+
143
+ | 규칙 | 수준 | 설명 |
144
+ |---|---|---|
145
+ | `tailwindcss/classnames-order` | warn | 클래스 순서 자동 정렬 |
146
+ | `tailwindcss/enforces-negative-arbitrary-values` | error | 음수 임의 값 형식 통일 |
147
+ | `tailwindcss/enforces-shorthand` | error | 축약형 사용 권장 |
148
+ | `tailwindcss/no-contradicting-classname` | error | 충돌 클래스 금지 (`p-2 p-4` 등) |
149
+ | `tailwindcss/no-custom-classname` | error | Tailwind 외 커스텀 클래스 금지 |
150
+ | `tailwindcss/no-unnecessary-arbitrary-value` | error | 불필요한 임의 값 금지 |
151
+
152
+ ### 테스트 파일 오버라이드
153
+
154
+ `**/tests/**`, `**/tests-e2e/**` 경로의 파일에는 다음 규칙이 완화된다:
77
155
 
78
156
  - `no-console`: off
79
157
  - `import/no-extraneous-dependencies`: off
80
158
  - `@simplysm/ts-no-throw-not-implemented-error`: off
81
159
 
82
- #### SolidJS (`**/*.ts`, `**/*.tsx`)
83
-
84
- - **eslint-plugin-solid** rules: `no-destructure`, `components-return-once`, `jsx-no-duplicate-props`, `jsx-no-undef`, `no-react-deps`, `no-react-specific-props`, `no-innerhtml`, `jsx-no-script-url`, `jsx-uses-vars`, `prefer-for`, `event-handlers`, `imports`, `style-prop`, `self-closing-comp`.
85
- - **eslint-plugin-tailwindcss** rules: `classnames-order` (warn), `enforces-negative-arbitrary-values`, `enforces-shorthand`, `no-contradicting-classname`, `no-custom-classname`, `no-unnecessary-arbitrary-value`.
86
-
87
- ---
88
-
89
- ## Custom Plugin
90
-
91
- **`@simplysm/lint/eslint-plugin`**
92
-
93
- An ESLint plugin object that exposes three custom rules under the `@simplysm` namespace.
160
+ ## 커스텀 규칙 상세
94
161
 
95
- ```typescript
96
- import plugin from "@simplysm/lint/eslint-plugin";
97
-
98
- // plugin.rules contains:
99
- // - "no-hard-private"
100
- // - "no-subpath-imports-from-simplysm"
101
- // - "ts-no-throw-not-implemented-error"
102
- ```
162
+ ### @simplysm/no-hard-private
103
163
 
104
- ### Rules
164
+ ECMAScript `#private` 필드/메서드 대신 TypeScript `private _` 키워드 사용을 강제한다.
105
165
 
106
- #### `@simplysm/no-hard-private`
166
+ - **타입**: problem
167
+ - **자동 수정**: 지원 (fixable)
168
+ - **적용 대상**: JS, TS 모두
107
169
 
108
- Enforces TypeScript `private _` style instead of ECMAScript hard private fields (`#`).
170
+ **감지 범위:**
171
+ - 클래스 필드 선언: `#field`
172
+ - 클래스 메서드 선언: `#method()`
173
+ - 클래스 접근자 선언: `accessor #field`
174
+ - 멤버 접근 표현식: `this.#field`
175
+ - 중첩 클래스 지원 (스택 구조)
109
176
 
110
- - **Type**: problem
111
- - **Fixable**: yes (auto-fix replaces `#field` with `private _field`)
112
- - **Recommended severity**: error
113
-
114
- Hard private fields (`#field`) are disallowed. The auto-fixer renames the field and adds the `private` keyword. Reports a conflict error if `_field` already exists on the class.
177
+ **자동 수정 동작:**
178
+ 1. `#name` -> `_name`으로 이름 변경
179
+ 2. `private` 접근 제한자가 없으면 자동 추가
180
+ 3. 데코레이터가 있으면 데코레이터 뒤에 `private` 삽입
181
+ 4. 동일 이름의 멤버가 이미 존재하면 충돌 에러 보고 (수정 불가)
115
182
 
116
183
  ```typescript
117
184
  // Bad
118
185
  class Foo {
119
- #value = 1;
120
- #compute() { return this.#value; }
186
+ #bar = 1;
187
+ #baz() { return this.#bar; }
121
188
  }
122
189
 
123
190
  // Good
124
191
  class Foo {
125
- private _value = 1;
126
- private _compute() { return this._value; }
192
+ private _bar = 1;
193
+ private _baz() { return this._bar; }
127
194
  }
128
195
  ```
129
196
 
130
- #### `@simplysm/no-subpath-imports-from-simplysm`
197
+ **메시지:**
198
+ - `preferSoftPrivate`: `Hard private fields (#) are not allowed. Use the "private _" style instead.`
199
+ - `nameConflict`: `Cannot convert hard private field "#name" to "_name". A member with the same name already exists.`
200
+
201
+ ### @simplysm/no-subpath-imports-from-simplysm
131
202
 
132
- Prohibits `src` subpath imports from `@simplysm/*` packages.
203
+ `@simplysm/*` 패키지의 `src/` 서브경로 import를 금지한다.
133
204
 
134
- - **Type**: problem
135
- - **Fixable**: yes (auto-fix strips the `/src/...` segment)
136
- - **Recommended severity**: error
205
+ - **타입**: problem
206
+ - **자동 수정**: 지원 (fixable)
207
+ - **적용 대상**: JS, TS 모두
137
208
 
138
- Prevents importing internal source paths such as `@simplysm/pkg/src/foo`. Only the package root import (`@simplysm/pkg`) is allowed.
209
+ **감지 범위:**
210
+ - 정적 import: `import { x } from "@simplysm/pkg/src/..."`
211
+ - 동적 import: `import("@simplysm/pkg/src/...")`
212
+ - named re-export: `export { x } from "@simplysm/pkg/src/..."`
213
+ - 전체 re-export: `export * from "@simplysm/pkg/src/..."`
214
+
215
+ **자동 수정 동작:**
216
+ - `@simplysm/pkg/src/...` -> `@simplysm/pkg`로 경로 축약
139
217
 
140
218
  ```typescript
141
219
  // Bad
142
- import { Foo } from "@simplysm/core-common/src/utils/foo";
220
+ import { foo } from "@simplysm/core-common/src/utils/obj";
221
+ export { bar } from "@simplysm/solid/src/controls";
143
222
 
144
223
  // Good
145
- import { Foo } from "@simplysm/core-common";
224
+ import { foo } from "@simplysm/core-common";
225
+ export { bar } from "@simplysm/solid";
146
226
  ```
147
227
 
148
- #### `@simplysm/ts-no-throw-not-implemented-error`
228
+ ### @simplysm/ts-no-throw-not-implemented-error
229
+
230
+ `@simplysm/core-common`의 `NotImplementedError` 사용을 경고한다. 프로덕션 코드에서 미구현 부분을 감지하기 위한 규칙.
149
231
 
150
- Warns about usage of `NotImplementedError` from `@simplysm/core-common` to catch unfinished code before production.
232
+ - **타입**: suggestion
233
+ - **자동 수정**: 미지원
234
+ - **적용 대상**: TS 전용 (타입 분석 필요)
235
+ - **기본 수준**: warn (테스트 파일에서는 off)
151
236
 
152
- - **Type**: suggestion
153
- - **Fixable**: no
154
- - **Recommended severity**: warn (off in test files)
237
+ **감지 범위:**
238
+ - named import: `import { NotImplementedError } from "@simplysm/core-common"`
239
+ - aliased import: `import { NotImplementedError as NIE } from "@simplysm/core-common"`
240
+ - namespace import: `import * as CC from "@simplysm/core-common"` -> `new CC.NotImplementedError()`
241
+ - 동적 import (`await import(...)`)는 감지하지 않음
155
242
 
156
- Detects `new NotImplementedError()` calls regardless of import form (named, aliased, or namespace import). The warning message displays the error's string argument if provided.
243
+ **보고 메시지:**
244
+ - 첫 번째 인자가 문자열이면 해당 문자열을 메시지로 표시
245
+ - 인자가 없으면 `"Not implemented"` 표시
157
246
 
158
247
  ```typescript
159
- // Triggers warning: "Not implemented"
248
+ // Warning: "TODO: 나중에 구현"
249
+ throw new NotImplementedError("TODO: 나중에 구현");
250
+
251
+ // Warning: "Not implemented"
160
252
  throw new NotImplementedError();
253
+ ```
254
+
255
+ ## 유틸리티
256
+
257
+ ### createRule
161
258
 
162
- // Triggers warning: "parseXml is not ready"
163
- throw new NotImplementedError("parseXml is not ready");
259
+ `@typescript-eslint/utils`의 `RuleCreator`를 래핑한 팩토리 함수. 커스텀 규칙 작성 시 사용한다.
260
+
261
+ ```typescript
262
+ import { createRule } from "../utils/create-rule";
263
+
264
+ export default createRule({
265
+ name: "my-rule",
266
+ meta: {
267
+ type: "problem",
268
+ docs: { description: "규칙 설명" },
269
+ messages: { errorId: "에러 메시지" },
270
+ schema: [],
271
+ },
272
+ defaultOptions: [],
273
+ create(context) {
274
+ return {
275
+ // AST visitor
276
+ };
277
+ },
278
+ });
164
279
  ```
280
+
281
+ ## 의존성
282
+
283
+ - `eslint` v9+
284
+ - `typescript-eslint` v8+
285
+ - `eslint-plugin-import` - import/export 규칙
286
+ - `eslint-plugin-unused-imports` - 미사용 import 자동 제거
287
+ - `eslint-plugin-solid` - SolidJS 규칙
288
+ - `eslint-plugin-tailwindcss` - Tailwind CSS 규칙
289
+ - `eslint-import-resolver-typescript` - TypeScript 경로 해석
290
+ - `globals` - 글로벌 변수 정의 (node, browser, es2024)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/lint",
3
- "version": "13.0.85",
3
+ "version": "13.0.86",
4
4
  "description": "Simplysm package - Lint configuration (ESLint)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",