@graphql-tools/load
Version:
A set of utils for faster development of GraphQL tools
105 lines (104 loc) • 4.24 kB
JavaScript
import { asArray, compareStrings } from '@graphql-tools/utils';
import { collectSources, collectSourcesSync } from './load-typedefs/collect-sources.js';
import { applyDefaultOptions } from './load-typedefs/options.js';
import { parseSource } from './load-typedefs/parse.js';
import { useLimit } from './utils/helpers.js';
import { normalizePointers } from './utils/pointers.js';
const CONCURRENCY_LIMIT = 100;
/**
* Asynchronously loads any GraphQL documents (i.e. executable documents like
* operations and fragments as well as type system definitions) from the
* provided pointers.
* loadTypedefs does not merge the typeDefs when `#import` is used ( https://github.com/ardatan/graphql-tools/issues/2980#issuecomment-1003692728 )
* @param pointerOrPointers Pointers to the sources to load the documents from
* @param options Additional options
*/
export async function loadTypedefs(pointerOrPointers, options) {
const { ignore, pointerOptionMap } = normalizePointers(pointerOrPointers);
options.ignore = asArray(options.ignore || []);
options.ignore.push(...ignore);
applyDefaultOptions(options);
const sources = await collectSources({
pointerOptionMap,
options,
});
const parsedSources = [];
// If we have few k of files it may be an issue
const limit = useLimit(CONCURRENCY_LIMIT);
await Promise.all(sources.map(partialSource => limit(() => parseSource({
partialSource,
options,
pointerOptionMap,
addSource(source) {
parsedSources.push(source);
},
}))));
return prepareResult({ options, pointerOptionMap, parsedSources });
}
/**
* Synchronously loads any GraphQL documents (i.e. executable documents like
* operations and fragments as well as type system definitions) from the
* provided pointers.
* @param pointerOrPointers Pointers to the sources to load the documents from
* @param options Additional options
*/
export function loadTypedefsSync(pointerOrPointers, options) {
const { ignore, pointerOptionMap } = normalizePointers(pointerOrPointers);
options.ignore = asArray(options.ignore || []).concat(ignore);
applyDefaultOptions(options);
const sources = collectSourcesSync({
pointerOptionMap,
options,
});
const parsedSources = [];
for (const partialSource of sources) {
parseSource({
partialSource,
options,
pointerOptionMap,
addSource(source) {
parsedSources.push(source);
},
});
}
return prepareResult({ options, pointerOptionMap, parsedSources });
}
//
function prepareResult({ options, pointerOptionMap, parsedSources, }) {
const failedSources = parsedSources.filter(source => source.error != null);
if (failedSources.length > 0) {
if (options.errorHandling === 'aggregate') {
const errors = failedSources.map(source => source.error);
throw new AggregateError(errors, errors.map(error => error.message).join('\n'));
}
if (options.errorHandling === 'throw') {
throw failedSources[0].error;
}
}
const resultSources = options.errorHandling === 'return'
? parsedSources
: parsedSources.filter(source => source.error == null);
const pointerList = Object.keys(pointerOptionMap);
const loadedDocuments = resultSources.filter(source => source.document?.definitions && source.document.definitions.length > 0);
if (pointerList.length > 0 &&
loadedDocuments.length === 0 &&
options.errorHandling !== 'return') {
throw new NoTypeDefinitionsFound(pointerList);
}
if (pointerList.length > 0 && resultSources.length === 0) {
throw new NoTypeDefinitionsFound(pointerList);
}
return options.sort
? resultSources.sort((left, right) => compareStrings(left.location, right.location))
: resultSources;
}
export class NoTypeDefinitionsFound extends Error {
constructor(pointerList) {
super(`
Unable to find any GraphQL type definitions for the following pointers:
${pointerList.map(p => `
- ${p}
`)}`);
this.name = 'NoTypeDefinitionsFound';
}
}