-
Notifications
You must be signed in to change notification settings - Fork 13
/
index.js
111 lines (89 loc) · 2.99 KB
/
index.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
103
104
105
106
107
108
109
110
111
// @flow
'use strict';
const unsafeRequire = require;
/*::
type Types = {
valueToNode(mixed): Node,
};
type Node = {
type: string,
[key: string]: any,
};
type Path = {
type: string,
node: Node,
[key: string]: any,
};
*/
module.exports = ({ types: t } /*: { types: Types } */) => {
return {
name: 'polished',
visitor: {
ImportDeclaration(path /*: Path */) {
let source = path.get('source');
let sourceValue = source.node.value;
let specifiers = path.get('specifiers');
if (sourceValue.indexOf('polished') !== 0) return;
let safeSourceValue = sourceValue.replace(/^polished\/src/, 'polished/lib')
let importedModule = unsafeRequire(safeSourceValue);
let invalidatedSpecifiers = specifiers.filter(specifier => {
let importedValue = importedModule;
if (specifier.node.imported) {
let imported = specifier.get('imported');
let importedName = imported.node.name;
let value = importedValue[importedName];
if (!value) {
throw imported.buildCodeFrameError('Method does not exist: ' + importedName);
}
importedValue = value;
}
let local = specifier.get('local');
let binding = local.scope.getBinding(local.node.name);
let refs = binding.referencePaths;
let invalidatedRefs = refs.filter(ref => {
let matchedMethod = importedValue;
let callExpression = ref.findParent(parent => {
if (parent.isCallExpression()) {
return true;
} else if (parent.isMemberExpression()) {
let property = parent.get('property');
let methodName = property.node.name;
let method = matchedMethod[methodName];
if (!method) {
throw property.buildCodeFrameError('Method does not exist: ' + methodName);
}
matchedMethod = method;
return false;
} else {
throw parent.buildCodeFrameError("Unexpected node type: " + parent.type);
}
});
let args = callExpression.get('arguments');
let foundNonLiteral = args.find(arg => !arg.isLiteral());
if (foundNonLiteral) return true;
let serializedArgs = args.map(arg => {
if (arg.isNullLiteral()) {
return null;
} else {
return arg.node.value
}
});
let result = matchedMethod(...serializedArgs);
let resultAst = t.valueToNode(result);
callExpression.replaceWith(resultAst);
return false;
});
if (!invalidatedRefs.length) {
specifier.remove();
return false;
} else {
return true;
}
});
if (!invalidatedSpecifiers.length) {
path.remove();
}
}
}
};
}