diff --git a/packages/jest-haste-map/src/__tests__/index.test.js b/packages/jest-haste-map/src/__tests__/index.test.js index df588dc896d1..546bb8c06d8d 100644 --- a/packages/jest-haste-map/src/__tests__/index.test.js +++ b/packages/jest-haste-map/src/__tests__/index.test.js @@ -141,10 +141,12 @@ describe('HasteMap', () => { '/vegetables/melon.js': ['/**', ' * @providesModule Melon', ' */'].join( '\n', ), + '/video/video.mp4': Buffer.from([0xfa, 0xce, 0xb0, 0x0c]).toString(), }); mockClocks = object({ '/fruits': 'c:fake-clock:1', '/vegetables': 'c:fake-clock:2', + '/video': 'c:fake-clock:3', }); mockChangedFiles = null; @@ -305,6 +307,28 @@ describe('HasteMap', () => { }); }); + it('does not crawl native files even if requested to do so', async () => { + mockFs['/video/i-require-a-video.js'] = [ + '/**', + ' * @providesModule IRequireAVideo', + ' */', + 'module.exports = require("./video.mp4");', + ].join('\n'); + + const hasteMap = new HasteMap( + Object.assign({}, defaultConfig, { + extensions: [...defaultConfig.extensions], + roots: [...defaultConfig.roots, '/video'], + }), + ); + + const {__hasteMapForTest: data} = await hasteMap.build(); + + expect(data.map.IRequireAVideo).toBeDefined(); + expect(data.files['/video/video.mp4']).toBeDefined(); + expect(fs.readFileSync).not.toBeCalledWith('/video/video.mp4', 'utf8'); + }); + it('retains all files if `retainAllFiles` is specified', () => { mockFs['/fruits/node_modules/fbjs/index.js'] = [ '/**', diff --git a/packages/jest-haste-map/src/blacklist.js b/packages/jest-haste-map/src/blacklist.js new file mode 100644 index 000000000000..6acaeb9b949b --- /dev/null +++ b/packages/jest-haste-map/src/blacklist.js @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +// This list is compiled after the MDN list of the most common MIME types (see +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/ +// Complete_list_of_MIME_types). +// +// Only MIME types starting with "image/", "video/", "audio/" and "font/" are +// reflected in the list. Adding "application/" is too risky since some text +// file formats (like ".js" and ".json") have an "application/" MIME type. +// +// Feel free to add any extensions that cannot contain any "@providesModule" +// annotation. + +const extensions: Set = new Set([ + // JSONs are never haste modules, except for "package.json", which is handled. + '.json', + + // Image extensions. + '.bmp', + '.gif', + '.ico', + '.jpeg', + '.jpg', + '.png', + '.svg', + '.tiff', + '.tif', + '.webp', + + // Video extensions. + '.avi', + '.mp4', + '.mpeg', + '.mpg', + '.ogv', + '.webm', + '.3gp', + '.3g2', + + // Audio extensions. + '.aac', + '.midi', + '.mid', + '.mp3', + '.oga', + '.wav', + '.3gp', + '.3g2', + + // Font extensions. + '.eot', + '.otf', + '.ttf', + '.woff', + '.woff2', +]); + +export default extensions; diff --git a/packages/jest-haste-map/src/worker.js b/packages/jest-haste-map/src/worker.js index 8a835c3a4492..c35365a15836 100644 --- a/packages/jest-haste-map/src/worker.js +++ b/packages/jest-haste-map/src/worker.js @@ -12,11 +12,11 @@ import type {HasteImpl, WorkerMessage, WorkerMetadata} from './types'; import path from 'path'; import * as docblock from 'jest-docblock'; import fs from 'graceful-fs'; +import blacklist from './blacklist'; import H from './constants'; import extractRequires from './lib/extract_requires'; -const JSON_EXTENSION = '.json'; -const PACKAGE_JSON = path.sep + 'package' + JSON_EXTENSION; +const PACKAGE_JSON = path.sep + 'package.json'; let hasteImpl: ?HasteImpl = null; let hasteImplModulePath: ?string = null; @@ -35,26 +35,33 @@ export async function worker(data: WorkerMessage): Promise { } const filePath = data.filePath; - const content = fs.readFileSync(filePath, 'utf8'); let module; let id: ?string; let dependencies; if (filePath.endsWith(PACKAGE_JSON)) { - const fileData = JSON.parse(content); + const fileData = JSON.parse(fs.readFileSync(filePath, 'utf8')); + if (fileData.name) { id = fileData.name; module = [filePath, H.PACKAGE]; } - } else if (!filePath.endsWith(JSON_EXTENSION)) { + + return {dependencies, id, module}; + } + + if (!blacklist.has(filePath.substr(filePath.lastIndexOf('.')))) { + const content = fs.readFileSync(filePath, 'utf8'); + if (hasteImpl) { id = hasteImpl.getHasteName(filePath); } else { const doc = docblock.parse(docblock.extract(content)); - const idPragmas = [].concat(doc.providesModule || doc.provides); - id = idPragmas[0]; + id = [].concat(doc.providesModule || doc.provides)[0]; } + dependencies = extractRequires(content); + if (id) { module = [filePath, H.MODULE]; }