Skip to content

Commit 0286437

Browse files
committed
enhance: directive extraction
1 parent 65452ab commit 0286437

File tree

6 files changed

+113
-144
lines changed

6 files changed

+113
-144
lines changed

.changeset/stale-weeks-type.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@graphql-tools/schema': patch
3+
'@graphql-tools/merge': patch
4+
'@graphql-tools/utils': patch
5+
---
6+
7+
Improve directive extraction

packages/merge/src/extensions.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ function applyExtensionObject(
1111
obj: Maybe<{ extensions: Maybe<Readonly<Record<string, any>>> }>,
1212
extensions: ExtensionsObject,
1313
) {
14-
if (!obj) {
14+
if (!obj || !extensions || extensions === obj.extensions) {
1515
return;
1616
}
17-
obj.extensions = mergeDeep([obj.extensions || {}, extensions || {}], false, true);
17+
if (!obj.extensions) {
18+
obj.extensions = extensions;
19+
return;
20+
}
21+
obj.extensions = mergeDeep([obj.extensions, extensions], false, true);
1822
}
1923

2024
export function applyExtensions(

packages/schema/src/merge-schemas.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,7 @@ export function mergeSchemas(config: MergeSchemasConfig) {
3232

3333
if (config.schemas != null) {
3434
for (const schema of config.schemas) {
35-
extractedTypeDefs.push(
36-
getDocumentNodeFromSchema(schema, {
37-
...config,
38-
pathToDirectivesInExtensions: ['NONEXISTENT'],
39-
}),
40-
);
35+
extractedTypeDefs.push(getDocumentNodeFromSchema(schema));
4136
extractedResolvers.push(getResolversFromSchema(schema));
4237
extractedSchemaExtensions.push(extractExtensionsFromSchema(schema));
4338
}

packages/utils/src/get-directives.ts

+3-34
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,12 @@
1-
import {
2-
GraphQLEnumTypeConfig,
3-
GraphQLEnumValue,
4-
GraphQLEnumValueConfig,
5-
GraphQLField,
6-
GraphQLFieldConfig,
7-
GraphQLInputField,
8-
GraphQLInputFieldConfig,
9-
GraphQLInputObjectTypeConfig,
10-
GraphQLInterfaceTypeConfig,
11-
GraphQLNamedType,
12-
GraphQLObjectTypeConfig,
13-
GraphQLScalarTypeConfig,
14-
GraphQLSchema,
15-
GraphQLSchemaConfig,
16-
GraphQLUnionTypeConfig,
17-
} from 'graphql';
18-
import { getDirectiveExtensions } from './getDirectiveExtensions.js';
1+
import { GraphQLSchema } from 'graphql';
2+
import { DirectableObject, getDirectiveExtensions } from './getDirectiveExtensions.js';
193

204
export interface DirectiveAnnotation {
215
name: string;
226
args?: Record<string, any>;
237
}
248

25-
export type DirectableGraphQLObject =
26-
| GraphQLSchema
27-
| GraphQLSchemaConfig
28-
| GraphQLNamedType
29-
| GraphQLObjectTypeConfig<any, any>
30-
| GraphQLInterfaceTypeConfig<any, any>
31-
| GraphQLUnionTypeConfig<any, any>
32-
| GraphQLScalarTypeConfig<any, any>
33-
| GraphQLEnumTypeConfig
34-
| GraphQLEnumValue
35-
| GraphQLEnumValueConfig
36-
| GraphQLInputObjectTypeConfig
37-
| GraphQLField<any, any>
38-
| GraphQLInputField
39-
| GraphQLFieldConfig<any, any>
40-
| GraphQLInputFieldConfig;
9+
export type DirectableGraphQLObject = DirectableObject;
4110

4211
export function getDirectivesInExtensions(
4312
node: DirectableGraphQLObject,

packages/utils/src/getDirectiveExtensions.ts

+40-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ASTNode, DirectiveNode, GraphQLSchema } from 'graphql';
22
import { valueFromAST, valueFromASTUntyped } from 'graphql';
33
import { getArgumentValues } from './getArgumentValues.js';
4+
import { memoize1 } from './memoize.js';
45

56
export type DirectableASTNode = ASTNode & { directives?: readonly DirectiveNode[] };
67
export type DirectableObject = {
@@ -25,6 +26,39 @@ export function getDirectiveExtensions<
2526
TDirectiveAnnotationsMap[directiveName]
2627
>;
2728
} = {};
29+
30+
if (directableObj.extensions) {
31+
let directivesInExtensions = directableObj.extensions;
32+
for (const pathSegment of pathToDirectivesInExtensions) {
33+
directivesInExtensions = directivesInExtensions?.[pathSegment];
34+
}
35+
if (directivesInExtensions != null) {
36+
for (const directiveNameProp in directivesInExtensions) {
37+
const directiveObjs = directivesInExtensions[directiveNameProp];
38+
const directiveName = directiveNameProp as keyof TDirectiveAnnotationsMap;
39+
if (Array.isArray(directiveObjs)) {
40+
for (const directiveObj of directiveObjs) {
41+
let existingDirectiveExtensions = directiveExtensions[directiveName];
42+
if (!existingDirectiveExtensions) {
43+
existingDirectiveExtensions = [];
44+
directiveExtensions[directiveName] = existingDirectiveExtensions;
45+
}
46+
existingDirectiveExtensions.push(directiveObj);
47+
}
48+
} else {
49+
let existingDirectiveExtensions = directiveExtensions[directiveName];
50+
if (!existingDirectiveExtensions) {
51+
existingDirectiveExtensions = [];
52+
directiveExtensions[directiveName] = existingDirectiveExtensions;
53+
}
54+
existingDirectiveExtensions.push(directiveObjs);
55+
}
56+
}
57+
}
58+
}
59+
60+
const memoizedStringify = memoize1(obj => JSON.stringify(obj));
61+
2862
const astNodes: DirectableASTNode[] = [];
2963
if (directableObj.astNode) {
3064
astNodes.push(directableObj.astNode);
@@ -60,39 +94,16 @@ export function getDirectiveExtensions<
6094
}
6195
}
6296
}
63-
existingDirectiveExtensions.push(value);
64-
}
65-
}
66-
}
67-
68-
if (directableObj.extensions) {
69-
let directivesInExtensions = directableObj.extensions;
70-
for (const pathSegment of pathToDirectivesInExtensions) {
71-
directivesInExtensions = directivesInExtensions?.[pathSegment];
72-
}
73-
if (directivesInExtensions != null) {
74-
for (const directiveNameProp in directivesInExtensions) {
75-
const directiveObjs = directivesInExtensions[directiveNameProp];
76-
const directiveName = directiveNameProp as keyof TDirectiveAnnotationsMap;
77-
if (Array.isArray(directiveObjs)) {
78-
for (const directiveObj of directiveObjs) {
79-
let existingDirectiveExtensions = directiveExtensions[directiveName];
80-
if (!existingDirectiveExtensions) {
81-
existingDirectiveExtensions = [];
82-
directiveExtensions[directiveName] = existingDirectiveExtensions;
83-
}
84-
existingDirectiveExtensions.push(directiveObj);
97+
if (astNodes.length > 0 && existingDirectiveExtensions.length > 0) {
98+
const valStr = memoizedStringify(value);
99+
if (existingDirectiveExtensions.some(val => memoizedStringify(val) === valStr)) {
100+
continue;
85101
}
86-
} else {
87-
let existingDirectiveExtensions = directiveExtensions[directiveName];
88-
if (!existingDirectiveExtensions) {
89-
existingDirectiveExtensions = [];
90-
directiveExtensions[directiveName] = existingDirectiveExtensions;
91-
}
92-
existingDirectiveExtensions.push(directiveObjs);
93102
}
103+
existingDirectiveExtensions.push(value);
94104
}
95105
}
96106
}
107+
97108
return directiveExtensions;
98109
}

0 commit comments

Comments
 (0)