Browse Source

Added `mark()` method to identifiers.

* Removed Module's `mark( name )` and `markExport( name, module )`
* Added `mark()` to Modules
gh-109
Oskar Segersvärd 9 years ago
parent
commit
616a5ce306
  1. 11
      src/ExternalModule.js
  2. 70
      src/Module.js
  3. 40
      src/Statement.js

11
src/ExternalModule.js

@ -39,7 +39,10 @@ export default class ExternalModule {
originalName: name, originalName: name,
name, name,
module: this module: this,
mark: () => {
this.importedByBundle[ name ] = true;
}
}); });
} }
@ -47,5 +50,9 @@ export default class ExternalModule {
}; };
} }
markExport () {} // External modules are always marked for inclusion in the bundle.
// Marking an external module signals its use as a namespace.
mark () {
this.needsAll = true;
}
} }

70
src/Module.js

@ -144,10 +144,14 @@ export default class Module {
// Always define a new `Identifier` for the default export. // Always define a new `Identifier` for the default export.
this.exports.define( 'default', { this.exports.define( 'default', {
originalName: name, originalName: 'default',
name, name,
module: this, module: this,
mark () {
this.isUsed = true;
this.statement.mark();
},
statement, statement,
// Keep the identifier name, if one exists. // Keep the identifier name, if one exists.
@ -194,6 +198,10 @@ export default class Module {
name, name,
module: this, module: this,
mark () {
this.isUsed = true;
this.statement.mark();
},
statement, statement,
localName: name, localName: name,
expression: declaration expression: declaration
@ -259,7 +267,11 @@ export default class Module {
name, name,
statement, statement,
module: this module: this,
mark () {
this.isUsed = true;
this.statement.mark();
}
}); });
}); });
@ -296,7 +308,11 @@ export default class Module {
// For each name we depend on that isn't in scope, // For each name we depend on that isn't in scope,
// add a new global and bind the local name to it. // add a new global and bind the local name to it.
if ( !this.locals.inScope( name ) ) { if ( !this.locals.inScope( name ) ) {
this.bundle.globals.define( name ); this.bundle.globals.define( name, {
originalName: name,
name,
mark () {}
});
this.locals.bind( name, this.bundle.globals.reference( name ) ); this.locals.bind( name, this.bundle.globals.reference( name ) );
} }
}); });
@ -383,6 +399,8 @@ export default class Module {
// Enforce dynamic access of the module's properties. // Enforce dynamic access of the module's properties.
dynamicAccess () { dynamicAccess () {
if ( this.needsDynamicAccess ) return;
this.needsDynamicAccess = true; this.needsDynamicAccess = true;
this.markAllExportStatements(); this.markAllExportStatements();
@ -395,20 +413,8 @@ export default class Module {
return this.bundle.moduleById[ this.resolvedIds[ source ] ]; return this.bundle.moduleById[ this.resolvedIds[ source ] ];
} }
mark ( name ) { mark () {
const id = this.locals.lookup( name ); this.dynamicAccess();
if ( id && id.module ) {
if ( id.module.isExternal ) {
id.module.importedByBundle[ id.originalName ] = true;
}
if ( id.statement ) {
// Assert that statement is defined. It isn't for external modules.
id.isUsed = true;
id.statement.mark();
}
}
} }
markAllStatements ( isEntryModule ) { markAllStatements ( isEntryModule ) {
@ -436,7 +442,7 @@ export default class Module {
else { else {
// Be sure to mark the default export for the entry module. // Be sure to mark the default export for the entry module.
if ( isEntryModule && statement.node.type === 'ExportDefaultDeclaration' ) { if ( isEntryModule && statement.node.type === 'ExportDefaultDeclaration' ) {
this.markExport( 'default', this ); this.exports.lookup( 'default' ).mark();
} }
statement.mark(); statement.mark();
@ -450,34 +456,6 @@ export default class Module {
}); });
} }
markExport ( name, importer ) {
const id = this.exports.lookup( name );
if ( id ) {
id.isUsed = true;
// Assert that statement is defined. It isn't for external modules.
if ( id.statement ) id.statement.mark();
return;
}
for ( const module of this.exportAlls ) {
const id = module.exports.lookup( name );
if ( id ) {
id.isUsed = true;
// Assert that statement is defined. It isn't for external modules.
if ( id.statement ) id.statement.mark();
return;
}
}
throw new Error( `Module ${this.id} does not export ${name} (imported by ${importer.id})` );
}
parse ( ast ) { parse ( ast ) {
// The ast can be supplied programmatically (but usually won't be) // The ast can be supplied programmatically (but usually won't be)
if ( !ast ) { if ( !ast ) {

40
src/Statement.js

@ -151,6 +151,7 @@ export default class Statement {
if ( node._scope ) scope = scope.parent; if ( node._scope ) scope = scope.parent;
// Optimize namespace lookups, which manifests as MemberExpressions.
if ( node.type === 'MemberExpression' && ( !currentMemberExpression || node.object === currentMemberExpression ) ) { if ( node.type === 'MemberExpression' && ( !currentMemberExpression || node.object === currentMemberExpression ) ) {
currentMemberExpression = node; currentMemberExpression = node;
@ -162,9 +163,20 @@ export default class Statement {
namespace = id; namespace = id;
} }
const name = node.property.name || ( node.property.type === 'Literal' ? node.property.value : null ); // Extract the name of the accessed property, from and Identifier or Literal.
// Any eventual Literal value is converted to a string.
if ( !name ) { const name = node.property.name ||
( node.property.type === 'Literal' ? String( node.property.value ) : null );
// If we can't resolve the name being accessed,
// we require the namespace to be dynamically accessible.
//
// // resolvable
// console.log( javascript.keywords[ 6 ] )
//
// // unresolvable
// console.log( javascript.keywords[ 1 + 5 ] )
if ( name === null ) {
namespace.dynamicAccess(); namespace.dynamicAccess();
namespace = null; namespace = null;
@ -312,31 +324,21 @@ export default class Statement {
// `export { name } from './other'` is a special case // `export { name } from './other'` is a special case
if ( this.isReexportDeclaration ) { if ( this.isReexportDeclaration ) {
const otherModule = this.module.getModule( this.node.source.value ); // TODO: If we add the specifiers to `dependantIds`,
// we can remove this special case.
this.node.specifiers.forEach( specifier => { this.node.specifiers.forEach( specifier => {
otherModule.markExport( specifier.local.name, this.module ); this.module.exports.lookup( specifier.exported.name ).mark();
}); });
return; return;
} }
this.dependantIds.forEach( id => { this.dependantIds.forEach( id => id.mark() );
// FIXME: what should be done about modules?
if ( id.isModule ) {
if ( id.isExternal ) {
} else {
}
}
id.module && id.module.markExport( id.originalName, this.module );
});
// TODO: perhaps these could also be added?
keys( this.dependsOn ).forEach( name => { keys( this.dependsOn ).forEach( name => {
if ( this.defines[ name ] ) return; // TODO maybe exclude from `this.dependsOn` in the first place? if ( this.defines[ name ] ) return; // TODO maybe exclude from `this.dependsOn` in the first place?
this.module.mark( name ); this.module.locals.lookup( name ).mark();
}); });
} }

Loading…
Cancel
Save