/
MemberExpression.js
96 lines (75 loc) · 2.24 KB
/
MemberExpression.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
import relativeId from '../../utils/relativeId.js';
import Node from '../Node.js';
import { UNKNOWN } from '../values.js';
const validProp = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
class Keypath {
constructor ( node ) {
this.parts = [];
while ( node.type === 'MemberExpression' ) {
const prop = node.property;
if ( node.computed ) {
if ( prop.type !== 'Literal' || typeof prop.value !== 'string' || !validProp.test( prop.value ) ) {
this.computed = true;
return;
}
}
this.parts.unshift( prop );
node = node.object;
}
this.root = node;
}
}
export default class MemberExpression extends Node {
bind ( scope ) {
// if this resolves to a namespaced declaration, prepare
// to replace it
// TODO this code is a bit inefficient
const keypath = new Keypath( this );
if ( !keypath.computed ) {
let declaration = scope.findDeclaration( keypath.root.name );
while ( declaration.isNamespace && keypath.parts.length ) {
const exporterId = declaration.module.id;
const part = keypath.parts[0];
declaration = declaration.module.traceExport( part.name || part.value );
if ( !declaration ) {
this.module.warn({
code: 'MISSING_EXPORT',
message: `'${part.name || part.value}' is not exported by '${relativeId( exporterId )}'`,
url: `https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module`
}, part.start );
this.replacement = 'undefined';
return;
}
keypath.parts.shift();
}
if ( keypath.parts.length ) {
super.bind( scope );
return; // not a namespaced declaration
}
this.declaration = declaration;
if ( declaration.isExternal ) {
declaration.module.suggestName( keypath.root.name );
}
}
else {
super.bind( scope );
}
}
gatherPossibleValues ( values ) {
values.add( UNKNOWN ); // TODO
}
render ( code, es ) {
if ( this.declaration ) {
const name = this.declaration.getName( es );
if ( name !== this.name ) code.overwrite( this.start, this.end, name, true );
}
else if ( this.replacement ) {
code.overwrite( this.start, this.end, this.replacement, true );
}
super.render( code, es );
}
run ( scope ) {
if ( this.declaration ) this.declaration.activate();
super.run( scope );
}
}