@graphql-tools/import 6.4.2 → 6.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.d.ts +26 -0
- package/index.js +224 -195
- package/index.mjs +222 -196
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Check API Reference for more information about this package;
|
|
2
|
-
https://www.graphql-tools.com/docs/api/modules/
|
|
2
|
+
https://www.graphql-tools.com/docs/api/modules/import_src
|
|
3
3
|
|
|
4
4
|
You can also learn more about GraphQL Import in this chapter;
|
|
5
5
|
https://www.graphql-tools.com/docs/schema-loading#using-import-expression
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { DefinitionNode, DocumentNode } from 'graphql';
|
|
2
2
|
export declare type VisitedFilesMap = Map<string, Map<string, Set<DefinitionNode>>>;
|
|
3
|
+
/**
|
|
4
|
+
* Loads the GraphQL document and recursively resolves all the imports
|
|
5
|
+
* and copies them into the final document.
|
|
6
|
+
*/
|
|
3
7
|
export declare function processImport(filePath: string, cwd?: string, predefinedImports?: Record<string, string>, visitedFiles?: VisitedFilesMap): DocumentNode;
|
|
8
|
+
export declare function extractDependencies(filePath: string, fileContents: string): {
|
|
9
|
+
definitionsByName: Map<string, Set<DefinitionNode>>;
|
|
10
|
+
dependenciesByDefinitionName: Map<string, Set<string>>;
|
|
11
|
+
};
|
|
12
|
+
export declare function processImports(importLines: string[], filePath: string, visitedFiles: VisitedFilesMap, predefinedImports: Record<string, string>): {
|
|
13
|
+
allImportedDefinitionsMap: Map<string, Set<DefinitionNode>>;
|
|
14
|
+
potentialTransitiveDefinitionsMap: Map<string, Set<DefinitionNode>>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Splits the contents of a GraphQL file into lines that are imports
|
|
18
|
+
* and other lines which define the actual GraphQL document.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractImportLines(fileContent: string): {
|
|
21
|
+
importLines: string[];
|
|
22
|
+
otherLines: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Parses an import line, returning a list of entities imported and the file
|
|
26
|
+
* from which they are imported.
|
|
27
|
+
*
|
|
28
|
+
* Throws if the import line does not have a correct format.
|
|
29
|
+
*/
|
|
4
30
|
export declare function parseImportLine(importLine: string): {
|
|
5
31
|
imports: string[];
|
|
6
32
|
from: string;
|
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const fs = require('fs');
|
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const resolveFrom = _interopDefault(require('resolve-from'));
|
|
11
11
|
const process = require('process');
|
|
12
|
+
const utils = require('@graphql-tools/utils');
|
|
12
13
|
|
|
13
14
|
/* eslint-disable no-unused-expressions */
|
|
14
15
|
const builtinTypes = ['String', 'Float', 'Int', 'Boolean', 'ID', 'Upload'];
|
|
@@ -27,18 +28,20 @@ const builtinDirectives = [
|
|
|
27
28
|
];
|
|
28
29
|
const IMPORT_FROM_REGEX = /^import\s+(\*|(.*))\s+from\s+('|")(.*)('|");?$/;
|
|
29
30
|
const IMPORT_DEFAULT_REGEX = /^import\s+('|")(.*)('|");?$/;
|
|
31
|
+
/**
|
|
32
|
+
* Loads the GraphQL document and recursively resolves all the imports
|
|
33
|
+
* and copies them into the final document.
|
|
34
|
+
*/
|
|
30
35
|
function processImport(filePath, cwd = process.cwd(), predefinedImports = {}, visitedFiles = new Map()) {
|
|
31
36
|
const set = visitFile(filePath, path.join(cwd + '/root.graphql'), visitedFiles, predefinedImports);
|
|
32
37
|
const definitionStrSet = new Set();
|
|
33
38
|
let definitionsStr = '';
|
|
34
|
-
|
|
35
|
-
for (const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
definitionsStr += defStr + '\n';
|
|
41
|
-
}
|
|
39
|
+
for (const defs of set.values()) {
|
|
40
|
+
for (const def of defs) {
|
|
41
|
+
const defStr = graphql.print(def);
|
|
42
|
+
if (!definitionStrSet.has(defStr)) {
|
|
43
|
+
definitionStrSet.add(defStr);
|
|
44
|
+
definitionsStr += defStr + '\n';
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
}
|
|
@@ -50,192 +53,17 @@ function processImport(filePath, cwd = process.cwd(), predefinedImports = {}, vi
|
|
|
50
53
|
};
|
|
51
54
|
}
|
|
52
55
|
function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
53
|
-
var _a;
|
|
54
56
|
if (!path.isAbsolute(filePath) && !(filePath in predefinedImports)) {
|
|
55
57
|
filePath = resolveFilePath(cwd, filePath);
|
|
56
58
|
}
|
|
57
59
|
if (!visitedFiles.has(filePath)) {
|
|
58
60
|
const fileContent = filePath in predefinedImports ? predefinedImports[filePath] : fs.readFileSync(filePath, 'utf8');
|
|
59
|
-
const importLines =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
else if (trimmedLine) {
|
|
67
|
-
otherLines += line + '\n';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const definitionsByName = new Map();
|
|
71
|
-
const dependenciesByDefinitionName = new Map();
|
|
72
|
-
if (otherLines) {
|
|
73
|
-
const fileDefinitionMap = new Map();
|
|
74
|
-
// To prevent circular dependency
|
|
75
|
-
visitedFiles.set(filePath, fileDefinitionMap);
|
|
76
|
-
const document = graphql.parse(new graphql.Source(otherLines, filePath), {
|
|
77
|
-
noLocation: true,
|
|
78
|
-
});
|
|
79
|
-
for (const definition of document.definitions) {
|
|
80
|
-
if ('name' in definition || definition.kind === graphql.Kind.SCHEMA_DEFINITION) {
|
|
81
|
-
const definitionName = 'name' in definition && definition.name ? definition.name.value : 'schema';
|
|
82
|
-
if (!definitionsByName.has(definitionName)) {
|
|
83
|
-
definitionsByName.set(definitionName, new Set());
|
|
84
|
-
}
|
|
85
|
-
const definitionsSet = definitionsByName.get(definitionName);
|
|
86
|
-
definitionsSet === null || definitionsSet === void 0 ? void 0 : definitionsSet.add(definition);
|
|
87
|
-
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
88
|
-
if (!dependencySet) {
|
|
89
|
-
dependencySet = new Set();
|
|
90
|
-
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
91
|
-
}
|
|
92
|
-
switch (definition.kind) {
|
|
93
|
-
case graphql.Kind.OPERATION_DEFINITION:
|
|
94
|
-
visitOperationDefinitionNode(definition, dependencySet);
|
|
95
|
-
break;
|
|
96
|
-
case graphql.Kind.FRAGMENT_DEFINITION:
|
|
97
|
-
visitFragmentDefinitionNode(definition, dependencySet);
|
|
98
|
-
break;
|
|
99
|
-
case graphql.Kind.OBJECT_TYPE_DEFINITION:
|
|
100
|
-
visitObjectTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
101
|
-
break;
|
|
102
|
-
case graphql.Kind.INTERFACE_TYPE_DEFINITION:
|
|
103
|
-
visitInterfaceTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
104
|
-
break;
|
|
105
|
-
case graphql.Kind.UNION_TYPE_DEFINITION:
|
|
106
|
-
visitUnionTypeDefinitionNode(definition, dependencySet);
|
|
107
|
-
break;
|
|
108
|
-
case graphql.Kind.ENUM_TYPE_DEFINITION:
|
|
109
|
-
visitEnumTypeDefinitionNode(definition, dependencySet);
|
|
110
|
-
break;
|
|
111
|
-
case graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
112
|
-
visitInputObjectTypeDefinitionNode(definition, dependencySet);
|
|
113
|
-
break;
|
|
114
|
-
case graphql.Kind.DIRECTIVE_DEFINITION:
|
|
115
|
-
visitDirectiveDefinitionNode(definition, dependencySet);
|
|
116
|
-
break;
|
|
117
|
-
case graphql.Kind.SCALAR_TYPE_DEFINITION:
|
|
118
|
-
visitScalarDefinitionNode(definition, dependencySet);
|
|
119
|
-
break;
|
|
120
|
-
case graphql.Kind.SCHEMA_DEFINITION:
|
|
121
|
-
visitSchemaDefinitionNode(definition, dependencySet);
|
|
122
|
-
break;
|
|
123
|
-
case graphql.Kind.OBJECT_TYPE_EXTENSION:
|
|
124
|
-
visitObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
125
|
-
break;
|
|
126
|
-
case graphql.Kind.INTERFACE_TYPE_EXTENSION:
|
|
127
|
-
visitInterfaceTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
128
|
-
break;
|
|
129
|
-
case graphql.Kind.UNION_TYPE_EXTENSION:
|
|
130
|
-
visitUnionTypeExtensionNode(definition, dependencySet);
|
|
131
|
-
break;
|
|
132
|
-
case graphql.Kind.ENUM_TYPE_EXTENSION:
|
|
133
|
-
visitEnumTypeExtensionNode(definition, dependencySet);
|
|
134
|
-
break;
|
|
135
|
-
case graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
136
|
-
visitInputObjectTypeExtensionNode(definition, dependencySet);
|
|
137
|
-
break;
|
|
138
|
-
case graphql.Kind.SCALAR_TYPE_EXTENSION:
|
|
139
|
-
visitScalarExtensionNode(definition, dependencySet);
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
if ('fields' in definition && definition.fields) {
|
|
143
|
-
for (const field of definition.fields) {
|
|
144
|
-
const definitionName = definition.name.value + '.' + field.name.value;
|
|
145
|
-
if (!definitionsByName.has(definitionName)) {
|
|
146
|
-
definitionsByName.set(definitionName, new Set());
|
|
147
|
-
}
|
|
148
|
-
(_a = definitionsByName.get(definitionName)) === null || _a === void 0 ? void 0 : _a.add({
|
|
149
|
-
...definition,
|
|
150
|
-
fields: [field],
|
|
151
|
-
});
|
|
152
|
-
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
153
|
-
if (!dependencySet) {
|
|
154
|
-
dependencySet = new Set();
|
|
155
|
-
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
156
|
-
}
|
|
157
|
-
switch (field.kind) {
|
|
158
|
-
case graphql.Kind.FIELD_DEFINITION:
|
|
159
|
-
visitFieldDefinitionNode(field, dependencySet);
|
|
160
|
-
break;
|
|
161
|
-
case graphql.Kind.INPUT_VALUE_DEFINITION:
|
|
162
|
-
visitInputValueDefinitionNode(field, dependencySet);
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
for (const [definitionName, definitions] of definitionsByName) {
|
|
170
|
-
let definitionsWithDependencies = fileDefinitionMap.get(definitionName);
|
|
171
|
-
if (definitionsWithDependencies == null) {
|
|
172
|
-
definitionsWithDependencies = new Set();
|
|
173
|
-
fileDefinitionMap.set(definitionName, definitionsWithDependencies);
|
|
174
|
-
}
|
|
175
|
-
for (const definition of definitions) {
|
|
176
|
-
definitionsWithDependencies.add(definition);
|
|
177
|
-
}
|
|
178
|
-
const dependenciesOfDefinition = dependenciesByDefinitionName.get(definitionName);
|
|
179
|
-
if (dependenciesOfDefinition) {
|
|
180
|
-
for (const dependencyName of dependenciesOfDefinition) {
|
|
181
|
-
const dependencyDefinitions = definitionsByName.get(dependencyName);
|
|
182
|
-
if (dependencyDefinitions != null) {
|
|
183
|
-
for (const dependencyDefinition of dependencyDefinitions) {
|
|
184
|
-
definitionsWithDependencies.add(dependencyDefinition);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
const potentialTransitiveDefinitionsMap = new Map();
|
|
192
|
-
const allImportedDefinitionsMap = new Map();
|
|
193
|
-
for (const line of importLines) {
|
|
194
|
-
const { imports, from } = parseImportLine(line.replace('#', '').trim());
|
|
195
|
-
const importFileDefinitionMap = visitFile(from, filePath, visitedFiles, predefinedImports);
|
|
196
|
-
if (importFileDefinitionMap != null) {
|
|
197
|
-
const buildFullDefinitionMap = (dependenciesMap) => {
|
|
198
|
-
for (const [importedDefinitionName, importedDefinitions] of importFileDefinitionMap) {
|
|
199
|
-
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
200
|
-
if (!dependenciesMap.has(importedDefinitionTypeName)) {
|
|
201
|
-
dependenciesMap.set(importedDefinitionTypeName, new Set());
|
|
202
|
-
}
|
|
203
|
-
const allImportedDefinitions = dependenciesMap.get(importedDefinitionTypeName);
|
|
204
|
-
if (allImportedDefinitions) {
|
|
205
|
-
for (const importedDefinition of importedDefinitions) {
|
|
206
|
-
allImportedDefinitions.add(importedDefinition);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
buildFullDefinitionMap(potentialTransitiveDefinitionsMap);
|
|
212
|
-
if (imports.includes('*')) {
|
|
213
|
-
buildFullDefinitionMap(allImportedDefinitionsMap);
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
for (let importedDefinitionName of imports) {
|
|
217
|
-
if (importedDefinitionName.endsWith('.*')) {
|
|
218
|
-
// Adding whole type means the same thing with adding every single field
|
|
219
|
-
importedDefinitionName = importedDefinitionName.replace('.*', '');
|
|
220
|
-
}
|
|
221
|
-
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
222
|
-
if (!allImportedDefinitionsMap.has(importedDefinitionTypeName)) {
|
|
223
|
-
allImportedDefinitionsMap.set(importedDefinitionTypeName, new Set());
|
|
224
|
-
}
|
|
225
|
-
const allImportedDefinitions = allImportedDefinitionsMap.get(importedDefinitionTypeName);
|
|
226
|
-
const importedDefinitions = importFileDefinitionMap.get(importedDefinitionName);
|
|
227
|
-
if (!importedDefinitions) {
|
|
228
|
-
throw new Error(`${importedDefinitionName} is not exported by ${from} imported by ${filePath}`);
|
|
229
|
-
}
|
|
230
|
-
if (allImportedDefinitions != null) {
|
|
231
|
-
for (const importedDefinition of importedDefinitions) {
|
|
232
|
-
allImportedDefinitions.add(importedDefinition);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
61
|
+
const { importLines, otherLines } = extractImportLines(fileContent);
|
|
62
|
+
const { definitionsByName, dependenciesByDefinitionName } = extractDependencies(filePath, otherLines);
|
|
63
|
+
const fileDefinitionMap = getFileDefinitionMap(definitionsByName, dependenciesByDefinitionName);
|
|
64
|
+
// To prevent circular dependency
|
|
65
|
+
visitedFiles.set(filePath, fileDefinitionMap);
|
|
66
|
+
const { allImportedDefinitionsMap, potentialTransitiveDefinitionsMap } = processImports(importLines, filePath, visitedFiles, predefinedImports);
|
|
239
67
|
const addDefinition = (definition, definitionName, definitionSet) => {
|
|
240
68
|
const fileDefinitionMap = visitedFiles.get(filePath);
|
|
241
69
|
if (fileDefinitionMap && !definitionSet.has(definition)) {
|
|
@@ -278,12 +106,6 @@ function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
|
278
106
|
};
|
|
279
107
|
if (!otherLines) {
|
|
280
108
|
visitedFiles.set(filePath, allImportedDefinitionsMap);
|
|
281
|
-
const definitionSet = new Set();
|
|
282
|
-
allImportedDefinitionsMap === null || allImportedDefinitionsMap === void 0 ? void 0 : allImportedDefinitionsMap.forEach((importedDefinitions, importedDefinitionName) => {
|
|
283
|
-
importedDefinitions === null || importedDefinitions === void 0 ? void 0 : importedDefinitions.forEach(importedDefinition => {
|
|
284
|
-
addDefinition(importedDefinition, importedDefinitionName, definitionSet);
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
109
|
}
|
|
288
110
|
else {
|
|
289
111
|
const fileDefinitionMap = visitedFiles.get(filePath);
|
|
@@ -315,6 +137,210 @@ function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
|
315
137
|
}
|
|
316
138
|
return visitedFiles.get(filePath);
|
|
317
139
|
}
|
|
140
|
+
function extractDependencies(filePath, fileContents) {
|
|
141
|
+
const definitionsByName = new Map();
|
|
142
|
+
const dependenciesByDefinitionName = new Map();
|
|
143
|
+
const { document } = utils.parseGraphQLSDL(filePath, fileContents, {
|
|
144
|
+
noLocation: true,
|
|
145
|
+
});
|
|
146
|
+
for (const definition of document.definitions) {
|
|
147
|
+
visitDefinition(definition, definitionsByName, dependenciesByDefinitionName);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
definitionsByName,
|
|
151
|
+
dependenciesByDefinitionName,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function visitDefinition(definition, definitionsByName, dependenciesByDefinitionName) {
|
|
155
|
+
var _a;
|
|
156
|
+
// TODO: handle queries without names
|
|
157
|
+
if ('name' in definition || definition.kind === graphql.Kind.SCHEMA_DEFINITION) {
|
|
158
|
+
const definitionName = 'name' in definition && definition.name ? definition.name.value : 'schema';
|
|
159
|
+
if (!definitionsByName.has(definitionName)) {
|
|
160
|
+
definitionsByName.set(definitionName, new Set());
|
|
161
|
+
}
|
|
162
|
+
const definitionsSet = definitionsByName.get(definitionName);
|
|
163
|
+
definitionsSet.add(definition);
|
|
164
|
+
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
165
|
+
if (!dependencySet) {
|
|
166
|
+
dependencySet = new Set();
|
|
167
|
+
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
168
|
+
}
|
|
169
|
+
switch (definition.kind) {
|
|
170
|
+
case graphql.Kind.OPERATION_DEFINITION:
|
|
171
|
+
visitOperationDefinitionNode(definition, dependencySet);
|
|
172
|
+
break;
|
|
173
|
+
case graphql.Kind.FRAGMENT_DEFINITION:
|
|
174
|
+
visitFragmentDefinitionNode(definition, dependencySet);
|
|
175
|
+
break;
|
|
176
|
+
case graphql.Kind.OBJECT_TYPE_DEFINITION:
|
|
177
|
+
visitObjectTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
178
|
+
break;
|
|
179
|
+
case graphql.Kind.INTERFACE_TYPE_DEFINITION:
|
|
180
|
+
visitInterfaceTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
181
|
+
break;
|
|
182
|
+
case graphql.Kind.UNION_TYPE_DEFINITION:
|
|
183
|
+
visitUnionTypeDefinitionNode(definition, dependencySet);
|
|
184
|
+
break;
|
|
185
|
+
case graphql.Kind.ENUM_TYPE_DEFINITION:
|
|
186
|
+
visitEnumTypeDefinitionNode(definition, dependencySet);
|
|
187
|
+
break;
|
|
188
|
+
case graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
189
|
+
visitInputObjectTypeDefinitionNode(definition, dependencySet);
|
|
190
|
+
break;
|
|
191
|
+
case graphql.Kind.DIRECTIVE_DEFINITION:
|
|
192
|
+
visitDirectiveDefinitionNode(definition, dependencySet);
|
|
193
|
+
break;
|
|
194
|
+
case graphql.Kind.SCALAR_TYPE_DEFINITION:
|
|
195
|
+
visitScalarDefinitionNode(definition, dependencySet);
|
|
196
|
+
break;
|
|
197
|
+
case graphql.Kind.SCHEMA_DEFINITION:
|
|
198
|
+
visitSchemaDefinitionNode(definition, dependencySet);
|
|
199
|
+
break;
|
|
200
|
+
case graphql.Kind.OBJECT_TYPE_EXTENSION:
|
|
201
|
+
visitObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
202
|
+
break;
|
|
203
|
+
case graphql.Kind.INTERFACE_TYPE_EXTENSION:
|
|
204
|
+
visitInterfaceTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
205
|
+
break;
|
|
206
|
+
case graphql.Kind.UNION_TYPE_EXTENSION:
|
|
207
|
+
visitUnionTypeExtensionNode(definition, dependencySet);
|
|
208
|
+
break;
|
|
209
|
+
case graphql.Kind.ENUM_TYPE_EXTENSION:
|
|
210
|
+
visitEnumTypeExtensionNode(definition, dependencySet);
|
|
211
|
+
break;
|
|
212
|
+
case graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
213
|
+
visitInputObjectTypeExtensionNode(definition, dependencySet);
|
|
214
|
+
break;
|
|
215
|
+
case graphql.Kind.SCALAR_TYPE_EXTENSION:
|
|
216
|
+
visitScalarExtensionNode(definition, dependencySet);
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
if ('fields' in definition && definition.fields) {
|
|
220
|
+
for (const field of definition.fields) {
|
|
221
|
+
const definitionName = definition.name.value + '.' + field.name.value;
|
|
222
|
+
if (!definitionsByName.has(definitionName)) {
|
|
223
|
+
definitionsByName.set(definitionName, new Set());
|
|
224
|
+
}
|
|
225
|
+
(_a = definitionsByName.get(definitionName)) === null || _a === void 0 ? void 0 : _a.add({
|
|
226
|
+
...definition,
|
|
227
|
+
fields: [field],
|
|
228
|
+
});
|
|
229
|
+
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
230
|
+
if (!dependencySet) {
|
|
231
|
+
dependencySet = new Set();
|
|
232
|
+
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
233
|
+
}
|
|
234
|
+
switch (field.kind) {
|
|
235
|
+
case graphql.Kind.FIELD_DEFINITION:
|
|
236
|
+
visitFieldDefinitionNode(field, dependencySet);
|
|
237
|
+
break;
|
|
238
|
+
case graphql.Kind.INPUT_VALUE_DEFINITION:
|
|
239
|
+
visitInputValueDefinitionNode(field, dependencySet);
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function getFileDefinitionMap(definitionsByName, dependenciesByDefinitionName) {
|
|
247
|
+
const fileDefinitionMap = new Map();
|
|
248
|
+
for (const [definitionName, definitions] of definitionsByName) {
|
|
249
|
+
let definitionsWithDependencies = fileDefinitionMap.get(definitionName);
|
|
250
|
+
if (definitionsWithDependencies == null) {
|
|
251
|
+
definitionsWithDependencies = new Set();
|
|
252
|
+
fileDefinitionMap.set(definitionName, definitionsWithDependencies);
|
|
253
|
+
}
|
|
254
|
+
for (const definition of definitions) {
|
|
255
|
+
definitionsWithDependencies.add(definition);
|
|
256
|
+
}
|
|
257
|
+
const dependenciesOfDefinition = dependenciesByDefinitionName.get(definitionName);
|
|
258
|
+
if (dependenciesOfDefinition) {
|
|
259
|
+
for (const dependencyName of dependenciesOfDefinition) {
|
|
260
|
+
const dependencyDefinitions = definitionsByName.get(dependencyName);
|
|
261
|
+
if (dependencyDefinitions != null) {
|
|
262
|
+
for (const dependencyDefinition of dependencyDefinitions) {
|
|
263
|
+
definitionsWithDependencies.add(dependencyDefinition);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return fileDefinitionMap;
|
|
270
|
+
}
|
|
271
|
+
function processImports(importLines, filePath, visitedFiles, predefinedImports) {
|
|
272
|
+
const potentialTransitiveDefinitionsMap = new Map();
|
|
273
|
+
const allImportedDefinitionsMap = new Map();
|
|
274
|
+
for (const line of importLines) {
|
|
275
|
+
const { imports, from } = parseImportLine(line.replace('#', '').trim());
|
|
276
|
+
const importFileDefinitionMap = visitFile(from, filePath, visitedFiles, predefinedImports);
|
|
277
|
+
const buildFullDefinitionMap = (dependenciesMap) => {
|
|
278
|
+
for (const [importedDefinitionName, importedDefinitions] of importFileDefinitionMap) {
|
|
279
|
+
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
280
|
+
if (!dependenciesMap.has(importedDefinitionTypeName)) {
|
|
281
|
+
dependenciesMap.set(importedDefinitionTypeName, new Set());
|
|
282
|
+
}
|
|
283
|
+
const allImportedDefinitions = dependenciesMap.get(importedDefinitionTypeName);
|
|
284
|
+
if (allImportedDefinitions) {
|
|
285
|
+
for (const importedDefinition of importedDefinitions) {
|
|
286
|
+
allImportedDefinitions.add(importedDefinition);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
buildFullDefinitionMap(potentialTransitiveDefinitionsMap);
|
|
292
|
+
if (imports.includes('*')) {
|
|
293
|
+
buildFullDefinitionMap(allImportedDefinitionsMap);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
for (let importedDefinitionName of imports) {
|
|
297
|
+
if (importedDefinitionName.endsWith('.*')) {
|
|
298
|
+
// Adding whole type means the same thing with adding every single field
|
|
299
|
+
importedDefinitionName = importedDefinitionName.replace('.*', '');
|
|
300
|
+
}
|
|
301
|
+
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
302
|
+
if (!allImportedDefinitionsMap.has(importedDefinitionTypeName)) {
|
|
303
|
+
allImportedDefinitionsMap.set(importedDefinitionTypeName, new Set());
|
|
304
|
+
}
|
|
305
|
+
const allImportedDefinitions = allImportedDefinitionsMap.get(importedDefinitionTypeName);
|
|
306
|
+
const importedDefinitions = importFileDefinitionMap.get(importedDefinitionName);
|
|
307
|
+
if (!importedDefinitions) {
|
|
308
|
+
throw new Error(`${importedDefinitionName} is not exported by ${from} imported by ${filePath}`);
|
|
309
|
+
}
|
|
310
|
+
if (allImportedDefinitions != null) {
|
|
311
|
+
for (const importedDefinition of importedDefinitions) {
|
|
312
|
+
allImportedDefinitions.add(importedDefinition);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { allImportedDefinitionsMap, potentialTransitiveDefinitionsMap };
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Splits the contents of a GraphQL file into lines that are imports
|
|
322
|
+
* and other lines which define the actual GraphQL document.
|
|
323
|
+
*/
|
|
324
|
+
function extractImportLines(fileContent) {
|
|
325
|
+
const importLines = [];
|
|
326
|
+
let otherLines = '';
|
|
327
|
+
for (const line of fileContent.split('\n')) {
|
|
328
|
+
const trimmedLine = line.trim();
|
|
329
|
+
if (trimmedLine.startsWith('#import ') || trimmedLine.startsWith('# import ')) {
|
|
330
|
+
importLines.push(trimmedLine);
|
|
331
|
+
}
|
|
332
|
+
else if (trimmedLine) {
|
|
333
|
+
otherLines += line + '\n';
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return { importLines, otherLines };
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Parses an import line, returning a list of entities imported and the file
|
|
340
|
+
* from which they are imported.
|
|
341
|
+
*
|
|
342
|
+
* Throws if the import line does not have a correct format.
|
|
343
|
+
*/
|
|
318
344
|
function parseImportLine(importLine) {
|
|
319
345
|
let regexMatch = importLine.match(IMPORT_FROM_REGEX);
|
|
320
346
|
if (regexMatch != null) {
|
|
@@ -563,5 +589,8 @@ function visitOperationTypeDefinitionNode(node, dependencySet) {
|
|
|
563
589
|
visitNamedTypeNode(node.type, dependencySet);
|
|
564
590
|
}
|
|
565
591
|
|
|
592
|
+
exports.extractDependencies = extractDependencies;
|
|
593
|
+
exports.extractImportLines = extractImportLines;
|
|
566
594
|
exports.parseImportLine = parseImportLine;
|
|
567
595
|
exports.processImport = processImport;
|
|
596
|
+
exports.processImports = processImports;
|
package/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync, realpathSync } from 'fs';
|
|
|
3
3
|
import { join, isAbsolute, dirname } from 'path';
|
|
4
4
|
import resolveFrom from 'resolve-from';
|
|
5
5
|
import { cwd } from 'process';
|
|
6
|
+
import { parseGraphQLSDL } from '@graphql-tools/utils';
|
|
6
7
|
|
|
7
8
|
/* eslint-disable no-unused-expressions */
|
|
8
9
|
const builtinTypes = ['String', 'Float', 'Int', 'Boolean', 'ID', 'Upload'];
|
|
@@ -21,18 +22,20 @@ const builtinDirectives = [
|
|
|
21
22
|
];
|
|
22
23
|
const IMPORT_FROM_REGEX = /^import\s+(\*|(.*))\s+from\s+('|")(.*)('|");?$/;
|
|
23
24
|
const IMPORT_DEFAULT_REGEX = /^import\s+('|")(.*)('|");?$/;
|
|
25
|
+
/**
|
|
26
|
+
* Loads the GraphQL document and recursively resolves all the imports
|
|
27
|
+
* and copies them into the final document.
|
|
28
|
+
*/
|
|
24
29
|
function processImport(filePath, cwd$1 = cwd(), predefinedImports = {}, visitedFiles = new Map()) {
|
|
25
30
|
const set = visitFile(filePath, join(cwd$1 + '/root.graphql'), visitedFiles, predefinedImports);
|
|
26
31
|
const definitionStrSet = new Set();
|
|
27
32
|
let definitionsStr = '';
|
|
28
|
-
|
|
29
|
-
for (const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
definitionsStr += defStr + '\n';
|
|
35
|
-
}
|
|
33
|
+
for (const defs of set.values()) {
|
|
34
|
+
for (const def of defs) {
|
|
35
|
+
const defStr = print(def);
|
|
36
|
+
if (!definitionStrSet.has(defStr)) {
|
|
37
|
+
definitionStrSet.add(defStr);
|
|
38
|
+
definitionsStr += defStr + '\n';
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
}
|
|
@@ -44,192 +47,17 @@ function processImport(filePath, cwd$1 = cwd(), predefinedImports = {}, visitedF
|
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
47
|
-
var _a;
|
|
48
50
|
if (!isAbsolute(filePath) && !(filePath in predefinedImports)) {
|
|
49
51
|
filePath = resolveFilePath(cwd, filePath);
|
|
50
52
|
}
|
|
51
53
|
if (!visitedFiles.has(filePath)) {
|
|
52
54
|
const fileContent = filePath in predefinedImports ? predefinedImports[filePath] : readFileSync(filePath, 'utf8');
|
|
53
|
-
const importLines =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
else if (trimmedLine) {
|
|
61
|
-
otherLines += line + '\n';
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const definitionsByName = new Map();
|
|
65
|
-
const dependenciesByDefinitionName = new Map();
|
|
66
|
-
if (otherLines) {
|
|
67
|
-
const fileDefinitionMap = new Map();
|
|
68
|
-
// To prevent circular dependency
|
|
69
|
-
visitedFiles.set(filePath, fileDefinitionMap);
|
|
70
|
-
const document = parse(new Source(otherLines, filePath), {
|
|
71
|
-
noLocation: true,
|
|
72
|
-
});
|
|
73
|
-
for (const definition of document.definitions) {
|
|
74
|
-
if ('name' in definition || definition.kind === Kind.SCHEMA_DEFINITION) {
|
|
75
|
-
const definitionName = 'name' in definition && definition.name ? definition.name.value : 'schema';
|
|
76
|
-
if (!definitionsByName.has(definitionName)) {
|
|
77
|
-
definitionsByName.set(definitionName, new Set());
|
|
78
|
-
}
|
|
79
|
-
const definitionsSet = definitionsByName.get(definitionName);
|
|
80
|
-
definitionsSet === null || definitionsSet === void 0 ? void 0 : definitionsSet.add(definition);
|
|
81
|
-
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
82
|
-
if (!dependencySet) {
|
|
83
|
-
dependencySet = new Set();
|
|
84
|
-
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
85
|
-
}
|
|
86
|
-
switch (definition.kind) {
|
|
87
|
-
case Kind.OPERATION_DEFINITION:
|
|
88
|
-
visitOperationDefinitionNode(definition, dependencySet);
|
|
89
|
-
break;
|
|
90
|
-
case Kind.FRAGMENT_DEFINITION:
|
|
91
|
-
visitFragmentDefinitionNode(definition, dependencySet);
|
|
92
|
-
break;
|
|
93
|
-
case Kind.OBJECT_TYPE_DEFINITION:
|
|
94
|
-
visitObjectTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
95
|
-
break;
|
|
96
|
-
case Kind.INTERFACE_TYPE_DEFINITION:
|
|
97
|
-
visitInterfaceTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
98
|
-
break;
|
|
99
|
-
case Kind.UNION_TYPE_DEFINITION:
|
|
100
|
-
visitUnionTypeDefinitionNode(definition, dependencySet);
|
|
101
|
-
break;
|
|
102
|
-
case Kind.ENUM_TYPE_DEFINITION:
|
|
103
|
-
visitEnumTypeDefinitionNode(definition, dependencySet);
|
|
104
|
-
break;
|
|
105
|
-
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
106
|
-
visitInputObjectTypeDefinitionNode(definition, dependencySet);
|
|
107
|
-
break;
|
|
108
|
-
case Kind.DIRECTIVE_DEFINITION:
|
|
109
|
-
visitDirectiveDefinitionNode(definition, dependencySet);
|
|
110
|
-
break;
|
|
111
|
-
case Kind.SCALAR_TYPE_DEFINITION:
|
|
112
|
-
visitScalarDefinitionNode(definition, dependencySet);
|
|
113
|
-
break;
|
|
114
|
-
case Kind.SCHEMA_DEFINITION:
|
|
115
|
-
visitSchemaDefinitionNode(definition, dependencySet);
|
|
116
|
-
break;
|
|
117
|
-
case Kind.OBJECT_TYPE_EXTENSION:
|
|
118
|
-
visitObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
119
|
-
break;
|
|
120
|
-
case Kind.INTERFACE_TYPE_EXTENSION:
|
|
121
|
-
visitInterfaceTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
122
|
-
break;
|
|
123
|
-
case Kind.UNION_TYPE_EXTENSION:
|
|
124
|
-
visitUnionTypeExtensionNode(definition, dependencySet);
|
|
125
|
-
break;
|
|
126
|
-
case Kind.ENUM_TYPE_EXTENSION:
|
|
127
|
-
visitEnumTypeExtensionNode(definition, dependencySet);
|
|
128
|
-
break;
|
|
129
|
-
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
130
|
-
visitInputObjectTypeExtensionNode(definition, dependencySet);
|
|
131
|
-
break;
|
|
132
|
-
case Kind.SCALAR_TYPE_EXTENSION:
|
|
133
|
-
visitScalarExtensionNode(definition, dependencySet);
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
if ('fields' in definition && definition.fields) {
|
|
137
|
-
for (const field of definition.fields) {
|
|
138
|
-
const definitionName = definition.name.value + '.' + field.name.value;
|
|
139
|
-
if (!definitionsByName.has(definitionName)) {
|
|
140
|
-
definitionsByName.set(definitionName, new Set());
|
|
141
|
-
}
|
|
142
|
-
(_a = definitionsByName.get(definitionName)) === null || _a === void 0 ? void 0 : _a.add({
|
|
143
|
-
...definition,
|
|
144
|
-
fields: [field],
|
|
145
|
-
});
|
|
146
|
-
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
147
|
-
if (!dependencySet) {
|
|
148
|
-
dependencySet = new Set();
|
|
149
|
-
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
150
|
-
}
|
|
151
|
-
switch (field.kind) {
|
|
152
|
-
case Kind.FIELD_DEFINITION:
|
|
153
|
-
visitFieldDefinitionNode(field, dependencySet);
|
|
154
|
-
break;
|
|
155
|
-
case Kind.INPUT_VALUE_DEFINITION:
|
|
156
|
-
visitInputValueDefinitionNode(field, dependencySet);
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
for (const [definitionName, definitions] of definitionsByName) {
|
|
164
|
-
let definitionsWithDependencies = fileDefinitionMap.get(definitionName);
|
|
165
|
-
if (definitionsWithDependencies == null) {
|
|
166
|
-
definitionsWithDependencies = new Set();
|
|
167
|
-
fileDefinitionMap.set(definitionName, definitionsWithDependencies);
|
|
168
|
-
}
|
|
169
|
-
for (const definition of definitions) {
|
|
170
|
-
definitionsWithDependencies.add(definition);
|
|
171
|
-
}
|
|
172
|
-
const dependenciesOfDefinition = dependenciesByDefinitionName.get(definitionName);
|
|
173
|
-
if (dependenciesOfDefinition) {
|
|
174
|
-
for (const dependencyName of dependenciesOfDefinition) {
|
|
175
|
-
const dependencyDefinitions = definitionsByName.get(dependencyName);
|
|
176
|
-
if (dependencyDefinitions != null) {
|
|
177
|
-
for (const dependencyDefinition of dependencyDefinitions) {
|
|
178
|
-
definitionsWithDependencies.add(dependencyDefinition);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
const potentialTransitiveDefinitionsMap = new Map();
|
|
186
|
-
const allImportedDefinitionsMap = new Map();
|
|
187
|
-
for (const line of importLines) {
|
|
188
|
-
const { imports, from } = parseImportLine(line.replace('#', '').trim());
|
|
189
|
-
const importFileDefinitionMap = visitFile(from, filePath, visitedFiles, predefinedImports);
|
|
190
|
-
if (importFileDefinitionMap != null) {
|
|
191
|
-
const buildFullDefinitionMap = (dependenciesMap) => {
|
|
192
|
-
for (const [importedDefinitionName, importedDefinitions] of importFileDefinitionMap) {
|
|
193
|
-
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
194
|
-
if (!dependenciesMap.has(importedDefinitionTypeName)) {
|
|
195
|
-
dependenciesMap.set(importedDefinitionTypeName, new Set());
|
|
196
|
-
}
|
|
197
|
-
const allImportedDefinitions = dependenciesMap.get(importedDefinitionTypeName);
|
|
198
|
-
if (allImportedDefinitions) {
|
|
199
|
-
for (const importedDefinition of importedDefinitions) {
|
|
200
|
-
allImportedDefinitions.add(importedDefinition);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
buildFullDefinitionMap(potentialTransitiveDefinitionsMap);
|
|
206
|
-
if (imports.includes('*')) {
|
|
207
|
-
buildFullDefinitionMap(allImportedDefinitionsMap);
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
for (let importedDefinitionName of imports) {
|
|
211
|
-
if (importedDefinitionName.endsWith('.*')) {
|
|
212
|
-
// Adding whole type means the same thing with adding every single field
|
|
213
|
-
importedDefinitionName = importedDefinitionName.replace('.*', '');
|
|
214
|
-
}
|
|
215
|
-
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
216
|
-
if (!allImportedDefinitionsMap.has(importedDefinitionTypeName)) {
|
|
217
|
-
allImportedDefinitionsMap.set(importedDefinitionTypeName, new Set());
|
|
218
|
-
}
|
|
219
|
-
const allImportedDefinitions = allImportedDefinitionsMap.get(importedDefinitionTypeName);
|
|
220
|
-
const importedDefinitions = importFileDefinitionMap.get(importedDefinitionName);
|
|
221
|
-
if (!importedDefinitions) {
|
|
222
|
-
throw new Error(`${importedDefinitionName} is not exported by ${from} imported by ${filePath}`);
|
|
223
|
-
}
|
|
224
|
-
if (allImportedDefinitions != null) {
|
|
225
|
-
for (const importedDefinition of importedDefinitions) {
|
|
226
|
-
allImportedDefinitions.add(importedDefinition);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
55
|
+
const { importLines, otherLines } = extractImportLines(fileContent);
|
|
56
|
+
const { definitionsByName, dependenciesByDefinitionName } = extractDependencies(filePath, otherLines);
|
|
57
|
+
const fileDefinitionMap = getFileDefinitionMap(definitionsByName, dependenciesByDefinitionName);
|
|
58
|
+
// To prevent circular dependency
|
|
59
|
+
visitedFiles.set(filePath, fileDefinitionMap);
|
|
60
|
+
const { allImportedDefinitionsMap, potentialTransitiveDefinitionsMap } = processImports(importLines, filePath, visitedFiles, predefinedImports);
|
|
233
61
|
const addDefinition = (definition, definitionName, definitionSet) => {
|
|
234
62
|
const fileDefinitionMap = visitedFiles.get(filePath);
|
|
235
63
|
if (fileDefinitionMap && !definitionSet.has(definition)) {
|
|
@@ -272,12 +100,6 @@ function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
|
272
100
|
};
|
|
273
101
|
if (!otherLines) {
|
|
274
102
|
visitedFiles.set(filePath, allImportedDefinitionsMap);
|
|
275
|
-
const definitionSet = new Set();
|
|
276
|
-
allImportedDefinitionsMap === null || allImportedDefinitionsMap === void 0 ? void 0 : allImportedDefinitionsMap.forEach((importedDefinitions, importedDefinitionName) => {
|
|
277
|
-
importedDefinitions === null || importedDefinitions === void 0 ? void 0 : importedDefinitions.forEach(importedDefinition => {
|
|
278
|
-
addDefinition(importedDefinition, importedDefinitionName, definitionSet);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
103
|
}
|
|
282
104
|
else {
|
|
283
105
|
const fileDefinitionMap = visitedFiles.get(filePath);
|
|
@@ -309,6 +131,210 @@ function visitFile(filePath, cwd, visitedFiles, predefinedImports) {
|
|
|
309
131
|
}
|
|
310
132
|
return visitedFiles.get(filePath);
|
|
311
133
|
}
|
|
134
|
+
function extractDependencies(filePath, fileContents) {
|
|
135
|
+
const definitionsByName = new Map();
|
|
136
|
+
const dependenciesByDefinitionName = new Map();
|
|
137
|
+
const { document } = parseGraphQLSDL(filePath, fileContents, {
|
|
138
|
+
noLocation: true,
|
|
139
|
+
});
|
|
140
|
+
for (const definition of document.definitions) {
|
|
141
|
+
visitDefinition(definition, definitionsByName, dependenciesByDefinitionName);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
definitionsByName,
|
|
145
|
+
dependenciesByDefinitionName,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function visitDefinition(definition, definitionsByName, dependenciesByDefinitionName) {
|
|
149
|
+
var _a;
|
|
150
|
+
// TODO: handle queries without names
|
|
151
|
+
if ('name' in definition || definition.kind === Kind.SCHEMA_DEFINITION) {
|
|
152
|
+
const definitionName = 'name' in definition && definition.name ? definition.name.value : 'schema';
|
|
153
|
+
if (!definitionsByName.has(definitionName)) {
|
|
154
|
+
definitionsByName.set(definitionName, new Set());
|
|
155
|
+
}
|
|
156
|
+
const definitionsSet = definitionsByName.get(definitionName);
|
|
157
|
+
definitionsSet.add(definition);
|
|
158
|
+
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
159
|
+
if (!dependencySet) {
|
|
160
|
+
dependencySet = new Set();
|
|
161
|
+
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
162
|
+
}
|
|
163
|
+
switch (definition.kind) {
|
|
164
|
+
case Kind.OPERATION_DEFINITION:
|
|
165
|
+
visitOperationDefinitionNode(definition, dependencySet);
|
|
166
|
+
break;
|
|
167
|
+
case Kind.FRAGMENT_DEFINITION:
|
|
168
|
+
visitFragmentDefinitionNode(definition, dependencySet);
|
|
169
|
+
break;
|
|
170
|
+
case Kind.OBJECT_TYPE_DEFINITION:
|
|
171
|
+
visitObjectTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
172
|
+
break;
|
|
173
|
+
case Kind.INTERFACE_TYPE_DEFINITION:
|
|
174
|
+
visitInterfaceTypeDefinitionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
175
|
+
break;
|
|
176
|
+
case Kind.UNION_TYPE_DEFINITION:
|
|
177
|
+
visitUnionTypeDefinitionNode(definition, dependencySet);
|
|
178
|
+
break;
|
|
179
|
+
case Kind.ENUM_TYPE_DEFINITION:
|
|
180
|
+
visitEnumTypeDefinitionNode(definition, dependencySet);
|
|
181
|
+
break;
|
|
182
|
+
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
|
|
183
|
+
visitInputObjectTypeDefinitionNode(definition, dependencySet);
|
|
184
|
+
break;
|
|
185
|
+
case Kind.DIRECTIVE_DEFINITION:
|
|
186
|
+
visitDirectiveDefinitionNode(definition, dependencySet);
|
|
187
|
+
break;
|
|
188
|
+
case Kind.SCALAR_TYPE_DEFINITION:
|
|
189
|
+
visitScalarDefinitionNode(definition, dependencySet);
|
|
190
|
+
break;
|
|
191
|
+
case Kind.SCHEMA_DEFINITION:
|
|
192
|
+
visitSchemaDefinitionNode(definition, dependencySet);
|
|
193
|
+
break;
|
|
194
|
+
case Kind.OBJECT_TYPE_EXTENSION:
|
|
195
|
+
visitObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
196
|
+
break;
|
|
197
|
+
case Kind.INTERFACE_TYPE_EXTENSION:
|
|
198
|
+
visitInterfaceTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName);
|
|
199
|
+
break;
|
|
200
|
+
case Kind.UNION_TYPE_EXTENSION:
|
|
201
|
+
visitUnionTypeExtensionNode(definition, dependencySet);
|
|
202
|
+
break;
|
|
203
|
+
case Kind.ENUM_TYPE_EXTENSION:
|
|
204
|
+
visitEnumTypeExtensionNode(definition, dependencySet);
|
|
205
|
+
break;
|
|
206
|
+
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
|
|
207
|
+
visitInputObjectTypeExtensionNode(definition, dependencySet);
|
|
208
|
+
break;
|
|
209
|
+
case Kind.SCALAR_TYPE_EXTENSION:
|
|
210
|
+
visitScalarExtensionNode(definition, dependencySet);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if ('fields' in definition && definition.fields) {
|
|
214
|
+
for (const field of definition.fields) {
|
|
215
|
+
const definitionName = definition.name.value + '.' + field.name.value;
|
|
216
|
+
if (!definitionsByName.has(definitionName)) {
|
|
217
|
+
definitionsByName.set(definitionName, new Set());
|
|
218
|
+
}
|
|
219
|
+
(_a = definitionsByName.get(definitionName)) === null || _a === void 0 ? void 0 : _a.add({
|
|
220
|
+
...definition,
|
|
221
|
+
fields: [field],
|
|
222
|
+
});
|
|
223
|
+
let dependencySet = dependenciesByDefinitionName.get(definitionName);
|
|
224
|
+
if (!dependencySet) {
|
|
225
|
+
dependencySet = new Set();
|
|
226
|
+
dependenciesByDefinitionName.set(definitionName, dependencySet);
|
|
227
|
+
}
|
|
228
|
+
switch (field.kind) {
|
|
229
|
+
case Kind.FIELD_DEFINITION:
|
|
230
|
+
visitFieldDefinitionNode(field, dependencySet);
|
|
231
|
+
break;
|
|
232
|
+
case Kind.INPUT_VALUE_DEFINITION:
|
|
233
|
+
visitInputValueDefinitionNode(field, dependencySet);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function getFileDefinitionMap(definitionsByName, dependenciesByDefinitionName) {
|
|
241
|
+
const fileDefinitionMap = new Map();
|
|
242
|
+
for (const [definitionName, definitions] of definitionsByName) {
|
|
243
|
+
let definitionsWithDependencies = fileDefinitionMap.get(definitionName);
|
|
244
|
+
if (definitionsWithDependencies == null) {
|
|
245
|
+
definitionsWithDependencies = new Set();
|
|
246
|
+
fileDefinitionMap.set(definitionName, definitionsWithDependencies);
|
|
247
|
+
}
|
|
248
|
+
for (const definition of definitions) {
|
|
249
|
+
definitionsWithDependencies.add(definition);
|
|
250
|
+
}
|
|
251
|
+
const dependenciesOfDefinition = dependenciesByDefinitionName.get(definitionName);
|
|
252
|
+
if (dependenciesOfDefinition) {
|
|
253
|
+
for (const dependencyName of dependenciesOfDefinition) {
|
|
254
|
+
const dependencyDefinitions = definitionsByName.get(dependencyName);
|
|
255
|
+
if (dependencyDefinitions != null) {
|
|
256
|
+
for (const dependencyDefinition of dependencyDefinitions) {
|
|
257
|
+
definitionsWithDependencies.add(dependencyDefinition);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return fileDefinitionMap;
|
|
264
|
+
}
|
|
265
|
+
function processImports(importLines, filePath, visitedFiles, predefinedImports) {
|
|
266
|
+
const potentialTransitiveDefinitionsMap = new Map();
|
|
267
|
+
const allImportedDefinitionsMap = new Map();
|
|
268
|
+
for (const line of importLines) {
|
|
269
|
+
const { imports, from } = parseImportLine(line.replace('#', '').trim());
|
|
270
|
+
const importFileDefinitionMap = visitFile(from, filePath, visitedFiles, predefinedImports);
|
|
271
|
+
const buildFullDefinitionMap = (dependenciesMap) => {
|
|
272
|
+
for (const [importedDefinitionName, importedDefinitions] of importFileDefinitionMap) {
|
|
273
|
+
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
274
|
+
if (!dependenciesMap.has(importedDefinitionTypeName)) {
|
|
275
|
+
dependenciesMap.set(importedDefinitionTypeName, new Set());
|
|
276
|
+
}
|
|
277
|
+
const allImportedDefinitions = dependenciesMap.get(importedDefinitionTypeName);
|
|
278
|
+
if (allImportedDefinitions) {
|
|
279
|
+
for (const importedDefinition of importedDefinitions) {
|
|
280
|
+
allImportedDefinitions.add(importedDefinition);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
buildFullDefinitionMap(potentialTransitiveDefinitionsMap);
|
|
286
|
+
if (imports.includes('*')) {
|
|
287
|
+
buildFullDefinitionMap(allImportedDefinitionsMap);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
for (let importedDefinitionName of imports) {
|
|
291
|
+
if (importedDefinitionName.endsWith('.*')) {
|
|
292
|
+
// Adding whole type means the same thing with adding every single field
|
|
293
|
+
importedDefinitionName = importedDefinitionName.replace('.*', '');
|
|
294
|
+
}
|
|
295
|
+
const [importedDefinitionTypeName] = importedDefinitionName.split('.');
|
|
296
|
+
if (!allImportedDefinitionsMap.has(importedDefinitionTypeName)) {
|
|
297
|
+
allImportedDefinitionsMap.set(importedDefinitionTypeName, new Set());
|
|
298
|
+
}
|
|
299
|
+
const allImportedDefinitions = allImportedDefinitionsMap.get(importedDefinitionTypeName);
|
|
300
|
+
const importedDefinitions = importFileDefinitionMap.get(importedDefinitionName);
|
|
301
|
+
if (!importedDefinitions) {
|
|
302
|
+
throw new Error(`${importedDefinitionName} is not exported by ${from} imported by ${filePath}`);
|
|
303
|
+
}
|
|
304
|
+
if (allImportedDefinitions != null) {
|
|
305
|
+
for (const importedDefinition of importedDefinitions) {
|
|
306
|
+
allImportedDefinitions.add(importedDefinition);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return { allImportedDefinitionsMap, potentialTransitiveDefinitionsMap };
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Splits the contents of a GraphQL file into lines that are imports
|
|
316
|
+
* and other lines which define the actual GraphQL document.
|
|
317
|
+
*/
|
|
318
|
+
function extractImportLines(fileContent) {
|
|
319
|
+
const importLines = [];
|
|
320
|
+
let otherLines = '';
|
|
321
|
+
for (const line of fileContent.split('\n')) {
|
|
322
|
+
const trimmedLine = line.trim();
|
|
323
|
+
if (trimmedLine.startsWith('#import ') || trimmedLine.startsWith('# import ')) {
|
|
324
|
+
importLines.push(trimmedLine);
|
|
325
|
+
}
|
|
326
|
+
else if (trimmedLine) {
|
|
327
|
+
otherLines += line + '\n';
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return { importLines, otherLines };
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Parses an import line, returning a list of entities imported and the file
|
|
334
|
+
* from which they are imported.
|
|
335
|
+
*
|
|
336
|
+
* Throws if the import line does not have a correct format.
|
|
337
|
+
*/
|
|
312
338
|
function parseImportLine(importLine) {
|
|
313
339
|
let regexMatch = importLine.match(IMPORT_FROM_REGEX);
|
|
314
340
|
if (regexMatch != null) {
|
|
@@ -557,4 +583,4 @@ function visitOperationTypeDefinitionNode(node, dependencySet) {
|
|
|
557
583
|
visitNamedTypeNode(node.type, dependencySet);
|
|
558
584
|
}
|
|
559
585
|
|
|
560
|
-
export { parseImportLine, processImport };
|
|
586
|
+
export { extractDependencies, extractImportLines, parseImportLine, processImport, processImports };
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphql-tools/import",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.3",
|
|
4
4
|
"description": "A set of utils for faster development of GraphQL tools",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
7
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
+
"@graphql-tools/utils": "8.2.5",
|
|
10
11
|
"resolve-from": "5.0.0",
|
|
11
12
|
"tslib": "~2.3.0"
|
|
12
13
|
},
|