2015-03-23 18:48:02 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
2015-02-20 04:10:52 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var fs = require('fs');
|
2015-04-01 03:23:33 +00:00
|
|
|
var Promise = require('bluebird');
|
2015-02-20 04:10:52 +00:00
|
|
|
var Cache = require('./Cache');
|
|
|
|
var workerFarm = require('worker-farm');
|
2015-02-24 22:22:13 +00:00
|
|
|
var declareOpts = require('../lib/declareOpts');
|
2015-02-26 04:29:14 +00:00
|
|
|
var util = require('util');
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-04-01 03:23:33 +00:00
|
|
|
var readFile = Promise.promisify(fs.readFile);
|
2015-02-20 04:10:52 +00:00
|
|
|
|
|
|
|
module.exports = Transformer;
|
|
|
|
Transformer.TransformError = TransformError;
|
|
|
|
|
2015-02-24 22:22:13 +00:00
|
|
|
var validateOpts = declareOpts({
|
|
|
|
projectRoots: {
|
|
|
|
type: 'array',
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
blacklistRE: {
|
|
|
|
type: 'object', // typeof regex is object
|
|
|
|
},
|
|
|
|
polyfillModuleNames: {
|
|
|
|
type: 'array',
|
|
|
|
default: [],
|
|
|
|
},
|
|
|
|
cacheVersion: {
|
|
|
|
type: 'string',
|
|
|
|
default: '1.0',
|
|
|
|
},
|
|
|
|
resetCache: {
|
|
|
|
type: 'boolean',
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
transformModulePath: {
|
|
|
|
type:'string',
|
2015-02-27 18:23:54 +00:00
|
|
|
required: false,
|
2015-02-24 22:22:13 +00:00
|
|
|
},
|
|
|
|
nonPersistent: {
|
|
|
|
type: 'boolean',
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
});
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-02-24 22:22:13 +00:00
|
|
|
function Transformer(options) {
|
|
|
|
var opts = validateOpts(options);
|
|
|
|
|
|
|
|
this._cache = opts.nonPersistent
|
|
|
|
? new DummyCache()
|
|
|
|
: new Cache({
|
|
|
|
resetCache: options.resetCache,
|
|
|
|
cacheVersion: options.cacheVersion,
|
|
|
|
projectRoots: options.projectRoots,
|
|
|
|
});
|
|
|
|
|
2015-04-03 22:46:59 +00:00
|
|
|
if (options.transformModulePath != null) {
|
2015-02-20 04:10:52 +00:00
|
|
|
this._workers = workerFarm(
|
2015-03-19 19:05:48 +00:00
|
|
|
{autoStart: true, maxConcurrentCallsPerWorker: 1},
|
2015-02-24 22:22:13 +00:00
|
|
|
options.transformModulePath
|
2015-02-20 04:10:52 +00:00
|
|
|
);
|
2015-04-01 03:23:33 +00:00
|
|
|
|
|
|
|
this._transform = Promise.promisify(this._workers);
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Transformer.prototype.kill = function() {
|
|
|
|
this._workers && workerFarm.end(this._workers);
|
|
|
|
return this._cache.end();
|
|
|
|
};
|
|
|
|
|
|
|
|
Transformer.prototype.invalidateFile = function(filePath) {
|
|
|
|
this._cache.invalidate(filePath);
|
2015-02-26 04:29:14 +00:00
|
|
|
};
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-03-01 01:13:18 +00:00
|
|
|
Transformer.prototype.loadFileAndTransform = function(filePath) {
|
2015-04-03 22:46:59 +00:00
|
|
|
if (this._transform == null) {
|
|
|
|
return Promise.reject(new Error('No transfrom module'));
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
|
|
|
|
2015-04-01 03:23:33 +00:00
|
|
|
var transform = this._transform;
|
2015-02-20 04:10:52 +00:00
|
|
|
return this._cache.get(filePath, function() {
|
|
|
|
return readFile(filePath)
|
|
|
|
.then(function(buffer) {
|
|
|
|
var sourceCode = buffer.toString();
|
2015-03-01 01:13:18 +00:00
|
|
|
|
2015-04-01 03:23:33 +00:00
|
|
|
return transform({
|
2015-02-20 04:10:52 +00:00
|
|
|
sourceCode: sourceCode,
|
2015-03-01 01:13:18 +00:00
|
|
|
filename: filePath,
|
2015-02-20 04:10:52 +00:00
|
|
|
}).then(
|
|
|
|
function(res) {
|
|
|
|
if (res.error) {
|
2015-03-01 01:13:18 +00:00
|
|
|
throw formatError(res.error, filePath, sourceCode);
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
code: res.code,
|
|
|
|
sourcePath: filePath,
|
|
|
|
sourceCode: sourceCode
|
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
function TransformError() {}
|
2015-02-26 04:29:14 +00:00
|
|
|
util.inherits(TransformError, SyntaxError);
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-03-01 01:13:18 +00:00
|
|
|
function formatError(err, filename, source) {
|
|
|
|
if (err.lineNumber && err.column) {
|
|
|
|
return formatEsprimaError(err, filename, source);
|
|
|
|
} else {
|
|
|
|
return formatGenericError(err, filename, source);
|
2015-02-20 04:10:52 +00:00
|
|
|
}
|
2015-03-01 01:13:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function formatGenericError(err, filename) {
|
|
|
|
var msg = 'TransformError: ' + filename + ': ' + err.message;
|
|
|
|
var error = new TransformError();
|
2015-04-08 21:28:44 +00:00
|
|
|
var stack = (err.stack || '').split('\n').slice(0, -1);
|
2015-03-01 01:13:18 +00:00
|
|
|
stack.push(msg);
|
|
|
|
error.stack = stack.join('\n');
|
|
|
|
error.message = msg;
|
|
|
|
error.type = 'TransformError';
|
|
|
|
return error;
|
|
|
|
}
|
2015-02-20 04:10:52 +00:00
|
|
|
|
2015-03-01 01:13:18 +00:00
|
|
|
function formatEsprimaError(err, filename, source) {
|
2015-02-20 04:10:52 +00:00
|
|
|
var stack = err.stack.split('\n');
|
|
|
|
stack.shift();
|
|
|
|
|
|
|
|
var msg = 'TransformError: ' + err.description + ' ' + filename + ':' +
|
|
|
|
err.lineNumber + ':' + err.column;
|
|
|
|
var sourceLine = source.split('\n')[err.lineNumber - 1];
|
|
|
|
var snippet = sourceLine + '\n' + new Array(err.column - 1).join(' ') + '^';
|
|
|
|
|
|
|
|
stack.unshift(msg);
|
|
|
|
|
|
|
|
var error = new TransformError();
|
|
|
|
error.message = msg;
|
|
|
|
error.type = 'TransformError';
|
|
|
|
error.stack = stack.join('\n');
|
|
|
|
error.snippet = snippet;
|
|
|
|
error.filename = filename;
|
|
|
|
error.lineNumber = err.lineNumber;
|
|
|
|
error.column = err.column;
|
|
|
|
error.description = err.description;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
function DummyCache() {}
|
|
|
|
DummyCache.prototype.get = function(filePath, loaderCb) {
|
|
|
|
return loaderCb();
|
|
|
|
};
|
|
|
|
DummyCache.prototype.end =
|
|
|
|
DummyCache.prototype.invalidate = function(){};
|