Skip to content

Commit 397f561

Browse files
authored
Merge pull request #846 from jocisneros/jcisneros/ns-imports
2 parents d2a4240 + 8390d20 commit 397f561

File tree

12 files changed

+743
-36
lines changed

12 files changed

+743
-36
lines changed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,34 @@ import { GeneratedInput } from './graphql'
8787
/* generates validation schema here */
8888
```
8989

90+
### `schemaNamespacedImportName`
91+
92+
type: `string`
93+
94+
If defined, will use named imports from the specified module (defined in `importFrom`) rather than individual imports for each type.
95+
96+
```yml
97+
generates:
98+
path/to/types.ts:
99+
plugins:
100+
- typescript
101+
path/to/schemas.ts:
102+
plugins:
103+
- graphql-codegen-validation-schema
104+
config:
105+
schema: yup
106+
importFrom: ./path/to/types
107+
schemaNamespacedImportName: types
108+
```
109+
110+
Then the generator generates code with import statement like below.
111+
112+
```ts
113+
import * as types from './graphql'
114+
115+
/* generates validation schema here */
116+
```
117+
90118
### `useTypeImports`
91119

92120
type: `boolean` default: `false`

src/config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig {
5454
* ```
5555
*/
5656
importFrom?: string
57+
/**
58+
* @description If defined, will use named imports from the specified module (defined in `importFrom`)
59+
* rather than individual imports for each type.
60+
*
61+
* @exampleMarkdown
62+
* ```yml
63+
* generates:
64+
* path/to/types.ts:
65+
* plugins:
66+
* - typescript
67+
* path/to/schemas.ts:
68+
* plugins:
69+
* - graphql-codegen-validation-schema
70+
* config:
71+
* schema: yup
72+
* importFrom: ./path/to/types
73+
* schemaNamespacedImportName: types
74+
* ```
75+
*/
76+
schemaNamespacedImportName?: string
5777
/**
5878
* @description Will use `import type {}` rather than `import {}` when importing generated typescript types.
5979
* This gives compatibility with TypeScript's "importsNotUsedAsValues": "error" option

src/myzod/index.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
6767
leave: InterfaceTypeDefinitionBuilder(this.config.withObjectType, (node: InterfaceTypeDefinitionNode) => {
6868
const visitor = this.createVisitor('output');
6969
const name = visitor.convertName(node.name.value);
70+
const typeName = visitor.prefixTypeNamespace(name);
7071
this.importTypes.push(name);
7172

7273
// Building schema for field arguments.
@@ -82,7 +83,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
8283
new DeclarationBlock({})
8384
.export()
8485
.asKind('const')
85-
.withName(`${name}Schema: myzod.Type<${name}>`)
86+
.withName(`${name}Schema: myzod.Type<${typeName}>`)
8687
.withContent([`myzod.object({`, shape, '})'].join('\n'))
8788
.string + appendArguments
8889
);
@@ -93,7 +94,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
9394
new DeclarationBlock({})
9495
.export()
9596
.asKind('function')
96-
.withName(`${name}Schema(): myzod.Type<${name}>`)
97+
.withName(`${name}Schema(): myzod.Type<${typeName}>`)
9798
.withBlock([indent(`return myzod.object({`), shape, indent('})')].join('\n'))
9899
.string + appendArguments
99100
);
@@ -107,6 +108,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
107108
leave: ObjectTypeDefinitionBuilder(this.config.withObjectType, (node: ObjectTypeDefinitionNode) => {
108109
const visitor = this.createVisitor('output');
109110
const name = visitor.convertName(node.name.value);
111+
const typeName = visitor.prefixTypeNamespace(name);
110112
this.importTypes.push(name);
111113

112114
// Building schema for field arguments.
@@ -122,7 +124,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
122124
new DeclarationBlock({})
123125
.export()
124126
.asKind('const')
125-
.withName(`${name}Schema: myzod.Type<${name}>`)
127+
.withName(`${name}Schema: myzod.Type<${typeName}>`)
126128
.withContent(
127129
[
128130
`myzod.object({`,
@@ -140,7 +142,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
140142
new DeclarationBlock({})
141143
.export()
142144
.asKind('function')
143-
.withName(`${name}Schema(): myzod.Type<${name}>`)
145+
.withName(`${name}Schema(): myzod.Type<${typeName}>`)
144146
.withBlock(
145147
[
146148
indent(`return myzod.object({`),
@@ -161,6 +163,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
161163
leave: (node: EnumTypeDefinitionNode) => {
162164
const visitor = this.createVisitor('both');
163165
const enumname = visitor.convertName(node.name.value);
166+
const enumTypeName = visitor.prefixTypeNamespace(enumname);
164167
this.importTypes.push(enumname);
165168
// z.enum are basically myzod.literals
166169
// hoist enum declarations
@@ -178,7 +181,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
178181
.export()
179182
.asKind('const')
180183
.withName(`${enumname}Schema`)
181-
.withContent(`myzod.enum(${enumname})`)
184+
.withContent(`myzod.enum(${enumTypeName})`)
182185
.string,
183186
);
184187
},
@@ -233,14 +236,15 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
233236
visitor: Visitor,
234237
name: string,
235238
) {
239+
const typeName = visitor.prefixTypeNamespace(name);
236240
const shape = fields.map(field => generateFieldMyZodSchema(this.config, visitor, field, 2)).join(',\n');
237241

238242
switch (this.config.validationSchemaExportType) {
239243
case 'const':
240244
return new DeclarationBlock({})
241245
.export()
242246
.asKind('const')
243-
.withName(`${name}Schema: myzod.Type<${name}>`)
247+
.withName(`${name}Schema: myzod.Type<${typeName}>`)
244248
.withContent(['myzod.object({', shape, '})'].join('\n'))
245249
.string;
246250

@@ -249,7 +253,7 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
249253
return new DeclarationBlock({})
250254
.export()
251255
.asKind('function')
252-
.withName(`${name}Schema(): myzod.Type<${name}>`)
256+
.withName(`${name}Schema(): myzod.Type<${typeName}>`)
253257
.withBlock([indent(`return myzod.object({`), shape, indent('})')].join('\n'))
254258
.string;
255259
}

src/schema_visitor.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@ export abstract class BaseSchemaVisitor implements SchemaVisitor {
2323

2424
buildImports(): string[] {
2525
if (this.config.importFrom && this.importTypes.length > 0) {
26+
const namedImportPrefix = this.config.useTypeImports ? 'type ' : '';
27+
28+
const importCore = this.config.schemaNamespacedImportName
29+
? `* as ${this.config.schemaNamespacedImportName}`
30+
: `${namedImportPrefix}{ ${this.importTypes.join(', ')} }`;
31+
2632
return [
2733
this.importValidationSchema(),
28-
`import ${this.config.useTypeImports ? 'type ' : ''}{ ${this.importTypes.join(', ')} } from '${
29-
this.config.importFrom
30-
}'`,
34+
`import ${importCore} from '${this.config.importFrom}'`,
3135
];
3236
}
3337
return [this.importValidationSchema()];

src/valibot/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
5858
leave: InterfaceTypeDefinitionBuilder(this.config.withObjectType, (node: InterfaceTypeDefinitionNode) => {
5959
const visitor = this.createVisitor('output');
6060
const name = visitor.convertName(node.name.value);
61+
const typeName = visitor.prefixTypeNamespace(name);
6162
this.importTypes.push(name);
6263

6364
// Building schema for field arguments.
@@ -73,7 +74,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
7374
new DeclarationBlock({})
7475
.export()
7576
.asKind('function')
76-
.withName(`${name}Schema(): v.GenericSchema<${name}>`)
77+
.withName(`${name}Schema(): v.GenericSchema<${typeName}>`)
7778
.withBlock([indent(`return v.object({`), shape, indent('})')].join('\n'))
7879
.string + appendArguments
7980
);
@@ -87,6 +88,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
8788
leave: ObjectTypeDefinitionBuilder(this.config.withObjectType, (node: ObjectTypeDefinitionNode) => {
8889
const visitor = this.createVisitor('output');
8990
const name = visitor.convertName(node.name.value);
91+
const typeName = visitor.prefixTypeNamespace(name);
9092
this.importTypes.push(name);
9193

9294
// Building schema for field arguments.
@@ -102,7 +104,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
102104
new DeclarationBlock({})
103105
.export()
104106
.asKind('function')
105-
.withName(`${name}Schema(): v.GenericSchema<${name}>`)
107+
.withName(`${name}Schema(): v.GenericSchema<${typeName}>`)
106108
.withBlock(
107109
[
108110
indent(`return v.object({`),
@@ -123,6 +125,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
123125
leave: (node: EnumTypeDefinitionNode) => {
124126
const visitor = this.createVisitor('both');
125127
const enumname = visitor.convertName(node.name.value);
128+
const enumTypeName = visitor.prefixTypeNamespace(enumname);
126129
this.importTypes.push(enumname);
127130

128131
// hoist enum declarations
@@ -138,7 +141,7 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
138141
.export()
139142
.asKind('const')
140143
.withName(`${enumname}Schema`)
141-
.withContent(`v.enum_(${enumname})`)
144+
.withContent(`v.enum_(${enumTypeName})`)
142145
.string,
143146
);
144147
},
@@ -185,14 +188,15 @@ export class ValibotSchemaVisitor extends BaseSchemaVisitor {
185188
visitor: Visitor,
186189
name: string,
187190
) {
191+
const typeName = visitor.prefixTypeNamespace(name);
188192
const shape = fields.map(field => generateFieldValibotSchema(this.config, visitor, field, 2)).join(',\n');
189193

190194
switch (this.config.validationSchemaExportType) {
191195
default:
192196
return new DeclarationBlock({})
193197
.export()
194198
.asKind('function')
195-
.withName(`${name}Schema(): v.GenericSchema<${name}>`)
199+
.withName(`${name}Schema(): v.GenericSchema<${typeName}>`)
196200
.withBlock([indent(`return v.object({`), shape, indent('})')].join('\n'))
197201
.string;
198202
}

src/visitor.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import type { BaseVisitorConvertOptions, ConvertOptions } from '@graphql-codegen/visitor-plugin-common';
12
import type {
3+
ASTNode,
24
FieldDefinitionNode,
35
GraphQLSchema,
46
InterfaceTypeDefinitionNode,
@@ -21,6 +23,14 @@ export class Visitor extends TsVisitor {
2123
super(schema, pluginConfig);
2224
}
2325

26+
public prefixTypeNamespace(type: string): string {
27+
if (this.pluginConfig.importFrom && this.pluginConfig.schemaNamespacedImportName) {
28+
return `${this.pluginConfig.schemaNamespacedImportName}.${type}`;
29+
}
30+
31+
return type;
32+
}
33+
2434
private isSpecifiedScalarName(scalarName: string) {
2535
return specifiedScalarTypes.some(({ name }) => name === scalarName);
2636
}

src/yup/index.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
7676
leave: InterfaceTypeDefinitionBuilder(this.config.withObjectType, (node: InterfaceTypeDefinitionNode) => {
7777
const visitor = this.createVisitor('output');
7878
const name = visitor.convertName(node.name.value);
79+
const typeName = visitor.prefixTypeNamespace(name);
7980
this.importTypes.push(name);
8081

8182
// Building schema for field arguments.
@@ -94,7 +95,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
9495
new DeclarationBlock({})
9596
.export()
9697
.asKind('const')
97-
.withName(`${name}Schema: yup.ObjectSchema<${name}>`)
98+
.withName(`${name}Schema: yup.ObjectSchema<${typeName}>`)
9899
.withContent([`yup.object({`, shape, '})'].join('\n'))
99100
.string + appendArguments
100101
);
@@ -105,7 +106,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
105106
new DeclarationBlock({})
106107
.export()
107108
.asKind('function')
108-
.withName(`${name}Schema(): yup.ObjectSchema<${name}>`)
109+
.withName(`${name}Schema(): yup.ObjectSchema<${typeName}>`)
109110
.withBlock([indent(`return yup.object({`), shape, indent('})')].join('\n'))
110111
.string + appendArguments
111112
);
@@ -119,6 +120,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
119120
leave: ObjectTypeDefinitionBuilder(this.config.withObjectType, (node: ObjectTypeDefinitionNode) => {
120121
const visitor = this.createVisitor('output');
121122
const name = visitor.convertName(node.name.value);
123+
const typeName = visitor.prefixTypeNamespace(name);
122124
this.importTypes.push(name);
123125

124126
// Building schema for field arguments.
@@ -134,7 +136,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
134136
new DeclarationBlock({})
135137
.export()
136138
.asKind('const')
137-
.withName(`${name}Schema: yup.ObjectSchema<${name}>`)
139+
.withName(`${name}Schema: yup.ObjectSchema<${typeName}>`)
138140
.withContent(
139141
[
140142
`yup.object({`,
@@ -152,7 +154,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
152154
new DeclarationBlock({})
153155
.export()
154156
.asKind('function')
155-
.withName(`${name}Schema(): yup.ObjectSchema<${name}>`)
157+
.withName(`${name}Schema(): yup.ObjectSchema<${typeName}>`)
156158
.withBlock(
157159
[
158160
indent(`return yup.object({`),
@@ -173,6 +175,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
173175
leave: (node: EnumTypeDefinitionNode) => {
174176
const visitor = this.createVisitor('both');
175177
const enumname = visitor.convertName(node.name.value);
178+
const enumTypeName = visitor.prefixTypeNamespace(enumname);
176179
this.importTypes.push(enumname);
177180

178181
// hoise enum declarations
@@ -193,7 +196,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
193196
.export()
194197
.asKind('const')
195198
.withName(`${enumname}Schema`)
196-
.withContent(`yup.string<${enumname}>().oneOf(Object.values(${enumname})).defined()`).string,
199+
.withContent(`yup.string<${enumTypeName}>().oneOf(Object.values(${enumTypeName})).defined()`).string,
197200
);
198201
}
199202
},
@@ -208,6 +211,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
208211
const visitor = this.createVisitor('output');
209212

210213
const unionName = visitor.convertName(node.name.value);
214+
const unionTypeName = visitor.prefixTypeNamespace(unionName);
211215
this.importTypes.push(unionName);
212216

213217
const unionElements = node.types?.map((t) => {
@@ -230,16 +234,16 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
230234
return new DeclarationBlock({})
231235
.export()
232236
.asKind('const')
233-
.withName(`${unionName}Schema: yup.MixedSchema<${unionName}>`)
234-
.withContent(`union<${unionName}>(${unionElements})`)
237+
.withName(`${unionName}Schema: yup.MixedSchema<${unionTypeName}>`)
238+
.withContent(`union<${unionTypeName}>(${unionElements})`)
235239
.string;
236240
case 'function':
237241
default:
238242
return new DeclarationBlock({})
239243
.export()
240244
.asKind('function')
241-
.withName(`${unionName}Schema(): yup.MixedSchema<${unionName}>`)
242-
.withBlock(indent(`return union<${unionName}>(${unionElements})`))
245+
.withName(`${unionName}Schema(): yup.MixedSchema<${unionTypeName}>`)
246+
.withBlock(indent(`return union<${unionTypeName}>(${unionElements})`))
243247
.string;
244248
}
245249
},
@@ -251,14 +255,15 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
251255
visitor: Visitor,
252256
name: string,
253257
) {
258+
const typeName = visitor.prefixTypeNamespace(name);
254259
const shape = shapeFields(fields, this.config, visitor);
255260

256261
switch (this.config.validationSchemaExportType) {
257262
case 'const':
258263
return new DeclarationBlock({})
259264
.export()
260265
.asKind('const')
261-
.withName(`${name}Schema: yup.ObjectSchema<${name}>`)
266+
.withName(`${name}Schema: yup.ObjectSchema<${typeName}>`)
262267
.withContent(['yup.object({', shape, '})'].join('\n'))
263268
.string;
264269

@@ -267,7 +272,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor {
267272
return new DeclarationBlock({})
268273
.export()
269274
.asKind('function')
270-
.withName(`${name}Schema(): yup.ObjectSchema<${name}>`)
275+
.withName(`${name}Schema(): yup.ObjectSchema<${typeName}>`)
271276
.withBlock([indent(`return yup.object({`), shape, indent('})')].join('\n'))
272277
.string;
273278
}

0 commit comments

Comments
 (0)