UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

358 lines 14 kB
import { __assign, __spreadArray } from "tslib"; import { invariant } from "../globals/index.js"; import { visit, Kind, } from 'graphql'; import { checkDocument, getOperationDefinition, getFragmentDefinition, getFragmentDefinitions, getMainDefinition, } from "./getFromAST.js"; import { isField } from "./storeUtils.js"; import { createFragmentMap, } from "./fragments.js"; import { isArray } from "../common/arrays.js"; var TYPENAME_FIELD = { kind: Kind.FIELD, name: { kind: Kind.NAME, value: '__typename', }, }; function isEmpty(op, fragmentMap) { return !op || op.selectionSet.selections.every(function (selection) { return selection.kind === Kind.FRAGMENT_SPREAD && isEmpty(fragmentMap[selection.name.value], fragmentMap); }); } function nullIfDocIsEmpty(doc) { return isEmpty(getOperationDefinition(doc) || getFragmentDefinition(doc), createFragmentMap(getFragmentDefinitions(doc))) ? null : doc; } function getDirectiveMatcher(directives) { var nameSet = new Set(); var tests = []; directives.forEach(function (directive) { if (directive.name) { nameSet.add(directive.name); } else if (directive.test) { tests.push(directive.test); } }); return function (directive) { return (nameSet.has(directive.name.value) || tests.some(function (test) { return test(directive); })); }; } function makeInUseGetterFunction(defaultKey) { var map = new Map(); return function inUseGetterFunction(key) { if (key === void 0) { key = defaultKey; } var inUse = map.get(key); if (!inUse) { map.set(key, inUse = { variables: new Set, fragmentSpreads: new Set, }); } return inUse; }; } export function removeDirectivesFromDocument(directives, doc) { var getInUseByOperationName = makeInUseGetterFunction(""); var getInUseByFragmentName = makeInUseGetterFunction(""); var getInUse = function (ancestors) { for (var p = 0, ancestor = void 0; p < ancestors.length && (ancestor = ancestors[p]); ++p) { if (isArray(ancestor)) continue; if (ancestor.kind === Kind.OPERATION_DEFINITION) { return getInUseByOperationName(ancestor.name && ancestor.name.value); } if (ancestor.kind === Kind.FRAGMENT_DEFINITION) { return getInUseByFragmentName(ancestor.name.value); } } __DEV__ && invariant.error("Could not find operation or fragment"); return null; }; var operationCount = 0; for (var i = doc.definitions.length - 1; i >= 0; --i) { if (doc.definitions[i].kind === Kind.OPERATION_DEFINITION) { ++operationCount; } } var directiveMatcher = getDirectiveMatcher(directives); var hasRemoveDirective = directives.some(function (directive) { return directive.remove; }); var shouldRemoveField = function (nodeDirectives) { return (hasRemoveDirective && nodeDirectives && nodeDirectives.some(directiveMatcher)); }; var originalFragmentDefsByPath = new Map(); var firstVisitMadeChanges = false; var fieldOrInlineFragmentVisitor = { enter: function (node) { if (shouldRemoveField(node.directives)) { firstVisitMadeChanges = true; return null; } }, }; var docWithoutDirectiveSubtrees = visit(doc, { Field: fieldOrInlineFragmentVisitor, InlineFragment: fieldOrInlineFragmentVisitor, VariableDefinition: { enter: function () { return false; }, }, Variable: { enter: function (node, _key, _parent, _path, ancestors) { var inUse = getInUse(ancestors); if (inUse) { inUse.variables.add(node.name.value); } }, }, FragmentSpread: { enter: function (node, _key, _parent, _path, ancestors) { if (shouldRemoveField(node.directives)) { firstVisitMadeChanges = true; return null; } var inUse = getInUse(ancestors); if (inUse) { inUse.fragmentSpreads.add(node.name.value); } }, }, FragmentDefinition: { enter: function (node, _key, _parent, path) { originalFragmentDefsByPath.set(JSON.stringify(path), node); }, leave: function (node, _key, _parent, path) { var originalNode = originalFragmentDefsByPath.get(JSON.stringify(path)); if (node === originalNode) { return node; } if (operationCount > 0 && node.selectionSet.selections.every(function (selection) { return (selection.kind === Kind.FIELD && selection.name.value === '__typename'); })) { getInUseByFragmentName(node.name.value).removed = true; firstVisitMadeChanges = true; return null; } }, }, Directive: { leave: function (node) { if (directiveMatcher(node)) { firstVisitMadeChanges = true; return null; } }, }, }); if (!firstVisitMadeChanges) { return doc; } var populateTransitiveVars = function (inUse) { if (!inUse.transitiveVars) { inUse.transitiveVars = new Set(inUse.variables); if (!inUse.removed) { inUse.fragmentSpreads.forEach(function (childFragmentName) { populateTransitiveVars(getInUseByFragmentName(childFragmentName)).transitiveVars.forEach(function (varName) { inUse.transitiveVars.add(varName); }); }); } } return inUse; }; var allFragmentNamesUsed = new Set(); docWithoutDirectiveSubtrees.definitions.forEach(function (def) { if (def.kind === Kind.OPERATION_DEFINITION) { populateTransitiveVars(getInUseByOperationName(def.name && def.name.value)).fragmentSpreads.forEach(function (childFragmentName) { allFragmentNamesUsed.add(childFragmentName); }); } else if (def.kind === Kind.FRAGMENT_DEFINITION && operationCount === 0 && !getInUseByFragmentName(def.name.value).removed) { allFragmentNamesUsed.add(def.name.value); } }); allFragmentNamesUsed.forEach(function (fragmentName) { populateTransitiveVars(getInUseByFragmentName(fragmentName)).fragmentSpreads.forEach(function (childFragmentName) { allFragmentNamesUsed.add(childFragmentName); }); }); var fragmentWillBeRemoved = function (fragmentName) { return !!(!allFragmentNamesUsed.has(fragmentName) || getInUseByFragmentName(fragmentName).removed); }; var enterVisitor = { enter: function (node) { if (fragmentWillBeRemoved(node.name.value)) { return null; } }, }; return nullIfDocIsEmpty(visit(docWithoutDirectiveSubtrees, { FragmentSpread: enterVisitor, FragmentDefinition: enterVisitor, OperationDefinition: { leave: function (node) { if (node.variableDefinitions) { var usedVariableNames_1 = populateTransitiveVars(getInUseByOperationName(node.name && node.name.value)).transitiveVars; if (usedVariableNames_1.size < node.variableDefinitions.length) { return __assign(__assign({}, node), { variableDefinitions: node.variableDefinitions.filter(function (varDef) { return usedVariableNames_1.has(varDef.variable.name.value); }) }); } } }, }, })); } export var addTypenameToDocument = Object.assign(function (doc) { return visit(doc, { SelectionSet: { enter: function (node, _key, parent) { if (parent && parent.kind === Kind.OPERATION_DEFINITION) { return; } var selections = node.selections; if (!selections) { return; } var skip = selections.some(function (selection) { return (isField(selection) && (selection.name.value === '__typename' || selection.name.value.lastIndexOf('__', 0) === 0)); }); if (skip) { return; } var field = parent; if (isField(field) && field.directives && field.directives.some(function (d) { return d.name.value === 'export'; })) { return; } return __assign(__assign({}, node), { selections: __spreadArray(__spreadArray([], selections, true), [TYPENAME_FIELD], false) }); }, }, }); }, { added: function (field) { return field === TYPENAME_FIELD; }, }); var connectionRemoveConfig = { test: function (directive) { var willRemove = directive.name.value === 'connection'; if (willRemove) { if (!directive.arguments || !directive.arguments.some(function (arg) { return arg.name.value === 'key'; })) { __DEV__ && invariant.warn('Removing an @connection directive even though it does not have a key. ' + 'You may want to use the key parameter to specify a store key.'); } } return willRemove; }, }; export function removeConnectionDirectiveFromDocument(doc) { return removeDirectivesFromDocument([connectionRemoveConfig], checkDocument(doc)); } function hasDirectivesInSelectionSet(directives, selectionSet, nestedCheck) { if (nestedCheck === void 0) { nestedCheck = true; } return (!!selectionSet && selectionSet.selections && selectionSet.selections.some(function (selection) { return hasDirectivesInSelection(directives, selection, nestedCheck); })); } function hasDirectivesInSelection(directives, selection, nestedCheck) { if (nestedCheck === void 0) { nestedCheck = true; } if (!isField(selection)) { return true; } if (!selection.directives) { return false; } return (selection.directives.some(getDirectiveMatcher(directives)) || (nestedCheck && hasDirectivesInSelectionSet(directives, selection.selectionSet, nestedCheck))); } function getArgumentMatcher(config) { return function argumentMatcher(argument) { return config.some(function (aConfig) { return argument.value && argument.value.kind === Kind.VARIABLE && argument.value.name && (aConfig.name === argument.value.name.value || (aConfig.test && aConfig.test(argument))); }); }; } export function removeArgumentsFromDocument(config, doc) { var argMatcher = getArgumentMatcher(config); return nullIfDocIsEmpty(visit(doc, { OperationDefinition: { enter: function (node) { return __assign(__assign({}, node), { variableDefinitions: node.variableDefinitions ? node.variableDefinitions.filter(function (varDef) { return !config.some(function (arg) { return arg.name === varDef.variable.name.value; }); }) : [] }); }, }, Field: { enter: function (node) { var shouldRemoveField = config.some(function (argConfig) { return argConfig.remove; }); if (shouldRemoveField) { var argMatchCount_1 = 0; if (node.arguments) { node.arguments.forEach(function (arg) { if (argMatcher(arg)) { argMatchCount_1 += 1; } }); } if (argMatchCount_1 === 1) { return null; } } }, }, Argument: { enter: function (node) { if (argMatcher(node)) { return null; } }, }, })); } export function removeFragmentSpreadFromDocument(config, doc) { function enter(node) { if (config.some(function (def) { return def.name === node.name.value; })) { return null; } } return nullIfDocIsEmpty(visit(doc, { FragmentSpread: { enter: enter }, FragmentDefinition: { enter: enter }, })); } export function buildQueryFromSelectionSet(document) { var definition = getMainDefinition(document); var definitionOperation = definition.operation; if (definitionOperation === 'query') { return document; } var modifiedDoc = visit(document, { OperationDefinition: { enter: function (node) { return __assign(__assign({}, node), { operation: 'query' }); }, }, }); return modifiedDoc; } export function removeClientSetsFromDocument(document) { checkDocument(document); var modifiedDoc = removeDirectivesFromDocument([ { test: function (directive) { return directive.name.value === 'client'; }, remove: true, }, ], document); return modifiedDoc; } //# sourceMappingURL=transform.js.map