Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid loading files that we know are binary ahead of time #5612

Merged
merged 1 commit into from
Feb 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/jest-cli/src/search_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {Glob, GlobalConfig, Path} from 'types/Config';
import type {Test} from 'types/TestRunner';
import type {ChangedFilesPromise} from 'types/ChangedFiles';

import fs from 'fs';
import path from 'path';
import micromatch from 'micromatch';
import DependencyResolver from 'jest-resolve-dependencies';
Expand Down
24 changes: 24 additions & 0 deletions packages/jest-haste-map/src/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'] = [
'/**',
Expand Down
65 changes: 65 additions & 0 deletions packages/jest-haste-map/src/blacklist.js
Original file line number Diff line number Diff line change
@@ -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<string> = 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;
21 changes: 14 additions & 7 deletions packages/jest-haste-map/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,26 +35,33 @@ export async function worker(data: WorkerMessage): Promise<WorkerMetadata> {
}

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];
}
Expand Down