add module metadata - closes #1601

This commit is contained in:
Sebastian McKenzie
2015-06-07 19:41:20 +01:00
parent 3d3cb4be4f
commit e804741632
3 changed files with 235 additions and 20 deletions

View File

@@ -36,9 +36,18 @@ export default class File {
this.declarations = {};
this.usedHelpers = {};
this.dynamicData = {};
this.metadata = {};
this.data = {};
this.metadata = {
modules: {
imports: [],
exports: {
exported: [],
specifiers: []
}
}
};
this.pipeline = pipeline;
this.log = new Logger(this, opts.filename || "unknown");
this.ast = {};
@@ -493,15 +502,9 @@ export default class File {
if (modFormatter.init && this.transformers["es6.modules"].canTransform()) {
modFormatter.init();
}
this.populateModuleMetadata();
this.log.debug("End module formatter init");
}
populateModuleMetadata() {
var modules = {};
this.metadata.modules = modules;
}
transform() {
this.call("pre");
for (var pass of (this.transformerStack: Array)) {

View File

@@ -77,31 +77,134 @@ var metadataVisitor = {
ImportDeclaration(node, parent, scope, formatter) {
formatter.hasLocalImports = true;
extend(formatter.localImports, this.getBindingIdentifiers());
var specifiers = [];
var imported = [];
formatter.metadata.imports.push({
source: node.source.value,
imported,
specifiers
});
for (var specifier of (this.get("specifiers"): Array)) {
var ids = specifier.getBindingIdentifiers();
extend(formatter.localImports, ids);
var local = specifier.node.local.name;
if (specifier.isImportDefaultSpecifier()) {
imported.push("default");
specifiers.push({
kind: "named",
imported: "default",
local
});
}
if (specifier.isImportSpecifier()) {
var importedName = specifier.node.imported.name;
imported.push(importedName);
specifiers.push({
kind: "named",
imported: importedName,
local
});
}
if (specifier.isImportNamespaceSpecifier()) {
imported.push("*");
specifiers.push({
kind: "namespace",
local
});
}
}
},
ExportDeclaration(node, parent, scope, formatter) {
formatter.hasLocalExports = true;
var source = node.source ? node.source.value : null;
var exports = formatter.metadata.exports;
// export function foo() {}
// export var foo = "bar";
var declar = this.get("declaration");
if (declar.isStatement()) {
var bindings = declar.getBindingIdentifiers();
for (var name in bindings) {
var binding = bindings[name];
formatter._addExport(name, binding);
exports.exported.push(name);
exports.specifiers.push({
kind: "local",
local: name,
exported: this.isExportDefaultDeclaration() ? "default" : name
});
}
}
if (this.isExportNamedDeclaration() && node.specifiers) {
for (var i = 0; i < node.specifiers.length; i++) {
var specifier = node.specifiers[i];
for (var specifier of (node.specifiers: Array)) {
var exported = specifier.exported.name;
exports.exported.push(exported);
// export foo from "bar";
if (t.isExportDefaultSpecifier(specifier)) {
exports.specifiers.push({
kind: "external",
local: exported,
exported,
source
});
}
// export * as foo from "bar";
if (t.isExportNamespaceSpecifier(specifier)) {
exports.specifiers.push({
kind: "external-namespace",
exported,
source
});
}
var local = specifier.local;
if (!local) continue;
formatter._addExport(local.name, specifier.exported);
// export { foo } from "bar";
// export { foo as bar } from "bar";
if (source) {
exports.specifiers.push({
kind: "external",
local: local.name,
exported,
source
});
}
// export { foo };
// export { foo as bar };
if (!source) {
exports.specifiers.push({
kind: "local",
local: local.name,
exported
});
}
}
}
// export * from "bar";
if (this.isExportAllDeclaration()) {
exports.specifiers.push({
kind: "external-all",
source
});
}
if (!t.isExportDefaultDeclaration(node)) {
var onlyDefault = node.specifiers && node.specifiers.length === 1 && t.isSpecifierDefault(node.specifiers[0]);
if (!onlyDefault) {
@@ -131,6 +234,7 @@ export default class DefaultFormatter {
this.localExports = object();
this.localImports = object();
this.metadata = file.metadata.modules;
this.getMetadata();
}

View File

@@ -8,17 +8,17 @@ var assert = require("assert");
var File = require("../../lib/babel/transformation/file");
suite("api", function () {
test("{ code: false }", function () {
test("code option false", function () {
var result = transform("foo('bar');", { code: false });
assert.ok(!result.code);
});
test("{ ast: false }", function () {
test("ast option false", function () {
var result = transform("foo('bar');", { ast: false });
assert.ok(!result.ast);
});
test("{ auxiliaryComment }", function () {
test("auxiliaryComment option", function () {
assert.ok(transform("class Foo {}", {
auxiliaryComment: "foobar"
}).code.indexOf("foobar") >= 0);
@@ -28,7 +28,115 @@ suite("api", function () {
}).code.indexOf("foobar") >= 0);
});
test("ignore", function () {
test("modules metadata", function () {
assert.deepEqual(transform('import { externalName as localName } from "external";').metadata.modules.imports[0], {
source: "external",
imported: ["externalName"],
specifiers: [{
kind: "named",
imported: "externalName",
local: "localName"
}]
});
assert.deepEqual(transform('import * as localName2 from "external";').metadata.modules.imports[0], {
source: "external",
imported: ["*"],
specifiers: [{
kind: "namespace",
local: "localName2"
}]
});
assert.deepEqual(transform('import localName3 from "external";').metadata.modules.imports[0], {
source: 'external',
imported: ['default'],
specifiers: [{
kind: 'named',
imported: 'default',
local: 'localName3'
}]
});
assert.deepEqual(transform('export * as externalName1 from "external";', {
stage: 0
}).metadata.modules.exports, {
exported: ['externalName1'],
specifiers: [{
kind: 'external-namespace',
exported: 'externalName1',
source: "external",
}]
});
assert.deepEqual(transform('export externalName2 from "external";', {
stage: 0
}).metadata.modules.exports, {
exported: ["externalName2"],
specifiers: [{
kind: "external",
local: "externalName2",
exported: "externalName2",
source: "external"
}]
});
assert.deepEqual(transform('export function namedFunction() {}').metadata.modules.exports, {
exported: ["namedFunction"],
specifiers: [{
kind: "local",
local: "namedFunction",
exported: "namedFunction"
}]
});
assert.deepEqual(transform('export var foo = "bar";').metadata.modules.exports, {
"exported": ["foo"],
specifiers: [{
kind: "local",
local: "foo",
exported: "foo"
}]
});
assert.deepEqual(transform("export { localName as externalName3 };").metadata.modules.exports, {
exported: ["externalName3"],
specifiers: [{
kind: "local",
local: "localName",
exported: "externalName3"
}]
});
assert.deepEqual(transform('export { externalName4 } from "external";').metadata.modules.exports, {
exported: ["externalName4"],
specifiers: [{
kind: "external",
local: "externalName4",
exported: "externalName4",
source: "external"
}]
});
assert.deepEqual(transform('export * from "external";').metadata.modules.exports, {
exported: [],
specifiers: [{
kind: "external-all",
source: "external"
}]
});
assert.deepEqual(transform("export default function defaultFunction() {}").metadata.modules.exports, {
exported: ["defaultFunction"],
specifiers: [{
kind: "local",
local: "defaultFunction",
exported: "default"
}]
});
});
test("ignore option", function () {
assert.ok(transform("", {
ignore: "node_modules",
filename: "/foo/node_modules/bar"
@@ -45,7 +153,7 @@ suite("api", function () {
}).ignored);
});
test("only", function () {
test("only option", function () {
assert.ok(!transform("", {
only: "node_modules",
filename: "/foo/node_modules/bar"
@@ -77,7 +185,7 @@ suite("api", function () {
}).ignored);
});
suite("getModuleId() {} option", function () {
suite("getModuleId option", function () {
// As of this commit, `getModuleId` is the only option that isn't JSON
// compatible which is why it's not inside /test/core/fixtures/transformation
@@ -94,7 +202,7 @@ suite("api", function () {
assert.equal(result.code, expected);
}
test("{ modules: \"amd\" }", function () {
test("amd", function () {
var expected = [
"define('foo/bar', ['exports'], function (exports) {",
" 'use strict';",
@@ -106,7 +214,7 @@ suite("api", function () {
getModuleNameTest("amd", expected);
});
test("{ modules: \"umd\" }", function () {
test("umd", function () {
var expected = [
"(function (global, factory) {",
" if (typeof define === 'function' && define.amd) {",
@@ -130,7 +238,7 @@ suite("api", function () {
getModuleNameTest("umd", expected);
});
test("{ modules: \"system\" }", function () {
test("system", function () {
var expected = [
"System.register('foo/bar', [], function (_export) {",
" 'use strict';",
@@ -196,7 +304,7 @@ suite("api", function () {
}, /Unknown helper foob/);
});
test("resolveModuleSource", function () {
test("resolveModuleSource option", function () {
var actual = 'import foo from "foo-import-default";\nimport "foo-import-bare";\nexport { foo } from "foo-export-named";';
var expected = 'import foo from "resolved/foo-import-default";\nimport "resolved/foo-import-bare";\nexport { foo } from "resolved/foo-export-named";';