Browse Source

Implemented export * from ...

contingency-plan
Oskar Segersvärd 10 years ago
committed by Oskar Segersvärd
parent
commit
0e2e705afa
  1. 53
      src/Module.js
  2. 1
      src/Statement.js
  3. 22
      src/utils/promise.js
  4. 5
      test/function/export-all/_config.js
  5. 2
      test/function/export-all/main.js
  6. 1
      test/function/export-all/wat-impl.js
  7. 1
      test/function/export-all/wat.js

53
src/Module.js

@ -6,7 +6,7 @@ import Statement from './Statement';
import walk from './ast/walk';
import analyse from './ast/analyse';
import { blank, keys } from './utils/object';
import { sequence } from './utils/promise';
import { first, sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';
@ -43,6 +43,11 @@ export default class Module {
this.imports = blank();
this.exports = blank();
this.exportAlls = blank();
// array of all-export sources
this.exportDelegates = [];
this.canonicalNames = blank();
this.definitions = blank();
@ -124,6 +129,15 @@ export default class Module {
};
}
}
// Store `export * from '...'` statements in an array of delegates.
// When an unknown import is encountered, we see if one of them can satisfy it.
else {
this.exportDelegates.push({
statement,
source
});
}
}
addImport ( statement ) {
@ -195,6 +209,13 @@ export default class Module {
keys( statement.stronglyDependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
const exportAllDeclaration = this.exportAlls[ name ];
if ( exportAllDeclaration && exportAllDeclaration.module && !exportAllDeclaration.module.isExternal ) {
strongDependencies[ exportAllDeclaration.module.id ] = exportAllDeclaration.module;
return;
}
const importDeclaration = this.imports[ name ];
if ( importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal ) {
@ -287,7 +308,13 @@ export default class Module {
exporterLocalName = importDeclaration.name;
} else {
const exportDeclaration = module.exports[ importDeclaration.name ];
exporterLocalName = exportDeclaration.localName;
// The export declaration of the particular name is known.
if (exportDeclaration) {
exporterLocalName = exportDeclaration.localName;
} else { // export * from '...'
exporterLocalName = importDeclaration.name;
}
}
canonicalName = module.getCanonicalName( exporterLocalName );
@ -362,7 +389,27 @@ export default class Module {
const exportDeclaration = module.exports[ importDeclaration.name ];
if ( !exportDeclaration ) {
throw new Error( `Module ${module.id} does not export ${importDeclaration.name} (imported by ${this.id})` );
const noExport = new Error( `Module ${module.id} does not export ${importDeclaration.name} (imported by ${this.id})` );
// See if there exists an export delegate that defines `name`.
return first( module.exportDelegates, noExport, declaration => {
return module.bundle.fetchModule( declaration.source, module.id ).then( submodule => {
declaration.module = submodule;
return submodule.mark( name ).then( result => {
if ( !result.length ) throw noExport;
// It's found! This module exports `name` through declaration.
// It is however not imported into this scope.
module.exportAlls[ name ] = declaration;
declaration.statement.dependsOn[ name ] =
declaration.statement.stronglyDependsOn[ name ] = result;
return result;
});
});
});
}
return module.mark( exportDeclaration.localName );

1
src/Statement.js

@ -31,6 +31,7 @@ export default class Statement {
// some facts about this statement...
this.isImportDeclaration = node.type === 'ImportDeclaration';
this.isExportDeclaration = /^Export/.test( node.type );
this.isExportAllDeclaration = /^ExportAll/.test( node.type );
}
analyse () {

22
src/utils/promise.js

@ -19,4 +19,24 @@ export function sequence ( arr, callback ) {
}
return promise.then( () => results );
}
}
export function first ( arr, fail, callback ) {
const len = arr.length;
let promise = Promise.reject( fail );
function next ( i ) {
return promise
.catch(() => callback( arr[i], i ));
}
let i;
for ( i = 0; i < len; i += 1 ) {
promise = next( i );
}
return promise;
}

5
test/function/export-all/_config.js

@ -0,0 +1,5 @@
var assert = require( 'assert' );
module.exports = {
description: 'allows export *'
};

2
test/function/export-all/main.js

@ -0,0 +1,2 @@
import { wat } from './wat';
assert.equal( wat(), 4711 );

1
test/function/export-all/wat-impl.js

@ -0,0 +1 @@
export function wat () { return 4711; }

1
test/function/export-all/wat.js

@ -0,0 +1 @@
export * from './wat-impl';
Loading…
Cancel
Save