start on babel module bundling and type inferrence

This commit is contained in:
Sebastian McKenzie 2015-05-01 02:59:59 +01:00
parent 5080534974
commit aaf4cbf06f
12 changed files with 213 additions and 98 deletions

View File

@ -28,6 +28,7 @@
},
"dependencies": {
"ast-types": "~0.7.0",
"bluebird": "^2.9.25",
"chalk": "^1.0.0",
"convert-source-map": "^1.1.0",
"core-js": "^0.9.0",
@ -49,6 +50,7 @@
"regenerator": "^0.8.20",
"regexpu": "^1.1.2",
"repeating": "^1.1.2",
"resolve": "^1.1.6",
"shebang-regex": "^1.0.0",
"slash": "^1.0.0",
"source-map": "^0.4.0",

View File

@ -9,6 +9,7 @@ export { canCompile } from "../util";
export { default as options } from "../transformation/file/options";
export { default as Transformer } from "../transformation/transformer";
export { default as Pipeline } from "../transformation/transformer-pipeline";
export { default as traverse } from "../traversal";
export { default as buildExternalHelpers } from "../tools/build-external-helpers";
export { version } from "../../../package";

View File

@ -0,0 +1,15 @@
export default class Bundler {
constructor(opts) {
this.resolvers = [];
this.cache = {};
this.opts = opts;
}
addResolver(resolver) {
this.resolvers.push(resolver);
}
transform() {
}
}

View File

@ -0,0 +1,25 @@
import { Promise } from "bluebird";
import resolve from "resolve";
import path from "path";
import fs from "fs";
export default function (request, parent) {
return new Promise(function (resolve, reject) {
resolve(request, { basedir: path.dirname(parent) }, function (err, res) {
if (err) {
resolve(null);
} else {
fs.readFile(res, "utf8", function (err) {
if (err) {
reject(err);
} else {
resolve({
filename: filename,
content: content
});
}
});
}
});
});
}

View File

@ -1,5 +1,6 @@
import convertSourceMap from "convert-source-map";
import * as optionParsers from "./option-parsers";
import moduleFormatters from "../modules";
import PluginManager from "./plugin-manager";
import shebangRegex from "shebang-regex";
import TraversalPath from "../../traversal/path";
@ -38,7 +39,7 @@ function checkPath(stack, path) {
}
export default class File {
constructor(opts = {}) {
constructor(opts = {}, pipeline) {
this.dynamicImportTypes = {};
this.dynamicImportIds = {};
this.dynamicImports = [];
@ -49,9 +50,10 @@ export default class File {
this.data = {};
this.uids = {};
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.ast = {};
this.pipeline = pipeline;
this.log = new Logger(this, opts.filename || "unknown");
this.opts = this.normalizeOptions(opts);
this.ast = {};
this.buildTransformers();
}
@ -133,7 +135,7 @@ export default class File {
}
var optionParser = optionParsers[option.type];
if (optionParser) val = optionParser(key, val);
if (optionParser) val = optionParser(key, val, this.pipeline);
if (option.alias) {
opts[option.alias] = opts[option.alias] || val;
@ -200,7 +202,7 @@ export default class File {
var stack = [];
// build internal transformers
each(transform.transformers, function (transformer, key) {
each(this.pipeline.transformers, function (transformer, key) {
var pass = transformers[key] = transformer.buildPass(file);
if (pass.canTransform()) {
@ -235,7 +237,7 @@ export default class File {
}
getModuleFormatter(type: string) {
var ModuleFormatter = isFunction(type) ? type : transform.moduleFormatters[type];
var ModuleFormatter = isFunction(type) ? type : moduleFormatters[type];
if (!ModuleFormatter) {
var loc = util.resolveRelative(type);

View File

@ -1,14 +1,13 @@
import transform from "./../index";
import * as util from "../../util";
export function transformerList(key, val) {
export function transformerList(key, val, pipeline) {
val = util.arrayify(val);
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
val = Object.keys(transform.transformers);
val = Object.keys(pipeline.transformers);
}
return transform._ensureTransformerNames(key, val);
return pipeline._ensureTransformerNames(key, val);
}
export function number(key, val) {

View File

@ -1,68 +1,34 @@
import normalizeAst from "../helpers/normalize-ast";
import Transformer from "./transformer";
import object from "../helpers/object";
import File from "./file";
import each from "lodash/collection/each";
import Pipeline from "./transformer-pipeline";
export default function transform(code: string, opts?: Object) {
var file = new File(opts);
return file.parse(code);
}
var pipeline = new Pipeline;
transform.fromAst = function (ast, code, opts) {
ast = normalizeAst(ast);
//
var file = new File(opts);
file.addCode(code);
file.transform(ast);
return file.generate();
};
import transformers from "./transformers";
pipeline.addTransformers(transformers);
transform._ensureTransformerNames = function (type: string, rawKeys: Array<string>) {
var keys = [];
//
for (var i = 0; i < rawKeys.length; i++) {
var key = rawKeys[i];
import deprecated from "./transformers/deprecated";
pipeline.addDeprecated(deprecated);
var deprecatedKey = transform.deprecatedTransformerMap[key];
var aliasKey = transform.aliasTransformerMap[key];
if (aliasKey) {
keys.push(aliasKey);
} else if (deprecatedKey) {
// deprecated key, remap it to the new one
console.error(`The transformer ${key} has been renamed to ${deprecatedKey}`);
rawKeys.push(deprecatedKey);
} else if (transform.transformers[key]) {
// valid key
keys.push(key);
} else if (transform.namespaces[key]) {
// namespace, append all transformers within this namespace
keys = keys.concat(transform.namespaces[key]);
} else {
// invalid key
throw new ReferenceError(`Unknown transformer ${key} specified in ${type}`);
}
}
//
return keys;
};
import aliases from "./transformers/aliases";
pipeline.addDeprecated(aliases);
transform.transformerNamespaces = object();
transform.transformers = object();
transform.namespaces = object();
//
transform.deprecatedTransformerMap = require("./transformers/deprecated");
transform.aliasTransformerMap = require("./transformers/aliases");
transform.moduleFormatters = require("./modules");
import * as filters from "./transformers/filters";
pipeline.addFilter(filters.internal);
pipeline.addFilter(filters.blacklist);
pipeline.addFilter(filters.whitelist);
pipeline.addFilter(filters.stage);
pipeline.addFilter(filters.optional);
import rawTransformers from "./transformers";
//
each(rawTransformers, function (transformer, key) {
var namespace = key.split(".")[0];
transform.namespaces[namespace] = transform.namespaces[namespace] || [];
transform.namespaces[namespace].push(key);
transform.transformerNamespaces[key] = namespace;
transform.transformers[key] = new Transformer(key, transformer);
});
var transform = pipeline.transform.bind(pipeline);
transform.fromAst = pipeline.transformFromAst.bind(pipeline);
transform.pipeline = pipeline;
export default transform;

View File

@ -17,30 +17,7 @@ export default class TransformerPass {
}
canTransform(): boolean {
var transformer = this.transformer;
var opts = this.file.opts;
var key = transformer.key;
// internal
if (key[0] === "_") return true;
// blacklist
var blacklist = opts.blacklist;
if (blacklist.length && includes(blacklist, key)) return false;
// whitelist
var whitelist = opts.whitelist;
if (whitelist) return includes(whitelist, key);
// stage
var stage = transformer.metadata.stage;
if (stage != null && stage >= opts.stage) return true;
// optional
if (transformer.metadata.optional && !includes(opts.optional, key)) return false;
return true;
return this.file.pipeline.canTransform(this.transformer, this.file.opts);
}
checkPath(path: TraversalPath): boolean {

View File

@ -0,0 +1,105 @@
import Transformer from "./transformer";
import normalizeAst from "../helpers/normalize-ast";
import Bundler from "./bundler";
import assign from "lodash/object/assign";
import object from "../helpers/object";
import File from "./file";
export default class TransformerPipeline {
constructor() {
this.transformers = object();
this.namespaces = object();
this.deprecated = object();
this.aliases = object();
this.filters = [];
}
addTransformers(transformers) {
for (var key in transformers) {
this.addTransformer(key, transformers[key]);
}
return this;
}
addTransformer(key, transformer) {
if (this.transformers[key]) throw new Error(); // todo: error
var namespace = key.split(".")[0];
this.namespaces[namespace] = this.namespaces[namespace] || [];
this.namespaces[namespace].push(key);
this.namespaces[key] = namespace;
this.transformers[key] = new Transformer(key, transformer);
}
addAliases(names) {
assign(this.aliases, names);
return this;
}
addDeprecated(names) {
assign(this.deprecated, names);
return this;
}
addFilter(filter: Function) {
this.filters.push(filter);
return this;
}
canTransform(transformer, fileOpts) {
for (var filter of (this.filters: Array)) {
var result = filter(transformer, fileOpts);
if (result != null) return result;
}
return true;
}
transform(code: string, opts?: Object) {
var file = new File(opts, this);
return file.parse(code);
}
transformFromAst(ast, code, opts) {
ast = normalizeAst(ast);
var file = new File(opts, this);
file.addCode(code);
file.transform(ast);
return file.generate();
}
createBundler() {
return new Bundler(this);
}
_ensureTransformerNames(type: string, rawKeys: Array<string>) {
var keys = [];
for (var i = 0; i < rawKeys.length; i++) {
var key = rawKeys[i];
var deprecatedKey = this.deprecated[key];
var aliasKey = this.aliases[key];
if (aliasKey) {
keys.push(aliasKey);
} else if (deprecatedKey) {
// deprecated key, remap it to the new one
console.error(`The transformer ${key} has been renamed to ${deprecatedKey}`);
rawKeys.push(deprecatedKey);
} else if (this.transformers[key]) {
// valid key
keys.push(key);
} else if (this.namespaces[key]) {
// namespace, append all transformers within this namespace
keys = keys.concat(this.namespaces[key]);
} else {
// invalid key
throw new ReferenceError(`Unknown transformer ${key} specified in ${type}`);
}
}
return keys;
}
}

View File

@ -15,7 +15,7 @@ import each from "lodash/collection/each";
*/
export default class Transformer {
constructor(transformerKey: string, transformer: Object, opts: Object) {
constructor(transformerKey: string, transformer: Object) {
transformer = assign({}, transformer);
var take = function (key) {
@ -40,7 +40,6 @@ export default class Transformer {
//
this.handlers = this.normalize(transformer);
this.opts = this.opts || {};
this.key = transformerKey;
//

View File

@ -0,0 +1,24 @@
import includes from "lodash/collection/includes";
export function internal(transformer, opts) {
if (transformer.key[0] === "_") return true;
}
export function blacklist(transformer, opts) {
var blacklist = opts.blacklist;
if (blacklist.length && includes(blacklist, transformer.key)) return false;
}
export function whitelist(transformer, opts) {
var whitelist = opts.whitelist;
if (whitelist) return includes(whitelist, transformer.key);
}
export function stage(transformer, opts) {
var stage = transformer.metadata.stage;
if (stage != null && stage >= opts.stage) return true;
}
export function optional(transformer, opts) {
if (transformer.metadata.optional && !includes(opts.optional, transformer.key)) return false;
}

View File

@ -19,7 +19,7 @@ suite("api", function () {
});
test("addHelper unknown", function () {
var file = new File;
var file = new File({}, transform.pipeline);
assert.throws(function () {
file.addHelper("foob");
}, /Unknown helper foob/);
@ -40,11 +40,11 @@ suite("api", function () {
});
test("extra options", function () {
var file1 = new File({ extra: { foo: "bar" } });
var file1 = new File({ extra: { foo: "bar" } }, transform.pipeline);
assert.equal(file1.opts.extra.foo, "bar");
var file2 = new File;
var file3 = new File;
var file2 = new File({}, transform.pipeline);
var file3 = new File({}, transform.pipeline);
assert.ok(file2.opts.extra !== file3.opts.extra);
});