Skip to content

Commit 493a9b6

Browse files
Add 'extensions' to all Type System objects (#2097)
Fixes #1527
1 parent 57e7e1b commit 493a9b6

13 files changed

+564
-2
lines changed

src/jsutils/ObjMap.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
// @flow strict
22

33
export type ObjMap<T> = { [key: string]: T, __proto__: null, ... };
4+
export type ObjMapLike<T> = ObjMap<T> | { [key: string]: T, ... };
5+
6+
export type ReadOnlyObjMap<T> = { +[key: string]: T, __proto__: null, ... };
7+
export type ReadOnlyObjMapLike<T> =
8+
| ReadOnlyObjMap<T>
9+
| { +[key: string]: T, ... };
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// @flow strict
2+
3+
import { expect } from 'chai';
4+
import { describe, it } from 'mocha';
5+
6+
import toObjMap from '../toObjMap';
7+
import { type ObjMapLike } from '../ObjMap';
8+
9+
// Workaround to make both ESLint and Flow happy
10+
const __proto__: string = '__proto__';
11+
12+
describe('toObjMap', () => {
13+
it('convert empty object to ObjMap', () => {
14+
const result = toObjMap({});
15+
expect(result).to.deep.equal({});
16+
expect(Object.getPrototypeOf(result)).to.equal(null);
17+
});
18+
19+
it('convert object with own properties to ObjMap', () => {
20+
const obj: ObjMapLike<string> = Object.freeze({ foo: 'bar' });
21+
22+
const result = toObjMap(obj);
23+
expect(result).to.deep.equal(obj);
24+
expect(Object.getPrototypeOf(result)).to.equal(null);
25+
});
26+
27+
it('convert object with __proto__ property to ObjMap', () => {
28+
const protoObj = Object.freeze({ toString: false });
29+
const obj = Object.create(null);
30+
obj[__proto__] = protoObj;
31+
Object.freeze(obj);
32+
33+
const result = toObjMap(obj);
34+
expect(Object.keys(result)).to.deep.equal(['__proto__']);
35+
expect(Object.getPrototypeOf(result)).to.equal(null);
36+
expect(result[__proto__]).to.equal(protoObj);
37+
});
38+
39+
it('passthrough empty ObjMap', () => {
40+
const objMap = Object.create(null);
41+
expect(toObjMap(objMap)).to.deep.equal(objMap);
42+
});
43+
44+
it('passthrough ObjMap with properties', () => {
45+
const objMap = Object.freeze({
46+
__proto__: null,
47+
foo: 'bar',
48+
});
49+
expect(toObjMap(objMap)).to.deep.equal(objMap);
50+
});
51+
});

src/jsutils/toObjMap.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @flow strict
2+
3+
import objectEntries from '../polyfills/objectEntries';
4+
import {
5+
type ObjMap,
6+
type ObjMapLike,
7+
type ReadOnlyObjMap,
8+
type ReadOnlyObjMapLike,
9+
} from './ObjMap';
10+
11+
/* eslint-disable no-redeclare */
12+
declare function toObjMap<T>(obj: ObjMapLike<T>): ObjMap<T>;
13+
declare function toObjMap<T>(obj: ReadOnlyObjMapLike<T>): ReadOnlyObjMap<T>;
14+
15+
export default function toObjMap(obj) {
16+
/* eslint-enable no-redeclare */
17+
if (Object.getPrototypeOf(obj) === null) {
18+
return obj;
19+
}
20+
21+
const map = Object.create(null);
22+
for (const [key, value] of objectEntries(obj)) {
23+
map[key] = value;
24+
}
25+
return map;
26+
}

src/type/__tests__/definition-test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ describe('Type System: Objects', () => {
195195
subscribe: undefined,
196196
isDeprecated: true,
197197
deprecationReason: 'A terrible reason',
198+
extensions: undefined,
198199
astNode: undefined,
199200
});
200201
});
@@ -216,6 +217,7 @@ describe('Type System: Objects', () => {
216217
subscribe: undefined,
217218
isDeprecated: false,
218219
deprecationReason: undefined,
220+
extensions: undefined,
219221
astNode: undefined,
220222
},
221223
});
@@ -244,13 +246,15 @@ describe('Type System: Objects', () => {
244246
description: null,
245247
type: ScalarType,
246248
defaultValue: undefined,
249+
extensions: undefined,
247250
astNode: undefined,
248251
},
249252
],
250253
resolve: undefined,
251254
subscribe: undefined,
252255
isDeprecated: false,
253256
deprecationReason: undefined,
257+
extensions: undefined,
254258
astNode: undefined,
255259
},
256260
});
@@ -524,6 +528,7 @@ describe('Type System: Enums', () => {
524528
isDeprecated: true,
525529
deprecationReason: 'Just because',
526530
value: 'foo',
531+
extensions: undefined,
527532
astNode: undefined,
528533
});
529534
});
@@ -544,6 +549,7 @@ describe('Type System: Enums', () => {
544549
value: null,
545550
isDeprecated: false,
546551
deprecationReason: undefined,
552+
extensions: undefined,
547553
astNode: undefined,
548554
},
549555
{
@@ -552,6 +558,7 @@ describe('Type System: Enums', () => {
552558
value: undefined,
553559
isDeprecated: false,
554560
deprecationReason: undefined,
561+
extensions: undefined,
555562
astNode: undefined,
556563
},
557564
]);
@@ -649,6 +656,7 @@ describe('Type System: Input Objects', () => {
649656
description: undefined,
650657
type: ScalarType,
651658
defaultValue: undefined,
659+
extensions: undefined,
652660
astNode: undefined,
653661
},
654662
});
@@ -667,6 +675,7 @@ describe('Type System: Input Objects', () => {
667675
description: undefined,
668676
type: ScalarType,
669677
defaultValue: undefined,
678+
extensions: undefined,
670679
astNode: undefined,
671680
},
672681
});

src/type/__tests__/directive-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ describe('Type System: Directive', () => {
3939
description: null,
4040
type: GraphQLString,
4141
defaultValue: undefined,
42+
extensions: undefined,
4243
astNode: undefined,
4344
},
4445
{
4546
name: 'bar',
4647
description: null,
4748
type: GraphQLInt,
4849
defaultValue: undefined,
50+
extensions: undefined,
4951
astNode: undefined,
5052
},
5153
],

src/type/__tests__/enumType-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ describe('Type System: Enum Values', () => {
345345
value: Complex1,
346346
isDeprecated: false,
347347
deprecationReason: undefined,
348+
extensions: undefined,
348349
astNode: undefined,
349350
},
350351
{
@@ -353,6 +354,7 @@ describe('Type System: Enum Values', () => {
353354
value: Complex2,
354355
isDeprecated: false,
355356
deprecationReason: undefined,
357+
extensions: undefined,
356358
astNode: undefined,
357359
},
358360
]);

0 commit comments

Comments
 (0)