Switch to pirates for babel-register. (#3670)
* Switch to pirates for babel-register. Pirates is a simple module that enables easy require hooking. It makes sure that your require hook works properly. It also makes the implimentation of babel-register a lot simpler. For more on pirates: http://ariporad.link/piratesjs * Use modified version of pirates. * Switch back to stable version * Initial tests for babel-register * Fix tests to work in new test env * Fix for new ignore behaviour * Update pirates to 3.0.1
This commit is contained in:
parent
8434f89bc0
commit
fce92fa1ad
@ -13,9 +13,11 @@
|
||||
"home-or-tmp": "^3.0.0",
|
||||
"lodash": "^4.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"pirates": "^3.0.1",
|
||||
"source-map-support": "^0.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"decache": "^4.1.0"
|
||||
"decache": "^4.1.0",
|
||||
"default-require-extensions": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,16 @@ import deepClone from "lodash/cloneDeep";
|
||||
import sourceMapSupport from "source-map-support";
|
||||
import * as registerCache from "./cache";
|
||||
import escapeRegExp from "lodash/escapeRegExp";
|
||||
import extend from "lodash/extend";
|
||||
import * as babel from "babel-core";
|
||||
import { OptionManager, DEFAULT_EXTENSIONS } from "babel-core";
|
||||
import { addHook } from "pirates";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const maps = {};
|
||||
const transformOpts = {};
|
||||
let piratesRevert = null;
|
||||
|
||||
sourceMapSupport.install({
|
||||
handleUncaughtExceptions: false,
|
||||
environment: "node",
|
||||
@ -27,27 +31,20 @@ sourceMapSupport.install({
|
||||
registerCache.load();
|
||||
let cache = registerCache.get();
|
||||
|
||||
const transformOpts = {};
|
||||
|
||||
let oldHandlers = {};
|
||||
const maps = {};
|
||||
|
||||
function mtime(filename) {
|
||||
return +fs.statSync(filename).mtime;
|
||||
}
|
||||
|
||||
function compile(filename) {
|
||||
let result;
|
||||
|
||||
function compile(code, filename) {
|
||||
// merge in base options and resolve all the plugins and presets relative to this file
|
||||
const opts = new OptionManager().init(extend(
|
||||
const opts = new OptionManager().init(Object.assign(
|
||||
{ sourceRoot: path.dirname(filename) }, // sourceRoot can be overwritten
|
||||
deepClone(transformOpts),
|
||||
{ filename }
|
||||
));
|
||||
|
||||
// Bail out ASAP if the file has been ignored.
|
||||
if (opts === null) return null;
|
||||
if (opts === null) return code;
|
||||
|
||||
let cacheKey = `${JSON.stringify(opts)}:${babel.version}`;
|
||||
|
||||
@ -58,19 +55,17 @@ function compile(filename) {
|
||||
if (cache) {
|
||||
const cached = cache[cacheKey];
|
||||
if (cached && cached.mtime === mtime(filename)) {
|
||||
result = cached;
|
||||
return cached.code;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = babel.transformFileSync(filename, extend(opts, {
|
||||
// Do not process config files since has already been done with the OptionManager
|
||||
// calls above and would introduce duplicates.
|
||||
babelrc: false,
|
||||
sourceMaps: "both",
|
||||
ast: false,
|
||||
}));
|
||||
}
|
||||
const result = babel.transform(code, Object.assign(opts, {
|
||||
// Do not process config files since has already been done with the OptionManager
|
||||
// calls above and would introduce duplicates.
|
||||
babelrc: false,
|
||||
sourceMaps: "both",
|
||||
ast: false,
|
||||
}));
|
||||
|
||||
if (cache) {
|
||||
cache[cacheKey] = result;
|
||||
@ -82,33 +77,14 @@ function compile(filename) {
|
||||
return result.code;
|
||||
}
|
||||
|
||||
function registerExtension(ext) {
|
||||
const old = oldHandlers[ext] || oldHandlers[".js"] || require.extensions[".js"];
|
||||
|
||||
require.extensions[ext] = function (m, filename) {
|
||||
const result = compile(filename);
|
||||
|
||||
if (result === null) old(m, filename);
|
||||
else m._compile(result, filename);
|
||||
};
|
||||
function hookExtensions(exts) {
|
||||
if (piratesRevert) piratesRevert();
|
||||
piratesRevert = addHook(compile, { exts, ignoreNodeModules: false });
|
||||
}
|
||||
|
||||
function hookExtensions(_exts) {
|
||||
Object.keys(oldHandlers).forEach(function (ext) {
|
||||
const old = oldHandlers[ext];
|
||||
if (old === undefined) {
|
||||
delete require.extensions[ext];
|
||||
} else {
|
||||
require.extensions[ext] = old;
|
||||
}
|
||||
});
|
||||
|
||||
oldHandlers = {};
|
||||
|
||||
_exts.forEach(function (ext) {
|
||||
oldHandlers[ext] = require.extensions[ext];
|
||||
registerExtension(ext);
|
||||
});
|
||||
export function revert() {
|
||||
if (piratesRevert) piratesRevert();
|
||||
delete require.cache[require.resolve(__filename)];
|
||||
}
|
||||
|
||||
register({
|
||||
@ -123,7 +99,7 @@ export default function register(opts?: Object = {}) {
|
||||
delete opts.extensions;
|
||||
delete opts.cache;
|
||||
|
||||
extend(transformOpts, opts);
|
||||
Object.assign(transformOpts, opts);
|
||||
|
||||
if (!transformOpts.ignore && !transformOpts.only) {
|
||||
transformOpts.ignore = [
|
||||
|
||||
3
packages/babel-register/test/__data__/es2015.js
Normal file
3
packages/babel-register/test/__data__/es2015.js
Normal file
@ -0,0 +1,3 @@
|
||||
import a from "assert";
|
||||
|
||||
export default () => { a.foo(); return "b"; };
|
||||
84
packages/babel-register/test/cache.js
Normal file
84
packages/babel-register/test/cache.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { expect } from "chai";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import decache from "decache";
|
||||
|
||||
const testCacheFilename = path.join(__dirname, ".babel");
|
||||
const oldBabelDisableCacheValue = process.env.BABEL_DISABLE_CACHE;
|
||||
|
||||
process.env.BABEL_CACHE_PATH = testCacheFilename;
|
||||
delete process.env.BABEL_DISABLE_CACHE;
|
||||
|
||||
function writeCache(data) {
|
||||
if (typeof data === "object") {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
|
||||
fs.writeFileSync(testCacheFilename, data);
|
||||
}
|
||||
|
||||
function cleanCache() {
|
||||
|
||||
try {
|
||||
fs.unlinkSync(testCacheFilename);
|
||||
} catch (e) {
|
||||
// It is convenient to always try to clear
|
||||
}
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
process.env.BABEL_CACHE_PATH = null;
|
||||
process.env.BABEL_DISABLE_CACHE = oldBabelDisableCacheValue;
|
||||
}
|
||||
|
||||
describe("babel register", () => {
|
||||
|
||||
describe("cache", () => {
|
||||
let load, get, save;
|
||||
|
||||
beforeEach(() => {
|
||||
// Since lib/cache is a singleton we need to fully reload it
|
||||
decache("../lib/cache");
|
||||
const cache = require("../lib/cache");
|
||||
|
||||
load = cache.load;
|
||||
get = cache.get;
|
||||
save = cache.save;
|
||||
});
|
||||
|
||||
afterEach(cleanCache);
|
||||
after(resetCache);
|
||||
|
||||
it("should load and get cached data", () => {
|
||||
writeCache({ foo: "bar" });
|
||||
|
||||
load();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({ foo: "bar" });
|
||||
});
|
||||
|
||||
it("should load and get an object with no cached data", () => {
|
||||
load();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
|
||||
it("should load and get an object with invalid cached data", () => {
|
||||
writeCache("foobar");
|
||||
|
||||
load();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
|
||||
it("should create the cache on save", () => {
|
||||
save();
|
||||
|
||||
expect(fs.existsSync(testCacheFilename)).to.be.true;
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,84 +1,57 @@
|
||||
import { expect } from "chai";
|
||||
import fs from "fs";
|
||||
import chai from "chai";
|
||||
import path from "path";
|
||||
import decache from "decache";
|
||||
|
||||
const testCacheFilename = path.join(__dirname, ".babel");
|
||||
const oldBabelDisableCacheValue = process.env.BABEL_DISABLE_CACHE;
|
||||
const DATA_ES2015 = require.resolve("./__data__/es2015");
|
||||
|
||||
process.env.BABEL_CACHE_PATH = testCacheFilename;
|
||||
delete process.env.BABEL_DISABLE_CACHE;
|
||||
describe("babel-register", function () {
|
||||
let babelRegister;
|
||||
let oldCompiler;
|
||||
|
||||
function writeCache(data) {
|
||||
if (typeof data === "object") {
|
||||
data = JSON.stringify(data);
|
||||
function setupRegister(config = {}) {
|
||||
babelRegister = require("../lib/node");
|
||||
babelRegister.default(Object.assign({
|
||||
presets: [path.join(__dirname, "../../babel-preset-es2015")],
|
||||
babelrc: false,
|
||||
}, config));
|
||||
}
|
||||
|
||||
fs.writeFileSync(testCacheFilename, data);
|
||||
}
|
||||
|
||||
function cleanCache() {
|
||||
|
||||
try {
|
||||
fs.unlinkSync(testCacheFilename);
|
||||
} catch (e) {
|
||||
// It is convenient to always try to clear
|
||||
function revertRegister() {
|
||||
if (babelRegister) {
|
||||
babelRegister.revert();
|
||||
babelRegister = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
process.env.BABEL_CACHE_PATH = null;
|
||||
process.env.BABEL_DISABLE_CACHE = oldBabelDisableCacheValue;
|
||||
}
|
||||
before(() => {
|
||||
const js = require("default-require-extensions/js");
|
||||
oldCompiler = require.extensions[".js"];
|
||||
require.extensions[".js"] = js;
|
||||
});
|
||||
|
||||
describe("babel register", () => {
|
||||
after(() => {
|
||||
require.extensions[".js"] = oldCompiler;
|
||||
});
|
||||
|
||||
describe("cache", () => {
|
||||
let load, get, save;
|
||||
afterEach(() => {
|
||||
revertRegister();
|
||||
decache(DATA_ES2015);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Since lib/cache is a singleton we need to fully reload it
|
||||
decache("../lib/cache");
|
||||
const cache = require("../lib/cache");
|
||||
it("registers correctly", () => {
|
||||
setupRegister();
|
||||
|
||||
load = cache.load;
|
||||
get = cache.get;
|
||||
save = cache.save;
|
||||
});
|
||||
chai.expect(require(DATA_ES2015)).to.be.ok;
|
||||
});
|
||||
|
||||
afterEach(cleanCache);
|
||||
after(resetCache);
|
||||
it("reverts correctly", () => {
|
||||
setupRegister();
|
||||
|
||||
it("should load and get cached data", () => {
|
||||
writeCache({ foo: "bar" });
|
||||
chai.expect(require(DATA_ES2015)).to.be.ok;
|
||||
decache(DATA_ES2015);
|
||||
|
||||
load();
|
||||
revertRegister();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({ foo: "bar" });
|
||||
});
|
||||
|
||||
it("should load and get an object with no cached data", () => {
|
||||
load();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
|
||||
it("should load and get an object with invalid cached data", () => {
|
||||
writeCache("foobar");
|
||||
|
||||
load();
|
||||
|
||||
expect(get()).to.be.an("object");
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
|
||||
it("should create the cache on save", () => {
|
||||
save();
|
||||
|
||||
expect(fs.existsSync(testCacheFilename)).to.be.true;
|
||||
expect(get()).to.deep.equal({});
|
||||
});
|
||||
chai.expect(() => { require(DATA_ES2015); }).to.throw(SyntaxError);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user