feat(modules): add "register" module type

Inspired by https://github.com/ModuleLoader/es6-module-loader/wiki/System.register-Explained
This commit is contained in:
Douglas Duteil 2014-11-23 02:22:24 +01:00
parent 680771c81b
commit c87e14f6a9
27 changed files with 576 additions and 0 deletions

View File

@ -135,6 +135,43 @@ function bar() {
}
```
### Register
**In**
```javascript
import foo from "foo";
export function bar() {
return foo("foobar");
}
```
**Out**
```javascript
System.register("bar", ["foo"], function ($__export) {
"use strict";
var __moduleName = "bar";
var foo;
function bar() {
return foo("foobar");
}
return {
setters: [function (m) {
foo = m.default;
}],
execute: function () {
$__export("bar", bar);
}
};
});
```
## Custom
You can alternatively specify module names instead of one of the built-in types.

View File

@ -0,0 +1 @@
System.register(MODULE_NAME, MODULE_DEPENDENCIES, MODULE_BODY);

View File

@ -0,0 +1,233 @@
module.exports = RegisterFormatter;
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
var EXPORT_IDENTIFIER = t.identifier("$__export");
var DEFAULT_IDENTIFIER = t.identifier("default");
var SETTER_MODULE_NAMESPACE = t.identifier("m");
var NULL_SETTER = {
"type": "Literal",
"value": null,
"raw": "null"
};
function RegisterFormatter(file) {
this.file = file;
this.importedModule = {};
this.exportedStatements = [];
}
RegisterFormatter.prototype.transform = function(ast) {
var program = ast.program;
var body = program.body;
// extract the module name
var moduleName = this.file.opts.filename
.replace(/^.*\//, "").replace(/\..*$/, "");
// build an array of module names
var dependencies = Object.keys(this.importedModule).map(t.literal);
// generate the __moduleName variable
var moduleNameVariableNode = t.variableDeclaration("var", [
t.variableDeclarator(
t.identifier("__moduleName"),
t.literal(moduleName)
)
]);
body.splice(1, 0, moduleNameVariableNode);
// generate an array of import variables
var declaredSetters = _(this.importedModule)
.map()
.flatten()
.pluck("VARIABLE_NAME")
.pluck("name")
.uniq()
.map(t.identifier)
.map(function(name) {
return t.variableDeclarator(name);
})
.value();
if (declaredSetters.length) {
body.splice(2, 0, t.variableDeclaration("var", declaredSetters));
}
// generate the execute function expression
var executeFunctionExpression = t.functionExpression(
null, [], t.blockStatement(this.exportedStatements)
);
// generate the execute function expression
var settersArrayExpression = t.arrayExpression(this._buildSetters());
// generate the return statement
var moduleReturnStatement = t.returnStatement(t.objectExpression([
t.property("init", t.identifier("setters"), settersArrayExpression),
t.property("init", t.identifier("execute"), executeFunctionExpression)
]));
body.push(moduleReturnStatement);
// runner
var runner = util.template("register", {
MODULE_NAME: t.literal(moduleName),
MODULE_DEPENDENCIES: t.arrayExpression(dependencies),
MODULE_BODY: t.functionExpression(
null,
[EXPORT_IDENTIFIER],
t.blockStatement(body)
)
});
program.body = [t.expressionStatement(runner)];
};
RegisterFormatter.prototype._buildSetters = function() {
// generate setters array expression elements
return _(this.importedModule)
.map(function(specifications) {
if (!specifications.length) {
return NULL_SETTER;
}
var expressionStatements = _.map(specifications, function(specification) {
return t.expressionStatement(
t.assignmentExpression(
"=",
specification.VARIABLE_NAME,
specification.IS_BATCH ?
SETTER_MODULE_NAMESPACE :
t.memberExpression(
SETTER_MODULE_NAMESPACE,
specification.KEY
)
)
);
});
return t.functionExpression(
null, [SETTER_MODULE_NAMESPACE], t.blockStatement(expressionStatements)
);
}.bind(this))
.value();
};
RegisterFormatter.prototype.import = function(node) {
var MODULE_NAME = node.source.value;
this.importedModule[MODULE_NAME] =
this.importedModule[MODULE_NAME] || [];
};
RegisterFormatter.prototype.importSpecifier = function(specifier, node) {
var variableName = t.getSpecifierName(specifier);
// import foo from "foo";
if (specifier.default) {
specifier.id = DEFAULT_IDENTIFIER;
}
var MODULE_NAME = node.source.value;
this.importedModule[MODULE_NAME] =
this.importedModule[MODULE_NAME] || [];
this.importedModule[MODULE_NAME].push(
{
VARIABLE_NAME: variableName,
KEY: specifier.id,
IS_BATCH: specifier.type === "ImportBatchSpecifier"
}
);
};
RegisterFormatter.prototype._export = function(name, identifier) {
this.exportedStatements.push(t.expressionStatement(
t.callExpression(EXPORT_IDENTIFIER, [t.literal(name), identifier])
));
};
RegisterFormatter.prototype.export = function(node, nodes) {
var declar = node.declaration;
var variableName, identifier;
if (node.default) {
// export default foo
variableName = DEFAULT_IDENTIFIER.name;
if (t.isClass(declar) || t.isFunction(declar)) {
if (!declar.id) {
declar.id = this.file.generateUidIdentifier("anonymousFct");
}
nodes.push(t.toStatement(declar));
declar = declar.id;
}
identifier = declar;
} else if (t.isVariableDeclaration(declar)) {
// export var foo
variableName = declar.declarations[0].id.name;
identifier = declar.declarations[0].id;
nodes.push((declar));
} else {
// export function foo () {}
variableName = declar.id.name;
identifier = declar.id;
nodes.push(declar);
}
this._export(variableName, identifier);
};
RegisterFormatter.prototype.exportSpecifier = function(specifier, node) {
var variableName = t.getSpecifierName(specifier);
if (node.source) {
if (t.isExportBatchSpecifier(specifier)) {
// export * from "foo";
var exportIdentifier = t.identifier("exports");
this.exportedStatements.push(
t.variableDeclaration("var",
[
t.variableDeclarator(
exportIdentifier,
EXPORT_IDENTIFIER
)
]
)
);
this.exportedStatements.push(util.template("exports-wildcard", {
OBJECT: t.identifier(node.source.value)
}, true));
} else {
// export { foo } from "test";
this._export(variableName.name, t.memberExpression(
t.identifier(node.source.value),
specifier.id
));
}
} else {
// export { foo };
this._export(variableName.name, specifier.id);
}
};

View File

@ -20,6 +20,7 @@ transform._ensureTransformerNames = function (type, keys) {
transform.transformers = {};
transform.moduleFormatters = {
register: require("./modules/register"),
common: require("./modules/common"),
commonInterop: require("./modules/common-interop"),
ignore: require("./modules/ignore"),

View File

@ -0,0 +1,8 @@
export default 42;
export default {};
export default [];
export default foo;
export default function () {}
export default class {}
export default function foo () {}
export default class Foo {}

View File

@ -0,0 +1,32 @@
System.register("actual", [], function ($__export) {
"use strict";
var __moduleName = "actual";
function _anonymousFct() {}
var _anonymousFct2 = function _anonymousFct2() {};
function foo() {}
var Foo = function Foo() {};
return {
setters: [],
execute: function () {
$__export("default", 42);
$__export("default", {});
$__export("default", []);
$__export("default", foo);
$__export("default", _anonymousFct);
$__export("default", _anonymousFct2);
$__export("default", foo);
$__export("default", Foo);
}
};
});

View File

@ -0,0 +1,6 @@
export * from "foo";
export {foo} from "foo";
export {foo, bar} from "foo";
export {foo as bar} from "foo";
export {foo as default} from "foo";
export {foo as default, bar} from "foo";

View File

@ -0,0 +1,31 @@
System.register("actual", [], function ($__export) {
"use strict";
var __moduleName = "actual";
return {
setters: [],
execute: function () {
var exports = $__export;
(function (obj) {
for (var i in obj) {
exports[i] = obj[i];
}
})(foo);
$__export("foo", foo.foo);
$__export("foo", foo.foo);
$__export("bar", foo.bar);
$__export("bar", foo.foo);
$__export("default", foo.foo);
$__export("default", foo.foo);
$__export("bar", foo.bar);
}
};
});

View File

@ -0,0 +1,5 @@
export {foo};
export {foo, bar};
export {foo as bar};
export {foo as default};
export {foo as default, bar};

View File

@ -0,0 +1,24 @@
System.register("actual", [], function ($__export) {
"use strict";
var __moduleName = "actual";
return {
setters: [],
execute: function () {
$__export("foo", foo);
$__export("foo", foo);
$__export("bar", bar);
$__export("bar", foo);
$__export("default", foo);
$__export("default", foo);
$__export("bar", bar);
}
};
});

View File

@ -0,0 +1,8 @@
export var foo = 1;
export var foo2 = function () {};
export var foo3;
export let foo4 = 2;
export let foo5;
export const foo6 = 3;
export function foo7 () {}
export class foo8 {}

View File

@ -0,0 +1,35 @@
System.register("actual", [], function ($__export) {
"use strict";
var __moduleName = "actual";
var foo = 1;
var foo2 = function () {};
var foo3;
var foo4 = 2;
var foo5;
var foo6 = 3;
function foo7() {}
var foo8 = function foo8() {};
return {
setters: [],
execute: function () {
$__export("foo", foo);
$__export("foo2", foo2);
$__export("foo3", foo3);
$__export("foo4", foo4);
$__export("foo5", foo5);
$__export("foo6", foo6);
$__export("foo7", foo7);
$__export("foo8", foo8);
}
};
});

View File

@ -0,0 +1,11 @@
import { isEven } from "./evens";
export function nextOdd(n) {
return isEven(n) ? n + 1 : n + 2;
}
export var isOdd = (function (isEven) {
return function (n) {
return !isEven(n);
};
})(isEven);

View File

@ -0,0 +1,25 @@
System.register("actual", ["./evens"], function ($__export) {
"use strict";
var __moduleName = "actual";
var isEven;
function nextOdd(n) {
return isEven(n) ? n + 1 : n + 2;
}
var isOdd = (function (isEven) {
return function (n) {
return !isEven(n);
};
})(isEven);return {
setters: [function (m) {
isEven = m.isEven;
}],
execute: function () {
$__export("nextOdd", nextOdd);
$__export("isOdd", isOdd);
}
};
});

View File

@ -0,0 +1,2 @@
import foo from "foo";
import {default as foo} from "foo";

View File

@ -0,0 +1,14 @@
System.register("actual", ["foo"], function ($__export) {
"use strict";
var __moduleName = "actual";
var foo;
return {
setters: [function (m) {
foo = m.default;
foo = m.default;
}],
execute: function () {}
};
});

View File

@ -0,0 +1 @@
import * as foo from "foo";

View File

@ -0,0 +1,13 @@
System.register("actual", ["foo"], function ($__export) {
"use strict";
var __moduleName = "actual";
var foo;
return {
setters: [function (m) {
foo = m;
}],
execute: function () {}
};
});

View File

@ -0,0 +1 @@
import foo, {baz as xyz} from "foo";

View File

@ -0,0 +1,14 @@
System.register("actual", ["foo"], function ($__export) {
"use strict";
var __moduleName = "actual";
var foo, xyz;
return {
setters: [function (m) {
foo = m.default;
xyz = m.baz;
}],
execute: function () {}
};
});

View File

@ -0,0 +1,4 @@
import {bar} from "foo";
import {bar, baz} from "foo";
import {bar as baz} from "foo";
import {bar as baz, xyz} from "foo";

View File

@ -0,0 +1,18 @@
System.register("actual", ["foo"], function ($__export) {
"use strict";
var __moduleName = "actual";
var bar, baz, xyz;
return {
setters: [function (m) {
bar = m.bar;
bar = m.bar;
baz = m.baz;
baz = m.bar;
baz = m.bar;
xyz = m.xyz;
}],
execute: function () {}
};
});

View File

@ -0,0 +1,3 @@
import "foo";
import "foo-bar";
import "./directory/foo-bar";

View File

@ -0,0 +1,10 @@
System.register("actual", ["foo", "foo-bar", "./directory/foo-bar"], function ($__export) {
"use strict";
var __moduleName = "actual";
return {
setters: [null, null, null],
execute: function () {}
};
});

View File

@ -0,0 +1,3 @@
{
"modules": "register"
}

View File

@ -0,0 +1,12 @@
import "foo";
import "foo-bar";
import "./directory/foo-bar";
import foo from "foo";
import * as foo from "foo";
import {bar} from "foo";
import {foo as bar} from "foo";
export {test};
export var test = 5;
export default test;

View File

@ -0,0 +1,24 @@
System.register("actual", ["foo", "foo-bar", "./directory/foo-bar"], function ($__export) {
"use strict";
var __moduleName = "actual";
var foo, bar;
var test = 5;
return {
setters: [function (m) {
foo = m.default;
foo = m;
bar = m.bar;
bar = m.foo;
}, null, null],
execute: function () {
$__export("test", test);
$__export("test", test);
$__export("default", test);
}
};
});