Skip to content

Commit 3a2854a

Browse files
authored
Add jest-serializer module (#5609)
1 parent bea889c commit 3a2854a

7 files changed

Lines changed: 335 additions & 33 deletions

File tree

packages/jest-haste-map/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"fb-watchman": "^2.0.0",
1212
"graceful-fs": "^4.1.11",
1313
"jest-docblock": "^22.2.2",
14+
"jest-serializer": "^22.3.0",
1415
"jest-worker": "^22.2.2",
1516
"micromatch": "^2.3.11",
1617
"sane": "^2.0.0"

packages/jest-haste-map/src/index.js

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {version as VERSION} from '../package.json';
1212
import {worker} from './worker';
1313
import crypto from 'crypto';
1414
import EventEmitter from 'events';
15-
import fs from 'graceful-fs';
1615
import getMockName from './get_mock_name';
1716
import getPlatformExtension from './lib/get_platform_extension';
1817
// eslint-disable-next-line import/no-duplicates
@@ -25,7 +24,7 @@ import normalizePathSep from './lib/normalize_path_sep';
2524
import os from 'os';
2625
import path from 'path';
2726
import sane from 'sane';
28-
import v8 from 'v8';
27+
import serializer from 'jest-serializer';
2928
// eslint-disable-next-line import/default
3029
import watchmanCrawl from './crawlers/watchman';
3130
import WatchmanWatcher from './lib/watchman_watcher';
@@ -290,21 +289,14 @@ class HasteMap extends EventEmitter {
290289
* 1. read data from the cache or create an empty structure.
291290
*/
292291
read(): InternalHasteMap {
293-
if (v8.deserialize) {
294-
// This may throw. `_buildFileMap` will catch it and create a new map.
295-
const {version, hasteMap} = v8.deserialize(
296-
fs.readFileSync(this._cachePath),
297-
);
298-
if (version !== process.versions.v8) {
299-
throw new Error('jest-haste-map: v8 versions do not match.');
300-
}
301-
return removePrototypes(hasteMap);
302-
} else {
303-
const hasteMap = (JSON.parse(
304-
fs.readFileSync(this._cachePath, 'utf8'),
305-
): InternalHasteMap);
306-
return removePrototypes(hasteMap);
292+
// This may throw. `_buildFileMap` will catch it and create a new map.
293+
const hasteMap: InternalHasteMap = serializer.readFileSync(this._cachePath);
294+
295+
for (const key in hasteMap) {
296+
Object.setPrototypeOf(hasteMap[key], null);
307297
}
298+
299+
return hasteMap;
308300
}
309301

310302
readModuleMap(): ModuleMap {
@@ -534,17 +526,7 @@ class HasteMap extends EventEmitter {
534526
* 4. serialize the new `HasteMap` in a cache file.
535527
*/
536528
_persist(hasteMap: InternalHasteMap) {
537-
if (v8.serialize) {
538-
fs.writeFileSync(
539-
this._cachePath,
540-
v8.serialize({
541-
hasteMap,
542-
version: process.versions.v8,
543-
}),
544-
);
545-
} else {
546-
fs.writeFileSync(this._cachePath, JSON.stringify(hasteMap), 'utf8');
547-
}
529+
serializer.writeFileSync(this._cachePath, hasteMap);
548530
}
549531

550532
/**
@@ -913,12 +895,6 @@ class HasteMap extends EventEmitter {
913895
}
914896

915897
const copy = object => Object.assign(Object.create(null), object);
916-
const removePrototypes = object => {
917-
for (const key in object) {
918-
Object.setPrototypeOf(object[key], null);
919-
}
920-
return object;
921-
};
922898

923899
HasteMap.H = H;
924900
HasteMap.ModuleMap = HasteModuleMap;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
**/__mocks__/**
2+
**/__tests__/**
3+
src

packages/jest-serializer/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# jest-serializer
2+
3+
Module for serializing and deserializing object into memory and disk. By
4+
default, the `v8` implementations are used, but if not present, it defaults to
5+
`JSON` implementation. Both serializers have the advantage of being able to
6+
serialize `Map`, `Set`, `undefined`, `NaN`, etc, although the JSON one does it
7+
through a replacer/reviver.
8+
9+
## Install
10+
11+
```sh
12+
$ yarn add jest-serializer
13+
```
14+
15+
## API
16+
17+
Three kinds of API groups are exposed:
18+
19+
### In-memory serialization: `serialize` and `deserialize`
20+
21+
This set of functions take or return a `Buffer`. All the process happens in
22+
memory. This is useful when willing to transfer over HTTP, TCP or via UNIX
23+
pipes.
24+
25+
```javascript
26+
import {serialize, deserialize} from 'jest-serializer';
27+
28+
const myObject = {
29+
foo: 'bar',
30+
baz: [0, true, '2', [], {}],
31+
};
32+
33+
const buffer = serialize(myObject);
34+
const myCopyObject = deserialize(buffer);
35+
```
36+
37+
### Synchronous persistent filesystem: `readFileSync` and `writeFileSync`
38+
39+
This set of functions allow to send to disk a serialization result and retrieve
40+
it back, in a synchronous way. It mimics the `fs` API so it looks familiar.
41+
42+
```javascript
43+
import {readFileSync, writeFileSync} from 'jest-serializer';
44+
45+
const myObject = {
46+
foo: 'bar',
47+
baz: [0, true, '2', [], {}],
48+
};
49+
50+
const myFile = '/tmp/obj';
51+
52+
writeFileSync(myFile, myObject);
53+
const myCopyObject = readFileSync(myFile);
54+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "jest-serializer",
3+
"version": "22.3.0",
4+
"repository": {
5+
"type": "git",
6+
"url": "https://github.com/facebook/jest.git"
7+
},
8+
"license": "MIT",
9+
"main": "build/index.js"
10+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Copyright (c) 2018-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
'use strict';
9+
10+
import prettyFormat from 'pretty-format';
11+
12+
import fs from 'fs';
13+
import os from 'os';
14+
import path from 'path';
15+
import v8 from 'v8';
16+
17+
import serializer from '..';
18+
19+
const v8s = [
20+
{
21+
deserialize: v8.deserialize,
22+
serialize: v8.serialize,
23+
},
24+
{
25+
deserialize: undefined,
26+
serialize: undefined,
27+
},
28+
];
29+
30+
const objs = [
31+
3,
32+
null,
33+
[0, true, '2', [3.14, {}, null]],
34+
{key1: 'foo', key2: 'bar', key3: {array: [null, {}]}},
35+
{minusInf: -Infinity, nan: NaN, plusInf: +Infinity},
36+
{date: new Date(1234567890), re: /foo/gi},
37+
{map: new Map([[NaN, 4], [undefined, 'm']]), set: new Set([undefined, NaN])},
38+
{buf: Buffer.from([0, 255, 127])},
39+
];
40+
41+
const file = path.join(os.tmpdir(), '__jest-serialize-test__');
42+
43+
afterEach(() => {
44+
try {
45+
fs.unlinkSync(file);
46+
} catch (err) {
47+
// Do nothing if file does not exist.
48+
}
49+
});
50+
51+
// We execute the same suite of tests over multiple objects ("objs") and over
52+
// multiple mocks of the V8 object ("v8s") so that we verify that all possible
53+
// encodings and cases work.
54+
v8s.forEach((mockV8, i) => {
55+
describe('Using V8 implementation ' + i, () => {
56+
beforeEach(() => {
57+
v8.serialize = mockV8.serialize;
58+
v8.deserialize = mockV8.deserialize;
59+
});
60+
61+
it('throws the error with an invalid serialization', () => {
62+
// No chance this is a valid serialization, neither in JSON nor V8.
63+
const invalidBuffer = Buffer.from([0, 85, 170, 255]);
64+
65+
fs.writeFileSync(file, invalidBuffer);
66+
67+
expect(() => serializer.deserialize(invalidBuffer)).toThrow();
68+
expect(() => serializer.readFileSync(file)).toThrow();
69+
});
70+
71+
objs.forEach((obj, i) => {
72+
describe('Object ' + i, () => {
73+
it('serializes/deserializes in memory', () => {
74+
const buf = serializer.serialize(obj);
75+
76+
expect(buf).toBeInstanceOf(Buffer);
77+
78+
expect(prettyFormat(serializer.deserialize(buf))).toEqual(
79+
prettyFormat(obj),
80+
);
81+
});
82+
83+
it('serializes/deserializes in disk', () => {
84+
serializer.writeFileSync(file, obj);
85+
86+
expect(prettyFormat(serializer.readFileSync(file))).toEqual(
87+
prettyFormat(obj),
88+
);
89+
});
90+
});
91+
});
92+
});
93+
});

0 commit comments

Comments
 (0)