motion
Version:
motion - moving development forward
162 lines (130 loc) • 4.01 kB
JavaScript
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var path = require("path");
var fs = require("fs");
var through = require("through");
var transform = require("./lib/visit").transform;
var utils = require("./lib/util");
var recast = require("recast");
var types = recast.types;
var genOrAsyncFunExp = /\bfunction\s*\*|\basync\b/;
var blockBindingExp = /\b(let|const)\s+/;
function exports(file, options) {
var data = [];
return through(write, end);
function write(buf) {
data.push(buf);
}
function end() {
this.queue(compile(data.join(""), options).code);
this.queue(null);
}
}
// To get a writable stream for use as a browserify transform, call
// require("regenerator")().
module.exports = exports;
// To include the runtime globally in the current node process, call
// require("regenerator").runtime().
function runtime() {
require("./runtime");
}
exports.runtime = runtime;
runtime.path = path.join(__dirname, "runtime.js");
function compile(source, options) {
options = normalizeOptions(options);
if (!genOrAsyncFunExp.test(source)) {
return {
// Shortcut: no generators or async functions to transform.
code: (options.includeRuntime === true ? fs.readFileSync(
path.join(__dirname, "runtime.js"), "utf-8"
) + "\n" : "") + source
};
}
var recastOptions = getRecastOptions(options);
var ast = recast.parse(source, recastOptions);
var nodePath = new types.NodePath(ast);
var programPath = nodePath.get("program");
if (shouldVarify(source, options)) {
// Transpile let/const into var declarations.
varifyAst(programPath.node);
}
transform(programPath, options);
return recast.print(nodePath, recastOptions);
}
function normalizeOptions(options) {
options = utils.defaults(options || {}, {
includeRuntime: false,
supportBlockBinding: true
});
if (!options.esprima) {
options.esprima = require("esprima-fb");
}
assert.ok(
/harmony/.test(options.esprima.version),
"Bad esprima version: " + options.esprima.version
);
return options;
}
function getRecastOptions(options) {
var recastOptions = {
range: true
};
function copy(name) {
if (name in options) {
recastOptions[name] = options[name];
}
}
copy("esprima");
copy("sourceFileName");
copy("sourceMapName");
copy("inputSourceMap");
copy("sourceRoot");
return recastOptions;
}
function shouldVarify(source, options) {
var supportBlockBinding = !!options.supportBlockBinding;
if (supportBlockBinding) {
if (!blockBindingExp.test(source)) {
supportBlockBinding = false;
}
}
return supportBlockBinding;
}
function varify(source, options) {
var recastOptions = getRecastOptions(normalizeOptions(options));
var ast = recast.parse(source, recastOptions);
varifyAst(ast.program);
return recast.print(ast, recastOptions).code;
}
function varifyAst(ast) {
types.namedTypes.Program.assert(ast);
var defsResult = require("defs")(ast, {
ast: true,
disallowUnknownReferences: false,
disallowDuplicated: false,
disallowVars: false,
loopClosures: "iife"
});
if (defsResult.errors) {
throw new Error(defsResult.errors.join("\n"))
}
return ast;
}
// Convenience for just translating let/const to var declarations.
exports.varify = varify;
// Allow packages that depend on Regenerator to use the same copy of
// ast-types, in case multiple versions are installed by NPM.
exports.types = types;
// Transforms a string of source code, returning the { code, map? } result
// from recast.print.
exports.compile = compile;
// To modify an AST directly, call require("regenerator").transform(ast).
exports.transform = transform;