From c35b78b7c0e6f7944b5b52392efdb09abc860570 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Wed, 14 Feb 2018 23:52:08 +0000 Subject: [PATCH] Use v8.serialize when available (#5565) --- .../src/__tests__/index.test.js | 17 ++-- packages/jest-haste-map/src/index.js | 93 ++++++++++++------- 2 files changed, 68 insertions(+), 42 deletions(-) diff --git a/packages/jest-haste-map/src/__tests__/index.test.js b/packages/jest-haste-map/src/__tests__/index.test.js index 392fc932b8b9..df588dc896d1 100644 --- a/packages/jest-haste-map/src/__tests__/index.test.js +++ b/packages/jest-haste-map/src/__tests__/index.test.js @@ -70,8 +70,6 @@ let mockFs; jest.mock('graceful-fs', () => ({ readFileSync: jest.fn((path, options) => { - expect(options).toBe('utf8'); - // A file change can be triggered by writing into the // mockChangedFiles object. if (mockChangedFiles && path in mockChangedFiles) { @@ -87,7 +85,7 @@ jest.mock('graceful-fs', () => ({ throw error; }), writeFileSync: jest.fn((path, data, options) => { - expect(options).toBe('utf8'); + expect(options).toBe(require('v8').serialize ? undefined : 'utf8'); mockFs[path] = data; }), })); @@ -468,8 +466,11 @@ describe('HasteMap', () => { .build() .then(({__hasteMapForTest: data}) => { expect(fs.readFileSync.mock.calls.length).toBe(1); - expect(fs.readFileSync).toBeCalledWith(cacheFilePath, 'utf8'); - + if (require('v8').deserialize) { + expect(fs.readFileSync).toBeCalledWith(cacheFilePath); + } else { + expect(fs.readFileSync).toBeCalledWith(cacheFilePath, 'utf8'); + } expect(data.clocks).toEqual(mockClocks); expect(data.files).toEqual(initialData.files); expect(data.map).toEqual(initialData.map); @@ -504,7 +505,11 @@ describe('HasteMap', () => { .then(({__hasteMapForTest: data}) => { expect(fs.readFileSync.mock.calls.length).toBe(2); - expect(fs.readFileSync).toBeCalledWith(cacheFilePath, 'utf8'); + if (require('v8').serialize) { + expect(fs.readFileSync).toBeCalledWith(cacheFilePath); + } else { + expect(fs.readFileSync).toBeCalledWith(cacheFilePath, 'utf8'); + } expect(fs.readFileSync).toBeCalledWith('/fruits/banana.js', 'utf8'); expect(data.clocks).toEqual(mockClocks); diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index a5bcef728c7f..c990ea92f9ae 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -7,6 +7,30 @@ * @flow */ +import {execSync} from 'child_process'; +import {version as VERSION} from '../package.json'; +import {worker} from './worker'; +import crypto from 'crypto'; +import EventEmitter from 'events'; +import fs from 'graceful-fs'; +import getMockName from './get_mock_name'; +import getPlatformExtension from './lib/get_platform_extension'; +// eslint-disable-next-line import/no-duplicates +import H from './constants'; +import HasteFS from './haste_fs'; +import HasteModuleMap from './module_map'; +// eslint-disable-next-line import/default +import nodeCrawl from './crawlers/node'; +import normalizePathSep from './lib/normalize_path_sep'; +import os from 'os'; +import path from 'path'; +import sane from 'sane'; +import v8 from 'v8'; +// eslint-disable-next-line import/default +import watchmanCrawl from './crawlers/watchman'; +import WatchmanWatcher from './lib/watchman_watcher'; +import Worker from 'jest-worker'; + import type {Console} from 'console'; import type {Path} from 'types/Config'; import type { @@ -18,34 +42,9 @@ import type { MockData, } from 'types/HasteMap'; -import {worker} from './worker'; - // eslint-disable-next-line import/no-duplicates import typeof HType from './constants'; -import EventEmitter from 'events'; -import os from 'os'; -import path from 'path'; -import crypto from 'crypto'; -import {execSync} from 'child_process'; -import fs from 'graceful-fs'; -import sane from 'sane'; -import {version as VERSION} from '../package.json'; -// eslint-disable-next-line import/no-duplicates -import H from './constants'; -import HasteFS from './haste_fs'; -import HasteModuleMap from './module_map'; -import getMockName from './get_mock_name'; -import getPlatformExtension from './lib/get_platform_extension'; -import normalizePathSep from './lib/normalize_path_sep'; -import Worker from 'jest-worker'; -import WatchmanWatcher from './lib/watchman_watcher'; - -// eslint-disable-next-line import/default -import nodeCrawl from './crawlers/node'; -// eslint-disable-next-line import/default -import watchmanCrawl from './crawlers/watchman'; - type Options = { cacheDirectory?: string, console?: Console, @@ -291,7 +290,21 @@ class HasteMap extends EventEmitter { * 1. read data from the cache or create an empty structure. */ read(): InternalHasteMap { - return this._parse(fs.readFileSync(this._cachePath, 'utf8')); + if (v8.deserialize) { + // This may throw. `_buildFileMap` will catch it and create a new map. + const {version, hasteMap} = v8.deserialize( + fs.readFileSync(this._cachePath), + ); + if (version !== process.versions.v8) { + throw new Error('jest-haste-map: v8 versions do not match.'); + } + return removePrototypes(hasteMap); + } else { + const hasteMap = (JSON.parse( + fs.readFileSync(this._cachePath, 'utf8'), + ): InternalHasteMap); + return removePrototypes(hasteMap); + } } readModuleMap(): ModuleMap { @@ -520,8 +533,18 @@ class HasteMap extends EventEmitter { /** * 4. serialize the new `HasteMap` in a cache file. */ - _persist(hasteMap: InternalHasteMap): void { - fs.writeFileSync(this._cachePath, JSON.stringify(hasteMap), 'utf8'); + _persist(hasteMap: InternalHasteMap) { + if (v8.serialize) { + fs.writeFileSync( + this._cachePath, + v8.serialize({ + hasteMap, + version: process.versions.v8, + }), + ); + } else { + fs.writeFileSync(this._cachePath, JSON.stringify(hasteMap), 'utf8'); + } } /** @@ -544,14 +567,6 @@ class HasteMap extends EventEmitter { return this._worker; } - _parse(hasteMapPath: string): InternalHasteMap { - const hasteMap = (JSON.parse(hasteMapPath): InternalHasteMap); - for (const key in hasteMap) { - Object.setPrototypeOf(hasteMap[key], null); - } - return hasteMap; - } - _crawl(hasteMap: InternalHasteMap): Promise { const options = this._options; const ignore = this._ignore.bind(this); @@ -898,6 +913,12 @@ class HasteMap extends EventEmitter { } const copy = object => Object.assign(Object.create(null), object); +const removePrototypes = object => { + for (const key in object) { + Object.setPrototypeOf(object[key], null); + } + return object; +}; HasteMap.H = H; HasteMap.ModuleMap = HasteModuleMap;