From 2821b68235ff0f5a3a76e6e39c531c80101e1eb9 Mon Sep 17 00:00:00 2001 From: Brian Donovan Date: Wed, 27 Aug 2014 11:54:42 -0700 Subject: [PATCH] Improve and fill out the inline documentation. We also just refer to the global names for objects in ast-types. --- lib/container.js | 18 +++++ lib/declaration_info.js | 10 +-- lib/exports.js | 26 +++---- lib/formatters/bundle_formatter.js | 74 +++++++++++------- lib/formatters/commonjs_formatter.js | 50 ++++++------- lib/imports.js | 31 +++++--- lib/module.js | 18 +++-- lib/module_binding_declaration.js | 6 +- lib/module_binding_list.js | 16 ++-- lib/module_binding_specifier.js | 108 +++++++++++++++++++++++++++ lib/replacement.js | 14 ++-- lib/rewriter.js | 20 ++--- lib/sorting.js | 6 +- 13 files changed, 282 insertions(+), 115 deletions(-) diff --git a/lib/container.js b/lib/container.js index d47fcf4..b5ebed3 100644 --- a/lib/container.js +++ b/lib/container.js @@ -129,12 +129,22 @@ Container.prototype.getCachedModule = function(resolvedPath) { return this.modules[resolvedPath]; }; +/** + * Writes the contents of this container to the given path. + * + * @param {string} target + */ Container.prototype.write = function(target) { var files = this.convert(); var writer = new Writer(target); writer.write(files); }; +/** + * Converts the contents of this container using the current formatter. + * + * @returns {File[]} + */ Container.prototype.convert = function() { if (this.formatter.beforeConvert) { this.formatter.beforeConvert(this); @@ -149,6 +159,9 @@ Container.prototype.convert = function() { return formatter.build(modules); }; +/** + * Follows all imports/exports looking for new modules to add to this container. + */ Container.prototype.findImportedModules = function() { var knownModules; var lastModuleCount = 0; @@ -164,6 +177,11 @@ Container.prototype.findImportedModules = function() { } }; +/** + * Gets the modules in this container in no particular order. + * + * @returns {Module[]} + */ Container.prototype.getModules = function() { var modules = this.modules; return Object.keys(modules).map(function(key) { diff --git a/lib/declaration_info.js b/lib/declaration_info.js index c0e897d..64c9d1e 100644 --- a/lib/declaration_info.js +++ b/lib/declaration_info.js @@ -20,17 +20,17 @@ var n = types.namedTypes; * Then `identifier` references the `add` node, the declaration's `id`. * * @constructor - * @param {ast-types.Node} declaration - * @param {ast-types.Identifier} identifier + * @param {Node} declaration + * @param {Identifier} identifier */ function DeclarationInfo(declaration, identifier) { /** - * @type {ast-types.Node} + * @type {Node} * @property declaration */ this.declaration = declaration; /** - * @type {ast-types.Identifier} + * @type {Identifier} * @property identifier */ this.identifier = identifier; @@ -40,7 +40,7 @@ function DeclarationInfo(declaration, identifier) { * Get the declaration info for the given identifier path, if the identifier is * actually part of a declaration. * - * @param {ast-types.NodePath} identifierPath + * @param {NodePath} identifierPath * @return {?DeclarationInfo} */ DeclarationInfo.forIdentifierPath = function(identifierPath) { diff --git a/lib/exports.js b/lib/exports.js index 91438e9..93e5640 100644 --- a/lib/exports.js +++ b/lib/exports.js @@ -29,7 +29,7 @@ extend(ExportDeclarationList, ModuleBindingList); /** * @private - * @param {ast-types.Node} node + * @param {Node} node * @return {boolean} */ ExportDeclarationList.prototype.isMatchingBinding = function(node) { @@ -40,7 +40,7 @@ ExportDeclarationList.prototype.isMatchingBinding = function(node) { * Gets an export declaration for the given `node`. * * @private - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node * @return {Import} */ ExportDeclarationList.prototype.declarationForNode = function(node) { @@ -61,7 +61,7 @@ ExportDeclarationList.prototype.declarationForNode = function(node) { }; /** - * @param {ast-types.NodePath} referencePath + * @param {NodePath} referencePath * @return {?ExportSpecifier} */ ExportDeclarationList.prototype.findSpecifierForReference = function(referencePath) { @@ -91,7 +91,7 @@ ExportDeclarationList.prototype.findSpecifierForReference = function(referencePa * @abstract * @extends ModuleBindingDeclaration * @param {Module} mod - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node */ function ExportDeclaration(mod, node) { assert.ok( @@ -125,7 +125,7 @@ ExportDeclaration.prototype.toString = ExportDeclaration.prototype.inspect; * @constructor * @extends ExportDeclaration * @param {Module} mod - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node */ function DefaultExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); @@ -135,7 +135,7 @@ extend(DefaultExportDeclaration, ExportDeclaration); /** * Contains a list of specifier name information for this export. * - * @type {Array.} + * @type {ExportSpecifier[]} * @property specifiers */ memo(DefaultExportDeclaration.prototype, 'specifiers', function() { @@ -151,7 +151,7 @@ memo(DefaultExportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ExportDeclaration * @param {Module} mod - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node */ function NamedExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); @@ -161,7 +161,7 @@ extend(NamedExportDeclaration, ExportDeclaration); /** * Contains a list of specifier name information for this export. * - * @type {Array.} + * @type {ExportSpecifier[]} * @property specifiers */ memo(NamedExportDeclaration.prototype, 'specifiers', function() { @@ -179,7 +179,7 @@ memo(NamedExportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ExportDeclaration * @param {Module} mod - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node */ function VariableExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); @@ -203,7 +203,7 @@ memo(VariableExportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ExportDeclaration * @param {Module} mod - * @param {ast-types.ExportDeclaration} node + * @param {ExportDeclaration} node */ function FunctionExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); @@ -222,7 +222,7 @@ memo(FunctionExportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ModuleBindingSpecifier * @param {ExportDeclaration} declaration - * @param {ast-types.ExportSpecifier} node + * @param {ExportSpecifier} node */ function ExportSpecifier(declaration, node) { ModuleBindingSpecifier.call(this, declaration, node); @@ -277,7 +277,7 @@ memo(ExportSpecifier.prototype, 'moduleDeclaration', function() { * @constructor * @extends ExportSpecifier * @param {ExportDeclaration} declaration - * @param {ast-types.ExportSpecifier} node + * @param {ExportSpecifier} node */ function DefaultExportSpecifier(declaration, node) { ExportSpecifier.call(this, declaration, node); @@ -295,7 +295,7 @@ DefaultExportSpecifier.prototype.name = 'default'; /** * Default export specifiers do not bind to a local identifier. * - * @type {?ast-types.Identifier} + * @type {?Identifier} * @property identifier */ DefaultExportSpecifier.prototype.identifier = null; diff --git a/lib/formatters/bundle_formatter.js b/lib/formatters/bundle_formatter.js index 1770356..d6d35e1 100644 --- a/lib/formatters/bundle_formatter.js +++ b/lib/formatters/bundle_formatter.js @@ -16,6 +16,7 @@ var sort = require('../sorting').sort; * source, especially by tools such as Google Closure Compiler or UglifyJS. * For example, given these modules: * + * ```js * // a.js * import { b } from './b'; * console.log(b); @@ -23,9 +24,11 @@ var sort = require('../sorting').sort; * // b.js * export var b = 3; * export var b2 = 6; + * ``` * * The final output will be a single file looking something like this: * + * ```js * (function() { * "use strict"; * // b.js @@ -35,6 +38,7 @@ var sort = require('../sorting').sort; * // a.js * console.log(b$$b); * }).call(this); + * ``` * * @constructor */ @@ -56,10 +60,10 @@ BundleFormatter.prototype.beforeConvert = function(container) { * `identifier` for the given module `mod`. * * @param {Module} mod - * @param {ast-types.Identifier|string} identifier - * @return {ast-types.MemberExpression} + * @param {Identifier|string} identifier + * @return {MemberExpression} */ -BundleFormatter.prototype.reference = function(/* mod, identifier */) { +BundleFormatter.prototype.reference = function(mod, identifier) { throw new Error('#reference must be implemented in subclasses'); }; @@ -68,17 +72,21 @@ BundleFormatter.prototype.reference = function(/* mod, identifier */) { * to ensure that exported variables are rewritten appropriately, so we may * need to rewrite some or all of this variable declaration. For example: * + * ```js * var a = 1, b, c = 3; * ... * export { a, b }; + * ``` * * We turn those being exported into assignments as needed, e.g. * + * ```js * var c = 3; * mod$$a = 1; + * ``` * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ BundleFormatter.prototype.processVariableDeclaration = function(mod, nodePath) { @@ -97,14 +105,18 @@ BundleFormatter.prototype.processVariableDeclaration = function(mod, nodePath) { /** * Rename the top-level function declaration to a unique name. * + * ```js * function foo() {} + * ``` * * Becomes e.g. * + * ```js * function mod$$foo() {} + * ``` * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ BundleFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) { @@ -120,7 +132,7 @@ BundleFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) { * are renamed within the module. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ BundleFormatter.prototype.processExportDeclaration = function(mod, nodePath) { @@ -150,7 +162,9 @@ BundleFormatter.prototype.processExportDeclaration = function(mod, nodePath) { /** * This node looks like this: * + * ```js * export { foo, bar }; + * ``` * * Which means that it has no value in the generated code as its only * function is to control how imports are rewritten. @@ -164,7 +178,7 @@ BundleFormatter.prototype.processExportDeclaration = function(mod, nodePath) { * remove them -- they don't turn into any actual statements. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ BundleFormatter.prototype.processImportDeclaration = function(mod, nodePath) { @@ -175,11 +189,13 @@ BundleFormatter.prototype.processImportDeclaration = function(mod, nodePath) { * Since named export reassignment is just a local variable, we can ignore it. * e.g. * - * export var foo = 1; - * foo = 2; + * ```js + * export var foo = 1; + * foo = 2; + * ``` * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ BundleFormatter.prototype.processExportReassignment = function (mod, nodePath) { @@ -192,19 +208,24 @@ BundleFormatter.prototype.processExportReassignment = function (mod, nodePath) { * export, we do not need to rewrite the reference. For example, since `value` * is not exported it does not need to be rewritten: * + * ```js * // a.js * var value = 99; * console.log(value); + * ``` * * If `value` was exported then we would need to rewrite it: * + * ```js * // a.js * export var value = 3; * console.log(value); + * ``` * * In this case we re-write both `value` references to something like * `a$$value`. The tricky part happens when we re-export an imported binding: * + * ```js * // a.js * export var value = 11; * @@ -215,6 +236,7 @@ BundleFormatter.prototype.processExportReassignment = function (mod, nodePath) { * // c.js * import { value } from './b'; * console.log(value); + * ``` * * The `value` reference in a.js will be rewritten as something like `a$$value` * as expected. The `value` reference in c.js will not be rewritten as @@ -224,8 +246,8 @@ BundleFormatter.prototype.processExportReassignment = function (mod, nodePath) { * match. * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @return {ast-types.Expression} + * @param {NodePath} referencePath + * @return {Expression} */ BundleFormatter.prototype.exportedReference = function(mod, referencePath) { var specifier = mod.exports.findSpecifierForReference(referencePath); @@ -239,13 +261,13 @@ BundleFormatter.prototype.exportedReference = function(mod, referencePath) { /** * Get a reference to the original exported value referenced in `mod` at - * `referencePath`. This is very similar to {#exportedReference} in its - * approach. + * `referencePath`. This is very similar to BundleFormatter#exportedReference + * in its approach. * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @return {ast-types.Expression} - * @see {#exportedReference} + * @param {NodePath} referencePath + * @return {Expression} + * @see BundleFormatter#exportedReference */ BundleFormatter.prototype.importedReference = function(mod, referencePath) { var specifier = mod.imports.findSpecifierForReference(referencePath); @@ -262,8 +284,8 @@ BundleFormatter.prototype.importedReference = function(mod, referencePath) { * rewrite that reference to have a module-scoped name. * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @returns {?ast-types.Node} + * @param {NodePath} referencePath + * @return {?Node} */ BundleFormatter.prototype.localReference = function(mod, referencePath) { var scope = referencePath.scope.lookup(referencePath.node.name); @@ -277,8 +299,8 @@ BundleFormatter.prototype.localReference = function(mod, referencePath) { /** * Convert a list of ordered modules into a list of files. * - * @param {Array.} modules Modules in execution order. - * @return {Array.} + * @param {NodePath} nodePath + * @return {?Node[]} */ -CommonJSFormatter.prototype.processVariableDeclaration = function(/* mod, nodePath */) { +CommonJSFormatter.prototype.processVariableDeclaration = function(mod, nodePath) { return null; }; @@ -58,8 +58,8 @@ CommonJSFormatter.prototype.processVariableDeclaration = function(/* mod, nodePa * declarations alone. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath - * @returns {Array.} + * @param {NodePath} nodePath + * @returns {Node[]} */ CommonJSFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) { return null; @@ -74,10 +74,10 @@ CommonJSFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) * export var value = 1; * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @return {ast-types.Expression} + * @param {NodePath} referencePath + * @return {Expression} */ -CommonJSFormatter.prototype.exportedReference = function(/* mod, referencePath */) { +CommonJSFormatter.prototype.exportedReference = function( mod, referencePath) { return null; }; @@ -98,8 +98,8 @@ CommonJSFormatter.prototype.exportedReference = function(/* mod, referencePath * * rewriting is required and `null` will be returned. * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @return {?ast-types.Expression} + * @param {NodePath} referencePath + * @return {?Expression} */ CommonJSFormatter.prototype.importedReference = function(mod, referencePath) { var specifier = mod.imports.findSpecifierForReference(referencePath); @@ -118,8 +118,8 @@ CommonJSFormatter.prototype.importedReference = function(mod, referencePath) { * We do not need to rewrite references to local declarations. * * @param {Module} mod - * @param {ast-types.NodePath} referencePath - * @returns {?ast-types.Node} + * @param {NodePath} referencePath + * @returns {?Node} */ CommonJSFormatter.prototype.localReference = function(mod, referencePath) { return null; @@ -127,8 +127,8 @@ CommonJSFormatter.prototype.localReference = function(mod, referencePath) { /** * @param {Module} mod - * @param {ast-types.Expression} declaration - * @return {ast-types.Statement} + * @param {Expression} declaration + * @return {Statement} */ CommonJSFormatter.prototype.defaultExport = function(mod, declaration) { return b.variableDeclaration( @@ -141,7 +141,7 @@ CommonJSFormatter.prototype.defaultExport = function(mod, declaration) { * Gets a reference to the default export of this module. * * @param {Module} mod - * @returns {ast-types.Node} + * @returns {Node} */ CommonJSFormatter.prototype.defaultExportReference = function(mod) { return b.identifier(mod.id + 'default'); @@ -157,7 +157,7 @@ CommonJSFormatter.prototype.defaultExportReference = function(mod) { * the `exports` object. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ CommonJSFormatter.prototype.processExportDeclaration = function(mod, nodePath) { @@ -181,7 +181,7 @@ CommonJSFormatter.prototype.processExportDeclaration = function(mod, nodePath) { * remove them -- they don't turn into any actual statements. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ CommonJSFormatter.prototype.processImportDeclaration = function(mod, nodePath) { @@ -196,18 +196,18 @@ CommonJSFormatter.prototype.processImportDeclaration = function(mod, nodePath) { * foo = 2; * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @return {?Replacement} */ -CommonJSFormatter.prototype.processExportReassignment = function (mod, nodePath) { +CommonJSFormatter.prototype.processExportReassignment = function(mod, nodePath) { return null; }; /** * Convert a list of ordered modules into a list of files. * - * @param {Array.} modules Modules in execution order. - * @return {Array.} + * @type {ImportSpecifier[]} * @property specifiers */ memo(DefaultImportDeclaration.prototype, 'specifiers', function() { @@ -145,7 +145,7 @@ memo(DefaultImportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ImportDeclaration * @param {Module} mod - * @param {ast-types.ImportDeclaration} node + * @param {ImportDeclaration} node */ function NamedImportDeclaration(mod, node) { assert.equal(node.kind, 'named'); @@ -156,7 +156,7 @@ extend(NamedImportDeclaration, ImportDeclaration); /** * Contains a list of specifier name information for this import. * - * @type {Array.} + * @type {ImportSpecifier[]} * @property specifiers */ memo(NamedImportDeclaration.prototype, 'specifiers', function() { @@ -174,7 +174,7 @@ memo(NamedImportDeclaration.prototype, 'specifiers', function() { * @constructor * @extends ImportDeclaration * @param {Module} mod - * @param {ast-types.ImportDeclaration} node + * @param {ImportDeclaration} node */ function BareImportDeclaration(mod, node) { assert.ok( @@ -190,7 +190,7 @@ extend(BareImportDeclaration, ImportDeclaration); /** * Returns an empty set of specifiers. * - * @type {Array.} + * @type {ImportSpecifier[]} * @property specifiers */ memo(BareImportDeclaration.prototype, 'specifiers', function() { @@ -198,6 +198,15 @@ memo(BareImportDeclaration.prototype, 'specifiers', function() { }); /** + * Represents an import specifier. The "a" and "b as c" are both import + * specifiers in the following import statement. + * + * import { a, b as c } from "a"; + * + * @constructor + * @extends ModuleBindingSpecifier + * @param {ImportDeclaration} declaration + * @param {Node} node */ function ImportSpecifier(declaration, node) { assert.ok( diff --git a/lib/module.js b/lib/module.js index f57c67c..d956857 100644 --- a/lib/module.js +++ b/lib/module.js @@ -17,6 +17,14 @@ var utils = require('./utils'); var memo = utils.memo; var endsWith = utils.endsWith; +/** + * Represents a JavaScript module at a particular location on disk. + * + * @param {string} path + * @param {string} relativePath + * @param {Container} container + * @constructor + */ function Module(path, relativePath, container) { Object.defineProperties(this, { path: { @@ -77,7 +85,7 @@ memo(Module.prototype, 'exports', function() { /** * This module's scope. * - * @type {ast-types.Scope} + * @type {Scope} * @property scope */ memo(Module.prototype, 'scope', function() { @@ -87,7 +95,7 @@ memo(Module.prototype, 'scope', function() { /** * This module's source code represented as an abstract syntax tree. * - * @type {ast-types.File} + * @type {File} * @property ast */ memo(Module.prototype, 'ast', function() { @@ -181,10 +189,10 @@ Module.prototype.getExportReference = function(identifier) { /** * Gets a reference to the original exported value corresponding to the local - * binding created by this import with the name given by `identfier`. + * binding created by this import with the name given by `identifier`. * - * @param {ast-types.NodePath} referencePath - * @return {ast-types.Expression} + * @param {NodePath} referencePath + * @return {Expression} */ Module.prototype.getBindingReference = function(referencePath) { var imp = this.imports.findImportForReference(referencePath); diff --git a/lib/module_binding_declaration.js b/lib/module_binding_declaration.js index 6be0b6a..dede950 100644 --- a/lib/module_binding_declaration.js +++ b/lib/module_binding_declaration.js @@ -17,7 +17,7 @@ var memo = utils.memo; * @constructor * @abstract * @param {Module} mod - * @param {ast-types.ImportDeclaration|ast-types.ExportDeclaration} node + * @param {ImportDeclaration|ExportDeclaration} node */ function ModuleBindingDeclaration(mod, node) { assert.ok( @@ -59,7 +59,7 @@ ModuleBindingDeclaration.prototype.findSpecifierByName = function(name) { /** * @private - * @param {ast-types.Identifier} identifier + * @param {Identifier} identifier * @return {?ModuleBindingSpecifier} */ ModuleBindingDeclaration.prototype.findSpecifierByIdentifier = function(identifier) { @@ -90,7 +90,7 @@ memo(ModuleBindingDeclaration.prototype, 'source', function() { /** * Gets the module scope. * - * @type {ast-types.Scope} + * @type {Scope} * @property scope */ memo(ModuleBindingDeclaration.prototype, 'moduleScope', function() { diff --git a/lib/module_binding_list.js b/lib/module_binding_list.js index 733cdf9..ee63101 100644 --- a/lib/module_binding_list.js +++ b/lib/module_binding_list.js @@ -30,7 +30,7 @@ function ModuleBindingList(mod) { * Add all the binding declarations from the given scope body. Generally this * should be the Program node's `body` property, an array of statements. * - * @param {ast-types.Program} program + * @param {Program} program */ ModuleBindingList.prototype.readProgram = function(program) { var body = program.body; @@ -45,7 +45,7 @@ ModuleBindingList.prototype.readProgram = function(program) { * Adds a declaration to the list. * * @private - * @param {ast-types.ImportDeclaration|ast-types.ExportDeclaration} node + * @param {ImportDeclaration|ExportDeclaration} node */ ModuleBindingList.prototype.addDeclaration = function(node) { assert.ok( @@ -64,7 +64,7 @@ ModuleBindingList.prototype.addDeclaration = function(node) { /** * Gets the module scope. * - * @type {ast-types.Scope} + * @type {Scope} * @property scope */ memo(ModuleBindingList.prototype, 'moduleScope', function() { @@ -74,7 +74,7 @@ memo(ModuleBindingList.prototype, 'moduleScope', function() { /** * Gets all the modules referenced by the declarations in this list. * - * @type {Array.} + * @type {Module[]} * @property modules */ memo(ModuleBindingList.prototype, 'modules', function() { @@ -108,7 +108,7 @@ ModuleBindingList.prototype.findSpecifierByName = function(name) { /** * @private - * @param {ast-types.Identifier} identifier + * @param {Identifier} identifier * @return {?ModuleBindingSpecifier} */ ModuleBindingList.prototype.findSpecifierByIdentifier = function(identifier) { @@ -123,7 +123,7 @@ ModuleBindingList.prototype.findSpecifierByIdentifier = function(identifier) { }; /** - * @param {ast-types.NodePath} referencePath + * @param {NodePath} referencePath * @return {?ModuleBindingSpecifier} */ ModuleBindingList.prototype.findSpecifierForReference = function(referencePath) { @@ -203,7 +203,7 @@ ModuleBindingList.prototype.toString = ModuleBindingList.prototype.inspect; /** * Contains a list of declarations. * - * @type {Array.<(Import|Export)>} + * @type {(ImportDeclaration[]|ExportDeclaration[])} * @property declarations */ memo(ModuleBindingList.prototype, 'declarations', function() { @@ -218,7 +218,7 @@ memo(ModuleBindingList.prototype, 'declarations', function() { * Contains a combined list of names for all the declarations contained in this * list. * - * @type {Array.} + * @type {string[]} * @property names */ memo(ModuleBindingList.prototype, 'names', function() { diff --git a/lib/module_binding_specifier.js b/lib/module_binding_specifier.js index 38b5684..dc62a7f 100644 --- a/lib/module_binding_specifier.js +++ b/lib/module_binding_specifier.js @@ -11,6 +11,12 @@ var memo = utils.memo; var sourcePosition = utils.sourcePosition; /** + * A module binding specifier provides the shared functionality of + * ImportSpecifiers and ExportSpecifiers in the ES6 spec. + * + * @constructor + * @param {ModuleBindingDeclaration} declaration + * @param {Node} node */ function ModuleBindingSpecifier(declaration, node) { Object.defineProperties(this, { @@ -25,36 +31,94 @@ function ModuleBindingSpecifier(declaration, node) { } /** + * Gets the module this specifier is declared in. + * + * @type Module + * @property module */ memo(ModuleBindingSpecifier.prototype, 'module', function() { return this.declaration.module; }); /** + * Gets the scope at the top level of the module. + * + * @type {Scope} + * @property moduleScope */ memo(ModuleBindingSpecifier.prototype, 'moduleScope', function() { return this.declaration.moduleScope; }); /** + * Gets the name of this specifier. For import specifiers this is the name of + * the binding this specifier will create locally, i.e. "foo" in both of these + * import statements: + * + * import { foo } from "util"; + * import { bar as foo } from "util"; + * + * In export specifiers it is the name of the exported declaration or the alias + * given to an internal name, i.e. "foo" in both of these export statements: + * + * export { bar as foo }; + * export var foo = 1; + * + * @type {string} + * @property name */ memo(ModuleBindingSpecifier.prototype, 'name', function() { return this.identifier.name; }); /** + * Gets the name of the identifier this specifier comes from as distinct from + * `name`. This value will only be set if the local name and the + * imported/exported name differ, i.e. it will be "foo" in these statements: + * + * import { foo as bar } from "util"; + * export { foo as bar }; + * + * And it will be undefined in these statements: + * + * import { foo } from "util"; + * export { foo }; + * + * @type {string} + * @property from */ memo(ModuleBindingSpecifier.prototype, 'from', function() { return this.node.id.name; }); /** + * Gets the node that gives this specifier its name as it would be imported, + * i.e. "foo" in these statements: + * + * import { foo } from "utils"; + * import { bar as foo } from "utils"; + * export { foo }; + * export { bar as foo }; + * + * @type {Identifier} + * @property identifier */ memo(ModuleBindingSpecifier.prototype, 'identifier', function() { return this.node.name || this.node.id; }); /** + * Gets the export specifier corresponding to this specifier. This can be from + * either an import or export declaration, since both can have a "from" part: + * + * import { map } from "array"; + * export { map } from "array"; + * + * In both of the above examples, the export specifier of `map` would be part + * of the export statement in the "array" module that exports it. + * + * @type {?ExportSpecifier} + * @property exportSpecifier */ memo(ModuleBindingSpecifier.prototype, 'exportSpecifier', function() { var source = this.declaration.source; @@ -66,6 +130,20 @@ memo(ModuleBindingSpecifier.prototype, 'exportSpecifier', function() { } }); +/** + * Gets the import specifier corresponding to this specifier. This should only + * happen when exporting a binding that is imported in the same module, like so: + * + * import { map } from "array"; + * export { map }; + * + * The `map` export specifier has the `map` import specifier as its + * `importSpecifier` property value. The `map` import specifier has no + * `importSpecifier` property value. + * + * @type {?ImportSpecifier} + * @property importSpecifier + */ memo(ModuleBindingSpecifier.prototype, 'importSpecifier', function() { // This may be an export from this module, so find the declaration. var localExportDeclarationInfo = this.moduleDeclaration; @@ -79,6 +157,29 @@ memo(ModuleBindingSpecifier.prototype, 'importSpecifier', function() { } }); +/** + * Gets the original export value by following chains of export/import + * statements. For example: + * + * // a.js + * export var a = 1; + * + * // b.js + * export { a } from "./a"; + * + * // c.js + * import { a } from "./b"; + * export { a }; + * + * // d.js + * import { a } from "./c"; + * + * The terminal export specifier for all of these specifiers is the export in + * a.js, since all of them can be traced back to that one. + * + * @type {ExportSpecifier} + * @property terminalExportSpecifier + */ memo(ModuleBindingSpecifier.prototype, 'terminalExportSpecifier', function() { if (this.exportSpecifier) { // This is true for both imports and exports with a source, e.g. @@ -104,6 +205,10 @@ memo(ModuleBindingSpecifier.prototype, 'terminalExportSpecifier', function() { }); /** + * Gets a string representation of this module binding specifier suitable for + * debugging. + * + * @return {string} */ ModuleBindingSpecifier.prototype.inspect = function() { return '#<' + this.constructor.name + @@ -113,6 +218,9 @@ ModuleBindingSpecifier.prototype.inspect = function() { '>'; }; +/** + * @alias inspect + */ ModuleBindingSpecifier.prototype.toString = ModuleBindingSpecifier.prototype.inspect; module.exports = ModuleBindingSpecifier; diff --git a/lib/replacement.js b/lib/replacement.js index c4dc8f5..6957c31 100644 --- a/lib/replacement.js +++ b/lib/replacement.js @@ -5,8 +5,8 @@ var recast = require('recast'); * Represents a replacement of a node path with zero or more nodes. * * @constructor - * @param {ast-types.NodePath} nodePath - * @param {Array.} nodes + * @param {NodePath} nodePath + * @param {Node[]} nodes */ function Replacement(nodePath, nodes) { this.queue = []; @@ -38,7 +38,7 @@ Replacement.prototype.and = function(anotherReplacement) { /** * Constructs a Replacement that, when run, will remove the node from the AST. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @returns {Replacement} */ Replacement.removes = function(nodePath) { @@ -49,8 +49,8 @@ Replacement.removes = function(nodePath) { * Constructs a Replacement that, when run, will insert the given nodes after * the one in nodePath. * - * @param {ast-types.NodePath} nodePath - * @param {Array.} nodes + * @param {NodePath} nodePath + * @param {Node[]} nodes * @returns {Replacement} */ Replacement.adds = function(nodePath, nodes) { @@ -61,8 +61,8 @@ Replacement.adds = function(nodePath, nodes) { * Constructs a Replacement that, when run, swaps the node in nodePath with the * given node or nodes. * - * @param {ast-types.NodePath} nodePath - * @param {ast-types.Node|Array.} nodes + * @param {NodePath} nodePath + * @param {Node|Node[]} nodes */ Replacement.swaps = function(nodePath, nodes) { if ({}.toString.call(nodes) !== '[object Array]') { diff --git a/lib/rewriter.js b/lib/rewriter.js index f9eb662..a2c200a 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -47,7 +47,7 @@ utils.extend(Rewriter, types.PathVisitor); * assert.equal(math$$.cos(0), 1); * assert.equal(math$fib$$.fib(1), 1); * - * @param {Array.} modules + * @param {Module[]} modules */ Rewriter.prototype.rewrite = function(modules) { var replacements = []; @@ -87,7 +87,7 @@ Rewriter.prototype.rewrite = function(modules) { /** * Process all identifiers looking for references to variables in scope. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @returns {boolean} * @private */ @@ -105,7 +105,7 @@ Rewriter.prototype.visitIdentifier = function(nodePath) { /** * Process all variable declarations looking for top-level exported variables. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitVariableDeclaration = function(nodePath) { @@ -125,7 +125,7 @@ Rewriter.prototype.visitVariableDeclaration = function(nodePath) { * spec (see section 12.14.1, Assignment Operators / Static Semantics: Early * Errors). * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitAssignmentExpression = function(nodePath) { @@ -143,7 +143,7 @@ Rewriter.prototype.visitAssignmentExpression = function(nodePath) { /** * Process all top-level function declarations in case they need to be processed. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitFunctionDeclaration = function(nodePath) { @@ -160,7 +160,7 @@ Rewriter.prototype.visitFunctionDeclaration = function(nodePath) { /** * Look for all export declarations so we can rewrite them. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitExportDeclaration = function(nodePath) { @@ -205,7 +205,7 @@ Rewriter.prototype.visitExportDeclaration = function(nodePath) { /** * Process import declarations so they can be rewritten. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitImportDeclaration = function(nodePath) { @@ -222,7 +222,7 @@ Rewriter.prototype.visitImportDeclaration = function(nodePath) { * Process update expressions (e.g. `a++`) so we can re-write modifications to * exported variables. * - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitUpdateExpression = function(nodePath) { @@ -245,7 +245,7 @@ Rewriter.prototype.visitUpdateExpression = function(nodePath) { * * @private * @param {Module} mod - * @param {ast-types.Identifier} identifierPath + * @param {Identifier} identifierPath */ Rewriter.prototype.assertImportIsNotReassigned = function(mod, identifierPath) { if (!n.Identifier.check(identifierPath.node) || !mod.imports.findDeclarationForReference(identifierPath)) { @@ -277,7 +277,7 @@ Rewriter.prototype.assertImportIsNotReassigned = function(mod, identifierPath) { * should perhaps take care of this for us, but it does not. * * @param {Module} mod - * @param {ast-types.NodePath} nodePath + * @param {NodePath} nodePath * @private */ Rewriter.prototype.assertStatementIsTopLevel = function(mod, nodePath) { diff --git a/lib/sorting.js b/lib/sorting.js index 2a5d162..372e50d 100644 --- a/lib/sorting.js +++ b/lib/sorting.js @@ -2,8 +2,8 @@ * Determines the execution order of the given modules. This function resolves * cycles by preserving the order in which the modules are visited. * - * @param {Array.} modules - * @return {Array.} + * @param {Module[]} modules + * @return {Module[]} */ function sort(modules) { var result = []; @@ -24,7 +24,7 @@ exports.sort = sort; * * @private * @param {Module} mod - * @param {Array.} result + * @param {Module[]} result * @param {Object.} state */ function visit(mod, result, state) {