es6-module-transpiler
Advanced tools
Comparing version 0.8.3 to 0.9.0
@@ -61,2 +61,13 @@ /* jshint node:true, undef:true, unused:true */ | ||
container.findImportedModules(); | ||
// Cache all the import and export specifier names. | ||
container.getModules().forEach(function(mod) { | ||
[mod.imports, mod.exports].forEach(function(bindingList) { | ||
bindingList.declarations.forEach(function (declaration) { | ||
declaration.specifiers.forEach(function (specifier) { | ||
specifier.name; | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
@@ -71,2 +82,3 @@ | ||
b.expressionStatement(b.literal('use strict')), | ||
this.buildNamespaceImportObjects(modules), | ||
modules.length === 1 ? | ||
@@ -81,2 +93,95 @@ modules[0].ast.program.body : | ||
/** | ||
* Builds a variable declaration that contains declarations of all the namespace | ||
* objects required by `import * as foo from 'foo'` statements. | ||
* | ||
* @private | ||
* @param {Module[]} modules | ||
* @return {?AST.VariableDeclaration} | ||
*/ | ||
BundleFormatter.prototype.buildNamespaceImportObjects = function(modules) { | ||
var self = this; | ||
var namespaceImportedModules = []; | ||
// Collect all the modules imported using a namespace import declaration. | ||
modules.forEach(function(mod) { | ||
mod.imports.namespaceImports.forEach(function(namespaceImportDeclaration) { | ||
var namespaceImportedModule = namespaceImportDeclaration.source; | ||
if (namespaceImportedModules.indexOf(namespaceImportedModule) < 0) { | ||
namespaceImportedModules.push(namespaceImportedModule); | ||
} | ||
}); | ||
}); | ||
if (namespaceImportedModules.length === 0) { | ||
return null; | ||
} | ||
/** | ||
* Builds a variable declarator for the given module whose initial value is an | ||
* object with properties for each export from the module being imported. For | ||
* example, given a module "foo" with exports "a" and "b" this object will be | ||
* created: | ||
* | ||
* foo$$ = { | ||
* get a() { | ||
* return foo$$a; | ||
* }, | ||
* | ||
* get b() { | ||
* return foo$$b; | ||
* } | ||
* } | ||
* | ||
* @param {Module} mod | ||
* @returns {AST.VariableDeclarator} | ||
*/ | ||
function createDeclaratorForModule(mod) { | ||
return b.variableDeclarator( | ||
b.identifier(mod.id), | ||
b.objectExpression( | ||
mod.exports.declarations.reduce(function(props, exportDeclaration) { | ||
exportDeclaration.specifiers.forEach(function(specifier) { | ||
props.push(createGetterForSpecifier(mod, specifier)); | ||
}); | ||
return props; | ||
}, []) | ||
) | ||
); | ||
} | ||
/** | ||
* Builds a getter property for retrieving the value of the given export | ||
* specifier at the time it is accessed. For example, given a module "foo" | ||
* with export specifier "a" this property will be created: | ||
* | ||
* get a() { | ||
* return foo$$a; | ||
* } | ||
* | ||
* @param {Module} mod | ||
* @param {ExportSpecifier} specifier | ||
* @returns {AST.Property} | ||
*/ | ||
function createGetterForSpecifier(mod, specifier) { | ||
return b.property( | ||
'get', | ||
b.identifier(specifier.name), | ||
b.functionExpression( | ||
null, | ||
[], | ||
b.blockStatement([ | ||
b.returnStatement(self.reference(mod, specifier.name)) | ||
]) | ||
) | ||
); | ||
} | ||
return b.variableDeclaration( | ||
'var', | ||
namespaceImportedModules.map(createDeclaratorForModule) | ||
); | ||
}; | ||
/** | ||
* @override | ||
@@ -183,7 +288,12 @@ * | ||
var specifier = mod.imports.findSpecifierForReference(referencePath); | ||
if (specifier) { | ||
if (!specifier) { | ||
return null; | ||
} | ||
if (specifier.from) { | ||
specifier = specifier.terminalExportSpecifier; | ||
return this.reference(specifier.module, specifier.name); | ||
} else { | ||
return null; | ||
return b.identifier(specifier.declaration.source.id); | ||
} | ||
@@ -190,0 +300,0 @@ }; |
@@ -13,3 +13,2 @@ /* jshint node:true, undef:true, unused:true */ | ||
var Formatter = require('./formatter'); | ||
var sourcePosition = require('../utils').sourcePosition; | ||
@@ -37,10 +36,21 @@ /** | ||
var body = mod.ast.program.body; | ||
body.unshift( | ||
b.expressionStatement(b.literal('use strict')), | ||
self.buildEarlyExports(mod), | ||
self.buildRequires(mod) | ||
); | ||
body.push( | ||
self.buildLateExports(mod) | ||
); | ||
var requiresDeclaration = self.buildRequires(mod); | ||
var earlyExportsStatement = self.buildEarlyExports(mod); | ||
var lateExports = self.buildLateExports(mod); | ||
if (requiresDeclaration) { | ||
body.unshift(requiresDeclaration); | ||
} | ||
if (earlyExportsStatement) { | ||
body.unshift(earlyExportsStatement); | ||
} | ||
body.unshift(b.expressionStatement(b.literal('use strict'))); | ||
if (lateExports) { | ||
body.push(lateExports); | ||
} | ||
mod.ast.filename = mod.relativePath; | ||
@@ -56,7 +66,6 @@ return mod.ast; | ||
* @param {Module} mod | ||
* @returns {AST.Statement} | ||
* @returns {?AST.Statement} | ||
* @private | ||
*/ | ||
CommonJSFormatter.prototype.buildEarlyExports = function(mod) { | ||
var self = this; | ||
var assignments = []; | ||
@@ -82,5 +91,9 @@ var exportObject = b.identifier('exports'); | ||
return b.expressionStatement( | ||
b.sequenceExpression(assignments) | ||
); | ||
if (assignments.length > 0) { | ||
return b.expressionStatement( | ||
b.sequenceExpression(assignments) | ||
); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
@@ -93,3 +106,3 @@ | ||
* @param {Module} mod | ||
* @returns {AST.Statement} | ||
* @returns {?AST.Statement} | ||
* @private | ||
@@ -132,5 +145,9 @@ */ | ||
return b.expressionStatement( | ||
b.sequenceExpression(assignments) | ||
); | ||
if (assignments.length > 0) { | ||
return b.expressionStatement( | ||
b.sequenceExpression(assignments) | ||
); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
@@ -170,3 +187,3 @@ | ||
* @param {Module} mod | ||
* @return {AST.VariableDeclaration|AST.EmptyStatement} | ||
* @return {?AST.VariableDeclaration} | ||
*/ | ||
@@ -211,3 +228,3 @@ CommonJSFormatter.prototype.buildRequires = function(mod) { | ||
} else { | ||
return b.emptyStatement(); | ||
return null; | ||
} | ||
@@ -302,3 +319,9 @@ }; | ||
if (specifier) { | ||
if (!specifier) { | ||
return null; | ||
} | ||
if (specifier.from) { | ||
// import { value } from './a'; | ||
// import a from './a'; | ||
return this.reference( | ||
@@ -309,3 +332,4 @@ specifier.declaration.source, | ||
} else { | ||
return null; | ||
// import * as a from './a' | ||
return b.identifier(specifier.declaration.source.id); | ||
} | ||
@@ -312,0 +336,0 @@ }; |
@@ -50,2 +50,15 @@ /* jshint node:true, undef:true, unused:true */ | ||
/** | ||
* Gets the namespace imports from the list of imports. | ||
* | ||
* @private | ||
* @type {ImportDeclaration[]} | ||
* @name ImportDeclaration#namespaceImports | ||
*/ | ||
memo(ImportDeclarationList.prototype, 'namespaceImports', /** @this ImportDeclarationList */function() { | ||
return this.declarations.filter(function(declaration) { | ||
return declaration.hasNamespaceImport; | ||
}); | ||
}); | ||
/** | ||
* Contains information about an import declaration. | ||
@@ -85,13 +98,9 @@ * | ||
var self = this; | ||
return this.node.specifiers.map(function(s) { | ||
var specifier = new ImportSpecifier(self, s); | ||
if (n.ImportDefaultSpecifier.check(s)) { | ||
specifier.from = 'default'; | ||
} else if (n.ImportNamespaceSpecifier.check(s)) { | ||
// TODO: implement import * as ... | ||
specifier.from = '*'; | ||
} else { | ||
specifier = new ImportSpecifier(self, s); | ||
return this.node.specifiers.map(function(specifier) { | ||
if (n.ImportDefaultSpecifier.check(specifier)) { | ||
return new ImportDefaultSpecifier(self, specifier); | ||
} else if (n.ImportNamespaceSpecifier.check(specifier)) { | ||
return new ImportNamespaceSpecifier(self, specifier); | ||
} | ||
return specifier; | ||
return new ImportNamedSpecifier(self, specifier); | ||
}); | ||
@@ -101,2 +110,12 @@ }); | ||
/** | ||
* @type {boolean} | ||
* @name ImportDeclaration#hasNamespaceImport | ||
*/ | ||
memo(ImportDeclaration.prototype, 'hasNamespaceImport', /** @this ImportDeclaration */function() { | ||
return this.specifiers.some(function(specifier) { | ||
return specifier instanceof ImportNamespaceSpecifier; | ||
}); | ||
}); | ||
/** | ||
* Represents an import specifier. The "a" and "b as c" are both import | ||
@@ -110,5 +129,5 @@ * specifiers in the following import statement. | ||
* @param {ImportDeclaration} declaration | ||
* @param {AST.ImportSpecifier} node | ||
* @param {AST.ImportNamedSpecifier} node | ||
*/ | ||
function ImportSpecifier(declaration, node) { | ||
function ImportNamedSpecifier(declaration, node) { | ||
assert.ok( | ||
@@ -120,3 +139,3 @@ declaration instanceof ImportDeclaration, | ||
} | ||
extend(ImportSpecifier, ModuleBindingSpecifier); | ||
extend(ImportNamedSpecifier, ModuleBindingSpecifier); | ||
@@ -127,3 +146,3 @@ /** | ||
*/ | ||
memo(ImportSpecifier.prototype, 'exportSpecifier', /** @this ImportSpecifier */function() { | ||
memo(ImportNamedSpecifier.prototype, 'exportSpecifier', /** @this ImportSpecifier */function() { | ||
var source = this.declaration.source; | ||
@@ -141,2 +160,69 @@ assert.ok(source, 'import specifiers must have a valid source'); | ||
/** | ||
* Represents a default import specifier. The "a" in the following import statement. | ||
* | ||
* import a from "a"; | ||
* | ||
* @constructor | ||
* @extends ModuleBindingSpecifier | ||
* @param {ImportDeclaration} declaration | ||
* @param {AST.ImportDefaultSpecifier} node | ||
*/ | ||
function ImportDefaultSpecifier(declaration, node) { | ||
assert.ok( | ||
declaration instanceof ImportDeclaration, | ||
'expected an instance of ImportDeclaration' | ||
); | ||
ModuleBindingSpecifier.call(this, declaration, node); | ||
} | ||
extend(ImportDefaultSpecifier, ModuleBindingSpecifier); | ||
memo(ImportDefaultSpecifier.prototype, 'exportSpecifier', /** @this ImportSpecifier */function() { | ||
var source = this.declaration.source; | ||
assert.ok(source, 'import specifiers must have a valid source'); | ||
var exportSpecifier = source.exports.findSpecifierByName(this.from); | ||
assert.ok( | ||
exportSpecifier, | ||
'import `default` at ' + | ||
sourcePosition(this.module, this.node) + | ||
' has no matching export in ' + source.relativePath | ||
); | ||
return exportSpecifier; | ||
}); | ||
memo(ImportDefaultSpecifier.prototype, 'from', function() { | ||
return 'default'; | ||
}); | ||
/** | ||
* Represents a namespace import specifier. The "a" in the following import | ||
* statement. | ||
* | ||
* import * as a from "a"; | ||
* | ||
* @constructor | ||
* @extends ModuleBindingSpecifier | ||
* @param {ImportDeclaration} declaration | ||
* @param {AST.ImportNamespaceSpecifier} node | ||
*/ | ||
function ImportNamespaceSpecifier(declaration, node) { | ||
assert.ok( | ||
declaration instanceof ImportDeclaration, | ||
'expected an instance of ImportDeclaration' | ||
); | ||
ModuleBindingSpecifier.call(this, declaration, node); | ||
} | ||
extend(ImportNamespaceSpecifier, ModuleBindingSpecifier); | ||
memo(ImportNamespaceSpecifier.prototype, 'exportSpecifier', /** @this ImportSpecifier */function() { | ||
var source = this.declaration.source; | ||
assert.ok(source, 'import specifiers must have a valid source'); | ||
return null; | ||
}); | ||
memo(ImportNamespaceSpecifier.prototype, 'from', function() { | ||
return null; | ||
}); | ||
module.exports = ImportDeclarationList; |
@@ -258,29 +258,61 @@ /* jshint node:true, undef:true, unused:true */ | ||
* @param {Module} mod | ||
* @param {Identifier} identifierPath | ||
* @param {Identifier} nodePath | ||
*/ | ||
Rewriter.prototype.assertImportIsNotReassigned = function(mod, identifierPath) { | ||
if (!n.Identifier.check(identifierPath.node) || !mod.imports.findDeclarationForReference(identifierPath)) { | ||
Rewriter.prototype.assertImportIsNotReassigned = function(mod, nodePath) { | ||
var declarationPath; | ||
var identifierPath; | ||
var bindingDescription; | ||
if (n.Identifier.check(nodePath.node)) { | ||
// Do we have a named import… | ||
// | ||
// import { foo } from 'foo'; | ||
// | ||
// …that we then try to assign or update? | ||
// | ||
// foo++; | ||
// foo = 1; | ||
// | ||
declarationPath = mod.imports.findDeclarationForReference(nodePath); | ||
if (!declarationPath || !n.ImportSpecifier.check(declarationPath.parent.node)) { | ||
return; | ||
} | ||
bindingDescription = '`' + declarationPath.node.name + '`'; | ||
} else if (n.MemberExpression.check(nodePath.node)) { | ||
// Do we have a namespace import… | ||
// | ||
// import * as foo from 'foo'; | ||
// | ||
// …with a property that we then try to assign or update? | ||
// | ||
// foo.a++; | ||
// foo.a = 1; | ||
// foo['a'] = 1; | ||
// | ||
var objectPath = nodePath.get('object'); | ||
if (!n.Identifier.check(objectPath.node)) { | ||
return; | ||
} | ||
declarationPath = mod.imports.findDeclarationForReference(objectPath); | ||
if (!declarationPath || !n.ImportNamespaceSpecifier.check(declarationPath.parent.node)) { | ||
return; | ||
} | ||
var propertyPath = nodePath.get('property'); | ||
if (n.Identifier.check(propertyPath.node)) { | ||
bindingDescription = '`' + propertyPath.node.name + '`'; | ||
} else { | ||
bindingDescription = 'of namespace `' + objectPath.node.name + '`'; | ||
} | ||
} else { | ||
return; | ||
} | ||
var identifier = identifierPath.node; | ||
var name = identifier.name; | ||
var declarationScope = identifierPath.scope.lookup(name); | ||
if (declarationScope && declarationScope.isGlobal) { | ||
var declarationPaths = declarationScope.getBindings()[name]; | ||
assert.ok( | ||
declarationPaths.length === 1, | ||
'expected exactly one declaration for `' + name + | ||
'`, found ' + declarationPaths.length | ||
); | ||
var declarationPath = declarationPaths[0]; | ||
if (n.ImportSpecifier.check(declarationPath.parent.node) || | ||
n.ImportDefaultSpecifier.check(declarationPath.parent.node) || | ||
n.ImportNamespaceSpecifier.check(declarationPath.parent.node)) { | ||
throw new SyntaxError( | ||
'Cannot reassign imported binding `' + name + | ||
'` at ' + sourcePosition(mod, identifier) | ||
); | ||
} | ||
} | ||
throw new SyntaxError( | ||
'Cannot reassign imported binding ' + bindingDescription + | ||
' at ' + sourcePosition(mod, nodePath.node) | ||
); | ||
}; | ||
@@ -287,0 +319,0 @@ |
{ | ||
"name": "es6-module-transpiler", | ||
"version": "0.8.3", | ||
"version": "0.9.0", | ||
"description": "es6-module-transpiler is an experimental compiler that allows you to write your JavaScript using a subset of the current ES6 module syntax, and compile it into various formats.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://esnext.github.io/es6-module-transpiler", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
114270
3506