Skip to content

Commit

Permalink
Handle duplicate args definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
captbaritone committed Aug 11, 2024
1 parent a5c0ec2 commit 5853543
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 35 deletions.
4 changes: 2 additions & 2 deletions src/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ export function resolverParamIsMissingType() {
return "Missing type annotation for resolver argument. Expected all resolver arguments to have an explicit type annotation. Grats needs to be able to see the type of the arguments to generate an executable GraphQL schema.";
}

export function argumentParamIsNotObject() {
return "Expected GraphQL field arguments to be typed using an inline literal object: `{someField: string}`. If there are no arguments, you can use `args: unknown`. Grats needs to be able to see the type of the arguments to generate a GraphQL schema.";
export function multipleResolverTypeLiterals() {
return "Unexpected multiple resolver parameters typed with an object literal. Grats assumes a resolver parameter typed with object literals describes the GraphQL arguments. Therefore only one such parameter is permitted.";
}

export function argIsNotProperty() {
Expand Down
56 changes: 23 additions & 33 deletions src/Extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1359,34 +1359,8 @@ class Extractor {
}

collectArgs(
argsParam: ts.ParameterDeclaration,
): ReadonlyArray<InputValueDefinitionNode> | null {
const args: InputValueDefinitionNode[] = [];

const argsType = argsParam.type;
if (argsType == null) {
return this.report(argsParam, E.resolverParamIsMissingType());
}
if (argsType.kind === ts.SyntaxKind.UnknownKeyword) {
return [];
}
if (!ts.isTypeLiteralNode(argsType)) {
return this.report(argsType, E.argumentParamIsNotObject());
}

let defaults: ArgDefaults | null = null;
if (ts.isObjectBindingPattern(argsParam.name)) {
defaults = this.collectArgDefaults(argsParam.name);
}

for (const member of argsType.members) {
const arg = this.collectArg(member, defaults);
if (arg != null) {
args.push(arg);
}
}
return args;
}
argsType: ts.TypeLiteralNode,
): ReadonlyArray<InputValueDefinitionNode> | null {}

collectArgDefaults(node: ts.ObjectBindingPattern): ArgDefaults {
const defaults = new Map();
Expand Down Expand Up @@ -1843,7 +1817,10 @@ class Extractor {
} | null {
const resolverParams: UnresolvedResolverParam[] = [];

let args: readonly InputValueDefinitionNode[] | null = null;
let args: {
param: ts.ParameterDeclaration;
inputs: InputValueDefinitionNode[];
} | null = null;

for (const param of parameters) {
if (param.dotDotDotToken != null) {
Expand All @@ -1857,11 +1834,24 @@ class Extractor {
}
if (ts.isTypeLiteralNode(param.type)) {
if (args != null) {
// FIXME
return this.report(param, "Unexpected second argument.");
return this.report(param, E.multipleResolverTypeLiterals(), [
tsRelated(args.param, "Previous type literal"),
]);
}
resolverParams.push({ kind: "named", name: "args" });
args = this.collectArgs(param);
args = { param, inputs: [] };

let defaults: ArgDefaults | null = null;
if (ts.isObjectBindingPattern(param.name)) {
defaults = this.collectArgDefaults(param.name);
}

for (const member of param.type.members) {
const arg = this.collectArg(member, defaults);
if (arg != null) {
args.inputs.push(arg);
}
}
continue;
}
if (ts.isTypeReferenceNode(param.type)) {
Expand All @@ -1885,7 +1875,7 @@ class Extractor {
}
return this.report(param.type, E.unexpectedResolverParamType());
}
return { resolverParams, args };
return { resolverParams, args: args ? args.inputs : null };
}

modifiersAreValidForField(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @gqlType */
export default class SomeType {
/** @gqlField */
hello(args: { greeting: string }, alsoArgs: { farewell: string }): string {
return "Hello world!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----------------
INPUT
-----------------
/** @gqlType */
export default class SomeType {
/** @gqlField */
hello(args: { greeting: string }, alsoArgs: { farewell: string }): string {
return "Hello world!";
}
}

-----------------
OUTPUT
-----------------
src/tests/fixtures/arguments/MultipleParamsTypedAsTypeLiteral.ts:4:37 - error: Unexpected multiple resolver parameters typed with an object literal. Grats assumes a resolver parameter typed with object literals describes the GraphQL arguments. Therefore only one such parameter is permitted.

4 hello(args: { greeting: string }, alsoArgs: { farewell: string }): string {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/tests/fixtures/arguments/MultipleParamsTypedAsTypeLiteral.ts:4:9
4 hello(args: { greeting: string }, alsoArgs: { farewell: string }): string {
~~~~~~~~~~~~~~~~~~~~~~~~~~
Previous type literal

0 comments on commit 5853543

Please sign in to comment.