diff --git a/src/Bundle.js b/src/Bundle.js index dcc50c7..d174b57 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -191,9 +191,17 @@ export default class Bundle { if ( !this.modulePromises[ id ] ) { this.modulePromises[ id ] = Promise.resolve( this.load( id, this.loadOptions ) ) .then( source => { + let ast; + + if ( typeof source === 'object' ) { + ast = source.ast; + source = source.code; + } + const module = new Module({ id, source, + ast, bundle: this }); diff --git a/src/Module.js b/src/Module.js index 70c2ccb..85bd7a0 100644 --- a/src/Module.js +++ b/src/Module.js @@ -29,7 +29,7 @@ function isEmptyExportedVarDeclaration ( node, module, allBundleExports, es6 ) { } export default class Module { - constructor ({ id, source, bundle }) { + constructor ({ id, source, ast, bundle }) { this.source = source; this.bundle = bundle; @@ -51,7 +51,7 @@ export default class Module { this.suggestedNames = blank(); this.comments = []; - this.statements = this._parse(); + this.statements = this._parse( ast ); // imports and exports, indexed by ID this.imports = blank(); @@ -517,21 +517,22 @@ export default class Module { } // TODO rename this to parse, once https://github.com/rollup/rollup/issues/42 is fixed - _parse () { - // Try to extract a list of top-level statements/declarations. If - // the parse fails, attach file info and abort - let ast; - - try { - ast = parse( this.source, { - ecmaVersion: 6, - sourceType: 'module', - onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }) - }); - } catch ( err ) { - err.code = 'PARSE_ERROR'; - err.file = this.id; // see above - not necessarily true, but true enough - throw err; + _parse ( ast ) { + // The ast can be supplied programmatically (but usually won't be) + if ( !ast ) { + // Try to extract a list of top-level statements/declarations. If + // the parse fails, attach file info and abort + try { + ast = parse( this.source, { + ecmaVersion: 6, + sourceType: 'module', + onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }) + }); + } catch ( err ) { + err.code = 'PARSE_ERROR'; + err.file = this.id; // see above - not necessarily true, but true enough + throw err; + } } walk( ast, { diff --git a/test/function/uses-supplied-ast/_config.js b/test/function/uses-supplied-ast/_config.js new file mode 100644 index 0000000..e7c9b00 --- /dev/null +++ b/test/function/uses-supplied-ast/_config.js @@ -0,0 +1,35 @@ +var acorn = require( 'acorn' ); + +var modules = { + 'main': 'import foo from \'foo\';\nfoo();', + + // the code points to './bar' but the AST points to './baz', so we + // can check the AST is being used + 'foo': { + code: 'import bar from \'bar\';\nexport default function foo () {\n\tconsole.log( bar );\n}', + ast: acorn.parse( 'import bar from \'baz\';\nexport default function foo () {\n\tconsole.log( bar );\n}', { + ecmaVersion: 6, + sourceType: 'module' + }) + }, + + 'baz': 'export default 42;' +}; + +module.exports = { + description: 'uses supplied AST', + options: { + resolveId: function ( importee, importer ) { + if ( !importer ) return 'main'; + return importee; + }, + load: function ( id ) { + if ( id === 'bar' ) { + throw new Error( 'loaded incorrect module' ); + } + + return modules[ id ]; + } + }, + solo: true +};