/
no-named-as-default-member.js
102 lines (87 loc) · 3 KB
/
no-named-as-default-member.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* @fileoverview Rule to warn about potentially confused use of name exports
* @author Desmond Brand
* @copyright 2016 Desmond Brand. All rights reserved.
* See LICENSE in root directory for full license.
*/
import Exports from '../ExportMap'
import importDeclaration from '../importDeclaration'
import docsUrl from '../docsUrl'
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'suggestion',
docs: {
url: docsUrl('no-named-as-default-member'),
},
schema: [],
},
create: function(context) {
const fileImports = new Map()
const allPropertyLookups = new Map()
function handleImportDefault(node) {
const declaration = importDeclaration(context)
const exportMap = Exports.get(declaration.source.value, context)
if (exportMap == null) return
if (exportMap.errors.length) {
exportMap.reportErrors(context, declaration)
return
}
fileImports.set(node.local.name, {
exportMap,
sourcePath: declaration.source.value,
})
}
function storePropertyLookup(objectName, propName, node) {
const lookups = allPropertyLookups.get(objectName) || []
lookups.push({node, propName})
allPropertyLookups.set(objectName, lookups)
}
function handlePropLookup(node) {
const objectName = node.object.name
const propName = node.property.name
storePropertyLookup(objectName, propName, node)
}
function handleDestructuringAssignment(node) {
const isDestructure = (
node.id.type === 'ObjectPattern' &&
node.init != null &&
node.init.type === 'Identifier'
)
if (!isDestructure) return
const objectName = node.init.name
for (const { key } of node.id.properties) {
if (key == null) continue // true for rest properties
storePropertyLookup(objectName, key.name, key)
}
}
function handleProgramExit() {
allPropertyLookups.forEach((lookups, objectName) => {
const fileImport = fileImports.get(objectName)
if (fileImport == null) return
for (const {propName, node} of lookups) {
// the default import can have a "default" property
if (propName === 'default') continue
if (!fileImport.exportMap.namespace.has(propName)) continue
context.report({
node,
message: (
`Caution: \`${objectName}\` also has a named export ` +
`\`${propName}\`. Check if you meant to write ` +
`\`import {${propName}} from '${fileImport.sourcePath}'\` ` +
'instead.'
),
})
}
})
}
return {
'ImportDefaultSpecifier': handleImportDefault,
'MemberExpression': handlePropLookup,
'VariableDeclarator': handleDestructuringAssignment,
'Program:exit': handleProgramExit,
}
},
}