Skip to content

Commit

Permalink
Vendor printer & keep fragments in sent query
Browse files Browse the repository at this point in the history
  • Loading branch information
bloodyowl committed Mar 22, 2024
1 parent 8a13d89 commit 1225c4d
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 2 deletions.
19 changes: 17 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@swan-io/request";
import { ClientCache } from "./cache/cache";
import { TypedDocumentNode } from "./types";
import { DocumentNode, GraphQLError, print } from "@0no-co/graphql.web";
import { DocumentNode, GraphQLError } from "@0no-co/graphql.web";
import {
addTypenames,
getExecutableOperationName,
Expand All @@ -24,6 +24,7 @@ import {
} from "./errors";
import { writeOperationToCache } from "./cache/write";
import { readOperationFromCache } from "./cache/read";
import { print } from "./graphql/print";

type RequestConfig = {
url: string;
Expand Down Expand Up @@ -94,6 +95,7 @@ export class Client {
subscribers: Set<() => void>;

transformedDocuments: Map<DocumentNode, DocumentNode>;
transformedDocumentsForRequest: Map<DocumentNode, DocumentNode>;

constructor(config: ClientConfig) {
this.url = config.url;
Expand All @@ -103,6 +105,7 @@ export class Client {
this.parseResponse = config.parseResponse ?? defaultParseResponse;
this.subscribers = new Set();
this.transformedDocuments = new Map();
this.transformedDocumentsForRequest = new Map();
}

getTransformedDocument(document: DocumentNode) {
Expand All @@ -115,6 +118,16 @@ export class Client {
}
}

getTransformedDocumentsForRequest(document: DocumentNode) {
if (this.transformedDocumentsForRequest.has(document)) {
return this.transformedDocumentsForRequest.get(document) as DocumentNode;
} else {
const transformedDocument = addTypenames(document);
this.transformedDocumentsForRequest.set(document, transformedDocument);
return transformedDocument;
}
}

subscribe(func: () => void) {
this.subscribers.add(func);
return () => this.subscribers.delete(func);
Expand All @@ -125,6 +138,8 @@ export class Client {
variables: Variables
) {
const transformedDocument = this.getTransformedDocument(document);
const transformedDocumentsForRequest =
this.getTransformedDocumentsForRequest(document);

const operationName =
getExecutableOperationName(transformedDocument).getWithDefault(
Expand All @@ -137,7 +152,7 @@ export class Client {
url: this.url,
headers: this.headers,
operationName,
document: transformedDocument,
document: transformedDocumentsForRequest,
variables: variablesAsRecord,
})
.mapOkToResult(this.parseResponse)
Expand Down
148 changes: 148 additions & 0 deletions src/graphql/print.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { ASTNode } from "@0no-co/graphql.web";

export const printString = (string: string) => {
return JSON.stringify(string);
};

export const printBlockString = (string: string) => {
return '"""' + string.replace(/"""/g, '\\"""') + '"""';
};

const hasItems = <T>(
array: ReadonlyArray<T> | undefined | null
): array is ReadonlyArray<T> => !!(array && array.length);

const MAX_LINE_LENGTH = 80;

const nodes: {
[NodeT in ASTNode as NodeT["kind"]]?: (node: NodeT) => string;
} = {
OperationDefinition(node) {
if (
node.operation === "query" &&
!node.name &&
!hasItems(node.variableDefinitions) &&
!hasItems(node.directives)
) {
return nodes.SelectionSet!(node.selectionSet);
}
let out: string = node.operation;
if (node.name) out += " " + node.name.value;
if (hasItems(node.variableDefinitions)) {
if (!node.name) out += " ";
out +=
"(" +
node.variableDefinitions.map(nodes.VariableDefinition!).join(", ") +
")";
}
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return out + " " + nodes.SelectionSet!(node.selectionSet);
},
VariableDefinition(node) {
let out = nodes.Variable!(node.variable) + ": " + print(node.type);
if (node.defaultValue) out += " = " + print(node.defaultValue);
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return out;
},
Field(node) {
let out = (node.alias ? node.alias.value + ": " : "") + node.name.value;
if (hasItems(node.arguments)) {
const args = node.arguments.map(nodes.Argument!);
const argsLine = out + "(" + args.join(", ") + ")";
out =
argsLine.length > MAX_LINE_LENGTH
? out + "(" + args.join(" ") + ")"
: argsLine;
}
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return node.selectionSet
? out + " " + nodes.SelectionSet!(node.selectionSet)
: out;
},
StringValue(node) {
return node.block ? printBlockString(node.value) : printString(node.value);
},
BooleanValue(node) {
return "" + node.value;
},
NullValue(_node) {
return "null";
},
IntValue(node) {
return node.value;
},
FloatValue(node) {
return node.value;
},
EnumValue(node) {
return node.value;
},
Name(node) {
return node.value;
},
Variable(node) {
return "$" + node.name.value;
},
ListValue(node) {
return "[" + node.values.map(print).join(", ") + "]";
},
ObjectValue(node) {
return "{" + node.fields.map(nodes.ObjectField!).join(", ") + "}";
},
ObjectField(node) {
return node.name.value + ": " + print(node.value);
},
Document(node) {
return hasItems(node.definitions)
? node.definitions.map(print).join(" ")
: "";
},
SelectionSet(node) {
return "{" + node.selections.map(print).join(" ") + "}";
},
Argument(node) {
return node.name.value + ": " + print(node.value);
},
FragmentSpread(node) {
let out = "..." + node.name.value;
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return out;
},
InlineFragment(node) {
let out = "...";
if (node.typeCondition) out += " on " + node.typeCondition.name.value;
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return out + " " + print(node.selectionSet);
},
FragmentDefinition(node) {
let out = "fragment " + node.name.value;
out += " on " + node.typeCondition.name.value;
if (hasItems(node.directives))
out += " " + node.directives.map(nodes.Directive!).join(" ");
return out + " " + print(node.selectionSet);
},
Directive(node) {
let out = "@" + node.name.value;
if (hasItems(node.arguments))
out += "(" + node.arguments.map(nodes.Argument!).join(", ") + ")";
return out;
},
NamedType(node) {
return node.name.value;
},
ListType(node) {
return "[" + print(node.type) + "]";
},
NonNullType(node) {
return print(node.type) + "!";
},
};

export const print = (node: ASTNode): string => {
return nodes[node.kind] ? (nodes as any)[node.kind]!(node) : "";
};

0 comments on commit 1225c4d

Please sign in to comment.