Skip to content

Commit 4bd475e

Browse files
authored
Merge pull request #7 from Conduitry/pojo-detection
enhance POJO detection
2 parents 2569060 + a64532c commit 4bd475e

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

src/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
22
const reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
33
const unsafe = /[<>\/\u2028\u2029]/g;
44
const escaped: Record<string, string> = { '<': '\\u003C', '>' : '\\u003E', '/': '\\u002F', '\u2028': '\\u2028', '\u2029': '\\u2029' };
5+
const objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join('\0');
56

67
export default function devalue(value: any) {
78
const repeated = new Map();
@@ -44,8 +45,16 @@ export default function devalue(value: any) {
4445
default:
4546
const proto = Object.getPrototypeOf(thing);
4647

47-
if (proto !== Object.prototype && proto !== null) {
48-
throw new Error(`Cannot stringify arbitrary non-POJOs`);
48+
if (
49+
proto !== Object.prototype &&
50+
proto !== null &&
51+
Object.getOwnPropertyNames(proto).sort().join('\0') !== objectProtoOwnPropertyNames
52+
) {
53+
throw new Error(`Cannot stringify arbitrary non-POJOs`);
54+
}
55+
56+
if (Object.getOwnPropertySymbols(thing).length > 0) {
57+
throw new Error(`Cannot stringify POJOs with symbolic keys`);
4958
}
5059

5160
Object.keys(thing).forEach(key => walk(thing[key]));

test/test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as assert from 'assert';
2+
import * as vm from 'vm';
23
import devalue from '../src/index';
34

45
describe('devalue', () => {
@@ -80,5 +81,17 @@ describe('devalue', () => {
8081
// let arr = [];
8182
// arr.x = 42;
8283
// test('Array with named properties', arr, `TODO`);
84+
85+
test('cross-realm POJO', vm.runInNewContext('({})'), '{}');
86+
87+
it('throws for non-POJOs', () => {
88+
class Foo {}
89+
const foo = new Foo();
90+
assert.throws(() => devalue(foo));
91+
});
92+
93+
it('throws for symbolic keys', () => {
94+
assert.throws(() => devalue({ [Symbol()]: null }));
95+
});
8396
});
8497
});

0 commit comments

Comments
 (0)