Skip to content

Commit d4b85b8

Browse files
authored
Merge pull request #250 from proto-graphql/izumin5210/input-type-ignore
feat: support (graphql.input_type).ignore option
2 parents dd566e3 + 6978804 commit d4b85b8

File tree

12 files changed

+254
-37
lines changed

12 files changed

+254
-37
lines changed

.changeset/curly-moose-applaud.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@proto-graphql/codegen-core": patch
3+
"@testapis/proto": patch
4+
"protoc-gen-nexus": patch
5+
"protoc-gen-pothos": patch
6+
---
7+
8+
support `(graphql.input_type).ignore` option

e2e/tests/nexus--extensions--google-protobuf/__generated__/schema.graphql

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/tests/nexus--extensions--protobufjs/__generated__/schema.graphql

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/tests/pothos--extensions--ts-proto/__generated__/schema.graphql

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@proto-graphql/codegen-core/src/types/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { TypeOptions } from "./options";
1919
import {
2020
exceptRequestOrResponse,
2121
isIgnoredField,
22+
isIgnoredInputType,
2223
isIgnoredType,
2324
isInterface,
2425
isScalar,
@@ -70,7 +71,7 @@ function buildInputObjectTypes(
7071
registry: ProtoRegistry
7172
): InputObjectType[] {
7273
return msgs
73-
.filter((m) => !isIgnoredType(m))
74+
.filter((m) => !isIgnoredInputType(m))
7475
.filter(exceptRequestOrResponse(registry))
7576
.map((m) => new InputObjectType(m, options))
7677
.flatMap((t) =>

packages/@proto-graphql/codegen-core/src/types/util.ts

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,14 @@ function nameWithParent(typ: ProtoMessage | ProtoOneof | ProtoEnum): string {
2828
if (t.kind === "File") break;
2929
let override: string | undefined;
3030
if (t.kind === "Message") {
31-
override = t.descriptor
32-
.getOptions()
33-
?.getExtension(extensions.objectType)
34-
?.getName();
31+
override = getExtension(t, "objectType")?.getName();
3532
}
3633
name = `${
3734
t.kind === "Oneof" ? pascalCase(t.name) : override || t.name
3835
}${name}`;
3936
t = t.parent;
4037
}
41-
const prefix = t.descriptor
42-
.getOptions()
43-
?.getExtension(extensions.schema)
44-
?.getTypePrefix();
38+
const prefix = getExtension(t, "schema")?.getTypePrefix();
4539
if (prefix) {
4640
name = `${prefix}${name}`;
4741
}
@@ -115,7 +109,7 @@ export function exceptRequestOrResponse(
115109
}
116110

117111
return (m) => {
118-
const ext = m.file.descriptor.getOptions()?.getExtension(extensions.schema);
112+
const ext = getExtension(m.file, "schema");
119113

120114
if (ext?.getIgnoreRequests() && reqSet.has(m.fullName.toString()))
121115
return false;
@@ -127,42 +121,34 @@ export function exceptRequestOrResponse(
127121
}
128122

129123
export function isIgnoredType(type: ProtoMessage | ProtoEnum): boolean {
130-
let ext: ExtensionFieldInfo<{ getIgnore(): boolean }>;
131-
if (
132-
type.file.descriptor
133-
.getOptions()
134-
?.getExtension(extensions.schema)
135-
?.getIgnore()
136-
) {
124+
let ext: { getIgnore(): boolean } | undefined;
125+
if (getExtension(type.file, "schema")?.getIgnore()) {
137126
return true;
138127
}
139128
if (type.kind === "Message") {
140-
ext = extensions.objectType;
129+
ext = getExtension(type, "objectType");
141130
} else if (type.kind === "Enum") {
142-
ext = extensions.enumType;
131+
ext = getExtension(type, "enumType");
143132
} else {
144133
const _exhaustiveCheck: never = type;
145134
throw "unreachable";
146135
}
147-
return type.descriptor.getOptions()?.getExtension(ext)?.getIgnore() ?? false;
136+
return ext?.getIgnore() ?? false;
148137
}
149138

150-
export function isInterface(m: ProtoMessage): boolean {
139+
export function isIgnoredInputType(type: ProtoMessage): boolean {
151140
return (
152-
m.descriptor
153-
.getOptions()
154-
?.getExtension(extensions.objectType)
155-
?.getInterface() ?? false
141+
isIgnoredType(type) ||
142+
(getExtension(type, "inputType")?.getIgnore() ?? false)
156143
);
157144
}
158145

146+
export function isInterface(m: ProtoMessage): boolean {
147+
return getExtension(m, "objectType")?.getInterface() ?? false;
148+
}
149+
159150
export function isSquashedUnion(m: ProtoMessage): boolean {
160-
return (
161-
m.descriptor
162-
.getOptions()
163-
?.getExtension(extensions.objectType)
164-
?.getSquashUnion() ?? false
165-
);
151+
return getExtension(m, "objectType")?.getSquashUnion() ?? false;
166152
}
167153

168154
export function isScalar(m: ProtoMessage, opts: TypeOptions): boolean {
@@ -177,7 +163,7 @@ export function isRequiredField(
177163
let nullability:
178164
| extensions.NullabilityMap[keyof extensions.NullabilityMap]
179165
| null = null;
180-
const ext = field.descriptor.getOptions()?.getExtension(extensions.field);
166+
const ext = getExtension(field, "field");
181167
if (ext != null) {
182168
switch (fieldType) {
183169
case "output": {
@@ -243,7 +229,7 @@ export function isInputOnlyField(field: ProtoField | ProtoOneof): boolean {
243229
export function isIgnoredField(
244230
field: ProtoField | ProtoEnumValue | ProtoOneof
245231
): boolean {
246-
let ext: ExtensionFieldInfo<{ getIgnore(): boolean }>;
232+
let ext: { getIgnore(): boolean } | undefined;
247233
if (field.kind === "Field") {
248234
if (
249235
field.type &&
@@ -256,19 +242,19 @@ export function isIgnoredField(
256242
if (oneof && isIgnoredField(oneof)) {
257243
return true;
258244
}
259-
ext = extensions.field;
245+
ext = getExtension(field, "field");
260246
} else if (field.kind === "EnumValue") {
261-
ext = extensions.enumValue;
247+
ext = getExtension(field, "enumValue");
262248
} else if (field.kind === "Oneof") {
263249
if (isIgnoredType(field.parent)) {
264250
return true;
265251
}
266-
ext = extensions.oneof;
252+
ext = getExtension(field, "oneof");
267253
} else {
268254
const _exhaustiveCheck: never = field;
269255
throw "unreachable";
270256
}
271-
return field.descriptor.getOptions()?.getExtension(ext)?.getIgnore() ?? false;
257+
return ext?.getIgnore() ?? false;
272258
}
273259

274260
const behaviorComments = ["Required", "Input only", "Output only"] as const;
@@ -290,3 +276,36 @@ export function descriptionFromProto(proto: {
290276
}): string | null {
291277
return proto.comments.leadingComments.trim() || null;
292278
}
279+
280+
function getExtension<
281+
K extends ExtensionKind,
282+
P extends {
283+
schema: ProtoFile;
284+
objectType: ProtoMessage;
285+
inputType: ProtoMessage;
286+
field: ProtoField;
287+
oneof: ProtoOneof;
288+
enumType: ProtoEnum;
289+
enumValue: ProtoEnumValue;
290+
}[K]
291+
>(proto: P, kind: K): Extension<K> | undefined {
292+
const extInfo = extensionInfoMap[kind];
293+
return proto.descriptor.getOptions()?.getExtension(extInfo) as any;
294+
}
295+
296+
type ExtensionKind = keyof typeof extensionInfoMap;
297+
298+
type Extension<K extends ExtensionKind> =
299+
typeof extensionInfoMap[K] extends ExtensionFieldInfo<infer Opt>
300+
? Opt
301+
: never;
302+
303+
const extensionInfoMap = {
304+
schema: extensions.schema,
305+
objectType: extensions.objectType,
306+
inputType: extensions.inputType,
307+
field: extensions.field,
308+
oneof: extensions.oneof,
309+
enumType: extensions.enumType,
310+
enumValue: extensions.enumValue,
311+
} as const;
164 Bytes
Binary file not shown.

packages/@testapis/proto/src/testapis/extensions/extensions.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,9 @@ message InterfaceMessage {
129129
uint64 id = 1;
130130
Type type = 2 [(graphql.field).ignore = true];
131131
}
132+
133+
message MessageOnlyOutput {
134+
option (graphql.input_type).ignore = true;
135+
136+
string body = 1;
137+
}

packages/protoc-gen-nexus/src/__tests__/__snapshots__/process.test.ts.snap

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3800,6 +3800,50 @@ export const TestPrefixInterfaceMessageType = enumType({
38003800
"
38013801
`;
38023802

3803+
exports[`protobuf custom options generates nexus DSLs with graphql_type file layout: extensions/TestPrefixMessageOnlyOutput.nexus.ts 1`] = `
3804+
"// Code generated by protoc-gen-nexus. DO NOT EDIT.
3805+
// source: testapis/extensions/extensions.proto
3806+
3807+
/* eslint-disable */
3808+
3809+
import { nonNull, objectType } from "nexus";
3810+
import { testapis } from "./testapis/extensions";
3811+
3812+
export type testapis$extensions$MessageOnlyOutput =
3813+
testapis.extensions.MessageOnlyOutput;
3814+
export const TestPrefixMessageOnlyOutput = objectType({
3815+
name: "TestPrefixMessageOnlyOutput",
3816+
definition: (t) => {
3817+
t.field("body", {
3818+
type: nonNull("String"),
3819+
resolve: (source) => {
3820+
const value = source.body;
3821+
if (value == null) {
3822+
throw new Error("Cannot return null for non-nullable field");
3823+
}
3824+
return value;
3825+
},
3826+
extensions: { protobufField: { name: "body", typeFullName: "string" } },
3827+
});
3828+
},
3829+
isTypeOf: (data: unknown) => {
3830+
return data instanceof testapis.extensions.MessageOnlyOutput;
3831+
},
3832+
sourceType: {
3833+
module: __filename,
3834+
export: "testapis$extensions$MessageOnlyOutput",
3835+
},
3836+
extensions: {
3837+
protobufMessage: {
3838+
fullName: "testapis.extensions.MessageOnlyOutput",
3839+
name: "MessageOnlyOutput",
3840+
package: "testapis.extensions",
3841+
},
3842+
},
3843+
});
3844+
"
3845+
`;
3846+
38033847
exports[`protobuf custom options generates nexus DSLs with graphql_type file layout: extensions/TestPrefixPrefixedEnum.nexus.ts 1`] = `
38043848
"// Code generated by protoc-gen-nexus. DO NOT EDIT.
38053849
// source: testapis/extensions/extensions.proto
@@ -4750,6 +4794,7 @@ import { stringToNumber } from "proto-nexus";
47504794
import {
47514795
IgnoredMessage,
47524796
InterfaceMessage,
4797+
MessageOnlyOutput,
47534798
MessageWillRename,
47544799
PrefixedEnum,
47554800
PrefixedMessage,
@@ -4975,6 +5020,35 @@ export const TestPrefixRenamedMessage = objectType({
49755020
},
49765021
});
49775022
5023+
export type testapis$extensions$MessageOnlyOutput = MessageOnlyOutput;
5024+
export const TestPrefixMessageOnlyOutput = objectType({
5025+
name: "TestPrefixMessageOnlyOutput",
5026+
definition: (t) => {
5027+
t.field("body", {
5028+
type: nonNull("String"),
5029+
resolve: (source) => {
5030+
const value = source.getBody();
5031+
return value;
5032+
},
5033+
extensions: { protobufField: { name: "body", typeFullName: "string" } },
5034+
});
5035+
},
5036+
isTypeOf: (data: unknown) => {
5037+
return data instanceof MessageOnlyOutput;
5038+
},
5039+
sourceType: {
5040+
module: __filename,
5041+
export: "testapis$extensions$MessageOnlyOutput",
5042+
},
5043+
extensions: {
5044+
protobufMessage: {
5045+
fullName: "testapis.extensions.MessageOnlyOutput",
5046+
name: "MessageOnlyOutput",
5047+
package: "testapis.extensions",
5048+
},
5049+
},
5050+
});
5051+
49785052
export type testapis$extensions$PrefixedMessage$InnerMessage =
49795053
PrefixedMessage.InnerMessage;
49805054
export const TestPrefixPrefixedMessageInnerMessage = objectType({
@@ -5933,6 +6007,39 @@ export const TestPrefixRenamedMessage = objectType({
59336007
},
59346008
});
59356009
6010+
export type testapis$extensions$MessageOnlyOutput =
6011+
testapis.extensions.MessageOnlyOutput;
6012+
export const TestPrefixMessageOnlyOutput = objectType({
6013+
name: "TestPrefixMessageOnlyOutput",
6014+
definition: (t) => {
6015+
t.field("body", {
6016+
type: nonNull("String"),
6017+
resolve: (source) => {
6018+
const value = source.body;
6019+
if (value == null) {
6020+
throw new Error("Cannot return null for non-nullable field");
6021+
}
6022+
return value;
6023+
},
6024+
extensions: { protobufField: { name: "body", typeFullName: "string" } },
6025+
});
6026+
},
6027+
isTypeOf: (data: unknown) => {
6028+
return data instanceof testapis.extensions.MessageOnlyOutput;
6029+
},
6030+
sourceType: {
6031+
module: __filename,
6032+
export: "testapis$extensions$MessageOnlyOutput",
6033+
},
6034+
extensions: {
6035+
protobufMessage: {
6036+
fullName: "testapis.extensions.MessageOnlyOutput",
6037+
name: "MessageOnlyOutput",
6038+
package: "testapis.extensions",
6039+
},
6040+
},
6041+
});
6042+
59366043
export type testapis$extensions$PrefixedMessage$InnerMessage =
59376044
testapis.extensions.PrefixedMessage.InnerMessage;
59386045
export const TestPrefixPrefixedMessageInnerMessage = objectType({

packages/protoc-gen-nexus/src/__tests__/process.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ describe("protobuf custom options", () => {
8383
"extensions/TestPrefixIgnoredMessageNotIgnoredInput.nexus.ts",
8484
"extensions/TestPrefixInterfaceMessageInput.nexus.ts",
8585
"extensions/TestPrefixRenamedMessageInput.nexus.ts",
86+
"extensions/TestPrefixMessageOnlyOutput.nexus.ts",
8687
]);
8788
});
8889
});

0 commit comments

Comments
 (0)