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.
@@ -1,8 +1,13 @@
1
1
  const path = require('path')
2
+ const Inflector = require('inflected')
3
+
2
4
  const { rootPath } = require('../libs/common')
3
5
 
4
6
  const uniq = (array) => array.filter((elem, index, self) => self.indexOf(elem) === index)
5
7
 
8
+ const COMMON_DEFAULT_CONFIG = {
9
+ IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
10
+ }
6
11
  const DEFAULT_CONFIG = {
7
12
  type: {
8
13
  IGNORE_KEYWORDS: [
@@ -11,44 +16,56 @@ const DEFAULT_CONFIG = {
11
16
  ],
12
17
  SUFFIX: ['Props', 'Type'],
13
18
  },
14
- file: {
15
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
16
- },
17
- property: {
18
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
19
- },
20
- function: {
21
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
22
- },
23
- variable: {
24
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
25
- },
26
- class: {
27
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
28
- },
29
- method: {
30
- IGNORE_KEYWORDS: ['redux', 'views', 'pages', 'parts'],
31
- },
19
+ typeProperty: COMMON_DEFAULT_CONFIG,
20
+ file: COMMON_DEFAULT_CONFIG,
21
+ property: COMMON_DEFAULT_CONFIG,
22
+ function: COMMON_DEFAULT_CONFIG,
23
+ functionParams: COMMON_DEFAULT_CONFIG,
24
+ variable: COMMON_DEFAULT_CONFIG,
25
+ class: COMMON_DEFAULT_CONFIG,
26
+ method: COMMON_DEFAULT_CONFIG,
32
27
  }
33
28
 
29
+ const BETTER_NAMES_CALCULATER_PROPERTY = {
30
+ type: 'object',
31
+ properties: {
32
+ operator: ['-', '+', '='],
33
+ names: {
34
+ type: 'array',
35
+ items: 'string',
36
+ },
37
+ },
38
+ }
34
39
  const DEFAULT_SCHEMA_PROPERTY = {
35
40
  ignoreKeywords: { type: 'array', items: { type: 'string' } },
36
- keywordGenerator: { type: 'function' },
41
+ betterNames: {
42
+ type: 'object',
43
+ properties: {
44
+ operator: ['-', '+', '='],
45
+ names: {
46
+ type: 'array',
47
+ items: 'string',
48
+ },
49
+ },
50
+ },
37
51
  }
38
52
 
39
53
  const SCHEMA = [
40
54
  {
41
55
  type: 'object',
42
56
  properties: {
43
- file: DEFAULT_SCHEMA_PROPERTY,
44
57
  type: {
45
58
  ...DEFAULT_SCHEMA_PROPERTY,
46
- suffixGenerator: { type: 'function' },
59
+ suffix: { type: 'array', items: { type: 'string' } },
47
60
  },
61
+ typeProperty: DEFAULT_SCHEMA_PROPERTY,
62
+ file: DEFAULT_SCHEMA_PROPERTY,
48
63
  property: DEFAULT_SCHEMA_PROPERTY,
49
64
  function: DEFAULT_SCHEMA_PROPERTY,
65
+ functionParams: DEFAULT_SCHEMA_PROPERTY,
50
66
  variable: DEFAULT_SCHEMA_PROPERTY,
51
67
  class: DEFAULT_SCHEMA_PROPERTY,
68
+ method: DEFAULT_SCHEMA_PROPERTY,
52
69
  },
53
70
  additionalProperties: false,
54
71
  }
@@ -68,21 +85,22 @@ const generateRedundantKeywords = ({ args, key, terminalImportName }) => {
68
85
  const option = args.option[key] || {}
69
86
  const ignoreKeywords = option.ignoreKeywords || DEFAULT_CONFIG[key].IGNORE_KEYWORDS
70
87
  const terminalImportKeyword = terminalImportName ? terminalImportName.toLowerCase() : ''
71
- const filterKeywords = (keys) => keys.filter((k) => k !== terminalImportKeyword && !ignoreKeywords.includes(k))
72
88
 
73
- let redundantKeywords = filterKeywords(args.keywords)
74
- if (option.keywordGenerator) {
75
- redundantKeywords = option.keywordGenerator({
76
- ...args,
77
- redundantKeywords,
78
- })
79
- }
89
+ return args.keywords.reduce((prev, keyword) => {
90
+ if (keyword === terminalImportKeyword || ignoreKeywords.includes(keyword)) {
91
+ return prev
92
+ }
93
+
94
+ const singularized = Inflector.singularize(keyword)
80
95
 
81
- return redundantKeywords
96
+ return singularized === keyword ? [...prev, keyword] : [...prev, keyword, singularized]
97
+ }, [])
82
98
  }
83
99
  const handleReportBetterName = ({
84
100
  key,
85
101
  context,
102
+ option,
103
+ filename,
86
104
  redundantKeywords,
87
105
  defaultBetterName,
88
106
  fetchName,
@@ -99,40 +117,75 @@ const handleReportBetterName = ({
99
117
  return
100
118
  }
101
119
 
102
- let hitCount = 0
103
- let betterName = redundantKeywords.reduce((prev, keyword) => {
104
- const replaced = prev.replace(new RegExp(keyword, 'i'), '')
120
+ let candidates = []
121
+ let conciseName = redundantKeywords.reduce((prev, keyword) => {
122
+ const regex = new RegExp(`(${keyword})`, 'i')
123
+ const matcher = prev.match(regex)
124
+
125
+ if (matcher) {
126
+ candidates.push(matcher[1])
105
127
 
106
- if (prev !== replaced) {
107
- hitCount++
128
+ return prev.replace(regex, '')
108
129
  }
109
130
 
110
- return replaced
131
+ return prev
111
132
  }, name)
112
133
 
113
- if (name !== betterName) {
114
- betterName = betterName
134
+ if (name !== conciseName) {
135
+ conciseName = conciseName
115
136
  .replace(/^_+/, '')
116
137
  .replace(/_+$/, '')
117
138
  .replace(/_+/, '_')
139
+ let fullRedundant = false
118
140
 
119
- if (!betterName) {
141
+ if (!conciseName) {
142
+ fullRedundant = true
120
143
  // HINT: 1keywordで構成されている名称はそのままにする
121
- betterName = hitCount === 1 ? name : defaultBetterName
144
+ conciseName = candidates.length === 1 ? name : defaultBetterName
122
145
  }
123
146
 
124
147
  // HINT: camelCase、lower_snake_case の場合、keywordが取り除かれた結果違うケースになってしまう場合があるので対応する
125
- if (name.match(/^[a-z]/) && betterName.match(/^[A-Z]/)) {
126
- betterName = `${betterName[0].toLowerCase()}${betterName.slice(1)}`
148
+ if (name.match(/^[a-z]/) && conciseName.match(/^[A-Z]/)) {
149
+ conciseName = `${conciseName[0].toLowerCase()}${conciseName.slice(1)}`
150
+ }
151
+
152
+ if (fullRedundant) {
153
+ if (name.match(/^[A-Z]/)) {
154
+ candidates = candidates.map((k) => `${k[0].toUpperCase()}${k.slice(1)}`)
155
+ }
156
+ } else {
157
+ candidates = []
127
158
  }
159
+
160
+ candidates = uniq([conciseName, ...candidates].filter((k) => !!k))
161
+
162
+ if (option.betterNames) {
163
+ Object.entries(option.betterNames).forEach(([regex, calc]) => {
164
+ if (calc && filename.match(new RegExp(regex))) {
165
+ switch(calc.operator) {
166
+ case '=':
167
+ candidates = calc.names
168
+ break
169
+ case '-':
170
+ candidates = candidates.filter((c) => !calc.names.includes(c))
171
+ break
172
+ case '+':
173
+ candidates = uniq([...candidates, ...calc.names])
174
+ break
175
+ }
176
+ }
177
+ })
178
+ }
179
+
180
+ candidates = candidates.filter((c) => c !== name)
128
181
  }
129
182
 
130
- if (name !== betterName) {
183
+ if (candidates.length > 0) {
131
184
  context.report({
132
185
  node,
133
186
  messageId: `${key}-name`,
134
187
  data: {
135
- message: generateMessage({ name, betterName }),
188
+ message: generateMessage({ name, betterName: candidates.join(', ') }),
136
189
  },
137
190
  });
138
191
  }
@@ -145,17 +198,10 @@ const generateTypeRedundant = (args) => {
145
198
  const redundantKeywords = generateRedundantKeywords({ args, key })
146
199
  const option = args.option[key]
147
200
  const defaultConfig = DEFAULT_CONFIG[key]
148
- const actualArgs = {
149
- ...args,
150
- redundantKeywords,
151
- }
152
201
 
153
202
  return (node) => {
154
203
  const typeName = node.id.name
155
- const suffix = option.suffixGenerator ? option.suffixGenerator({
156
- ...actualArgs,
157
- node,
158
- }) : defaultConfig.SUFFIX
204
+ const suffix = option.suffix || defaultConfig.SUFFIX
159
205
 
160
206
  let SuffixedName = typeName
161
207
  let report = null
@@ -197,12 +243,41 @@ const generateTypeRedundant = (args) => {
197
243
  }
198
244
  }
199
245
 
246
+ const generateTypePropertyRedundant = (args) => {
247
+ const key = 'typeProperty'
248
+
249
+ return handleReportBetterName({
250
+ ...args,
251
+ key,
252
+ option: args.option[key],
253
+ redundantKeywords: generateRedundantKeywords({ args, key }),
254
+ defaultBetterName: '',
255
+ fetchName: (node) => node.key.name,
256
+ })
257
+ }
258
+ const generateTypePropertyFunctionParamsRedundant = (args) => {
259
+ const key = 'typeProperty'
260
+ const redundant = handleReportBetterName({
261
+ ...args,
262
+ key,
263
+ option: args.option[key],
264
+ redundantKeywords: generateRedundantKeywords({ args, key }),
265
+ defaultBetterName: '',
266
+ fetchName: (node) => node.name,
267
+ })
268
+
269
+ return (node) => {
270
+ node.params.forEach((param) => redundant(param))
271
+ }
272
+ }
273
+
200
274
  const generatePropertyRedundant = (args) => {
201
275
  const key = 'property'
202
276
 
203
277
  return handleReportBetterName({
278
+ ...args,
204
279
  key,
205
- context: args.context,
280
+ option: args.option[key],
206
281
  redundantKeywords: generateRedundantKeywords({ args, key }),
207
282
  defaultBetterName: 'item',
208
283
  fetchName: (node) => node.key.name,
@@ -214,8 +289,9 @@ const generateFileRedundant = (args) => {
214
289
  const terminalImportName = fetchTerminalImportName(args.filename)
215
290
 
216
291
  return handleReportBetterName({
292
+ ...args,
217
293
  key,
218
- context: args.context,
294
+ option: args.option[key],
219
295
  redundantKeywords: generateRedundantKeywords({ args, key, terminalImportName }),
220
296
  defaultBetterName: 'index',
221
297
  fetchName: () => terminalImportName,
@@ -227,20 +303,37 @@ const generateFunctionRedundant = (args) => {
227
303
  const key = 'function'
228
304
 
229
305
  return handleReportBetterName({
306
+ ...args,
230
307
  key,
231
- context: args.context,
308
+ option: args.option[key],
232
309
  redundantKeywords: generateRedundantKeywords({ args, key, terminalImportName: fetchTerminalImportName(args.filename) }),
233
310
  defaultBetterName: '',
234
311
  fetchName: (node) => node.id.name,
235
312
  })
236
313
  }
314
+ const generateFunctionParamsRedundant = (args) => {
315
+ const key = 'functionParams'
316
+ const redundant = handleReportBetterName({
317
+ ...args,
318
+ key,
319
+ option: args.option[key],
320
+ redundantKeywords: generateRedundantKeywords({ args, key }),
321
+ defaultBetterName: '',
322
+ fetchName: (node) => node.name,
323
+ })
324
+
325
+ return (node) => {
326
+ node.params.forEach((param) => redundant(param))
327
+ }
328
+ }
237
329
 
238
330
  const generateVariableRedundant = (args) => {
239
331
  const key = 'variable'
240
332
 
241
333
  return handleReportBetterName({
334
+ ...args,
242
335
  key,
243
- context: args.context,
336
+ option: args.option[key],
244
337
  redundantKeywords: generateRedundantKeywords({ args, key, terminalImportName: fetchTerminalImportName(args.filename) }),
245
338
  defaultBetterName: '',
246
339
  fetchName: (node) => node.id.name,
@@ -251,8 +344,9 @@ const generateClassRedundant = (args) => {
251
344
  const key = 'class'
252
345
 
253
346
  return handleReportBetterName({
347
+ ...args,
254
348
  key,
255
- context: args.context,
349
+ option: args.option[key],
256
350
  redundantKeywords: generateRedundantKeywords({ args, key, terminalImportName: fetchTerminalImportName(args.filename) }),
257
351
  defaultBetterName: '',
258
352
  fetchName: (node) => node.id.name,
@@ -263,8 +357,9 @@ const generateMethodRedundant = (args) => {
263
357
  const key = 'method'
264
358
 
265
359
  return handleReportBetterName({
360
+ ...args,
266
361
  key,
267
- context: args.context,
362
+ option: args.option[key],
268
363
  redundantKeywords: generateRedundantKeywords({ args, key }),
269
364
  defaultBetterName: 'item',
270
365
  fetchName: (node) => node.key.name,
@@ -278,8 +373,10 @@ module.exports = {
278
373
  'file-name': ' {{ message }}',
279
374
  'type-name': '{{ message }}',
280
375
  'type-name/invalid-suffix': '{{ message }}',
376
+ 'typeProperty-name': '{{ message }}',
281
377
  'property-name': ' {{ message }}',
282
378
  'function-name': ' {{ message }}',
379
+ 'functionParams-name': ' {{ message }}',
283
380
  'variable-name': ' {{ message }}',
284
381
  'class-name': ' {{ message }}',
285
382
  'method-name': ' {{ message }}',
@@ -324,50 +421,73 @@ module.exports = {
324
421
  keywords,
325
422
  }
326
423
 
424
+ const addRule = (key, redundant) => {
425
+ const addedRules = rules[key] || []
426
+
427
+ rules[key] = [...addedRules, redundant]
428
+ }
429
+
327
430
  if (option.type) {
328
- rules = {
329
- ...rules,
330
- TSTypeAliasDeclaration: generateTypeRedundant(args),
331
- }
431
+ addRule('TSTypeAliasDeclaration', generateTypeRedundant(args))
432
+ // addRule('TSInterfaceDeclaration', generateTypeRedundant(args)) // 必要になったら実装する
433
+ }
434
+ if (option.typeProperty) {
435
+ const typePropRedundant = generateTypePropertyRedundant(args)
436
+ const typeFuncParamRedundant = generateTypePropertyFunctionParamsRedundant(args)
437
+
438
+ addRule('TSPropertySignature', (node) => {
439
+ typePropRedundant(node)
440
+
441
+ if (node.typeAnnotation.typeAnnotation.type === 'TSFunctionType') {
442
+ typeFuncParamRedundant(node.typeAnnotation.typeAnnotation)
443
+ }
444
+ })
332
445
  }
333
446
  if (option.property) {
334
- propRedundant = generatePropertyRedundant(args)
447
+ const redundant = generatePropertyRedundant(args)
335
448
 
336
- rules = {
337
- ...rules,
338
- Property: propRedundant,
339
- PropertyDefinition: propRedundant,
340
- }
449
+ addRule('Property', redundant)
450
+ addRule('PropertyDefinition', redundant)
341
451
  }
342
452
  if (option.file) {
343
- rules = {
344
- ...rules,
345
- Program: generateFileRedundant(args),
346
- }
453
+ addRule('Program', generateFileRedundant(args))
347
454
  }
348
455
  if (option.function) {
349
- rules = {
350
- ...rules,
351
- FunctionDeclaration: generateFunctionRedundant(args),
352
- }
456
+ addRule('FunctionDeclaration', generateFunctionRedundant(args))
457
+ }
458
+ if (option.functionParams) {
459
+ const redundant = generateFunctionParamsRedundant(args)
460
+
461
+ addRule('FunctionDeclaration', redundant)
462
+ addRule('ArrowFunctionExpression', redundant)
463
+ addRule('MethodDefinition', (node) => {
464
+ if (node.value.type === 'FunctionExpression') {
465
+ redundant(node.value)
466
+ }
467
+ })
353
468
  }
354
469
  if (option.variable) {
355
470
  const redundant = generateVariableRedundant(args)
356
471
 
357
- rules = {
358
- ...rules,
359
- VariableDeclarator: redundant,
360
- TSEnumDeclaration: redundant,
361
- }
472
+ addRule('VariableDeclarator', redundant)
473
+ addRule('TSEnumDeclaration', redundant)
362
474
  }
363
475
  if (option.class) {
364
- rules = {
365
- ...rules,
366
- ClassDeclaration: generateClassRedundant(args),
367
- MethodDefinition: generateMethodRedundant(args) ,
368
- }
476
+ addRule('ClassDeclaration', generateClassRedundant(args))
477
+ }
478
+ if (option.method) {
479
+ addRule('MethodDefinition', generateMethodRedundant(args))
369
480
  }
370
481
 
482
+ Object.keys(rules).forEach((key) => {
483
+ const redundants = rules[key]
484
+ rules[key] = (node) => {
485
+ redundants.forEach((redundant) => {
486
+ redundant(node)
487
+ })
488
+ }
489
+ })
490
+
371
491
  return rules
372
492
  },
373
493
  }
@@ -0,0 +1,125 @@
1
+ const path = require('path')
2
+ const fs = require('fs')
3
+ const { replacePaths, rootPath } = require('../libs/common')
4
+ const calculateAbsoluteImportPath = (source) => {
5
+ if (source[0] === '/') {
6
+ return source
7
+ }
8
+
9
+ return Object.entries(replacePaths).reduce((prev, [key, values]) => {
10
+ if (source === prev) {
11
+ return values.reduce((p, v) => {
12
+ if (prev === p) {
13
+ const regexp = new RegExp(`^${key}(.+)$`)
14
+
15
+ if (prev.match(regexp)) {
16
+ return p.replace(regexp, `${path.resolve(`${process.cwd()}/${v}`)}/$1`)
17
+ }
18
+ }
19
+
20
+ return p
21
+ }, prev)
22
+ }
23
+
24
+ return prev
25
+ }, source)
26
+ }
27
+ const calculateReplacedImportPath = (source) => {
28
+ return Object.entries(replacePaths).reduce((prev, [key, values]) => {
29
+ if (source === prev) {
30
+ return values.reduce((p, v) => {
31
+ if (prev === p) {
32
+ const regexp = new RegExp(`^${path.resolve(`${process.cwd()}/${v}`)}(.+)$`)
33
+
34
+ if (prev.match(regexp)) {
35
+ return p.replace(regexp, `${key}/$1`).replace(/(\/)+/g, '/')
36
+ }
37
+ }
38
+
39
+ return p
40
+ }, prev)
41
+ }
42
+
43
+ return prev
44
+ }, source)
45
+ }
46
+
47
+ module.exports = {
48
+ meta: {
49
+ type: 'suggestion',
50
+ messages: {
51
+ 'require-barrel-import': '{{ message }}',
52
+ },
53
+ schema: [],
54
+ },
55
+ create(context) {
56
+ const filename = context.getFilename()
57
+
58
+ // HINT: indexファイルがある == barrelであるとする
59
+ if (filename.match(/\/index\.(js|ts)x?$/)) {
60
+ return {}
61
+ }
62
+
63
+ const dir = (() => {
64
+ const d = filename.split('/')
65
+ d.pop()
66
+
67
+ return d.join('/')
68
+ })()
69
+
70
+ return {
71
+ ImportDeclaration: (node) => {
72
+ let sourceValue = node.source.value
73
+
74
+ if (sourceValue[0] === '.') {
75
+ sourceValue = path.resolve(`${dir}/${sourceValue}`)
76
+ }
77
+
78
+ sourceValue = calculateAbsoluteImportPath(sourceValue)
79
+
80
+ if (sourceValue[0] !== '/') {
81
+ return
82
+ }
83
+
84
+ const sources = sourceValue.split('/')
85
+ let joinedSources = sourceValue
86
+ let ext = undefined
87
+
88
+ while (sources.length > 0) {
89
+ // HINT: 以下の場合は即終了
90
+ // - import元以下のimportだった場合
91
+ // - rootまで捜索した場合
92
+ if (dir === joinedSources || dir === rootPath) {
93
+ return
94
+ }
95
+
96
+ ext = ['ts', 'tsx', 'js', 'jsx'].find((e) => fs.existsSync(`${sources.join('/')}/index.${e}`))
97
+
98
+ if (ext) {
99
+ break
100
+ }
101
+
102
+ sources.pop()
103
+ joinedSources = sources.join('/')
104
+ }
105
+
106
+ if (
107
+ joinedSources &&
108
+ sourceValue !== joinedSources &&
109
+ !dir.match(new RegExp(`^${joinedSources}/`))
110
+ ) {
111
+ const replacedSources = calculateReplacedImportPath(joinedSources)
112
+
113
+ context.report({
114
+ node,
115
+ messageId: 'require-barrel-import',
116
+ data: {
117
+ message: `${replacedSources}からimportするか、${replacedSources}/index.${ext}を削除してください`,
118
+ },
119
+ });
120
+ }
121
+ },
122
+ }
123
+ },
124
+ }
125
+ module.exports.schema = []
@@ -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