Remove baseTransformer
Reviewed By: jeanlauliac Differential Revision: D4506124 fbshipit-source-id: 642f06dffe4ea710113e8e8426915bf1b40d4611
This commit is contained in:
parent
57990b7970
commit
a4d7a7835f
|
@ -14,35 +14,46 @@ jest.mock('../extract-dependencies');
|
|||
jest.mock('../inline');
|
||||
jest.mock('../minify');
|
||||
|
||||
const {any, objectContaining} = jasmine;
|
||||
const {objectContaining} = jasmine;
|
||||
|
||||
describe('code transformation worker:', () => {
|
||||
let transformCode;
|
||||
|
||||
let extractDependencies, transform;
|
||||
let extractDependencies, transformer;
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
({transformCode} = require('..'));
|
||||
extractDependencies =
|
||||
require('../extract-dependencies').mockReturnValue({});
|
||||
transform = jest.fn();
|
||||
transformer = {
|
||||
transform: jest.fn((src, filename, options) => ({
|
||||
code: src,
|
||||
map: {},
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
it('calls the transform with file name, source code, and transform options', function() {
|
||||
const filename = 'arbitrary/file.js';
|
||||
const sourceCode = 'arbitrary(code)';
|
||||
const transformOptions = {arbitrary: 'options'};
|
||||
transformCode(transform, filename, sourceCode, {transform: transformOptions});
|
||||
expect(transform).toBeCalledWith(
|
||||
{filename, sourceCode, options: transformOptions}, any(Function));
|
||||
transformCode(transformer, filename, sourceCode, {transform: transformOptions}, () => {});
|
||||
expect(transformer.transform).toBeCalledWith(
|
||||
sourceCode,
|
||||
filename,
|
||||
transformOptions,
|
||||
);
|
||||
});
|
||||
|
||||
it('prefixes JSON files with an assignment to module.exports to make the code valid', function() {
|
||||
const filename = 'arbitrary/file.json';
|
||||
const sourceCode = '{"arbitrary":"property"}';
|
||||
transformCode(transform, filename, sourceCode, {});
|
||||
expect(transform).toBeCalledWith(
|
||||
{filename, sourceCode: `module.exports=${sourceCode}`}, any(Function));
|
||||
transformCode(transformer, filename, sourceCode, {}, () => {});
|
||||
expect(transformer.transform).toBeCalledWith(
|
||||
`module.exports=${sourceCode}`,
|
||||
filename,
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('calls back with the result of the transform in the cache', done => {
|
||||
|
@ -50,10 +61,8 @@ describe('code transformation worker:', () => {
|
|||
code: 'some.other(code)',
|
||||
map: {}
|
||||
};
|
||||
transform.mockImplementation((_, callback) =>
|
||||
callback(null, result));
|
||||
|
||||
transformCode(transform, 'filename', 'code', {}, (error, data) => {
|
||||
transformCode(transformer, 'filename', result.code, {}, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
expect(data.result).toEqual(objectContaining(result));
|
||||
done();
|
||||
|
@ -64,14 +73,11 @@ describe('code transformation worker:', () => {
|
|||
'removes the leading assignment to `module.exports` before passing ' +
|
||||
'on the result if the file is a JSON file, even if minified',
|
||||
done => {
|
||||
const result = {
|
||||
code: 'p.exports={a:1,b:2}',
|
||||
};
|
||||
transform.mockImplementation((_, callback) => callback(null, result));
|
||||
const code = '{a:1,b:2}';
|
||||
const filePath = 'arbitrary/file.json';
|
||||
transformCode(transform, filePath, 'b', {}, (error, data) => {
|
||||
transformCode(transformer, filePath, code, {}, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
expect(data.result.code).toEqual('{a:1,b:2}');
|
||||
expect(data.result.code).toEqual(code);
|
||||
done();
|
||||
},
|
||||
);
|
||||
|
@ -83,9 +89,8 @@ describe('code transformation worker:', () => {
|
|||
const result = {
|
||||
code: `${shebang} \n arbitrary(code)`,
|
||||
};
|
||||
transform.mockImplementation((_, callback) => callback(null, result));
|
||||
const filePath = 'arbitrary/file.js';
|
||||
transformCode(transform, filePath, 'b', {}, (error, data) => {
|
||||
transformCode(transformer, filePath, result.code, {}, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
const {code} = data.result;
|
||||
expect(code).not.toContain(shebang);
|
||||
|
@ -95,26 +100,22 @@ describe('code transformation worker:', () => {
|
|||
});
|
||||
|
||||
it('calls back with any error yielded by the transform', done => {
|
||||
const error = Error('arbitrary error');
|
||||
transform.mockImplementation((_, callback) => callback(error));
|
||||
transformCode(transform, 'filename', 'code', {}, e => {
|
||||
expect(e).toBe(error);
|
||||
const message = 'SyntaxError: this code is broken.';
|
||||
transformer.transform.mockImplementation(() => {
|
||||
throw new Error(message);
|
||||
});
|
||||
|
||||
transformCode(transformer, 'filename', 'code', {}, error => {
|
||||
expect(error.message).toBe(message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('dependency extraction:', () => {
|
||||
let code;
|
||||
|
||||
beforeEach(() => {
|
||||
transform.mockImplementation(
|
||||
(_, callback) => callback(null, {code}));
|
||||
});
|
||||
|
||||
describe('dependency extraction', () => {
|
||||
it('passes the transformed code the `extractDependencies`', done => {
|
||||
code = 'arbitrary(code)';
|
||||
const code = 'arbitrary(code)';
|
||||
|
||||
transformCode(transform, 'filename', 'code', {}, (error) => {
|
||||
transformCode(transformer, 'filename', code, {}, (error) => {
|
||||
expect(error).toBeNull();
|
||||
expect(extractDependencies).toBeCalledWith(code);
|
||||
done();
|
||||
|
@ -131,7 +132,7 @@ describe('code transformation worker:', () => {
|
|||
};
|
||||
extractDependencies.mockReturnValue(dependencyData);
|
||||
|
||||
transformCode(transform, 'filename', 'code', {}, (error, data) => {
|
||||
transformCode(transformer, 'filename', 'code', {}, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
expect(data.result).toEqual(objectContaining(dependencyData));
|
||||
done();
|
||||
|
@ -141,7 +142,7 @@ describe('code transformation worker:', () => {
|
|||
|
||||
it('does not extract requires if files are marked as "extern"', done => {
|
||||
const opts = {extern: true};
|
||||
transformCode(transform, 'filename', 'code', opts, (error, data) => {
|
||||
transformCode(transformer, 'filename', 'code', opts, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
const {dependencies, dependencyOffsets} = data.result;
|
||||
expect(extractDependencies).not.toBeCalled();
|
||||
|
@ -153,7 +154,7 @@ describe('code transformation worker:', () => {
|
|||
|
||||
it('does not extract requires of JSON files', done => {
|
||||
const jsonStr = '{"arbitrary":"json"}';
|
||||
transformCode(transform, 'arbitrary.json', jsonStr, {}, (error, data) => {
|
||||
transformCode(transformer, 'arbitrary.json', jsonStr, {}, (error, data) => {
|
||||
expect(error).toBeNull();
|
||||
const {dependencies, dependencyOffsets} = data.result;
|
||||
expect(extractDependencies).not.toBeCalled();
|
||||
|
@ -187,13 +188,12 @@ describe('code transformation worker:', () => {
|
|||
extractDependencies.mockImplementation(
|
||||
code => code === foldedCode ? dependencyData : {});
|
||||
|
||||
transform.mockImplementation(
|
||||
(_, callback) => callback(null, transformResult));
|
||||
transformer.transform.mockImplementation((src, fileName, _) => transformResult);
|
||||
});
|
||||
|
||||
it('passes the transform result to `inline` for constant inlining', done => {
|
||||
transformResult = {map: {version: 3}, code: 'arbitrary(code)'};
|
||||
transformCode(transform, filename, 'code', options, () => {
|
||||
transformCode(transformer, filename, 'code', options, () => {
|
||||
expect(inline).toBeCalledWith(filename, transformResult, options);
|
||||
done();
|
||||
});
|
||||
|
@ -202,21 +202,21 @@ describe('code transformation worker:', () => {
|
|||
it('passes the result obtained from `inline` on to `constant-folding`', done => {
|
||||
const inlineResult = {map: {version: 3, sources: []}, ast: {}};
|
||||
inline.mockReturnValue(inlineResult);
|
||||
transformCode(transform, filename, 'code', options, () => {
|
||||
transformCode(transformer, filename, 'code', options, () => {
|
||||
expect(constantFolding).toBeCalledWith(filename, inlineResult);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Uses the code obtained from `constant-folding` to extract dependencies', done => {
|
||||
transformCode(transform, filename, 'code', options, () => {
|
||||
transformCode(transformer, filename, 'code', options, () => {
|
||||
expect(extractDependencies).toBeCalledWith(foldedCode);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('uses the dependencies obtained from the optimized result', done => {
|
||||
transformCode(transform, filename, 'code', options, (_, data) => {
|
||||
transformCode(transformer, filename, 'code', options, (_, data) => {
|
||||
const result = data.result;
|
||||
expect(result.dependencies).toEqual(dependencyData.dependencies);
|
||||
done();
|
||||
|
@ -224,7 +224,7 @@ describe('code transformation worker:', () => {
|
|||
});
|
||||
|
||||
it('uses data produced by `constant-folding` for the result', done => {
|
||||
transformCode(transform, 'filename', 'code', options, (_, data) => {
|
||||
transformCode(transformer, 'filename', 'code', options, (_, data) => {
|
||||
expect(data.result)
|
||||
.toEqual(objectContaining({code: foldedCode, map: foldedMap}));
|
||||
done();
|
||||
|
|
|
@ -20,20 +20,6 @@ const minify = require('./minify');
|
|||
import type {LogEntry} from '../../Logger/Types';
|
||||
import type {Ast, SourceMap, TransformOptions as BabelTransformOptions} from 'babel-core';
|
||||
|
||||
function makeTransformParams(filename, sourceCode, options, willMinify) {
|
||||
invariant(
|
||||
!willMinify || options.generateSourceMaps,
|
||||
'Minifying source code requires the `generateSourceMaps` option to be `true`',
|
||||
);
|
||||
|
||||
|
||||
if (filename.endsWith('.json')) {
|
||||
sourceCode = 'module.exports=' + sourceCode;
|
||||
}
|
||||
|
||||
return {filename, sourceCode, options};
|
||||
}
|
||||
|
||||
export type TransformedCode = {
|
||||
code: string,
|
||||
dependencies: Array<string>,
|
||||
|
@ -41,17 +27,13 @@ export type TransformedCode = {
|
|||
map?: ?SourceMap,
|
||||
};
|
||||
|
||||
type Transform = (
|
||||
params: {
|
||||
type Transformer = {
|
||||
transform: (
|
||||
filename: string,
|
||||
sourceCode: string,
|
||||
options: ?{},
|
||||
},
|
||||
callback: (
|
||||
error?: Error,
|
||||
tranformed?: {ast: ?Ast, code: string, map: ?SourceMap},
|
||||
) => mixed,
|
||||
) => void;
|
||||
) => {ast: ?Ast, code: string, map: ?SourceMap}
|
||||
};
|
||||
|
||||
export type TransformOptions = {
|
||||
generateSourceMaps: boolean,
|
||||
|
@ -80,19 +62,21 @@ type Callback = (
|
|||
) => mixed;
|
||||
|
||||
function transformCode(
|
||||
transform: Transform,
|
||||
transformer: Transformer,
|
||||
filename: string,
|
||||
sourceCode: string,
|
||||
options: Options,
|
||||
callback: Callback,
|
||||
) {
|
||||
const params = makeTransformParams(
|
||||
filename,
|
||||
sourceCode,
|
||||
options.transform,
|
||||
options.minify,
|
||||
invariant(
|
||||
!options.minify || options.transform.generateSourceMaps,
|
||||
'Minifying source code requires the `generateSourceMaps` option to be `true`',
|
||||
);
|
||||
|
||||
const isJson = filename.endsWith('.json');
|
||||
if (isJson) {
|
||||
sourceCode = 'module.exports=' + sourceCode;
|
||||
}
|
||||
|
||||
const transformFileStartLogEntry = {
|
||||
action_name: 'Transforming file',
|
||||
|
@ -102,52 +86,53 @@ function transformCode(
|
|||
start_timestamp: process.hrtime(),
|
||||
};
|
||||
|
||||
transform(params, (error, transformed) => {
|
||||
if (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
let transformed;
|
||||
try {
|
||||
transformed = transformer.transform(sourceCode, filename, options.transform);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
invariant(
|
||||
transformed != null,
|
||||
'Missing transform results despite having no error.',
|
||||
);
|
||||
invariant(
|
||||
transformed != null,
|
||||
'Missing transform results despite having no error.',
|
||||
);
|
||||
|
||||
var code, map;
|
||||
if (options.minify) {
|
||||
({code, map} =
|
||||
constantFolding(filename, inline(filename, transformed, options)));
|
||||
invariant(code != null, 'Missing code from constant-folding transform.');
|
||||
} else {
|
||||
({code, map} = transformed);
|
||||
}
|
||||
var code, map;
|
||||
if (options.minify) {
|
||||
({code, map} =
|
||||
constantFolding(filename, inline(filename, transformed, options)));
|
||||
invariant(code != null, 'Missing code from constant-folding transform.');
|
||||
} else {
|
||||
({code, map} = transformed);
|
||||
}
|
||||
|
||||
if (isJson) {
|
||||
code = code.replace(/^\w+\.exports=/, '');
|
||||
} else {
|
||||
// Remove shebang
|
||||
code = code.replace(/^#!.*/, '');
|
||||
}
|
||||
if (isJson) {
|
||||
code = code.replace(/^\w+\.exports=/, '');
|
||||
} else {
|
||||
// Remove shebang
|
||||
code = code.replace(/^#!.*/, '');
|
||||
}
|
||||
|
||||
const depsResult = isJson || options.extern
|
||||
? {dependencies: [], dependencyOffsets: []}
|
||||
: extractDependencies(code);
|
||||
const depsResult = isJson || options.extern
|
||||
? {dependencies: [], dependencyOffsets: []}
|
||||
: extractDependencies(code);
|
||||
|
||||
const timeDelta = process.hrtime(transformFileStartLogEntry.start_timestamp);
|
||||
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
|
||||
const transformFileEndLogEntry = {
|
||||
action_name: 'Transforming file',
|
||||
action_phase: 'end',
|
||||
file_name: filename,
|
||||
duration_ms: duration_ms,
|
||||
log_entry_label: 'Transforming file',
|
||||
};
|
||||
const timeDelta = process.hrtime(transformFileStartLogEntry.start_timestamp);
|
||||
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
|
||||
const transformFileEndLogEntry = {
|
||||
action_name: 'Transforming file',
|
||||
action_phase: 'end',
|
||||
file_name: filename,
|
||||
duration_ms: duration_ms,
|
||||
log_entry_label: 'Transforming file',
|
||||
};
|
||||
|
||||
return callback(null, {
|
||||
result: {...depsResult, code, map},
|
||||
transformFileStartLogEntry,
|
||||
transformFileEndLogEntry,
|
||||
});
|
||||
callback(null, {
|
||||
result: {...depsResult, code, map},
|
||||
transformFileStartLogEntry,
|
||||
transformFileEndLogEntry,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
'use strict';
|
||||
|
||||
import type {SourceMap} from './output/source-map';
|
||||
import type {Ast} from 'babel-core';
|
||||
import type {Console} from 'console';
|
||||
|
||||
export type Callback<A = void, B = void>
|
||||
|
@ -99,18 +100,19 @@ type ResolveOptions = {
|
|||
log?: Console,
|
||||
};
|
||||
|
||||
export type TransformFn = (
|
||||
data: {|
|
||||
filename: string,
|
||||
options?: Object,
|
||||
plugins?: Array<string | Object | [string | Object, any]>,
|
||||
sourceCode: string,
|
||||
|},
|
||||
callback: Callback<TransformFnResult>
|
||||
) => void;
|
||||
export type TransformerResult = {
|
||||
ast: ?Ast,
|
||||
code: string,
|
||||
map: ?SourceMap,
|
||||
};
|
||||
|
||||
export type TransformFnResult = {
|
||||
ast: Object,
|
||||
export type Transformer = {
|
||||
transform: (
|
||||
sourceCode: string,
|
||||
filename: string,
|
||||
options: ?{},
|
||||
plugins?: Array<string | Object | [string | Object, any]>,
|
||||
) => {ast: ?Ast, code: string, map: ?SourceMap}
|
||||
};
|
||||
|
||||
export type TransformResult = {|
|
||||
|
|
|
@ -12,7 +12,7 @@ jest.disableAutomock();
|
|||
|
||||
const optimizeModule = require('../optimize-module');
|
||||
const transformModule = require('../transform-module');
|
||||
const transform = require('../../../../transformer.js');
|
||||
const transformer = require('../../../../transformer.js');
|
||||
const {SourceMapConsumer} = require('source-map');
|
||||
|
||||
const {objectContaining} = jasmine;
|
||||
|
@ -32,7 +32,7 @@ describe('optimizing JS modules', () => {
|
|||
|
||||
let transformResult;
|
||||
beforeAll(done => {
|
||||
transformModule(originalCode, {filename, transform}, (error, result) => {
|
||||
transformModule(originalCode, {filename, transformer}, (error, result) => {
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -24,18 +24,20 @@ const {any, objectContaining} = jasmine;
|
|||
describe('transforming JS modules:', () => {
|
||||
const filename = 'arbitrary';
|
||||
|
||||
let transform;
|
||||
let transformer;
|
||||
|
||||
beforeEach(() => {
|
||||
transform = fn();
|
||||
transform.stub.yields(null, transformResult());
|
||||
transformer = {
|
||||
transform: fn(),
|
||||
};
|
||||
transformer.transform.stub.returns(transformResult());
|
||||
});
|
||||
|
||||
const {bodyAst, sourceCode, transformedCode} = createTestData();
|
||||
|
||||
const options = variants => ({
|
||||
filename,
|
||||
transform,
|
||||
transformer,
|
||||
variants,
|
||||
});
|
||||
|
||||
|
@ -80,17 +82,17 @@ describe('transforming JS modules:', () => {
|
|||
const variants = {dev: {dev: true}, prod: {dev: false}};
|
||||
|
||||
transformModule(sourceCode, options(variants), () => {
|
||||
expect(transform)
|
||||
.toBeCalledWith({filename, sourceCode, options: variants.dev}, any(Function));
|
||||
expect(transform)
|
||||
.toBeCalledWith({filename, sourceCode, options: variants.prod}, any(Function));
|
||||
expect(transformer.transform)
|
||||
.toBeCalledWith(sourceCode, filename, variants.dev);
|
||||
expect(transformer.transform)
|
||||
.toBeCalledWith(sourceCode, filename, variants.prod);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls back with any error yielded by the transform function', done => {
|
||||
const error = new Error();
|
||||
transform.stub.yields(error);
|
||||
transformer.transform.stub.throws(error);
|
||||
|
||||
transformModule(sourceCode, options(), e => {
|
||||
expect(e).toBe(error);
|
||||
|
@ -138,7 +140,7 @@ describe('transforming JS modules:', () => {
|
|||
const dep1 = 'foo', dep2 = 'bar';
|
||||
const code = `require('${dep1}'),require('${dep2}')`;
|
||||
const {body} = parse(code).program;
|
||||
transform.stub.yields(null, transformResult(body));
|
||||
transformer.transform.stub.returns(transformResult(body));
|
||||
|
||||
transformModule(code, options(), (error, result) => {
|
||||
expect(result.transformed.default)
|
||||
|
@ -149,11 +151,11 @@ describe('transforming JS modules:', () => {
|
|||
|
||||
it('transforms for all variants', done => {
|
||||
const variants = {dev: {dev: true}, prod: {dev: false}};
|
||||
transform.stub
|
||||
transformer.transform.stub
|
||||
.withArgs(filename, sourceCode, variants.dev)
|
||||
.yields(null, transformResult(bodyAst))
|
||||
.returns(transformResult(bodyAst))
|
||||
.withArgs(filename, sourceCode, variants.prod)
|
||||
.yields(null, transformResult([]));
|
||||
.returns(transformResult([]));
|
||||
|
||||
transformModule(sourceCode, options(variants), (error, result) => {
|
||||
const {dev, prod} = result.transformed;
|
||||
|
|
|
@ -21,8 +21,8 @@ const {basename} = require('path');
|
|||
import type {
|
||||
Callback,
|
||||
TransformedFile,
|
||||
TransformFn,
|
||||
TransformFnResult,
|
||||
Transformer,
|
||||
TransformerResult,
|
||||
TransformResult,
|
||||
TransformVariants,
|
||||
} from '../types.flow';
|
||||
|
@ -30,7 +30,7 @@ import type {
|
|||
export type TransformOptions = {|
|
||||
filename: string,
|
||||
polyfill?: boolean,
|
||||
transform: TransformFn,
|
||||
transformer: Transformer,
|
||||
variants?: TransformVariants,
|
||||
|};
|
||||
|
||||
|
@ -47,17 +47,23 @@ function transformModule(
|
|||
return transformJSON(code, options, callback);
|
||||
}
|
||||
|
||||
const {filename, transform, variants = defaultVariants} = options;
|
||||
const {filename, transformer, variants = defaultVariants} = options;
|
||||
const tasks = {};
|
||||
Object.keys(variants).forEach(name => {
|
||||
tasks[name] = cb => transform({
|
||||
filename,
|
||||
sourceCode: code,
|
||||
options: variants[name],
|
||||
}, cb);
|
||||
tasks[name] = cb => {
|
||||
try {
|
||||
cb(null, transformer.transform(
|
||||
code,
|
||||
filename,
|
||||
variants[name],
|
||||
));
|
||||
} catch (error) {
|
||||
cb(error, null);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
series(tasks, (error, results: {[key: string]: TransformFnResult}) => {
|
||||
series(tasks, (error, results: {[key: string]: TransformerResult}) => {
|
||||
if (error) {
|
||||
callback(error);
|
||||
return;
|
||||
|
|
|
@ -126,17 +126,4 @@ function transform(src, filename, options) {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = function(data, callback) {
|
||||
let result;
|
||||
try {
|
||||
result = transform(data.sourceCode, data.filename, data.options);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, result);
|
||||
};
|
||||
|
||||
// export for use in jest
|
||||
module.exports.transform = transform;
|
||||
|
|
Loading…
Reference in New Issue