Skip to content

Commit efe99f9

Browse files
authored
feat: support fine-grained directive replacements (#30)
1 parent c6f4184 commit efe99f9

File tree

5 files changed

+76
-5
lines changed

5 files changed

+76
-5
lines changed

src/config.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@ See the License for the specific language governing permissions and
1111
limitations under the License.
1212
*/
1313

14-
import { array, boolean, enum_, object, optional, string } from "valibot";
14+
import {
15+
array,
16+
boolean,
17+
enum_,
18+
object,
19+
optional,
20+
string,
21+
union,
22+
} from "valibot";
1523
import { Kind } from "graphql";
1624

1725
export const configSchema = object({
@@ -70,7 +78,22 @@ export const configSchema = object({
7078
/**
7179
* A list of Kotlin annotations to replace the directive with.
7280
*/
73-
kotlinAnnotations: array(string()),
81+
kotlinAnnotations: array(
82+
union([
83+
string(),
84+
object({
85+
/**
86+
* The name of the annotation to replace the directive with.
87+
*/
88+
annotationName: string(),
89+
/**
90+
* The arguments to forward from the directive directly to the Kotlin annotation. Can be INT, FLOAT, STRING, BOOLEAN, or ENUM.
91+
* @example @YourGraphQLDirective(arg1: "value1") -> @YourKotlinAnnotation(arg1 = "value1")
92+
*/
93+
argumentsToRetain: array(string()),
94+
}),
95+
]),
96+
),
7497
/**
7598
* The type definition to apply the directive replacement to. If omitted, the replacement will apply to all definition types.
7699
*/

src/helpers/build-directive-annotations.ts

+39-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ See the License for the specific language governing permissions and
1111
limitations under the License.
1212
*/
1313

14-
import { CodegenConfig } from "../plugin";
14+
import { CodegenConfig, GraphQLKotlinCodegenConfig } from "../plugin";
1515
import { DefinitionNode, isDeprecatedDescription } from "./build-annotations";
1616
import { getFederationDirectiveReplacement } from "./get-federation-directive-replacement";
1717
import { TypeMetadata } from "./build-type-metadata";
18+
import { ConstDirectiveNode } from "graphql/language";
1819

1920
export function buildDirectiveAnnotations(
2021
incomingNode: DefinitionNode,
@@ -57,7 +58,43 @@ export function buildDirectiveAnnotations(
5758
(!definitionType || definitionType === kind),
5859
);
5960
if (!directiveReplacementFromConfig) return "";
60-
return directiveReplacementFromConfig.kotlinAnnotations.join("\n") + "\n";
61+
const kotlinAnnotations = buildKotlinAnnotations(
62+
directive,
63+
directiveReplacementFromConfig.kotlinAnnotations,
64+
);
65+
return kotlinAnnotations.join("\n") + "\n";
6166
})
6267
.join("");
6368
}
69+
70+
function buildKotlinAnnotations(
71+
directive: ConstDirectiveNode,
72+
kotlinAnnotations: NonNullable<
73+
GraphQLKotlinCodegenConfig["directiveReplacements"]
74+
>[number]["kotlinAnnotations"],
75+
) {
76+
return kotlinAnnotations.map((kotlinAnnotation) => {
77+
if (typeof kotlinAnnotation === "string") return kotlinAnnotation;
78+
const directiveArguments = kotlinAnnotation.argumentsToRetain
79+
?.map((argumentToRetain) => {
80+
const argumentValueNode = directive.arguments?.find(
81+
(argument) => argument.name.value === argumentToRetain,
82+
)?.value;
83+
if (!argumentValueNode)
84+
throw new Error(
85+
`Argument ${argumentToRetain} was provided in argumentsToRetain config but was not found in directive ${directive.name.value}`,
86+
);
87+
if (!("value" in argumentValueNode))
88+
throw new Error(
89+
`Directive argument ${argumentToRetain} in directive ${directive.name.value} has an unsupported type. Only INT, FLOAT, STRING, BOOLEAN, and ENUM are supported.`,
90+
);
91+
const argumentValue =
92+
argumentValueNode.kind === "StringValue"
93+
? `"${argumentValueNode.value}"`
94+
: argumentValueNode.value;
95+
return `${argumentToRetain} = ${argumentValue}`;
96+
})
97+
.join(", ");
98+
return `@${kotlinAnnotation.annotationName}(${directiveArguments})`;
99+
});
100+
}

test/unit/should_honor_directiveReplacements_config/codegen.config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,14 @@ export default {
66
directive: "directive1",
77
kotlinAnnotations: ["@SomeAnnotation1", "@SomeAnnotation2"],
88
},
9+
{
10+
directive: "directiveWithArgs",
11+
kotlinAnnotations: [
12+
{
13+
annotationName: "SomeAnnotation3",
14+
argumentsToRetain: ["arg1", "arg2"],
15+
},
16+
],
17+
},
918
],
1019
} satisfies GraphQLKotlinCodegenConfig;

test/unit/should_honor_directiveReplacements_config/expected.kt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.expediagroup.graphql.generator.annotations.*
55
@GraphQLDescription("A description for MyDirectiveType")
66
@SomeAnnotation1
77
@SomeAnnotation2
8+
@SomeAnnotation3(arg1 = "arg1", arg2 = 0)
89
data class MyDirectiveType(
910
val field: String? = null
1011
)

test/unit/should_honor_directiveReplacements_config/schema.graphql

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
directive @directive1 on OBJECT | UNION
2+
directive @directiveWithArgs(arg1: String, arg2: Int) on OBJECT | UNION
23

34
"A description for MyDirectiveType"
4-
type MyDirectiveType @directive1 {
5+
type MyDirectiveType @directive1 @directiveWithArgs(arg1: "arg1", arg2: 0) {
56
field: String
67
}
78

0 commit comments

Comments
 (0)