Skip to content

Commit e80fd49

Browse files
committed
fixed #394
1 parent a838cf4 commit e80fd49

File tree

6 files changed

+190
-10
lines changed

6 files changed

+190
-10
lines changed

src/graphql.ts

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
DefinitionNode,
55
DocumentNode,
66
GraphQLSchema,
7+
isSpecifiedScalarType,
78
ListTypeNode,
89
NamedTypeNode,
910
NameNode,
@@ -169,3 +170,8 @@ export const topsort = (g: Graph): string[] => {
169170

170171
return results.reverse();
171172
};
173+
174+
export const isGeneratedByIntrospection = (schema: GraphQLSchema): boolean =>
175+
Object.entries(schema.getTypeMap())
176+
.filter(([name, type]) => !name.startsWith('__') && !isSpecifiedScalarType(type))
177+
.every(([, type]) => type.astNode === undefined);

src/index.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { PluginFunction, Types } from '@graphql-codegen/plugin-helpers';
22
import { transformSchemaAST } from '@graphql-codegen/schema-ast';
3-
import { GraphQLSchema, visit } from 'graphql';
3+
import { buildSchema, GraphQLSchema, printSchema, visit } from 'graphql';
44

55
import { ValidationSchemaPluginConfig } from './config';
6-
import { topologicalSortAST } from './graphql';
6+
import { isGeneratedByIntrospection, topologicalSortAST } from './graphql';
77
import { MyZodSchemaVisitor } from './myzod/index';
88
import { SchemaVisitor } from './types';
99
import { YupSchemaVisitor } from './yup/index';
@@ -40,16 +40,20 @@ const schemaVisitor = (schema: GraphQLSchema, config: ValidationSchemaPluginConf
4040

4141
const _transformSchemaAST = (schema: GraphQLSchema, config: ValidationSchemaPluginConfig) => {
4242
const { schema: _schema, ast } = transformSchemaAST(schema, config);
43+
44+
// See: https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema/issues/394
45+
const __schema = isGeneratedByIntrospection(_schema) ? buildSchema(printSchema(_schema)) : _schema;
46+
4347
// This affects the performance of code generation, so it is
4448
// enabled only when this option is selected.
4549
if (config.validationSchemaExportType === 'const') {
4650
return {
47-
schema: _schema,
48-
ast: topologicalSortAST(_schema, ast),
51+
schema: __schema,
52+
ast: topologicalSortAST(__schema, ast),
4953
};
5054
}
5155
return {
52-
schema: _schema,
56+
schema: __schema,
5357
ast,
5458
};
5559
};

tests/graphql.spec.ts

+60-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import { Graph } from 'graphlib';
2-
import { buildSchema, Kind, ObjectTypeDefinitionNode, parse, print } from 'graphql';
2+
import {
3+
buildClientSchema,
4+
buildSchema,
5+
introspectionFromSchema,
6+
Kind,
7+
ObjectTypeDefinitionNode,
8+
parse,
9+
print,
10+
} from 'graphql';
311
import dedent from 'ts-dedent';
412

5-
import { ObjectTypeDefinitionBuilder, topologicalSortAST, topsort } from '../src/graphql';
13+
import { isGeneratedByIntrospection, ObjectTypeDefinitionBuilder, topologicalSortAST, topsort } from '../src/graphql';
614

715
describe('graphql', () => {
816
describe('ObjectTypeDefinitionBuilder', () => {
@@ -238,3 +246,53 @@ describe('topologicalSortAST', () => {
238246
expect(sortedSchema).toBe(expectedSortedSchema);
239247
});
240248
});
249+
250+
describe('isGeneratedByIntrospection function', () => {
251+
const schemaDefinition = /* GraphQL */ `
252+
scalar CustomScalar
253+
254+
interface Node {
255+
id: ID!
256+
}
257+
258+
type UserType implements Node {
259+
id: ID!
260+
name: String!
261+
email: String!
262+
}
263+
264+
union SearchResult = UserType
265+
266+
enum Role {
267+
ADMIN
268+
USER
269+
}
270+
271+
input UserInput {
272+
name: String!
273+
email: String!
274+
role: Role!
275+
}
276+
277+
type Query {
278+
user(id: ID!): UserType!
279+
search(text: String!): [SearchResult]
280+
}
281+
282+
type Mutation {
283+
createUser(input: UserInput!): UserType!
284+
}
285+
`;
286+
287+
test('returns false for a schema not generated by introspection', () => {
288+
const schema = buildSchema(schemaDefinition);
289+
expect(isGeneratedByIntrospection(schema)).toBe(false);
290+
});
291+
292+
test('returns true for a schema generated by introspection', () => {
293+
const schema = buildSchema(schemaDefinition);
294+
const query = introspectionFromSchema(schema);
295+
const clientSchema = buildClientSchema(query);
296+
expect(isGeneratedByIntrospection(clientSchema)).toBe(true);
297+
});
298+
});

tests/myzod.spec.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { buildSchema } from 'graphql';
1+
import { buildClientSchema, buildSchema, introspectionFromSchema } from 'graphql';
22
import dedent from 'ts-dedent';
33

44
import { plugin } from '../src/index';
@@ -922,4 +922,41 @@ describe('myzod', () => {
922922
expect(result.content).not.toContain(wantNotContain);
923923
}
924924
});
925+
926+
it('issue #394', async () => {
927+
const schema = buildSchema(/* GraphQL */ `
928+
enum Test {
929+
A
930+
B
931+
}
932+
933+
type Query {
934+
_dummy: Test
935+
}
936+
937+
input QueryInput {
938+
_dummy: Test
939+
}
940+
`);
941+
const query = introspectionFromSchema(schema);
942+
const clientSchema = buildClientSchema(query);
943+
const result = await plugin(
944+
clientSchema,
945+
[],
946+
{
947+
schema: 'myzod',
948+
scalars: {
949+
ID: 'string',
950+
},
951+
},
952+
{}
953+
);
954+
const wantContain = dedent`
955+
export function QueryInputSchema(): myzod.Type<QueryInput> {
956+
return myzod.object({
957+
_dummy: TestSchema.optional().nullable()
958+
})
959+
}`;
960+
expect(result.content).toContain(wantContain);
961+
});
925962
});

tests/yup.spec.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { buildSchema } from 'graphql';
1+
import { buildClientSchema, buildSchema, introspectionFromSchema } from 'graphql';
22
import dedent from 'ts-dedent';
33

44
import { plugin } from '../src/index';
@@ -836,4 +836,41 @@ describe('yup', () => {
836836
expect(result.content).not.toContain(wantNotContain);
837837
}
838838
});
839+
840+
it('issue #394', async () => {
841+
const schema = buildSchema(/* GraphQL */ `
842+
enum Test {
843+
A
844+
B
845+
}
846+
847+
type Query {
848+
_dummy: Test
849+
}
850+
851+
input QueryInput {
852+
_dummy: Test
853+
}
854+
`);
855+
const query = introspectionFromSchema(schema);
856+
const clientSchema = buildClientSchema(query);
857+
const result = await plugin(
858+
clientSchema,
859+
[],
860+
{
861+
schema: 'yup',
862+
scalars: {
863+
ID: 'string',
864+
},
865+
},
866+
{}
867+
);
868+
const wantContain = dedent`
869+
export function QueryInputSchema(): yup.ObjectSchema<QueryInput> {
870+
return yup.object({
871+
_dummy: TestSchema.nullable().optional()
872+
})
873+
}`;
874+
expect(result.content).toContain(wantContain);
875+
});
839876
});

tests/zod.spec.ts

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { buildSchema } from 'graphql';
1+
import { getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers';
2+
import { buildClientSchema, buildSchema, introspectionFromSchema, isSpecifiedScalarType } from 'graphql';
23
import { dedent } from 'ts-dedent';
34

45
import { plugin } from '../src/index';
@@ -989,4 +990,41 @@ describe('zod', () => {
989990
expect(result.content).not.toContain(wantNotContain);
990991
}
991992
});
993+
994+
it('issue #394', async () => {
995+
const schema = buildSchema(/* GraphQL */ `
996+
enum Test {
997+
A
998+
B
999+
}
1000+
1001+
type Query {
1002+
_dummy: Test
1003+
}
1004+
1005+
input QueryInput {
1006+
_dummy: Test
1007+
}
1008+
`);
1009+
const query = introspectionFromSchema(schema);
1010+
const clientSchema = buildClientSchema(query);
1011+
const result = await plugin(
1012+
clientSchema,
1013+
[],
1014+
{
1015+
schema: 'zod',
1016+
scalars: {
1017+
ID: 'string',
1018+
},
1019+
},
1020+
{}
1021+
);
1022+
const wantContain = dedent`
1023+
export function QueryInputSchema(): z.ZodObject<Properties<QueryInput>> {
1024+
return z.object({
1025+
_dummy: TestSchema.nullish()
1026+
})
1027+
}`;
1028+
expect(result.content).toContain(wantContain);
1029+
});
9921030
});

0 commit comments

Comments
 (0)