eslint-plugin-smarthr 0.0.1 → 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/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
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.1.0](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.1...v0.1.0) (2022-02-09)
6
+
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * update prohibit-imoprt option
11
+
12
+ * chore: require-importの対象ファイル指定方法をoptionの第一階層のkeyにする
13
+
14
+ * chore: update README.md
15
+
16
+ * chore: require-importのdefaultReportMessageを修正
17
+
18
+ * chore: update yarn.lock
19
+
20
+ * chore: fix test
21
+
22
+ * chore: add test
23
+
24
+ * chore: refactoring prohibit-import
25
+
26
+ * chore: add test
27
+
28
+ * 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)
29
+
5
30
  ### [0.0.1](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.0...v0.0.1) (2022-02-08)
6
31
 
7
32
 
@@ -10,9 +35,6 @@ All notable changes to this project will be documented in this file. See [standa
10
35
  * add type property function params redundant ([758df90](https://github.com/kufu/eslint-plugin-smarthr/commit/758df90f89bd27dd589aeeb55165e27c8e072b08))
11
36
  * redundant-name の修正候補を操作できるように改修 ([20991e8](https://github.com/kufu/eslint-plugin-smarthr/commit/20991e874890556e84e7c682e789e4b2650a85b0))
12
37
 
13
- ### [0.0.2](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.1...v0.0.2) (2022-01-26)
14
-
15
- ### [0.0.1](https://github.com/kufu/eslint-plugin-smarthr/compare/v0.0.0...v0.0.1) (2022-01-26)
16
38
 
17
39
  ## 0.0.0 (2022-01-25)
18
40
 
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': 'error', // 'warn', 'off'
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
- targets: {
272
- '^query-string$': true, // key は 正規表現を指定する
273
- '^smarthr-ui$': ['SecondaryButtonAnchor'],
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,61 @@ 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'
297
357
 
358
+ // client/src/Page.tsx
359
+ import useTitle from '.hooks/useTitle'
360
+ ```
298
361
 
299
362
 
300
363
  ## smarthr/redundant-name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-smarthr",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "author": "SmartHR",
5
5
  "license": "MIT",
6
6
  "description": "A sharable ESLint plugin for SmartHR",
@@ -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
- schema: [],
17
+ fixable: 'code',
18
+ schema: SCHEMA,
8
19
  },
9
20
  create(context) {
10
21
  return {
11
22
  JSXSpreadAttribute: (node) => {
12
- // HINT: 0: 計算中 1: 見つからなかった 2: 見つかった
13
- const hit = node.parent.attributes.reduce((h, a) => {
14
- if (h === 0) {
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' ? 2 : 0
30
+ return a.type !== 'JSXSpreadAttribute' ? i : h
20
31
  }
21
32
 
22
33
  return h
23
- }, 0)
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: `"${context.getSourceCode().getText(node)}" は他の属性より先に記述してください`,
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
@@ -1,28 +1,34 @@
1
+ const path = require('path')
2
+
1
3
  const SCHEMA = [{
2
- type: "object",
4
+ type: 'object',
3
5
  patternProperties: {
4
- ".+": {
5
- type: "object",
6
- required: [
7
- "imported",
8
- ],
9
- properties: {
10
- imported: {
11
- type: ["boolean", "array"],
12
- items: {
13
- type: "string"
14
- }
15
- },
16
- reportMessage: {
17
- type: "string"
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
18
26
  }
19
- },
20
- additionalProperties: false
21
27
  }
22
28
  },
23
- additionalProperties: true,
24
- }
25
- ]
29
+ },
30
+ additionalProperties: true,
31
+ }]
26
32
 
27
33
  const defaultReportMessage = (moduleName, exportName) => `${moduleName}${typeof exportName == 'string' ? `/${exportName}`: ''} は利用しないでください`
28
34
 
@@ -36,34 +42,59 @@ module.exports = {
36
42
  },
37
43
  create(context) {
38
44
  const options = context.options[0]
39
- const targetModules = Object.keys(options)
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
+ }
58
+
40
59
  return {
41
60
  ImportDeclaration: (node) => {
42
- targetModules.forEach((targetModule) => {
43
- if (!node.source.value.match(new RegExp(targetModule))) {
44
- return
45
- }
46
-
47
- const {imported, reportMessage} = Object.assign({imported: true}, options[targetModule])
48
- const useImported = (() => {
49
- if (!Array.isArray(imported)) {
50
- return !!imported
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}`)
51
72
  }
52
73
 
53
- const specifier = node.specifiers.find((s) => s.imported && imported.includes(s.imported.name))
74
+ if (actualTarget !== sourceValue) {
75
+ return
76
+ }
77
+
78
+ const useImported = (() => {
79
+ if (!Array.isArray(imported)) {
80
+ return !!imported
81
+ }
54
82
 
55
- return specifier ? specifier.imported.name : false
56
- })()
83
+ const specifier = node.specifiers.find((s) => s.imported && imported.includes(s.imported.name))
57
84
 
58
- if (useImported) {
59
- context.report({
60
- node,
61
- messageId: 'prohibit_import',
62
- data: {
63
- message: reportMessage ? reportMessage.replace('{{module}}', node.source.value).replace('{{export}}', useImported) : defaultReportMessage(node.source.value, useImported)
64
- },
65
- });
66
- }
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
+ })
67
98
  })
68
99
  },
69
100
  }
@@ -0,0 +1,113 @@
1
+ const path = require('path')
2
+ const SCHEMA = [{
3
+ type: 'object',
4
+ patternProperties: {
5
+ '.+': {
6
+ type: 'object',
7
+ patternProperties: {
8
+ '.+': {
9
+ type: 'object',
10
+ required: [
11
+ 'imported',
12
+ ],
13
+ properties: {
14
+ imported: {
15
+ type: ['boolean', 'array'],
16
+ items: {
17
+ type: 'string',
18
+ }
19
+ },
20
+ reportMessage: {
21
+ type: 'string',
22
+ },
23
+ },
24
+ additionalProperties: false,
25
+ }
26
+ },
27
+ additionalProperties: true,
28
+ },
29
+ },
30
+ additionalProperties: true,
31
+ }]
32
+
33
+ const defaultReportMessage = (moduleName, exportName) => `${moduleName}${typeof exportName == 'string' ? `/${exportName}`: ''} をimportしてください`
34
+
35
+ module.exports = {
36
+ meta: {
37
+ type: 'suggestion',
38
+ messages: {
39
+ 'require_import': '{{ message }}',
40
+ },
41
+ schema: SCHEMA,
42
+ },
43
+ create(context) {
44
+ const options = context.options[0]
45
+ const filename = context.getFilename()
46
+ const targetPathRegexs = Object.keys(options)
47
+ const targetRequires = targetPathRegexs.filter((regex) => !!filename.match(new RegExp(regex)))
48
+
49
+ if (targetRequires.length === 0) {
50
+ return {}
51
+ }
52
+
53
+ return {
54
+ Program: (node) => {
55
+ const importDeclarations = node.body.filter((item) => item.type === 'ImportDeclaration')
56
+ const parentDir = (() => {
57
+ const dir = filename.match(/^(.+?)\..+?$/)[1].split('/')
58
+ dir.pop()
59
+
60
+ return dir.join('/')
61
+ })()
62
+
63
+ targetRequires.forEach((requireKey) => {
64
+ const option = options[requireKey]
65
+
66
+ Object.keys(option).forEach((targetModule) => {
67
+ const { imported, reportMessage, targetRegex } = Object.assign({imported: true}, option[targetModule])
68
+
69
+ if (targetRegex && !filename.match(new RegExp(targetRegex))) {
70
+ return
71
+ }
72
+
73
+ const actualTarget = targetModule[0] !== '.' ? targetModule : path.resolve(`${process.cwd()}/${targetModule}`)
74
+ const importDeclaration = importDeclarations.find(
75
+ actualTarget[0] !== '/' ? (
76
+ (id) => id.source.value === actualTarget
77
+ ) : (
78
+ (id) => path.resolve(`${parentDir}/${id.source.value}`) === actualTarget
79
+ )
80
+ )
81
+ const reporter = (item) => {
82
+ context.report({
83
+ node,
84
+ messageId: 'require_import',
85
+ data: {
86
+ message: reportMessage ? reportMessage.replace('{{module}}', actualTarget).replace('{{export}}', item) : defaultReportMessage(actualTarget, item)
87
+ },
88
+ })
89
+ }
90
+
91
+ if (!importDeclaration) {
92
+ if (Array.isArray(imported)) {
93
+ imported.forEach((i) => {
94
+ reporter(i)
95
+ })
96
+ } else if (imported) {
97
+ reporter()
98
+ }
99
+ } else if (Array.isArray(imported)) {
100
+ imported.forEach((i) => {
101
+ if (!importDeclaration.specifiers.find((s) => s.imported && s.imported.name === i)) {
102
+ reporter(i)
103
+ }
104
+ })
105
+ }
106
+ })
107
+ })
108
+ },
109
+ }
110
+ },
111
+ }
112
+
113
+ module.exports.schema = SCHEMA
@@ -1,63 +1,104 @@
1
- const rule = require("../rules/prohibit-import")
2
- const RuleTester = require("eslint").RuleTester
1
+ const rule = require('../rules/prohibit-import')
2
+ const RuleTester = require('eslint').RuleTester
3
3
 
4
4
  const ruleTester = new RuleTester({
5
5
  parserOptions: {
6
- sourceType: "module",
6
+ sourceType: 'module',
7
7
  ecmaVersion: 2015
8
8
  },
9
9
  })
10
10
 
11
- ruleTester.run("prohibit-import-lodash", rule, {
11
+ ruleTester.run('prohibit-import', rule, {
12
12
  valid: [
13
13
  {
14
14
  code: `import _ from 'lodash-es'`,
15
+ filename: 'hoge.js',
15
16
  options: [
16
17
  {
17
- '^lodash$': {
18
- imported: true,
18
+ '^.+$': {
19
+ 'lodash': {
20
+ imported: true,
21
+ },
19
22
  },
20
23
  }
21
24
  ]
22
25
  },
23
26
  {
24
27
  code: `import { isEqual } from 'lodash-es'`,
28
+ filename: 'hoge.js',
25
29
  options: [
26
30
  {
27
- '^lodash$': {
28
- imported: ['isEqual']
31
+ '^.+$': {
32
+ 'lodash': {
33
+ imported: ['isEqual']
34
+ },
29
35
  },
30
36
  }
31
37
  ]
32
38
  },
33
39
  {
34
40
  code: `import { isEqaul } from 'lodash'`,
41
+ filename: 'hoge.js',
35
42
  options: [
36
43
  {
37
- '^lodash$': {
38
- imported: ['isEqual']
44
+ '^.+$': {
45
+ 'lodash': {
46
+ imported: ['isEqual']
47
+ },
39
48
  },
40
49
  }
41
50
  ]
42
51
  },
43
52
  {
44
53
  code: `import _ from 'lodash'`,
54
+ filename: 'hoge.js',
45
55
  options: [
46
56
  {
47
- '^lodash$': {
48
- imported: ['isEqual']
57
+ '^.+$': {
58
+ 'lodash': {
59
+ imported: ['isEqual']
60
+ },
49
61
  },
50
62
  }
51
63
  ]
52
- }
64
+ },
65
+ {
66
+ code: `import _ from 'lodash'`,
67
+ filename: 'hoge.js',
68
+ options: [
69
+ {
70
+ '^fuga.js$': {
71
+ 'lodash': {
72
+ imported: true
73
+ },
74
+ },
75
+ }
76
+ ],
77
+ },
78
+ {
79
+ code: `import { isEqual } from './module/validator'`,
80
+ filename: 'page/hoge.js',
81
+ options: [
82
+ {
83
+ '^.+$': {
84
+ './module/validator': {
85
+ imported: ['isEqual'],
86
+ },
87
+ },
88
+ }
89
+ ],
90
+ },
53
91
  ],
54
92
  invalid: [
55
93
  {
56
94
  code: `import _ from 'lodash'`,
95
+ filename: 'hoge.js',
57
96
  options: [
58
97
  {
59
- '^lodash$': {
60
- imported: true
98
+ '^.+$': {
99
+ 'lodash': {
100
+ imported: true
101
+ },
61
102
  },
62
103
  }
63
104
  ],
@@ -65,10 +106,13 @@ ruleTester.run("prohibit-import-lodash", rule, {
65
106
  },
66
107
  {
67
108
  code: `import { isEqual } from 'lodash'`,
109
+ filename: 'hoge.js',
68
110
  options: [
69
111
  {
70
- '^lodash$': {
71
- imported: true
112
+ '^.+$': {
113
+ 'lodash': {
114
+ imported: true
115
+ },
72
116
  },
73
117
  }
74
118
  ],
@@ -76,10 +120,13 @@ ruleTester.run("prohibit-import-lodash", rule, {
76
120
  },
77
121
  {
78
122
  code: `import { isEqual } from 'lodash'`,
123
+ filename: 'hoge.js',
79
124
  options: [
80
125
  {
81
- '^lodash$': {
82
- imported: ['isEqual']
126
+ '^.+$': {
127
+ 'lodash': {
128
+ imported: ['isEqual']
129
+ },
83
130
  },
84
131
  }
85
132
  ],
@@ -87,11 +134,14 @@ ruleTester.run("prohibit-import-lodash", rule, {
87
134
  },
88
135
  {
89
136
  code: `import { isEqual } from 'lodash'`,
137
+ filename: 'hoge.js',
90
138
  options: [
91
139
  {
92
- '^lodash$': {
93
- imported: ['isEqual'],
94
- "reportMessage": "must not use {{module}}/{{export}}"
140
+ '^.+$': {
141
+ 'lodash': {
142
+ imported: ['isEqual'],
143
+ "reportMessage": "must not use {{module}}/{{export}}"
144
+ },
95
145
  },
96
146
  }
97
147
  ],
@@ -99,18 +149,53 @@ ruleTester.run("prohibit-import-lodash", rule, {
99
149
  },
100
150
  {
101
151
  code: `import { isEqual } from 'lodash'`,
152
+ filename: 'hoge.js',
102
153
  options: [
103
154
  {
104
- 'example': {
105
- imported: true,
155
+ '^.+$': {
156
+ 'example': {
157
+ imported: true,
158
+ },
159
+ 'lodash': {
160
+ imported: ['isEqual'],
161
+ reportMessage: "must not use {{module}}/{{export}}",
162
+ },
106
163
  },
107
- '^lodash$': {
108
- imported: ['isEqual'],
109
- reportMessage: "must not use {{module}}/{{export}}",
164
+ }
165
+ ],
166
+ errors: [{message: 'must not use lodash/isEqual'}]
167
+ },
168
+ {
169
+ code: `import { isEqual } from 'lodash'`,
170
+ filename: 'hoge.js',
171
+ options: [
172
+ {
173
+ '^hoge.js$': {
174
+ 'example': {
175
+ imported: true,
176
+ },
177
+ 'lodash': {
178
+ imported: ['isEqual'],
179
+ reportMessage: "must not use {{module}}/{{export}}",
180
+ },
110
181
  },
111
182
  }
112
183
  ],
113
184
  errors: [{message: 'must not use lodash/isEqual'}]
114
- }
185
+ },
186
+ {
187
+ code: `import { isEqual } from './module/validator'`,
188
+ filename: 'page/hoge.js',
189
+ options: [
190
+ {
191
+ '^.+$': {
192
+ './page/module/validator': {
193
+ imported: ['isEqual'],
194
+ },
195
+ },
196
+ }
197
+ ],
198
+ errors: [{ message: './module/validator/isEqual は利用しないでください' }]
199
+ },
115
200
  ]
116
- })
201
+ })
@@ -0,0 +1,184 @@
1
+ const rule = require('../rules/require-import')
2
+ const RuleTester = require('eslint').RuleTester
3
+
4
+ const ruleTester = new RuleTester({
5
+ parserOptions: {
6
+ sourceType: 'module',
7
+ ecmaVersion: 2015
8
+ },
9
+ })
10
+
11
+ ruleTester.run('require-import', rule, {
12
+ valid: [
13
+ {
14
+ code: `import _ from 'lodash'`,
15
+ filename: 'hoge.js',
16
+ options: [
17
+ {
18
+ '^.+$': {
19
+ 'lodash': {
20
+ imported: true,
21
+ },
22
+ },
23
+ }
24
+ ],
25
+ },
26
+ {
27
+ code: ``,
28
+ filename: 'hoge.js',
29
+ options: [
30
+ {
31
+ '^fuga.js$': {
32
+ 'lodash': {
33
+ imported: true,
34
+ },
35
+ },
36
+ }
37
+ ],
38
+ },
39
+ {
40
+ code: `import _ from 'lodash'`,
41
+ filename: 'hoge.js',
42
+ options: [
43
+ {
44
+ '^hoge.js$': {
45
+ 'lodash': {
46
+ imported: true,
47
+ reportMessage: '{{module}} を絶対使ってください'
48
+ },
49
+ },
50
+ }
51
+ ],
52
+ },
53
+ {
54
+ code: `import { isEqual } from 'lodash'`,
55
+ filename: 'hoge.js',
56
+ options: [
57
+ {
58
+ '^hoge.js$': {
59
+ 'lodash': {
60
+ imported: ['isEqual'],
61
+ reportMessage: '{{module}}/{{export}} を絶対使ってください'
62
+ },
63
+ },
64
+ }
65
+ ],
66
+ errors: [{ message: 'lodash/isEqual を絶対使ってください' }],
67
+ },
68
+ {
69
+ code: `import { chunk } from 'lodash'`,
70
+ filename: 'hoge.js',
71
+ options: [
72
+ {
73
+ '^hoge.js$': {
74
+ 'lodash': {
75
+ imported: true,
76
+ },
77
+ },
78
+ }
79
+ ],
80
+ },
81
+ {
82
+ code: `import { isEqual } from './module/validator'`,
83
+ filename: 'page/hoge.js',
84
+ options: [
85
+ {
86
+ '^.+$': {
87
+ './page/module/validator': {
88
+ imported: ['isEqual'],
89
+ },
90
+ },
91
+ }
92
+ ],
93
+ },
94
+ ],
95
+ invalid: [
96
+ {
97
+ code: ``,
98
+ filename: 'hoge.js',
99
+ options: [
100
+ {
101
+ '^.+$': {
102
+ 'lodash': {
103
+ imported: true,
104
+ },
105
+ },
106
+ }
107
+ ],
108
+ errors: [{ message: 'lodash をimportしてください' }],
109
+ },
110
+ {
111
+ code: ``,
112
+ filename: 'hoge.js',
113
+ options: [
114
+ {
115
+ '^hoge.js$': {
116
+ 'lodash': {
117
+ imported: true,
118
+ },
119
+ },
120
+ }
121
+ ],
122
+ errors: [{ message: 'lodash をimportしてください' }],
123
+ },
124
+ {
125
+ code: ``,
126
+ filename: 'hoge.js',
127
+ options: [
128
+ {
129
+ '^hoge.js$': {
130
+ 'lodash': {
131
+ imported: true,
132
+ reportMessage: '{{module}} を絶対使ってください'
133
+ },
134
+ },
135
+ }
136
+ ],
137
+ errors: [{ message: 'lodash を絶対使ってください' }],
138
+ },
139
+ {
140
+ code: ``,
141
+ filename: 'hoge.js',
142
+ options: [
143
+ {
144
+ '^hoge.js$': {
145
+ 'lodash': {
146
+ imported: ['isEqual'],
147
+ reportMessage: '{{module}}/{{export}} を絶対使ってください'
148
+ },
149
+ },
150
+ }
151
+ ],
152
+ errors: [{ message: 'lodash/isEqual を絶対使ってください' }],
153
+ },
154
+ {
155
+ code: `import { chunk } from 'lodash'`,
156
+ filename: 'hoge.js',
157
+ options: [
158
+ {
159
+ '^hoge.js$': {
160
+ 'lodash': {
161
+ imported: ['isEqual'],
162
+ reportMessage: '{{module}}/{{export}} を絶対使ってください'
163
+ },
164
+ },
165
+ }
166
+ ],
167
+ errors: [{ message: 'lodash/isEqual を絶対使ってください' }],
168
+ },
169
+ {
170
+ code: `import { isEqual } from './module/validator'`,
171
+ filename: 'page/hoge.js',
172
+ options: [
173
+ {
174
+ '^.+$': {
175
+ './module/validator': {
176
+ imported: ['isEqual'],
177
+ },
178
+ },
179
+ }
180
+ ],
181
+ errors: [{ message: /module\/validator\/isEqual をimportしてください$/ }],
182
+ },
183
+ ]
184
+ })