eslint-plugin-smarthr 6.10.2 → 6.10.3
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/CHANGELOG.md +8 -0
- package/package.json +2 -2
- package/rules/require-barrel-import/index.js +26 -3
- package/rules/trim-props/index.js +16 -8
- package/test/require-barrel-import.js +61 -73
- package/test/trim-props.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [6.10.3](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.10.2...eslint-plugin-smarthr-v6.10.3) (2026-04-10)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **require-barrel-import:** commonParentのbarrelを除外して同一ツリー内の相対importを許可 ([#1222](https://github.com/kufu/tamatebako/issues/1222)) ([fe5a68c](https://github.com/kufu/tamatebako/commit/fe5a68cd50a6f76dde0c403dd1ec33e5b1dd5d57))
|
|
11
|
+
* trim-propsのセレクターをesquery互換へ修正し、ESLint 9.xでのクラッシュを解消 ([#1214](https://github.com/kufu/tamatebako/issues/1214)) ([d2345a0](https://github.com/kufu/tamatebako/commit/d2345a0623ebbf0f805c7c8a6b2b957ac21b0ffd))
|
|
12
|
+
|
|
5
13
|
## [6.10.2](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.10.1...eslint-plugin-smarthr-v6.10.2) (2026-04-09)
|
|
6
14
|
|
|
7
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-smarthr",
|
|
3
|
-
"version": "6.10.
|
|
3
|
+
"version": "6.10.3",
|
|
4
4
|
"author": "SmartHR",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A sharable ESLint plugin for SmartHR",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"eslintplugin",
|
|
38
38
|
"smarthr"
|
|
39
39
|
],
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "e1a8159fdc6396bb83fdf7f616f52f3c714ff390"
|
|
41
41
|
}
|
|
@@ -104,6 +104,24 @@ const isImportedInsideImporter = (importerDir, importedPath) => {
|
|
|
104
104
|
return importedPath === importerDir || importedPath.startsWith(importerDir + '/')
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* 2つのパスの共通の親ディレクトリを見つける
|
|
109
|
+
* @param {string} path1 - パス1
|
|
110
|
+
* @param {string} path2 - パス2
|
|
111
|
+
* @returns {string} 共通の親ディレクトリの絶対パス
|
|
112
|
+
*/
|
|
113
|
+
const findCommonParent = (path1, path2) => {
|
|
114
|
+
const segments1 = path1.split('/')
|
|
115
|
+
const segments2 = path2.split('/')
|
|
116
|
+
|
|
117
|
+
let i = 0
|
|
118
|
+
while (i < segments1.length && i < segments2.length && segments1[i] === segments2[i]) {
|
|
119
|
+
i++
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return segments1.slice(0, i).join('/')
|
|
123
|
+
}
|
|
124
|
+
|
|
107
125
|
/**
|
|
108
126
|
* allowedImportsオプションに基づいて、特定のimportが許可されているかチェックする
|
|
109
127
|
* @param {object} node - ImportDeclaration node
|
|
@@ -167,6 +185,10 @@ const findBarrelFile = (importedPath, importerDir) => {
|
|
|
167
185
|
let currentPath = importedPath
|
|
168
186
|
let barrel = undefined
|
|
169
187
|
|
|
188
|
+
// import元とimport先の共通の親ディレクトリを見つける
|
|
189
|
+
// 共通の親のbarrelファイルは除外する(同じディレクトリツリー内の相対importには適用されない)
|
|
190
|
+
const commonParent = findCommonParent(importerDir, importedPath)
|
|
191
|
+
|
|
170
192
|
// ディレクトリ指定の場合、そのindex.tsを指していることは自明なので一階層上から探索
|
|
171
193
|
if (fs.existsSync(currentPath) && fs.statSync(currentPath).isDirectory()) {
|
|
172
194
|
pathSegments.pop()
|
|
@@ -175,9 +197,10 @@ const findBarrelFile = (importedPath, importerDir) => {
|
|
|
175
197
|
|
|
176
198
|
while (pathSegments.length > 0) {
|
|
177
199
|
// 以下の場合は探索終了
|
|
178
|
-
// 1.
|
|
179
|
-
// 2.
|
|
180
|
-
|
|
200
|
+
// 1. 共通の親ディレクトリに到達した場合(commonParent自体のbarrelは除外)
|
|
201
|
+
// 2. いずれかのreplacePathsのルートに到達した場合
|
|
202
|
+
// 3. import先がimport元の内部にある場合(同階層・サブディレクトリからのimport)
|
|
203
|
+
if (currentPath === commonParent || ALL_ROOT_PATHS.includes(currentPath) || isImportedInsideImporter(importerDir, currentPath)) {
|
|
181
204
|
break
|
|
182
205
|
}
|
|
183
206
|
|
|
@@ -12,15 +12,23 @@ module.exports = {
|
|
|
12
12
|
fixable: 'whitespace',
|
|
13
13
|
},
|
|
14
14
|
create(context) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
message: `属性に設定している文字列から先頭、末尾の空白文字を削除してください
|
|
15
|
+
const checker = (node) => {
|
|
16
|
+
context.report({
|
|
17
|
+
node,
|
|
18
|
+
message: `属性に設定している文字列から先頭、末尾の空白文字を削除してください
|
|
20
19
|
- 詳細: https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/trim-props`,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
fix: (fixer) => fixer.replaceText(node, context.sourceCode.getText(node).replace(TRIM_REGEX, '$1$2$3')),
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
// esquery は :matches()・:has() 内での > (子結合子) を解釈できないため、
|
|
26
|
+
// 1つの複合セレクターではなく個別のセレクターに分割している
|
|
27
|
+
'JSXAttribute > Literal[value=/(^ | $)/]': checker,
|
|
28
|
+
'JSXAttribute > JSXExpressionContainer > TemplateLiteral > TemplateElement:matches(:first-child[value.raw=/^ /],:last-child[value.raw=/ $/])':
|
|
29
|
+
(node) => {
|
|
30
|
+
checker(node.parent)
|
|
31
|
+
},
|
|
24
32
|
}
|
|
25
33
|
},
|
|
26
34
|
}
|
|
@@ -261,16 +261,14 @@ ruleTester.run('require-barrel-import', rule, {
|
|
|
261
261
|
return `${fixturesRoot}/path-alias-parent-no-barrel/Button/Button.tsx`
|
|
262
262
|
})(),
|
|
263
263
|
},
|
|
264
|
-
],
|
|
265
264
|
|
|
266
|
-
|
|
267
|
-
// 親階層からのimport(barrelが存在する場合)
|
|
265
|
+
// 親階層からのimport(commonParentにbarrelがある場合)
|
|
268
266
|
{
|
|
269
267
|
code: `import { createUserRole } from '../hooks/createUserRoleAction'`,
|
|
270
268
|
filename: (() => {
|
|
271
|
-
createFixture('parent-import-
|
|
269
|
+
createFixture('parent-import-common-parent-barrel', {
|
|
272
270
|
'components': {
|
|
273
|
-
'index.tsx': 'export {}',
|
|
271
|
+
'index.tsx': 'export {}', // commonParentのbarrelは除外される
|
|
274
272
|
'AddDialog': {
|
|
275
273
|
'AddDialog.tsx': '',
|
|
276
274
|
},
|
|
@@ -279,91 +277,57 @@ ruleTester.run('require-barrel-import', rule, {
|
|
|
279
277
|
},
|
|
280
278
|
},
|
|
281
279
|
})
|
|
282
|
-
return `${fixturesRoot}/parent-import-
|
|
280
|
+
return `${fixturesRoot}/parent-import-common-parent-barrel/components/AddDialog/AddDialog.tsx`
|
|
283
281
|
})(),
|
|
284
|
-
errors: [
|
|
285
|
-
{
|
|
286
|
-
message: /からimportするか、.*のbarrelファイルを削除して直接import可能にしてください/,
|
|
287
|
-
},
|
|
288
|
-
],
|
|
289
282
|
},
|
|
290
283
|
|
|
291
|
-
//
|
|
284
|
+
// 複雑なネスト - commonParentのbarrelは除外される
|
|
292
285
|
{
|
|
293
|
-
code: `import {
|
|
286
|
+
code: `import type { RequestStepActionNotSkipped } from '../utils/withSkipped'`,
|
|
294
287
|
filename: (() => {
|
|
295
|
-
createFixture('
|
|
296
|
-
'
|
|
297
|
-
'
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
},
|
|
288
|
+
createFixture('nested-common-parent-barrel', {
|
|
289
|
+
'Nodes': {
|
|
290
|
+
'index.tsx': 'export {}', // commonParentより上のbarrel(除外される)
|
|
291
|
+
'StepNodeRequestView': {
|
|
292
|
+
'index.tsx': 'export {}', // commonParent(除外される)
|
|
293
|
+
'Approvers': {
|
|
294
|
+
'ApproverRow': {
|
|
295
|
+
'buildUserRowsProps.ts': '',
|
|
296
|
+
},
|
|
297
|
+
'utils': {
|
|
298
|
+
'withSkipped': {
|
|
299
|
+
'index.ts': 'export {}', // import先のbarrel(valid)
|
|
308
300
|
},
|
|
309
301
|
},
|
|
310
302
|
},
|
|
311
303
|
},
|
|
312
304
|
},
|
|
313
305
|
})
|
|
314
|
-
return `${fixturesRoot}/
|
|
306
|
+
return `${fixturesRoot}/nested-common-parent-barrel/Nodes/StepNodeRequestView/Approvers/ApproverRow/buildUserRowsProps.ts`
|
|
315
307
|
})(),
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
},
|
|
320
|
-
],
|
|
308
|
+
languageOptions: {
|
|
309
|
+
parser: require('typescript-eslint').parser,
|
|
310
|
+
},
|
|
321
311
|
},
|
|
312
|
+
],
|
|
322
313
|
|
|
323
|
-
|
|
314
|
+
invalid: [
|
|
315
|
+
// 親階層からのimport(import先の親にbarrelがある場合)
|
|
324
316
|
{
|
|
325
317
|
code: `import { api } from '../api/client'`,
|
|
326
318
|
filename: (() => {
|
|
327
|
-
createFixture('
|
|
328
|
-
'app': {
|
|
329
|
-
'items': {
|
|
330
|
-
'index.tsx': 'export {}',
|
|
331
|
-
'[id]': {
|
|
332
|
-
'DetailPage.tsx': '',
|
|
333
|
-
},
|
|
334
|
-
'api': {
|
|
335
|
-
'client.ts': '',
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
})
|
|
340
|
-
return `${fixturesRoot}/dynamic-route-parent-import/app/items/[id]/DetailPage.tsx`
|
|
341
|
-
})(),
|
|
342
|
-
errors: [
|
|
343
|
-
{
|
|
344
|
-
message: /からimportするか、.*のbarrelファイルを削除して直接import可能にしてください/,
|
|
345
|
-
},
|
|
346
|
-
],
|
|
347
|
-
},
|
|
348
|
-
|
|
349
|
-
// ============================================================
|
|
350
|
-
// Path alias - 親階層からのimport(barrelあり)
|
|
351
|
-
// ============================================================
|
|
352
|
-
{
|
|
353
|
-
code: `import { createUserRole } from '~/path-alias-parent-import-with-barrel/components/hooks/createUserRoleAction'`,
|
|
354
|
-
filename: (() => {
|
|
355
|
-
createFixture('path-alias-parent-import-with-barrel', {
|
|
319
|
+
createFixture('parent-import-with-barrel', {
|
|
356
320
|
'components': {
|
|
357
|
-
'index.tsx': 'export {}',
|
|
358
321
|
'AddDialog': {
|
|
359
322
|
'AddDialog.tsx': '',
|
|
360
323
|
},
|
|
361
|
-
'
|
|
362
|
-
'
|
|
324
|
+
'api': {
|
|
325
|
+
'index.tsx': 'export {}', // import先の親にbarrel
|
|
326
|
+
'client.ts': '',
|
|
363
327
|
},
|
|
364
328
|
},
|
|
365
329
|
})
|
|
366
|
-
return `${fixturesRoot}/
|
|
330
|
+
return `${fixturesRoot}/parent-import-with-barrel/components/AddDialog/AddDialog.tsx`
|
|
367
331
|
})(),
|
|
368
332
|
errors: [
|
|
369
333
|
{
|
|
@@ -372,22 +336,22 @@ ruleTester.run('require-barrel-import', rule, {
|
|
|
372
336
|
],
|
|
373
337
|
},
|
|
374
338
|
|
|
375
|
-
//
|
|
339
|
+
// Next.js特殊文字パス - import先の親にbarrel
|
|
376
340
|
{
|
|
377
|
-
code: `import {
|
|
341
|
+
code: `import { api } from '../api/client'`,
|
|
378
342
|
filename: (() => {
|
|
379
|
-
createFixture('
|
|
343
|
+
createFixture('nextjs-import-parent-barrel', {
|
|
380
344
|
'app': {
|
|
381
345
|
'(private)': {
|
|
382
346
|
'settings': {
|
|
383
347
|
'user_roles': {
|
|
384
348
|
'_components': {
|
|
385
|
-
'index.tsx': 'export {}',
|
|
386
349
|
'AddUserRoleDialog': {
|
|
387
350
|
'AddUserRoleDialog.tsx': '',
|
|
388
351
|
},
|
|
389
|
-
'
|
|
390
|
-
'
|
|
352
|
+
'api': {
|
|
353
|
+
'index.tsx': 'export {}', // import先の親にbarrel
|
|
354
|
+
'client.ts': '',
|
|
391
355
|
},
|
|
392
356
|
},
|
|
393
357
|
},
|
|
@@ -395,7 +359,31 @@ ruleTester.run('require-barrel-import', rule, {
|
|
|
395
359
|
},
|
|
396
360
|
},
|
|
397
361
|
})
|
|
398
|
-
return `${fixturesRoot}/
|
|
362
|
+
return `${fixturesRoot}/nextjs-import-parent-barrel/app/(private)/settings/user_roles/_components/AddUserRoleDialog/AddUserRoleDialog.tsx`
|
|
363
|
+
})(),
|
|
364
|
+
errors: [
|
|
365
|
+
{
|
|
366
|
+
message: /からimportするか、.*のbarrelファイルを削除して直接import可能にしてください/,
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
// Path alias - import先の親にbarrel
|
|
372
|
+
{
|
|
373
|
+
code: `import { api } from '~/path-alias-import-parent-barrel/components/api/client'`,
|
|
374
|
+
filename: (() => {
|
|
375
|
+
createFixture('path-alias-import-parent-barrel', {
|
|
376
|
+
'components': {
|
|
377
|
+
'AddDialog': {
|
|
378
|
+
'AddDialog.tsx': '',
|
|
379
|
+
},
|
|
380
|
+
'api': {
|
|
381
|
+
'index.tsx': 'export {}', // import先の親にbarrel
|
|
382
|
+
'client.ts': '',
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
})
|
|
386
|
+
return `${fixturesRoot}/path-alias-import-parent-barrel/components/AddDialog/AddDialog.tsx`
|
|
399
387
|
})(),
|
|
400
388
|
errors: [
|
|
401
389
|
{
|
package/test/trim-props.js
CHANGED
|
@@ -55,12 +55,12 @@ ruleTester.run('trim-props', rule, {
|
|
|
55
55
|
{
|
|
56
56
|
code: '<div data-spec={` a${b} c `}>....</div>',
|
|
57
57
|
output: '<div data-spec={`a${b} c`}>....</div>',
|
|
58
|
-
errors: [{ message: ERROR_MESSAGE }],
|
|
58
|
+
errors: [{ message: ERROR_MESSAGE }, { message: ERROR_MESSAGE }],
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
code: '<div data-spec={` a${b ? ` ${c} ` : " "} d `}>....</div>',
|
|
62
62
|
output: '<div data-spec={`a${b ? ` ${c} ` : " "} d`}>....</div>',
|
|
63
|
-
errors: [{ message: ERROR_MESSAGE }],
|
|
63
|
+
errors: [{ message: ERROR_MESSAGE }, { message: ERROR_MESSAGE }],
|
|
64
64
|
},
|
|
65
65
|
],
|
|
66
66
|
})
|