graphql-document-collector
Version:
Load up smartly, in one location, all of the GraphQL queries/mutations/subscriptions of your project
90 lines (79 loc) • 2.8 kB
text/typescript
import {
DocumentNode,
FragmentDefinitionNode,
OperationDefinitionNode,
SelectionSetNode,
FragmentSpreadNode,
FieldNode,
InlineFragmentNode,
} from 'graphql';
import {DocumentDirectory} from '../ast';
export interface FragmentMap {
[fragmentName: string]: FragmentDefinitionNode;
}
export function createFragmentMap(
dir: DocumentDirectory, fragmentMap: FragmentMap = {}
): FragmentMap {
// TODO: make this function pure
dir.documents.forEach(doc => doc.definitions.forEach(def => {
if (def.kind === 'FragmentDefinition') {
const fragDef = (def as FragmentDefinitionNode);
fragmentMap[fragDef.name.value] = fragDef;
}
}));
dir.directories.forEach(subDir => createFragmentMap(subDir, fragmentMap));
return fragmentMap;
}
function fragmentSpreadsInSelectionSet(
selSet: SelectionSetNode, fMap: FragmentMap, fragmentSpreads: Set<string>
): Set<string> {
// TODO: make this function pure
selSet.selections.forEach(sel => {
if (sel.kind === 'FragmentSpread') {
const fragmentName = (sel as FragmentSpreadNode).name.value;
fragmentSpreads.add(fragmentName);
fragmentSpreadsInSelectionSet(fMap[fragmentName].selectionSet, fMap, fragmentSpreads);
} else if (sel.kind === 'Field' && (sel as FieldNode).selectionSet) {
fragmentSpreadsInSelectionSet((sel as FieldNode).selectionSet, fMap, fragmentSpreads);
} else if ((sel.kind === 'InlineFragment')) {
fragmentSpreadsInSelectionSet((sel as InlineFragmentNode).selectionSet, fMap, fragmentSpreads);
}
});
return fragmentSpreads;
}
export function addFragmentsToDocument(document: DocumentNode, fMap: FragmentMap): DocumentNode {
// TODO: make this function pure
const definedFragments: Set<string> = new Set();
const fragmentSpreads: Set<string> = new Set()
document.definitions.forEach(def => {
if (def.kind === 'FragmentDefinition') {
definedFragments.add(def.name.value);
}
if (def.kind === 'OperationDefinition' || def.kind === 'FragmentDefinition') {
const selSetDef = (def as OperationDefinitionNode|FragmentDefinitionNode);
fragmentSpreadsInSelectionSet(selSetDef.selectionSet, fMap, fragmentSpreads)
}
});
return Object.assign({}, document, {
definitions: [
...document.definitions,
...Array.from(fragmentSpreads).filter(sp => !definedFragments.has(sp)).map(sp => fMap[sp]),
],
});
}
export function resolveFragments(
dir: DocumentDirectory,
fMap: FragmentMap = null
): DocumentDirectory {
if (!fMap) {
fMap = createFragmentMap(dir);
}
return Object.assign({}, dir, {
directories: dir.directories.map(subDir =>
resolveFragments(subDir, fMap)
),
documents: dir.documents.map(doc =>
addFragmentsToDocument(doc, fMap)
),
});
}