Handle synchronous errors in `worker.transformCode`

Summary: `worker.transformCode` is a callback-taking function, but did not properly guard against errors thrown in its body.

Reviewed By: cpojer

Differential Revision: D5245253

fbshipit-source-id: 3fd08b68dd8605f664b316652ebd1f9497b2dac9
This commit is contained in:
David Aurelio 2017-06-14 05:00:57 -07:00 committed by Facebook Github Bot
parent fdc8f37a5b
commit e87a8205d8
2 changed files with 92 additions and 68 deletions

View File

@ -213,6 +213,24 @@ describe('code transformation worker:', () => {
}, },
); );
}); });
it('calls back with every error thrown by `extractDependencies`', done => {
const error = new Error('arbitrary');
extractDependencies.mockImplementation(() => {
throw error;
});
transformCode(
transformer,
'arbitrary.js',
'local/arbitrary.js',
'code',
{},
(e, data) => {
expect(e).toBe(error);
done();
},
);
});
}); });
describe('Minifications:', () => { describe('Minifications:', () => {

View File

@ -12,6 +12,7 @@
'use strict'; 'use strict';
const asyncify = require('async/asyncify');
const constantFolding = require('./constant-folding'); const constantFolding = require('./constant-folding');
const extractDependencies = require('./extract-dependencies'); const extractDependencies = require('./extract-dependencies');
const inline = require('./inline'); const inline = require('./inline');
@ -73,15 +74,23 @@ export type Data = {
}; };
type Callback<T> = (error: ?Error, data: ?T) => mixed; type Callback<T> = (error: ?Error, data: ?T) => mixed;
type TransformCode = (
Transformer<*>,
string,
LocalPath,
string,
Options,
Callback<Data>,
) => void;
function transformCode( const transformCode: TransformCode = asyncify(
(
transformer: Transformer<*>, transformer: Transformer<*>,
filename: string, filename: string,
localPath: LocalPath, localPath: LocalPath,
sourceCode: string, sourceCode: string,
options: Options, options: Options,
callback: Callback<Data>, ): Data => {
) {
invariant( invariant(
!options.minify || options.transform.generateSourceMaps, !options.minify || options.transform.generateSourceMaps,
'Minifying source code requires the `generateSourceMaps` option to be `true`', 'Minifying source code requires the `generateSourceMaps` option to be `true`',
@ -100,18 +109,12 @@ function transformCode(
start_timestamp: process.hrtime(), start_timestamp: process.hrtime(),
}; };
let transformed; const transformed = transformer.transform({
try {
transformed = transformer.transform({
filename, filename,
localPath, localPath,
options: options.transform, options: options.transform,
src: sourceCode, src: sourceCode,
}); });
} catch (error) {
callback(error);
return;
}
invariant( invariant(
transformed != null, transformed != null,
@ -140,7 +143,9 @@ function transformCode(
? {dependencies: [], dependencyOffsets: []} ? {dependencies: [], dependencyOffsets: []}
: extractDependencies(code); : extractDependencies(code);
const timeDelta = process.hrtime(transformFileStartLogEntry.start_timestamp); const timeDelta = process.hrtime(
transformFileStartLogEntry.start_timestamp,
);
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6); const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
const transformFileEndLogEntry = { const transformFileEndLogEntry = {
action_name: 'Transforming file', action_name: 'Transforming file',
@ -150,12 +155,13 @@ function transformCode(
log_entry_label: 'Transforming file', log_entry_label: 'Transforming file',
}; };
callback(null, { return {
result: {...depsResult, code, map}, result: {...depsResult, code, map},
transformFileStartLogEntry, transformFileStartLogEntry,
transformFileEndLogEntry, transformFileEndLogEntry,
}); };
} },
);
exports.transformAndExtractDependencies = ( exports.transformAndExtractDependencies = (
transform: string, transform: string,