diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 4ebb85ec3..a7200713a 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -122,16 +122,16 @@ "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz" }, - "ast-types": { - "version": "0.8.12", - "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz" - }, "babylon": { "version": "5.8.29", "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz", "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz" }, + "ast-types": { + "version": "0.8.12", + "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz" + }, "globals": { "version": "6.4.1", "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", @@ -248,15 +248,15 @@ "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz" }, - "regenerator": { - "version": "0.8.40", - "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", - "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz" - }, "source-map": { "version": "0.5.3", "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz" + }, + "regenerator": { + "version": "0.8.40", + "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", + "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz" } } }, @@ -1900,16 +1900,16 @@ "from": "abbrev@1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" }, - "ansi": { - "version": "0.3.0", - "from": "ansi@~0.3.0", - "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz" - }, "ansi-regex": { "version": "2.0.0", "from": "ansi-regex@^2.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" }, + "ansi": { + "version": "0.3.0", + "from": "ansi@~0.3.0", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz" + }, "ansi-styles": { "version": "2.1.0", "from": "ansi-styles@^2.1.0", @@ -1920,15 +1920,20 @@ "from": "are-we-there-yet@~1.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz" }, + "asn1": { + "version": "0.1.11", + "from": "asn1@0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" + }, "assert-plus": { "version": "0.1.5", "from": "assert-plus@^0.1.5", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" }, - "asn1": { - "version": "0.1.11", - "from": "asn1@0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" + "aws-sign2": { + "version": "0.6.0", + "from": "aws-sign2@~0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" }, "async": { "version": "1.5.0", @@ -1940,46 +1945,41 @@ "from": "balanced-match@>=0.2.0 <0.3.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz" }, - "aws-sign2": { - "version": "0.6.0", - "from": "aws-sign2@~0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" + "block-stream": { + "version": "0.0.8", + "from": "block-stream@*", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz" }, "boom": { "version": "2.10.1", "from": "boom@^2.8.x", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" }, - "block-stream": { - "version": "0.0.8", - "from": "block-stream@*", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz" - }, "brace-expansion": { "version": "1.1.1", "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz" }, - "caseless": { - "version": "0.11.0", - "from": "caseless@~0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" - }, "chalk": { "version": "1.1.1", "from": "chalk@^1.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz" }, - "commander": { - "version": "2.9.0", - "from": "commander@^2.8.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" + "caseless": { + "version": "0.11.0", + "from": "caseless@~0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" }, "combined-stream": { "version": "1.0.5", "from": "combined-stream@~1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz" }, + "commander": { + "version": "2.9.0", + "from": "commander@^2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" + }, "concat-map": { "version": "0.0.1", "from": "concat-map@0.0.1", @@ -2065,26 +2065,26 @@ "from": "graceful-fs@4.1", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz" }, - "graceful-readlink": { - "version": "1.0.1", - "from": "graceful-readlink@>= 1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - }, "har-validator": { "version": "2.0.2", "from": "har-validator@~2.0.2", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz" }, - "has-ansi": { - "version": "2.0.0", - "from": "has-ansi@^2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" + "graceful-readlink": { + "version": "1.0.1", + "from": "graceful-readlink@>= 1.0.0", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" }, "has-unicode": { "version": "1.0.1", "from": "has-unicode@^1.0.0", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz" }, + "has-ansi": { + "version": "2.0.0", + "from": "has-ansi@^2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" + }, "hawk": { "version": "3.1.0", "from": "hawk@~3.1.0", @@ -2100,6 +2100,11 @@ "from": "http-signature@~0.11.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz" }, + "inherits": { + "version": "2.0.1", + "from": "inherits@*", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, "ini": { "version": "1.3.4", "from": "ini@~1.3.0", @@ -2120,36 +2125,31 @@ "from": "isarray@0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" }, - "inherits": { - "version": "2.0.1", - "from": "inherits@*", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - }, - "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + "isstream": { + "version": "0.1.2", + "from": "isstream@~0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" }, "json-stringify-safe": { "version": "5.0.1", "from": "json-stringify-safe@~5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" }, - "isstream": { - "version": "0.1.2", - "from": "isstream@~0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" - }, - "lodash._basetostring": { - "version": "3.0.1", - "from": "lodash._basetostring@^3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" }, "lodash._createpadding": { "version": "3.6.1", "from": "lodash._createpadding@^3.0.0", "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz" }, + "lodash._basetostring": { + "version": "3.0.1", + "from": "lodash._basetostring@^3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" + }, "lodash.pad": { "version": "3.1.1", "from": "lodash.pad@^3.0.0", @@ -2270,16 +2270,16 @@ "from": "strip-json-comments@0.1.x", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz" }, - "supports-color": { - "version": "2.0.0", - "from": "supports-color@^2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - }, "tar": { "version": "2.2.1", "from": "tar@~2.2.0", "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz" }, + "supports-color": { + "version": "2.0.0", + "from": "supports-color@^2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + }, "tough-cookie": { "version": "2.2.0", "from": "tough-cookie@~2.2.0", @@ -2305,6 +2305,28 @@ "from": "xtend@^4.0.0", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" }, + "fstream-ignore": { + "version": "1.0.3", + "from": "fstream-ignore@~1.0.3", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz", + "dependencies": { + "minimatch": { + "version": "3.0.0", + "from": "minimatch@>=3.0.0 <4.0.0" + } + } + }, + "inflight": { + "version": "1.0.4", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "dependencies": { + "once": { + "version": "1.3.2", + "from": "once@>=1.3.0 <2.0.0" + } + } + }, "rc": { "version": "1.1.2", "from": "rc@~1.1.0", @@ -2339,28 +2361,6 @@ } } }, - "inflight": { - "version": "1.0.4", - "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", - "dependencies": { - "once": { - "version": "1.3.2", - "from": "once@>=1.3.0 <2.0.0" - } - } - }, - "fstream-ignore": { - "version": "1.0.3", - "from": "fstream-ignore@~1.0.3", - "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz", - "dependencies": { - "minimatch": { - "version": "3.0.0", - "from": "minimatch@>=3.0.0 <4.0.0" - } - } - }, "bl": { "version": "1.0.0", "from": "bl@~1.0.0", @@ -3928,6 +3928,82 @@ } } }, + "node-haste": { + "version": "2.0.0", + "from": "node-haste@*", + "dependencies": { + "graceful-fs": { + "version": "4.1.3", + "from": "graceful-fs@>=4.1.3 <5.0.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" + }, + "sane": { + "version": "1.3.1", + "from": "sane@>=1.3.1 <2.0.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-1.3.1.tgz", + "dependencies": { + "exec-sh": { + "version": "0.2.0", + "from": "exec-sh@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", + "dependencies": { + "merge": { + "version": "1.2.0", + "from": "merge@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz" + } + } + }, + "fb-watchman": { + "version": "1.9.0", + "from": "fb-watchman@>=1.8.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.0.tgz" + }, + "minimatch": { + "version": "0.2.14", + "from": "minimatch@>=0.2.14 <0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "dependencies": { + "lru-cache": { + "version": "2.7.3", + "from": "lru-cache@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz" + }, + "sigmund": { + "version": "1.0.1", + "from": "sigmund@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz" + } + } + }, + "walker": { + "version": "1.0.7", + "from": "walker@>=1.0.5 <1.1.0", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "dependencies": { + "makeerror": { + "version": "1.0.11", + "from": "makeerror@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "dependencies": { + "tmpl": { + "version": "1.0.4", + "from": "tmpl@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz" + } + } + } + } + }, + "watch": { + "version": "0.10.0", + "from": "watch@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz" + } + } + } + } + }, "normalize-package-data": { "version": "2.3.5", "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", diff --git a/package.json b/package.json index 852ae1cb3..2ed9714e1 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,7 @@ "mkdirp": "^0.5.1", "module-deps": "^3.9.1", "node-fetch": "^1.3.3", + "node-haste": "^2.0.0", "opn": "^3.0.2", "optimist": "^0.6.1", "progress": "^1.1.8", diff --git a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js index 1cb90b334..0172f39b4 100644 --- a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js +++ b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js @@ -1,8 +1,7 @@ 'use strict'; jest - .dontMock('../../DependencyResolver/lib/getPlatformExtension') - .dontMock('../../DependencyResolver/lib/getAssetDataFromName') + .dontMock('node-haste/lib/lib/getPlatformExtension') .dontMock('../'); jest @@ -16,6 +15,11 @@ var crypto = require('crypto'); var fs = require('fs'); describe('AssetServer', () => { + beforeEach(() => { + const NodeHaste = require('node-haste'); + NodeHaste.getAssetDataFromName = require.requireActual('node-haste/lib/lib/getAssetDataFromName'); + }); + describe('assetServer.get', () => { pit('should work for the simple case', () => { const server = new AssetServer({ diff --git a/packager/react-packager/src/AssetServer/index.js b/packager/react-packager/src/AssetServer/index.js index bb411ce6f..71356acf3 100644 --- a/packager/react-packager/src/AssetServer/index.js +++ b/packager/react-packager/src/AssetServer/index.js @@ -13,7 +13,7 @@ const Promise = require('promise'); const crypto = require('crypto'); const declareOpts = require('../lib/declareOpts'); const fs = require('fs'); -const getAssetDataFromName = require('../DependencyResolver/lib/getAssetDataFromName'); +const getAssetDataFromName = require('node-haste').getAssetDataFromName; const path = require('path'); const stat = Promise.denodeify(fs.stat); diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js index 6285fcc28..22696cf59 100644 --- a/packager/react-packager/src/Bundler/index.js +++ b/packager/react-packager/src/Bundler/index.js @@ -13,7 +13,7 @@ const fs = require('fs'); const path = require('path'); const Promise = require('promise'); const ProgressBar = require('progress'); -const Cache = require('../DependencyResolver/Cache'); +const Cache = require('node-haste').Cache; const Transformer = require('../JSTransformer'); const Resolver = require('../Resolver'); const Bundle = require('./Bundle'); diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js deleted file mode 100644 index c2f51fbb2..000000000 --- a/packager/react-packager/src/DependencyResolver/AssetModule.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -const Module = require('./Module'); -const Promise = require('promise'); -const getAssetDataFromName = require('./lib/getAssetDataFromName'); - -class AssetModule extends Module { - constructor(...args) { - super(...args); - const { resolution, name, type } = getAssetDataFromName(this.path); - this.resolution = resolution; - this._name = name; - this._type = type; - } - - isHaste() { - return Promise.resolve(false); - } - - getDependencies() { - return Promise.resolve([]); - } - - read() { - return Promise.resolve({}); - } - - getName() { - return super.getName().then( - id => id.replace(/\/[^\/]+$/, `/${this._name}.${this._type}`) - ); - } - - hash() { - return `AssetModule : ${this.path}`; - } - - isJSON() { - return false; - } - - isAsset() { - return true; - } -} - -module.exports = AssetModule; diff --git a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js b/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js deleted file mode 100644 index 3c4659462..000000000 --- a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -const Module = require('./Module'); -const Promise = require('promise'); -const getAssetDataFromName = require('./lib/getAssetDataFromName'); - -class AssetModule_DEPRECATED extends Module { - constructor(...args) { - super(...args); - const {resolution, name} = getAssetDataFromName(this.path); - this.resolution = resolution; - this.name = name; - } - - isHaste() { - return Promise.resolve(false); - } - - getName() { - return Promise.resolve(`image!${this.name}`); - } - - getDependencies() { - return Promise.resolve([]); - } - - hash() { - return `AssetModule_DEPRECATED : ${this.path}`; - } - - isJSON() { - return false; - } - - isAsset_DEPRECATED() { - return true; - } - - resolution() { - return getAssetDataFromName(this.path).resolution; - } - -} - -module.exports = AssetModule_DEPRECATED; diff --git a/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js b/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js deleted file mode 100644 index 6f7632f66..000000000 --- a/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -class Cache { - get(filepath, field, cb) { - return cb(filepath); - } - - invalidate(filepath) { } - end() { } -} - -module.exports = Cache; diff --git a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js deleted file mode 100644 index 2de2318e4..000000000 --- a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest - .dontMock('absolute-path') - .dontMock('../') - .dontMock('../lib/loadCacheSync') - .dontMock('../lib/getCacheFilePath'); - -jest - .mock('fs') - .setMock('os', { - tmpDir() { return 'tmpDir'; }, - }); - -var Promise = require('promise'); -var fs = require('graceful-fs'); - -var Cache = require('../'); - -describe('Cache', () => { - describe('getting/setting', () => { - pit('calls loader callback for uncached file', () => { - fs.stat.mockImpl((file, callback) => { - callback(null, { - mtime: { - getTime: () => {}, - }, - }); - }); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => Promise.resolve()); - - return cache - .get('/rootDir/someFile', 'field', loaderCb) - .then($ => - expect(loaderCb).toBeCalledWith('/rootDir/someFile') - ); - }); - - pit('supports storing multiple fields', () => { - fs.stat.mockImpl((file, callback) => { - callback(null, { - mtime: { - getTime: () => {}, - }, - }); - }); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var index = 0; - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve(index++) - ); - - return cache - .get('/rootDir/someFile', 'field1', loaderCb) - .then(value => { - expect(value).toBe(0); - return cache - .get('/rootDir/someFile', 'field2', loaderCb) - .then(value2 => expect(value2).toBe(1)); - }); - }); - - pit('gets the value from the loader callback', () => { - fs.stat.mockImpl((file, callback) => - callback(null, { - mtime: { - getTime: () => {}, - }, - }) - ); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('lol') - ); - - return cache - .get('/rootDir/someFile', 'field', loaderCb) - .then(value => expect(value).toBe('lol')); - }); - - pit('caches the value after the first call', () => { - fs.stat.mockImpl((file, callback) => { - callback(null, { - mtime: { - getTime: () => {}, - }, - }); - }); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('lol') - ); - - return cache - .get('/rootDir/someFile', 'field', loaderCb) - .then(() => { - var shouldNotBeCalled = jest.genMockFn(); - return cache.get('/rootDir/someFile', 'field', shouldNotBeCalled) - .then(value => { - expect(shouldNotBeCalled).not.toBeCalled(); - expect(value).toBe('lol'); - }); - }); - }); - - pit('clears old field when getting new field and mtime changed', () => { - var mtime = 0; - fs.stat.mockImpl((file, callback) => { - callback(null, { - mtime: { - getTime: () => mtime++, - }, - }); - }); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('lol' + mtime) - ); - - return cache - .get('/rootDir/someFile', 'field1', loaderCb) - .then(value => cache - .get('/rootDir/someFile', 'field2', loaderCb) - .then(value2 => cache - .get('/rootDir/someFile', 'field1', loaderCb) - .then(value3 => expect(value3).toBe('lol2')) - ) - ); - }); - }); - - describe('loading cache from disk', () => { - var fileStats; - - beforeEach(() => { - fileStats = { - '/rootDir/someFile': { - mtime: { - getTime: () => 22, - }, - }, - '/rootDir/foo': { - mtime: { - getTime: () => 11, - }, - }, - }; - - fs.existsSync.mockImpl(() => true); - - fs.statSync.mockImpl(filePath => fileStats[filePath]); - - fs.readFileSync.mockImpl(() => JSON.stringify({ - '/rootDir/someFile': { - metadata: {mtime: 22}, - data: {field: 'oh hai'}, - }, - '/rootDir/foo': { - metadata: {mtime: 11}, - data: {field: 'lol wat'}, - }, - })); - }); - - pit('should load cache from disk', () => { - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn(); - - return cache - .get('/rootDir/someFile', 'field', loaderCb) - .then(value => { - expect(loaderCb).not.toBeCalled(); - expect(value).toBe('oh hai'); - - return cache - .get('/rootDir/foo', 'field', loaderCb) - .then(val => { - expect(loaderCb).not.toBeCalled(); - expect(val).toBe('lol wat'); - }); - }); - }); - - pit('should not load outdated cache', () => { - fs.stat.mockImpl((file, callback) => - callback(null, { - mtime: { - getTime: () => {}, - }, - }) - ); - - fileStats['/rootDir/foo'].mtime.getTime = () => 123; - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('new value') - ); - - return cache - .get('/rootDir/someFile', 'field', loaderCb) - .then(value => { - expect(loaderCb).not.toBeCalled(); - expect(value).toBe('oh hai'); - - return cache - .get('/rootDir/foo', 'field', loaderCb) - .then(val => { - expect(loaderCb).toBeCalled(); - expect(val).toBe('new value'); - }); - }); - }); - }); - - describe('writing cache to disk', () => { - it('should write cache to disk', () => { - var index = 0; - var mtimes = [10, 20, 30]; - - fs.stat.mockImpl((file, callback) => - callback(null, { - mtime: { - getTime: () => mtimes[index++], - }, - }) - ); - - var cache = new Cache({ - cacheKey: 'cache', - }); - - cache.get('/rootDir/bar', 'field', () => - Promise.resolve('bar value') - ); - cache.get('/rootDir/foo', 'field', () => - Promise.resolve('foo value') - ); - cache.get('/rootDir/baz', 'field', () => - Promise.resolve('baz value') - ); - - // jest has some trouble with promises and timeouts within promises :( - jest.runAllTimers(); - jest.runAllTimers(); - - expect(fs.writeFile).toBeCalled(); - }); - }); - - describe('check for cache presence', () => { - it('synchronously resolves cache presence', () => { - fs.stat.mockImpl((file, callback) => - callback(null, { - mtime: { - getTime: () => {}, - }, - }) - ); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('banana') - ); - var file = '/rootDir/someFile'; - - return cache - .get(file, 'field', loaderCb) - .then(() => { - expect(cache.has(file)).toBe(true); - expect(cache.has(file, 'field')).toBe(true); - expect(cache.has(file, 'foo')).toBe(false); - }); - }); - }); - - describe('invalidate', () => { - it('invalidates the cache per file or per-field', () => { - fs.stat.mockImpl((file, callback) => - callback(null, { - mtime: { - getTime: () => {}, - }, - }) - ); - - var cache = new Cache({ - cacheKey: 'cache', - }); - var loaderCb = jest.genMockFn().mockImpl(() => - Promise.resolve('banana') - ); - var file = '/rootDir/someFile'; - - return cache.get(file, 'field', loaderCb).then(() => { - expect(cache.has(file)).toBe(true); - cache.invalidate(file, 'field'); - expect(cache.has(file)).toBe(true); - expect(cache.has(file, 'field')).toBe(false); - cache.invalidate(file); - expect(cache.has(file)).toBe(false); - }); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js deleted file mode 100644 index 26ccb1e7c..000000000 --- a/packager/react-packager/src/DependencyResolver/Cache/index.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const Promise = require('promise'); -const fs = require('graceful-fs'); -const getCacheFilePath = require('./lib/getCacheFilePath'); -const isAbsolutePath = require('absolute-path'); -const loadCacheSync = require('./lib/loadCacheSync'); -const tmpDir = require('os').tmpDir(); - -function getObjectValues(object) { - return Object.keys(object).map(key => object[key]); -} - -function debounce(fn, delay) { - var timeout; - return () => { - clearTimeout(timeout); - timeout = setTimeout(fn, delay); - }; -} - -class Cache { - constructor({ - resetCache, - cacheKey, - cacheDirectory = tmpDir, - }) { - this._cacheFilePath = getCacheFilePath(cacheDirectory, cacheKey); - if (!resetCache) { - this._data = this._loadCacheSync(this._cacheFilePath); - } else { - this._data = Object.create(null); - } - - this._persistEventually = debounce( - this._persistCache.bind(this), - 2000, - ); - } - - get(filepath, field, loaderCb) { - if (!isAbsolutePath(filepath)) { - throw new Error('Use absolute paths'); - } - - return this.has(filepath, field) - ? this._data[filepath].data[field] - : this.set(filepath, field, loaderCb(filepath)); - } - - invalidate(filepath, field) { - if (this.has(filepath, field)) { - if (field == null) { - delete this._data[filepath]; - } else { - delete this._data[filepath].data[field]; - } - } - } - - end() { - return this._persistCache(); - } - - has(filepath, field) { - return Object.prototype.hasOwnProperty.call(this._data, filepath) && - (field == null || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field)); - } - - set(filepath, field, loaderPromise) { - let record = this._data[filepath]; - if (!record) { - record = Object.create(null); - this._data[filepath] = record; - this._data[filepath].data = Object.create(null); - this._data[filepath].metadata = Object.create(null); - } - - record.data[field] = loaderPromise - .then(data => Promise.all([ - data, - Promise.denodeify(fs.stat)(filepath), - ])) - .then(([data, stat]) => { - this._persistEventually(); - - // Evict all existing field data from the cache if we're putting new - // more up to date data - var mtime = stat.mtime.getTime(); - if (record.metadata.mtime !== mtime) { - record.data = Object.create(null); - } - record.metadata.mtime = mtime; - - return data; - }); - - return record.data[field]; - } - - _persistCache() { - if (this._persisting != null) { - return this._persisting; - } - - const data = this._data; - const cacheFilepath = this._cacheFilePath; - - const allPromises = getObjectValues(data) - .map(record => { - const fieldNames = Object.keys(record.data); - const fieldValues = getObjectValues(record.data); - - return Promise - .all(fieldValues) - .then(ref => { - const ret = Object.create(null); - ret.metadata = record.metadata; - ret.data = Object.create(null); - fieldNames.forEach((field, index) => - ret.data[field] = ref[index] - ); - - return ret; - }); - } - ); - - this._persisting = Promise.all(allPromises) - .then(values => { - const json = Object.create(null); - Object.keys(data).forEach((key, i) => { - // make sure the key wasn't added nor removed after we started - // persisting the cache - const value = values[i]; - if (!value) { - return; - } - - json[key] = Object.create(null); - json[key].metadata = data[key].metadata; - json[key].data = value.data; - }); - return Promise.denodeify(fs.writeFile)(cacheFilepath, JSON.stringify(json)); - }) - .catch(e => console.error('Error while persisting cache:', e.message)) - .then(() => { - this._persisting = null; - return true; - }); - - return this._persisting; - } - - _loadCacheSync(cachePath) { - var ret = Object.create(null); - var cacheOnDisk = loadCacheSync(cachePath); - - // Filter outdated cache and convert to promises. - Object.keys(cacheOnDisk).forEach(key => { - if (!fs.existsSync(key)) { - return; - } - var record = cacheOnDisk[key]; - var stat = fs.statSync(key); - if (stat.mtime.getTime() === record.metadata.mtime) { - ret[key] = Object.create(null); - ret[key].metadata = Object.create(null); - ret[key].data = Object.create(null); - ret[key].metadata.mtime = record.metadata.mtime; - - Object.keys(record.data).forEach(field => { - ret[key].data[field] = Promise.resolve(record.data[field]); - }); - } - }); - - return ret; - } -} - -module.exports = Cache; diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js deleted file mode 100644 index a14faf9ff..000000000 --- a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const crypto = require('crypto'); -const path = require('fast-path'); - -function getCacheFilePath(tmpdir, ...args) { - const hash = crypto.createHash('md5'); - args.forEach(arg => hash.update(arg)); - return path.join(tmpdir, hash.digest('hex')); -} - -module.exports = getCacheFilePath; diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js b/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js deleted file mode 100644 index 87d6944c1..000000000 --- a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const fs = require('graceful-fs'); - -function loadCacheSync(cachePath) { - if (!fs.existsSync(cachePath)) { - return Object.create(null); - } - - try { - return JSON.parse(fs.readFileSync(cachePath)); - } catch (e) { - if (e instanceof SyntaxError) { - console.warn('Unable to parse cache file. Will clear and continue.'); - try { - fs.unlinkSync(cachePath); - } catch (err) { - // Someone else might've deleted it. - } - return Object.create(null); - } - throw e; - } -} - -module.exports = loadCacheSync; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js deleted file mode 100644 index ed5a1a7b7..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js +++ /dev/null @@ -1,45 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const path = require('fast-path'); - -class DependencyGraphHelpers { - constructor({ providesModuleNodeModules, assetExts }) { - this._providesModuleNodeModules = providesModuleNodeModules; - this._assetExts = assetExts; - } - - isNodeModulesDir(file) { - const index = file.lastIndexOf('/node_modules/'); - if (index === -1) { - return false; - } - - const parts = file.substr(index + 14).split(path.sep); - const dirs = this._providesModuleNodeModules; - for (let i = 0; i < dirs.length; i++) { - if (parts.indexOf(dirs[i]) > -1) { - return false; - } - } - - return true; - } - - isAssetFile(file) { - return this._assetExts.indexOf(this.extname(file)) !== -1; - } - - extname(name) { - return path.extname(name).substr(1); - } -} - -module.exports = DependencyGraphHelpers; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js deleted file mode 100644 index 531d54bc4..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js +++ /dev/null @@ -1,119 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const AssetModule_DEPRECATED = require('../AssetModule_DEPRECATED'); -const Fastfs = require('../fastfs'); -const debug = require('debug')('ReactNativePackager:DependencyGraph'); -const path = require('fast-path'); -const Promise = require('promise'); - -class DeprecatedAssetMap { - constructor({ - fsCrawl, - roots, - assetExts, - fileWatcher, - ignoreFilePath, - helpers, - activity, - enabled, - }) { - if (roots == null || roots.length === 0 || !enabled) { - this._disabled = true; - return; - } - - this._helpers = helpers; - this._map = Object.create(null); - this._assetExts = assetExts; - this._activity = activity; - - if (!this._disabled) { - this._fastfs = new Fastfs( - 'Assets', - roots, - fileWatcher, - { ignore: ignoreFilePath, crawling: fsCrawl, activity } - ); - - this._fastfs.on('change', this._processFileChange.bind(this)); - } - } - - build() { - if (this._disabled) { - return Promise.resolve(); - } - - return this._fastfs.build().then( - () => { - const activity = this._activity; - let processAsset_DEPRECATEDActivity; - if (activity) { - processAsset_DEPRECATEDActivity = activity.startEvent( - 'Building (deprecated) Asset Map', - ); - } - - this._fastfs.findFilesByExts(this._assetExts).forEach( - file => this._processAsset(file) - ); - - if (activity) { - activity.endEvent(processAsset_DEPRECATEDActivity); - } - } - ); - } - - resolve(fromModule, toModuleName) { - if (this._disabled) { - return null; - } - - const assetMatch = toModuleName.match(/^image!(.+)/); - if (assetMatch && assetMatch[1]) { - if (!this._map[assetMatch[1]]) { - debug('WARINING: Cannot find asset:', assetMatch[1]); - return null; - } - return this._map[assetMatch[1]]; - } - } - - _processAsset(file) { - const ext = this._helpers.extname(file); - if (this._assetExts.indexOf(ext) !== -1) { - const name = assetName(file, ext); - if (this._map[name] != null) { - debug('Conflicting assets', name); - } - - this._map[name] = new AssetModule_DEPRECATED({ file }); - } - } - - _processFileChange(type, filePath, root, fstat) { - const name = assetName(filePath); - if (type === 'change' || type === 'delete') { - delete this._map[name]; - } - - if (type === 'change' || type === 'add') { - this._processAsset(path.join(root, filePath)); - } - } -} - -function assetName(file, ext) { - return path.basename(file, '.' + ext).replace(/@[\d\.]+x/, ''); -} - -module.exports = DeprecatedAssetMap; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js deleted file mode 100644 index 47f93699b..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js +++ /dev/null @@ -1,142 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; -const path = require('fast-path'); -const getPlatformExtension = require('../lib/getPlatformExtension'); -const Promise = require('promise'); - -const GENERIC_PLATFORM = 'generic'; -const NATIVE_PLATFORM = 'native'; - -class HasteMap { - constructor({ - extensions, - fastfs, - moduleCache, - preferNativePlatform, - helpers, - }) { - this._extensions = extensions; - this._fastfs = fastfs; - this._moduleCache = moduleCache; - this._preferNativePlatform = preferNativePlatform; - this._helpers = helpers; - } - - build() { - this._map = Object.create(null); - const promises = []; - this._fastfs.getAllFiles().forEach(filePath => { - if (!this._helpers.isNodeModulesDir(filePath)) { - if (this._extensions.indexOf(path.extname(filePath).substr(1)) !== -1) { - promises.push(this._processHasteModule(filePath)); - } - if (filePath.endsWith('/package.json')) { - promises.push(this._processHastePackage(filePath)); - } - } - }); - return Promise.all(promises).then(() => this._map); - } - - processFileChange(type, absPath) { - return Promise.resolve().then(() => { - /*eslint no-labels: 0 */ - if (type === 'delete' || type === 'change') { - loop: for (const name in this._map) { - const modulesMap = this._map[name]; - for (const platform in modulesMap) { - const module = modulesMap[platform]; - if (module.path === absPath) { - delete modulesMap[platform]; - break loop; - } - } - } - - if (type === 'delete') { - return null; - } - } - - if (this._extensions.indexOf(this._helpers.extname(absPath)) !== -1) { - if (path.basename(absPath) === 'package.json') { - return this._processHastePackage(absPath); - } else { - return this._processHasteModule(absPath); - } - } - }); - } - - getModule(name, platform = null) { - const modulesMap = this._map[name]; - if (modulesMap == null) { - return null; - } - - // If platform is 'ios', we prefer .ios.js to .native.js which we prefer to - // a plain .js file. - let module = undefined; - if (module == null && platform != null) { - module = modulesMap[platform]; - } - if (module == null && this._preferNativePlatform) { - module = modulesMap[NATIVE_PLATFORM]; - } - if (module == null) { - module = modulesMap[GENERIC_PLATFORM]; - } - return module; - } - - _processHasteModule(file) { - const module = this._moduleCache.getModule(file); - return module.isHaste().then( - isHaste => isHaste && module.getName() - .then(name => this._updateHasteMap(name, module)) - ); - } - - _processHastePackage(file) { - file = path.resolve(file); - const p = this._moduleCache.getPackage(file); - return p.isHaste() - .then(isHaste => isHaste && p.getName() - .then(name => this._updateHasteMap(name, p))) - .catch(e => { - if (e instanceof SyntaxError) { - // Malformed package.json. - return; - } - throw e; - }); - } - - _updateHasteMap(name, mod) { - if (this._map[name] == null) { - this._map[name] = Object.create(null); - } - - const moduleMap = this._map[name]; - const modulePlatform = getPlatformExtension(mod.path) || GENERIC_PLATFORM; - const existingModule = moduleMap[modulePlatform]; - - if (existingModule && existingModule.path !== mod.path) { - throw new Error( - `Naming collision detected: ${mod.path} ` + - `collides with ${existingModule.path}` - ); - } - - moduleMap[modulePlatform] = mod; - } -} - -module.exports = HasteMap; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js deleted file mode 100644 index 510b03fe3..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js +++ /dev/null @@ -1,446 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const debug = require('debug')('ReactNativePackager:DependencyGraph'); -const util = require('util'); -const path = require('fast-path'); -const realPath = require('path'); -const isAbsolutePath = require('absolute-path'); -const getAssetDataFromName = require('../lib/getAssetDataFromName'); -const Promise = require('promise'); - -class ResolutionRequest { - constructor({ - platform, - preferNativePlatform, - entryPath, - hasteMap, - deprecatedAssetMap, - helpers, - moduleCache, - fastfs, - shouldThrowOnUnresolvedErrors, - }) { - this._platform = platform; - this._preferNativePlatform = preferNativePlatform; - this._entryPath = entryPath; - this._hasteMap = hasteMap; - this._deprecatedAssetMap = deprecatedAssetMap; - this._helpers = helpers; - this._moduleCache = moduleCache; - this._fastfs = fastfs; - this._shouldThrowOnUnresolvedErrors = shouldThrowOnUnresolvedErrors; - this._resetResolutionCache(); - } - - _tryResolve(action, secondaryAction) { - return action().catch((error) => { - if (error.type !== 'UnableToResolveError') { - throw error; - } - return secondaryAction(); - }); - } - - resolveDependency(fromModule, toModuleName) { - const resHash = resolutionHash(fromModule.path, toModuleName); - - if (this._immediateResolutionCache[resHash]) { - return Promise.resolve(this._immediateResolutionCache[resHash]); - } - - const asset_DEPRECATED = this._deprecatedAssetMap.resolve( - fromModule, - toModuleName - ); - if (asset_DEPRECATED) { - return Promise.resolve(asset_DEPRECATED); - } - - const cacheResult = (result) => { - this._immediateResolutionCache[resHash] = result; - return result; - }; - - const forgive = (error) => { - if ( - error.type !== 'UnableToResolveError' || - this._shouldThrowOnUnresolvedErrors(this._entryPath, this._platform) - ) { - throw error; - } - - debug( - 'Unable to resolve module %s from %s', - toModuleName, - fromModule.path - ); - return null; - }; - - if (!this._helpers.isNodeModulesDir(fromModule.path) - && toModuleName[0] !== '.' && - toModuleName[0] !== '/') { - return this._tryResolve( - () => this._resolveHasteDependency(fromModule, toModuleName), - () => this._resolveNodeDependency(fromModule, toModuleName) - ).then( - cacheResult, - forgive, - ); - } - - return this._resolveNodeDependency(fromModule, toModuleName) - .then( - cacheResult, - forgive, - ); - } - - getOrderedDependencies(response, mocksPattern, recursive = true) { - return this._getAllMocks(mocksPattern).then(allMocks => { - const entry = this._moduleCache.getModule(this._entryPath); - const mocks = Object.create(null); - const visited = Object.create(null); - visited[entry.hash()] = true; - - response.pushDependency(entry); - const collect = (mod) => { - return mod.getDependencies().then( - depNames => Promise.all( - depNames.map(name => this.resolveDependency(mod, name)) - ).then((dependencies) => [depNames, dependencies]) - ).then(([depNames, dependencies]) => { - if (allMocks) { - const list = [mod.getName()]; - const pkg = mod.getPackage(); - if (pkg) { - list.push(pkg.getName()); - } - return Promise.all(list).then(names => { - names.forEach(name => { - if (allMocks[name] && !mocks[name]) { - const mockModule = - this._moduleCache.getModule(allMocks[name]); - depNames.push(name); - dependencies.push(mockModule); - mocks[name] = allMocks[name]; - } - }); - return [depNames, dependencies]; - }); - } - return Promise.resolve([depNames, dependencies]); - }).then(([depNames, dependencies]) => { - let p = Promise.resolve(); - const filteredPairs = []; - - dependencies.forEach((modDep, i) => { - const name = depNames[i]; - if (modDep == null) { - // It is possible to require mocks that don't have a real - // module backing them. If a dependency cannot be found but there - // exists a mock with the desired ID, resolve it and add it as - // a dependency. - if (allMocks && allMocks[name] && !mocks[name]) { - const mockModule = this._moduleCache.getModule(allMocks[name]); - mocks[name] = allMocks[name]; - return filteredPairs.push([name, mockModule]); - } - - debug( - 'WARNING: Cannot find required module `%s` from module `%s`', - name, - mod.path - ); - return false; - } - return filteredPairs.push([name, modDep]); - }); - - response.setResolvedDependencyPairs(mod, filteredPairs); - - filteredPairs.forEach(([depName, modDep]) => { - p = p.then(() => { - if (!visited[modDep.hash()]) { - visited[modDep.hash()] = true; - response.pushDependency(modDep); - if (recursive) { - return collect(modDep); - } - } - return null; - }); - }); - - return p; - }); - }; - - return collect(entry).then(() => response.setMocks(mocks)); - }); - } - - _getAllMocks(pattern) { - // Take all mocks in all the roots into account. This is necessary - // because currently mocks are global: any module can be mocked by - // any mock in the system. - let mocks = null; - if (pattern) { - mocks = Object.create(null); - this._fastfs.matchFilesByPattern(pattern).forEach(file => - mocks[path.basename(file, path.extname(file))] = file - ); - } - return Promise.resolve(mocks); - } - - _resolveHasteDependency(fromModule, toModuleName) { - toModuleName = normalizePath(toModuleName); - - let p = fromModule.getPackage(); - if (p) { - p = p.redirectRequire(toModuleName); - } else { - p = Promise.resolve(toModuleName); - } - - return p.then((realModuleName) => { - let dep = this._hasteMap.getModule(realModuleName, this._platform); - if (dep && dep.type === 'Module') { - return dep; - } - - let packageName = realModuleName; - while (packageName && packageName !== '.') { - dep = this._hasteMap.getModule(packageName, this._platform); - if (dep && dep.type === 'Package') { - break; - } - packageName = path.dirname(packageName); - } - - if (dep && dep.type === 'Package') { - const potentialModulePath = path.join( - dep.root, - path.relative(packageName, realModuleName) - ); - return this._tryResolve( - () => this._loadAsFile( - potentialModulePath, - fromModule, - toModuleName, - ), - () => this._loadAsDir(potentialModulePath, fromModule, toModuleName), - ); - } - - throw new UnableToResolveError( - fromModule, - toModuleName, - 'Unable to resolve dependency', - ); - }); - } - - _redirectRequire(fromModule, modulePath) { - return Promise.resolve(fromModule.getPackage()).then(p => { - if (p) { - return p.redirectRequire(modulePath); - } - return modulePath; - }); - } - - _resolveFileOrDir(fromModule, toModuleName) { - const potentialModulePath = isAbsolutePath(toModuleName) ? - toModuleName : - path.join(path.dirname(fromModule.path), toModuleName); - - return this._redirectRequire(fromModule, potentialModulePath).then( - realModuleName => this._tryResolve( - () => this._loadAsFile(realModuleName, fromModule, toModuleName), - () => this._loadAsDir(realModuleName, fromModule, toModuleName) - ) - ); - } - - _resolveNodeDependency(fromModule, toModuleName) { - if (toModuleName[0] === '.' || toModuleName[1] === '/') { - return this._resolveFileOrDir(fromModule, toModuleName); - } else { - return this._redirectRequire(fromModule, toModuleName).then( - realModuleName => { - if (realModuleName[0] === '.' || realModuleName[1] === '/') { - // derive absolute path /.../node_modules/fromModuleDir/realModuleName - const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules/') + 13; - const fromModuleDir = fromModule.path.slice(0, fromModule.path.indexOf('/', fromModuleParentIdx)); - const absPath = path.join(fromModuleDir, realModuleName); - return this._resolveFileOrDir(fromModule, absPath); - } - - const searchQueue = []; - for (let currDir = path.dirname(fromModule.path); - currDir !== realPath.parse(fromModule.path).root; - currDir = path.dirname(currDir)) { - searchQueue.push( - path.join(currDir, 'node_modules', realModuleName) - ); - } - - let p = Promise.reject(new UnableToResolveError( - fromModule, - toModuleName, - 'Node module not found', - )); - searchQueue.forEach(potentialModulePath => { - p = this._tryResolve( - () => this._tryResolve( - () => p, - () => this._loadAsFile(potentialModulePath, fromModule, toModuleName), - ), - () => this._loadAsDir(potentialModulePath, fromModule, toModuleName) - ); - }); - - return p; - }); - } - } - - _loadAsFile(potentialModulePath, fromModule, toModule) { - return Promise.resolve().then(() => { - if (this._helpers.isAssetFile(potentialModulePath)) { - const dirname = path.dirname(potentialModulePath); - if (!this._fastfs.dirExists(dirname)) { - throw new UnableToResolveError( - fromModule, - toModule, - `Directory ${dirname} doesn't exist`, - ); - } - - const {name, type} = getAssetDataFromName(potentialModulePath); - - let pattern = '^' + name + '(@[\\d\\.]+x)?'; - if (this._platform != null) { - pattern += '(\\.' + this._platform + ')?'; - } - pattern += '\\.' + type; - - // We arbitrarly grab the first one, because scale selection - // will happen somewhere - const [assetFile] = this._fastfs.matches( - dirname, - new RegExp(pattern) - ); - - if (assetFile) { - return this._moduleCache.getAssetModule(assetFile); - } - } - - let file; - if (this._fastfs.fileExists(potentialModulePath)) { - file = potentialModulePath; - } else if (this._platform != null && - this._fastfs.fileExists(potentialModulePath + '.' + this._platform + '.js')) { - file = potentialModulePath + '.' + this._platform + '.js'; - } else if (this._preferNativePlatform && - this._fastfs.fileExists(potentialModulePath + '.native.js')) { - file = potentialModulePath + '.native.js'; - } else if (this._fastfs.fileExists(potentialModulePath + '.js')) { - file = potentialModulePath + '.js'; - } else if (this._fastfs.fileExists(potentialModulePath + '.json')) { - file = potentialModulePath + '.json'; - } else { - throw new UnableToResolveError( - fromModule, - toModule, - `File ${potentialModulePath} doesnt exist`, - ); - } - - return this._moduleCache.getModule(file); - }); - } - - _loadAsDir(potentialDirPath, fromModule, toModule) { - return Promise.resolve().then(() => { - if (!this._fastfs.dirExists(potentialDirPath)) { - throw new UnableToResolveError( - fromModule, - toModule, -`Unable to find this module in its module map or any of the node_modules directories under ${potentialDirPath} and its parent directories - -This might be related to https://github.com/facebook/react-native/issues/4968 -To resolve try the following: - 1. Clear watchman watches: \`watchman watch-del-all\`. - 2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`. - 3. Reset packager cache: \`rm -fr $TMPDIR/react-*\` or \`npm start -- --reset-cache\`.`, - ); - } - - const packageJsonPath = path.join(potentialDirPath, 'package.json'); - if (this._fastfs.fileExists(packageJsonPath)) { - return this._moduleCache.getPackage(packageJsonPath) - .getMain().then( - (main) => this._tryResolve( - () => this._loadAsFile(main, fromModule, toModule), - () => this._loadAsDir(main, fromModule, toModule) - ) - ); - } - - return this._loadAsFile( - path.join(potentialDirPath, 'index'), - fromModule, - toModule, - ); - }); - } - - _resetResolutionCache() { - this._immediateResolutionCache = Object.create(null); - } - -} - - -function resolutionHash(modulePath, depName) { - return `${path.resolve(modulePath)}:${depName}`; -} - - -function UnableToResolveError(fromModule, toModule, message) { - Error.call(this); - Error.captureStackTrace(this, this.constructor); - this.message = util.format( - 'Unable to resolve module %s from %s: %s', - toModule, - fromModule.path, - message, - ); - this.type = this.name = 'UnableToResolveError'; -} - -util.inherits(UnableToResolveError, Error); - -function normalizePath(modulePath) { - if (path.sep === '/') { - modulePath = path.normalize(modulePath); - } else if (path.posix) { - modulePath = path.posix.normalize(modulePath); - } - - return modulePath.replace(/\/$/, ''); -} - -module.exports = ResolutionRequest; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js deleted file mode 100644 index 56e1ed7a1..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js +++ /dev/null @@ -1,87 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -class ResolutionResponse { - constructor() { - this.dependencies = []; - this.mainModuleId = null; - this.mocks = null; - this.numPrependedDependencies = 0; - this._mappings = Object.create(null); - this._finalized = false; - } - - copy(properties) { - const { - dependencies = this.dependencies, - mainModuleId = this.mainModuleId, - mocks = this.mocks, - } = properties; - return Object.assign(new this.constructor(), this, { - dependencies, - mainModuleId, - mocks, - }); - } - - _assertNotFinalized() { - if (this._finalized) { - throw new Error('Attempted to mutate finalized response.'); - } - } - - _assertFinalized() { - if (!this._finalized) { - throw new Error('Attempted to access unfinalized response.'); - } - } - - finalize() { - return this._mainModule.getName().then(id => { - this.mainModuleId = id; - this._finalized = true; - return this; - }); - } - - pushDependency(module) { - this._assertNotFinalized(); - if (this.dependencies.length === 0) { - this._mainModule = module; - } - - this.dependencies.push(module); - } - - prependDependency(module) { - this._assertNotFinalized(); - this.dependencies.unshift(module); - this.numPrependedDependencies += 1; - } - - setResolvedDependencyPairs(module, pairs) { - this._assertNotFinalized(); - const hash = module.hash(); - if (this._mappings[hash] == null) { - this._mappings[hash] = pairs; - } - } - - setMocks(mocks) { - this.mocks = mocks; - } - - getResolvedDependencyPairs(module) { - this._assertFinalized(); - return this._mappings[module.hash()]; - } -} - -module.exports = ResolutionResponse; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js deleted file mode 100644 index fa823286a..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js +++ /dev/null @@ -1,4285 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest.autoMockOff(); - -jest.mock('fs'); - -const Promise = require('promise'); -const DependencyGraph = require('../index'); -const fs = require('graceful-fs'); - -const mocksPattern = /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/; - -describe('DependencyGraph', function() { - let defaults; - - function getOrderedDependenciesAsJSON(dgraph, entry, platform, recursive = true) { - return dgraph.getDependencies(entry, platform, recursive) - .then(response => response.finalize()) - .then(({ dependencies }) => Promise.all(dependencies.map(dep => Promise.all([ - dep.getName(), - dep.getDependencies(), - ]).then(([name, moduleDependencies]) => ({ - path: dep.path, - isJSON: dep.isJSON(), - isAsset: dep.isAsset(), - isAsset_DEPRECATED: dep.isAsset_DEPRECATED(), - isPolyfill: dep.isPolyfill(), - resolution: dep.resolution, - id: name, - dependencies: moduleDependencies, - }))) - )); - } - - beforeEach(function() { - const fileWatcher = { - on: function() { - return this; - }, - isWatchman: () => Promise.resolve(false), - }; - - const Cache = jest.genMockFn().mockImplementation(function() { - this._maps = Object.create(null); - }); - Cache.prototype.has = jest.genMockFn() - .mockImplementation(function(filepath, field) { - if (!(filepath in this._maps)) { - return false; - } - return !field || field in this._maps[filepath]; - }); - Cache.prototype.get = jest.genMockFn() - .mockImplementation(function(filepath, field, factory) { - let cacheForPath = this._maps[filepath]; - if (this.has(filepath, field)) { - return field ? cacheForPath[field] : cacheForPath; - } - - if (!cacheForPath) { - cacheForPath = this._maps[filepath] = Object.create(null); - } - const value = cacheForPath[field] = factory(); - return value; - }); - Cache.prototype.invalidate = jest.genMockFn() - .mockImplementation(function(filepath, field) { - if (!this.has(filepath, field)) { - return; - } - - if (field) { - delete this._maps[filepath][field]; - } else { - delete this._maps[filepath]; - } - }); - Cache.prototype.end = jest.genMockFn(); - - defaults = { - assetExts: ['png', 'jpg'], - cache: new Cache(), - fileWatcher, - providesModuleNodeModules: [ - 'haste-fbjs', - 'react-haste', - 'react-native', - // Parse requires AsyncStorage. They will - // change that to require('react-native') which - // should work after this release and we can - // remove it from here. - 'parse', - ], - platforms: ['ios', 'android'], - shouldThrowOnUnresolvedErrors: () => false, - }; - }); - - describe('get sync dependencies', function() { - pit('should get dependencies', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("a")', - ].join('\n'), - 'a.js': [ - '/**', - ' * @providesModule a', - ' */', - 'require("b")', - ].join('\n'), - 'b.js': [ - '/**', - ' * @providesModule b', - ' */', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'a', - path: '/root/a.js', - dependencies: ['b'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'b', - path: '/root/b.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should get shallow dependencies', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("a")', - ].join('\n'), - 'a.js': [ - '/**', - ' * @providesModule a', - ' */', - 'require("b")', - ].join('\n'), - 'b.js': [ - '/**', - ' * @providesModule b', - ' */', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js', null, false).then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'a', - path: '/root/a.js', - dependencies: ['b'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should get dependencies with the correct extensions', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("a")', - ].join('\n'), - 'a.js': [ - '/**', - ' * @providesModule a', - ' */', - ].join('\n'), - 'a.js.orig': [ - '/**', - ' * @providesModule a', - ' */', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'a', - path: '/root/a.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should get json dependencies', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'package.json': JSON.stringify({ - name: 'package', - }), - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./a.json")', - 'require("./b")', - ].join('\n'), - 'a.json': JSON.stringify({}), - 'b.json': JSON.stringify({}), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['./a.json', './b'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'package/a.json', - isJSON: true, - path: '/root/a.json', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'package/b.json', - isJSON: true, - path: '/root/b.json', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should get package json as a dep', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'package.json': JSON.stringify({ - name: 'package', - }), - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./package.json")', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(deps => { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['./package.json'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'package/package.json', - isJSON: true, - path: '/root/package.json', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should get dependencies with deprecated assets', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("image!a")', - ].join('\n'), - 'imgs': { - 'a.png': '', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetRoots_DEPRECATED: ['/root/imgs'], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['image!a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'image!a', - path: '/root/imgs/a.png', - dependencies: [], - isAsset_DEPRECATED: true, - resolution: 1, - isAsset: false, - isJSON: false, - isPolyfill: false, - }, - ]); - }); - }); - - pit('should get dependencies with relative assets', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./imgs/a.png")', - ].join('\n'), - 'imgs': { - 'a.png': '', - }, - 'package.json': JSON.stringify({ - name: 'rootPackage', - }), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['./imgs/a.png'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'rootPackage/imgs/a.png', - path: '/root/imgs/a.png', - dependencies: [], - isAsset: true, - resolution: 1, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - ]); - }); - }); - - pit('should get dependencies with assets and resolution', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./imgs/a.png");', - 'require("./imgs/b.png");', - 'require("./imgs/c.png");', - ].join('\n'), - 'imgs': { - 'a@1.5x.png': '', - 'b@.7x.png': '', - 'c.png': '', - 'c@2x.png': '', - }, - 'package.json': JSON.stringify({ - name: 'rootPackage', - }), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: [ - './imgs/a.png', - './imgs/b.png', - './imgs/c.png', - ], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'rootPackage/imgs/a.png', - path: '/root/imgs/a@1.5x.png', - resolution: 1.5, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - { - id: 'rootPackage/imgs/b.png', - path: '/root/imgs/b@.7x.png', - resolution: 0.7, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - { - id: 'rootPackage/imgs/c.png', - path: '/root/imgs/c.png', - resolution: 1, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - ]); - }); - }); - - pit('should respect platform extension in assets', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./imgs/a.png");', - 'require("./imgs/b.png");', - 'require("./imgs/c.png");', - ].join('\n'), - 'imgs': { - 'a@1.5x.ios.png': '', - 'b@.7x.ios.png': '', - 'c.ios.png': '', - 'c@2x.ios.png': '', - }, - 'package.json': JSON.stringify({ - name: 'rootPackage', - }), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js', 'ios').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: [ - './imgs/a.png', - './imgs/b.png', - './imgs/c.png', - ], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'rootPackage/imgs/a.png', - path: '/root/imgs/a@1.5x.ios.png', - resolution: 1.5, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - { - id: 'rootPackage/imgs/b.png', - path: '/root/imgs/b@.7x.ios.png', - resolution: 0.7, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - { - id: 'rootPackage/imgs/c.png', - path: '/root/imgs/c.ios.png', - resolution: 1, - dependencies: [], - isAsset: true, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - ]); - }); - }); - - pit('Deprecated and relative assets can live together', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./imgs/a.png")', - 'require("image!a")', - ].join('\n'), - 'imgs': { - 'a.png': '', - }, - 'package.json': JSON.stringify({ - name: 'rootPackage', - }), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetRoots_DEPRECATED: ['/root/imgs'], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['./imgs/a.png', 'image!a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'rootPackage/imgs/a.png', - path: '/root/imgs/a.png', - dependencies: [], - isAsset: true, - resolution: 1, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - }, - { - id: 'image!a', - path: '/root/imgs/a.png', - dependencies: [], - isAsset_DEPRECATED: true, - resolution: 1, - isAsset: false, - isJSON: false, - isPolyfill: false, - }, - ]); - }); - }); - - pit('should get recursive dependencies', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("a")', - ].join('\n'), - 'a.js': [ - '/**', - ' * @providesModule a', - ' */', - 'require("index")', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'a', - path: '/root/a.js', - dependencies: ['index'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with packages', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with packages', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage/")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage/'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with packages with a dot in the name', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("sha.js")', - 'require("x.y.z")', - ].join('\n'), - 'sha.js': { - 'package.json': JSON.stringify({ - name: 'sha.js', - main: 'main.js', - }), - 'main.js': 'lol', - }, - 'x.y.z': { - 'package.json': JSON.stringify({ - name: 'x.y.z', - main: 'main.js', - }), - 'main.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['sha.js', 'x.y.z'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'sha.js/main.js', - path: '/root/sha.js/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'x.y.z/main.js', - path: '/root/x.y.z/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should default main package to index.js', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': 'require("aPackage")', - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - }), - 'index.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: '/root/index.js', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/index.js', - path: '/root/aPackage/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should resolve using alternative ids', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': 'require("aPackage")', - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - }), - 'index.js': [ - '/**', - ' * @providesModule EpicModule', - ' */', - ].join('\n'), - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: '/root/index.js', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'EpicModule', - path: '/root/aPackage/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should default use index.js if main is a dir', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': 'require("aPackage")', - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'lib', - }), - lib: { - 'index.js': 'lol', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: '/root/index.js', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/lib/index.js', - path: '/root/aPackage/lib/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should resolve require to index if it is a dir', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'package.json': JSON.stringify({ - name: 'test', - }), - 'index.js': 'require("./lib/")', - lib: { - 'index.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'test/index.js', - path: '/root/index.js', - dependencies: ['./lib/'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'test/lib/index.js', - path: '/root/lib/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should resolve require to main if it is a dir w/ a package.json', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'package.json': JSON.stringify({ - name: 'test', - }), - 'index.js': 'require("./lib/")', - lib: { - 'package.json': JSON.stringify({ - 'main': 'main.js', - }), - 'index.js': 'lol', - 'main.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'test/index.js', - path: '/root/index.js', - dependencies: ['./lib/'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: '/root/lib/main.js', - path: '/root/lib/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should ignore malformed packages', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - ].join('\n'), - 'aPackage': { - 'package.json': 'lol', - 'main.js': 'lol', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should fatal on multiple modules with the same name', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - ].join('\n'), - 'b.js': [ - '/**', - ' * @providesModule index', - ' */', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - - return dgraph.load().catch(err => { - expect(err.message).toEqual('Failed to build DependencyGraph: Naming collision detected: /root/b.js collides with /root/index.js'); - expect(err.type).toEqual('DependencyGraphError'); - }); - }); - - pit('should be forgiving with missing requires', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("lolomg")', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['lolomg'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should work with packages with subdirs', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage/subdir/lolynot")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'lol', - 'subdir': { - 'lolynot.js': 'lolynot', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage/subdir/lolynot'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/subdir/lolynot.js', - path: '/root/aPackage/subdir/lolynot.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should work with packages with symlinked subdirs', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'symlinkedPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'lol', - 'subdir': { - 'lolynot.js': 'lolynot', - }, - }, - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage/subdir/lolynot")', - ].join('\n'), - 'aPackage': { SYMLINK: '/symlinkedPackage' }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage/subdir/lolynot'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/subdir/lolynot.js', - path: '/root/aPackage/subdir/lolynot.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should work with relative modules in packages', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'require("./subdir/lolynot")', - 'subdir': { - 'lolynot.js': 'require("../other")', - }, - 'other.js': 'some code', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: ['./subdir/lolynot'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/subdir/lolynot.js', - path: '/root/aPackage/subdir/lolynot.js', - dependencies: ['../other'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/other.js', - path: '/root/aPackage/other.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - testBrowserField('browser'); - testBrowserField('react-native'); - - function replaceBrowserField(json, fieldName) { - if (fieldName !== 'browser') { - json[fieldName] = json.browser; - delete json.browser; - } - - return json; - } - - function testBrowserField(fieldName) { - pit('should support simple browser field in packages ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - main: 'main.js', - browser: 'client.js', - }, fieldName)), - 'main.js': 'some other code', - 'client.js': 'some code', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/client.js', - path: '/root/aPackage/client.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should support browser field in packages w/o .js ext ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - main: 'main.js', - browser: 'client', - }, fieldName)), - 'main.js': 'some other code', - 'client.js': 'some code', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/client.js', - path: '/root/aPackage/client.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should support mapping main in browser field json ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - main: './main.js', - browser: { - './main.js': './client.js', - }, - }, fieldName)), - 'main.js': 'some other code', - 'client.js': 'some code', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetExts: ['png', 'jpg'], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/client.js', - path: '/root/aPackage/client.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should work do correct browser mapping w/o js ext ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - main: './main.js', - browser: { - './main': './client.js', - }, - }, fieldName)), - 'main.js': 'some other code', - 'client.js': 'some code', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetExts: ['png', 'jpg'], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/client.js', - path: '/root/aPackage/client.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - - pit('should support browser mapping of files ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - main: './main.js', - browser: { - './main': './client.js', - './node.js': './not-node.js', - './not-browser': './browser.js', - './dir/server.js': './dir/client', - './hello.js': './bye.js', - }, - }, fieldName)), - 'main.js': 'some other code', - 'client.js': 'require("./node")\nrequire("./dir/server.js")', - 'not-node.js': 'require("./not-browser")', - 'not-browser.js': 'require("./dir/server")', - 'browser.js': 'some browser code', - 'dir': { - 'server.js': 'some node code', - 'client.js': 'require("../hello")', - }, - 'hello.js': 'hello', - 'bye.js': 'bye', - }, - }, - }); - - const dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/client.js', - path: '/root/aPackage/client.js', - dependencies: ['./node', './dir/server.js'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/not-node.js', - path: '/root/aPackage/not-node.js', - dependencies: ['./not-browser'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/browser.js', - path: '/root/aPackage/browser.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/dir/client.js', - path: '/root/aPackage/dir/client.js', - dependencies: ['../hello'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/bye.js', - path: '/root/aPackage/bye.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should support browser mapping for packages ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - browser: { - 'node-package': 'browser-package', - }, - }, fieldName)), - 'index.js': 'require("node-package")', - 'node-package': { - 'package.json': JSON.stringify({ - 'name': 'node-package', - }), - 'index.js': 'some node code', - }, - 'browser-package': { - 'package.json': JSON.stringify({ - 'name': 'browser-package', - }), - 'index.js': 'some browser code', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/index.js', - path: '/root/aPackage/index.js', - dependencies: ['node-package'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'browser-package/index.js', - path: '/root/aPackage/browser-package/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should support browser mapping of a package to a file ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - browser: { - 'node-package': './dir/browser.js', - }, - }, fieldName)), - 'index.js': 'require("./dir/ooga")', - 'dir': { - 'ooga.js': 'require("node-package")', - 'browser.js': 'some browser code', - }, - 'node-package': { - 'package.json': JSON.stringify({ - 'name': 'node-package', - }), - 'index.js': 'some node code', - }, - }, - }, - }); - - const dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/index.js', - path: '/root/aPackage/index.js', - dependencies: ['./dir/ooga'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/dir/ooga.js', - path: '/root/aPackage/dir/ooga.js', - dependencies: ['node-package'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/dir/browser.js', - path: '/root/aPackage/dir/browser.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should support browser mapping for packages ("' + fieldName + '")', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify(replaceBrowserField({ - name: 'aPackage', - browser: { - 'node-package': 'browser-package', - }, - }, fieldName)), - 'index.js': 'require("node-package")', - 'node-package': { - 'package.json': JSON.stringify({ - 'name': 'node-package', - }), - 'index.js': 'some node code', - }, - 'browser-package': { - 'package.json': JSON.stringify({ - 'name': 'browser-package', - }), - 'index.js': 'some browser code', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/index.js', - path: '/root/aPackage/index.js', - dependencies: ['node-package'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'browser-package/index.js', - path: '/root/aPackage/browser-package/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - } - - pit('should fall back to browser mapping from react-native mapping', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - 'react-native': { - 'node-package': 'rn-package', - }, - }), - 'index.js': 'require("node-package")', - 'node_modules': { - 'node-package': { - 'package.json': JSON.stringify({ - 'name': 'node-package', - }), - 'index.js': 'some node code', - }, - 'rn-package': { - 'package.json': JSON.stringify({ - 'name': 'rn-package', - browser: { - 'nested-package': 'nested-browser-package', - }, - }), - 'index.js': 'require("nested-package")', - }, - 'nested-browser-package': { - 'package.json': JSON.stringify({ - 'name': 'nested-browser-package', - }), - 'index.js': 'some code', - }, - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'aPackage/index.js', - path: '/root/aPackage/index.js', - dependencies: ['node-package'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'rn-package/index.js', - path: '/root/aPackage/node_modules/rn-package/index.js', - dependencies: ['nested-package'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { id: 'nested-browser-package/index.js', - path: '/root/aPackage/node_modules/nested-browser-package/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - }); - - describe('node_modules', function() { - pit('should work with nested node_modules', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - 'require("bar");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'require("bar");\nfoo module', - 'node_modules': { - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'bar 1 module', - }, - }, - }, - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'bar 2 module', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo', 'bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: ['bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main.js', - path: '/root/node_modules/foo/node_modules/bar/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main.js', - path: '/root/node_modules/bar/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('platform should work with node_modules', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.ios.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - 'require("bar");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - }), - 'index.ios.js': '', - }, - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main', - }), - 'main.ios.js': '', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.ios.js', - dependencies: ['foo', 'bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/index.ios.js', - path: '/root/node_modules/foo/index.ios.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main.ios.js', - path: '/root/node_modules/bar/main.ios.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('nested node_modules with specific paths', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - 'require("bar/");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'require("bar/lol");\nfoo module', - 'node_modules': { - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'bar 1 module', - 'lol.js': '', - }, - }, - }, - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'bar 2 module', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo', 'bar/'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: ['bar/lol'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/lol.js', - path: '/root/node_modules/foo/node_modules/bar/lol.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main.js', - path: '/root/node_modules/bar/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('nested node_modules with browser field', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - 'require("bar");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'require("bar/lol");\nfoo module', - 'node_modules': { - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - browser: { - './lol': './wow', - }, - }), - 'main.js': 'bar 1 module', - 'lol.js': '', - 'wow.js': '', - }, - }, - }, - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - browser: './main2', - }), - 'main2.js': 'bar 2 module', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo', 'bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: ['bar/lol'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/lol.js', - path: '/root/node_modules/foo/node_modules/bar/lol.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main2.js', - path: '/root/node_modules/bar/main2.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('node_modules should support multi level', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("bar");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': '', - }, - }, - 'path': { - 'to': { - 'bar.js': [ - '/**', - ' * @providesModule bar', - ' */', - 'require("foo")', - ].join('\n'), - }, - 'node_modules': {}, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar', - path: '/root/path/to/bar.js', - dependencies: ['foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should selectively ignore providesModule in node_modules', function() { - var root = '/root'; - var otherRoot = '/anotherRoot'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("shouldWork");', - 'require("dontWork");', - 'require("wontWork");', - 'require("ember");', - 'require("internalVendoredPackage");', - 'require("anotherIndex");', - ].join('\n'), - 'node_modules': { - 'react-haste': { - 'package.json': JSON.stringify({ - name: 'react-haste', - main: 'main.js', - }), - // @providesModule should not be ignored here, because react-haste is whitelisted - 'main.js': [ - '/**', - ' * @providesModule shouldWork', - ' */', - 'require("submodule");', - ].join('\n'), - 'node_modules': { - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - // @providesModule should be ignored here, because it's not whitelisted - 'main.js':[ - '/**', - ' * @providesModule dontWork', - ' */', - 'hi();', - ].join('\n'), - }, - 'submodule': { - 'package.json': JSON.stringify({ - name: 'submodule', - main: 'main.js', - }), - 'main.js': 'log()', - }, - }, - }, - 'ember': { - 'package.json': JSON.stringify({ - name: 'ember', - main: 'main.js', - }), - // @providesModule should be ignored here, because it's not whitelisted, - // and also, the modules "id" should be ember/main.js, not it's haste name - 'main.js':[ - '/**', - ' * @providesModule wontWork', - ' */', - 'hi();', - ].join('\n'), - }, - }, - // This part of the dep graph is meant to emulate internal facebook infra. - // By whitelisting `vendored_modules`, haste should still work. - 'vendored_modules': { - 'a-vendored-package': { - 'package.json': JSON.stringify({ - name: 'a-vendored-package', - main: 'main.js', - }), - // @providesModule should _not_ be ignored here, because it's whitelisted. - 'main.js':[ - '/**', - ' * @providesModule internalVendoredPackage', - ' */', - 'hiFromInternalPackage();', - ].join('\n'), - }, - }, - }, - // we need to support multiple roots and using haste between them - 'anotherRoot': { - 'index.js': [ - '/**', - ' * @providesModule anotherIndex', - ' */', - 'wazup()', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root, otherRoot], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: [ - 'shouldWork', - 'dontWork', - 'wontWork', - 'ember', - 'internalVendoredPackage', - 'anotherIndex', - ], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'shouldWork', - path: '/root/node_modules/react-haste/main.js', - dependencies: ['submodule'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'submodule/main.js', - path: '/root/node_modules/react-haste/node_modules/submodule/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'ember/main.js', - path: '/root/node_modules/ember/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'internalVendoredPackage', - path: '/root/vendored_modules/a-vendored-package/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'anotherIndex', - path: '/anotherRoot/index.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should not be confused by prev occuring whitelisted names', function() { - var root = '/react-haste'; - fs.__setMockFilesystem({ - 'react-haste': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("shouldWork");', - ].join('\n'), - 'node_modules': { - 'react-haste': { - 'package.json': JSON.stringify({ - name: 'react-haste', - main: 'main.js', - }), - 'main.js': [ - '/**', - ' * @providesModule shouldWork', - ' */', - ].join('\n'), - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/react-haste/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/react-haste/index.js', - dependencies: ['shouldWork'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'shouldWork', - path: '/react-haste/node_modules/react-haste/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - - pit('should ignore modules it cant find (assumes own require system)', function() { - // For example SourceMap.js implements it's own require system. - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo/lol");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'foo module', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo/lol'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with node packages with a .js in the name', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("sha.js")', - ].join('\n'), - 'node_modules': { - 'sha.js': { - 'package.json': JSON.stringify({ - name: 'sha.js', - main: 'main.js', - }), - 'main.js': 'lol', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['sha.js'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'sha.js/main.js', - path: '/root/node_modules/sha.js/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with multiple platforms (haste)', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.ios.js': ` - /** - * @providesModule index - */ - require('a'); - `, - 'a.ios.js': ` - /** - * @providesModule a - */ - `, - 'a.android.js': ` - /** - * @providesModule a - */ - `, - 'a.js': ` - /** - * @providesModule a - */ - `, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.ios.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'a', - path: '/root/a.ios.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should pick the generic file', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.ios.js': ` - /** - * @providesModule index - */ - require('a'); - `, - 'a.android.js': ` - /** - * @providesModule a - */ - `, - 'a.js': ` - /** - * @providesModule a - */ - `, - 'a.web.js': ` - /** - * @providesModule a - */ - `, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.ios.js', - dependencies: ['a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'a', - path: '/root/a.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should work with multiple platforms (node)', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.ios.js': ` - /** - * @providesModule index - */ - require('./a'); - `, - 'a.ios.js': '', - 'a.android.js': '', - 'a.js': '', - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.ios.js', - dependencies: ['./a'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: '/root/a.ios.js', - path: '/root/a.ios.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - - pit('should require package.json', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo/package.json");', - 'require("bar");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - }, - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'require("./package.json")', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(deps => { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo/package.json', 'bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'foo/package.json', - path: '/root/node_modules/foo/package.json', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: true, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/main.js', - path: '/root/node_modules/bar/main.js', - dependencies: ['./package.json'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar/package.json', - path: '/root/node_modules/bar/package.json', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: true, - isPolyfill: false, - resolution: undefined, - }, - - ]); - }); - }); - }); - - describe('file watch updating', function() { - var triggerFileChange; - var mockStat = { - isDirectory: () => false, - }; - - beforeEach(function() { - var callbacks = []; - triggerFileChange = (...args) => - callbacks.map(callback => callback(...args)); - - defaults.fileWatcher = { - on: function(eventType, callback) { - if (eventType !== 'all') { - throw new Error('Can only handle "all" event in watcher.'); - } - callbacks.push(callback); - return this; - }, - isWatchman: () => Promise.resolve(false), - }; - }); - - pit('updates module dependencies', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root['index.js'] = - filesystem.root['index.js'].replace('require("foo")', ''); - triggerFileChange('change', 'index.js', root, mockStat); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - }); - - pit('updates module dependencies on file change', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root['index.js'] = - filesystem.root['index.js'].replace('require("foo")', ''); - triggerFileChange('change', 'index.js', root, mockStat); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - }); - - pit('updates module dependencies on file delete', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - delete filesystem.root.foo; - triggerFileChange('delete', 'foo.js', root); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage', 'foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); - }); - }); - }); - - pit('updates module dependencies on file add', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root['bar.js'] = [ - '/**', - ' * @providesModule bar', - ' */', - 'require("foo")', - ].join('\n'); - triggerFileChange('add', 'bar.js', root, mockStat); - - filesystem.root.aPackage['main.js'] = 'require("bar")'; - triggerFileChange('change', 'aPackage/main.js', root, mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage', 'foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: ['bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'bar', - path: '/root/bar.js', - dependencies: ['foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo', - path: '/root/foo.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('updates module dependencies on deprecated asset add', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("image!foo")', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetRoots_DEPRECATED: [root], - assetExts: ['png'], - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['image!foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - - filesystem.root['foo.png'] = ''; - triggerFileChange('add', 'foo.png', root, mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) { - expect(deps2) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['image!foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'image!foo', - path: '/root/foo.png', - dependencies: [], - isAsset_DEPRECATED: true, - resolution: 1, - isAsset: false, - isJSON: false, - isPolyfill: false, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('updates module dependencies on relative asset add', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("./foo.png")', - ].join('\n'), - 'package.json': JSON.stringify({ - name: 'aPackage', - }), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - assetExts: ['png'], - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { id: 'index', - path: '/root/index.js', - dependencies: ['./foo.png'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - - filesystem.root['foo.png'] = ''; - triggerFileChange('add', 'foo.png', root, mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) { - expect(deps2) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['./foo.png'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/foo.png', - path: '/root/foo.png', - dependencies: [], - isAsset: true, - resolution: 1, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('runs changes through ignore filter', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - ignoreFilePath: function(filePath) { - if (filePath === '/root/bar.js') { - return true; - } - return false; - }, - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root['bar.js'] = [ - '/**', - ' * @providesModule bar', - ' */', - 'require("foo")', - ].join('\n'); - triggerFileChange('add', 'bar.js', root, mockStat); - - filesystem.root.aPackage['main.js'] = 'require("bar")'; - triggerFileChange('change', 'aPackage/main.js', root, mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage', 'foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: ['bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo', - path: '/root/foo.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('should ignore directory updates', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - 'require("foo")', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - }, - }, - }); - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - triggerFileChange('change', 'aPackage', '/root', { - isDirectory: () => true, - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage', 'foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/main.js', - path: '/root/aPackage/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo', - path: '/root/foo.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('changes to browser field', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - 'browser.js': 'browser', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root.aPackage['package.json'] = JSON.stringify({ - name: 'aPackage', - main: 'main.js', - browser: 'browser.js', - }); - triggerFileChange('change', 'package.json', '/root/aPackage', mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'aPackage/browser.js', - path: '/root/aPackage/browser.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('removes old package from cache', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("aPackage")', - ].join('\n'), - 'aPackage': { - 'package.json': JSON.stringify({ - name: 'aPackage', - main: 'main.js', - }), - 'main.js': 'main', - 'browser.js': 'browser', - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - filesystem.root.aPackage['package.json'] = JSON.stringify({ - name: 'bPackage', - main: 'main.js', - }); - triggerFileChange('change', 'package.json', '/root/aPackage', mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['aPackage'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('should update node package changes', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'require("bar");\nfoo module', - 'node_modules': { - 'bar': { - 'package.json': JSON.stringify({ - name: 'bar', - main: 'main.js', - }), - 'main.js': 'bar 1 module', - }, - }, - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - expect(deps) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: ['bar'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'bar/main.js', - path: '/root/node_modules/foo/node_modules/bar/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - - filesystem.root.node_modules.foo['main.js'] = 'lol'; - triggerFileChange('change', 'main.js', '/root/node_modules/foo', mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) { - expect(deps2) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo/main.js', - path: '/root/node_modules/foo/main.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('should update node package main changes', function() { - var root = '/root'; - var filesystem = fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'require("foo");', - ].join('\n'), - 'node_modules': { - 'foo': { - 'package.json': JSON.stringify({ - name: 'foo', - main: 'main.js', - }), - 'main.js': 'foo module', - 'browser.js': 'foo module', - }, - }, - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { - filesystem.root.node_modules.foo['package.json'] = JSON.stringify({ - name: 'foo', - main: 'main.js', - browser: 'browser.js', - }); - triggerFileChange('change', 'package.json', '/root/node_modules/foo', mockStat); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) { - expect(deps2) - .toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: ['foo'], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - { - id: 'foo/browser.js', - path: '/root/node_modules/foo/browser.js', - dependencies: [], - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - resolveDependency: undefined, - }, - ]); - }); - }); - }); - - pit('should not error when the watcher reports a known file as added', function() { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.js': [ - '/**', - ' * @providesModule index', - ' */', - 'var b = require("b");', - ].join('\n'), - 'b.js': [ - '/**', - ' * @providesModule b', - ' */', - 'module.exports = function() {};', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() { - triggerFileChange('add', 'index.js', root, mockStat); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js'); - }); - }); - }); - - describe('Extensions', () => { - pit('supports custom file extensions', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - 'index.jsx': [ - '/**', - ' * @providesModule index', - ' */', - 'require("a")', - ].join('\n'), - 'a.coffee': [ - '/**', - ' * @providesModule a', - ' */', - ].join('\n'), - 'X.js': '', - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - extensions: ['jsx', 'coffee'], - }); - - return dgraph.matchFilesByPattern('.*') - .then(files => { - expect(files).toEqual([ - '/root/index.jsx', '/root/a.coffee', - ]); - }) - .then(() => getOrderedDependenciesAsJSON(dgraph, '/root/index.jsx')) - .then(deps => { - expect(deps).toEqual([ - { - dependencies: ['a'], - id: 'index', - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - path: '/root/index.jsx', - resolution: undefined, - }, - { - dependencies: [], - id: 'a', - isAsset: false, - isAsset_DEPRECATED: false, - isJSON: false, - isPolyfill: false, - path: '/root/a.coffee', - resolution: undefined, - }, - ]); - }); - }); - }); - - describe('Mocks', () => { - pit('resolves to null if mocksPattern is not specified', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - '__mocks__': { - 'A.js': '', - }, - 'index.js': '', - }, - }); - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - }); - - return dgraph.getDependencies('/root/index.js') - .then(response => response.finalize()) - .then(response => { - expect(response.mocks).toEqual({}); - }); - }); - - pit('retrieves a list of all required mocks', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - '__mocks__': { - 'A.js': '', - 'b.js': '', - }, - 'b.js': [ - '/**', - ' * @providesModule b', - ' */', - 'require("A");', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - mocksPattern, - }); - - return dgraph.getDependencies('/root/b.js') - .then(response => response.finalize()) - .then(response => { - expect(response.mocks).toEqual({ - A: '/root/__mocks__/A.js', - b: '/root/__mocks__/b.js', - }); - }); - }); - - pit('adds mocks as a dependency of their actual module', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - '__mocks__': { - 'A.js': [ - 'require("b");', - ].join('\n'), - 'b.js': '', - }, - 'A.js': [ - '/**', - ' * @providesModule A', - ' */', - 'require("foo");', - ].join('\n'), - 'foo.js': [ - '/**', - ' * @providesModule foo', - ' */', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - mocksPattern, - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/A.js') - .then(deps => { - expect(deps).toEqual([ - { - path: '/root/A.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: 'A', - dependencies: ['foo', 'A'], - }, - { - path: '/root/foo.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: 'foo', - dependencies: [], - }, - { - path: '/root/__mocks__/A.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: '/root/__mocks__/A.js', - dependencies: ['b'], - }, - { - path: '/root/__mocks__/b.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: '/root/__mocks__/b.js', - dependencies: [], - }, - ]); - }); - }); - - pit('resolves mocks that do not have a real module associated with them', () => { - var root = '/root'; - fs.__setMockFilesystem({ - 'root': { - '__mocks__': { - 'foo.js': [ - 'require("b");', - ].join('\n'), - 'b.js': '', - }, - 'A.js': [ - '/**', - ' * @providesModule A', - ' */', - 'require("foo");', - ].join('\n'), - }, - }); - - var dgraph = new DependencyGraph({ - ...defaults, - roots: [root], - mocksPattern, - }); - - return getOrderedDependenciesAsJSON(dgraph, '/root/A.js') - .then(deps => { - expect(deps).toEqual([ - { - path: '/root/A.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: 'A', - dependencies: ['foo'], - }, - { - path: '/root/__mocks__/foo.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: '/root/__mocks__/foo.js', - dependencies: ['b'], - }, - { - path: '/root/__mocks__/b.js', - isJSON: false, - isAsset: false, - isAsset_DEPRECATED: false, - isPolyfill: false, - id: '/root/__mocks__/b.js', - dependencies: [], - }, - ]); - }); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js deleted file mode 100644 index d710112a9..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -'use strict'; - -var docblockRe = /^\s*(\/\*\*(.|\r?\n)*?\*\/)/; - -var ltrimRe = /^\s*/; -/** - * @param {String} contents - * @return {String} - */ -function extract(contents) { - var match = contents.match(docblockRe); - if (match) { - return match[0].replace(ltrimRe, '') || ''; - } - return ''; -} - - -var commentStartRe = /^\/\*\*/; -var commentEndRe = /\*\/$/; -var wsRe = /[\t ]+/g; -var stringStartRe = /(\r?\n|^) *\*/g; -var multilineRe = - /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g; -var propertyRe = /(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g; - -/** - * @param {String} contents - * @return {Array} - */ -function parse(docblock) { - docblock = docblock - .replace(commentStartRe, '') - .replace(commentEndRe, '') - .replace(wsRe, ' ') - .replace(stringStartRe, '$1'); - - // Normalize multi-line directives - var prev = ''; - while (prev !== docblock) { - prev = docblock; - docblock = docblock.replace(multilineRe, '\n$1 $2\n'); - } - docblock = docblock.trim(); - - var result = []; - var match; - while ((match = propertyRe.exec(docblock))) { - result.push([match[1], match[2]]); - } - - return result; -} - -/** - * Same as parse but returns an object of prop: value instead of array of paris - * If a property appers more than once the last one will be returned - * - * @param {String} contents - * @return {Object} - */ -function parseAsObject(docblock) { - var pairs = parse(docblock); - var result = {}; - for (var i = 0; i < pairs.length; i++) { - result[pairs[i][0]] = pairs[i][1]; - } - return result; -} - - -exports.extract = extract; -exports.parse = parse; -exports.parseAsObject = parseAsObject; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js deleted file mode 100644 index b3a987b1f..000000000 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js +++ /dev/null @@ -1,287 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const Fastfs = require('../fastfs'); -const ModuleCache = require('../ModuleCache'); -const Promise = require('promise'); -const crawl = require('../crawlers'); -const getPlatformExtension = require('../lib/getPlatformExtension'); -const isAbsolutePath = require('absolute-path'); -const path = require('fast-path'); -const util = require('util'); -const DependencyGraphHelpers = require('./DependencyGraphHelpers'); -const ResolutionRequest = require('./ResolutionRequest'); -const ResolutionResponse = require('./ResolutionResponse'); -const HasteMap = require('./HasteMap'); -const DeprecatedAssetMap = require('./DeprecatedAssetMap'); - -const ERROR_BUILDING_DEP_GRAPH = 'DependencyGraphError'; - -const defaultActivity = { - startEvent: () => {}, - endEvent: () => {}, -}; - -class DependencyGraph { - constructor({ - activity, - roots, - ignoreFilePath, - fileWatcher, - assetRoots_DEPRECATED, - assetExts, - providesModuleNodeModules, - platforms, - preferNativePlatform, - cache, - extensions, - mocksPattern, - extractRequires, - transformCode, - shouldThrowOnUnresolvedErrors = () => true, - enableAssetMap, - }) { - this._opts = { - activity: activity || defaultActivity, - roots, - ignoreFilePath: ignoreFilePath || (() => {}), - fileWatcher, - assetRoots_DEPRECATED: assetRoots_DEPRECATED || [], - assetExts: assetExts || [], - providesModuleNodeModules, - platforms: platforms || [], - preferNativePlatform: preferNativePlatform || false, - extensions: extensions || ['js', 'json'], - mocksPattern, - extractRequires, - transformCode, - shouldThrowOnUnresolvedErrors, - enableAssetMap: enableAssetMap || true, - }; - this._cache = cache; - this._helpers = new DependencyGraphHelpers(this._opts); - this.load(); - } - - load() { - if (this._loading) { - return this._loading; - } - - const {activity} = this._opts; - const depGraphActivity = activity.startEvent('Building Dependency Graph'); - const crawlActivity = activity.startEvent('Crawling File System'); - const allRoots = this._opts.roots.concat(this._opts.assetRoots_DEPRECATED); - this._crawling = crawl(allRoots, { - ignore: this._opts.ignoreFilePath, - exts: this._opts.extensions.concat(this._opts.assetExts), - fileWatcher: this._opts.fileWatcher, - }); - this._crawling.then((files) => activity.endEvent(crawlActivity)); - - this._fastfs = new Fastfs( - 'JavaScript', - this._opts.roots, - this._opts.fileWatcher, - { - ignore: this._opts.ignoreFilePath, - crawling: this._crawling, - activity: activity, - } - ); - - this._fastfs.on('change', this._processFileChange.bind(this)); - - this._moduleCache = new ModuleCache({ - fastfs: this._fastfs, - cache: this._cache, - extractRequires: this._opts.extractRequires, - transformCode: this._opts.transformCode, - depGraphHelpers: this._helpers, - }); - - this._hasteMap = new HasteMap({ - fastfs: this._fastfs, - extensions: this._opts.extensions, - moduleCache: this._moduleCache, - preferNativePlatform: this._opts.preferNativePlatform, - helpers: this._helpers, - }); - - this._deprecatedAssetMap = new DeprecatedAssetMap({ - fsCrawl: this._crawling, - roots: this._opts.assetRoots_DEPRECATED, - helpers: this._helpers, - fileWatcher: this._opts.fileWatcher, - ignoreFilePath: this._opts.ignoreFilePath, - assetExts: this._opts.assetExts, - activity: this._opts.activity, - enabled: this._opts.enableAssetMap, - }); - - this._loading = Promise.all([ - this._fastfs.build() - .then(() => { - const hasteActivity = activity.startEvent('Building Haste Map'); - return this._hasteMap.build().then(map => { - activity.endEvent(hasteActivity); - return map; - }); - }), - this._deprecatedAssetMap.build(), - ]).then( - response => { - activity.endEvent(depGraphActivity); - return response[0]; // Return the haste map - }, - err => { - const error = new Error( - `Failed to build DependencyGraph: ${err.message}` - ); - error.type = ERROR_BUILDING_DEP_GRAPH; - error.stack = err.stack; - throw error; - } - ); - - return this._loading; - } - - /** - * Returns a promise with the direct dependencies the module associated to - * the given entryPath has. - */ - getShallowDependencies(entryPath) { - return this._moduleCache.getModule(entryPath).getDependencies(); - } - - getFS() { - return this._fastfs; - } - - /** - * Returns the module object for the given path. - */ - getModuleForPath(entryFile) { - return this._moduleCache.getModule(entryFile); - } - - getAllModules() { - return this.load().then(() => this._moduleCache.getAllModules()); - } - - getDependencies(entryPath, platform, recursive = true) { - return this.load().then(() => { - platform = this._getRequestPlatform(entryPath, platform); - const absPath = this._getAbsolutePath(entryPath); - const req = new ResolutionRequest({ - platform, - preferNativePlatform: this._opts.preferNativePlatform, - entryPath: absPath, - deprecatedAssetMap: this._deprecatedAssetMap, - hasteMap: this._hasteMap, - helpers: this._helpers, - moduleCache: this._moduleCache, - fastfs: this._fastfs, - shouldThrowOnUnresolvedErrors: this._opts.shouldThrowOnUnresolvedErrors, - }); - - const response = new ResolutionResponse(); - - return req.getOrderedDependencies( - response, - this._opts.mocksPattern, - recursive, - ).then(() => response); - }); - } - - matchFilesByPattern(pattern) { - return this.load().then(() => this._fastfs.matchFilesByPattern(pattern)); - } - - _getRequestPlatform(entryPath, platform) { - if (platform == null) { - platform = getPlatformExtension(entryPath); - if (platform == null || this._opts.platforms.indexOf(platform) === -1) { - platform = null; - } - } else if (this._opts.platforms.indexOf(platform) === -1) { - throw new Error('Unrecognized platform: ' + platform); - } - return platform; - } - - _getAbsolutePath(filePath) { - if (isAbsolutePath(filePath)) { - return path.resolve(filePath); - } - - for (let i = 0; i < this._opts.roots.length; i++) { - const root = this._opts.roots[i]; - const potentialAbsPath = path.join(root, filePath); - if (this._fastfs.fileExists(potentialAbsPath)) { - return path.resolve(potentialAbsPath); - } - } - - throw new NotFoundError( - 'Cannot find entry file %s in any of the roots: %j', - filePath, - this._opts.roots - ); - } - - _processFileChange(type, filePath, root, fstat) { - const absPath = path.join(root, filePath); - if (fstat && fstat.isDirectory() || - this._opts.ignoreFilePath(absPath) || - this._helpers.isNodeModulesDir(absPath)) { - return; - } - - // Ok, this is some tricky promise code. Our requirements are: - // * we need to report back failures - // * failures shouldn't block recovery - // * Errors can leave `hasteMap` in an incorrect state, and we need to rebuild - // After we process a file change we record any errors which will also be - // reported via the next request. On the next file change, we'll see that - // we are in an error state and we should decide to do a full rebuild. - this._loading = this._loading.finally(() => { - if (this._hasteMapError) { - console.warn( - 'Rebuilding haste map to recover from error:\n' + - this._hasteMapError.stack - ); - this._hasteMapError = null; - - // Rebuild the entire map if last change resulted in an error. - this._loading = this._hasteMap.build(); - } else { - this._loading = this._hasteMap.processFileChange(type, absPath); - this._loading.catch((e) => this._hasteMapError = e); - } - return this._loading; - }); - } - -} - -function NotFoundError() { - Error.call(this); - Error.captureStackTrace(this, this.constructor); - var msg = util.format.apply(util, arguments); - this.message = msg; - this.type = this.name = 'NotFoundError'; - this.status = 404; -} -util.inherits(NotFoundError, Error); - -module.exports = DependencyGraph; diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js deleted file mode 100644 index f59fa9104..000000000 --- a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -module.exports = { - WatchmanWatcher: jest.genMockFromModule('sane/src/watchman_watcher'), - NodeWatcher: jest.genMockFromModule('sane/src/node_watcher'), -}; diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js deleted file mode 100644 index 650e51009..000000000 --- a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest - .dontMock('util') - .dontMock('events') - .dontMock('../') - .setMock('child_process', { - exec: (cmd, cb) => cb(null, '/usr/bin/watchman'), - }); - -const sane = require('sane'); - -describe('FileWatcher', () => { - let WatchmanWatcher; - let NodeWatcher; - let FileWatcher; - let config; - - beforeEach(() => { - WatchmanWatcher = sane.WatchmanWatcher; - WatchmanWatcher.prototype.once.mockImplementation( - (type, callback) => callback() - ); - NodeWatcher = sane.NodeWatcher; - NodeWatcher.prototype.once.mockImplementation( - (type, callback) => callback() - ); - - FileWatcher = require('../'); - - config = [{ - dir: 'rootDir', - globs: [ - '**/*.js', - '**/*.json', - ], - }]; - }); - - pit('gets the watcher instance when ready', () => { - const fileWatcher = new FileWatcher(config, {useWatchman: true}); - return fileWatcher.getWatchers().then(watchers => { - watchers.forEach(watcher => { - expect(watcher instanceof WatchmanWatcher).toBe(true); - }); - }); - }); - - pit('gets the node watcher if watchman is disabled', () => { - const fileWatcher = new FileWatcher(config, {useWatchman: false}); - return fileWatcher.getWatchers().then(watchers => { - watchers.forEach(watcher => { - expect(watcher instanceof NodeWatcher).toBe(true); - }); - }); - }); - - pit('emits events', () => { - let cb; - WatchmanWatcher.prototype.on.mockImplementation((type, callback) => { - cb = callback; - }); - const fileWatcher = new FileWatcher(config, {useWatchman: true}); - const handler = jest.genMockFn(); - fileWatcher.on('all', handler); - return fileWatcher.getWatchers().then(watchers => { - cb(1, 2, 3, 4); - jest.runAllTimers(); - expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]); - }); - }); - - pit('ends the watcher', () => { - const fileWatcher = new FileWatcher(config, {useWatchman: true}); - WatchmanWatcher.prototype.close.mockImplementation(callback => callback()); - - return fileWatcher.end().then(() => { - expect(WatchmanWatcher.prototype.close).toBeCalled(); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js deleted file mode 100644 index ab548366b..000000000 --- a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const EventEmitter = require('events').EventEmitter; -const sane = require('sane'); -const Promise = require('promise'); -const exec = require('child_process').exec; - -const MAX_WAIT_TIME = 120000; - -// TODO(amasad): can we use watchman version command instead? -const detectingWatcherClass = new Promise(function(resolve) { - exec('which watchman', function(err, out) { - if (err || out.length === 0) { - resolve(sane.NodeWatcher); - } else { - resolve(sane.WatchmanWatcher); - } - }); -}); - -let inited = false; - -class FileWatcher extends EventEmitter { - - constructor(rootConfigs, options) { - if (inited) { - throw new Error('FileWatcher can only be instantiated once'); - } - inited = true; - - super(); - this._useWatchman = options.useWatchman; - this._watcherByRoot = Object.create(null); - - this._loading = Promise.all( - rootConfigs.map(rootConfig => this._createWatcher(rootConfig)) - ).then(watchers => { - watchers.forEach((watcher, i) => { - this._watcherByRoot[rootConfigs[i].dir] = watcher; - watcher.on( - 'all', - // args = (type, filePath, root, stat) - (...args) => this.emit('all', ...args) - ); - }); - return watchers; - }); - - this._loading.done(); - } - - getWatchers() { - return this._loading; - } - - getWatcherForRoot(root) { - return this._loading.then(() => this._watcherByRoot[root]); - } - - isWatchman() { - return this._useWatchman ? detectingWatcherClass.then( - Watcher => Watcher === sane.WatchmanWatcher - ) : Promise.resolve(false); - } - - end() { - inited = false; - return this._loading.then( - (watchers) => watchers.map( - watcher => Promise.denodeify(watcher.close).call(watcher) - ) - ); - } - - _createWatcher(rootConfig) { - return detectingWatcherClass.then(Watcher => { - if (!this._useWatchman) { - Watcher = sane.NodeWatcher; - } - const watcher = new Watcher(rootConfig.dir, { - glob: rootConfig.globs, - dot: false, - }); - - return new Promise((resolve, reject) => { - const rejectTimeout = setTimeout( - () => reject(new Error(timeoutMessage(Watcher))), - MAX_WAIT_TIME - ); - - watcher.once('ready', () => { - clearTimeout(rejectTimeout); - resolve(watcher); - }); - }); - }); - } - - static createDummyWatcher() { - return Object.assign(new EventEmitter(), { - isWatchman: () => Promise.resolve(false), - end: () => Promise.resolve(), - }); - } -} - -function timeoutMessage(Watcher) { - const lines = [ - 'Watcher took too long to load (' + Watcher.name + ')', - ]; - if (Watcher === sane.WatchmanWatcher) { - lines.push( - 'Try running `watchman version` from your terminal', - 'https://facebook.github.io/watchman/docs/troubleshooting.html', - ); - } - return lines.join('\n'); -} - -module.exports = FileWatcher; diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js deleted file mode 100644 index 6849c9220..000000000 --- a/packager/react-packager/src/DependencyResolver/Module.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const crypto = require('crypto'); -const docblock = require('./DependencyGraph/docblock'); -const isAbsolutePath = require('absolute-path'); -const jsonStableStringify = require('json-stable-stringify'); -const path = require('fast-path'); -const extractRequires = require('./lib/extractRequires'); - -class Module { - - constructor({ - file, - fastfs, - moduleCache, - cache, - extractor = extractRequires, - transformCode, - depGraphHelpers, - }) { - if (!isAbsolutePath(file)) { - throw new Error('Expected file to be absolute path but got ' + file); - } - - this.path = file; - this.type = 'Module'; - - this._fastfs = fastfs; - this._moduleCache = moduleCache; - this._cache = cache; - this._extractor = extractor; - this._transformCode = transformCode; - this._depGraphHelpers = depGraphHelpers; - } - - isHaste() { - return this._cache.get( - this.path, - 'isHaste', - () => this._readDocBlock().then(({id}) => !!id) - ); - } - - getCode(transformOptions) { - return this.read(transformOptions).then(({code}) => code); - } - - getMap(transformOptions) { - return this.read(transformOptions).then(({map}) => map); - } - - getName() { - return this._cache.get( - this.path, - 'name', - () => this._readDocBlock().then(({id}) => { - if (id) { - return id; - } - - const p = this.getPackage(); - - if (!p) { - // Name is full path - return this.path; - } - - return p.getName() - .then(name => { - if (!name) { - return this.path; - } - - return path.join(name, path.relative(p.root, this.path)).replace(/\\/g, '/'); - }); - }) - ); - } - - getPackage() { - return this._moduleCache.getPackageForModule(this); - } - - getDependencies(transformOptions) { - return this.read(transformOptions).then(data => data.dependencies); - } - - invalidate() { - this._cache.invalidate(this.path); - } - - _parseDocBlock(docBlock) { - // Extract an id for the module if it's using @providesModule syntax - // and if it's NOT in node_modules (and not a whitelisted node_module). - // This handles the case where a project may have a dep that has @providesModule - // docblock comments, but doesn't want it to conflict with whitelisted @providesModule - // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency, - // project-specific code that is using @providesModule. - const moduleDocBlock = docblock.parseAsObject(docBlock); - const provides = moduleDocBlock.providesModule || moduleDocBlock.provides; - - const id = provides && !this._depGraphHelpers.isNodeModulesDir(this.path) - ? /^\S+/.exec(provides)[0] - : undefined; - return {id, moduleDocBlock}; - } - - _readDocBlock(contentPromise) { - if (!this._docBlock) { - if (!contentPromise) { - contentPromise = this._fastfs.readWhile(this.path, whileInDocBlock); - } - this._docBlock = contentPromise - .then(docBlock => this._parseDocBlock(docBlock)); - } - return this._docBlock; - } - - read(transformOptions) { - return this._cache.get( - this.path, - cacheKey('moduleData', transformOptions), - () => { - const fileContentPromise = this._fastfs.readFile(this.path); - return Promise.all([ - fileContentPromise, - this._readDocBlock(fileContentPromise), - ]).then(([code, {id, moduleDocBlock}]) => { - // Ignore requires in JSON files or generated code. An example of this - // is prebuilt files like the SourceMap library. - if (this.isJSON() || 'extern' in moduleDocBlock) { - return {id, code, dependencies: []}; - } else { - const transformCode = this._transformCode; - const codePromise = transformCode - ? transformCode(this, code, transformOptions) - : Promise.resolve({code}); - - return codePromise.then(({code, dependencies, map}) => { - if (!dependencies) { - dependencies = this._extractor(code).deps.sync; - } - return {id, code, dependencies, map}; - }); - } - }); - } - ); - } - - hash() { - return `Module : ${this.path}`; - } - - isJSON() { - return path.extname(this.path) === '.json'; - } - - isAsset() { - return false; - } - - isPolyfill() { - return false; - } - - isAsset_DEPRECATED() { - return false; - } - - toJSON() { - return { - hash: this.hash(), - isJSON: this.isJSON(), - isAsset: this.isAsset(), - isAsset_DEPRECATED: this.isAsset_DEPRECATED(), - type: this.type, - path: this.path, - }; - } -} - -function whileInDocBlock(chunk, i, result) { - // consume leading whitespace - if (!/\S/.test(result)) { - return true; - } - - // check for start of doc block - if (!/^\s*\/(\*{2}|\*?$)/.test(result)) { - return false; - } - - // check for end of doc block - return !/\*\//.test(result); -} - -// 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; -} - -function cacheKey(field, transformOptions) { - return transformOptions !== undefined - ? stableObjectHash(transformOptions) + '\0' + field - : field; -} - -module.exports = Module; diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js deleted file mode 100644 index 11c56919c..000000000 --- a/packager/react-packager/src/DependencyResolver/ModuleCache.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -const AssetModule = require('./AssetModule'); -const Package = require('./Package'); -const Module = require('./Module'); -const path = require('fast-path'); - -class ModuleCache { - - constructor({ - fastfs, - cache, - extractRequires, - transformCode, - depGraphHelpers, - }) { - this._moduleCache = Object.create(null); - this._packageCache = Object.create(null); - this._fastfs = fastfs; - this._cache = cache; - this._extractRequires = extractRequires; - this._transformCode = transformCode; - this._depGraphHelpers = depGraphHelpers; - - fastfs.on('change', this._processFileChange.bind(this)); - } - - getModule(filePath) { - if (!this._moduleCache[filePath]) { - this._moduleCache[filePath] = new Module({ - file: filePath, - fastfs: this._fastfs, - moduleCache: this, - cache: this._cache, - extractor: this._extractRequires, - transformCode: this._transformCode, - depGraphHelpers: this._depGraphHelpers, - }); - } - return this._moduleCache[filePath]; - } - - getAllModules() { - return this._moduleCache; - } - - getAssetModule(filePath) { - if (!this._moduleCache[filePath]) { - this._moduleCache[filePath] = new AssetModule({ - file: filePath, - fastfs: this._fastfs, - moduleCache: this, - cache: this._cache, - }); - } - return this._moduleCache[filePath]; - } - - getPackage(filePath) { - if (!this._packageCache[filePath]) { - this._packageCache[filePath] = new Package({ - file: filePath, - fastfs: this._fastfs, - cache: this._cache, - }); - } - return this._packageCache[filePath]; - } - - getPackageForModule(module) { - // TODO(amasad): use ES6 Map. - if (module.__package) { - if (this._packageCache[module.__package]) { - return this._packageCache[module.__package]; - } else { - delete module.__package; - } - } - - const packagePath = this._fastfs.closest(module.path, 'package.json'); - - if (!packagePath) { - return null; - } - - module.__package = packagePath; - return this.getPackage(packagePath); - } - - _processFileChange(type, filePath, root) { - const absPath = path.join(root, filePath); - - if (this._moduleCache[absPath]) { - this._moduleCache[absPath].invalidate(); - delete this._moduleCache[absPath]; - } - if (this._packageCache[absPath]) { - this._packageCache[absPath].invalidate(); - delete this._packageCache[absPath]; - } - } -} - -module.exports = ModuleCache; diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js deleted file mode 100644 index 0d28b3b00..000000000 --- a/packager/react-packager/src/DependencyResolver/Package.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -const isAbsolutePath = require('absolute-path'); -const path = require('fast-path'); - -class Package { - - constructor({ file, fastfs, cache }) { - this.path = file; - this.root = path.dirname(this.path); - this._fastfs = fastfs; - this.type = 'Package'; - this._cache = cache; - } - - getMain() { - return this.read().then(json => { - var replacements = getReplacements(json); - if (typeof replacements === 'string') { - return path.join(this.root, replacements); - } - - let main = json.main || 'index'; - - if (replacements && typeof replacements === 'object') { - main = replacements[main] || - replacements[main + '.js'] || - replacements[main + '.json'] || - replacements[main.replace(/(\.js|\.json)$/, '')] || - main; - } - - return path.join(this.root, main); - }); - } - - isHaste() { - return this._cache.get(this.path, 'package-haste', () => - this.read().then(json => !!json.name) - ); - } - - getName() { - return this._cache.get(this.path, 'package-name', () => - this.read().then(json => json.name) - ); - } - - invalidate() { - this._cache.invalidate(this.path); - } - - redirectRequire(name) { - return this.read().then(json => { - var replacements = getReplacements(json); - - if (!replacements || typeof replacements !== 'object') { - return name; - } - - if (name[0] !== '/') { - return replacements[name] || name; - } - - if (!isAbsolutePath(name)) { - throw new Error(`Expected ${name} to be absolute path`); - } - - const relPath = './' + path.relative(this.root, name); - const redirect = replacements[relPath] || - replacements[relPath + '.js'] || - replacements[relPath + '.json']; - if (redirect) { - return path.join( - this.root, - redirect - ); - } - - return name; - }); - } - - read() { - if (!this._reading) { - this._reading = this._fastfs.readFile(this.path) - .then(jsonStr => JSON.parse(jsonStr)); - } - - return this._reading; - } -} - -function getReplacements(pkg) { - return pkg['react-native'] == null - ? pkg.browser - : pkg['react-native']; -} - -module.exports = Package; diff --git a/packager/react-packager/src/DependencyResolver/Polyfill.js b/packager/react-packager/src/DependencyResolver/Polyfill.js deleted file mode 100644 index 97c57adb7..000000000 --- a/packager/react-packager/src/DependencyResolver/Polyfill.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const Promise = require('promise'); -const Module = require('./Module'); - -class Polyfill extends Module { - constructor({ path, id, dependencies }) { - super({ file: path }); - this._id = id; - this._dependencies = dependencies; - } - - isHaste() { - return Promise.resolve(false); - } - - getName() { - return Promise.resolve(this._id); - } - - getPackage() { - return null; - } - - getDependencies() { - return Promise.resolve(this._dependencies); - } - - isJSON() { - return false; - } - - isPolyfill() { - return true; - } -} - -module.exports = Polyfill; diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js deleted file mode 100644 index ee2623a3a..000000000 --- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest - .dontMock('absolute-path') - .dontMock('json-stable-stringify') - .dontMock('../fastfs') - .dontMock('../lib/extractRequires') - .dontMock('../lib/replacePatterns') - .dontMock('../DependencyGraph/docblock') - .dontMock('../Module'); - -jest - .mock('fs'); - -const Fastfs = require('../fastfs'); -const Module = require('../Module'); -const ModuleCache = require('../ModuleCache'); -const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers'); -const Promise = require('promise'); -const fs = require('graceful-fs'); - -function mockIndexFile(indexJs) { - fs.__setMockFilesystem({'root': {'index.js': indexJs}}); -} - -describe('Module', () => { - const fileWatcher = { - on: () => this, - isWatchman: () => Promise.resolve(false), - }; - const fileName = '/root/index.js'; - - let cache, fastfs; - - const createCache = () => ({ - get: jest.genMockFn().mockImplementation( - (filepath, field, cb) => cb(filepath) - ), - invalidate: jest.genMockFn(), - end: jest.genMockFn(), - }); - - const createModule = (options) => - new Module({ - cache, - fastfs, - file: fileName, - depGraphHelpers: new DependencyGraphHelpers(), - moduleCache: new ModuleCache({fastfs, cache}), - ...options, - }); - - beforeEach(function(done) { - cache = createCache(); - fastfs = new Fastfs( - 'test', - ['/root'], - fileWatcher, - {crawling: Promise.resolve([fileName]), ignore: []}, - ); - - fastfs.build().then(done); - }); - - describe('Module ID', () => { - const moduleId = 'arbitraryModule'; - const source = - `/** - * @providesModule ${moduleId} - */ - `; - - let module; - beforeEach(() => { - module = createModule(); - }); - - describe('@providesModule annotations', () => { - beforeEach(() => { - mockIndexFile(source); - }); - - pit('extracts the module name from the header', () => - module.getName().then(name => expect(name).toEqual(moduleId)) - ); - - pit('identifies the module as haste module', () => - module.isHaste().then(isHaste => expect(isHaste).toBe(true)) - ); - - pit('does not transform the file in order to access the name', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).getName() - .then(() => expect(transformCode).not.toBeCalled()); - }); - - pit('does not transform the file in order to access the haste status', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).isHaste() - .then(() => expect(transformCode).not.toBeCalled()); - }); - }); - - describe('@provides annotations', () => { - beforeEach(() => { - mockIndexFile(source.replace(/@providesModule/, '@provides')); - }); - - pit('extracts the module name from the header if it has a @provides annotation', () => - module.getName().then(name => expect(name).toEqual(moduleId)) - ); - - pit('identifies the module as haste module', () => - module.isHaste().then(isHaste => expect(isHaste).toBe(true)) - ); - - pit('does not transform the file in order to access the name', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).getName() - .then(() => expect(transformCode).not.toBeCalled()); - }); - - pit('does not transform the file in order to access the haste status', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).isHaste() - .then(() => expect(transformCode).not.toBeCalled()); - }); - }); - - describe('no annotation', () => { - beforeEach(() => { - mockIndexFile('arbitrary(code);'); - }); - - pit('uses the file name as module name', () => - module.getName().then(name => expect(name).toEqual(fileName)) - ); - - pit('does not identify the module as haste module', () => - module.isHaste().then(isHaste => expect(isHaste).toBe(false)) - ); - - pit('does not transform the file in order to access the name', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).getName() - .then(() => expect(transformCode).not.toBeCalled()); - }); - - pit('does not transform the file in order to access the haste status', () => { - const transformCode = - jest.genMockFn().mockReturnValue(Promise.resolve()); - return createModule({transformCode}).isHaste() - .then(() => expect(transformCode).not.toBeCalled()); - }); - }); - }); - - describe('Code', () => { - const fileContents = 'arbitrary(code)'; - beforeEach(function() { - mockIndexFile(fileContents); - }); - - pit('exposes file contents as `code` property on the data exposed by `read()`', () => - createModule().read().then(({code}) => - expect(code).toBe(fileContents)) - ); - - pit('exposes file contents via the `getCode()` method', () => - createModule().getCode().then(code => - expect(code).toBe(fileContents)) - ); - }); - - describe('Extrators', () => { - - pit('uses custom require extractors if specified', () => { - mockIndexFile(''); - const module = createModule({ - extractor: code => ({deps: {sync: ['foo', 'bar']}}), - }); - - return module.getDependencies().then(actual => - expect(actual).toEqual(['foo', 'bar'])); - }); - }); - - describe('Custom Code Transform', () => { - let transformCode; - const fileContents = 'arbitrary(code);'; - const exampleCode = ` - ${'require'}('a'); - ${'System.import'}('b'); - ${'require'}('c');`; - - beforeEach(function() { - transformCode = jest.genMockFn(); - mockIndexFile(fileContents); - transformCode.mockReturnValue(Promise.resolve({code: ''})); - }); - - pit('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); - }); - }); - - pit('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) - ); - }); - - pit('uses the code that `transformCode` resolves to to extract dependencies', () => { - transformCode.mockReturnValue(Promise.resolve({code: exampleCode})); - const module = createModule({transformCode}); - - return module.getDependencies().then(dependencies => { - expect(dependencies).toEqual(['a', 'c']); - }); - }); - - pit('uses dependencies that `transformCode` resolves to, instead of extracting them', () => { - const mockedDependencies = ['foo', 'bar']; - transformCode.mockReturnValue(Promise.resolve({ - code: exampleCode, - dependencies: mockedDependencies, - })); - const module = createModule({transformCode}); - - return module.getDependencies().then(dependencies => { - expect(dependencies).toEqual(mockedDependencies); - }); - }); - - pit('exposes the transformed code rather than the raw file contents', () => { - transformCode.mockReturnValue(Promise.resolve({code: exampleCode})); - const module = createModule({transformCode}); - return Promise.all([module.read(), module.getCode()]) - .then(([data, code]) => { - expect(data.code).toBe(exampleCode); - expect(code).toBe(exampleCode); - }); - }); - - pit('exposes a source map returned by the transform', () => { - const map = {version: 3}; - transformCode.mockReturnValue(Promise.resolve({map, code: exampleCode})); - const module = createModule({transformCode}); - return Promise.all([module.read(), module.getMap()]) - .then(([data, sourceMap]) => { - expect(data.map).toBe(map); - expect(sourceMap).toBe(map); - }); - }); - - describe('Caching based on options', () => { - let module; - beforeEach(function() { - module = createModule({transformCode}); - }); - - const callsEqual = ([path1, key1], [path2, key2]) => { - expect(path1).toEqual(path2); - expect(key1).toEqual(key2); - }; - - it('gets dependencies from the cache with the same cache key for the same transform options', () => { - const options = {some: 'options'}; - module.getDependencies(options); // first call - module.getDependencies(options); // second call - - const {calls} = cache.get.mock; - callsEqual(calls[0], calls[1]); - }); - - it('gets dependencies from the cache with the same cache key for the equivalent transform options', () => { - module.getDependencies({a: 'b', c: 'd'}); // first call - module.getDependencies({c: 'd', a: 'b'}); // second call - - const {calls} = cache.get.mock; - callsEqual(calls[0], calls[1]); - }); - - it('gets dependencies from the cache with different cache keys for different transform options', () => { - module.getDependencies({some: 'options'}); - module.getDependencies({other: 'arbitrary options'}); - const {calls} = cache.get.mock; - expect(calls[0][1]).not.toEqual(calls[1][1]); - }); - - it('gets code from the cache with the same cache key for the same transform options', () => { - const options = {some: 'options'}; - module.getCode(options); // first call - module.getCode(options); // second call - - const {calls} = cache.get.mock; - callsEqual(calls[0], calls[1]); - }); - - it('gets code from the cache with the same cache key for the equivalent transform options', () => { - module.getCode({a: 'b', c: 'd'}); // first call - module.getCode({c: 'd', a: 'b'}); // second call - - const {calls} = cache.get.mock; - callsEqual(calls[0], calls[1]); - }); - - it('gets code from the cache with different cache keys for different transform options', () => { - module.getCode({some: 'options'}); - module.getCode({other: 'arbitrary options'}); - const {calls} = cache.get.mock; - expect(calls[0][1]).not.toEqual(calls[1][1]); - }); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data deleted file mode 100644 index fe2c63885..000000000 --- a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * An arbitrary module header - * @providesModule - */ - - const some: string = 'arbitrary code'; - const containing: string = 'ūñïčødę'; - -/** - * An arbitrary class that extends some thing - * It exposes a random number, which may be reset at the callers discretion - */ -class Arbitrary extends Something { - constructor() { - this.reset(); - } - - /** - * Returns the random number - * @returns number - */ - get random(): number { - return this._random; - } - - /** - * Re-creates the internal random number - * @returns void - */ - reset(): void { - this._random = Math.random(); - } -} diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js deleted file mode 100644 index cbff314af..000000000 --- a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest.autoMockOff() - .dontMock('graceful-fs'); - -const Fastfs = require('../fastfs'); - -const {EventEmitter} = require('events'); -const fs = require('fs'); -const path = require('path'); - -const fileName = path.resolve(__dirname, 'fastfs-data'); -const contents = fs.readFileSync(fileName, 'utf-8'); - -describe('fastfs:', function() { - let fastfs; - const crawling = Promise.resolve([fileName]); - const roots = [__dirname]; - const watcher = new EventEmitter(); - - beforeEach(function(done) { - fastfs = new Fastfs('arbitrary', roots, watcher, {crawling}); - fastfs.build().then(done); - }); - - describe('partial reading', () => { - // these are integrated tests that read real files from disk - - pit('reads a file while a predicate returns true', function() { - return fastfs.readWhile(fileName, () => true).then(readContent => - expect(readContent).toEqual(contents) - ); - }); - - pit('invokes the predicate with the new chunk, the invocation index, and the result collected so far', () => { - const predicate = jest.genMockFn().mockReturnValue(true); - return fastfs.readWhile(fileName, predicate).then(() => { - let aggregated = ''; - const {calls} = predicate.mock; - expect(calls).not.toEqual([]); - - calls.forEach((call, i) => { - const [chunk] = call; - aggregated += chunk; - expect(chunk).not.toBe(''); - expect(call).toEqual([chunk, i, aggregated]); - }); - - expect(aggregated).toEqual(contents); - }); - }); - - pit('stops reading when the predicate returns false', () => { - const predicate = jest.genMockFn().mockImpl((_, i) => i !== 0); - return fastfs.readWhile(fileName, predicate).then((readContent) => { - const {calls} = predicate.mock; - expect(calls.length).toBe(1); - expect(readContent).toBe(calls[0][2]); - }); - }); - - pit('after reading the whole file with `readWhile`, `read()` still works', () => { - // this test allows to reuse the results of `readWhile` for `readFile` - return fastfs.readWhile(fileName, () => true).then(() => { - fastfs.readFile(fileName).then(readContent => - expect(readContent).toEqual(contents) - ); - }); - }); - - pit('after reading parts of the file with `readWhile`, `read()` still works', () => { - return fastfs.readWhile(fileName, () => false).then(() => { - fastfs.readFile(fileName).then(readContent => - expect(readContent).toEqual(contents) - ); - }); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/crawlers/index.js b/packager/react-packager/src/DependencyResolver/crawlers/index.js deleted file mode 100644 index fe755bcb6..000000000 --- a/packager/react-packager/src/DependencyResolver/crawlers/index.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -const nodeCrawl = require('./node'); -const watchmanCrawl = require('./watchman'); - -function crawl(roots, options) { - const {fileWatcher} = options; - return fileWatcher.isWatchman().then(isWatchman => { - if (!isWatchman) { - return false; - } - - // Make sure we're dealing with a version of watchman - // that's using `watch-project` - // TODO(amasad): properly expose (and document) used sane internals. - return fileWatcher.getWatchers().then(([watcher]) => !!watcher.watchProjectInfo.root); - }).then(isWatchman => { - if (isWatchman) { - return watchmanCrawl(roots, options); - } - - return nodeCrawl(roots, options); - }); -} - -module.exports = crawl; diff --git a/packager/react-packager/src/DependencyResolver/crawlers/node.js b/packager/react-packager/src/DependencyResolver/crawlers/node.js deleted file mode 100644 index 871bbc1d7..000000000 --- a/packager/react-packager/src/DependencyResolver/crawlers/node.js +++ /dev/null @@ -1,61 +0,0 @@ -'use strict'; - -const Promise = require('promise'); -const debug = require('debug')('ReactNativePackager:DependencyGraph'); -const fs = require('graceful-fs'); -const path = require('fast-path'); - -const readDir = Promise.denodeify(fs.readdir); -const stat = Promise.denodeify(fs.stat); - -function nodeRecReadDir(roots, {ignore, exts}) { - const queue = roots.slice(); - const retFiles = []; - const extPattern = new RegExp( - '\.(' + exts.join('|') + ')$' - ); - - function search() { - const currDir = queue.shift(); - if (!currDir) { - return Promise.resolve(); - } - - return readDir(currDir) - .then(files => files.map(f => path.join(currDir, f))) - .then(files => Promise.all( - files.map(f => stat(f).catch(handleBrokenLink)) - ).then(stats => [ - // Remove broken links. - files.filter((file, i) => !!stats[i]), - stats.filter(Boolean), - ])) - .then(([files, stats]) => { - files.forEach((filePath, i) => { - if (ignore(filePath)) { - return; - } - - if (stats[i].isDirectory()) { - queue.push(filePath); - return; - } - - if (filePath.match(extPattern)) { - retFiles.push(filePath); - } - }); - - return search(); - }); - } - - return search().then(() => retFiles); -} - -function handleBrokenLink(e) { - debug('WARNING: error stating, possibly broken symlink', e.message); - return Promise.resolve(); -} - -module.exports = nodeRecReadDir; diff --git a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js b/packager/react-packager/src/DependencyResolver/crawlers/watchman.js deleted file mode 100644 index 6e3d6a6c9..000000000 --- a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -const Promise = require('promise'); -const path = require('fast-path'); - -function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) { - const files = []; - return Promise.all( - roots.map( - root => fileWatcher.getWatcherForRoot(root) - ) - ).then( - watchers => { - // All watchman roots for all watches we have. - const watchmanRoots = watchers.map( - watcher => watcher.watchProjectInfo.root - ); - - // Actual unique watchers (because we use watch-project we may end up with - // duplicate "real" watches, and that's by design). - // TODO(amasad): push this functionality into the `FileWatcher`. - const uniqueWatchers = watchers.filter( - (watcher, i) => watchmanRoots.indexOf(watcher.watchProjectInfo.root) === i - ); - - return Promise.all( - uniqueWatchers.map(watcher => { - const watchedRoot = watcher.watchProjectInfo.root; - - // Build up an expression to filter the output by the relevant roots. - const dirExpr = ['anyof']; - for (let i = 0; i < roots.length; i++) { - const root = roots[i]; - if (isDescendant(watchedRoot, root)) { - dirExpr.push(['dirname', path.relative(watchedRoot, root)]); - } - } - - const cmd = Promise.denodeify(watcher.client.command.bind(watcher.client)); - return cmd(['query', watchedRoot, { - suffix: exts, - expression: ['allof', ['type', 'f'], 'exists', dirExpr], - fields: ['name'], - }]).then(resp => { - if ('warning' in resp) { - console.warn('watchman warning: ', resp.warning); - } - - resp.files.forEach(filePath => { - filePath = watchedRoot + path.sep + filePath; - if (!ignore(filePath)) { - files.push(filePath); - } - return false; - }); - }); - }) - ); - }).then(() => files); -} - -function isDescendant(root, child) { - return child.startsWith(root); -} - -module.exports = watchmanRecReadDir; diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js deleted file mode 100644 index af2010086..000000000 --- a/packager/react-packager/src/DependencyResolver/fastfs.js +++ /dev/null @@ -1,360 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const Promise = require('promise'); -const {EventEmitter} = require('events'); - -const fs = require('graceful-fs'); -const path = require('fast-path'); - -// workaround for https://github.com/isaacs/node-graceful-fs/issues/56 -// fs.close is patched, whereas graceful-fs.close is not. -const fsClose = require('fs').close; - -const readFile = Promise.denodeify(fs.readFile); -const stat = Promise.denodeify(fs.stat); - -const NOT_FOUND_IN_ROOTS = 'NotFoundInRootsError'; - -class Fastfs extends EventEmitter { - constructor(name, roots, fileWatcher, {ignore, crawling, activity}) { - super(); - this._name = name; - this._fileWatcher = fileWatcher; - this._ignore = ignore; - this._roots = roots.map(root => { - // If the path ends in a separator ("/"), remove it to make string - // operations on paths safer. - if (root.endsWith(path.sep)) { - root = root.substr(0, root.length - 1); - } - return new File(root, true); - }); - this._fastPaths = Object.create(null); - this._crawling = crawling; - this._activity = activity; - } - - build() { - return this._crawling.then(files => { - let fastfsActivity; - const activity = this._activity; - if (activity) { - fastfsActivity = activity.startEvent('Building in-memory fs for ' + this._name); - } - files.forEach(filePath => { - const root = this._getRoot(filePath); - if (root) { - const newFile = new File(filePath, false); - const dirname = filePath.substr(0, filePath.lastIndexOf(path.sep)); - const parent = this._fastPaths[dirname]; - this._fastPaths[filePath] = newFile; - if (parent) { - parent.addChild(newFile, this._fastPaths); - } else { - root.addChild(newFile, this._fastPaths); - } - } - }); - if (activity) { - activity.endEvent(fastfsActivity); - } - this._fileWatcher.on('all', this._processFileChange.bind(this)); - }); - } - - stat(filePath) { - return Promise.resolve().then(() => this._getFile(filePath).stat()); - } - - getAllFiles() { - return Object.keys(this._fastPaths) - .filter(filePath => !this._fastPaths[filePath].isDir); - } - - findFilesByExts(exts, { ignore } = {}) { - return this.getAllFiles() - .filter(filePath => ( - exts.indexOf(path.extname(filePath).substr(1)) !== -1 && - (!ignore || !ignore(filePath)) - )); - } - - matchFilesByPattern(pattern) { - return this.getAllFiles().filter(file => file.match(pattern)); - } - - readFile(filePath) { - const file = this._getFile(filePath); - if (!file) { - throw new Error(`Unable to find file with path: ${filePath}`); - } - return file.read(); - } - - readWhile(filePath, predicate) { - const file = this._getFile(filePath); - if (!file) { - throw new Error(`Unable to find file with path: ${filePath}`); - } - return file.readWhile(predicate); - } - - closest(filePath, name) { - for (let file = this._getFile(filePath).parent; - file; - file = file.parent) { - if (file.children[name]) { - return file.children[name].path; - } - } - return null; - } - - fileExists(filePath) { - let file; - try { - file = this._getFile(filePath); - } catch (e) { - if (e.type === NOT_FOUND_IN_ROOTS) { - return false; - } - throw e; - } - - return file && !file.isDir; - } - - dirExists(filePath) { - let file; - try { - file = this._getFile(filePath); - } catch (e) { - if (e.type === NOT_FOUND_IN_ROOTS) { - return false; - } - throw e; - } - - return file && file.isDir; - } - - matches(dir, pattern) { - const dirFile = this._getFile(dir); - if (!dirFile.isDir) { - throw new Error(`Expected file ${dirFile.path} to be a directory`); - } - - return Object.keys(dirFile.children) - .filter(name => name.match(pattern)) - .map(name => path.join(dirFile.path, name)); - } - - _getRoot(filePath) { - for (let i = 0; i < this._roots.length; i++) { - const possibleRoot = this._roots[i]; - if (isDescendant(possibleRoot.path, filePath)) { - return possibleRoot; - } - } - return null; - } - - _getAndAssertRoot(filePath) { - const root = this._getRoot(filePath); - if (!root) { - const error = new Error(`File ${filePath} not found in any of the roots`); - error.type = NOT_FOUND_IN_ROOTS; - throw error; - } - return root; - } - - _getFile(filePath) { - filePath = path.normalize(filePath); - if (!this._fastPaths[filePath]) { - const file = this._getAndAssertRoot(filePath).getFileFromPath(filePath); - if (file) { - this._fastPaths[filePath] = file; - } - } - - return this._fastPaths[filePath]; - } - - _processFileChange(type, filePath, rootPath, fstat) { - const absPath = path.join(rootPath, filePath); - if (this._ignore(absPath) || (fstat && fstat.isDirectory())) { - return; - } - - // Make sure this event belongs to one of our roots. - const root = this._getRoot(absPath); - if (!root) { - return; - } - - if (type === 'delete' || type === 'change') { - const file = this._getFile(absPath); - if (file) { - file.remove(); - } - } - - delete this._fastPaths[path.normalize(absPath)]; - - if (type !== 'delete') { - const file = new File(absPath, false); - root.addChild(file, this._fastPaths); - } - - this.emit('change', type, filePath, rootPath, fstat); - } -} - -class File { - constructor(filePath, isDir) { - this.path = filePath; - this.isDir = isDir; - this.children = this.isDir ? Object.create(null) : null; - } - - read() { - if (!this._read) { - this._read = readFile(this.path, 'utf8'); - } - return this._read; - } - - readWhile(predicate) { - return readWhile(this.path, predicate).then(({result, completed}) => { - if (completed && !this._read) { - this._read = Promise.resolve(result); - } - return result; - }); - } - - stat() { - if (!this._stat) { - this._stat = stat(this.path); - } - - return this._stat; - } - - addChild(file, fileMap) { - const parts = file.path.substr(this.path.length + 1).split(path.sep); - if (parts.length === 1) { - this.children[parts[0]] = file; - file.parent = this; - } else if (this.children[parts[0]]) { - this.children[parts[0]].addChild(file, fileMap); - } else { - const dir = new File(this.path + path.sep + parts[0], true); - dir.parent = this; - this.children[parts[0]] = dir; - fileMap[dir.path] = dir; - dir.addChild(file, fileMap); - } - } - - getFileFromPath(filePath) { - const parts = path.relative(this.path, filePath).split(path.sep); - - /*eslint consistent-this:0*/ - let file = this; - for (let i = 0; i < parts.length; i++) { - const fileName = parts[i]; - if (!fileName) { - continue; - } - - if (!file || !file.isDir) { - // File not found. - return null; - } - - file = file.children[fileName]; - } - - return file; - } - - ext() { - return path.extname(this.path).substr(1); - } - - remove() { - if (!this.parent) { - throw new Error(`No parent to delete ${this.path} from`); - } - - delete this.parent.children[path.basename(this.path)]; - } -} - -function readWhile(filePath, predicate) { - return new Promise((resolve, reject) => { - fs.open(filePath, 'r', (openError, fd) => { - if (openError) { - reject(openError); - return; - } - - read( - fd, - /*global Buffer: true*/ - new Buffer(512), - makeReadCallback(fd, predicate, (readError, result, completed) => { - if (readError) { - reject(readError); - } else { - resolve({result, completed}); - } - }) - ); - }); - }); -} - -function read(fd, buffer, callback) { - fs.read(fd, buffer, 0, buffer.length, -1, callback); -} - -function close(fd, error, result, complete, callback) { - fsClose(fd, closeError => callback(error || closeError, result, complete)); -} - -function makeReadCallback(fd, predicate, callback) { - let result = ''; - let index = 0; - return function readCallback(error, bytesRead, buffer) { - if (error) { - close(fd, error, undefined, false, callback); - return; - } - - const completed = bytesRead === 0; - const chunk = completed ? '' : buffer.toString('utf8', 0, bytesRead); - result += chunk; - if (completed || !predicate(chunk, index++, result)) { - close(fd, null, result, completed, callback); - } else { - read(fd, buffer, readCallback); - } - }; -} - -function isDescendant(root, child) { - return child.startsWith(root); -} - -module.exports = Fastfs; diff --git a/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js b/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js deleted file mode 100644 index ff61c4053..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest.dontMock('../getPlatformExtension') - .dontMock('../getAssetDataFromName'); - -var getAssetDataFromName = require('../getAssetDataFromName'); - -describe('getAssetDataFromName', () => { - it('should get data from name', () => { - expect(getAssetDataFromName('a/b/c.png')).toEqual({ - resolution: 1, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: null, - }); - - expect(getAssetDataFromName('a/b/c@1x.png')).toEqual({ - resolution: 1, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: null, - }); - - expect(getAssetDataFromName('a/b/c@2.5x.png')).toEqual({ - resolution: 2.5, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: null, - }); - - expect(getAssetDataFromName('a/b/c.ios.png')).toEqual({ - resolution: 1, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: 'ios', - }); - - expect(getAssetDataFromName('a/b/c@1x.ios.png')).toEqual({ - resolution: 1, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: 'ios', - }); - - expect(getAssetDataFromName('a/b/c@2.5x.ios.png')).toEqual({ - resolution: 2.5, - assetName: 'a/b/c.png', - type: 'png', - name: 'c', - platform: 'ios', - }); - }); - - describe('resolution extraction', () => { - it('should extract resolution simple case', () => { - var data = getAssetDataFromName('test@2x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 2, - type: 'png', - name: 'test', - platform: null, - }); - }); - - it('should default resolution to 1', () => { - var data = getAssetDataFromName('test.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 1, - type: 'png', - name: 'test', - platform: null, - }); - }); - - it('should support float', () => { - var data = getAssetDataFromName('test@1.1x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 1.1, - type: 'png', - name: 'test', - platform: null, - }); - - data = getAssetDataFromName('test@.1x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 0.1, - type: 'png', - name: 'test', - platform: null, - }); - - data = getAssetDataFromName('test@0.2x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 0.2, - type: 'png', - name: 'test', - platform: null, - }); - }); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js b/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js deleted file mode 100644 index f5ccdc3ab..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -jest.dontMock('../getPlatformExtension'); - -var getPlatformExtension = require('../getPlatformExtension'); - -describe('getPlatformExtension', function() { - it('should get platform ext', function() { - expect(getPlatformExtension('a.ios.js')).toBe('ios'); - expect(getPlatformExtension('a.android.js')).toBe('android'); - expect(getPlatformExtension('/b/c/a.ios.js')).toBe('ios'); - expect(getPlatformExtension('/b/c.android/a.ios.js')).toBe('ios'); - expect(getPlatformExtension('/b/c/a@1.5x.ios.png')).toBe('ios'); - expect(getPlatformExtension('/b/c/a@1.5x.lol.png')).toBe(null); - expect(getPlatformExtension('/b/c/a.lol.png')).toBe(null); - }); -}); diff --git a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js deleted file mode 100644 index 547ffbbb3..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const replacePatterns = require('./replacePatterns'); - -/** - * Extract all required modules from a `code` string. - */ -const blockCommentRe = /\/\*(.|\n)*?\*\//g; -const lineCommentRe = /\/\/.+(\n|$)/g; -function extractRequires(code) { - var deps = { - sync: [], - }; - - code = code - .replace(blockCommentRe, '') - .replace(lineCommentRe, '') - // Parse the sync dependencies this module has. When the module is - // required, all it's sync dependencies will be loaded into memory. - // Sync dependencies can be defined either using `require` or the ES6 - // `import` or `export` syntaxes: - // var dep1 = require('dep1'); - .replace(replacePatterns.IMPORT_RE, (match, pre, quot, dep, post) => { - deps.sync.push(dep); - return match; - }) - .replace(replacePatterns.EXPORT_RE, (match, pre, quot, dep, post) => { - deps.sync.push(dep); - return match; - }) - .replace(replacePatterns.REQUIRE_RE, (match, pre, quot, dep, post) => { - deps.sync.push(dep); - return match; - }); - - return {code, deps}; -} - -module.exports = extractRequires; diff --git a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js b/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js deleted file mode 100644 index a616d1084..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js +++ /dev/null @@ -1,55 +0,0 @@ - /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const path = require('fast-path'); -const getPlatformExtension = require('./getPlatformExtension'); - -function getAssetDataFromName(filename) { - const ext = path.extname(filename); - const platformExt = getPlatformExtension(filename); - - let pattern = '@([\\d\\.]+)x'; - if (platformExt != null) { - pattern += '(\\.' + platformExt + ')?'; - } - pattern += '\\' + ext + '$'; - const re = new RegExp(pattern); - - const match = filename.match(re); - let resolution; - - if (!(match && match[1])) { - resolution = 1; - } else { - resolution = parseFloat(match[1], 10); - if (isNaN(resolution)) { - resolution = 1; - } - } - - let assetName; - if (match) { - assetName = filename.replace(re, ext); - } else if (platformExt != null) { - assetName = filename.replace(new RegExp(`\\.${platformExt}\\${ext}`), ext); - } else { - assetName = filename; - } - - return { - resolution: resolution, - assetName: assetName, - type: ext.slice(1), - name: path.basename(assetName, ext), - platform: platformExt, - }; -} - -module.exports = getAssetDataFromName; diff --git a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js b/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js deleted file mode 100644 index 721470d10..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; - -const SUPPORTED_PLATFORM_EXTS = { - android: true, - ios: true, - web: true, -}; - -// Extract platform extension: index.ios.js -> ios -function getPlatformExtension(file) { - const last = file.lastIndexOf('.'); - const secondToLast = file.lastIndexOf('.', last - 1); - if (secondToLast === -1) { - return null; - } - const platform = file.substring(secondToLast + 1, last); - return SUPPORTED_PLATFORM_EXTS[platform] ? platform : null; -} - -module.exports = getPlatformExtension; diff --git a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js deleted file mode 100644 index 8c10710ec..000000000 --- a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -'use strict'; - -exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g; -exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g; -exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g; diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js index 7e1297689..ad4dc4d4e 100644 --- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js +++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js @@ -15,16 +15,20 @@ jest jest.mock('fs'); jest.setMock('temp', {path: () => '/arbitrary/path'}); -var Cache = require('../../DependencyResolver/Cache'); var Transformer = require('../'); var fs = require('fs'); +var Cache; var options; describe('Transformer', function() { var workers; beforeEach(function() { + Cache = require('node-haste').Cache; + + Cache.prototype.get = jest.genMockFn().mockImpl((a, b, c) => c()); + workers = jest.genMockFn(); jest.setMock('worker-farm', jest.genMockFn().mockImpl(function() { return workers; diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js index 2f1f65dea..7b3a5616c 100644 --- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js +++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js @@ -9,29 +9,29 @@ 'use strict'; jest.dontMock('../') - .dontMock('underscore') - .dontMock('../../DependencyResolver/lib/extractRequires') - .dontMock('../../DependencyResolver/lib/replacePatterns'); + .dontMock('underscore'); jest.mock('path'); -var Promise = require('promise'); -var Resolver = require('../'); -var Module = require('../../DependencyResolver/Module'); -var Polyfill = require('../../DependencyResolver/Polyfill'); -var DependencyGraph = require('../../DependencyResolver/DependencyGraph'); +const Promise = require('promise'); +const Resolver = require('../'); +const DependencyGraph = require('node-haste'); -var path = require('path'); -var _ = require('underscore'); +const path = require('path'); +const _ = require('underscore'); + +let Module; +let Polyfill; describe('Resolver', function() { beforeEach(function() { - Polyfill.mockClear(); + Module = require('node-haste').Module; + Polyfill = require('node-haste').Polyfill; + + DependencyGraph.replacePatterns = require.requireActual('node-haste/lib/lib/replacePatterns'); // For the polyfillDeps - path.join.mockImpl(function(a, b) { - return b; - }); + path.join = jest.genMockFn().mockImpl((a, b) => b); DependencyGraph.prototype.load.mockImpl(() => Promise.resolve()); }); diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js index 7e993a5d7..5b9e89024 100644 --- a/packager/react-packager/src/Resolver/index.js +++ b/packager/react-packager/src/Resolver/index.js @@ -11,9 +11,9 @@ const path = require('path'); const Activity = require('../Activity'); -const DependencyGraph = require('../DependencyResolver/DependencyGraph'); -const replacePatterns = require('../DependencyResolver/lib/replacePatterns'); -const Polyfill = require('../DependencyResolver/Polyfill'); +const DependencyGraph = require('node-haste'); +const replacePatterns = require('node-haste').replacePatterns; +const Polyfill = require('node-haste').Polyfill; const declareOpts = require('../lib/declareOpts'); const Promise = require('promise'); diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js index e6a74aeb0..246397a2c 100644 --- a/packager/react-packager/src/Server/__tests__/Server-test.js +++ b/packager/react-packager/src/Server/__tests__/Server-test.js @@ -21,11 +21,12 @@ jest.setMock('worker-farm', function() { return () => {}; }) const Promise = require('promise'); var Bundler = require('../../Bundler'); -var FileWatcher = require('../../DependencyResolver/FileWatcher'); var Server = require('../'); var Server = require('../../Server'); var AssetServer = require('../../AssetServer'); +var FileWatcher; + describe('processRequest', () => { var server; @@ -58,6 +59,7 @@ describe('processRequest', () => { var triggerFileChange; beforeEach(() => { + FileWatcher = require('node-haste').FileWatcher; Bundler.prototype.bundle = jest.genMockFunction().mockImpl(() => Promise.resolve({ getSource: () => 'this is the source', diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js index aa32175aa..7db64bf74 100644 --- a/packager/react-packager/src/Server/index.js +++ b/packager/react-packager/src/Server/index.js @@ -10,8 +10,8 @@ const Activity = require('../Activity'); const AssetServer = require('../AssetServer'); -const FileWatcher = require('../DependencyResolver/FileWatcher'); -const getPlatformExtension = require('../DependencyResolver/lib/getPlatformExtension'); +const FileWatcher = require('node-haste').FileWatcher; +const getPlatformExtension = require('node-haste').getPlatformExtension; const Bundler = require('../Bundler'); const Promise = require('promise'); diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js index cf8345b3e..b5a7b9160 100644 --- a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js +++ b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js @@ -8,8 +8,7 @@ */ 'use strict'; -jest.setMock('worker-farm', function() { return () => {}; }) - .setMock('uglify-js') +jest.setMock('uglify-js') .mock('child_process') .dontMock('underscore') .dontMock('../'); diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js index 39c28d965..c269a0e55 100644 --- a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js +++ b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js @@ -8,8 +8,7 @@ */ 'use strict'; -jest.setMock('worker-farm', function() { return () => {}; }) - .setMock('uglify-js') +jest.setMock('uglify-js') .mock('net') .mock('fs') .dontMock('../SocketServer'); diff --git a/packager/react-packager/src/__mocks__/fs.js b/packager/react-packager/src/__mocks__/fs.js index 64b0c9b18..adcbf11ad 100644 --- a/packager/react-packager/src/__mocks__/fs.js +++ b/packager/react-packager/src/__mocks__/fs.js @@ -8,181 +8,4 @@ */ 'use strict'; -var fs = jest.genMockFromModule('fs'); - -function asyncCallback(callback) { - return function() { - setImmediate(() => callback.apply(this, arguments)); - }; -} - -fs.realpath.mockImpl(function(filepath, callback) { - callback = asyncCallback(callback); - var node; - try { - node = getToNode(filepath); - } catch (e) { - return callback(e); - } - if (node && typeof node === 'object' && node.SYMLINK != null) { - return callback(null, node.SYMLINK); - } - callback(null, filepath); -}); - -fs.readdir.mockImpl(function(filepath, callback) { - callback = asyncCallback(callback); - var node; - try { - node = getToNode(filepath); - if (node && typeof node === 'object' && node.SYMLINK != null) { - node = getToNode(node.SYMLINK); - } - } catch (e) { - return callback(e); - } - - if (!(node && typeof node === 'object' && node.SYMLINK == null)) { - return callback(new Error(filepath + ' is not a directory.')); - } - - callback(null, Object.keys(node)); -}); - -fs.readFile.mockImpl(function(filepath, encoding, callback) { - callback = asyncCallback(callback); - if (arguments.length === 2) { - callback = encoding; - encoding = null; - } - - try { - var node = getToNode(filepath); - // dir check - if (node && typeof node === 'object' && node.SYMLINK == null) { - callback(new Error('Error readFile a dir: ' + filepath)); - } - return callback(null, node); - } catch (e) { - return callback(e); - } -}); - -fs.stat.mockImpl(function(filepath, callback) { - callback = asyncCallback(callback); - var node; - try { - node = getToNode(filepath); - } catch (e) { - callback(e); - return; - } - - var mtime = { - getTime: function() { - return Math.ceil(Math.random() * 10000000); - }, - }; - - if (node.SYMLINK) { - fs.stat(node.SYMLINK, callback); - return; - } - - if (node && typeof node === 'object') { - callback(null, { - isDirectory: function() { - return true; - }, - isSymbolicLink: function() { - return false; - }, - mtime: mtime, - }); - } else { - callback(null, { - isDirectory: function() { - return false; - }, - isSymbolicLink: function() { - return false; - }, - mtime: mtime, - }); - } -}); - -const noop = () => {}; -fs.open.mockImpl(function(path) { - const callback = arguments[arguments.length - 1] || noop; - let data, error, fd; - try { - data = getToNode(path); - } catch (e) { - error = e; - } - - if (error || data == null) { - error = Error(`ENOENT: no such file or directory, open ${path}`); - } - if (data != null) { - /* global Buffer: true */ - fd = { - buffer: new Buffer(data, 'utf8'), - position: 0, - }; - } - - callback(error, fd); -}); - -fs.read.mockImpl((fd, buffer, writeOffset, length, position, callback = noop) => { - let bytesWritten; - try { - if (position == null || position < 0) { - ({position} = fd); - } - bytesWritten = - fd.buffer.copy(buffer, writeOffset, position, position + length); - fd.position = position + bytesWritten; - } catch (e) { - callback(Error('invalid argument')); - return; - } - callback(null, bytesWritten, buffer); -}); - -fs.close.mockImpl((fd, callback = noop) => { - try { - fd.buffer = fs.position = undefined; - } catch (e) { - callback(Error('invalid argument')); - return; - } - callback(null); -}); - -var filesystem; - -fs.__setMockFilesystem = function(object) { - filesystem = object; - return filesystem; -}; - -function getToNode(filepath) { - var parts = filepath.split('/'); - if (parts[0] !== '') { - throw new Error('Make sure all paths are absolute.'); - } - var node = filesystem; - parts.slice(1).forEach(function(part) { - if (node && node.SYMLINK) { - node = getToNode(node.SYMLINK); - } - node = node[part]; - }); - - return node; -} - -module.exports = fs; +module.exports = require.requireActual('node-haste/mocks/graceful-fs');