diff --git a/packages/metro/src/Bundler.js b/packages/metro/src/Bundler.js index 0b9691fe..0e0b3fda 100644 --- a/packages/metro/src/Bundler.js +++ b/packages/metro/src/Bundler.js @@ -291,12 +291,6 @@ class Bundler { } } - if (!cache && code == null) { - throw new Error( - 'When not using experimental caches, code should always be provided', - ); - } - // Second, if there was no result, compute it ourselves. if (!data) { data = await this._transformer.transform( diff --git a/packages/metro/src/DeltaBundler/__tests__/__snapshots__/traverseDependencies-integration-test.js.snap b/packages/metro/src/DeltaBundler/__tests__/__snapshots__/traverseDependencies-integration-test.js.snap index 3269d478..c4473ec8 100644 --- a/packages/metro/src/DeltaBundler/__tests__/__snapshots__/traverseDependencies-integration-test.js.snap +++ b/packages/metro/src/DeltaBundler/__tests__/__snapshots__/traverseDependencies-integration-test.js.snap @@ -7,7 +7,7 @@ Array [ "a", "b", ], - "id": "index", + "id": "index.js", "isAsset": false, "isPolyfill": false, "path": "/root/index.js", @@ -15,7 +15,7 @@ Array [ }, Object { "dependencies": Array [], - "id": "a", + "id": "a.js", "isAsset": false, "isPolyfill": false, "path": "/root/a.js", @@ -23,7 +23,7 @@ Array [ }, Object { "dependencies": Array [], - "id": "b", + "id": "b.js", "isAsset": false, "isPolyfill": false, "path": "/root/b.js", diff --git a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-integration-test.js b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-integration-test.js index 61c0ff62..dc7eeb36 100644 --- a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-integration-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-integration-test.js @@ -133,11 +133,15 @@ describe('traverseDependencies', function() { transformCache: require('TransformCaching').mocked(), transformCode: (module, sourceCode, transformOptions) => { return new Promise(resolve => { + // require call must stay inline, so the latest defined mock is used! + const code = require('fs').readFileSync(module.path, 'utf8'); const deps = {dependencies: []}; + if (!module.path.endsWith('.json')) { - deps.dependencies = extractDependencies(sourceCode); + deps.dependencies = extractDependencies(code); } - resolve({...deps, code: sourceCode}); + + resolve({...deps, code}); }); }, getTransformCacheKey: () => 'abcdef', @@ -191,7 +195,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['a'], isAsset: false, @@ -200,7 +204,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'a', + id: 'a.js', path: '/root/a.js', dependencies: ['b'], isAsset: false, @@ -209,7 +213,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'b', + id: 'b.js', path: '/root/b.js', dependencies: [], isAsset: false, @@ -248,7 +252,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'a', + id: 'a.js', path: '/root/a.js', dependencies: ['b'], isAsset: false, @@ -281,14 +285,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.js', path: '/root/a.js', dependencies: [], isAsset: false, @@ -325,21 +329,21 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./a.json', './b'], isAsset: false, isPolyfill: false, }, { - id: 'package/a.json', + id: 'a.json', path: '/root/a.json', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'package/b.json', + id: 'b.json', path: '/root/b.json', dependencies: [], isAsset: false, @@ -373,14 +377,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./package.json'], isAsset: false, isPolyfill: false, }, { - id: 'package/package.json', + id: 'package.json', path: '/root/package.json', dependencies: [], isAsset: false, @@ -417,7 +421,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./imgs/a.png'], isAsset: false, @@ -466,7 +470,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./imgs/a.png', './imgs/b.png', './imgs/c.png'], isAsset: false, @@ -530,7 +534,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./imgs/a.png', './imgs/b.png', './imgs/c.png'], isAsset: false, @@ -588,14 +592,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.js', path: '/root/a.js', dependencies: ['index'], isAsset: false, @@ -633,7 +637,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -678,7 +682,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage/'], isAsset: false, @@ -731,7 +735,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['sha.js', 'x.y.z'], isAsset: false, @@ -825,7 +829,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'EpicModule', + id: 'aPackage/index.js', path: '/root/aPackage/index.js', dependencies: [], isAsset: false, @@ -899,14 +903,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'test/index.js', + id: 'index.js', path: '/root/index.js', dependencies: ['./lib/'], isAsset: false, isPolyfill: false, }, { - id: 'test/lib/index.js', + id: 'lib/index.js', path: '/root/lib/index.js', dependencies: [], isAsset: false, @@ -942,14 +946,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'test/index.js', + id: 'index.js', path: '/root/index.js', dependencies: ['./lib/'], isAsset: false, isPolyfill: false, }, { - id: '/root/lib/main.js', + id: 'lib/main.js', path: '/root/lib/main.js', dependencies: [], isAsset: false, @@ -979,7 +983,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: [], isAsset: false, @@ -1074,7 +1078,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage/subdir/lolynot'], isAsset: false, @@ -1127,7 +1131,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1216,7 +1220,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1277,7 +1281,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1340,7 +1344,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1401,7 +1405,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1465,7 +1469,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1539,7 +1543,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1634,7 +1638,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1648,7 +1652,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'browser-package/index.js', + id: 'aPackage/browser-package/index.js', path: '/root/aPackage/browser-package/index.js', dependencies: [], isAsset: false, @@ -1708,7 +1712,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1789,7 +1793,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1803,7 +1807,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'browser-package/index.js', + id: 'aPackage/browser-package/index.js', path: '/root/aPackage/browser-package/index.js', dependencies: [], isAsset: false, @@ -1860,7 +1864,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -1927,7 +1931,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -2006,7 +2010,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -2020,14 +2024,14 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'rn-package/index.js', + id: 'aPackage/node_modules/rn-package/index.js', path: '/root/aPackage/node_modules/rn-package/index.js', dependencies: ['nested-package'], isAsset: false, isPolyfill: false, }, { - id: 'nested-browser-package/index.js', + id: 'aPackage/node_modules/nested-browser-package/index.js', path: '/root/aPackage/node_modules/nested-browser-package/index.js', dependencies: [], isAsset: false, @@ -2161,7 +2165,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -2179,21 +2183,21 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'rn-package-a/index.js', + id: 'aPackage/node_modules/rn-package-a/index.js', path: '/root/aPackage/node_modules/rn-package-a/index.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'rn-package-b/index.js', + id: 'aPackage/node_modules/rn-package-b/index.js', path: '/root/aPackage/node_modules/rn-package-b/index.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'rn-package-d/index.js', + id: 'aPackage/node_modules/rn-package-d/index.js', path: '/root/aPackage/node_modules/rn-package-d/index.js', dependencies: [], isAsset: false, @@ -2248,7 +2252,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: '/root/provides-bar/lib/bar.js', + id: 'provides-bar/lib/bar.js', path: '/root/provides-bar/lib/bar.js', dependencies: [], isAsset: false, @@ -2332,7 +2336,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: '/root/provides-bar/lib/foo.js', + id: 'provides-bar/lib/foo.js', path: '/root/provides-bar/lib/foo.js', dependencies: [], isAsset: false, @@ -2390,7 +2394,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['a'], isAsset: false, @@ -2399,7 +2403,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'a', + id: 'a.js', path: 'C:\\root\\a.js', dependencies: ['b'], isAsset: false, @@ -2408,7 +2412,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'b', + id: 'b.js', path: 'C:\\root\\b.js', dependencies: [], isAsset: false, @@ -2486,7 +2490,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['./imgs/a.png', './imgs/b.png', './imgs/c.png'], isAsset: false, @@ -2580,28 +2584,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: ['bar'], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules/foo/node_modules/bar/main.js', path: '/root/node_modules/foo/node_modules/bar/main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules/bar/main.js', path: '/root/node_modules/bar/main.js', dependencies: [], isAsset: false, @@ -2649,21 +2653,21 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: '/root/index.ios.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/index.ios.js', + id: 'node_modules/foo/index.ios.js', path: '/root/node_modules/foo/index.ios.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.ios.js', + id: 'node_modules/bar/main.ios.js', path: '/root/node_modules/bar/main.ios.js', dependencies: [], isAsset: false, @@ -2721,28 +2725,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo', 'bar/'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: ['bar/lol'], isAsset: false, isPolyfill: false, }, { - id: 'bar/lol.js', + id: 'node_modules/foo/node_modules/bar/lol.js', path: '/root/node_modules/foo/node_modules/bar/lol.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules/bar/main.js', path: '/root/node_modules/bar/main.js', dependencies: [], isAsset: false, @@ -2804,28 +2808,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: ['bar/lol'], isAsset: false, isPolyfill: false, }, { - id: 'bar/lol.js', + id: 'node_modules/foo/node_modules/bar/lol.js', path: '/root/node_modules/foo/node_modules/bar/lol.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main2.js', + id: 'node_modules/bar/main2.js', path: '/root/node_modules/bar/main2.js', dependencies: [], isAsset: false, @@ -2876,21 +2880,21 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['bar'], isAsset: false, isPolyfill: false, }, { - id: 'bar', + id: 'path/to/bar.js', path: '/root/path/to/bar.js', dependencies: ['foo'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: [], isAsset: false, @@ -3023,7 +3027,7 @@ describe('traverseDependencies', function() { .then(deps => { expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: [ 'shouldWork', @@ -3035,14 +3039,14 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'shouldWork', + id: 'node_modules/react-haste/main.js', path: '/root/node_modules/react-haste/main.js', dependencies: ['submodule'], isAsset: false, isPolyfill: false, }, { - id: 'submodule/main.js', + id: 'node_modules/react-haste/node_modules/submodule/main.js', path: '/root/node_modules/react-haste/node_modules/submodule/main.js', dependencies: [], @@ -3050,21 +3054,21 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'ember/main.js', + id: 'node_modules/ember/main.js', path: '/root/node_modules/ember/main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'internalVendoredPackage', + id: 'vendored_modules/a-vendored-package/main.js', path: '/root/vendored_modules/a-vendored-package/main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'anotherIndex', + id: 'index.js', path: '/anotherRoot/index.js', dependencies: [], isAsset: false, @@ -3107,14 +3111,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/react-haste/index.js', dependencies: ['shouldWork'], isAsset: false, isPolyfill: false, }, { - id: 'shouldWork', + id: 'node_modules/react-haste/main.js', path: '/react-haste/node_modules/react-haste/main.js', dependencies: [], isAsset: false, @@ -3154,14 +3158,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['sha.js'], isAsset: false, isPolyfill: false, }, { - id: 'sha.js/main.js', + id: 'node_modules/sha.js/main.js', path: '/root/node_modules/sha.js/main.js', dependencies: [], isAsset: false, @@ -3208,14 +3212,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: '/root/index.ios.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.ios.js', path: '/root/a.ios.js', dependencies: [], isAsset: false, @@ -3265,14 +3269,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: '/root/index.ios.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.js', path: '/root/a.js', dependencies: [], isAsset: false, @@ -3307,7 +3311,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: '/root/index.ios.js', dependencies: ['./a'], isAsset: false, @@ -3361,28 +3365,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo/package.json', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/package.json', + id: 'node_modules/foo/package.json', path: '/root/node_modules/foo/package.json', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules/bar/main.js', path: '/root/node_modules/bar/main.js', dependencies: ['./package.json'], isAsset: false, isPolyfill: false, }, { - id: 'bar/package.json', + id: 'node_modules/bar/package.json', path: '/root/node_modules/bar/package.json', dependencies: [], isAsset: false, @@ -3421,7 +3425,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'a/index.js', + id: 'node_modules/a/index.js', path: '/root/node_modules/a/index.js', dependencies: [], isAsset: false, @@ -3505,28 +3509,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules\\foo\\main.js', path: 'C:\\root\\node_modules\\foo\\main.js', dependencies: ['bar'], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules\\foo\\node_modules\\bar\\main.js', path: 'C:\\root\\node_modules\\foo\\node_modules\\bar\\main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules\\bar\\main.js', path: 'C:\\root\\node_modules\\bar\\main.js', dependencies: [], isAsset: false, @@ -3574,21 +3578,21 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: 'C:\\root\\index.ios.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/index.ios.js', + id: 'node_modules\\foo\\index.ios.js', path: 'C:\\root\\node_modules\\foo\\index.ios.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.ios.js', + id: 'node_modules\\bar\\main.ios.js', path: 'C:\\root\\node_modules\\bar\\main.ios.js', dependencies: [], isAsset: false, @@ -3646,28 +3650,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['foo', 'bar/'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules\\foo\\main.js', path: 'C:\\root\\node_modules\\foo\\main.js', dependencies: ['bar/lol'], isAsset: false, isPolyfill: false, }, { - id: 'bar/lol.js', + id: 'node_modules\\foo\\node_modules\\bar\\lol.js', path: 'C:\\root\\node_modules\\foo\\node_modules\\bar\\lol.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules\\bar\\main.js', path: 'C:\\root\\node_modules\\bar\\main.js', dependencies: [], isAsset: false, @@ -3729,28 +3733,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['foo', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules\\foo\\main.js', path: 'C:\\root\\node_modules\\foo\\main.js', dependencies: ['bar/lol'], isAsset: false, isPolyfill: false, }, { - id: 'bar/lol.js', + id: 'node_modules\\foo\\node_modules\\bar\\lol.js', path: 'C:\\root\\node_modules\\foo\\node_modules\\bar\\lol.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main2.js', + id: 'node_modules\\bar\\main2.js', path: 'C:\\root\\node_modules\\bar\\main2.js', dependencies: [], isAsset: false, @@ -3801,21 +3805,21 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['bar'], isAsset: false, isPolyfill: false, }, { - id: 'bar', + id: 'path\\to\\bar.js', path: 'C:\\root\\path\\to\\bar.js', dependencies: ['foo'], isAsset: false, isPolyfill: false, }, { - id: 'foo/main.js', + id: 'node_modules\\foo\\main.js', path: 'C:\\root\\node_modules\\foo\\main.js', dependencies: [], isAsset: false, @@ -3948,7 +3952,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: [ 'shouldWork', @@ -3960,14 +3964,14 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'shouldWork', + id: 'node_modules\\react-haste\\main.js', path: 'C:\\root\\node_modules\\react-haste\\main.js', dependencies: ['submodule'], isAsset: false, isPolyfill: false, }, { - id: 'submodule/main.js', + id: 'node_modules\\react-haste\\node_modules\\submodule\\main.js', path: 'C:\\root\\node_modules\\react-haste\\node_modules\\submodule\\main.js', dependencies: [], @@ -3975,21 +3979,21 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'ember/main.js', + id: 'node_modules\\ember\\main.js', path: 'C:\\root\\node_modules\\ember\\main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'internalVendoredPackage', + id: 'vendored_modules\\a-vendored-package\\main.js', path: 'C:\\root\\vendored_modules\\a-vendored-package\\main.js', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'anotherIndex', + id: 'index.js', path: 'C:\\anotherRoot\\index.js', dependencies: [], isAsset: false, @@ -4031,14 +4035,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\react-haste\\index.js', dependencies: ['shouldWork'], isAsset: false, isPolyfill: false, }, { - id: 'shouldWork', + id: 'node_modules\\react-haste\\main.js', path: 'C:\\react-haste\\node_modules\\react-haste\\main.js', dependencies: [], isAsset: false, @@ -4078,14 +4082,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['sha.js'], isAsset: false, isPolyfill: false, }, { - id: 'sha.js/main.js', + id: 'node_modules\\sha.js\\main.js', path: 'C:\\root\\node_modules\\sha.js\\main.js', dependencies: [], isAsset: false, @@ -4132,14 +4136,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: 'C:\\root\\index.ios.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.ios.js', path: 'C:\\root\\a.ios.js', dependencies: [], isAsset: false, @@ -4185,14 +4189,14 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: 'C:\\root\\index.ios.js', dependencies: ['a'], isAsset: false, isPolyfill: false, }, { - id: 'a', + id: 'a.js', path: 'C:\\root\\a.js', dependencies: [], isAsset: false, @@ -4227,7 +4231,7 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.ios.js', path: 'C:\\root\\index.ios.js', dependencies: ['./a'], isAsset: false, @@ -4281,28 +4285,28 @@ describe('traverseDependencies', function() { ); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: 'C:\\root\\index.js', dependencies: ['foo/package.json', 'bar'], isAsset: false, isPolyfill: false, }, { - id: 'foo/package.json', + id: 'node_modules\\foo\\package.json', path: 'C:\\root\\node_modules\\foo\\package.json', dependencies: [], isAsset: false, isPolyfill: false, }, { - id: 'bar/main.js', + id: 'node_modules\\bar\\main.js', path: 'C:\\root\\node_modules\\bar\\main.js', dependencies: ['./package.json'], isAsset: false, isPolyfill: false, }, { - id: 'bar/package.json', + id: 'node_modules\\bar\\package.json', path: 'C:\\root\\node_modules\\bar\\package.json', dependencies: [], isAsset: false, @@ -4370,7 +4374,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -4427,7 +4431,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -4535,7 +4539,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage', 'foo'], isAsset: false, @@ -4549,7 +4553,7 @@ describe('traverseDependencies', function() { isPolyfill: false, }, { - id: 'bar', + id: 'bar.js', path: '/root/bar.js', dependencies: ['foo'], isAsset: false, @@ -4557,7 +4561,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'foo', + id: 'foo.js', path: '/root/foo.js', dependencies: ['aPackage'], isAsset: false, @@ -4603,7 +4607,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['./foo.png'], isAsset: false, @@ -4661,7 +4665,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['aPackage'], isAsset: false, @@ -4727,7 +4731,7 @@ describe('traverseDependencies', function() { expect(deps).toEqual([ { dependencies: ['bPackage'], - id: 'index', + id: 'index.js', isAsset: false, isPolyfill: false, path: '/root/index.js', @@ -4735,7 +4739,7 @@ describe('traverseDependencies', function() { }, { dependencies: [], - id: 'bPackage/main.js', + id: 'aPackage/main.js', isAsset: false, isPolyfill: false, path: '/root/aPackage/main.js', @@ -4782,7 +4786,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo'], isAsset: false, @@ -4790,7 +4794,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: ['bar'], isAsset: false, @@ -4798,7 +4802,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'bar/main.js', + id: 'node_modules/foo/node_modules/bar/main.js', path: '/root/node_modules/foo/node_modules/bar/main.js', dependencies: [], isAsset: false, @@ -4813,7 +4817,7 @@ describe('traverseDependencies', function() { const deps2 = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps2).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo'], isAsset: false, @@ -4821,7 +4825,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'foo/main.js', + id: 'node_modules/foo/main.js', path: '/root/node_modules/foo/main.js', dependencies: [], isAsset: false, @@ -4874,7 +4878,7 @@ describe('traverseDependencies', function() { const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath); expect(deps).toEqual([ { - id: 'index', + id: 'index.js', path: '/root/index.js', dependencies: ['foo'], isAsset: false, @@ -4882,7 +4886,7 @@ describe('traverseDependencies', function() { resolveDependency: undefined, }, { - id: 'foo/browser.js', + id: 'node_modules/foo/browser.js', path: '/root/node_modules/foo/browser.js', dependencies: [], isAsset: false, @@ -4984,14 +4988,14 @@ describe('traverseDependencies', function() { expect(deps).toEqual([ { dependencies: ['a'], - id: 'index', + id: 'index.jsx', isAsset: false, isPolyfill: false, path: '/root/index.jsx', }, { dependencies: [], - id: 'a', + id: 'a.coffee', isAsset: false, isPolyfill: false, path: '/root/a.coffee', @@ -5288,7 +5292,7 @@ describe('traverseDependencies', function() { function setMockFileSystem(object) { const fs = require('fs'); - const root = process.platform === 'win32' ? 'c:\\' : '/'; + const root = process.platform === 'win32' ? 'C:\\' : '/'; mockDir(fs, root, {...object, tmp: {}}); } diff --git a/packages/metro/src/node-haste/AssetModule.js b/packages/metro/src/node-haste/AssetModule.js index 9d683877..48488064 100644 --- a/packages/metro/src/node-haste/AssetModule.js +++ b/packages/metro/src/node-haste/AssetModule.js @@ -12,9 +12,6 @@ const Module = require('./Module'); -import type {TransformedCode} from '../JSTransformer/worker'; -import type {ReadResult} from './Module'; - class AssetModule extends Module { getPackage() { return null; @@ -28,12 +25,12 @@ class AssetModule extends Module { return true; } - _finalizeReadResult(source: string, result: TransformedCode): ReadResult { + _readSourceCode() { // We do not want to return the "source code" of assets, since it's going to // be binary data and can potentially be very large. This source property // is only used to generate the sourcemaps (since we include all the // modules original sources in the sourcemaps). - return {...result, source: ''}; + return ''; } } diff --git a/packages/metro/src/node-haste/Module.js b/packages/metro/src/node-haste/Module.js index dac5a077..dc9ab582 100644 --- a/packages/metro/src/node-haste/Module.js +++ b/packages/metro/src/node-haste/Module.js @@ -10,26 +10,13 @@ 'use strict'; -const crypto = require('crypto'); -const docblock = require('jest-docblock'); const fs = require('fs'); -const invariant = require('fbjs/lib/invariant'); const isAbsolutePath = require('absolute-path'); -const jsonStableStringify = require('json-stable-stringify'); -const path = require('path'); import type { TransformedCode, Options as WorkerOptions, } from '../JSTransformer/worker'; -import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; -import type { - TransformCache, - GetTransformCacheKey, - ReadTransformProps, -} from '../lib/TransformCaching'; -import type {Reporter} from '../lib/reporting'; -import type DependencyGraphHelpers from './DependencyGraph/DependencyGraphHelpers'; import type ModuleCache from './ModuleCache'; import type {LocalPath} from './lib/toLocalPath'; import type {MetroSourceMapSegmentTuple} from 'metro-source-map'; @@ -49,67 +36,23 @@ export type TransformCode = ( transformOptions: WorkerOptions, ) => Promise; -export type HasteImpl = { - getHasteName(filePath: string): string | void, - // This exists temporarily to enforce consistency while we deprecate - // @providesModule. - enforceHasteNameMatches?: ( - filePath: string, - expectedName: string | void, - ) => void, -}; - -export type Options = { - globalTransformCache: ?GlobalTransformCache, - hasteImplModulePath?: string, - reporter: Reporter, - resetCache: boolean, - transformCache: TransformCache, -}; - export type ConstructorArgs = { - depGraphHelpers: DependencyGraphHelpers, - experimentalCaches: boolean, file: string, - getTransformCacheKey: GetTransformCacheKey, localPath: LocalPath, moduleCache: ModuleCache, - options: Options, transformCode: TransformCode, }; -type DocBlock = {+[key: string]: string}; - class Module { localPath: LocalPath; path: string; type: string; - _experimentalCaches: boolean; - _moduleCache: ModuleCache; _transformCode: TransformCode; - _getTransformCacheKey: GetTransformCacheKey; - _depGraphHelpers: DependencyGraphHelpers; - _options: Options; - - _docBlock: ?DocBlock; - _hasteNameCache: ?{+hasteName: ?string}; _sourceCode: ?string; - _readPromises: Map>; - _readResultsByOptionsKey: Map; - - constructor({ - depGraphHelpers, - experimentalCaches, - file, - getTransformCacheKey, - localPath, - moduleCache, - options, - transformCode, - }: ConstructorArgs) { + constructor({file, localPath, moduleCache, transformCode}: ConstructorArgs) { if (!isAbsolutePath(file)) { throw new Error('Expected file to be absolute path but got ' + file); } @@ -118,295 +61,59 @@ class Module { this.path = file; this.type = 'Module'; - this._experimentalCaches = experimentalCaches; - this._moduleCache = moduleCache; this._transformCode = transformCode; - this._getTransformCacheKey = getTransformCacheKey; - this._depGraphHelpers = depGraphHelpers; - this._options = options || {}; - - this._readPromises = new Map(); - this._readResultsByOptionsKey = new Map(); } isHaste(): boolean { - return this._getHasteName() != null; + return false; } getName(): string { - // TODO: T26134860 Used for debugging purposes only; disabled with the new - // caches. - if (this._experimentalCaches) { - return path.basename(this.path); - } - - if (this.isHaste()) { - const name = this._getHasteName(); - if (name != null) { - return name; - } - } - - const p = this.getPackage(); - - if (!p) { - // Name is local path - return this.localPath; - } - - const packageName = p.getName(); - if (!packageName) { - return this.path; - } - - return path - .join(packageName, path.relative(p.root, this.path)) - .replace(/\\/g, '/'); + return this.localPath; } getPackage() { return this._moduleCache.getPackageForModule(this); } - /** - * We don't need to invalidate the TranformCache itself because it guarantees - * itself that if a source code changed we won't return the cached transformed - * code. - */ invalidate() { this._sourceCode = null; - - // TODO: T26134860 Caches present in Module are not used with experimental - // caches, except for the one related to source code. - if (this._experimentalCaches) { - return; - } - - this._readPromises.clear(); - this._readResultsByOptionsKey.clear(); - this._docBlock = null; - this._hasteNameCache = null; } _readSourceCode(): string { if (this._sourceCode == null) { this._sourceCode = fs.readFileSync(this.path, 'utf8'); } + return this._sourceCode; } - _readDocBlock(): DocBlock { - if (this._docBlock == null) { - this._docBlock = docblock.parse(docblock.extract(this._readSourceCode())); - } - return this._docBlock; + async read(transformOptions: WorkerOptions): Promise { + const result: TransformedCode = await this._transformCode( + this, + null, // Source code is read on the worker + transformOptions, + ); + + const module = this; + + return { + code: result.code, + dependencies: result.dependencies, + map: result.map, + get source() { + return module._readSourceCode(); + }, + }; } - _getHasteName(): ?string { - if (this._hasteNameCache == null) { - this._hasteNameCache = {hasteName: this._readHasteName()}; - } - return this._hasteNameCache.hasteName; - } - - /** - * If a custom Haste implementation is provided, then we use it to determine - * the actual Haste name instead of "@providesModule". - * `enforceHasteNameMatches` has been added to that it is easier to - * transition from a system using "@providesModule" to a system using another - * custom system, by throwing if inconsistencies are detected. For example, - * we could verify that the file's basename (ex. "bar/foo.js") is the same as - * the "@providesModule" name (ex. "foo"). - */ - _readHasteName(): ?string { - const hasteImplModulePath = this._options.hasteImplModulePath; - if (hasteImplModulePath == null) { - return this._readHasteNameFromDocBlock(); - } - // eslint-disable-next-line no-useless-call - const HasteImpl = (require.call(null, hasteImplModulePath): HasteImpl); - if (HasteImpl.enforceHasteNameMatches != null) { - const name = this._readHasteNameFromDocBlock(); - HasteImpl.enforceHasteNameMatches(this.path, name || undefined); - } - return HasteImpl.getHasteName(this.path); - } - - /** - * We extract the Haste name from the `@providesModule` docbloc field. This is - * not allowed for modules living in `node_modules`, except if they are - * whitelisted. - */ - _readHasteNameFromDocBlock(): ?string { - const moduleDocBlock = this._readDocBlock(); - const {providesModule} = moduleDocBlock; - if (providesModule && !this._depGraphHelpers.isNodeModulesDir(this.path)) { - return /^\S+/.exec(providesModule)[0]; - } + readCached(transformOptions: WorkerOptions): null { return null; } - /** - * To what we read from the cache or worker, we need to add id and source. - */ - _finalizeReadResult(source: string, result: TransformedCode): ReadResult { - return {...result, source}; - } - - async _transformCodeFor( - cacheProps: ReadTransformProps, - ): Promise { - const {_transformCode} = this; - invariant(_transformCode != null, 'missing code transform funtion'); - const {sourceCode, transformOptions} = cacheProps; - return await _transformCode(this, sourceCode, transformOptions); - } - - async _transformAndStoreCodeGlobally( - cacheProps: ReadTransformProps, - globalCache: GlobalTransformCache, - ): Promise { - const result = await this._transformCodeFor(cacheProps); - globalCache.store(globalCache.keyOf(cacheProps), result); - return result; - } - - async _getTransformedCode( - cacheProps: ReadTransformProps, - ): Promise { - const globalCache = this._options.globalTransformCache; - if (globalCache == null || !globalCache.shouldFetch(cacheProps)) { - return await this._transformCodeFor(cacheProps); - } - const globalCachedResult = await globalCache.fetch( - globalCache.keyOf(cacheProps), - ); - if (globalCachedResult != null) { - return globalCachedResult; - } - return await this._transformAndStoreCodeGlobally(cacheProps, globalCache); - } - - async _getAndCacheTransformedCode( - cacheProps: ReadTransformProps, - ): Promise { - const result = await this._getTransformedCode(cacheProps); - this._options.transformCache.writeSync({...cacheProps, result}); - return result; - } - - /** - * Shorthand for reading both from cache or from fresh for all call sites that - * are asynchronous by default. - */ - async read(transformOptions: WorkerOptions): Promise { - // TODO: T26134860 Cache layer lives inside the transformer now; just call - // the transform method. - if (this._experimentalCaches) { - const result: TransformedCode = await this._transformCode( - this, - null, // Source code is read on the worker - transformOptions, - ); - - const module = this; - - return { - code: result.code, - dependencies: result.dependencies, - map: result.map, - get source() { - return module._readSourceCode(); - }, - }; - } - - const cached = this.readCached(transformOptions); - - if (cached != null) { - return cached; - } - return this.readFresh(transformOptions); - } - - /** - * Same as `readFresh`, but reads from the cache instead of transforming - * the file from source. This has the benefit of being synchronous. As a - * result it is possible to read many cached Module in a row, synchronously. - */ - readCached(transformOptions: WorkerOptions): CachedReadResult { - const key = stableObjectHash(transformOptions || {}); - let result = this._readResultsByOptionsKey.get(key); - if (result != null) { - return result; - } - result = this._readFromTransformCache(transformOptions, key); - this._readResultsByOptionsKey.set(key, result); - return result; - } - - /** - * Read again from the TransformCache, on disk. `readCached` should be favored - * so it's faster in case the results are already in memory. - */ - _readFromTransformCache( - transformOptions: WorkerOptions, - transformOptionsKey: string, - ): CachedReadResult { - const cacheProps = this._getCacheProps( - transformOptions, - transformOptionsKey, - ); - const cachedResult = this._options.transformCache.readSync(cacheProps); - - if (cachedResult == null) { - return null; - } - return this._finalizeReadResult(cacheProps.sourceCode, cachedResult); - } - - /** - * Gathers relevant data about a module: source code, transformed code, - * dependencies, etc. This function reads and transforms the source from - * scratch. We don't repeat the same work as `readCached` because we assume - * call sites have called it already. - */ readFresh(transformOptions: WorkerOptions): Promise { - const key = stableObjectHash(transformOptions || {}); - const promise = this._readPromises.get(key); - if (promise != null) { - return promise; - } - const freshPromise = (async () => { - const cacheProps = this._getCacheProps(transformOptions, key); - const freshResult = await this._getAndCacheTransformedCode(cacheProps); - const finalResult = this._finalizeReadResult( - cacheProps.sourceCode, - freshResult, - ); - this._readResultsByOptionsKey.set(key, finalResult); - return finalResult; - })(); - this._readPromises.set(key, freshPromise); - return freshPromise; - } - - _getCacheProps(transformOptions: WorkerOptions, transformOptionsKey: string) { - const sourceCode = this._readSourceCode(); - const getTransformCacheKey = this._getTransformCacheKey; - return { - filePath: this.path, - localPath: this.localPath, - sourceCode, - getTransformCacheKey, - transformOptions, - transformOptionsKey, - cacheOptions: { - resetCache: this._options.resetCache, - reporter: this._options.reporter, - }, - }; + return this.read(transformOptions); } hash() { @@ -422,19 +129,4 @@ class Module { } } -// use weak map to speed up hash creation of known objects -const knownHashes = new WeakMap(); -function stableObjectHash(object) { - let digest = knownHashes.get(object); - if (!digest) { - digest = crypto - .createHash('md5') - .update(jsonStableStringify(object)) - .digest('base64'); - knownHashes.set(object, digest); - } - - return digest; -} - module.exports = Module; diff --git a/packages/metro/src/node-haste/__tests__/Module-test.js b/packages/metro/src/node-haste/__tests__/Module-test.js index 934e8688..73158df4 100644 --- a/packages/metro/src/node-haste/__tests__/Module-test.js +++ b/packages/metro/src/node-haste/__tests__/Module-test.js @@ -10,363 +10,94 @@ 'use strict'; -jest - .mock('fs', () => new (require('metro-memory-fs'))()) - .mock('graceful-fs') - .mock('../ModuleCache') - .mock('../DependencyGraph/DependencyGraphHelpers') - .mock('../../lib/TransformCaching'); +jest.mock('fs').mock('../ModuleCache'); -const Module = require('../Module'); -const ModuleCache = require('../ModuleCache'); -const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers'); -const TransformCaching = require('../../lib/TransformCaching'); const fs = require('fs'); - -const packageJson = JSON.stringify({ - name: 'arbitrary', - version: '1.0.0', - description: "A require('foo') story", -}); - -function mockPackageFile() { - fs.reset(); - fs.mkdirSync('/root'); - fs.writeFileSync('/root/package.json', packageJson); -} - -function mockIndexFile(indexJs) { - fs.reset(); - fs.mkdirSync('/root'); - fs.writeFileSync('/root/index.js', indexJs); -} +const ModuleCache = require('../ModuleCache'); +const Module = require('../Module'); describe('Module', () => { - const fileName = '/root/index.js'; + let transformCode; + let moduleCache; + let module; - let cache; - const transformCache = TransformCaching.mocked(); - - const createCache = () => ({ - get: jest - .genMockFn() - .mockImplementation((filepath, field, cb) => cb(filepath)), - invalidate: jest.genMockFn(), - end: jest.genMockFn(), - }); - - let transformCacheKey; - const createModule = options => - new Module({ - options: {transformCache}, - transformCode: (module, sourceCode, transformOptions) => { - return Promise.resolve({code: sourceCode}); - }, - ...options, - cache, - file: (options && options.file) || fileName, - depGraphHelpers: new DependencyGraphHelpers(), - localPath: (options && options.localPath) || fileName, - moduleCache: new ModuleCache({cache}), - getTransformCacheKey: () => transformCacheKey, + beforeEach(() => { + transformCode = jest.fn().mockReturnValue({ + code: 'int main(void) { return -1; }', + dependencies: ['stdlib.h', 'conio.h'], + map: [], }); - const createJSONModule = options => - createModule({...options, file: '/root/package.json'}); + moduleCache = new ModuleCache(); - beforeEach(function() { - Object.defineProperty(process, 'platform', { - configurable: true, - enumerable: true, - value: 'linux', - }); - cache = createCache(); - transformCacheKey = 'abcdef'; - transformCache.mock.reset(); - }); - - describe('Experimental caches', () => { - it('Calls into the transformer directly when having experimental caches on', async () => { - const transformCode = jest.fn().mockReturnValue({ - code: 'code', - dependencies: ['dep1', 'dep2'], - map: [], - }); - - const module = new Module({ - cache, - experimentalCaches: true, - depGraphHelpers: new DependencyGraphHelpers(), - file: fileName, - getTransformCacheKey: () => transformCacheKey, - localPath: fileName, - moduleCache: new ModuleCache({cache}), - options: {transformCache}, - transformCode, - }); - - mockIndexFile('originalCode'); - jest.spyOn(fs, 'readFileSync'); - - // Read the first time, transform code is called. - const res1 = await module.read({foo: 3}); - expect(res1.code).toBe('code'); - expect(res1.dependencies).toEqual(['dep1', 'dep2']); - expect(transformCode).toHaveBeenCalledTimes(1); - - // Read a second time, transformCode is called again! - const res2 = await module.read({foo: 3}); - expect(res2.code).toBe('code'); - expect(res2.dependencies).toEqual(['dep1', 'dep2']); - expect(transformCode).toHaveBeenCalledTimes(2); - - // Code was never read, though, because experimental caches read on the - // worker, to speed up local cache! - expect(fs.readFileSync).not.toHaveBeenCalled(); + module = new Module({ + file: '/root/to/file.js', + localPath: 'file.js', + moduleCache, + transformCode, }); }); - describe('Module ID', () => { - const moduleId = 'arbitraryModule'; - const source = `/** - * @providesModule ${moduleId} - */ - `; + afterEach(() => { + fs.readFileSync.mockReset(); + }); - let module; - beforeEach(() => { - module = createModule(); - }); + it('Returns the correct values for many properties and methods', () => { + expect(module.localPath).toBe('file.js'); + expect(module.path).toBe('/root/to/file.js'); + expect(module.type).toBe('Module'); - describe('@providesModule annotations', () => { - beforeEach(() => { - mockIndexFile(source); - }); + expect(module.hash()).toBeDefined(); + expect(module.getName()).toBe('file.js'); + expect(module.isHaste()).toBe(false); + expect(module.isAsset()).toBe(false); + expect(module.isPolyfill()).toBe(false); + }); - it('extracts the module name from the header', () => { - expect(module.getName()).toEqual(moduleId); - }); + it('reads the modules correctly', () => { + const opts = {}; - it('identifies the module as haste module', () => { - expect(module.isHaste()).toBe(true); - }); + // Caches are not in Module.js anymore. + expect(module.readCached()).toBe(null); - it('does not transform the file in order to access the name', () => { - const transformCode = jest - .genMockFn() - .mockReturnValue(Promise.resolve()); + // When reading fresh, we call directly into read. + module.readFresh(opts); + expect(transformCode.mock.calls[0][0]).toBe(module); + expect(transformCode.mock.calls[0][1]).toBe(null); + expect(transformCode.mock.calls[0][2]).toBe(opts); + }); - createModule({transformCode}).getName(); - expect(transformCode).not.toBeCalled(); - }); + it('returns the result from the transform code straight away', async () => { + fs.readFileSync.mockReturnValue('original code'); - it('does not transform the file in order to access the haste status', () => { - const transformCode = jest - .genMockFn() - .mockReturnValue(Promise.resolve()); - createModule({transformCode}).isHaste(); - expect(transformCode).not.toBeCalled(); - }); - }); - - describe('no annotation', () => { - beforeEach(() => { - mockIndexFile('arbitrary(code);'); - }); - - it('uses the file name as module name', () => { - expect(module.getName()).toEqual(fileName); - }); - - it('does not identify the module as haste module', () => - expect(module.isHaste()).toBe(false)); - - it('does not transform the file in order to access the name', () => { - const transformCode = jest - .genMockFn() - .mockReturnValue(Promise.resolve()); - - createModule({transformCode}).getName(); - expect(transformCode).not.toBeCalled(); - }); - - it('does not transform the file in order to access the haste status', () => { - const transformCode = jest - .genMockFn() - .mockReturnValue(Promise.resolve()); - createModule({transformCode}).isHaste(); - expect(transformCode).not.toBeCalled(); - }); + expect(await module.read({})).toEqual({ + code: 'int main(void) { return -1; }', + dependencies: ['stdlib.h', 'conio.h'], + map: [], + source: 'original code', }); }); - describe('Code', () => { - const fileContents = 'arbitrary(code)'; - beforeEach(function() { - mockIndexFile(fileContents); - }); + it('checks that code is only read once until invalidated', async () => { + fs.readFileSync.mockReturnValue('original code'); - it('exposes file contents as `code` property on the data exposed by `read()`', () => - createModule() - .read() - .then(({code}) => expect(code).toBe(fileContents))); - }); + // Read once. No access to "source", so no reads. + await module.read({}); + expect(fs.readFileSync).toHaveBeenCalledTimes(0); - describe('Custom Code Transform', () => { - let transformCode; - let transformResult; - const fileContents = 'arbitrary(code);'; - const exampleCode = ` - ${'require'}('a'); - ${'System.import'}('b'); - ${'require'}('c');`; + // Read again, accessing "source". + expect((await module.read({})).source).toEqual('original code'); + expect(fs.readFileSync).toHaveBeenCalledTimes(1); - beforeEach(function() { - transformResult = {code: ''}; - transformCode = jest - .genMockFn() - .mockImplementation((module, sourceCode, options) => { - transformCache.writeSync({ - filePath: module.path, - sourceCode, - transformOptions: options, - getTransformCacheKey: () => transformCacheKey, - result: transformResult, - }); - return Promise.resolve(transformResult); - }); - mockIndexFile(fileContents); - }); + // Read again, accessing "source" again. Still 1 because code was cached. + expect((await module.read({})).source).toEqual('original code'); + expect(fs.readFileSync).toHaveBeenCalledTimes(1); - it('passes the module and file contents to the transform function when reading', () => { - const module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toBeCalledWith(module, fileContents, undefined); - }); - }); + // Invalidate. + module.invalidate(); - it('passes any additional options to the transform function when reading', () => { - const module = createModule({transformCode}); - const transformOptions = {arbitrary: Object()}; - return module - .read(transformOptions) - .then(() => - expect(transformCode.mock.calls[0][2]).toBe(transformOptions), - ); - }); - - it('passes the module and file contents to the transform for JSON files', () => { - mockPackageFile(); - const module = createJSONModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toBeCalledWith(module, packageJson, undefined); - }); - }); - - it('does not extend the passed options object for JSON files', () => { - mockPackageFile(); - const module = createJSONModule({transformCode}); - const options = {arbitrary: 'foo'}; - return module.read(options).then(() => { - expect(transformCode).toBeCalledWith(module, packageJson, options); - }); - }); - - it('uses dependencies that `transformCode` resolves to, instead of extracting them', async () => { - const mockedDependencies = ['foo', 'bar']; - transformResult = { - code: exampleCode, - dependencies: mockedDependencies, - }; - const module = createModule({transformCode}); - const data = await module.read(); - - expect(data.dependencies).toEqual(mockedDependencies); - }); - - it('forwards all additional properties of the result provided by `transformCode`', () => { - transformResult = { - code: exampleCode, - arbitrary: 'arbitrary', - dependencyOffsets: [12, 764], - map: {version: 3}, - subObject: {foo: 'bar'}, - }; - const module = createModule({transformCode}); - - return module.read().then(result => { - expect(result).toEqual(jasmine.objectContaining(transformResult)); - }); - }); - - it('exposes the transformed code rather than the raw file contents', async () => { - transformResult = {code: exampleCode}; - const module = createModule({transformCode}); - const data = await module.read(); - - expect(data.code).toBe(exampleCode); - }); - - it('exposes the raw file contents as `source` property', () => { - const module = createModule({transformCode}); - return module.read().then(data => expect(data.source).toBe(fileContents)); - }); - - it('exposes a source map returned by the transform', async () => { - const map = {version: 3}; - transformResult = {map, code: exampleCode}; - const module = createModule({transformCode}); - const data = await module.read(); - - expect(data.map).toBe(map); - }); - - it('caches the transform result for the same transform options', () => { - let module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(1); - // We want to check transform caching rather than shallow caching of - // Promises returned by read(). - module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(1); - }); - }); - }); - - it('triggers a new transform for different transform options', () => { - const module = createModule({transformCode}); - return module.read({foo: 1}).then(() => { - expect(transformCode).toHaveBeenCalledTimes(1); - return module.read({foo: 2}).then(() => { - expect(transformCode).toHaveBeenCalledTimes(2); - }); - }); - }); - - it('triggers a new transform for different source code', () => { - let module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(1); - cache = createCache(); - mockIndexFile('test'); - module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(2); - }); - }); - }); - - it('triggers a new transform for different transform cache key', () => { - let module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(1); - transformCacheKey = 'other'; - module = createModule({transformCode}); - return module.read().then(() => { - expect(transformCode).toHaveBeenCalledTimes(2); - }); - }); - }); + // Read again, this time it will read it. + expect((await module.read({})).source).toEqual('original code'); + expect(fs.readFileSync).toHaveBeenCalledTimes(2); }); });