diff --git a/packages/metro-bundler/src/JSTransformer/__mocks__/lodash.js b/packages/metro-bundler/src/JSTransformer/__mocks__/lodash.js index ac8224e6..822ef1dc 100644 --- a/packages/metro-bundler/src/JSTransformer/__mocks__/lodash.js +++ b/packages/metro-bundler/src/JSTransformer/__mocks__/lodash.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; diff --git a/packages/metro-bundler/src/JSTransformer/__mocks__/worker.js b/packages/metro-bundler/src/JSTransformer/__mocks__/worker.js index bc445e25..c7d2c7fa 100644 --- a/packages/metro-bundler/src/JSTransformer/__mocks__/worker.js +++ b/packages/metro-bundler/src/JSTransformer/__mocks__/worker.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; diff --git a/packages/metro-bundler/src/JSTransformer/__tests__/Transformer-test.js b/packages/metro-bundler/src/JSTransformer/__tests__/Transformer-test.js index 156f459a..f436a8e2 100644 --- a/packages/metro-bundler/src/JSTransformer/__tests__/Transformer-test.js +++ b/packages/metro-bundler/src/JSTransformer/__tests__/Transformer-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -34,48 +36,68 @@ describe('Transformer', function() { fs.writeFileSync.mockClear(); workerFarm.mockClear(); workerFarm.mockImplementation((opts, path, methods) => { - const api = workers = {}; - methods.forEach(method => {api[method] = jest.fn();}); - return {methods: api, stdout: new Readable({read() {}}), stderr: new Readable({read() {}})}; + const api = (workers = {}); + methods.forEach(method => { + api[method] = jest.fn(); + }); + return { + methods: api, + stdout: new Readable({read() {}}), + stderr: new Readable({read() {}}), + }; }); }); - it('passes transform module path, file path, source code' + - ' to the worker farm when transforming', () => { - const transformOptions = {arbitrary: 'options'}; - const code = 'arbitrary(code)'; - new Transformer(transformModulePath).transformFile(fileName, localPath, code, transformOptions); - expect(workers.transformAndExtractDependencies).toBeCalledWith( - transformModulePath, - fileName, - localPath, - code, - transformOptions, - any(Function), - ); - }); + it( + 'passes transform module path, file path, source code' + + ' to the worker farm when transforming', + () => { + const transformOptions = {arbitrary: 'options'}; + const code = 'arbitrary(code)'; + new Transformer(transformModulePath).transformFile( + fileName, + localPath, + code, + transformOptions, + ); + expect(workers.transformAndExtractDependencies).toBeCalledWith( + transformModulePath, + fileName, + localPath, + code, + transformOptions, + any(Function), + ); + }, + ); it('should add file info to parse errors', function() { const transformer = new Transformer(transformModulePath); var message = 'message'; var snippet = 'snippet'; - workers.transformAndExtractDependencies.mockImplementation( - function(transformPath, filename, localPth, code, opts, callback) { - var babelError = new SyntaxError(message); - babelError.type = 'SyntaxError'; - babelError.description = message; - babelError.loc = { - line: 2, - column: 15, - }; - babelError.codeFrame = snippet; - callback(babelError); - }, - ); + workers.transformAndExtractDependencies.mockImplementation(function( + transformPath, + filename, + localPth, + code, + opts, + callback, + ) { + var babelError = new SyntaxError(message); + babelError.type = 'SyntaxError'; + babelError.description = message; + babelError.loc = { + line: 2, + column: 15, + }; + babelError.codeFrame = snippet; + callback(babelError); + }); expect.assertions(7); - return transformer.transformFile(fileName, localPath, '', {}) + return transformer + .transformFile(fileName, localPath, '', {}) .catch(function(error) { expect(error.type).toEqual('TransformError'); expect(error.message).toBe('SyntaxError ' + message); diff --git a/packages/metro-bundler/src/JSTransformer/index.js b/packages/metro-bundler/src/JSTransformer/index.js index 4cf2a993..d6f803ec 100644 --- a/packages/metro-bundler/src/JSTransformer/index.js +++ b/packages/metro-bundler/src/JSTransformer/index.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; @@ -23,12 +24,18 @@ const workerFarm = require('../worker-farm'); import type {Data as TransformData, Options as WorkerOptions} from './worker'; import type {LocalPath} from '../node-haste/lib/toLocalPath'; import type {MappingsMap} from '../lib/SourceMap'; -import typeof {minify as Minify, transformAndExtractDependencies as TransformAndExtractDependencies} from './worker'; +import typeof { + minify as Minify, + transformAndExtractDependencies as TransformAndExtractDependencies, +} from './worker'; type CB = (?Error, ?T) => mixed; -type Denodeify = - & (((A, B, C, CB) => void) => (A, B, C) => Promise) - & (((A, B, C, D, E, CB) => void) => (A, B, C, D, E) => Promise); +type Denodeify = (( + (A, B, C, CB) => void, +) => (A, B, C) => Promise) & + (( + (A, B, C, D, E, CB) => void, + ) => (A, B, C, D, E) => Promise); // Avoid memory leaks caused in workers. This number seems to be a good enough number // to avoid any memory leak while not slowing down initial builds. @@ -63,7 +70,6 @@ type Reporters = { }; class Transformer { - _workers: {[name: string]: Function}; _transformModulePath: string; _transform: ( @@ -85,7 +91,10 @@ class Transformer { reporters: Reporters, workerPath: ?string, ) { - invariant(path.isAbsolute(transformModulePath), 'transform module path should be absolute'); + invariant( + path.isAbsolute(transformModulePath), + 'transform module path should be absolute', + ); this._transformModulePath = transformModulePath; const farm = makeFarm( @@ -102,7 +111,10 @@ class Transformer { }); this._workers = farm.methods; - this._transform = denodeify((this._workers.transformAndExtractDependencies: TransformAndExtractDependencies)); + this._transform = denodeify( + (this._workers + .transformAndExtractDependencies: TransformAndExtractDependencies), + ); this.minify = denodeify((this._workers.minify: Minify)); } @@ -114,19 +126,19 @@ class Transformer { fileName: string, localPath: LocalPath, code: string, - options: WorkerOptions) { + options: WorkerOptions, + ) { if (!this._transform) { return Promise.reject(new Error('No transform module')); } debug('transforming file', fileName); - return this - ._transform( - this._transformModulePath, - fileName, - localPath, - code, - options, - ) + return this._transform( + this._transformModulePath, + fileName, + localPath, + code, + options, + ) .then(data => { Logger.log(data.transformFileStartLogEntry); Logger.log(data.transformFileEndLogEntry); @@ -137,8 +149,8 @@ class Transformer { if (error.type === 'TimeoutError') { const timeoutErr = new Error( `TimeoutError: transforming ${fileName} took longer than ` + - `${TRANSFORM_TIMEOUT_INTERVAL / 1000} seconds.\n` + - 'You can adjust timeout via the \'transformTimeoutInterval\' option' + `${TRANSFORM_TIMEOUT_INTERVAL / 1000} seconds.\n` + + "You can adjust timeout via the 'transformTimeoutInterval' option", ); /* $FlowFixMe: monkey-patch Error */ timeoutErr.type = 'TimeoutError'; @@ -146,7 +158,7 @@ class Transformer { } else if (error.type === 'ProcessTerminatedError') { const uncaughtError = new Error( 'Uncaught error in the transformer worker: ' + - this._transformModulePath + this._transformModulePath, ); /* $FlowFixMe: monkey-patch Error */ uncaughtError.type = 'ProcessTerminatedError'; diff --git a/packages/metro-bundler/src/JSTransformer/worker/JsMinification.js b/packages/metro-bundler/src/JSTransformer/worker/JsMinification.js index 580212eb..b9f6d702 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/JsMinification.js +++ b/packages/metro-bundler/src/JSTransformer/worker/JsMinification.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/constant-folding-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/constant-folding-test.js index 1f8a26cb..bd15a1c6 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/constant-folding-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/constant-folding-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -38,18 +40,19 @@ describe('constant expressions', () => { 'foo'==='bar' ? b : c, f() ? g() : h() );`; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('a(true,true,2,true,{},{a:1},c,f()?g():h());'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + 'a(true,true,2,true,{},{a:1},c,f()?g():h());', + ); }); it('can optimize ternary expressions with constant conditions', () => { - const code = - `var a = true ? 1 : 2; + const code = `var a = true ? 1 : 2; var b = 'android' == 'android' ? ('production' != 'production' ? 'a' : 'A') : 'i';`; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('var a=1;var b=\'A\';'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + "var a=1;var b='A';", + ); }); it('can optimize logical operator expressions with constant conditions', () => { @@ -57,8 +60,9 @@ describe('constant expressions', () => { var a = true || 1; var b = 'android' == 'android' && 'production' != 'production' || null || "A";`; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('var a=true;var b="A";'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + 'var a=true;var b="A";', + ); }); it('can optimize logical operators with partly constant operands', () => { @@ -69,8 +73,9 @@ describe('constant expressions', () => { var d = null || z(); var e = !1 && z(); `; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('var a="truthy";var b=z();var c=null;var d=z();var e=false;'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + 'var a="truthy";var b=z();var c=null;var d=z();var e=false;', + ); }); it('can remode an if statement with a falsy constant test', () => { @@ -79,8 +84,7 @@ describe('constant expressions', () => { var a = 1; } `; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual(''); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(''); }); it('can optimize if-else-branches with constant conditions', () => { @@ -95,8 +99,9 @@ describe('constant expressions', () => { var a = 'b'; } `; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('{var a=3;var b=a+4;}'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + '{var a=3;var b=a+4;}', + ); }); it('can optimize nested if-else constructs', () => { @@ -115,7 +120,8 @@ describe('constant expressions', () => { } } `; - expect(normalize(constantFolding('arbitrary.js', parse(code)))) - .toEqual('{{require(\'c\');}}'); + expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual( + "{{require('c');}}", + ); }); }); diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js index 53725cdd..398e1923 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/extract-dependencies-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -22,8 +24,7 @@ describe('Dependency extraction:', () => { require ('more');`; const {dependencies, dependencyOffsets} = extractDependencies(code); - expect(dependencies) - .toEqual(['foo/bar', 'React', 'Component', 'more']); + expect(dependencies).toEqual(['foo/bar', 'React', 'Component', 'more']); expect(dependencyOffsets).toEqual([8, 46, 147, 203]); }); @@ -76,7 +77,7 @@ describe('Dependency extraction:', () => { }); it('does not extract calls to function with names that start with "require"', () => { - const code = 'arbitraryrequire(\'foo\');'; + const code = "arbitraryrequire('foo');"; const {dependencies, dependencyOffsets} = extractDependencies(code); expect(dependencies).toEqual([]); @@ -84,7 +85,7 @@ describe('Dependency extraction:', () => { }); it('does not extract calls to require with non-static arguments', () => { - const code = 'require(\'foo/\' + bar)'; + const code = "require('foo/' + bar)"; const {dependencies, dependencyOffsets} = extractDependencies(code); expect(dependencies).toEqual([]); @@ -101,7 +102,7 @@ describe('Dependency extraction:', () => { }); it('can handle regular expressions', () => { - const code = 'require(\'a\'); /["\']/.test(\'foo\'); require("b");'; + const code = "require('a'); /[\"']/.test('foo'); require(\"b\");"; const {dependencies, dependencyOffsets} = extractDependencies(code); expect(dependencies).toEqual(['a', 'b']); diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/inline-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/inline-test.js index d329a715..9a452aee 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/inline-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/inline-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -47,7 +49,9 @@ describe('inline constants', () => { var b = a.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.OS/, '"ios"')), + ); }); it('replaces Platform.OS in the code if Platform is a top level import', () => { @@ -58,7 +62,9 @@ describe('inline constants', () => { var b = a.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.OS/, '"ios"')), + ); }); it('replaces Platform.OS in the code if Platform is a top level import from react-native', () => { @@ -69,7 +75,9 @@ describe('inline constants', () => { var b = a.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.OS/, '"ios"')), + ); }); it('replaces require("Platform").OS in the code', () => { @@ -79,7 +87,8 @@ describe('inline constants', () => { }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); expect(toString(ast)).toEqual( - normalize(code.replace(/require\('Platform'\)\.OS/, '"android"'))); + normalize(code.replace(/require\('Platform'\)\.OS/, '"android"')), + ); }); it('replaces React.Platform.OS in the code if React is a global', () => { @@ -88,7 +97,9 @@ describe('inline constants', () => { var b = a.React.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/React\.Platform\.OS/, '"ios"')), + ); }); it('replaces ReactNative.Platform.OS in the code if ReactNative is a global', () => { @@ -97,7 +108,9 @@ describe('inline constants', () => { var b = a.ReactNative.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative\.Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/ReactNative\.Platform\.OS/, '"ios"')), + ); }); it('replaces React.Platform.OS in the code if React is a top level import', () => { @@ -108,7 +121,9 @@ describe('inline constants', () => { var b = a.React.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/React.Platform\.OS/, '"ios"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/React.Platform\.OS/, '"ios"')), + ); }); it('replaces require("React").Platform.OS in the code', () => { @@ -118,7 +133,8 @@ describe('inline constants', () => { }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); expect(toString(ast)).toEqual( - normalize(code.replace(/require\('React'\)\.Platform\.OS/, '"android"'))); + normalize(code.replace(/require\('React'\)\.Platform\.OS/, '"android"')), + ); }); it('replaces ReactNative.Platform.OS in the code if ReactNative is a top level import', () => { @@ -129,7 +145,9 @@ describe('inline constants', () => { var b = a.ReactNative.Platform.OS; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); - expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative.Platform\.OS/, '"android"'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/ReactNative.Platform\.OS/, '"android"')), + ); }); it('replaces require("react-native").Platform.OS in the code', () => { @@ -139,7 +157,10 @@ describe('inline constants', () => { }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); expect(toString(ast)).toEqual( - normalize(code.replace(/require\('react-native'\)\.Platform\.OS/, '"android"'))); + normalize( + code.replace(/require\('react-native'\)\.Platform\.OS/, '"android"'), + ), + ); }); it('inlines Platform.select in the code if Platform is a global and the argument is an object literal', () => { @@ -148,16 +169,20 @@ describe('inline constants', () => { var b = a.Platform.select({ios: 1, android: 2}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '1'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.select[^;]+/, '1')), + ); }); - it('inlines Platform.select in the code if Platform is a global and the argument doesn\'t have target platform in it\'s keys', () => { + it("inlines Platform.select in the code if Platform is a global and the argument doesn't have target platform in it's keys", () => { const code = `function a() { var a = Platform.select({ios: 1, default: 2}); var b = a.Platform.select({ios: 1, default: 2}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '2'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.select[^;]+/, '2')), + ); }); it('replaces Platform.select in the code if Platform is a top level import', () => { @@ -168,7 +193,9 @@ describe('inline constants', () => { var b = a.Platform.select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '2'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.select[^;]+/, '2')), + ); }); it('replaces Platform.select in the code if Platform is a top level import from react-native', () => { @@ -179,7 +206,9 @@ describe('inline constants', () => { var b = a.Platform.select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '1'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.select[^;]+/, '1')), + ); }); it('replaces require("Platform").select in the code', () => { @@ -188,7 +217,9 @@ describe('inline constants', () => { var b = a.require('Platform').select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); - expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '2'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/Platform\.select[^;]+/, '2')), + ); }); it('replaces React.Platform.select in the code if React is a global', () => { @@ -197,7 +228,9 @@ describe('inline constants', () => { var b = a.React.Platform.select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.select[^;]+/, '1'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/React\.Platform\.select[^;]+/, '1')), + ); }); it('replaces ReactNative.Platform.select in the code if ReactNative is a global', () => { @@ -219,7 +252,9 @@ describe('inline constants', () => { var b = a.React.Platform.select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.select[^;]+/, '1'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/React\.Platform\.select[^;]+/, '1')), + ); }); it('replaces require("React").Platform.select in the code', () => { @@ -229,7 +264,8 @@ describe('inline constants', () => { }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); expect(toString(ast)).toEqual( - normalize(code.replace(/require\('React'\)\.Platform\.select[^;]+/, '2'))); + normalize(code.replace(/require\('React'\)\.Platform\.select[^;]+/, '2')), + ); }); it('replaces ReactNative.Platform.select in the code if ReactNative is a top level import', () => { @@ -252,14 +288,18 @@ describe('inline constants', () => { `; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); expect(toString(ast)).toEqual( - normalize(code.replace(/require\('react-native'\)\.Platform\.select[^;]+/, '2'))); + normalize( + code.replace(/require\('react-native'\)\.Platform\.select[^;]+/, '2'), + ), + ); }); it('replaces non-existing properties with `undefined`', () => { const code = 'var a = Platform.select({ios: 1, android: 2})'; const {ast} = inline('arbitrary.js', {code}, {platform: 'doesnotexist'}); expect(toString(ast)).toEqual( - normalize(code.replace(/Platform\.select[^;]+/, 'undefined'))); + normalize(code.replace(/Platform\.select[^;]+/, 'undefined')), + ); }); it('replaces process.env.NODE_ENV in the code', () => { @@ -271,7 +311,8 @@ describe('inline constants', () => { }`; const {ast} = inline('arbitrary.js', {code}, {dev: false}); expect(toString(ast)).toEqual( - normalize(code.replace(/process\.env\.NODE_ENV/, '"production"'))); + normalize(code.replace(/process\.env\.NODE_ENV/, '"production"')), + ); }); it('accepts an AST as input', function() { @@ -286,13 +327,16 @@ describe('inline constants', () => { var a = Platform.OS, b = Platform.select({android: 1, ios: 2}); });`; const {ast} = inline( - 'arbitrary', {code}, {dev: true, platform: 'android', isWrapped: true}); + 'arbitrary', + {code}, + {dev: true, platform: 'android', isWrapped: true}, + ); expect(toString(ast)).toEqual( normalize( code .replace(/Platform\.OS/, '"android"') - .replace(/Platform\.select[^)]+\)/, 1) - ) + .replace(/Platform\.select[^)]+\)/, 1), + ), ); }); @@ -301,9 +345,13 @@ describe('inline constants', () => { var a = require(arbitraryMapName[123], 'react-native').Platform.OS; });`; const {ast} = inline( - 'arbitrary', {code}, {dev: true, platform: 'android', isWrapped: true}); + 'arbitrary', + {code}, + {dev: true, platform: 'android', isWrapped: true}, + ); expect(toString(ast)).toEqual( - normalize(code.replace(/require\([^)]+\)\.Platform\.OS/, '"android"'))); + normalize(code.replace(/require\([^)]+\)\.Platform\.OS/, '"android"')), + ); }); it('works with flow-declared variables', () => { @@ -311,10 +359,10 @@ describe('inline constants', () => { const code = `declare var __DEV__; const a: boolean = __DEV__;`; - const transformed = transform( - code, - {...babelOptions, plugins: [stripFlow, [inline.plugin, {dev: false}]]}, - ).code; + const transformed = transform(code, { + ...babelOptions, + plugins: [stripFlow, [inline.plugin, {dev: false}]], + }).code; expect(transformed).toEqual('const a=false;'); }); @@ -326,10 +374,10 @@ describe('inline constants', () => { const a: boolean = __DEV__; });`; - const transformed = transform( - code, - {...babelOptions, plugins: [stripFlow, [inline.plugin, {dev: true}]]}, - ).code; + const transformed = transform(code, { + ...babelOptions, + plugins: [stripFlow, [inline.plugin, {dev: true}]], + }).code; expect(transformed).toEqual('__d(()=>{const a=true;});'); }); diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/minify-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/minify-test.js index 6a2e8329..6a5ab01f 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/minify-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/minify-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -35,11 +37,14 @@ describe('Minification:', () => { it('passes file name, code, and source map to `uglify`', () => { minify(filename, code, map); - expect(uglify.minify).toBeCalledWith(code, objectContaining({ - fromString: true, - inSourceMap: map, - outSourceMap: true, - })); + expect(uglify.minify).toBeCalledWith( + code, + objectContaining({ + fromString: true, + inSourceMap: map, + outSourceMap: true, + }), + ); }); it('returns the code provided by uglify', () => { diff --git a/packages/metro-bundler/src/JSTransformer/worker/__tests__/worker-test.js b/packages/metro-bundler/src/JSTransformer/worker/__tests__/worker-test.js index 3c8d50a8..15af1357 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/__tests__/worker-test.js +++ b/packages/metro-bundler/src/JSTransformer/worker/__tests__/worker-test.js @@ -5,6 +5,8 @@ * 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. + * + * @format */ 'use strict'; @@ -22,8 +24,9 @@ describe('code transformation worker:', () => { beforeEach(() => { jest.resetModules(); ({transformCode} = require('..')); - extractDependencies = - require('../extract-dependencies').mockReturnValue({}); + extractDependencies = require('../extract-dependencies').mockReturnValue( + {}, + ); transformer = { transform: jest.fn(({filename, options, src}) => ({ code: src, @@ -37,7 +40,14 @@ describe('code transformation worker:', () => { const localPath = `local/${filename}`; const sourceCode = 'arbitrary(code)'; const transformOptions = {arbitrary: 'options'}; - transformCode(transformer, filename, localPath, sourceCode, {transform: transformOptions}, () => {}); + transformCode( + transformer, + filename, + localPath, + sourceCode, + {transform: transformOptions}, + () => {}, + ); expect(transformer.transform).toBeCalledWith({ filename, localPath, @@ -65,26 +75,39 @@ describe('code transformation worker:', () => { map: {}, }; - transformCode(transformer, 'filename', 'local/filename', result.code, {}, (error, data) => { - expect(error).toBeNull(); - expect(data.result).toEqual(objectContaining(result)); - done(); - }); + transformCode( + transformer, + 'filename', + 'local/filename', + result.code, + {}, + (error, data) => { + expect(error).toBeNull(); + expect(data.result).toEqual(objectContaining(result)); + done(); + }, + ); }); it( 'removes the leading assignment to `module.exports` before passing ' + - 'on the result if the file is a JSON file, even if minified', + 'on the result if the file is a JSON file, even if minified', done => { const code = '{a:1,b:2}'; const filePath = 'arbitrary/file.json'; - transformCode(transformer, filePath, filePath, code, {}, (error, data) => { - expect(error).toBeNull(); - expect(data.result.code).toEqual(code); - done(); - }, + transformCode( + transformer, + filePath, + filePath, + code, + {}, + (error, data) => { + expect(error).toBeNull(); + expect(data.result.code).toEqual(code); + done(); + }, ); - } + }, ); it('removes shebang when present', done => { @@ -93,13 +116,20 @@ describe('code transformation worker:', () => { code: `${shebang} \n arbitrary(code)`, }; const filePath = 'arbitrary/file.js'; - transformCode(transformer, filePath, filePath, result.code, {}, (error, data) => { - expect(error).toBeNull(); - const {code} = data.result; - expect(code).not.toContain(shebang); - expect(code.split('\n').length).toEqual(result.code.split('\n').length); - done(); - }); + transformCode( + transformer, + filePath, + filePath, + result.code, + {}, + (error, data) => { + expect(error).toBeNull(); + const {code} = data.result; + expect(code).not.toContain(shebang); + expect(code.split('\n').length).toEqual(result.code.split('\n').length); + done(); + }, + ); }); it('calls back with any error yielded by the transform', done => { @@ -108,51 +138,78 @@ describe('code transformation worker:', () => { throw new Error(message); }); - transformCode(transformer, 'filename', 'local/filename', 'code', {}, error => { - expect(error.message).toBe(message); - done(); - }); + transformCode( + transformer, + 'filename', + 'local/filename', + 'code', + {}, + error => { + expect(error.message).toBe(message); + done(); + }, + ); }); describe('dependency extraction', () => { it('passes the transformed code the `extractDependencies`', done => { const code = 'arbitrary(code)'; - transformCode(transformer, 'filename', 'local/filename', code, {}, error => { - expect(error).toBeNull(); - expect(extractDependencies).toBeCalledWith(code); - done(); - }); + transformCode( + transformer, + 'filename', + 'local/filename', + code, + {}, + error => { + expect(error).toBeNull(); + expect(extractDependencies).toBeCalledWith(code); + done(); + }, + ); }); it( 'uses `dependencies` and `dependencyOffsets` ' + - 'provided by `extractDependencies` for the result', + 'provided by `extractDependencies` for the result', done => { const dependencyData = { dependencies: ['arbitrary', 'list', 'of', 'dependencies'], - dependencyOffsets: [12, 119, 185, 328, 471], + dependencyOffsets: [12, 119, 185, 328, 471], }; extractDependencies.mockReturnValue(dependencyData); - transformCode(transformer, 'filename', 'local/filename', 'code', {}, (error, data) => { - expect(error).toBeNull(); - expect(data.result).toEqual(objectContaining(dependencyData)); - done(); - }); - } + transformCode( + transformer, + 'filename', + 'local/filename', + 'code', + {}, + (error, data) => { + expect(error).toBeNull(); + expect(data.result).toEqual(objectContaining(dependencyData)); + done(); + }, + ); + }, ); it('does not extract requires of JSON files', done => { const jsonStr = '{"arbitrary":"json"}'; - transformCode(transformer, 'arbitrary.json', 'local/arbitrary.json', jsonStr, {}, (error, data) => { - expect(error).toBeNull(); - const {dependencies, dependencyOffsets} = data.result; - expect(extractDependencies).not.toBeCalled(); - expect(dependencies).toEqual([]); - expect(dependencyOffsets).toEqual([]); - done(); - } + transformCode( + transformer, + 'arbitrary.json', + 'local/arbitrary.json', + jsonStr, + {}, + (error, data) => { + expect(error).toBeNull(); + const {dependencies, dependencyOffsets} = data.result; + expect(extractDependencies).not.toBeCalled(); + expect(dependencies).toEqual([]); + expect(dependencyOffsets).toEqual([]); + done(); + }, ); }); }); @@ -165,8 +222,10 @@ describe('code transformation worker:', () => { const foldedMap = {version: 3, sources: ['fold.js']}; beforeEach(() => { - constantFolding = require('../constant-folding') - .mockReturnValue({code: foldedCode, map: foldedMap}); + constantFolding = require('../constant-folding').mockReturnValue({ + code: foldedCode, + map: foldedMap, + }); extractDependencies = require('../extract-dependencies'); inline = require('../inline'); @@ -177,9 +236,12 @@ describe('code transformation worker:', () => { }; extractDependencies.mockImplementation( - code => code === foldedCode ? dependencyData : {}); + code => (code === foldedCode ? dependencyData : {}), + ); - transformer.transform.mockImplementation((src, fileName, _) => transformResult); + transformer.transform.mockImplementation( + (src, fileName, _) => transformResult, + ); }); it('passes the transform result to `inline` for constant inlining', done => { @@ -207,19 +269,34 @@ describe('code transformation worker:', () => { }); it('uses the dependencies obtained from the optimized result', done => { - transformCode(transformer, filename, filename, 'code', options, (_, data) => { - const result = data.result; - expect(result.dependencies).toEqual(dependencyData.dependencies); - done(); - }); + transformCode( + transformer, + filename, + filename, + 'code', + options, + (_, data) => { + const result = data.result; + expect(result.dependencies).toEqual(dependencyData.dependencies); + done(); + }, + ); }); it('uses data produced by `constant-folding` for the result', done => { - transformCode(transformer, 'filename', 'local/filename', 'code', options, (_, data) => { - expect(data.result) - .toEqual(objectContaining({code: foldedCode, map: foldedMap})); - done(); - }); + transformCode( + transformer, + 'filename', + 'local/filename', + 'code', + options, + (_, data) => { + expect(data.result).toEqual( + objectContaining({code: foldedCode, map: foldedMap}), + ); + done(); + }, + ); }); }); }); diff --git a/packages/metro-bundler/src/JSTransformer/worker/constant-folding.js b/packages/metro-bundler/src/JSTransformer/worker/constant-folding.js index 36cfbf62..46597935 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/constant-folding.js +++ b/packages/metro-bundler/src/JSTransformer/worker/constant-folding.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; @@ -70,11 +71,14 @@ const plugin = { }, }; -function constantFolding(filename: string, transformResult: { - ast: Ast, - code?: ?string, - map: ?MappingsMap, -}) { +function constantFolding( + filename: string, + transformResult: { + ast: Ast, + code?: ?string, + map: ?MappingsMap, + }, +) { return babel.transformFromAst(transformResult.ast, transformResult.code, { filename, plugins: [plugin], diff --git a/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js b/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js index 1ce908b9..7b124a9d 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js +++ b/packages/metro-bundler/src/JSTransformer/worker/extract-dependencies.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; diff --git a/packages/metro-bundler/src/JSTransformer/worker/index.js b/packages/metro-bundler/src/JSTransformer/worker/index.js index f88706ff..693f37d8 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/index.js +++ b/packages/metro-bundler/src/JSTransformer/worker/index.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; @@ -41,7 +42,6 @@ export type Transformer = { getCacheKey: () => string, }; - export type TransformOptionsStrict = {| +dev: boolean, +generateSourceMaps: boolean, @@ -73,10 +73,7 @@ export type Data = { transformFileEndLogEntry: LogEntry, }; -type Callback = ( - error: ?Error, - data: ?T, -) => mixed; +type Callback = (error: ?Error, data: ?T) => mixed; function transformCode( transformer: Transformer<*>, @@ -124,8 +121,10 @@ function transformCode( var code, map; if (options.minify) { - ({code, map} = - constantFolding(filename, inline(filename, transformed, options))); + ({code, map} = constantFolding( + filename, + inline(filename, transformed, options), + )); invariant(code != null, 'Missing code from constant-folding transform.'); } else { ({code, map} = transformed); @@ -170,7 +169,14 @@ exports.transformAndExtractDependencies = ( babelRegisterOnly([transform]); /* $FlowFixMe: impossible to type a dynamic require */ const transformModule: Transformer<*> = require(transform); - transformCode(transformModule, filename, localPath, sourceCode, options, callback); + transformCode( + transformModule, + filename, + localPath, + sourceCode, + options, + callback, + ); }; exports.minify = ( diff --git a/packages/metro-bundler/src/JSTransformer/worker/inline.js b/packages/metro-bundler/src/JSTransformer/worker/inline.js index 041c903f..57ce5f01 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/inline.js +++ b/packages/metro-bundler/src/JSTransformer/worker/inline.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict'; @@ -34,8 +35,7 @@ const importMap = new Map([['ReactNative', 'react-native']]); const isGlobal = binding => !binding; -const isFlowDeclared = binding => - t.isDeclareVariable(binding.path); +const isFlowDeclared = binding => t.isDeclareVariable(binding.path); const isGlobalOrFlowDeclared = binding => isGlobal(binding) || isFlowDeclared(binding); @@ -43,7 +43,7 @@ const isGlobalOrFlowDeclared = binding => const isToplevelBinding = (binding, isWrappedModule) => isGlobal(binding) || !binding.scope.parent || - isWrappedModule && !binding.scope.parent.parent; + (isWrappedModule && !binding.scope.parent.parent); const isRequireCall = (node, dependencyId, scope) => t.isCallExpression(node) && @@ -59,8 +59,8 @@ const isImport = (node, scope, patterns) => function isImportOrGlobal(node, scope, patterns, isWrappedModule) { const identifier = patterns.find(pattern => t.isIdentifier(node, pattern)); return ( - identifier && - isToplevelBinding(scope.getBinding(identifier.name), isWrappedModule) || + (identifier && + isToplevelBinding(scope.getBinding(identifier.name), isWrappedModule)) || isImport(node, scope, patterns) ); } @@ -74,7 +74,11 @@ const isReactPlatformOS = (node, scope, isWrappedModule) => t.isMemberExpression(node.object) && t.isIdentifier(node.object.property, platform) && isImportOrGlobal( - node.object.object, scope, [React, ReactNative], isWrappedModule); + node.object.object, + scope, + [React, ReactNative], + isWrappedModule, + ); const isProcessEnvNodeEnv = (node, scope) => t.isIdentifier(node.property, nodeEnv) && @@ -95,12 +99,16 @@ const isReactPlatformSelect = (node, scope, isWrappedModule) => t.isMemberExpression(node.callee.object) && t.isIdentifier(node.callee.object.property, platform) && isImportOrGlobal( - node.callee.object.object, scope, [React, ReactNative], isWrappedModule); + node.callee.object.object, + scope, + [React, ReactNative], + isWrappedModule, + ); const isDev = (node, parent, scope) => t.isIdentifier(node, dev) && isGlobalOrFlowDeclared(scope.getBinding(dev.name)) && - !(t.isMemberExpression(parent)); + !t.isMemberExpression(parent); function findProperty(objectExpression, key, fallback) { const property = objectExpression.properties.find(p => p.key.name === key); @@ -126,7 +134,8 @@ const inlinePlugin = { path.replaceWith(t.stringLiteral(opts.platform)); } else if (isProcessEnvNodeEnv(node, scope)) { path.replaceWith( - t.stringLiteral(opts.dev ? 'development' : 'production')); + t.stringLiteral(opts.dev ? 'development' : 'production'), + ); } }, CallExpression(path, state) { @@ -155,10 +164,12 @@ const plugin = () => inlinePlugin; function checkRequireArgs(args, dependencyId) { const pattern = t.stringLiteral(dependencyId); - return t.isStringLiteral(args[0], pattern) || - t.isMemberExpression(args[0]) && - t.isNumericLiteral(args[0].property) && - t.isStringLiteral(args[1], pattern); + return ( + t.isStringLiteral(args[0], pattern) || + (t.isMemberExpression(args[0]) && + t.isNumericLiteral(args[0].property) && + t.isStringLiteral(args[1], pattern)) + ); } type AstResult = { diff --git a/packages/metro-bundler/src/JSTransformer/worker/minify.js b/packages/metro-bundler/src/JSTransformer/worker/minify.js index 54f3c638..67e3b1c5 100644 --- a/packages/metro-bundler/src/JSTransformer/worker/minify.js +++ b/packages/metro-bundler/src/JSTransformer/worker/minify.js @@ -7,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. * * @flow + * @format */ 'use strict';