1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.pruneSchema = void 0;
|
4 | const graphql_1 = require("graphql");
|
5 | const get_implementing_types_js_1 = require("./get-implementing-types.js");
|
6 | const Interfaces_js_1 = require("./Interfaces.js");
|
7 | const mapSchema_js_1 = require("./mapSchema.js");
|
8 | const rootTypes_js_1 = require("./rootTypes.js");
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | function pruneSchema(schema, options = {}) {
|
15 | const { skipEmptyCompositeTypePruning, skipEmptyUnionPruning, skipPruning, skipUnimplementedInterfacesPruning, skipUnusedTypesPruning, } = options;
|
16 | let prunedTypes = [];
|
17 | let prunedSchema = schema;
|
18 | do {
|
19 | let visited = visitSchema(prunedSchema);
|
20 |
|
21 | if (skipPruning) {
|
22 | const revisit = [];
|
23 | for (const typeName in prunedSchema.getTypeMap()) {
|
24 | if (typeName.startsWith('__')) {
|
25 | continue;
|
26 | }
|
27 | const type = prunedSchema.getType(typeName);
|
28 |
|
29 | if (type && skipPruning(type)) {
|
30 | revisit.push(typeName);
|
31 | }
|
32 | }
|
33 | visited = visitQueue(revisit, prunedSchema, visited);
|
34 | }
|
35 | prunedTypes = [];
|
36 | prunedSchema = (0, mapSchema_js_1.mapSchema)(prunedSchema, {
|
37 | [Interfaces_js_1.MapperKind.TYPE]: type => {
|
38 | if (!visited.has(type.name) && !(0, graphql_1.isSpecifiedScalarType)(type)) {
|
39 | if ((0, graphql_1.isUnionType)(type) ||
|
40 | (0, graphql_1.isInputObjectType)(type) ||
|
41 | (0, graphql_1.isInterfaceType)(type) ||
|
42 | (0, graphql_1.isObjectType)(type) ||
|
43 | (0, graphql_1.isScalarType)(type)) {
|
44 |
|
45 | if (skipUnusedTypesPruning) {
|
46 | return type;
|
47 | }
|
48 |
|
49 | if ((0, graphql_1.isUnionType)(type) &&
|
50 | skipEmptyUnionPruning &&
|
51 | !Object.keys(type.getTypes()).length) {
|
52 | return type;
|
53 | }
|
54 | if ((0, graphql_1.isInputObjectType)(type) || (0, graphql_1.isInterfaceType)(type) || (0, graphql_1.isObjectType)(type)) {
|
55 |
|
56 | if (skipEmptyCompositeTypePruning && !Object.keys(type.getFields()).length) {
|
57 | return type;
|
58 | }
|
59 | }
|
60 |
|
61 | if ((0, graphql_1.isInterfaceType)(type) && skipUnimplementedInterfacesPruning) {
|
62 | return type;
|
63 | }
|
64 | }
|
65 | prunedTypes.push(type.name);
|
66 | visited.delete(type.name);
|
67 | return null;
|
68 | }
|
69 | return type;
|
70 | },
|
71 | });
|
72 | } while (prunedTypes.length);
|
73 | return prunedSchema;
|
74 | }
|
75 | exports.pruneSchema = pruneSchema;
|
76 | function visitSchema(schema) {
|
77 | const queue = [];
|
78 |
|
79 | for (const type of (0, rootTypes_js_1.getRootTypes)(schema)) {
|
80 | queue.push(type.name);
|
81 | }
|
82 | return visitQueue(queue, schema);
|
83 | }
|
84 | function visitQueue(queue, schema, visited = new Set()) {
|
85 |
|
86 | const revisit = new Map();
|
87 |
|
88 | while (queue.length) {
|
89 | const typeName = queue.pop();
|
90 |
|
91 | if (visited.has(typeName) && revisit[typeName] !== true) {
|
92 | continue;
|
93 | }
|
94 | const type = schema.getType(typeName);
|
95 | if (type) {
|
96 |
|
97 | if ((0, graphql_1.isUnionType)(type)) {
|
98 | queue.push(...type.getTypes().map(type => type.name));
|
99 | }
|
100 |
|
101 | if ((0, graphql_1.isInterfaceType)(type) && revisit[typeName] === true) {
|
102 | queue.push(...(0, get_implementing_types_js_1.getImplementingTypes)(type.name, schema));
|
103 |
|
104 | revisit[typeName] = false;
|
105 | }
|
106 | if ((0, graphql_1.isEnumType)(type)) {
|
107 |
|
108 | queue.push(...type.getValues().flatMap(value => getDirectivesArgumentsTypeNames(schema, value)));
|
109 | }
|
110 |
|
111 | if ('getInterfaces' in type) {
|
112 |
|
113 | queue.push(...type.getInterfaces().map(iface => iface.name));
|
114 | }
|
115 |
|
116 | if ('getFields' in type) {
|
117 | const fields = type.getFields();
|
118 | const entries = Object.entries(fields);
|
119 | if (!entries.length) {
|
120 | continue;
|
121 | }
|
122 | for (const [, field] of entries) {
|
123 | if ((0, graphql_1.isObjectType)(type)) {
|
124 |
|
125 | queue.push(...field.args.flatMap(arg => {
|
126 | const typeNames = [(0, graphql_1.getNamedType)(arg.type).name];
|
127 | typeNames.push(...getDirectivesArgumentsTypeNames(schema, arg));
|
128 | return typeNames;
|
129 | }));
|
130 | }
|
131 | const namedType = (0, graphql_1.getNamedType)(field.type);
|
132 | queue.push(namedType.name);
|
133 | queue.push(...getDirectivesArgumentsTypeNames(schema, field));
|
134 |
|
135 | if ((0, graphql_1.isInterfaceType)(namedType) && !(namedType.name in revisit)) {
|
136 | revisit[namedType.name] = true;
|
137 | }
|
138 | }
|
139 | }
|
140 | queue.push(...getDirectivesArgumentsTypeNames(schema, type));
|
141 | visited.add(typeName);
|
142 | }
|
143 | }
|
144 | return visited;
|
145 | }
|
146 | function getDirectivesArgumentsTypeNames(schema, directableObj) {
|
147 | const argTypeNames = new Set();
|
148 | if (directableObj.astNode?.directives) {
|
149 | for (const directiveNode of directableObj.astNode.directives) {
|
150 | const directive = schema.getDirective(directiveNode.name.value);
|
151 | if (directive?.args) {
|
152 | for (const arg of directive.args) {
|
153 | const argType = (0, graphql_1.getNamedType)(arg.type);
|
154 | argTypeNames.add(argType.name);
|
155 | }
|
156 | }
|
157 | }
|
158 | }
|
159 | if (directableObj.extensions?.['directives']) {
|
160 | for (const directiveName in directableObj.extensions['directives']) {
|
161 | const directive = schema.getDirective(directiveName);
|
162 | if (directive?.args) {
|
163 | for (const arg of directive.args) {
|
164 | const argType = (0, graphql_1.getNamedType)(arg.type);
|
165 | argTypeNames.add(argType.name);
|
166 | }
|
167 | }
|
168 | }
|
169 | }
|
170 | return [...argTypeNames];
|
171 | }
|