feat(transiler/dart): re-export imported vars
``` import {Foo} from ‘./foo’; var localVar = true; export {Foo, localVar}; ===> import ‘./foo’ show Foo; export ‘./foo’ show Foo; var localVar = true; ``` Closes #41
This commit is contained in:
parent
c5153175b6
commit
c68e78075a
|
@ -0,0 +1 @@
|
|||
export var Baz = 'BAZ';
|
|
@ -9,8 +9,14 @@ import * as exportModule from './export';
|
|||
|
||||
import {Type} from 'facade/lang';
|
||||
|
||||
import {Baz} from './reexport';
|
||||
|
||||
export function main() {
|
||||
describe('imports', function() {
|
||||
it('should re-export imported vars', function() {
|
||||
expect(Baz).toBe('BAZ');
|
||||
});
|
||||
|
||||
it('should work', function() {
|
||||
expect(Foo).toBe('FOO');
|
||||
expect(Bar).toBe('BAR');
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import {Baz} from './baz';
|
||||
import {Bar1} from './bar';
|
||||
|
||||
var localVar = true;
|
||||
|
||||
export {Baz, localVar, Bar1};
|
||||
|
||||
// Will become:
|
||||
// export {Baz} from './baz';
|
||||
// export {Bar1} from './bar';
|
|
@ -8,6 +8,7 @@ import {InstanceOfTransformer} from './InstanceOfTransformer';
|
|||
import {MultiVarTransformer} from './MultiVarTransformer';
|
||||
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
|
||||
import {NamedParamsTransformer} from './NamedParamsTransformer';
|
||||
import {ExportTransformer} from './ExportTransformer';
|
||||
|
||||
/**
|
||||
* Transforms ES6 + annotations to Dart code.
|
||||
|
@ -28,5 +29,6 @@ export class DartTransformer extends MultiTransformer {
|
|||
append(InstanceOfTransformer);
|
||||
append(StrictEqualityTransformer);
|
||||
append(ClassTransformer);
|
||||
append(ExportTransformer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import {ParseTreeTransformer} from './ParseTreeTransformer';
|
||||
import {Map} from 'traceur/src/runtime/polyfills/Map';
|
||||
import {
|
||||
ExportDeclaration,
|
||||
ExportSpecifierSet,
|
||||
NamedExport,
|
||||
EmptyStatement
|
||||
} from 'traceur/src/syntax/trees/ParseTrees';
|
||||
import {
|
||||
IMPORT_DECLARATION,
|
||||
NAMED_EXPORT
|
||||
} from 'traceur/src/syntax/trees/ParseTreeType';
|
||||
|
||||
|
||||
// Return the index of the first item that is not of IMPORT_DECLARATION type.
|
||||
function getIndexOfFirstNonImportStatement(items) {
|
||||
var index = 0;
|
||||
|
||||
while (index < items.length && items[index].type === IMPORT_DECLARATION) {
|
||||
index++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transforms re-exports:
|
||||
* ```
|
||||
* import {Foo} from './foo';
|
||||
* import {Bar} from './bar';
|
||||
* var localVar = true;
|
||||
*
|
||||
* export {Foo, Bar, localVar}
|
||||
*
|
||||
* ===>
|
||||
*
|
||||
* import {Foo} from './foo';
|
||||
* import {Bar} from './bar';
|
||||
* var localVar = true;
|
||||
*
|
||||
* export {Foo} from './foo';
|
||||
* export {Bar} from './bar';
|
||||
* ```
|
||||
*
|
||||
* In Dart, all variables defined in the root context of a module that don't start with
|
||||
* an underscore are exported. Thus we just drop the "export" keyword for the locally defined vars.
|
||||
* Variables imported from other modules need to be exported with `export './foo' show Foo`.
|
||||
* This transformer drops the local exports and add the information about module path for the
|
||||
* imported variables.
|
||||
*/
|
||||
export class ExportTransformer extends ParseTreeTransformer {
|
||||
constructor(idGenerator, reporter) {
|
||||
this.reporter_ = reporter;
|
||||
this.importedVars_ = null;
|
||||
this.collectedExports_ = null;
|
||||
}
|
||||
|
||||
transformModule(tree) {
|
||||
// New context for each file (module).
|
||||
this.importedVars_ = new Map();
|
||||
this.collectedExports_ = [];
|
||||
|
||||
tree = super.transformModule(tree);
|
||||
|
||||
// In Dart, imports and exports have to be at the top, before any other statement.
|
||||
// Insert the collected exports before the first non-import statement (after all imports).
|
||||
var items = tree.scriptItemList;
|
||||
var index = getIndexOfFirstNonImportStatement(items);
|
||||
tree.scriptItemList = items.slice(0, index).concat(this.collectedExports_, items.slice(index));
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
// For each imported variable, store the module path where it comes from.
|
||||
// For instance, `import {Foo} from './foo'` will map 'Foo' -> './foo'.
|
||||
// TODO(vojta): deal with `import * as m from './foo'`.
|
||||
transformImportDeclaration(tree) {
|
||||
tree.importClause.specifiers.forEach((specifier) => {
|
||||
this.importedVars_.set(specifier.binding.binding.identifierToken.value, tree.moduleSpecifier);
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
transformExportDeclaration(tree) {
|
||||
if (tree.declaration.type === NAMED_EXPORT && tree.declaration.moduleSpecifier === null) {
|
||||
// export {...}
|
||||
tree.declaration.specifierSet.specifiers.forEach((specifier) => {
|
||||
// Filter out local variables, keep only imported ones.
|
||||
if (!this.importedVars_.has(specifier.lhs.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For each specifier, create a new ExportDeclaration and attach the module path (collected
|
||||
// in `transformImportDeclaration`) to it.
|
||||
this.collectedExports_.push(new ExportDeclaration(tree.location,
|
||||
new NamedExport(tree.declaration.location, this.importedVars_.get(specifier.lhs.value),
|
||||
new ExportSpecifierSet(tree.declaration.specifierSet.location, [specifier])),
|
||||
tree.annotations));
|
||||
});
|
||||
|
||||
return new EmptyStatement(tree.location);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import {
|
|||
import {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter';
|
||||
import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees';
|
||||
import {IdentifierToken} from 'traceur/src/syntax/IdentifierToken';
|
||||
import {EXPORT_STAR} from 'traceur/src/syntax/trees/ParseTreeType';
|
||||
import {EXPORT_STAR, NAMED_EXPORT} from 'traceur/src/syntax/trees/ParseTreeType';
|
||||
|
||||
export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
||||
constructor(moduleName, outputPath) {
|
||||
|
@ -34,6 +34,8 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
|||
this.annotationContextCounter = 0;
|
||||
}
|
||||
|
||||
visitEmptyStatement() {}
|
||||
|
||||
// CLASS FIELDS
|
||||
visitPropertyVariableDeclaration(tree) {
|
||||
if (tree.isStatic) {
|
||||
|
@ -275,35 +277,43 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
|||
|
||||
// EXPORTS
|
||||
visitExportDeclaration(tree) {
|
||||
if (tree.declaration.moduleSpecifier) {
|
||||
if (tree.declaration.specifierSet.type === EXPORT_STAR) {
|
||||
// export * from './foo'
|
||||
// ===>
|
||||
// export './foo';
|
||||
this.write_('export');
|
||||
this.writeSpace_();
|
||||
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
|
||||
this.write_(SEMI_COLON);
|
||||
if (tree.declaration.type === NAMED_EXPORT) {
|
||||
// export {...}
|
||||
// export {...} from './foo'
|
||||
// export * from './foo'
|
||||
|
||||
if (tree.declaration.moduleSpecifier) {
|
||||
if (tree.declaration.specifierSet.type === EXPORT_STAR) {
|
||||
// export * from './foo'
|
||||
// ===>
|
||||
// export './foo';
|
||||
this.write_('export');
|
||||
this.writeSpace_();
|
||||
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
|
||||
this.write_(SEMI_COLON);
|
||||
} else {
|
||||
// export {Foo, Bar} from './foo'
|
||||
// ===>
|
||||
// export './foo' show Foo, Bar;
|
||||
this.write_('export');
|
||||
this.writeSpace_();
|
||||
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
|
||||
this.writeSpace_();
|
||||
this.write_('show');
|
||||
this.writeSpace_();
|
||||
this.writeList_(tree.declaration.specifierSet.specifiers, COMMA, false);
|
||||
this.write_(SEMI_COLON);
|
||||
}
|
||||
} else {
|
||||
// export {Foo, Bar} from './foo'
|
||||
// ===>
|
||||
// export './foo' show Foo, Bar;
|
||||
this.write_('export');
|
||||
this.writeSpace_();
|
||||
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
|
||||
this.writeSpace_();
|
||||
this.write_('show');
|
||||
this.writeSpace_();
|
||||
this.writeList_(tree.declaration.specifierSet.specifiers, COMMA, false);
|
||||
this.write_(SEMI_COLON);
|
||||
// export {...}
|
||||
// This case is handled in `ExportTransformer`.
|
||||
throw new Error('Should never happen!');
|
||||
}
|
||||
} else {
|
||||
// Just remove the "export" keyword.
|
||||
// export var x = true;
|
||||
// export var x = true
|
||||
// export class Foo {}
|
||||
// ===>
|
||||
// var x = true;
|
||||
// class Foo {}
|
||||
// export function bar() {}
|
||||
// Just remove "export" keyword.
|
||||
this.writeAnnotations_(tree.annotations);
|
||||
this.visitAny(tree.declaration);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue