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 {Type} from 'facade/lang';
|
||||||
|
|
||||||
|
import {Baz} from './reexport';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('imports', function() {
|
describe('imports', function() {
|
||||||
|
it('should re-export imported vars', function() {
|
||||||
|
expect(Baz).toBe('BAZ');
|
||||||
|
});
|
||||||
|
|
||||||
it('should work', function() {
|
it('should work', function() {
|
||||||
expect(Foo).toBe('FOO');
|
expect(Foo).toBe('FOO');
|
||||||
expect(Bar).toBe('BAR');
|
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 {MultiVarTransformer} from './MultiVarTransformer';
|
||||||
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
|
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
|
||||||
import {NamedParamsTransformer} from './NamedParamsTransformer';
|
import {NamedParamsTransformer} from './NamedParamsTransformer';
|
||||||
|
import {ExportTransformer} from './ExportTransformer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms ES6 + annotations to Dart code.
|
* Transforms ES6 + annotations to Dart code.
|
||||||
|
@ -28,5 +29,6 @@ export class DartTransformer extends MultiTransformer {
|
||||||
append(InstanceOfTransformer);
|
append(InstanceOfTransformer);
|
||||||
append(StrictEqualityTransformer);
|
append(StrictEqualityTransformer);
|
||||||
append(ClassTransformer);
|
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 {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter';
|
||||||
import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees';
|
import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees';
|
||||||
import {IdentifierToken} from 'traceur/src/syntax/IdentifierToken';
|
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 {
|
export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
||||||
constructor(moduleName, outputPath) {
|
constructor(moduleName, outputPath) {
|
||||||
|
@ -34,6 +34,8 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
||||||
this.annotationContextCounter = 0;
|
this.annotationContextCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitEmptyStatement() {}
|
||||||
|
|
||||||
// CLASS FIELDS
|
// CLASS FIELDS
|
||||||
visitPropertyVariableDeclaration(tree) {
|
visitPropertyVariableDeclaration(tree) {
|
||||||
if (tree.isStatic) {
|
if (tree.isStatic) {
|
||||||
|
@ -275,6 +277,11 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
||||||
|
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
visitExportDeclaration(tree) {
|
visitExportDeclaration(tree) {
|
||||||
|
if (tree.declaration.type === NAMED_EXPORT) {
|
||||||
|
// export {...}
|
||||||
|
// export {...} from './foo'
|
||||||
|
// export * from './foo'
|
||||||
|
|
||||||
if (tree.declaration.moduleSpecifier) {
|
if (tree.declaration.moduleSpecifier) {
|
||||||
if (tree.declaration.specifierSet.type === EXPORT_STAR) {
|
if (tree.declaration.specifierSet.type === EXPORT_STAR) {
|
||||||
// export * from './foo'
|
// export * from './foo'
|
||||||
|
@ -298,12 +305,15 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
|
||||||
this.write_(SEMI_COLON);
|
this.write_(SEMI_COLON);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Just remove the "export" keyword.
|
// export {...}
|
||||||
// export var x = true;
|
// This case is handled in `ExportTransformer`.
|
||||||
|
throw new Error('Should never happen!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// export var x = true
|
||||||
// export class Foo {}
|
// export class Foo {}
|
||||||
// ===>
|
// export function bar() {}
|
||||||
// var x = true;
|
// Just remove "export" keyword.
|
||||||
// class Foo {}
|
|
||||||
this.writeAnnotations_(tree.annotations);
|
this.writeAnnotations_(tree.annotations);
|
||||||
this.visitAny(tree.declaration);
|
this.visitAny(tree.declaration);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue