-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathno-named-as-default-member.js
91 lines (78 loc) · 2.94 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
/**
* @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 ExportMapBuilder from '../exportMap/builder';
import importDeclaration from '../importDeclaration';
import docsUrl from '../docsUrl';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'suggestion',
docs: {
category: 'Helpful warnings',
description: 'Forbid use of exported name as property of default export.',
url: docsUrl('no-named-as-default-member'),
},
schema: [],
},
create(context) {
const fileImports = new Map();
const allPropertyLookups = new Map();
function storePropertyLookup(objectName, propName, node) {
const lookups = allPropertyLookups.get(objectName) || [];
lookups.push({ node, propName });
allPropertyLookups.set(objectName, lookups);
}
return {
ImportDefaultSpecifier(node) {
const declaration = importDeclaration(context, node);
const exportMap = ExportMapBuilder.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,
});
},
MemberExpression(node) {
const objectName = node.object.name;
const propName = node.property.name;
storePropertyLookup(objectName, propName, node);
},
VariableDeclarator(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);
}
},
'Program:exit'() {
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.`,
});
}
});
},
};
},
};