Skip to content

Commit ecfdebf

Browse files
committed
Add @semanticNonNull support
1 parent b674bc5 commit ecfdebf

File tree

1 file changed

+60
-13
lines changed

1 file changed

+60
-13
lines changed

src/cli.ts

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
GraphQLSemanticNonNull,
1212
GraphQLType,
1313
GraphQLUnionType,
14+
Kind,
1415
printSchema,
1516
validateSchema,
1617
} from "graphql";
@@ -59,6 +60,7 @@ export async function main(toStrict = false) {
5960
types: config.types
6061
.filter((t) => !t.name.startsWith("__"))
6162
.map((t) => convertType(t)),
63+
directives: config.directives.filter((d) => d.name !== "semanticNonNull"),
6264
});
6365

6466
const newSdl = printSchema(derivedSchema);
@@ -72,13 +74,33 @@ function makeConvertType(toStrict: boolean) {
7274
function convertFields(fields: GraphQLFieldConfigMap<any, any>) {
7375
return () => {
7476
return Object.fromEntries(
75-
Object.entries(fields).map(([fieldName, spec]) => [
76-
fieldName,
77-
{
78-
...spec,
79-
type: convertType(spec.type),
80-
},
81-
]),
77+
Object.entries(fields).map(([fieldName, spec]) => {
78+
const directive = spec.astNode?.directives?.find(
79+
(d) => d.name.value === "semanticNonNull",
80+
);
81+
const levelsArg = directive?.arguments?.find(
82+
(a) => a.name.value === "levels",
83+
);
84+
const levels =
85+
levelsArg?.value?.kind === Kind.LIST
86+
? levelsArg.value.values
87+
.filter((v) => v.kind === Kind.INT)
88+
.map((v) => Number(v.value))
89+
: [0];
90+
return [
91+
fieldName,
92+
{
93+
...spec,
94+
type: convertType(spec.type, directive ? levels : undefined),
95+
astNode: spec.astNode && {
96+
...spec.astNode,
97+
directives: spec.astNode?.directives?.filter(
98+
(d) => d.name.value !== "semanticNonNull",
99+
),
100+
},
101+
},
102+
];
103+
}),
82104
) as any;
83105
};
84106
}
@@ -102,14 +124,30 @@ function makeConvertType(toStrict: boolean) {
102124
return () => types.map((t) => convertType(t));
103125
}
104126

105-
function convertType(type: null | undefined): null | undefined;
106-
function convertType(type: GraphQLObjectType): GraphQLObjectType;
127+
function convertType(
128+
type: null | undefined,
129+
semanticNonNullLevels?: number[],
130+
): null | undefined;
131+
function convertType(
132+
type: GraphQLObjectType,
133+
semanticNonNullLevels?: number[],
134+
): GraphQLObjectType;
107135
function convertType(
108136
type: Maybe<GraphQLObjectType>,
137+
semanticNonNullLevels?: number[],
109138
): Maybe<GraphQLObjectType>;
110-
function convertType(type: GraphQLNamedType): GraphQLNamedType;
111-
function convertType(type: GraphQLType): GraphQLType;
112-
function convertType(type: GraphQLType | null | undefined) {
139+
function convertType(
140+
type: GraphQLNamedType,
141+
semanticNonNullLevels?: number[],
142+
): GraphQLNamedType;
143+
function convertType(
144+
type: GraphQLType,
145+
semanticNonNullLevels?: number[],
146+
): GraphQLType;
147+
function convertType(
148+
type: GraphQLType | null | undefined,
149+
semanticNonNullLevels?: number[],
150+
) {
113151
if (!type) return type;
114152
if (type instanceof GraphQLSemanticNonNull) {
115153
const unwrapped = convertType(type.ofType);
@@ -122,7 +160,16 @@ function makeConvertType(toStrict: boolean) {
122160
} else if (type instanceof GraphQLNonNull) {
123161
return new GraphQLNonNull(convertType(type.ofType));
124162
} else if (type instanceof GraphQLList) {
125-
return new GraphQLList(convertType(type.ofType));
163+
const innerLevels = semanticNonNullLevels?.includes(1) ? [0] : undefined;
164+
if (semanticNonNullLevels?.includes(0) && toStrict) {
165+
return new GraphQLNonNull(
166+
new GraphQLList(convertType(type.ofType, innerLevels)),
167+
);
168+
} else {
169+
return new GraphQLList(convertType(type.ofType, innerLevels));
170+
}
171+
} else if (semanticNonNullLevels?.includes(0) && toStrict) {
172+
return new GraphQLNonNull(convertType(type));
126173
}
127174
if (type.name.startsWith("__")) {
128175
return null;

0 commit comments

Comments
 (0)