UNPKG

20.7 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7const utils = require('@graphql-tools/utils');
8const process = require('process');
9const graphql = require('graphql');
10const isGlob = _interopDefault(require('is-glob'));
11const pLimit = _interopDefault(require('p-limit'));
12const importFrom = _interopDefault(require('import-from'));
13const unixify = _interopDefault(require('unixify'));
14const globby = require('globby');
15const globby__default = _interopDefault(globby);
16const merge = require('@graphql-tools/merge');
17
18function normalizePointers(unnormalizedPointerOrPointers) {
19 return utils.asArray(unnormalizedPointerOrPointers).reduce((normalizedPointers, unnormalizedPointer) => {
20 if (typeof unnormalizedPointer === 'string') {
21 normalizedPointers[unnormalizedPointer] = {};
22 }
23 else if (typeof unnormalizedPointer === 'object') {
24 Object.assign(normalizedPointers, unnormalizedPointer);
25 }
26 else {
27 throw new Error(`Invalid pointer ${unnormalizedPointer}`);
28 }
29 return normalizedPointers;
30 }, {});
31}
32
33function applyDefaultOptions(options) {
34 options.cache = options.cache || {};
35 options.cwd = options.cwd || process.cwd();
36 options.sort = 'sort' in options ? options.sort : true;
37}
38
39async function loadFile(pointer, options) {
40 const cached = useCache({ pointer, options });
41 if (cached) {
42 return cached;
43 }
44 for await (const loader of options.loaders) {
45 try {
46 const canLoad = await loader.canLoad(pointer, options);
47 if (canLoad) {
48 return await loader.load(pointer, options);
49 }
50 }
51 catch (error) {
52 utils.debugLog(`Failed to find any GraphQL type definitions in: ${pointer} - ${error.message}`);
53 throw error;
54 }
55 }
56 return undefined;
57}
58function loadFileSync(pointer, options) {
59 const cached = useCache({ pointer, options });
60 if (cached) {
61 return cached;
62 }
63 for (const loader of options.loaders) {
64 try {
65 const canLoad = loader.canLoadSync && loader.loadSync && loader.canLoadSync(pointer, options);
66 if (canLoad) {
67 return loader.loadSync(pointer, options);
68 }
69 }
70 catch (error) {
71 utils.debugLog(`Failed to find any GraphQL type definitions in: ${pointer} - ${error.message}`);
72 throw error;
73 }
74 }
75 return undefined;
76}
77function useCache({ pointer, options }) {
78 if (options['cache']) {
79 return options['cache'][pointer];
80 }
81}
82
83/**
84 * Converts a string to 32bit integer
85 */
86function stringToHash(str) {
87 let hash = 0;
88 if (str.length === 0) {
89 return hash;
90 }
91 let char;
92 for (let i = 0; i < str.length; i++) {
93 char = str.charCodeAt(i);
94 // tslint:disable-next-line: no-bitwise
95 hash = (hash << 5) - hash + char;
96 // tslint:disable-next-line: no-bitwise
97 hash = hash & hash;
98 }
99 return hash;
100}
101function useStack(...fns) {
102 return (input) => {
103 function createNext(i) {
104 if (i >= fns.length) {
105 return () => { };
106 }
107 return function next() {
108 fns[i](input, createNext(i + 1));
109 };
110 }
111 fns[0](input, createNext(1));
112 };
113}
114function useLimit(concurrency) {
115 return pLimit(concurrency);
116}
117
118function getCustomLoaderByPath(path, cwd) {
119 try {
120 const requiredModule = importFrom(cwd, path);
121 if (requiredModule) {
122 if (requiredModule.default && typeof requiredModule.default === 'function') {
123 return requiredModule.default;
124 }
125 if (typeof requiredModule === 'function') {
126 return requiredModule;
127 }
128 }
129 }
130 catch (e) { }
131 return null;
132}
133async function useCustomLoader(loaderPointer, cwd) {
134 let loader;
135 if (typeof loaderPointer === 'string') {
136 loader = await getCustomLoaderByPath(loaderPointer, cwd);
137 }
138 else if (typeof loaderPointer === 'function') {
139 loader = loaderPointer;
140 }
141 if (typeof loader !== 'function') {
142 throw new Error(`Failed to load custom loader: ${loaderPointer}`);
143 }
144 return loader;
145}
146function useCustomLoaderSync(loaderPointer, cwd) {
147 let loader;
148 if (typeof loaderPointer === 'string') {
149 loader = getCustomLoaderByPath(loaderPointer, cwd);
150 }
151 else if (typeof loaderPointer === 'function') {
152 loader = loaderPointer;
153 }
154 if (typeof loader !== 'function') {
155 throw new Error(`Failed to load custom loader: ${loaderPointer}`);
156 }
157 return loader;
158}
159
160function useQueue(options) {
161 const queue = [];
162 const limit = (options === null || options === void 0 ? void 0 : options.concurrency) ? pLimit(options.concurrency) : async (fn) => fn();
163 return {
164 add(fn) {
165 queue.push(() => limit(fn));
166 },
167 runAll() {
168 return Promise.all(queue.map(fn => fn()));
169 },
170 };
171}
172function useSyncQueue() {
173 const queue = [];
174 return {
175 add(fn) {
176 queue.push(fn);
177 },
178 runAll() {
179 queue.forEach(fn => fn());
180 },
181 };
182}
183
184const CONCURRENCY_LIMIT = 50;
185async function collectSources({ pointerOptionMap, options, }) {
186 var _a;
187 const sources = [];
188 const globs = [];
189 const globOptions = {};
190 const queue = useQueue({ concurrency: CONCURRENCY_LIMIT });
191 const { addSource, addGlob, collect } = createHelpers({
192 sources,
193 globs,
194 options,
195 globOptions,
196 stack: [collectDocumentString, collectGlob, collectCustomLoader, collectFallback],
197 });
198 for (const pointer in pointerOptionMap) {
199 const pointerOptions = {
200 ...((_a = pointerOptionMap[pointer]) !== null && _a !== void 0 ? _a : {}),
201 unixify,
202 };
203 collect({
204 pointer,
205 pointerOptions,
206 pointerOptionMap,
207 options,
208 addSource,
209 addGlob,
210 queue: queue.add,
211 });
212 }
213 if (globs.length) {
214 includeIgnored({
215 options,
216 globs,
217 });
218 const paths = await globby__default(globs, createGlobbyOptions(options));
219 collectSourcesFromGlobals({
220 filepaths: paths,
221 options,
222 globOptions,
223 pointerOptionMap,
224 addSource,
225 queue: queue.add,
226 });
227 }
228 await queue.runAll();
229 return sources;
230}
231function collectSourcesSync({ pointerOptionMap, options, }) {
232 var _a;
233 const sources = [];
234 const globs = [];
235 const globOptions = {};
236 const queue = useSyncQueue();
237 const { addSource, addGlob, collect } = createHelpers({
238 sources,
239 globs,
240 options,
241 globOptions,
242 stack: [collectDocumentString, collectGlob, collectCustomLoaderSync, collectFallbackSync],
243 });
244 for (const pointer in pointerOptionMap) {
245 const pointerOptions = {
246 ...((_a = pointerOptionMap[pointer]) !== null && _a !== void 0 ? _a : {}),
247 unixify,
248 };
249 collect({
250 pointer,
251 pointerOptions,
252 pointerOptionMap,
253 options,
254 addSource,
255 addGlob,
256 queue: queue.add,
257 });
258 }
259 if (globs.length) {
260 includeIgnored({
261 options,
262 globs,
263 });
264 const paths = globby.sync(globs, createGlobbyOptions(options));
265 collectSourcesFromGlobalsSync({
266 filepaths: paths,
267 options,
268 globOptions,
269 pointerOptionMap,
270 addSource,
271 queue: queue.add,
272 });
273 }
274 queue.runAll();
275 return sources;
276}
277//
278function createHelpers({ sources, globs, options, globOptions, stack, }) {
279 const addSource = ({ pointer, source, noCache, }) => {
280 sources.push(source);
281 if (!noCache) {
282 options.cache[pointer] = source;
283 }
284 };
285 const collect = useStack(...stack);
286 const addGlob = ({ pointerOptions, pointer }) => {
287 globs.push(pointer);
288 Object.assign(globOptions, pointerOptions);
289 };
290 return {
291 addSource,
292 collect,
293 addGlob,
294 };
295}
296function includeIgnored({ options, globs }) {
297 if (options.ignore) {
298 const ignoreList = utils.asArray(options.ignore)
299 .map(g => `!(${g})`)
300 .map(unixify);
301 if (ignoreList.length > 0) {
302 globs.push(...ignoreList);
303 }
304 }
305}
306function createGlobbyOptions(options) {
307 return { absolute: true, ...options, ignore: [] };
308}
309function collectSourcesFromGlobals({ filepaths, options, globOptions, pointerOptionMap, addSource, queue, }) {
310 const collectFromGlobs = useStack(collectCustomLoader, collectFallback);
311 for (let i = 0; i < filepaths.length; i++) {
312 const pointer = filepaths[i];
313 collectFromGlobs({
314 pointer,
315 pointerOptions: globOptions,
316 pointerOptionMap,
317 options,
318 addSource,
319 addGlob: () => {
320 throw new Error(`I don't accept any new globs!`);
321 },
322 queue,
323 });
324 }
325}
326function collectSourcesFromGlobalsSync({ filepaths, options, globOptions, pointerOptionMap, addSource, queue, }) {
327 const collectFromGlobs = useStack(collectCustomLoaderSync, collectFallbackSync);
328 for (let i = 0; i < filepaths.length; i++) {
329 const pointer = filepaths[i];
330 collectFromGlobs({
331 pointer,
332 pointerOptions: globOptions,
333 pointerOptionMap,
334 options,
335 addSource,
336 addGlob: () => {
337 throw new Error(`I don't accept any new globs!`);
338 },
339 queue,
340 });
341 }
342}
343function addResultOfCustomLoader({ pointer, result, addSource, }) {
344 if (graphql.isSchema(result)) {
345 addSource({
346 source: {
347 location: pointer,
348 schema: result,
349 document: graphql.parse(utils.printSchemaWithDirectives(result)),
350 },
351 pointer,
352 noCache: true,
353 });
354 }
355 else if (result.kind && result.kind === graphql.Kind.DOCUMENT) {
356 addSource({
357 source: {
358 document: result,
359 location: pointer,
360 },
361 pointer,
362 });
363 }
364 else if (result.document) {
365 addSource({
366 source: {
367 location: pointer,
368 ...result,
369 },
370 pointer,
371 });
372 }
373}
374function collectDocumentString({ pointer, pointerOptions, options, addSource, queue }, next) {
375 if (utils.isDocumentString(pointer)) {
376 return queue(() => {
377 const source = utils.parseGraphQLSDL(`${stringToHash(pointer)}.graphql`, pointer, {
378 ...options,
379 ...pointerOptions,
380 });
381 addSource({
382 source,
383 pointer,
384 });
385 });
386 }
387 next();
388}
389function collectGlob({ pointer, pointerOptions, addGlob }, next) {
390 if (isGlob(pointerOptions.unixify(pointer))) {
391 return addGlob({
392 pointer: pointerOptions.unixify(pointer),
393 pointerOptions,
394 });
395 }
396 next();
397}
398function collectCustomLoader({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) {
399 if (pointerOptions.loader) {
400 return queue(async () => {
401 const loader = await useCustomLoader(pointerOptions.loader, options.cwd);
402 const result = await loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap);
403 if (!result) {
404 return;
405 }
406 addResultOfCustomLoader({ pointer, result, addSource });
407 });
408 }
409 next();
410}
411function collectCustomLoaderSync({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) {
412 if (pointerOptions.loader) {
413 return queue(() => {
414 const loader = useCustomLoaderSync(pointerOptions.loader, options.cwd);
415 const result = loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap);
416 if (result) {
417 addResultOfCustomLoader({ pointer, result, addSource });
418 }
419 });
420 }
421 next();
422}
423function collectFallback({ queue, pointer, options, pointerOptions, addSource }) {
424 return queue(async () => {
425 const source = await loadFile(pointer, {
426 ...options,
427 ...pointerOptions,
428 });
429 if (source) {
430 addSource({ source, pointer });
431 }
432 });
433}
434function collectFallbackSync({ queue, pointer, options, pointerOptions, addSource }) {
435 return queue(() => {
436 const source = loadFileSync(pointer, {
437 ...options,
438 ...pointerOptions,
439 });
440 if (source) {
441 addSource({ source, pointer });
442 }
443 });
444}
445
446const filterKind = (content, filterKinds) => {
447 if (content && content.definitions && content.definitions.length && filterKinds && filterKinds.length > 0) {
448 const invalidDefinitions = [];
449 const validDefinitions = [];
450 for (const definitionNode of content.definitions) {
451 if (filterKinds.includes(definitionNode.kind)) {
452 invalidDefinitions.push(definitionNode);
453 }
454 else {
455 validDefinitions.push(definitionNode);
456 }
457 }
458 if (invalidDefinitions.length > 0) {
459 invalidDefinitions.forEach(d => {
460 utils.debugLog(`Filtered document of kind ${d.kind} due to filter policy (${filterKinds.join(', ')})`);
461 });
462 }
463 return {
464 kind: graphql.Kind.DOCUMENT,
465 definitions: validDefinitions,
466 };
467 }
468 return content;
469};
470
471function parseSource({ partialSource, options, globOptions, pointerOptionMap, addValidSource }) {
472 if (partialSource) {
473 const input = prepareInput({
474 source: partialSource,
475 options,
476 globOptions,
477 pointerOptionMap,
478 });
479 parseSchema(input);
480 parseRawSDL(input);
481 if (input.source.document) {
482 useKindsFilter(input);
483 useComments(input);
484 collectValidSources(input, addValidSource);
485 }
486 }
487}
488//
489function prepareInput({ source, options, globOptions, pointerOptionMap, }) {
490 const specificOptions = {
491 ...options,
492 ...(source.location in pointerOptionMap ? globOptions : pointerOptionMap[source.location]),
493 };
494 return { source: { ...source }, options: specificOptions };
495}
496function parseSchema(input) {
497 if (input.source.schema) {
498 input.source.schema = utils.fixSchemaAst(input.source.schema, input.options);
499 input.source.rawSDL = utils.printSchemaWithDirectives(input.source.schema, input.options);
500 }
501}
502function parseRawSDL(input) {
503 if (input.source.rawSDL) {
504 input.source.document = graphql.parse(new graphql.Source(input.source.rawSDL, input.source.location), input.options);
505 }
506}
507function useKindsFilter(input) {
508 if (input.options.filterKinds) {
509 input.source.document = filterKind(input.source.document, input.options.filterKinds);
510 }
511}
512function useComments(input) {
513 if (!input.source.rawSDL) {
514 input.source.rawSDL = merge.printWithComments(input.source.document);
515 merge.resetComments();
516 }
517}
518function collectValidSources(input, addValidSource) {
519 if (input.source.document.definitions && input.source.document.definitions.length > 0) {
520 addValidSource(input.source);
521 }
522}
523
524const CONCURRENCY_LIMIT$1 = 100;
525async function loadTypedefs(pointerOrPointers, options) {
526 const pointerOptionMap = normalizePointers(pointerOrPointers);
527 const globOptions = {};
528 applyDefaultOptions(options);
529 const sources = await collectSources({
530 pointerOptionMap,
531 options,
532 });
533 const validSources = [];
534 // If we have few k of files it may be an issue
535 const limit = useLimit(CONCURRENCY_LIMIT$1);
536 await Promise.all(sources.map(partialSource => limit(() => parseSource({
537 partialSource,
538 options,
539 globOptions,
540 pointerOptionMap,
541 addValidSource(source) {
542 validSources.push(source);
543 },
544 }))));
545 return prepareResult({ options, pointerOptionMap, validSources });
546}
547function loadTypedefsSync(pointerOrPointers, options) {
548 const pointerOptionMap = normalizePointers(pointerOrPointers);
549 const globOptions = {};
550 applyDefaultOptions(options);
551 const sources = collectSourcesSync({
552 pointerOptionMap,
553 options,
554 });
555 const validSources = [];
556 sources.forEach(partialSource => {
557 parseSource({
558 partialSource,
559 options,
560 globOptions,
561 pointerOptionMap,
562 addValidSource(source) {
563 validSources.push(source);
564 },
565 });
566 });
567 return prepareResult({ options, pointerOptionMap, validSources });
568}
569//
570function prepareResult({ options, pointerOptionMap, validSources, }) {
571 const pointerList = Object.keys(pointerOptionMap);
572 if (pointerList.length > 0 && validSources.length === 0) {
573 throw new Error(`
574 Unable to find any GraphQL type definitions for the following pointers:
575 ${pointerList.map(p => `
576 - ${p}
577 `)}`);
578 }
579 return options.sort
580 ? validSources.sort((left, right) => utils.compareStrings(left.location, right.location))
581 : validSources;
582}
583
584const OPERATION_KINDS = [graphql.Kind.OPERATION_DEFINITION, graphql.Kind.FRAGMENT_DEFINITION];
585const NON_OPERATION_KINDS = Object.keys(graphql.Kind)
586 .reduce((prev, v) => [...prev, graphql.Kind[v]], [])
587 .filter(v => !OPERATION_KINDS.includes(v));
588function loadDocuments(documentDef, options) {
589 return loadTypedefs(documentDef, { noRequire: true, filterKinds: NON_OPERATION_KINDS, ...options });
590}
591function loadDocumentsSync(documentDef, options) {
592 return loadTypedefsSync(documentDef, { noRequire: true, filterKinds: NON_OPERATION_KINDS, ...options });
593}
594
595async function loadSchema(schemaPointers, options) {
596 const sources = await loadTypedefs(schemaPointers, {
597 filterKinds: OPERATION_KINDS,
598 ...options,
599 });
600 const { schemas, typeDefs } = collectSchemasAndTypeDefs(sources);
601 const mergeSchemasOptions = {
602 schemas,
603 typeDefs,
604 ...options,
605 };
606 const schema = await merge.mergeSchemasAsync(mergeSchemasOptions);
607 if (options === null || options === void 0 ? void 0 : options.includeSources) {
608 includeSources(schema, sources);
609 }
610 return schema;
611}
612function loadSchemaSync(schemaPointers, options) {
613 const sources = loadTypedefsSync(schemaPointers, {
614 filterKinds: OPERATION_KINDS,
615 ...options,
616 });
617 const { schemas, typeDefs } = collectSchemasAndTypeDefs(sources);
618 const mergeSchemasOptions = {
619 schemas,
620 typeDefs,
621 ...options,
622 };
623 const schema = merge.mergeSchemas(mergeSchemasOptions);
624 if (options === null || options === void 0 ? void 0 : options.includeSources) {
625 includeSources(schema, sources);
626 }
627 return schema;
628}
629function includeSources(schema, sources) {
630 schema.extensions = {
631 ...schema.extensions,
632 sources: sources
633 .filter(source => source.rawSDL || source.document)
634 .map(source => new graphql.Source(source.rawSDL || graphql.print(source.document), source.location)),
635 };
636}
637function collectSchemasAndTypeDefs(sources) {
638 const schemas = [];
639 const typeDefs = [];
640 sources.forEach(source => {
641 if (source.schema) {
642 schemas.push(source.schema);
643 }
644 else {
645 typeDefs.push(source.document);
646 }
647 });
648 return {
649 schemas,
650 typeDefs,
651 };
652}
653
654exports.NON_OPERATION_KINDS = NON_OPERATION_KINDS;
655exports.OPERATION_KINDS = OPERATION_KINDS;
656exports.filterKind = filterKind;
657exports.loadDocuments = loadDocuments;
658exports.loadDocumentsSync = loadDocumentsSync;
659exports.loadSchema = loadSchema;
660exports.loadSchemaSync = loadSchemaSync;
661exports.loadTypedefs = loadTypedefs;
662exports.loadTypedefsSync = loadTypedefsSync;
663//# sourceMappingURL=index.cjs.js.map