diff --git a/src/Bundle.js b/src/Bundle.js index 975314f..baebff2 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -112,6 +112,7 @@ export default class Bundle { .then( statements => { this.statements = statements; this.deconflict(); + this.sort(); }); } @@ -200,6 +201,76 @@ export default class Bundle { } } + sort () { + // TODO avoid this work whenever possible... + + let definitions = blank(); + + // gather definitions + this.statements.forEach( statement => { + keys( statement.defines ).forEach( name => { + const canonicalName = statement.module.getCanonicalName( name ); + definitions[ canonicalName ] = statement; + }); + }); + + let strongDeps = blank(); + let stronglyDependsOn = blank(); + + this.statements.forEach( statement => { + const id = statement.id; + strongDeps[ id ] = []; + stronglyDependsOn[ id ] = {}; + + keys( statement.stronglyDependsOn ).forEach( name => { + if ( statement.defines[ name ] ) return; // TODO seriously... need to fix this + const canonicalName = statement.module.getCanonicalName( name ); + const definition = definitions[ canonicalName ]; + + if ( definition ) strongDeps[ statement.id ].push( definition ); + }); + }); + + // add second (and third...) order strong dependencies + this.statements.forEach( statement => { + const id = statement.id; + + // add second (and third...) order dependencies + function addStrongDependencies ( dependency ) { + if ( stronglyDependsOn[ id ][ dependency.id ] ) return; + + stronglyDependsOn[ id ][ dependency.id ] = true; + strongDeps[ dependency.id ].forEach( addStrongDependencies ); + } + + strongDeps[ id ].forEach( addStrongDependencies ); + }); + + // reinsert each statement, ensuring its strong dependencies appear first + let sorted = []; + let included = blank(); + + this.statements.forEach( statement => { + strongDeps[ statement.id ].forEach( place ); + + function place ( dependency ) { + if ( !stronglyDependsOn[ dependency.id ][ statement.id ] && !included[ dependency.id ] ) { + strongDeps[ dependency.id ].forEach( place ); + sorted.push( dependency ); + + included[ dependency.id ] = true; + } + } + + if ( !included[ statement.id ] ) { + sorted.push( statement ); + included[ statement.id ] = true; + } + }); + + this.statements = sorted; + } + generate ( options = {} ) { let magicString = new MagicString.Bundle({ separator: '' }); diff --git a/src/Statement.js b/src/Statement.js index 0d665f6..15a9f5c 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -4,14 +4,13 @@ import getLocation from './utils/getLocation'; import walk from './ast/walk'; import Scope from './ast/Scope'; -const emptyArrayPromise = Promise.resolve([]); - export default class Statement { constructor ( node, magicString, module, index ) { this.node = node; this.module = module; this.magicString = magicString; this.index = index; + this.id = module.path + '#' + index; this.scope = new Scope(); this.defines = blank(); diff --git a/test/function/cycles-pathological/_config.js b/test/function/cycles-pathological/_config.js index 801659f..156a2f3 100644 --- a/test/function/cycles-pathological/_config.js +++ b/test/function/cycles-pathological/_config.js @@ -14,6 +14,5 @@ module.exports = { assert.ok( exports.c2.isC ); assert.ok( exports.c2.isD ); assert.ok( exports.d.isD ); - }, - solo: true + } };