1 | {"version":3,"file":"equalByQuery.js","sourceRoot":"","sources":["../../src/core/equalByQuery.ts"],"names":[],"mappings":"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","sourcesContent":["import equal from \"@wry/equality\";\n\nimport type {\n DirectiveNode,\n DocumentNode,\n FieldNode,\n FragmentDefinitionNode,\n FragmentSpreadNode,\n InlineFragmentNode,\n SelectionNode,\n SelectionSetNode,\n} from \"graphql\";\n\nimport type { ApolloQueryResult, OperationVariables } from \"./types.js\";\n\nimport type { FragmentMap } from \"../utilities/index.js\";\nimport {\n createFragmentMap,\n getFragmentDefinitions,\n getFragmentFromSelection,\n getMainDefinition,\n isField,\n resultKeyNameFromField,\n shouldInclude,\n} from \"../utilities/index.js\";\n\n// Returns true if aResult and bResult are deeply equal according to the fields\n// selected by the given query, ignoring any fields marked as @nonreactive.\nexport function equalByQuery(\n query: DocumentNode,\n { data: aData, ...aRest }: Partial<ApolloQueryResult<unknown>>,\n { data: bData, ...bRest }: Partial<ApolloQueryResult<unknown>>,\n variables?: OperationVariables\n): boolean {\n return (\n equal(aRest, bRest) &&\n equalBySelectionSet(getMainDefinition(query).selectionSet, aData, bData, {\n fragmentMap: createFragmentMap(getFragmentDefinitions(query)),\n variables,\n })\n );\n}\n\n// Encapsulates the information used by equalBySelectionSet that does not change\n// during the recursion.\ninterface CompareContext<TVariables> {\n fragmentMap: FragmentMap;\n variables: TVariables | undefined;\n}\n\nfunction equalBySelectionSet(\n selectionSet: SelectionSetNode,\n aResult: any,\n bResult: any,\n context: CompareContext<OperationVariables>\n): boolean {\n if (aResult === bResult) {\n return true;\n }\n\n const seenSelections = new Set<SelectionNode>();\n\n // Returning true from this Array.prototype.every callback function skips the\n // current field/subtree. Returning false aborts the entire traversal\n // immediately, causing equalBySelectionSet to return false.\n return selectionSet.selections.every((selection) => {\n // Avoid re-processing the same selection at the same level of recursion, in\n // case the same field gets included via multiple indirect fragment spreads.\n if (seenSelections.has(selection)) return true;\n seenSelections.add(selection);\n\n // Ignore @skip(if: true) and @include(if: false) fields.\n if (!shouldInclude(selection, context.variables)) return true;\n\n // If the field or (named) fragment spread has a @nonreactive directive on\n // it, we don't care if it's different, so we pretend it's the same.\n if (selectionHasNonreactiveDirective(selection)) return true;\n\n if (isField(selection)) {\n const resultKey = resultKeyNameFromField(selection);\n const aResultChild = aResult && aResult[resultKey];\n const bResultChild = bResult && bResult[resultKey];\n const childSelectionSet = selection.selectionSet;\n\n if (!childSelectionSet) {\n // These are scalar values, so we can compare them with deep equal\n // without redoing the main recursive work.\n return equal(aResultChild, bResultChild);\n }\n\n const aChildIsArray = Array.isArray(aResultChild);\n const bChildIsArray = Array.isArray(bResultChild);\n if (aChildIsArray !== bChildIsArray) return false;\n if (aChildIsArray && bChildIsArray) {\n const length = aResultChild.length;\n if (bResultChild.length !== length) {\n return false;\n }\n for (let i = 0; i < length; ++i) {\n if (\n !equalBySelectionSet(\n childSelectionSet,\n aResultChild[i],\n bResultChild[i],\n context\n )\n ) {\n return false;\n }\n }\n return true;\n }\n\n return equalBySelectionSet(\n childSelectionSet,\n aResultChild,\n bResultChild,\n context\n );\n } else {\n const fragment = getFragmentFromSelection(selection, context.fragmentMap);\n if (fragment) {\n // The fragment might === selection if it's an inline fragment, but\n // could be !== if it's a named fragment ...spread.\n if (selectionHasNonreactiveDirective(fragment)) return true;\n\n return equalBySelectionSet(\n fragment.selectionSet,\n // Notice that we reuse the same aResult and bResult values here,\n // since the fragment ...spread does not specify a field name, but\n // consists of multiple fields (within the fragment's selection set)\n // that should be applied to the current result value(s).\n aResult,\n bResult,\n context\n );\n }\n }\n });\n}\n\nfunction selectionHasNonreactiveDirective(\n selection:\n | FieldNode\n | InlineFragmentNode\n | FragmentSpreadNode\n | FragmentDefinitionNode\n): boolean {\n return (\n !!selection.directives && selection.directives.some(directiveIsNonreactive)\n );\n}\n\nfunction directiveIsNonreactive(dir: DirectiveNode): boolean {\n return dir.name.value === \"nonreactive\";\n}\n"]} |