@graphql-tools/load 7.6.0 → 7.7.0-alpha-b76ec274.0
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/cjs/documents.js +39 -0
- package/cjs/filter-document-kind.js +35 -0
- package/cjs/index.js +7 -0
- package/cjs/load-typedefs/collect-sources.js +195 -0
- package/cjs/load-typedefs/load-file.js +86 -0
- package/cjs/load-typedefs/options.js +10 -0
- package/cjs/load-typedefs/parse.js +62 -0
- package/cjs/load-typedefs.js +84 -0
- package/cjs/package.json +1 -0
- package/cjs/schema.js +86 -0
- package/cjs/utils/custom-loader.js +50 -0
- package/cjs/utils/helpers.js +42 -0
- package/cjs/utils/pointers.js +31 -0
- package/cjs/utils/queue.js +32 -0
- package/esm/documents.js +34 -0
- package/esm/filter-document-kind.js +31 -0
- package/esm/index.js +4 -0
- package/esm/load-typedefs/collect-sources.js +167 -0
- package/esm/load-typedefs/load-file.js +81 -0
- package/esm/load-typedefs/options.js +6 -0
- package/esm/load-typedefs/parse.js +58 -0
- package/esm/load-typedefs.js +79 -0
- package/esm/schema.js +81 -0
- package/esm/utils/custom-loader.js +44 -0
- package/esm/utils/helpers.js +35 -0
- package/esm/utils/pointers.js +27 -0
- package/esm/utils/queue.js +26 -0
- package/package.json +33 -12
- package/{documents.d.ts → typings/documents.d.ts} +1 -1
- package/{filter-document-kind.d.ts → typings/filter-document-kind.d.ts} +0 -0
- package/typings/index.d.ts +4 -0
- package/{load-typedefs → typings/load-typedefs}/collect-sources.d.ts +1 -1
- package/{load-typedefs → typings/load-typedefs}/load-file.d.ts +1 -1
- package/{load-typedefs → typings/load-typedefs}/options.d.ts +1 -1
- package/{load-typedefs → typings/load-typedefs}/parse.d.ts +0 -0
- package/{load-typedefs.d.ts → typings/load-typedefs.d.ts} +0 -0
- package/{schema.d.ts → typings/schema.d.ts} +1 -1
- package/{utils → typings/utils}/custom-loader.d.ts +0 -0
- package/{utils → typings/utils}/helpers.d.ts +0 -0
- package/{utils → typings/utils}/pointers.d.ts +1 -1
- package/{utils → typings/utils}/queue.d.ts +0 -0
- package/README.md +0 -8
- package/index.d.ts +0 -4
- package/index.js +0 -691
- package/index.mjs +0 -658
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useLimit = exports.useStack = exports.stringToHash = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const p_limit_1 = tslib_1.__importDefault(require("p-limit"));
|
|
6
|
+
/**
|
|
7
|
+
* Converts a string to 32bit integer
|
|
8
|
+
*/
|
|
9
|
+
function stringToHash(str) {
|
|
10
|
+
let hash = 0;
|
|
11
|
+
if (str.length === 0) {
|
|
12
|
+
return hash;
|
|
13
|
+
}
|
|
14
|
+
let char;
|
|
15
|
+
for (let i = 0; i < str.length; i++) {
|
|
16
|
+
char = str.charCodeAt(i);
|
|
17
|
+
// tslint:disable-next-line: no-bitwise
|
|
18
|
+
hash = (hash << 5) - hash + char;
|
|
19
|
+
// tslint:disable-next-line: no-bitwise
|
|
20
|
+
hash = hash & hash;
|
|
21
|
+
}
|
|
22
|
+
return hash;
|
|
23
|
+
}
|
|
24
|
+
exports.stringToHash = stringToHash;
|
|
25
|
+
function useStack(...fns) {
|
|
26
|
+
return (input) => {
|
|
27
|
+
function createNext(i) {
|
|
28
|
+
if (i >= fns.length) {
|
|
29
|
+
return () => { };
|
|
30
|
+
}
|
|
31
|
+
return function next() {
|
|
32
|
+
fns[i](input, createNext(i + 1));
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
fns[0](input, createNext(1));
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
exports.useStack = useStack;
|
|
39
|
+
function useLimit(concurrency) {
|
|
40
|
+
return (0, p_limit_1.default)(concurrency);
|
|
41
|
+
}
|
|
42
|
+
exports.useLimit = useLimit;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizePointers = void 0;
|
|
4
|
+
const utils_1 = require("@graphql-tools/utils");
|
|
5
|
+
function normalizePointers(unnormalizedPointerOrPointers) {
|
|
6
|
+
const ignore = [];
|
|
7
|
+
const pointerOptionMap = {};
|
|
8
|
+
const handlePointer = (rawPointer, options = {}) => {
|
|
9
|
+
if (rawPointer.startsWith('!')) {
|
|
10
|
+
ignore.push(rawPointer.replace('!', ''));
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
pointerOptionMap[rawPointer] = options;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
for (const rawPointer of (0, utils_1.asArray)(unnormalizedPointerOrPointers)) {
|
|
17
|
+
if (typeof rawPointer === 'string') {
|
|
18
|
+
handlePointer(rawPointer);
|
|
19
|
+
}
|
|
20
|
+
else if (typeof rawPointer === 'object') {
|
|
21
|
+
for (const [path, options] of Object.entries(rawPointer)) {
|
|
22
|
+
handlePointer(path, options);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
throw new Error(`Invalid pointer '${rawPointer}'.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { ignore, pointerOptionMap };
|
|
30
|
+
}
|
|
31
|
+
exports.normalizePointers = normalizePointers;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSyncQueue = exports.useQueue = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const p_limit_1 = tslib_1.__importDefault(require("p-limit"));
|
|
6
|
+
function useQueue(options) {
|
|
7
|
+
const queue = [];
|
|
8
|
+
const limit = (options === null || options === void 0 ? void 0 : options.concurrency) ? (0, p_limit_1.default)(options.concurrency) : async (fn) => fn();
|
|
9
|
+
return {
|
|
10
|
+
add(fn) {
|
|
11
|
+
queue.push(() => limit(fn));
|
|
12
|
+
},
|
|
13
|
+
runAll() {
|
|
14
|
+
return Promise.all(queue.map(fn => fn()));
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
exports.useQueue = useQueue;
|
|
19
|
+
function useSyncQueue() {
|
|
20
|
+
const queue = [];
|
|
21
|
+
return {
|
|
22
|
+
add(fn) {
|
|
23
|
+
queue.push(fn);
|
|
24
|
+
},
|
|
25
|
+
runAll() {
|
|
26
|
+
for (const fn of queue) {
|
|
27
|
+
fn();
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
exports.useSyncQueue = useSyncQueue;
|
package/esm/documents.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Kind } from 'graphql';
|
|
2
|
+
import { loadTypedefs, loadTypedefsSync } from './load-typedefs.js';
|
|
3
|
+
/**
|
|
4
|
+
* Kinds of AST nodes that are included in executable documents
|
|
5
|
+
*/
|
|
6
|
+
export const OPERATION_KINDS = [Kind.OPERATION_DEFINITION, Kind.FRAGMENT_DEFINITION];
|
|
7
|
+
/**
|
|
8
|
+
* Kinds of AST nodes that are included in type system definition documents
|
|
9
|
+
*/
|
|
10
|
+
export const NON_OPERATION_KINDS = Object.keys(Kind)
|
|
11
|
+
.reduce((prev, v) => [...prev, Kind[v]], [])
|
|
12
|
+
.filter(v => !OPERATION_KINDS.includes(v));
|
|
13
|
+
/**
|
|
14
|
+
* Asynchronously loads executable documents (i.e. operations and fragments) from
|
|
15
|
+
* the provided pointers. The pointers may be individual files or a glob pattern.
|
|
16
|
+
* The files themselves may be `.graphql` files or `.js` and `.ts` (in which
|
|
17
|
+
* case they will be parsed using graphql-tag-pluck).
|
|
18
|
+
* @param pointerOrPointers Pointers to the files to load the documents from
|
|
19
|
+
* @param options Additional options
|
|
20
|
+
*/
|
|
21
|
+
export function loadDocuments(pointerOrPointers, options) {
|
|
22
|
+
return loadTypedefs(pointerOrPointers, { noRequire: true, filterKinds: NON_OPERATION_KINDS, ...options });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Synchronously loads executable documents (i.e. operations and fragments) from
|
|
26
|
+
* the provided pointers. The pointers may be individual files or a glob pattern.
|
|
27
|
+
* The files themselves may be `.graphql` files or `.js` and `.ts` (in which
|
|
28
|
+
* case they will be parsed using graphql-tag-pluck).
|
|
29
|
+
* @param pointerOrPointers Pointers to the files to load the documents from
|
|
30
|
+
* @param options Additional options
|
|
31
|
+
*/
|
|
32
|
+
export function loadDocumentsSync(pointerOrPointers, options) {
|
|
33
|
+
return loadTypedefsSync(pointerOrPointers, { noRequire: true, filterKinds: NON_OPERATION_KINDS, ...options });
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Kind } from 'graphql';
|
|
2
|
+
import { env } from 'process';
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export const filterKind = (content, filterKinds) => {
|
|
7
|
+
if (content && content.definitions && content.definitions.length && filterKinds && filterKinds.length > 0) {
|
|
8
|
+
const invalidDefinitions = [];
|
|
9
|
+
const validDefinitions = [];
|
|
10
|
+
for (const definitionNode of content.definitions) {
|
|
11
|
+
if (filterKinds.includes(definitionNode.kind)) {
|
|
12
|
+
invalidDefinitions.push(definitionNode);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
validDefinitions.push(definitionNode);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (invalidDefinitions.length > 0) {
|
|
19
|
+
if (env['DEBUG']) {
|
|
20
|
+
for (const d of invalidDefinitions) {
|
|
21
|
+
console.log(`Filtered document of kind ${d.kind} due to filter policy (${filterKinds.join(', ')})`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
kind: Kind.DOCUMENT,
|
|
27
|
+
definitions: validDefinitions,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return content;
|
|
31
|
+
};
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { isDocumentString, parseGraphQLSDL, getDocumentNodeFromSchema, asArray } from '@graphql-tools/utils';
|
|
2
|
+
import { isSchema, Kind } from 'graphql';
|
|
3
|
+
import { loadFile, loadFileSync } from './load-file.js';
|
|
4
|
+
import { stringToHash, useStack } from '../utils/helpers.js';
|
|
5
|
+
import { useCustomLoader, useCustomLoaderSync } from '../utils/custom-loader.js';
|
|
6
|
+
import { useQueue, useSyncQueue } from '../utils/queue.js';
|
|
7
|
+
import { createRequire } from 'module';
|
|
8
|
+
import { cwd } from 'process';
|
|
9
|
+
const CONCURRENCY_LIMIT = 50;
|
|
10
|
+
export async function collectSources({ pointerOptionMap, options, }) {
|
|
11
|
+
const sources = [];
|
|
12
|
+
const queue = useQueue({ concurrency: CONCURRENCY_LIMIT });
|
|
13
|
+
const { addSource, collect } = createHelpers({
|
|
14
|
+
sources,
|
|
15
|
+
stack: [collectDocumentString, collectCustomLoader, collectFallback],
|
|
16
|
+
});
|
|
17
|
+
for (const pointer in pointerOptionMap) {
|
|
18
|
+
const pointerOptions = pointerOptionMap[pointer];
|
|
19
|
+
collect({
|
|
20
|
+
pointer,
|
|
21
|
+
pointerOptions,
|
|
22
|
+
pointerOptionMap,
|
|
23
|
+
options,
|
|
24
|
+
addSource,
|
|
25
|
+
queue: queue.add,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
await queue.runAll();
|
|
29
|
+
return sources;
|
|
30
|
+
}
|
|
31
|
+
export function collectSourcesSync({ pointerOptionMap, options, }) {
|
|
32
|
+
const sources = [];
|
|
33
|
+
const queue = useSyncQueue();
|
|
34
|
+
const { addSource, collect } = createHelpers({
|
|
35
|
+
sources,
|
|
36
|
+
stack: [collectDocumentString, collectCustomLoaderSync, collectFallbackSync],
|
|
37
|
+
});
|
|
38
|
+
for (const pointer in pointerOptionMap) {
|
|
39
|
+
const pointerOptions = pointerOptionMap[pointer];
|
|
40
|
+
collect({
|
|
41
|
+
pointer,
|
|
42
|
+
pointerOptions,
|
|
43
|
+
pointerOptionMap,
|
|
44
|
+
options,
|
|
45
|
+
addSource,
|
|
46
|
+
queue: queue.add,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
queue.runAll();
|
|
50
|
+
return sources;
|
|
51
|
+
}
|
|
52
|
+
function createHelpers({ sources, stack }) {
|
|
53
|
+
const addSource = ({ source }) => {
|
|
54
|
+
sources.push(source);
|
|
55
|
+
};
|
|
56
|
+
const collect = useStack(...stack);
|
|
57
|
+
return {
|
|
58
|
+
addSource,
|
|
59
|
+
collect,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function addResultOfCustomLoader({ pointer, result, addSource, }) {
|
|
63
|
+
if (isSchema(result)) {
|
|
64
|
+
addSource({
|
|
65
|
+
source: {
|
|
66
|
+
location: pointer,
|
|
67
|
+
schema: result,
|
|
68
|
+
document: getDocumentNodeFromSchema(result),
|
|
69
|
+
},
|
|
70
|
+
pointer,
|
|
71
|
+
noCache: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (result.kind && result.kind === Kind.DOCUMENT) {
|
|
75
|
+
addSource({
|
|
76
|
+
source: {
|
|
77
|
+
document: result,
|
|
78
|
+
location: pointer,
|
|
79
|
+
},
|
|
80
|
+
pointer,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else if (result.document) {
|
|
84
|
+
addSource({
|
|
85
|
+
source: {
|
|
86
|
+
location: pointer,
|
|
87
|
+
...result,
|
|
88
|
+
},
|
|
89
|
+
pointer,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function collectDocumentString({ pointer, pointerOptions, options, addSource, queue }, next) {
|
|
94
|
+
if (isDocumentString(pointer)) {
|
|
95
|
+
return queue(() => {
|
|
96
|
+
const source = parseGraphQLSDL(`${stringToHash(pointer)}.graphql`, pointer, {
|
|
97
|
+
...options,
|
|
98
|
+
...pointerOptions,
|
|
99
|
+
});
|
|
100
|
+
addSource({
|
|
101
|
+
source,
|
|
102
|
+
pointer,
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
next();
|
|
107
|
+
}
|
|
108
|
+
function collectCustomLoader({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) {
|
|
109
|
+
if (pointerOptions.loader) {
|
|
110
|
+
return queue(async () => {
|
|
111
|
+
await Promise.all(asArray(pointerOptions.require).map(m => import(m)));
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
113
|
+
// @ts-ignore TODO options.cwd is possibly undefined, but it seems like no test covers this path
|
|
114
|
+
const loader = await useCustomLoader(pointerOptions.loader, options.cwd);
|
|
115
|
+
const result = await loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap);
|
|
116
|
+
if (!result) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
addResultOfCustomLoader({ pointer, result, addSource });
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
next();
|
|
123
|
+
}
|
|
124
|
+
function collectCustomLoaderSync({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) {
|
|
125
|
+
if (pointerOptions.loader) {
|
|
126
|
+
return queue(() => {
|
|
127
|
+
const cwdRequire = createRequire(options.cwd || cwd());
|
|
128
|
+
for (const m of asArray(pointerOptions.require)) {
|
|
129
|
+
cwdRequire(m);
|
|
130
|
+
}
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
132
|
+
// @ts-ignore TODO options.cwd is possibly undefined, but it seems like no test covers this path
|
|
133
|
+
const loader = useCustomLoaderSync(pointerOptions.loader, options.cwd);
|
|
134
|
+
const result = loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap);
|
|
135
|
+
if (result) {
|
|
136
|
+
addResultOfCustomLoader({ pointer, result, addSource });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
next();
|
|
141
|
+
}
|
|
142
|
+
function collectFallback({ queue, pointer, options, pointerOptions, addSource }) {
|
|
143
|
+
return queue(async () => {
|
|
144
|
+
const sources = await loadFile(pointer, {
|
|
145
|
+
...options,
|
|
146
|
+
...pointerOptions,
|
|
147
|
+
});
|
|
148
|
+
if (sources) {
|
|
149
|
+
for (const source of sources) {
|
|
150
|
+
addSource({ source, pointer });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function collectFallbackSync({ queue, pointer, options, pointerOptions, addSource }) {
|
|
156
|
+
return queue(() => {
|
|
157
|
+
const sources = loadFileSync(pointer, {
|
|
158
|
+
...options,
|
|
159
|
+
...pointerOptions,
|
|
160
|
+
});
|
|
161
|
+
if (sources) {
|
|
162
|
+
for (const source of sources) {
|
|
163
|
+
addSource({ source, pointer });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { AggregateError } from '@graphql-tools/utils';
|
|
2
|
+
import { env } from 'process';
|
|
3
|
+
export async function loadFile(pointer, options) {
|
|
4
|
+
var _a;
|
|
5
|
+
let results = (_a = options.cache) === null || _a === void 0 ? void 0 : _a[pointer];
|
|
6
|
+
if (!results) {
|
|
7
|
+
results = [];
|
|
8
|
+
const errors = [];
|
|
9
|
+
await Promise.all(options.loaders.map(async (loader) => {
|
|
10
|
+
try {
|
|
11
|
+
const loaderResults = await loader.load(pointer, options);
|
|
12
|
+
loaderResults === null || loaderResults === void 0 ? void 0 : loaderResults.forEach(result => results.push(result));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (env['DEBUG']) {
|
|
16
|
+
console.error(error);
|
|
17
|
+
}
|
|
18
|
+
if (error instanceof AggregateError) {
|
|
19
|
+
for (const errorElement of error.errors) {
|
|
20
|
+
errors.push(errorElement);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
errors.push(error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
if (results.length === 0 && errors.length > 0) {
|
|
29
|
+
if (errors.length === 1) {
|
|
30
|
+
throw errors[0];
|
|
31
|
+
}
|
|
32
|
+
throw new AggregateError(errors, `Failed to find any GraphQL type definitions in: ${pointer};\n - ${errors
|
|
33
|
+
.map(error => error.message)
|
|
34
|
+
.join('\n - ')}`);
|
|
35
|
+
}
|
|
36
|
+
if (options.cache) {
|
|
37
|
+
options.cache[pointer] = results;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
export function loadFileSync(pointer, options) {
|
|
43
|
+
var _a;
|
|
44
|
+
let results = (_a = options.cache) === null || _a === void 0 ? void 0 : _a[pointer];
|
|
45
|
+
if (!results) {
|
|
46
|
+
results = [];
|
|
47
|
+
const errors = [];
|
|
48
|
+
for (const loader of options.loaders) {
|
|
49
|
+
try {
|
|
50
|
+
// We check for the existence so it is okay to force non null
|
|
51
|
+
const loaderResults = loader.loadSync(pointer, options);
|
|
52
|
+
loaderResults === null || loaderResults === void 0 ? void 0 : loaderResults.forEach(result => results.push(result));
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (env['DEBUG']) {
|
|
56
|
+
console.error(error);
|
|
57
|
+
}
|
|
58
|
+
if (error instanceof AggregateError) {
|
|
59
|
+
for (const errorElement of error.errors) {
|
|
60
|
+
errors.push(errorElement);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
errors.push(error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (results.length === 0 && errors.length > 0) {
|
|
69
|
+
if (errors.length === 1) {
|
|
70
|
+
throw errors[0];
|
|
71
|
+
}
|
|
72
|
+
throw new AggregateError(errors, `Failed to find any GraphQL type definitions in: ${pointer};\n - ${errors
|
|
73
|
+
.map(error => error.message)
|
|
74
|
+
.join('\n - ')}`);
|
|
75
|
+
}
|
|
76
|
+
if (options.cache) {
|
|
77
|
+
options.cache[pointer] = results;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { printSchemaWithDirectives, parseGraphQLSDL, printWithComments, resetComments, } from '@graphql-tools/utils';
|
|
2
|
+
import { filterKind } from '../filter-document-kind.js';
|
|
3
|
+
export function parseSource({ partialSource, options, pointerOptionMap, addValidSource }) {
|
|
4
|
+
if (partialSource) {
|
|
5
|
+
const input = prepareInput({
|
|
6
|
+
source: partialSource,
|
|
7
|
+
options,
|
|
8
|
+
pointerOptionMap,
|
|
9
|
+
});
|
|
10
|
+
parseSchema(input);
|
|
11
|
+
parseRawSDL(input);
|
|
12
|
+
if (input.source.document) {
|
|
13
|
+
useKindsFilter(input);
|
|
14
|
+
useComments(input);
|
|
15
|
+
collectValidSources(input, addValidSource);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//
|
|
20
|
+
function prepareInput({ source, options, pointerOptionMap, }) {
|
|
21
|
+
let specificOptions = {
|
|
22
|
+
...options,
|
|
23
|
+
};
|
|
24
|
+
if (source.location) {
|
|
25
|
+
specificOptions = {
|
|
26
|
+
...specificOptions,
|
|
27
|
+
...pointerOptionMap[source.location],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return { source: { ...source }, options: specificOptions };
|
|
31
|
+
}
|
|
32
|
+
function parseSchema(input) {
|
|
33
|
+
if (input.source.schema) {
|
|
34
|
+
input.source.rawSDL = printSchemaWithDirectives(input.source.schema, input.options);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function parseRawSDL(input) {
|
|
38
|
+
if (input.source.rawSDL) {
|
|
39
|
+
input.source.document = parseGraphQLSDL(input.source.location, input.source.rawSDL, input.options).document;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function useKindsFilter(input) {
|
|
43
|
+
if (input.options.filterKinds) {
|
|
44
|
+
input.source.document = filterKind(input.source.document, input.options.filterKinds);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function useComments(input) {
|
|
48
|
+
if (!input.source.rawSDL && input.source.document) {
|
|
49
|
+
input.source.rawSDL = printWithComments(input.source.document);
|
|
50
|
+
resetComments();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function collectValidSources(input, addValidSource) {
|
|
54
|
+
var _a;
|
|
55
|
+
if (((_a = input.source.document) === null || _a === void 0 ? void 0 : _a.definitions) && input.source.document.definitions.length > 0) {
|
|
56
|
+
addValidSource(input.source);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { compareStrings, asArray } from '@graphql-tools/utils';
|
|
2
|
+
import { normalizePointers } from './utils/pointers.js';
|
|
3
|
+
import { applyDefaultOptions } from './load-typedefs/options.js';
|
|
4
|
+
import { collectSources, collectSourcesSync } from './load-typedefs/collect-sources.js';
|
|
5
|
+
import { parseSource } from './load-typedefs/parse.js';
|
|
6
|
+
import { useLimit } from './utils/helpers.js';
|
|
7
|
+
const CONCURRENCY_LIMIT = 100;
|
|
8
|
+
/**
|
|
9
|
+
* Asynchronously loads any GraphQL documents (i.e. executable documents like
|
|
10
|
+
* operations and fragments as well as type system definitions) from the
|
|
11
|
+
* provided pointers.
|
|
12
|
+
* loadTypedefs does not merge the typeDefs when `#import` is used ( https://github.com/ardatan/graphql-tools/issues/2980#issuecomment-1003692728 )
|
|
13
|
+
* @param pointerOrPointers Pointers to the sources to load the documents from
|
|
14
|
+
* @param options Additional options
|
|
15
|
+
*/
|
|
16
|
+
export async function loadTypedefs(pointerOrPointers, options) {
|
|
17
|
+
const { ignore, pointerOptionMap } = normalizePointers(pointerOrPointers);
|
|
18
|
+
options.ignore = asArray(options.ignore || []);
|
|
19
|
+
options.ignore.push(...ignore);
|
|
20
|
+
applyDefaultOptions(options);
|
|
21
|
+
const sources = await collectSources({
|
|
22
|
+
pointerOptionMap,
|
|
23
|
+
options,
|
|
24
|
+
});
|
|
25
|
+
const validSources = [];
|
|
26
|
+
// If we have few k of files it may be an issue
|
|
27
|
+
const limit = useLimit(CONCURRENCY_LIMIT);
|
|
28
|
+
await Promise.all(sources.map(partialSource => limit(() => parseSource({
|
|
29
|
+
partialSource,
|
|
30
|
+
options,
|
|
31
|
+
pointerOptionMap,
|
|
32
|
+
addValidSource(source) {
|
|
33
|
+
validSources.push(source);
|
|
34
|
+
},
|
|
35
|
+
}))));
|
|
36
|
+
return prepareResult({ options, pointerOptionMap, validSources });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Synchronously loads any GraphQL documents (i.e. executable documents like
|
|
40
|
+
* operations and fragments as well as type system definitions) from the
|
|
41
|
+
* provided pointers.
|
|
42
|
+
* @param pointerOrPointers Pointers to the sources to load the documents from
|
|
43
|
+
* @param options Additional options
|
|
44
|
+
*/
|
|
45
|
+
export function loadTypedefsSync(pointerOrPointers, options) {
|
|
46
|
+
const { ignore, pointerOptionMap } = normalizePointers(pointerOrPointers);
|
|
47
|
+
options.ignore = asArray(options.ignore || []).concat(ignore);
|
|
48
|
+
applyDefaultOptions(options);
|
|
49
|
+
const sources = collectSourcesSync({
|
|
50
|
+
pointerOptionMap,
|
|
51
|
+
options,
|
|
52
|
+
});
|
|
53
|
+
const validSources = [];
|
|
54
|
+
for (const partialSource of sources) {
|
|
55
|
+
parseSource({
|
|
56
|
+
partialSource,
|
|
57
|
+
options,
|
|
58
|
+
pointerOptionMap,
|
|
59
|
+
addValidSource(source) {
|
|
60
|
+
validSources.push(source);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return prepareResult({ options, pointerOptionMap, validSources });
|
|
65
|
+
}
|
|
66
|
+
//
|
|
67
|
+
function prepareResult({ options, pointerOptionMap, validSources, }) {
|
|
68
|
+
const pointerList = Object.keys(pointerOptionMap);
|
|
69
|
+
if (pointerList.length > 0 && validSources.length === 0) {
|
|
70
|
+
throw new Error(`
|
|
71
|
+
Unable to find any GraphQL type definitions for the following pointers:
|
|
72
|
+
${pointerList.map(p => `
|
|
73
|
+
- ${p}
|
|
74
|
+
`)}`);
|
|
75
|
+
}
|
|
76
|
+
return options.sort
|
|
77
|
+
? validSources.sort((left, right) => compareStrings(left.location, right.location))
|
|
78
|
+
: validSources;
|
|
79
|
+
}
|
package/esm/schema.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { loadTypedefs, loadTypedefsSync } from './load-typedefs.js';
|
|
2
|
+
import { Source as GraphQLSource, print, lexicographicSortSchema, } from 'graphql';
|
|
3
|
+
import { OPERATION_KINDS } from './documents.js';
|
|
4
|
+
import { mergeSchemas } from '@graphql-tools/schema';
|
|
5
|
+
/**
|
|
6
|
+
* Asynchronously loads a schema from the provided pointers.
|
|
7
|
+
* @param schemaPointers Pointers to the sources to load the schema from
|
|
8
|
+
* @param options Additional options
|
|
9
|
+
*/
|
|
10
|
+
export async function loadSchema(schemaPointers, options) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
const sources = await loadTypedefs(schemaPointers, {
|
|
13
|
+
...options,
|
|
14
|
+
filterKinds: OPERATION_KINDS,
|
|
15
|
+
});
|
|
16
|
+
const { schemas, typeDefs } = collectSchemasAndTypeDefs(sources);
|
|
17
|
+
schemas.push(...((_a = options.schemas) !== null && _a !== void 0 ? _a : []));
|
|
18
|
+
const mergeSchemasOptions = {
|
|
19
|
+
...options,
|
|
20
|
+
schemas: schemas.concat((_b = options.schemas) !== null && _b !== void 0 ? _b : []),
|
|
21
|
+
typeDefs,
|
|
22
|
+
};
|
|
23
|
+
const schema = (typeDefs === null || typeDefs === void 0 ? void 0 : typeDefs.length) === 0 && (schemas === null || schemas === void 0 ? void 0 : schemas.length) === 1 ? schemas[0] : mergeSchemas(mergeSchemasOptions);
|
|
24
|
+
if (options === null || options === void 0 ? void 0 : options.includeSources) {
|
|
25
|
+
includeSources(schema, sources);
|
|
26
|
+
}
|
|
27
|
+
return options.sort ? lexicographicSortSchema(schema) : schema;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Synchronously loads a schema from the provided pointers.
|
|
31
|
+
* @param schemaPointers Pointers to the sources to load the schema from
|
|
32
|
+
* @param options Additional options
|
|
33
|
+
*/
|
|
34
|
+
export function loadSchemaSync(schemaPointers, options) {
|
|
35
|
+
const sources = loadTypedefsSync(schemaPointers, {
|
|
36
|
+
filterKinds: OPERATION_KINDS,
|
|
37
|
+
...options,
|
|
38
|
+
});
|
|
39
|
+
const { schemas, typeDefs } = collectSchemasAndTypeDefs(sources);
|
|
40
|
+
const schema = mergeSchemas({
|
|
41
|
+
schemas,
|
|
42
|
+
typeDefs,
|
|
43
|
+
...options,
|
|
44
|
+
});
|
|
45
|
+
if (options === null || options === void 0 ? void 0 : options.includeSources) {
|
|
46
|
+
includeSources(schema, sources);
|
|
47
|
+
}
|
|
48
|
+
return options.sort ? lexicographicSortSchema(schema) : schema;
|
|
49
|
+
}
|
|
50
|
+
function includeSources(schema, sources) {
|
|
51
|
+
const finalSources = [];
|
|
52
|
+
for (const source of sources) {
|
|
53
|
+
if (source.rawSDL) {
|
|
54
|
+
finalSources.push(new GraphQLSource(source.rawSDL, source.location));
|
|
55
|
+
}
|
|
56
|
+
else if (source.document) {
|
|
57
|
+
finalSources.push(new GraphQLSource(print(source.document), source.location));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
schema.extensions = {
|
|
61
|
+
...schema.extensions,
|
|
62
|
+
sources: finalSources,
|
|
63
|
+
extendedSources: sources,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function collectSchemasAndTypeDefs(sources) {
|
|
67
|
+
const schemas = [];
|
|
68
|
+
const typeDefs = [];
|
|
69
|
+
for (const source of sources) {
|
|
70
|
+
if (source.schema) {
|
|
71
|
+
schemas.push(source.schema);
|
|
72
|
+
}
|
|
73
|
+
else if (source.document) {
|
|
74
|
+
typeDefs.push(source.document);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
schemas,
|
|
79
|
+
typeDefs,
|
|
80
|
+
};
|
|
81
|
+
}
|