@kurateh/eslint-plugin 0.1.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/dist/index.mjs ADDED
@@ -0,0 +1,400 @@
1
+ import { createRequire } from 'module';
2
+ import react from 'eslint-plugin-react';
3
+ import reactHook from 'eslint-plugin-react-hooks';
4
+ import globals from 'globals';
5
+ import importPlugin from 'eslint-plugin-import';
6
+ import tseslint from 'typescript-eslint';
7
+ import { readFileSync, existsSync } from 'node:fs';
8
+ import { join, dirname, relative } from 'node:path';
9
+ import { ESLintUtils } from '@typescript-eslint/utils';
10
+ import js from '@eslint/js';
11
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
12
+ import unusedImportsPlugin from 'eslint-plugin-unused-imports';
13
+
14
+ createRequire(import.meta.url);
15
+ var __defProp = Object.defineProperty;
16
+ var __defProps = Object.defineProperties;
17
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
18
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
19
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
20
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
21
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
22
+ var __spreadValues = (a, b) => {
23
+ for (var prop in b || (b = {}))
24
+ if (__hasOwnProp.call(b, prop))
25
+ __defNormalProp(a, prop, b[prop]);
26
+ if (__getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(b)) {
28
+ if (__propIsEnum.call(b, prop))
29
+ __defNormalProp(a, prop, b[prop]);
30
+ }
31
+ return a;
32
+ };
33
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
34
+ var createRule = ESLintUtils.RuleCreator.withoutDocs;
35
+
36
+ // src/rules/import-path.ts
37
+ var TS_CONFIG_FILE_NAMES = ["tsconfig.path.json", "tsconfig.json"];
38
+ var has = (map, path) => {
39
+ let inner = map;
40
+ for (const step of path.split(".")) {
41
+ inner = inner[step];
42
+ if (inner === void 0) {
43
+ return false;
44
+ }
45
+ }
46
+ return true;
47
+ };
48
+ var findFilePath = (filename, initialPath) => {
49
+ let dir = initialPath;
50
+ do {
51
+ dir = dirname(dir);
52
+ } while (!existsSync(join(dir, filename)) && dir !== "/");
53
+ const filePath = join(dir, filename);
54
+ if (!existsSync(filePath)) {
55
+ return;
56
+ }
57
+ return filePath;
58
+ };
59
+ var getAbsolutePathInfo = (fileName) => {
60
+ for (const configPath of TS_CONFIG_FILE_NAMES) {
61
+ const filePath = findFilePath(configPath, fileName);
62
+ if (filePath === void 0) {
63
+ continue;
64
+ }
65
+ const baseDir = dirname(filePath);
66
+ const tsPathConfig = JSON.parse(
67
+ readFileSync(filePath, {
68
+ encoding: "utf-8"
69
+ })
70
+ );
71
+ const result = {
72
+ baseUrl: "",
73
+ paths: {}
74
+ };
75
+ if (has(tsPathConfig, "compilerOptions.baseUrl")) {
76
+ result.baseUrl = join(baseDir, tsPathConfig.compilerOptions.baseUrl);
77
+ }
78
+ if (has(tsPathConfig, "compilerOptions.paths")) {
79
+ result.paths = Object.fromEntries(
80
+ Object.entries(tsPathConfig.compilerOptions.paths).map(
81
+ ([key, value]) => [
82
+ key.replace(/\/\*$/, "/"),
83
+ value.map((path) => join(baseDir, path).replace(/\/\*$/, "/"))
84
+ ]
85
+ )
86
+ );
87
+ }
88
+ return result;
89
+ }
90
+ return;
91
+ };
92
+ var import_path_default = createRule({
93
+ meta: {
94
+ type: "suggestion",
95
+ fixable: "code",
96
+ messages: {
97
+ shouldBeRelativePath: 'When importing a child module, you must use the relative path. Use "{{expectedPath}}" instead of "{{source}}".',
98
+ shouldBeAbsolutePath: 'When importing a parent module, you must use the absolute path. Use "{{expectedPath}}" instead of "{{source}}".'
99
+ },
100
+ schema: [],
101
+ docs: {
102
+ description: "Enforce import path according to the location of the imported file."
103
+ }
104
+ },
105
+ defaultOptions: [],
106
+ create: (context) => {
107
+ return {
108
+ ImportDeclaration: (node) => {
109
+ const fileName = context.getFilename();
110
+ const absolutePathInfo = getAbsolutePathInfo(fileName);
111
+ if (absolutePathInfo === void 0) {
112
+ return;
113
+ }
114
+ const source = node.source.value;
115
+ if (source.startsWith("..")) {
116
+ const sourceAbsolutePath2 = join(dirname(fileName), source);
117
+ for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
118
+ for (const path of paths) {
119
+ if (sourceAbsolutePath2.startsWith(path)) {
120
+ const expectedPath2 = sourceAbsolutePath2.replace(path, alias);
121
+ context.report({
122
+ node,
123
+ messageId: "shouldBeAbsolutePath",
124
+ data: {
125
+ expectedPath: expectedPath2,
126
+ source
127
+ },
128
+ fix(fixer) {
129
+ return fixer.replaceText(node.source, `"${expectedPath2}"`);
130
+ }
131
+ });
132
+ return;
133
+ }
134
+ }
135
+ }
136
+ return;
137
+ }
138
+ let sourceAbsolutePath;
139
+ for (const [alias, paths] of Object.entries(absolutePathInfo.paths)) {
140
+ for (const path of paths) {
141
+ if (source.startsWith(alias)) {
142
+ sourceAbsolutePath = join(path, source.replace(alias, ""));
143
+ break;
144
+ }
145
+ }
146
+ if (sourceAbsolutePath !== void 0) {
147
+ break;
148
+ }
149
+ }
150
+ if (sourceAbsolutePath === void 0) {
151
+ return;
152
+ }
153
+ const sourceRelativePath = relative(
154
+ dirname(fileName),
155
+ sourceAbsolutePath
156
+ );
157
+ if (sourceRelativePath.startsWith("..")) {
158
+ return;
159
+ }
160
+ const expectedPath = "./" + sourceRelativePath;
161
+ context.report({
162
+ node,
163
+ messageId: "shouldBeRelativePath",
164
+ data: {
165
+ expectedPath,
166
+ source
167
+ },
168
+ fix(fixer) {
169
+ return fixer.replaceText(node.source, `"${expectedPath}"`);
170
+ }
171
+ });
172
+ return;
173
+ }
174
+ };
175
+ }
176
+ });
177
+
178
+ // src/rules/index.ts
179
+ var rules_default = {
180
+ "import-path": import_path_default
181
+ };
182
+ var recommended_default = [
183
+ js.configs.recommended,
184
+ importPlugin.flatConfigs.recommended,
185
+ eslintPluginPrettierRecommended,
186
+ {
187
+ languageOptions: {
188
+ ecmaVersion: 2020,
189
+ sourceType: "module",
190
+ globals: __spreadValues(__spreadValues(__spreadValues({}, globals.es2017), globals.browser), globals.node)
191
+ },
192
+ plugins: {
193
+ "unused-imports": unusedImportsPlugin
194
+ },
195
+ ignores: ["node_modules/", "dist/", "build/", "coverage/"],
196
+ rules: {
197
+ // eslint
198
+ "object-shorthand": 1,
199
+ "no-unused-vars": [
200
+ 1,
201
+ {
202
+ ignoreRestSiblings: true,
203
+ vars: "all",
204
+ args: "after-used",
205
+ argsIgnorePattern: "^_",
206
+ varsIgnorePattern: "^_"
207
+ }
208
+ ],
209
+ "no-param-reassign": [
210
+ 2,
211
+ {
212
+ props: true,
213
+ ignorePropertyModificationsForRegex: ["^draft$", "Draft$"]
214
+ }
215
+ ],
216
+ camelcase: [1, { allow: ["^\\w*_[A-Z]*$"] }],
217
+ "no-var": 2,
218
+ // prettier
219
+ "prettier/prettier": [
220
+ 1,
221
+ {
222
+ trailingComma: "all",
223
+ tabWidth: 2,
224
+ semi: true,
225
+ singleQuote: false,
226
+ endOfLine: "auto"
227
+ },
228
+ {
229
+ usePrettierrc: false
230
+ }
231
+ ],
232
+ // import
233
+ "import/no-unresolved": 0,
234
+ "import/no-extraneous-dependencies": [
235
+ 2,
236
+ {
237
+ devDependencies: [
238
+ "**/*.test.*",
239
+ "**/*.stories.*",
240
+ "**/*.config.*",
241
+ "**/*.spec.*"
242
+ ]
243
+ }
244
+ ],
245
+ "import/order": [
246
+ 1,
247
+ {
248
+ alphabetize: {
249
+ order: "asc",
250
+ caseInsensitive: true
251
+ },
252
+ "newlines-between": "always",
253
+ groups: [
254
+ "builtin",
255
+ "external",
256
+ "internal",
257
+ ["parent", "sibling", "index"]
258
+ ],
259
+ pathGroups: [
260
+ {
261
+ pattern: "~*/**",
262
+ group: "internal"
263
+ },
264
+ {
265
+ pattern: "@*/**",
266
+ group: "internal"
267
+ }
268
+ ]
269
+ }
270
+ ],
271
+ // unused-imports
272
+ "unused-imports/no-unused-imports": 2
273
+ }
274
+ }
275
+ ];
276
+
277
+ // src/configs/typescript.ts
278
+ var typescript_default = [
279
+ ...recommended_default,
280
+ // eslint-disable-next-line import/no-named-as-default-member
281
+ ...tseslint.configs.recommended,
282
+ importPlugin.flatConfigs.typescript,
283
+ {
284
+ // ESLint config block에 file이 있으면 해당 파일을 검사할 차례가 와서야 plugin이 적용됨
285
+ // 따라서 이 Plugin을 끄려면 Config File에서 file: "~~"을 넣어야 됨
286
+ // 이 과정을 없애기 위해 plugin 적용을 앞서 진행
287
+ plugins: {
288
+ "@kurateh": { rules: rules_default, meta: { name: "@kurateh" } }
289
+ }
290
+ },
291
+ {
292
+ files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
293
+ settings: {
294
+ "import/resolver": {
295
+ typescript: {
296
+ alwaysTryTypes: true,
297
+ // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
298
+ // Choose from one of the "project" configs below or omit to use <root>/tsconfig.json by default
299
+ // use <root>/path/to/folder/tsconfig.json
300
+ project: "tsconfig.json"
301
+ // Multiple tsconfigs (Useful for monorepos)
302
+ // use a glob pattern
303
+ // project: "packages/*/tsconfig.json",
304
+ // use an array
305
+ // project: [
306
+ // "packages/module-a/tsconfig.json",
307
+ // "packages/module-b/tsconfig.json"
308
+ // ],
309
+ // use an array of glob patterns
310
+ // project: [
311
+ // "packages/*/tsconfig.json",
312
+ // "other-packages/*/
313
+ }
314
+ }
315
+ },
316
+ rules: {
317
+ // eslint
318
+ "@kurateh/import-path": 1,
319
+ "object-shorthand": 1,
320
+ "no-unused-vars": 0,
321
+ "@typescript-eslint/no-unused-vars": [
322
+ 1,
323
+ {
324
+ ignoreRestSiblings: true,
325
+ vars: "all",
326
+ args: "after-used",
327
+ argsIgnorePattern: "^_",
328
+ varsIgnorePattern: "^_"
329
+ }
330
+ ],
331
+ "@typescript-eslint/consistent-type-imports": [
332
+ 1,
333
+ {
334
+ fixStyle: "inline-type-imports"
335
+ }
336
+ ],
337
+ "no-param-reassign": [
338
+ 2,
339
+ {
340
+ props: true,
341
+ ignorePropertyModificationsForRegex: ["^draft$", "Draft$"]
342
+ }
343
+ ],
344
+ camelcase: [1, { allow: ["^\\w*_[A-Z]*$"] }],
345
+ "no-var": 2,
346
+ "import-plugin/no-unresolved": 0
347
+ }
348
+ }
349
+ ];
350
+
351
+ // src/configs/react.ts
352
+ var _a, _b;
353
+ var react_default = [
354
+ ...typescript_default,
355
+ (_b = (_a = react.configs.flat) == null ? void 0 : _a.recommended) != null ? _b : {},
356
+ {
357
+ plugins: { "react-hooks": reactHook },
358
+ files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"],
359
+ languageOptions: {
360
+ parserOptions: {
361
+ ecmaFeatures: {
362
+ jsx: true
363
+ }
364
+ },
365
+ globals: __spreadValues({}, globals.browser)
366
+ },
367
+ rules: __spreadProps(__spreadValues({}, reactHook.configs.recommended.rules), {
368
+ "react/react-in-jsx-scope": 0,
369
+ "react/function-component-definition": [
370
+ 2,
371
+ {
372
+ namedComponents: "arrow-function",
373
+ unnamedComponents: "arrow-function"
374
+ }
375
+ ],
376
+ "react/jsx-curly-brace-presence": [
377
+ 1,
378
+ {
379
+ props: "never",
380
+ children: "never"
381
+ }
382
+ ],
383
+ "react/prop-types": 0,
384
+ "react/require-default-props": 0,
385
+ "react/display-name": 0
386
+ })
387
+ }
388
+ ];
389
+
390
+ // src/index.ts
391
+ var index_default = {
392
+ configs: {
393
+ recommended: recommended_default,
394
+ typescript: typescript_default,
395
+ react: react_default
396
+ },
397
+ rules: rules_default
398
+ };
399
+
400
+ export { index_default as default };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@kurateh/eslint-plugin",
3
+ "version": "0.1.0",
4
+ "exports": {
5
+ ".": {
6
+ "import": "./dist/index.mjs",
7
+ "require": "./dist/index.js"
8
+ }
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "keywords": [
14
+ "eslint",
15
+ "plugin"
16
+ ],
17
+ "license": "ISC",
18
+ "engines": {
19
+ "node": ">=22"
20
+ },
21
+ "devDependencies": {
22
+ "@kurateh/eslint-plugin": "file:",
23
+ "@types/node": "^22.10.2",
24
+ "@types/react": "^19.0.2",
25
+ "eslint": "^9.17.0",
26
+ "prettier": "^3.4.2",
27
+ "react": "^19.0.0",
28
+ "tsup": "^8.3.5",
29
+ "typescript": "^5.7.2"
30
+ },
31
+ "dependencies": {
32
+ "@eslint/js": "^9.17.0",
33
+ "@typescript-eslint/eslint-plugin": "^8.18.1",
34
+ "@typescript-eslint/parser": "^8.18.1",
35
+ "@typescript-eslint/utils": "^8.18.1",
36
+ "eslint-config-prettier": "^9.1.0",
37
+ "eslint-import-resolver-typescript": "^3.7.0",
38
+ "eslint-plugin-import": "^2.31.0",
39
+ "eslint-plugin-prettier": "^5.2.1",
40
+ "eslint-plugin-react": "^7.37.2",
41
+ "eslint-plugin-react-hooks": "^5.1.0",
42
+ "eslint-plugin-unused-imports": "^4.1.4",
43
+ "globals": "^15.14.0",
44
+ "typescript-eslint": "^8.18.1"
45
+ },
46
+ "peerDependencies": {
47
+ "eslint": ">=9"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "lint": "eslint .",
52
+ "type-check": "tsc --noEmit",
53
+ "version": "npm version"
54
+ }
55
+ }