|
@ -28,7 +28,6 @@ export default class Module { |
|
|
|
|
|
|
|
|
this.definedNames = this.ast._scope.names.slice(); |
|
|
this.definedNames = this.ast._scope.names.slice(); |
|
|
|
|
|
|
|
|
this.nameReplacements = {}; |
|
|
|
|
|
this.canonicalNames = {}; |
|
|
this.canonicalNames = {}; |
|
|
|
|
|
|
|
|
this.definitions = {}; |
|
|
this.definitions = {}; |
|
@ -49,9 +48,13 @@ export default class Module { |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// imports and exports, indexed by ID
|
|
|
this.imports = {}; |
|
|
this.imports = {}; |
|
|
this.exports = {}; |
|
|
this.exports = {}; |
|
|
|
|
|
|
|
|
|
|
|
// an array of export statements, used for the entry module
|
|
|
|
|
|
this.exportStatements = []; |
|
|
|
|
|
|
|
|
this.ast.body.forEach( node => { |
|
|
this.ast.body.forEach( node => { |
|
|
// import foo from './foo';
|
|
|
// import foo from './foo';
|
|
|
// import { bar } from './bar';
|
|
|
// import { bar } from './bar';
|
|
@ -59,65 +62,73 @@ export default class Module { |
|
|
const source = node.source.value; |
|
|
const source = node.source.value; |
|
|
|
|
|
|
|
|
node.specifiers.forEach( specifier => { |
|
|
node.specifiers.forEach( specifier => { |
|
|
const name = specifier.local.name; |
|
|
|
|
|
const isDefault = specifier.type === 'ImportDefaultSpecifier'; |
|
|
const isDefault = specifier.type === 'ImportDefaultSpecifier'; |
|
|
|
|
|
const isNamespace = specifier.type === 'ImportNamespaceSpecifier'; |
|
|
|
|
|
|
|
|
|
|
|
const localName = specifier.local.name; |
|
|
|
|
|
const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name; |
|
|
|
|
|
|
|
|
this.imports[ name ] = { |
|
|
this.imports[ localName ] = { |
|
|
source, |
|
|
source, |
|
|
name: isDefault ? 'default' : specifier.imported.name, |
|
|
name, |
|
|
localName: name |
|
|
localName |
|
|
}; |
|
|
}; |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// export default function foo () {}
|
|
|
else if ( /^Export/.test( node.type ) ) { |
|
|
// export default foo;
|
|
|
this.exportStatements.push( node ); |
|
|
// export default 42;
|
|
|
|
|
|
else if ( node.type === 'ExportDefaultDeclaration' ) { |
|
|
|
|
|
const isDeclaration = /Declaration$/.test( node.declaration.type ); |
|
|
|
|
|
|
|
|
|
|
|
this.exports.default = { |
|
|
|
|
|
node, |
|
|
|
|
|
name: 'default', |
|
|
|
|
|
localName: isDeclaration ? node.declaration.id.name : 'default', |
|
|
|
|
|
isDeclaration, |
|
|
|
|
|
module: null // filled in later
|
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// export { foo, bar, baz }
|
|
|
// export default function foo () {}
|
|
|
// export var foo = 42;
|
|
|
// export default foo;
|
|
|
// export function foo () {}
|
|
|
// export default 42;
|
|
|
else if ( node.type === 'ExportNamedDeclaration' ) { |
|
|
if ( node.type === 'ExportDefaultDeclaration' ) { |
|
|
if ( node.specifiers.length ) { |
|
|
const isDeclaration = /Declaration$/.test( node.declaration.type ); |
|
|
// export { foo, bar, baz }
|
|
|
|
|
|
node.specifiers.forEach( specifier => { |
|
|
this.exports.default = { |
|
|
const localName = specifier.local.name; |
|
|
node, |
|
|
const exportedName = specifier.exported.name; |
|
|
name: 'default', |
|
|
|
|
|
localName: isDeclaration ? node.declaration.id.name : 'default', |
|
|
this.exports[ exportedName ] = { |
|
|
isDeclaration |
|
|
localName |
|
|
}; |
|
|
}; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
else { |
|
|
// export { foo, bar, baz }
|
|
|
let declaration = node.declaration; |
|
|
// export var foo = 42;
|
|
|
|
|
|
// export function foo () {}
|
|
|
|
|
|
else if ( node.type === 'ExportNamedDeclaration' ) { |
|
|
|
|
|
if ( node.specifiers.length ) { |
|
|
|
|
|
// export { foo, bar, baz }
|
|
|
|
|
|
node.specifiers.forEach( specifier => { |
|
|
|
|
|
const localName = specifier.local.name; |
|
|
|
|
|
const exportedName = specifier.exported.name; |
|
|
|
|
|
|
|
|
|
|
|
this.exports[ exportedName ] = { |
|
|
|
|
|
localName, |
|
|
|
|
|
exportedName |
|
|
|
|
|
}; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
let name; |
|
|
else { |
|
|
|
|
|
let declaration = node.declaration; |
|
|
|
|
|
|
|
|
if ( declaration.type === 'VariableDeclaration' ) { |
|
|
let name; |
|
|
// export var foo = 42
|
|
|
|
|
|
name = declaration.declarations[0].id.name; |
|
|
|
|
|
} else { |
|
|
|
|
|
// export function foo () {}
|
|
|
|
|
|
name = declaration.id.name; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.exports[ name ] = { |
|
|
if ( declaration.type === 'VariableDeclaration' ) { |
|
|
localName: name, |
|
|
// export var foo = 42
|
|
|
expression: declaration |
|
|
name = declaration.declarations[0].id.name; |
|
|
}; |
|
|
} else { |
|
|
|
|
|
// export function foo () {}
|
|
|
|
|
|
name = declaration.id.name; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.exports[ name ] = { |
|
|
|
|
|
node, |
|
|
|
|
|
localName: name, |
|
|
|
|
|
expression: declaration |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
@ -128,10 +139,16 @@ export default class Module { |
|
|
const importDeclaration = this.imports[ name ]; |
|
|
const importDeclaration = this.imports[ name ]; |
|
|
const module = importDeclaration.module; |
|
|
const module = importDeclaration.module; |
|
|
|
|
|
|
|
|
// TODO handle external modules
|
|
|
let exporterLocalName; |
|
|
const exportDeclaration = module.exports[ importDeclaration.name ]; |
|
|
|
|
|
|
|
|
|
|
|
return module.getCanonicalName( exportDeclaration.localName ); |
|
|
if ( module.isExternal ) { |
|
|
|
|
|
exporterLocalName = name; |
|
|
|
|
|
} else { |
|
|
|
|
|
const exportDeclaration = module.exports[ importDeclaration.name ]; |
|
|
|
|
|
exporterLocalName = exportDeclaration.localName; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return module.getCanonicalName( exporterLocalName ); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ( name === 'default' ) { |
|
|
if ( name === 'default' ) { |
|
@ -156,23 +173,23 @@ export default class Module { |
|
|
|
|
|
|
|
|
promise = this.bundle.fetchModule( path, importDeclaration.source ) |
|
|
promise = this.bundle.fetchModule( path, importDeclaration.source ) |
|
|
.then( module => { |
|
|
.then( module => { |
|
|
|
|
|
importDeclaration.module = module; |
|
|
|
|
|
|
|
|
|
|
|
if ( importDeclaration.name === 'default' ) { |
|
|
|
|
|
module.suggestDefaultName( importDeclaration.localName ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if ( module.isExternal ) { |
|
|
if ( module.isExternal ) { |
|
|
module.specifiers.push( importDeclaration ); |
|
|
module.importedByBundle.push( importDeclaration ); |
|
|
return emptyArrayPromise; |
|
|
return emptyArrayPromise; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
importDeclaration.module = module; |
|
|
|
|
|
|
|
|
|
|
|
const exportDeclaration = module.exports[ importDeclaration.name ]; |
|
|
const exportDeclaration = module.exports[ importDeclaration.name ]; |
|
|
|
|
|
|
|
|
if ( !exportDeclaration ) { |
|
|
if ( !exportDeclaration ) { |
|
|
throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` ); |
|
|
throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` ); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ( importDeclaration.name === 'default' ) { |
|
|
|
|
|
module.suggestDefaultName( importDeclaration.localName ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return module.define( exportDeclaration.localName ); |
|
|
return module.define( exportDeclaration.localName ); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|