UNPKG

@graphql-tools/load

Version:

A set of utils for faster development of GraphQL tools

190 lines (189 loc) • 7.34 kB
import { createRequire } from 'module'; import { cwd } from 'process'; import { isSchema, Kind } from 'graphql'; import { asArray, debugTimerEnd, debugTimerStart, getDocumentNodeFromSchema, isDocumentString, parseGraphQLSDL, } from '@graphql-tools/utils'; import { useCustomLoader, useCustomLoaderSync } from '../utils/custom-loader.js'; import { stringToHash, useStack } from '../utils/helpers.js'; import { useQueue, useSyncQueue } from '../utils/queue.js'; import { loadFile, loadFileSync } from './load-file.js'; const CONCURRENCY_LIMIT = 50; export async function collectSources({ pointerOptionMap, options, }) { debugTimerStart('@graphql-tools/load: collectSources'); const sources = []; const queue = useQueue({ concurrency: CONCURRENCY_LIMIT }); const { addSource, collect } = createHelpers({ sources, stack: [collectDocumentString, collectCustomLoader, collectFallback], }); for (const pointer in pointerOptionMap) { const pointerOptions = pointerOptionMap[pointer]; debugTimerStart(`@graphql-tools/load: collectSources ${pointer}`); collect({ pointer, pointerOptions, pointerOptionMap, options, addSource, queue: queue.add, }); debugTimerEnd(`@graphql-tools/load: collectSources ${pointer}`); } debugTimerStart('@graphql-tools/load: collectSources queue'); await queue.runAll(); debugTimerEnd('@graphql-tools/load: collectSources queue'); return sources; } export function collectSourcesSync({ pointerOptionMap, options, }) { const sources = []; const queue = useSyncQueue(); const { addSource, collect } = createHelpers({ sources, stack: [collectDocumentString, collectCustomLoaderSync, collectFallbackSync], }); debugTimerStart('@graphql-tools/load: collectSourcesSync'); for (const pointer in pointerOptionMap) { const pointerOptions = pointerOptionMap[pointer]; debugTimerStart(`@graphql-tools/load: collectSourcesSync ${pointer}`); collect({ pointer, pointerOptions, pointerOptionMap, options, addSource, queue: queue.add, }); debugTimerEnd(`@graphql-tools/load: collectSourcesSync ${pointer}`); } debugTimerStart('@graphql-tools/load: collectSourcesSync queue'); queue.runAll(); debugTimerEnd('@graphql-tools/load: collectSourcesSync queue'); return sources; } function createHelpers({ sources, stack, }) { const addSource = ({ source }) => { sources.push(source); }; const collect = useStack(...stack); return { addSource, collect, }; } function addResultOfCustomLoader({ pointer, result, addSource, }) { debugTimerStart(`@graphql-tools/load: addResultOfCustomLoader ${pointer}`); if (isSchema(result)) { addSource({ source: { location: pointer, schema: result, document: getDocumentNodeFromSchema(result), }, pointer, noCache: true, }); } else if (result.kind && result.kind === Kind.DOCUMENT) { addSource({ source: { document: result, location: pointer, }, pointer, }); } else if (result.document) { addSource({ source: { location: pointer, ...result, }, pointer, }); } debugTimerEnd(`@graphql-tools/load: addResultOfCustomLoader ${pointer}`); } function collectDocumentString({ pointer, pointerOptions, options, addSource, queue }, next) { debugTimerStart(`@graphql-tools/load: collectDocumentString ${pointer}`); if (isDocumentString(pointer)) { return queue(() => { const source = parseGraphQLSDL(`${stringToHash(pointer)}.graphql`, pointer, { ...options, ...pointerOptions, }); addSource({ source, pointer, }); }); } debugTimerEnd(`@graphql-tools/load: collectDocumentString ${pointer}`); next(); } function collectCustomLoader({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) { if (pointerOptions.loader) { return queue(async () => { debugTimerStart(`@graphql-tools/load: collectCustomLoader ${pointer}`); await Promise.all(asArray(pointerOptions.require).map(m => import(m))); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore TODO options.cwd is possibly undefined, but it seems like no test covers this path const loader = await useCustomLoader(pointerOptions.loader, options.cwd); const result = await loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap); debugTimerEnd(`@graphql-tools/load: collectCustomLoader ${pointer}`); if (!result) { return; } addResultOfCustomLoader({ pointer, result, addSource }); }); } next(); } function collectCustomLoaderSync({ pointer, pointerOptions, queue, addSource, options, pointerOptionMap }, next) { if (pointerOptions.loader) { return queue(() => { debugTimerStart(`@graphql-tools/load: collectCustomLoaderSync ${pointer}`); const cwdRequire = createRequire(options.cwd || cwd()); for (const m of asArray(pointerOptions.require)) { cwdRequire(m); } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore TODO options.cwd is possibly undefined, but it seems like no test covers this path const loader = useCustomLoaderSync(pointerOptions.loader, options.cwd); const result = loader(pointer, { ...options, ...pointerOptions }, pointerOptionMap); debugTimerEnd(`@graphql-tools/load: collectCustomLoaderSync ${pointer}`); if (result) { addResultOfCustomLoader({ pointer, result, addSource }); } }); } next(); } function collectFallback({ queue, pointer, options, pointerOptions, addSource, }) { return queue(async () => { debugTimerStart(`@graphql-tools/load: collectFallback ${pointer}`); const sources = await loadFile(pointer, { ...options, ...pointerOptions, }); if (sources) { for (const source of sources) { addSource({ source, pointer }); } } debugTimerEnd(`@graphql-tools/load: collectFallback ${pointer}`); }); } function collectFallbackSync({ queue, pointer, options, pointerOptions, addSource, }) { return queue(() => { debugTimerStart(`@graphql-tools/load: collectFallbackSync ${pointer}`); const sources = loadFileSync(pointer, { ...options, ...pointerOptions, }); if (sources) { for (const source of sources) { addSource({ source, pointer }); } } debugTimerEnd(`@graphql-tools/load: collectFallbackSync ${pointer}`); }); }