eslint-plugin-smarthr 0.0.0 → 0.1.1
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 +21 -2
- package/README.md +136 -50
- package/jest.config.js +5 -0
- package/libs/common_domain.js +10 -9
- package/package.json +5 -1
- package/rules/jsx-start-with-spread-attributes.js +44 -10
- package/rules/prohibit-import.js +80 -33
- package/rules/redundant-name.js +206 -86
- package/rules/require-barrel-import.js +125 -0
- package/rules/require-import.js +113 -0
- package/test/prohibit-import.js +201 -0
- package/test/require-import.js +184 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,28 @@
|
|
|
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
|
-
### [0.
|
|
5
|
+
### [0.1.1](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.1.0...v0.1.1) (2022-03-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add require-barrel-import rule ([#13](https://github.com/kufu/eslint-plugin-smarthr/issues/13)) ([79ee88d](https://github.com/kufu/eslint-plugin-smarthr/commit/79ee88d355e01bb8344dc95bd65157e2fbcf916e))
|
|
11
|
+
|
|
12
|
+
## [0.1.0](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.1...v0.1.0) (2022-02-09)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ⚠ BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
* BREAKING CHANGE: add require-import & update prohibit-import (#12) ([e6c5c44](https://github.com/kufu/eslint-plugin-smarthr/commit/e6c5c445a21620d4b796ded00a685e5da367c7bb)), closes [#12](https://github.com/kufu/eslint-plugin-smarthr/issues/12)
|
|
18
|
+
|
|
19
|
+
### [0.0.1](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.0...v0.0.1) (2022-02-08)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* add type property function params redundant ([758df90](https://github.com/kufu/eslint-plugin-smarthr/commit/758df90f89bd27dd589aeeb55165e27c8e072b08))
|
|
25
|
+
* redundant-name の修正候補を操作できるように改修 ([20991e8](https://github.com/kufu/eslint-plugin-smarthr/commit/20991e874890556e84e7c682e789e4b2650a85b0))
|
|
6
26
|
|
|
7
|
-
### [0.0.1](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.0...v0.0.1) (2022-01-26)
|
|
8
27
|
|
|
9
28
|
## 0.0.0 (2022-01-25)
|
|
10
29
|
|
package/README.md
CHANGED
|
@@ -145,13 +145,19 @@ import globalModulePart from '@/modules/views/parts'
|
|
|
145
145
|
## smarthr/jsx-start-with-spread-attributes
|
|
146
146
|
|
|
147
147
|
- jsxを記述する際、意図しない属性の上書きを防ぐため、spread-attributesを先に指定するように強制するruleです
|
|
148
|
+
- eslint を `--fix` オプション付きで実行する際、 fix option を true にすると自動修正します
|
|
148
149
|
|
|
149
150
|
### rules
|
|
150
151
|
|
|
151
152
|
```js
|
|
152
153
|
{
|
|
153
154
|
rules: {
|
|
154
|
-
'smarthr/jsx-start-with-spread-attributes':
|
|
155
|
+
'smarthr/jsx-start-with-spread-attributes': [
|
|
156
|
+
'error', // 'warn', 'off'
|
|
157
|
+
{
|
|
158
|
+
fix: false, // true
|
|
159
|
+
},
|
|
160
|
+
]
|
|
155
161
|
},
|
|
156
162
|
}
|
|
157
163
|
```
|
|
@@ -268,12 +274,17 @@ import globalModulePart from '@/modules/views/parts'
|
|
|
268
274
|
'smarthr/prohibit-import': [
|
|
269
275
|
'error', // 'warn', 'off'
|
|
270
276
|
{
|
|
271
|
-
|
|
272
|
-
'
|
|
273
|
-
|
|
277
|
+
'^.+$': {
|
|
278
|
+
'smarthr-ui': {
|
|
279
|
+
imported: ['SecondaryButtonAnchor'],
|
|
280
|
+
reportMessage: `{{module}}/{{export}} はXxxxxxなので利用せず yyyy/zzzz を利用してください`
|
|
281
|
+
},
|
|
282
|
+
}
|
|
283
|
+
'\/pages\/views\/': {
|
|
284
|
+
'query-string': {
|
|
285
|
+
imported: true,
|
|
286
|
+
},
|
|
274
287
|
},
|
|
275
|
-
// generateReportMessage: (source, imported) =>
|
|
276
|
-
// `${source}${imported && `/${imported}`} はXxxxxxなので利用せず yyyy/zzzz を利用してください`
|
|
277
288
|
}
|
|
278
289
|
]
|
|
279
290
|
},
|
|
@@ -283,6 +294,7 @@ import globalModulePart from '@/modules/views/parts'
|
|
|
283
294
|
### ❌ Incorrect
|
|
284
295
|
|
|
285
296
|
```js
|
|
297
|
+
// src/pages/views/Page.tsx
|
|
286
298
|
import queryString from 'query-string'
|
|
287
299
|
import { SecondaryButtonAnchor } from 'smarthr-ui'
|
|
288
300
|
```
|
|
@@ -291,10 +303,101 @@ import { SecondaryButtonAnchor } from 'smarthr-ui'
|
|
|
291
303
|
|
|
292
304
|
|
|
293
305
|
```js
|
|
306
|
+
// src/pages/views/Page.tsx
|
|
294
307
|
import { PrimaryButton, SecondaryButton } from 'smarthr-ui'
|
|
295
308
|
```
|
|
296
309
|
|
|
310
|
+
## smarthr/require-import
|
|
311
|
+
|
|
312
|
+
- 対象ファイルにimportを強制させたい場合に利用します
|
|
313
|
+
- 例: Page.tsx ではページタイトルを設定させたいので useTitle を必ずimportさせたい
|
|
314
|
+
|
|
315
|
+
### rules
|
|
316
|
+
|
|
317
|
+
```js
|
|
318
|
+
{
|
|
319
|
+
rules: {
|
|
320
|
+
'smarthr/require-import': [
|
|
321
|
+
'error',
|
|
322
|
+
{
|
|
323
|
+
'Buttons\/.+\.tsx': {
|
|
324
|
+
'smarthr-ui': {
|
|
325
|
+
imported: ['SecondaryButton'],
|
|
326
|
+
reportMessage: 'Buttons以下のコンポーネントでは {{module}}/{{export}} を拡張するようにしてください',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
'Page.tsx$': {
|
|
330
|
+
'./client/src/hooks/useTitle': {
|
|
331
|
+
imported: true,
|
|
332
|
+
reportMessage: '{{module}} を利用してください(ページタイトルを設定するため必要です)',
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
]
|
|
337
|
+
},
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### ❌ Incorrect
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
// client/src/Buttons/SecondaryButton.tsx
|
|
345
|
+
import { SecondaryButtonAnchor } from 'smarthr-ui'
|
|
346
|
+
|
|
347
|
+
// client/src/Page.tsx
|
|
348
|
+
import { SecondaryButton } from 'smarthr-ui'
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### ✅ Correct
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
// client/src/Buttons/SecondaryButton.tsx
|
|
356
|
+
import { SecondaryButton } from 'smarthr-ui'
|
|
357
|
+
|
|
358
|
+
// client/src/Page.tsx
|
|
359
|
+
import useTitle from '.hooks/useTitle'
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## smarthr/require-barrel-import
|
|
363
|
+
|
|
364
|
+
- tsconfig.json の compilerOptions.pathsに '@/*' としてroot path を指定する必要があります
|
|
365
|
+
- importした対象が本来exportされているべきであるbarrel(index.tsなど)が有る場合、import pathの変更を促します
|
|
366
|
+
- 例: Page/parts/Menu/Item の import は Page/parts/Menu から行わせたい
|
|
367
|
+
- ディレクトリ内のindexファイルを捜査し、対象を決定します
|
|
368
|
+
|
|
369
|
+
### rules
|
|
370
|
+
|
|
371
|
+
```js
|
|
372
|
+
{
|
|
373
|
+
rules: {
|
|
374
|
+
'smarthr/require-barrel-import': 'error',
|
|
375
|
+
},
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### ❌ Incorrect
|
|
297
380
|
|
|
381
|
+
```js
|
|
382
|
+
// client/src/views/Page/parts/Menu/index.ts
|
|
383
|
+
export { Menu } from './Menu'
|
|
384
|
+
export { Item } from './Item'
|
|
385
|
+
|
|
386
|
+
// client/src/App.tsx
|
|
387
|
+
import { Item } from './Page/parts/Menu/Item'
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### ✅ Correct
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
```js
|
|
394
|
+
// client/src/views/Page/parts/Menu/index.ts
|
|
395
|
+
export { Menu } from './Menu'
|
|
396
|
+
export { Item } from './Item'
|
|
397
|
+
|
|
398
|
+
// client/src/App.tsx
|
|
399
|
+
import { Item } from './Page/parts/Menu'
|
|
400
|
+
```
|
|
298
401
|
|
|
299
402
|
|
|
300
403
|
## smarthr/redundant-name
|
|
@@ -305,47 +408,14 @@ import { PrimaryButton, SecondaryButton } from 'smarthr-ui'
|
|
|
305
408
|
### config
|
|
306
409
|
|
|
307
410
|
- tsconfig.json の compilerOptions.pathsに '@/*' としてroot path を指定する必要があります
|
|
308
|
-
-
|
|
411
|
+
- 以下の設定を行えます。全て省略可能です。
|
|
309
412
|
- ignoreKeywords
|
|
310
413
|
- ディレクトリ名から生成されるキーワードに含めたくない文字列を指定します
|
|
311
|
-
-
|
|
312
|
-
-
|
|
313
|
-
-
|
|
414
|
+
- betterNames
|
|
415
|
+
- 対象の名前を修正する候補を指定します
|
|
416
|
+
- suffix:
|
|
314
417
|
- type のみ指定出来ます
|
|
315
|
-
- type のsuffix
|
|
316
|
-
|
|
317
|
-
#### 指定例
|
|
318
|
-
```
|
|
319
|
-
const ignorekeywords = ['views', 'parts']
|
|
320
|
-
const keywordGenerator = ({ keywords }) => (
|
|
321
|
-
keywords.reduce((prev, keyword, index) => {
|
|
322
|
-
switch (keyword) {
|
|
323
|
-
case 'repositories':
|
|
324
|
-
return [...prev, keyword, 'repository']
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const replacedKeyword = keyword.replace(/(repository|s)$/, '')
|
|
328
|
-
if (keyword !== replacedKeyword) {
|
|
329
|
-
return [...prev, keyword, replacedKeyword]
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return [...prev, keyword]
|
|
333
|
-
}, [])
|
|
334
|
-
)
|
|
335
|
-
// 例: actions 以下の場合だけ 'Action' もしくは `Actions` のSuffixを許可する
|
|
336
|
-
const suffixGenerator = ({ node, filename }) => {
|
|
337
|
-
let suffix = ['Props', 'Type']
|
|
338
|
-
|
|
339
|
-
if (filename.match(/\/actions\//)) {
|
|
340
|
-
suffix = [
|
|
341
|
-
isUnionType || (node.typeAnnotation.type === 'TSTypeReference' && node.id.name.match(/Actions$/))
|
|
342
|
-
? 'Actions'
|
|
343
|
-
: 'Action',
|
|
344
|
-
...suffix,
|
|
345
|
-
]
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
```
|
|
418
|
+
- type のsuffixを指定します
|
|
349
419
|
|
|
350
420
|
#### ファイル例
|
|
351
421
|
- `@/crews/index/views/page.tsx` の場合
|
|
@@ -359,17 +429,33 @@ const suffixGenerator = ({ node, filename }) => {
|
|
|
359
429
|
### rules
|
|
360
430
|
|
|
361
431
|
```js
|
|
432
|
+
const ignorekeywords = ['views', 'parts']
|
|
433
|
+
const betterNames = {
|
|
434
|
+
'\/repositories\/': {
|
|
435
|
+
operator: '-',
|
|
436
|
+
names: ['repository', 'Repository'],
|
|
437
|
+
},
|
|
438
|
+
'\/entities\/': {
|
|
439
|
+
operator: '+',
|
|
440
|
+
names: ['entity'],
|
|
441
|
+
},
|
|
442
|
+
'\/slices\/': {
|
|
443
|
+
operator: '=',
|
|
444
|
+
names: ['index'],
|
|
445
|
+
},
|
|
446
|
+
}
|
|
447
|
+
|
|
362
448
|
{
|
|
363
449
|
rules: {
|
|
364
450
|
'smarthr/redundant-name': [
|
|
365
451
|
'error', // 'warn', 'off'
|
|
366
452
|
{
|
|
367
|
-
type: { ignorekeywords,
|
|
368
|
-
file: { ignorekeywords,
|
|
369
|
-
// property: { ignorekeywords
|
|
370
|
-
// function: { ignorekeywords
|
|
371
|
-
// variable: { ignorekeywords
|
|
372
|
-
// class: { ignorekeywords
|
|
453
|
+
type: { ignorekeywords, suffix: ['Props', 'Type'] },
|
|
454
|
+
file: { ignorekeywords, betternames },
|
|
455
|
+
// property: { ignorekeywords },
|
|
456
|
+
// function: { ignorekeywords },
|
|
457
|
+
// variable: { ignorekeywords },
|
|
458
|
+
// class: { ignorekeywords },
|
|
373
459
|
}
|
|
374
460
|
]
|
|
375
461
|
},
|
package/jest.config.js
ADDED
package/libs/common_domain.js
CHANGED
|
@@ -6,7 +6,6 @@ const BASE_SCHEMA_PROPERTIES = {
|
|
|
6
6
|
globalModuleDir: { type: 'array', items: { type: 'string' } },
|
|
7
7
|
domainModuleDir: { type: 'array', items: { type: 'string' }, default: [] },
|
|
8
8
|
domainConstituteDir: { type: 'array', items: { type: 'string' } },
|
|
9
|
-
isDomain: { type: 'function' },
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
const calculateDomainContext = (context) => {
|
|
@@ -87,13 +86,14 @@ const calculateDomainNode = (calclatedContext, node) => {
|
|
|
87
86
|
let filteredDirs = dirs
|
|
88
87
|
let filteredPaths = paths
|
|
89
88
|
|
|
89
|
+
const deductedNames = []
|
|
90
90
|
const recursiveDeductionEq = () => {
|
|
91
91
|
if (dirs.length === 0 || paths.length === 0) {
|
|
92
92
|
return
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
if (dirs[0] === paths[0]) {
|
|
96
|
-
dirs.shift()
|
|
96
|
+
deductedNames.push(dirs.shift())
|
|
97
97
|
paths.shift()
|
|
98
98
|
recursiveDeductionEq()
|
|
99
99
|
}
|
|
@@ -102,21 +102,22 @@ const calculateDomainNode = (calclatedContext, node) => {
|
|
|
102
102
|
filteredDirs = dirs
|
|
103
103
|
filteredPaths = paths
|
|
104
104
|
|
|
105
|
+
let isDomainConstitute = false
|
|
106
|
+
|
|
105
107
|
if (option.domainConstituteDir) {
|
|
108
|
+
const { domainConstituteDir } = option
|
|
109
|
+
isDomainConstitute =
|
|
110
|
+
!!deductedNames.find((d) => domainConstituteDir.includes(d)) || // 同一dirを削り、その中にconstitute dir があれば同一ドメイン
|
|
111
|
+
domainConstituteDir.includes(dirs[0]) && domainConstituteDir.includes(paths[0]) // 同一を削りきった先頭が両方constitute dirならば同一ドメイン
|
|
112
|
+
|
|
106
113
|
// HINT: 同一ドメイン内(例: workflows/index)で定形で利用されるディレクトリ名を省くことで
|
|
107
114
|
// ドメインの識別に利用される文字を抽出する
|
|
108
115
|
dirs = dirs.filter((k) => !option.domainConstituteDir.includes(k))
|
|
109
116
|
paths = paths.filter((k) => !option.domainConstituteDir.includes(k))
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
if (option.isDomain) {
|
|
113
|
-
// HINT: ドメインの識別に利用される文字を抽出する
|
|
114
|
-
dirs = dirs.filter((k) => option.isDomain(k))
|
|
115
|
-
paths = paths.filter((k) => option.isDomain(k))
|
|
116
|
-
}
|
|
117
|
-
|
|
118
119
|
const isLowerImport = filteredDirs.length === 0 // 同一階層、もしくは下層からのimport
|
|
119
|
-
const isDomainImport = dirs.length === 0 // 同一ドメイン内、もしくは同一階層・下層からのimport
|
|
120
|
+
const isDomainImport = dirs.length === 0 || isDomainConstitute // 同一ドメイン内、もしくは同一階層・下層からのimport
|
|
120
121
|
const isModuleImport = paths.length > 0 && option.domainModuleDir.includes(paths[0]) // ドメイン内共通パーツ
|
|
121
122
|
|
|
122
123
|
return {
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-smarthr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"author": "SmartHR",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A sharable ESLint plugin for SmartHR",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
+
"test": "jest",
|
|
9
10
|
"release:dryrun": "standard-version --dry-run",
|
|
10
11
|
"release": "standard-version"
|
|
11
12
|
},
|
|
@@ -21,9 +22,12 @@
|
|
|
21
22
|
"url": "https://github.com/kufu/eslint-plugin-smarthr/issues"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
25
|
+
"inflected": "^2.1.0",
|
|
24
26
|
"json5": "^2.2.0"
|
|
25
27
|
},
|
|
26
28
|
"devDependencies": {
|
|
29
|
+
"eslint": "^8.8.0",
|
|
30
|
+
"jest": "^27.4.7",
|
|
27
31
|
"standard-version": "^9.3.2"
|
|
28
32
|
},
|
|
29
33
|
"peerDependencies": {
|
|
@@ -1,38 +1,72 @@
|
|
|
1
|
+
const SCHEMA = [
|
|
2
|
+
{
|
|
3
|
+
type: 'object',
|
|
4
|
+
properties: {
|
|
5
|
+
fix: { type: 'boolean', default: false },
|
|
6
|
+
},
|
|
7
|
+
additionalProperties: false,
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
|
|
1
11
|
module.exports = {
|
|
2
12
|
meta: {
|
|
3
13
|
type: 'suggestion',
|
|
4
14
|
messages: {
|
|
5
15
|
'jsx-start-with-spread-attributes': '{{ message }}',
|
|
6
16
|
},
|
|
7
|
-
|
|
17
|
+
fixable: 'code',
|
|
18
|
+
schema: SCHEMA,
|
|
8
19
|
},
|
|
9
20
|
create(context) {
|
|
10
21
|
return {
|
|
11
22
|
JSXSpreadAttribute: (node) => {
|
|
12
|
-
// HINT:
|
|
13
|
-
const
|
|
14
|
-
if (h ===
|
|
23
|
+
// HINT: -2: 計算中 -1: 見つからなかった >= 0: 見つかった
|
|
24
|
+
const insertIndex = node.parent.attributes.reduce((h, a, i) => {
|
|
25
|
+
if (h === -2) {
|
|
15
26
|
if (a === node) {
|
|
16
|
-
return 1
|
|
27
|
+
return -1
|
|
17
28
|
}
|
|
18
29
|
|
|
19
|
-
return a.type !== 'JSXSpreadAttribute' ?
|
|
30
|
+
return a.type !== 'JSXSpreadAttribute' ? i : h
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
return h
|
|
23
|
-
},
|
|
34
|
+
}, -2)
|
|
35
|
+
|
|
36
|
+
if (insertIndex >= 0) {
|
|
37
|
+
const option = context.options[0]
|
|
38
|
+
const sourceCode = context.getSourceCode()
|
|
39
|
+
const attributeCode = sourceCode.getText(node)
|
|
24
40
|
|
|
25
|
-
if (hit === 2) {
|
|
26
41
|
context.report({
|
|
27
42
|
node,
|
|
28
43
|
messageId: 'jsx-start-with-spread-attributes',
|
|
29
44
|
data: {
|
|
30
|
-
message: `"${
|
|
45
|
+
message: `"${attributeCode}" は意図しない上書きを防ぐため、spread attributesでない属性より先に記述してください`,
|
|
31
46
|
},
|
|
47
|
+
fix: option?.fix ? (fixer) => {
|
|
48
|
+
const elementNode = node.parent
|
|
49
|
+
const sortedAttributes = [...elementNode.attributes].reduce((p, a, i) => {
|
|
50
|
+
if (insertIndex === i) {
|
|
51
|
+
p = [attributeCode, ...p]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (a !== node) {
|
|
55
|
+
p = [...p, sourceCode.getText(a)]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return p
|
|
59
|
+
}, [])
|
|
60
|
+
|
|
61
|
+
return fixer.replaceText(
|
|
62
|
+
elementNode,
|
|
63
|
+
`<${elementNode.name.name} ${sortedAttributes.join(' ')}${elementNode.selfClosing ? '/' : ''}>`
|
|
64
|
+
)
|
|
65
|
+
} : null
|
|
32
66
|
});
|
|
33
67
|
}
|
|
34
68
|
},
|
|
35
69
|
}
|
|
36
70
|
},
|
|
37
71
|
}
|
|
38
|
-
module.exports.schema =
|
|
72
|
+
module.exports.schema = SCHEMA
|
package/rules/prohibit-import.js
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
const SCHEMA = [{
|
|
4
|
+
type: 'object',
|
|
5
|
+
patternProperties: {
|
|
6
|
+
'.+': {
|
|
7
|
+
type: 'object',
|
|
8
|
+
patternProperties: {
|
|
9
|
+
'.+': {
|
|
10
|
+
type: 'object',
|
|
11
|
+
required: [
|
|
12
|
+
'imported',
|
|
13
|
+
],
|
|
14
|
+
properties: {
|
|
15
|
+
imported: {
|
|
16
|
+
type: ['boolean', 'array'],
|
|
17
|
+
items: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
reportMessage: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
7
28
|
},
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
]
|
|
29
|
+
},
|
|
30
|
+
additionalProperties: true,
|
|
31
|
+
}]
|
|
11
32
|
|
|
12
|
-
const
|
|
33
|
+
const defaultReportMessage = (moduleName, exportName) => `${moduleName}${typeof exportName == 'string' ? `/${exportName}`: ''} は利用しないでください`
|
|
13
34
|
|
|
14
35
|
module.exports = {
|
|
15
36
|
meta: {
|
|
@@ -20,38 +41,64 @@ module.exports = {
|
|
|
20
41
|
schema: SCHEMA,
|
|
21
42
|
},
|
|
22
43
|
create(context) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
44
|
+
const options = context.options[0]
|
|
45
|
+
const filename = context.getFilename()
|
|
46
|
+
const parentDir = (() => {
|
|
47
|
+
const dir = filename.match(/^(.+?)\..+?$/)[1].split('/')
|
|
48
|
+
dir.pop()
|
|
49
|
+
|
|
50
|
+
return dir.join('/')
|
|
51
|
+
})()
|
|
52
|
+
const targetPathRegexs = Object.keys(options)
|
|
53
|
+
const targetProhibits = targetPathRegexs.filter((regex) => !!filename.match(new RegExp(regex)))
|
|
54
|
+
|
|
55
|
+
if (targetProhibits.length === 0) {
|
|
56
|
+
return {}
|
|
57
|
+
}
|
|
26
58
|
|
|
27
59
|
return {
|
|
28
60
|
ImportDeclaration: (node) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
targetProhibits.forEach((prohibitKey) => {
|
|
62
|
+
const option = options[prohibitKey]
|
|
63
|
+
const targetModules = Object.keys(option)
|
|
64
|
+
|
|
65
|
+
targetModules.forEach((targetModule) => {
|
|
66
|
+
const { imported, reportMessage } = Object.assign({imported: true}, option[targetModule])
|
|
67
|
+
const actualTarget = targetModule[0] !== '.' ? targetModule : path.resolve(`${process.cwd()}/${targetModule}`)
|
|
68
|
+
let sourceValue = node.source.value
|
|
69
|
+
|
|
70
|
+
if (actualTarget[0] === '/') {
|
|
71
|
+
sourceValue = path.resolve(`${parentDir}/${sourceValue}`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (actualTarget !== sourceValue) {
|
|
75
|
+
return
|
|
37
76
|
}
|
|
38
|
-
|
|
77
|
+
|
|
78
|
+
const useImported = (() => {
|
|
79
|
+
if (!Array.isArray(imported)) {
|
|
80
|
+
return !!imported
|
|
81
|
+
}
|
|
39
82
|
|
|
40
|
-
|
|
41
|
-
})()
|
|
83
|
+
const specifier = node.specifiers.find((s) => s.imported && imported.includes(s.imported.name))
|
|
42
84
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
85
|
+
return specifier ? specifier.imported.name : false
|
|
86
|
+
})()
|
|
87
|
+
|
|
88
|
+
if (useImported) {
|
|
89
|
+
context.report({
|
|
90
|
+
node,
|
|
91
|
+
messageId: 'prohibit_import',
|
|
92
|
+
data: {
|
|
93
|
+
message: reportMessage ? reportMessage.replace('{{module}}', node.source.value).replace('{{export}}', useImported) : defaultReportMessage(node.source.value, useImported)
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
})
|
|
52
98
|
})
|
|
53
99
|
},
|
|
54
100
|
}
|
|
55
101
|
},
|
|
56
102
|
}
|
|
103
|
+
|
|
57
104
|
module.exports.schema = SCHEMA
|