Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

major(core/graphcache): Remove graphql imports by default (#3097)

+6
.changeset/fluffy-tools-marry.md
···
+
---
+
'@urql/exchange-graphcache': major
+
'@urql/core': major
+
---
+
+
Remove dependence on `graphql` package and replace it with `@0no-co/graphql.web`, which reduces the default bundlesize impact of `urql` packages to a minimum. All types should remain compatible, even if you use `graphql` elsewhere in your app, and if other dependencies are using `graphql` you may alias it to `graphql-web-lite`.
+5
.changeset/tame-pumas-promise.md
···
+
---
+
'@urql/core': patch
+
---
+
+
Remove dependence on `import { visit } from 'graphql';` with smaller but functionally equivalent alternative.
-3
exchanges/auth/package.json
···
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"devDependencies": {
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
+3 -5
exchanges/auth/src/authExchange.ts
···
OperationResult,
CombinedError,
Exchange,
-
TypedDocumentNode,
+
DocumentInput,
AnyVariables,
} from '@urql/core';
-
-
import { DocumentNode } from 'graphql';
/** Utilities to use while refreshing authentication tokens. */
export interface AuthUtilities {
···
* options, so you may have to pass them again, if needed.
*/
mutate<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): Promise<OperationResult<Data>>;
···
.then(() =>
init({
mutate<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): Promise<OperationResult<Data>> {
-3
exchanges/context/package.json
···
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"devDependencies": {
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
+1 -3
exchanges/graphcache/package.json
···
"prepublishOnly": "run-s clean build"
},
"dependencies": {
+
"@0no-co/graphql.web": "^1.0.0",
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
-
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
},
"devDependencies": {
"@cypress/react": "^7.0.2",
+55
exchanges/graphcache/src/ast/graphql.ts
···
+
import type * as GraphQL from 'graphql';
+
+
type OrNever<T> = 0 extends 1 & T ? never : T;
+
+
export type IntrospectionQuery =
+
| {
+
readonly __schema: {
+
queryType: { name: string; kind?: any };
+
mutationType?: { name: string; kind?: any } | null;
+
subscriptionType?: { name: string; kind?: any } | null;
+
types?: readonly IntrospectionType[];
+
};
+
}
+
| OrNever<GraphQL.IntrospectionQuery>;
+
+
export type IntrospectionTypeRef =
+
| {
+
readonly kind:
+
| 'SCALAR'
+
| 'OBJECT'
+
| 'INTERFACE'
+
| 'ENUM'
+
| 'UNION'
+
| 'INPUT_OBJECT';
+
readonly name?: string;
+
readonly ofType?: IntrospectionTypeRef;
+
}
+
| OrNever<GraphQL.IntrospectionTypeRef>;
+
+
export type IntrospectionInputTypeRef =
+
| {
+
readonly kind: 'SCALAR' | 'ENUM' | 'INPUT_OBJECT';
+
readonly name?: string;
+
readonly ofType?: IntrospectionInputTypeRef;
+
}
+
| OrNever<GraphQL.IntrospectionInputTypeRef>;
+
+
export type IntrospectionInputValue =
+
| {
+
readonly name: string;
+
readonly description?: string | null;
+
readonly defaultValue?: string | null;
+
readonly type: IntrospectionInputTypeRef;
+
}
+
| OrNever<GraphQL.IntrospectionInputValue>;
+
+
export type IntrospectionType =
+
| {
+
readonly kind: string;
+
readonly name: string;
+
readonly fields?: readonly any[];
+
readonly interfaces?: readonly any[];
+
readonly possibleTypes?: readonly any[];
+
}
+
| OrNever<GraphQL.IntrospectionType>;
+1 -1
exchanges/graphcache/src/ast/node.ts
···
FieldNode,
FragmentDefinitionNode,
Kind,
-
} from 'graphql';
+
} from '@0no-co/graphql.web';
export type SelectionSet = ReadonlyArray<SelectionNode>;
+5 -6
exchanges/graphcache/src/ast/schema.ts
···
-
import {
+
import type {
IntrospectionQuery,
-
IntrospectionSchema,
-
IntrospectionInputValue,
IntrospectionTypeRef,
+
IntrospectionInputValue,
IntrospectionType,
-
} from 'graphql';
+
} from './graphql';
export interface SchemaField {
name: string;
···
queryType: { name: string; kind?: any };
mutationType?: { name: string; kind?: any } | null;
subscriptionType?: { name: string; kind?: any } | null;
-
types?: IntrospectionSchema['types'];
+
types?: readonly any[];
}
export type IntrospectionData =
···
kind: type.kind as 'OBJECT' | 'INTERFACE',
interfaces: buildNameMap(type.interfaces || []),
fields: buildNameMap(
-
type.fields.map(field => ({
+
type.fields!.map((field: any) => ({
name: field.name,
type: field.type,
args: buildNameMap(field.args),
+4 -1
exchanges/graphcache/src/ast/schemaPredicates.ts
···
-
import { InlineFragmentNode, FragmentDefinitionNode } from 'graphql';
+
import {
+
InlineFragmentNode,
+
FragmentDefinitionNode,
+
} from '@0no-co/graphql.web';
import { warn, invariant } from '../helpers/help';
import { getTypeCondition } from './node';
+1 -1
exchanges/graphcache/src/ast/traversal.ts
···
InlineFragmentNode,
valueFromASTUntyped,
Kind,
-
} from 'graphql';
+
} from '@0no-co/graphql.web';
import { getName } from './node';
+1 -1
exchanges/graphcache/src/ast/variables.ts
···
FieldNode,
OperationDefinitionNode,
valueFromASTUntyped,
-
} from 'graphql';
+
} from '@0no-co/graphql.web';
import { getName } from './node';
+5 -1
exchanges/graphcache/src/helpers/help.ts
···
// Every warning and error comes with a number that uniquely identifies them.
// You can read more about the messages themselves in `docs/graphcache/errors.md`
-
import { Kind, ExecutableDefinitionNode, InlineFragmentNode } from 'graphql';
+
import {
+
Kind,
+
ExecutableDefinitionNode,
+
InlineFragmentNode,
+
} from '@0no-co/graphql.web';
export type ErrorCode =
| 1
+1 -1
exchanges/graphcache/src/offlineExchange.ts
···
import { pipe, merge, makeSubject, filter } from 'wonka';
-
import { SelectionNode } from 'graphql';
+
import { SelectionNode } from '@0no-co/graphql.web';
import {
Operation,
+6 -1
exchanges/graphcache/src/operations/query.ts
···
-
import { FieldNode, DocumentNode, FragmentDefinitionNode } from 'graphql';
import { CombinedError } from '@urql/core';
+
+
import {
+
FieldNode,
+
DocumentNode,
+
FragmentDefinitionNode,
+
} from '@0no-co/graphql.web';
import {
getSelectionSet,
+6 -6
exchanges/graphcache/src/operations/shared.ts
···
-
import { CombinedError } from '@urql/core';
+
import { CombinedError, ErrorLike } from '@urql/core';
+
import {
-
GraphQLError,
FieldNode,
InlineFragmentNode,
FragmentDefinitionNode,
-
} from 'graphql';
+
} from '@0no-co/graphql.web';
import {
isDeferred,
···
parentFieldKey: string;
parent: Data;
fieldName: string;
-
error: GraphQLError | undefined;
+
error: ErrorLike | undefined;
partial: boolean;
optimistic: boolean;
__internal: {
path: Array<string | number>;
-
errorMap: { [path: string]: GraphQLError } | undefined;
+
errorMap: { [path: string]: ErrorLike } | undefined;
};
}
···
export const deferRef: { current: boolean } = { current: false };
// Checks whether the current data field is a cache miss because of a GraphQLError
-
export const getFieldError = (ctx: Context): GraphQLError | undefined =>
+
export const getFieldError = (ctx: Context): ErrorLike | undefined =>
ctx.__internal.path.length > 0 && ctx.__internal.errorMap
? ctx.__internal.errorMap[ctx.__internal.path.join('.')]
: undefined;
+6 -1
exchanges/graphcache/src/operations/write.ts
···
-
import { FieldNode, DocumentNode, FragmentDefinitionNode } from 'graphql';
import { CombinedError } from '@urql/core';
+
+
import {
+
FieldNode,
+
DocumentNode,
+
FragmentDefinitionNode,
+
} from '@0no-co/graphql.web';
import {
getFragments,
+1 -1
exchanges/graphcache/src/store/store.ts
···
-
import { DocumentNode } from 'graphql';
import { TypedDocumentNode, formatDocument, createRequest } from '@urql/core';
import {
···
expectValidOptimisticMutationsConfig,
} from '../ast';
+
type DocumentNode = TypedDocumentNode<any, any>;
type RootField = 'query' | 'mutation' | 'subscription';
/** Implementation of the {@link Cache} interface as created internally by the {@link cacheExchange}.
+15 -8
exchanges/graphcache/src/types.ts
···
-
import { AnyVariables, TypedDocumentNode, RequestExtensions } from '@urql/core';
-
import { GraphQLError, DocumentNode, FragmentDefinitionNode } from 'graphql';
+
import {
+
AnyVariables,
+
DocumentInput,
+
RequestExtensions,
+
TypedDocumentNode,
+
ErrorLike,
+
} from '@urql/core';
+
+
import { FragmentDefinitionNode } from '@0no-co/graphql.web';
import { IntrospectionData } from './ast';
/** Nullable GraphQL list types of `T`.
···
* GraphQL operation: its query document and variables.
*/
export interface OperationRequest {
-
query: DocumentNode | TypedDocumentNode<any, any>;
+
query: Exclude<DocumentInput<any, any>, string>;
variables?: any;
}
···
parentFieldKey: string;
/** Current field that the resolver has been called on. */
fieldName: string;
-
/** Map of fragment definitions from the {@link DocumentNode}. */
+
/** Map of fragment definitions from the query document. */
fragments: Fragments;
/** Full original {@link Variables} object on the {@link OperationRequest}. */
variables: Variables;
···
* will be set and provided here. This can be useful to recover from an
* error on a specific field.
*/
-
error: GraphQLError | undefined;
+
error: ErrorLike | undefined;
/** Flag used to indicate whether the current GraphQL query is only partially cached.
*
* @remarks
···
* cached data, as accepted by {@link cache.readQuery}.
*/
export interface QueryInput<T = Data, V = Variables> {
-
query: string | DocumentNode | TypedDocumentNode<T, V>;
+
query: DocumentInput<T, V>;
variables?: V;
}
···
* ```
*/
readFragment<T = Data, V = Variables>(
-
fragment: DocumentNode | TypedDocumentNode<T, V>,
+
fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>,
entity: string | Data | T,
variables?: V
): T | null;
···
* ```
*/
writeFragment<T = Data, V = Variables>(
-
fragment: DocumentNode | TypedDocumentNode<T, V>,
+
fragment: TypedDocumentNode<any, any> | TypedDocumentNode<T, V>,
data: T,
variables?: V
): void;
-3
exchanges/multipart-fetch/package.json
···
"extract-files": "^11.0.0",
"wonka": "^6.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"devDependencies": {
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
-3
exchanges/persisted/package.json
···
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"devDependencies": {
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
+5 -3
exchanges/persisted/src/persistedExchange.ts
···
makeOperation,
stringifyDocument,
PersistedRequestExtensions,
+
TypedDocumentNode,
OperationResult,
CombinedError,
Exchange,
Operation,
} from '@urql/core';
-
-
import type { DocumentNode } from 'graphql';
import { hash } from './sha256';
···
* API is unavailable on React Native, which may require you to
* pass a custom function here.
*/
-
generateHash?(query: string, document: DocumentNode): Promise<string>;
+
generateHash?(
+
query: string,
+
document: TypedDocumentNode<any, any>
+
): Promise<string>;
/** Enables persisted queries to be used for mutations.
*
* @remarks
-3
exchanges/refocus/package.json
···
"@types/react": "^17.0.4",
"graphql": "^16.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"dependencies": {
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
-3
exchanges/request-policy/package.json
···
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"dependencies": {
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
-3
exchanges/retry/package.json
···
"@urql/core": "workspace:*",
"graphql": "^16.0.0"
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"dependencies": {
"@urql/core": ">=3.2.2",
"wonka": "^6.0.0"
+1
package.json
···
}
},
"devDependencies": {
+
"@0no-co/graphql.web": "^1.0.0",
"@actions/artifact": "^1.1.1",
"@actions/core": "^1.10.0",
"@babel/core": "^7.21.3",
+1 -6
packages/core/package.json
···
"prepare": "node ../../scripts/prepare/index.js",
"prepublishOnly": "run-s clean build"
},
-
"devDependencies": {
-
"graphql": "^16.0.0"
-
},
-
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
-
},
"dependencies": {
+
"@0no-co/graphql.web": "^1.0.0",
"wonka": "^6.1.2"
},
"publishConfig": {
+1 -1
packages/core/src/client.test.ts
···
-
import { print } from 'graphql';
+
import { print } from '@0no-co/graphql.web';
import { vi, expect, it, beforeEach, describe, afterEach } from 'vitest';
/** NOTE: Testing in this file is designed to test both the client and its interaction with default Exchanges */
+5 -7
packages/core/src/client.ts
···
Subscription,
} from 'wonka';
-
import { DocumentNode } from 'graphql';
-
import { composeExchanges } from './exchanges';
import { fallbackExchange } from './exchanges/fallback';
import {
-
TypedDocumentNode,
+
DocumentInput,
AnyVariables,
Exchange,
ExchangeInput,
···
* ```
*/
query<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): OperationResultSource<OperationResult<Data, Variables>>;
···
* or asynchronously.
*/
readQuery<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): OperationResult<Data, Variables> | null;
···
* ```
*/
subscription<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): OperationResultSource<OperationResult<Data, Variables>>;
···
* ```
*/
mutation<Data = any, Variables extends AnyVariables = AnyVariables>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
+
query: DocumentInput<Data, Variables>,
variables: Variables,
context?: Partial<OperationContext>
): OperationResultSource<OperationResult<Data, Variables>>;
+1 -1
packages/core/src/exchanges/ssr.ts
···
-
import { GraphQLError } from 'graphql';
+
import type { GraphQLError } from '../utils/graphql';
import { pipe, filter, merge, map, tap } from 'wonka';
import { Exchange, OperationResult, Operation } from '../types';
import { addMetadata, CombinedError } from '../utils';
+1 -1
packages/core/src/gql.test.ts
···
-
import { parse, print } from 'graphql';
+
import { parse, print } from '@0no-co/graphql.web';
import { vi, expect, it, beforeEach, SpyInstance } from 'vitest';
import { gql } from './gql';
+2 -1
packages/core/src/gql.ts
···
/* eslint-disable prefer-rest-params */
-
import { DocumentNode, DefinitionNode, Kind } from 'graphql';
+
import { Kind } from '@0no-co/graphql.web';
+
import type { DocumentNode, DefinitionNode } from './utils/graphql';
import { AnyVariables, TypedDocumentNode } from './types';
import { keyDocument, stringifyDocument } from './utils';
+19 -9
packages/core/src/types.ts
···
-
import type { GraphQLError, DocumentNode, DefinitionNode } from 'graphql';
+
import type { GraphQLError, DocumentNode } from './utils/graphql';
import { Subscription, Source } from 'wonka';
import { Client } from './client';
import { CombinedError } from './utils/error';
···
*
* @see {@link https://github.com/dotansimha/graphql-typed-document-node} for more information.
*/
-
export interface TypedDocumentNode<
+
export type TypedDocumentNode<
Result = { [key: string]: any },
Variables = { [key: string]: any }
-
> extends DocumentNode {
-
/** GraphQL.js Definition Nodes of the `DocumentNode`. */
-
readonly definitions: ReadonlyArray<DefinitionNode>;
+
> = DocumentNode & {
/** Type to support `@graphql-typed-document-node/core`
* @internal
*/
···
* @internal
*/
__ensureTypesOfVariablesAndResultMatching?: (variables: Variables) => Result;
-
}
+
};
+
+
/** Any GraphQL `DocumentNode` or query string input.
+
*
+
* @remarks
+
* Wherever any `urql` bindings or API expect a query, it accepts either a query string,
+
* a `DocumentNode`, or a {@link TypedDocumentNode}.
+
*/
+
export type DocumentInput<
+
Result = { [key: string]: any },
+
Variables = { [key: string]: any }
+
> = string | DocumentNode | TypedDocumentNode<Result, Variables>;
/** A list of errors on {@link ExecutionResult | ExecutionResults}.
* @see {@link https://spec.graphql.org/draft/#sec-Errors.Error-Result-Format} for the GraphQL Error Result format spec.
*/
-
type ErrorLike = Partial<GraphQLError> | Error;
+
export type ErrorLike = Partial<GraphQLError> | Error;
+
/** Extensions which may be placed on {@link ExecutionResult | ExecutionResults}.
* @see {@link https://spec.graphql.org/draft/#sel-EAPHJCAACCoGu9J} for the GraphQL Error Result format spec.
*/
···
Variables extends AnyVariables = AnyVariables
> =
| ({
-
query: string | DocumentNode | TypedDocumentNode<Data, Variables>;
+
query: DocumentInput<Data, Variables>;
} & (Variables extends void
? {
variables?: Variables;
···
variables?: Variables;
}))
| {
-
query: string | DocumentNode | TypedDocumentNode<Data, Variables>;
+
query: DocumentInput<Data, Variables>;
variables: Variables;
};
+3 -2
packages/core/src/utils/error.ts
···
-
import { GraphQLError } from 'graphql';
+
import { GraphQLError } from '@0no-co/graphql.web';
+
import { ErrorLike } from '../types';
const generateErrorMessage = (
networkErr?: Error,
···
constructor(input: {
networkError?: Error;
-
graphQLErrors?: Array<string | Partial<GraphQLError> | Error>;
+
graphQLErrors?: Array<string | ErrorLike>;
response?: any;
}) {
const normalizedGraphQLErrors = (input.graphQLErrors || []).map(
+16
packages/core/src/utils/graphql.ts
···
+
import type * as GraphQLWeb from '@0no-co/graphql.web';
+
import type * as GraphQL from 'graphql';
+
+
type OrNever<T> = 0 extends 1 & T ? never : T;
+
+
export type GraphQLError =
+
| GraphQLWeb.GraphQLError
+
| OrNever<GraphQL.GraphQLError>;
+
+
export type DocumentNode =
+
| GraphQLWeb.DocumentNode
+
| OrNever<GraphQL.DocumentNode>;
+
+
export type DefinitionNode =
+
| GraphQLWeb.DefinitionNode
+
| OrNever<GraphQL.DefinitionNode>;
+1 -1
packages/core/src/utils/request.test.ts
···
import { expect, it, describe } from 'vitest';
-
import { parse, print } from 'graphql';
+
import { parse, print } from '@0no-co/graphql.web';
import { gql } from '../gql';
import { createRequest, stringifyDocument } from './request';
import { formatDocument } from './typenames';
+8 -18
packages/core/src/utils/request.ts
···
-
import {
-
Location,
-
DefinitionNode,
-
DocumentNode,
-
Kind,
-
parse,
-
print,
-
} from 'graphql';
-
+
import { Kind, parse, print } from '@0no-co/graphql.web';
+
import type { DocumentNode, DefinitionNode } from './graphql';
import { HashValue, phash } from './hash';
import { stringifyVariables } from './variables';
import type {
+
DocumentInput,
TypedDocumentNode,
AnyVariables,
GraphQLRequest,
RequestExtensions,
} from '../types';
-
interface WritableLocation {
-
loc: Location | undefined;
-
}
-
/** A `DocumentNode` annotated with its hashed key.
* @internal
*/
-
export interface KeyedDocumentNode extends DocumentNode {
+
export type KeyedDocumentNode = TypedDocumentNode & {
__key: HashValue;
-
}
+
};
const SOURCE_NAME = 'gql';
const GRAPHQL_STRING_RE = /("{3}[\s\S]*"{3}|"(?:\\.|[^"])*")/g;
···
}
if (typeof node !== 'string' && !node.loc) {
-
(node as WritableLocation).loc = {
+
(node as any).loc = {
start: 0,
end: printed.length,
source: {
···
name: SOURCE_NAME,
locationOffset: { line: 1, column: 1 },
},
-
} as Location;
+
};
}
return printed;
···
Data = any,
Variables extends AnyVariables = AnyVariables
>(
-
_query: string | DocumentNode | TypedDocumentNode<Data, Variables>,
+
_query: DocumentInput<Data, Variables>,
_variables: Variables,
extensions?: RequestExtensions | undefined
): GraphQLRequest<Data, Variables> => {
+1 -1
packages/core/src/utils/typenames.test.ts
···
-
import { parse, print } from 'graphql';
+
import { parse, print } from '@0no-co/graphql.web';
import { describe, it, expect } from 'vitest';
import { collectTypesFromResponse, formatDocument } from './typenames';
import { createRequest } from './request';
+48 -36
packages/core/src/utils/typenames.ts
···
-
import {
-
DocumentNode,
-
FieldNode,
-
InlineFragmentNode,
-
Kind,
-
visit,
-
} from 'graphql';
-
+
import { Kind, SelectionNode, DefinitionNode } from '@0no-co/graphql.web';
import { KeyedDocumentNode, keyDocument } from './request';
+
import { TypedDocumentNode } from '../types';
interface EntityLike {
[key: string]: EntityLike | EntityLike[] | any;
···
...collectTypes(response as EntityLike, new Set()),
];
-
const formatNode = (node: FieldNode | InlineFragmentNode) => {
-
if (!node.selectionSet) return node;
-
for (const selection of node.selectionSet.selections)
-
if (
-
selection.kind === Kind.FIELD &&
-
selection.name.value === '__typename' &&
-
!selection.alias
-
)
-
return node;
+
const formatNode = <
+
T extends SelectionNode | DefinitionNode | TypedDocumentNode<any, any>
+
>(
+
node: T
+
): T => {
+
let hasChanged = false;
-
return {
-
...node,
-
selectionSet: {
-
...node.selectionSet,
-
selections: [
-
...node.selectionSet.selections,
-
{
+
if ('definitions' in node) {
+
const definitions: DefinitionNode[] = [];
+
for (const definition of node.definitions) {
+
const newDefinition = formatNode(definition);
+
hasChanged = hasChanged || newDefinition !== definition;
+
definitions.push(newDefinition);
+
}
+
if (hasChanged) return { ...node, definitions };
+
} else if ('selectionSet' in node) {
+
const selections: SelectionNode[] = [];
+
let hasTypename = node.kind === Kind.OPERATION_DEFINITION;
+
if (node.selectionSet) {
+
for (const selection of node.selectionSet.selections || []) {
+
hasTypename =
+
hasTypename ||
+
(selection.kind === Kind.FIELD &&
+
selection.name.value === '__typename' &&
+
!selection.alias);
+
const newSelection = formatNode(selection);
+
hasChanged = hasChanged || newSelection !== selection;
+
selections.push(newSelection);
+
}
+
if (!hasTypename) {
+
hasChanged = true;
+
selections.push({
kind: Kind.FIELD,
name: {
kind: Kind.NAME,
value: '__typename',
},
-
},
-
],
-
},
-
};
+
});
+
}
+
if (hasChanged)
+
return { ...node, selectionSet: { ...node.selectionSet, selections } };
+
}
+
}
+
+
return node;
};
const formattedDocs = new Map<number, KeyedDocumentNode>();
···
* @see {@link https://spec.graphql.org/October2021/#sec-Type-Name-Introspection} for more information
* on typename introspection via the `__typename` field.
*/
-
export const formatDocument = <T extends DocumentNode>(node: T): T => {
+
export const formatDocument = <T extends TypedDocumentNode<any, any>>(
+
node: T
+
): T => {
const query = keyDocument(node);
let result = formattedDocs.get(query.__key);
if (!result) {
-
result = visit(query, {
-
Field: formatNode,
-
InlineFragment: formatNode,
-
}) as KeyedDocumentNode;
-
+
formattedDocs.set(
+
query.__key,
+
(result = formatNode(query) as KeyedDocumentNode)
+
);
// Ensure that the hash of the resulting document won't suddenly change
// we are marking __key as non-enumerable so when external exchanges use visit
// to manipulate a document we won't restore the previous query due to the __key
···
value: query.__key,
enumerable: false,
});
-
-
formattedDocs.set(query.__key, result);
}
return result as unknown as T;
-1
packages/preact-urql/package.json
···
"preact": "^10.13.0"
},
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"preact": ">= 10.0.0"
},
"dependencies": {
+2 -3
packages/preact-urql/src/components/Mutation.ts
···
import { VNode } from 'preact';
-
import { DocumentNode } from 'graphql';
-
import { AnyVariables, TypedDocumentNode } from '@urql/core';
+
import { AnyVariables, DocumentInput } from '@urql/core';
import { useMutation, UseMutationState, UseMutationExecute } from '../hooks';
···
Variables extends AnyVariables = AnyVariables
> {
/* The GraphQL mutation document that {@link useMutation} will execute. */
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string;
+
query: DocumentInput<Data, Variables>;
children(arg: MutationState<Data, Variables>): VNode<any>;
}
+2 -5
packages/preact-urql/src/hooks/useMutation.ts
···
-
import { DocumentNode } from 'graphql';
import { useState, useCallback, useRef, useEffect } from 'preact/hooks';
import { pipe, toPromise } from 'wonka';
import {
AnyVariables,
-
TypedDocumentNode,
+
DocumentInput,
OperationResult,
OperationContext,
CombinedError,
···
export function useMutation<
Data = any,
Variables extends AnyVariables = AnyVariables
-
>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string
-
): UseMutationResponse<Data, Variables> {
+
>(query: DocumentInput<Data, Variables>): UseMutationResponse<Data, Variables> {
const isMounted = useRef(true);
const client = useClient();
-1
packages/react-urql/package.json
···
"vite": "^3.2.4"
},
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"react": ">= 16.8.0"
},
"dependencies": {
+2 -3
packages/react-urql/src/components/Mutation.ts
···
-
import { DocumentNode } from 'graphql';
import { ReactElement } from 'react';
-
import { AnyVariables, TypedDocumentNode } from '@urql/core';
+
import { AnyVariables, DocumentInput } from '@urql/core';
import { useMutation, UseMutationState, UseMutationExecute } from '../hooks';
···
Variables extends AnyVariables = AnyVariables
> {
/* The GraphQL mutation document that {@link useMutation} will execute. */
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string;
+
query: DocumentInput<Data, Variables>;
children(arg: MutationState<Data, Variables>): ReactElement<any>;
}
+2 -5
packages/react-urql/src/hooks/useMutation.ts
···
-
import { DocumentNode } from 'graphql';
import { useState, useCallback, useRef, useEffect } from 'react';
import { pipe, toPromise } from 'wonka';
import {
AnyVariables,
-
TypedDocumentNode,
+
DocumentInput,
OperationResult,
OperationContext,
CombinedError,
···
export function useMutation<
Data = any,
Variables extends AnyVariables = AnyVariables
-
>(
-
query: DocumentNode | TypedDocumentNode<Data, Variables> | string
-
): UseMutationResponse<Data, Variables> {
+
>(query: DocumentInput<Data, Variables>): UseMutationResponse<Data, Variables> {
const isMounted = useRef(true);
const client = useClient();
+2 -3
packages/react-urql/src/hooks/useRequest.ts
···
-
import { DocumentNode } from 'graphql';
import { useRef, useMemo } from 'react';
import {
AnyVariables,
-
TypedDocumentNode,
+
DocumentInput,
GraphQLRequest,
createRequest,
} from '@urql/core';
···
Data = any,
Variables extends AnyVariables = AnyVariables
>(
-
query: string | DocumentNode | TypedDocumentNode<Data, Variables>,
+
query: DocumentInput<Data, Variables>,
variables: Variables
): GraphQLRequest<Data, Variables> {
const prev = useRef<undefined | GraphQLRequest<Data, Variables>>(undefined);
-1
packages/svelte-urql/package.json
···
"prepublishOnly": "run-s clean build"
},
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"svelte": "^3.0.0"
},
"dependencies": {
-1
packages/vue-urql/package.json
···
"vue": "^3.2.47"
},
"peerDependencies": {
-
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
"vue": "^2.7.0 || ^3.0.0"
},
"dependencies": {
+25 -4
pnpm-lock.yaml
···
.:
specifiers:
+
'@0no-co/graphql.web': ^1.0.0
'@actions/artifact': ^1.1.1
'@actions/core': ^1.10.0
'@actions/github': ^5.1.1
···
'@actions/github': 5.1.1
node-fetch: 3.3.1
devDependencies:
+
'@0no-co/graphql.web': 1.0.0_graphql@16.6.0
'@actions/artifact': 1.1.1
'@actions/core': 1.10.0
'@babel/core': 7.21.3
···
exchanges/graphcache:
specifiers:
+
'@0no-co/graphql.web': ^1.0.0
'@cypress/react': ^7.0.2
'@urql/core': '>=3.2.2'
'@urql/exchange-execute': workspace:*
···
urql: workspace:*
wonka: ^6.2.4
dependencies:
+
'@0no-co/graphql.web': 1.0.0_graphql@16.6.0
'@urql/core': link:../../packages/core
wonka: 6.2.4
devDependencies:
···
packages/core:
specifiers:
-
graphql: ^16.6.0
+
'@0no-co/graphql.web': ^1.0.0
wonka: ^6.2.4
dependencies:
+
'@0no-co/graphql.web': 1.0.0
wonka: 6.2.4
-
devDependencies:
-
graphql: 16.6.0
packages/introspection:
specifiers:
···
vue: 3.2.47
packages:
+
+
/@0no-co/graphql.web/1.0.0:
+
resolution: {integrity: sha512-JBq2pWyDchE1vVjj/+c4dzZ8stbpew4RrzpZ3vYdn1WJFGHfYg6YIX1fDdMKtSXJJM9FUlsoDOxemr9WMM2p+A==}
+
peerDependencies:
+
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
+
peerDependenciesMeta:
+
graphql:
+
optional: true
+
dev: false
+
+
/@0no-co/graphql.web/1.0.0_graphql@16.6.0:
+
resolution: {integrity: sha512-JBq2pWyDchE1vVjj/+c4dzZ8stbpew4RrzpZ3vYdn1WJFGHfYg6YIX1fDdMKtSXJJM9FUlsoDOxemr9WMM2p+A==}
+
peerDependencies:
+
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
+
peerDependenciesMeta:
+
graphql:
+
optional: true
+
dependencies:
+
graphql: 16.6.0
/@actions/artifact/1.1.1:
resolution: {integrity: sha512-Vv4y0EW0ptEkU+Pjs5RGS/0EryTvI6s79LjSV9Gg/h+O3H/ddpjhuX/Bi/HZE4pbNPyjGtQjbdFWphkZhmgabA==}
···
/graphql/16.6.0:
resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
-
dev: true
/gud/1.0.0:
resolution: {integrity: sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==}
+4 -1
scripts/rollup/cleanup-plugin.mjs
···
function cleanup() {
const emptyImportRe = /import\s+(?:'[^']+'|"[^"]+")\s*;?/g;
+
const gqlImportRe = /(import\s+(?:[*\s{}\w\d]+)\s*from\s*'graphql';?)/g;
const jsFilter = createFilter(/.m?js$/, null, { resolve: false });
const dtsFilter = createFilter(/\.d\.ts(\.map)?$/, null, { resolve: false });
···
babelrc: false
});
} else if (dtsFilter(chunk.fileName)) {
-
return code.replace(emptyImportRe, '');
+
return code
+
.replace(emptyImportRe, '')
+
.replace(gqlImportRe, x => '/*!@ts-ignore*/\n' + x);
}
},
};