Browse Source

refactoring

contingency-plan
Rich Harris 10 years ago
parent
commit
415cb548c2
  1. 49
      src/Bundle.js
  2. 111
      src/Module.js
  3. 4
      test/samples/bindings/main.js

49
src/Bundle.js

@ -65,53 +65,10 @@ export default class Bundle {
return this.fetchModule( this.entryPath, null )
.then( entryModule => {
this.entryModule = entryModule;
const importedNames = keys( entryModule.imports );
// pull in imports
return sequence( importedNames, name => {
return entryModule.define( name )
.then( nodes => {
this.statements.push.apply( this.statements, nodes );
});
})
.then( () => {
entryModule.ast.body.forEach( node => {
// Exclude imports
if ( /^Import/.test( node.type ) ) return;
// Exclude default exports that proxy a name
// e.g. `export default foo`
if ( node.type === 'ExportDefaultDeclaration' && /Declaration$/.test( node.declaration.type ) ) return;
// Exclude specifier exports
// e.g. `export { foo }`
if ( node.type === 'ExportNamedDeclaration' && node.specifiers.length ) return;
// Include everything else...
if ( node.type === 'ExportDefaultDeclaration' ) {
// TODO generic 'get deconflicted name' mechanism
let defaultExportName = makeLegalIdentifier( basename( this.entryPath ).slice( 0, -extname( this.entryPath ).length ) );
while ( this.entryModule.ast._scope.contains( defaultExportName ) ) {
defaultExportName = `_${defaultExportName}`;
}
entryModule.suggestedNames.default = defaultExportName;
node._source.overwrite( node.start, node.declaration.start, `var ${defaultExportName} = ` );
}
if ( node.type === 'ExportNamedDeclaration' ) {
// Remove the `export`
node._source.remove( node.start, node.declaration.start );
}
// Include everything else
this.statements.push( node );
});
});
return entryModule.expandAllStatements();
})
.then( () => {
.then( statements => {
this.statements = statements;
this.deconflict();
});

111
src/Module.js

@ -3,7 +3,7 @@ import { Promise } from 'sander';
import { parse } from 'acorn';
import MagicString from 'magic-string';
import analyse from './ast/analyse';
import { has } from './utils/object';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';
@ -241,7 +241,7 @@ export default class Module {
this.bundle.internalNamespaceModules.push( module );
}
return module.includeAllStatements();
return module.expandAllStatements();
}
const exportDeclaration = module.exports[ importDeclaration.name ];
@ -294,68 +294,74 @@ export default class Module {
}
if ( statement && !statement._included ) {
const result = [];
promise = this.expandStatement( statement );
}
}
const include = statement => {
if ( statement._included ) return emptyArrayPromise;
statement._included = true;
this.definitionPromises[ name ] = promise || emptyArrayPromise;
return this.definitionPromises[ name ];
}
// We have a statement, and it hasn't been included yet. First, include
// the statements it depends on
const dependencies = Object.keys( statement._dependsOn );
expandStatement ( statement ) {
if ( statement._included ) return emptyArrayPromise;
statement._included = true;
return sequence( dependencies, name => {
return this.define( name ).then( definition => {
result.push.apply( result, definition );
});
})
let result = [];
// then include the statement itself
.then( () => {
result.push( statement );
})
// We have a statement, and it hasn't been included yet. First, include
// the statements it depends on
const dependencies = Object.keys( statement._dependsOn );
// then include any statements that could modify the
// thing(s) this statement defines
.then( () => {
const modifications = has( this.modifications, name ) && this.modifications[ name ];
if ( modifications ) {
return sequence( modifications, statement => {
if ( !statement._included ) {
return include( statement );
}
});
return sequence( dependencies, name => {
return this.define( name ).then( definition => {
result.push.apply( result, definition );
});
})
// then include the statement itself
.then( () => {
result.push( statement );
})
// then include any statements that could modify the
// thing(s) this statement defines
.then( () => {
const definedByThisStatement = keys( statement._defines );
return sequence( keys( statement._defines ), name => {
const modifications = has( this.modifications, name ) && this.modifications[ name ];
if ( modifications ) {
return sequence( modifications, statement => {
if ( !statement._included ) {
return this.expandStatement( statement )
.then( statements => {
result.push.apply( result, statements );
});
}
})
}
});
})
// the `result` is an array of statements needed to define `name`
.then( () => {
return result;
});
};
promise = !statement._included ? include( statement ) : emptyArrayPromise;
}
}
this.definitionPromises[ name ] = promise || emptyArrayPromise;
return this.definitionPromises[ name ];
// the `result` is an array of statements needed to define `name`
.then( () => {
return result;
});
}
includeAllStatements () {
return this.ast.body.filter( statement => {
expandAllStatements () {
let allStatements = [];
return sequence( this.ast.body, statement => {
// skip already-included statements
if ( statement._included ) return false;
if ( statement._included ) return;
// skip import declarations
if ( /^Import/.test( statement.type ) ) return false;
if ( /^Import/.test( statement.type ) ) return;
// skip `export { foo, bar, baz }`
if ( statement.type === 'ExportNamedDeclaration' && statement.specifiers.length ) return false;
if ( statement.type === 'ExportNamedDeclaration' && statement.specifiers.length ) return;
// include everything else
@ -379,7 +385,12 @@ export default class Module {
}
}
return true;
return this.expandStatement( statement )
.then( statements => {
allStatements.push.apply( allStatements, statements );
});
}).then( () => {
return allStatements;
});
}

4
test/samples/bindings/main.js

@ -1,5 +1,5 @@
import { count, incr } from './foo';
assert.equal (count, 0 );
assert.equal(count, 0);
incr();
assert.equal( count, 1 );
assert.equal(count, 1);

Loading…
Cancel
Save