Skip to content

Commit

Permalink
Allow to use graphql-modules-preset plugin without graphql-modules li…
Browse files Browse the repository at this point in the history
…brary
  • Loading branch information
dotansimha committed Oct 19, 2021
1 parent 20eb661 commit 83e504b
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-mails-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-codegen/graphql-modules-preset': minor
---

Added an option to allow to skip generating code related to graphql-modules library
10 changes: 8 additions & 2 deletions packages/presets/graphql-modules/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export function buildModule(
rootTypes,
schema,
baseVisitor,
useGraphQLModules,
}: {
importNamespace: string;
importPath: string;
Expand All @@ -54,6 +55,7 @@ export function buildModule(
rootTypes: string[];
baseVisitor: BaseVisitor;
schema?: GraphQLSchema;
useGraphQLModules: boolean;
}
): string {
const picks: Record<RegistryKeys, Record<string, string[]>> = createObject(registryKeys, () => ({}));
Expand Down Expand Up @@ -114,7 +116,11 @@ export function buildModule(
//

// An actual output
const imports = [`import * as ${importNamespace} from "${importPath}";`, `import * as gm from "graphql-modules";`];
const imports = [`import * as ${importNamespace} from "${importPath}";`];

if (useGraphQLModules) {
imports.push(`import * as gm from "graphql-modules";`);
}

let content = [
printDefinedFields(),
Expand All @@ -124,7 +130,7 @@ export function buildModule(
printScalars(visited),
printResolveSignaturesPerType(visited),
printResolversType(visited),
printResolveMiddlewareMap(),
useGraphQLModules ? printResolveMiddlewareMap() : undefined,
]
.filter(Boolean)
.join('\n\n');
Expand Down
33 changes: 9 additions & 24 deletions packages/presets/graphql-modules/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,6 @@ export type ModulesConfig = {
* @type string
* @description Required, sets the file name for the generated files.
*
* @example
* ```yml
* generates:
* src/:
* preset: modules
* presetConfig:
* baseTypesPath: types.ts
* filename: types.ts
* plugins:
* - typescript-operations
* - typescript-react-apollo
* ```
*/
filename: string;
/**
Expand All @@ -92,18 +80,15 @@ export type ModulesConfig = {
* `prefix`: will prefix all types from a specific module with the module name.
* `none`: will skip encapsulation, and generate type as-is.
*
* @example
* ```yml
* generates:
* src/:
* preset: modules
* presetConfig:
* baseTypesPath: types.ts
* filename: types.ts
* plugins:
* - typescript-operations
* - typescript-react-apollo
* ```
*/
encapsulateModuleTypes: 'prefix' | 'namespace' | 'none';
/**
* @name useGraphQLModules
* @type boolean
* @default true
* @description By default, the generated types will be generate some code specific to `graphql-modules` library.
*
* If you are not using GraphQL-Modules, you can disable this feature by setting this to `false`.
*/
useGraphQLModules?: boolean;
};
4 changes: 3 additions & 1 deletion packages/presets/graphql-modules/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { resolve, relative, join } from 'path';
import { groupSourcesByModule, stripFilename, normalize, isGraphQLPrimitive } from './utils';
import { buildModule } from './builder';
import { ModulesConfig } from './config';
import { BaseVisitor } from '@graphql-codegen/visitor-plugin-common';
import { BaseVisitor, getConfigValue } from '@graphql-codegen/visitor-plugin-common';

export const preset: Types.OutputPreset<ModulesConfig> = {
buildGeneratesSection: options => {
const useGraphQLModules = getConfigValue(options?.presetConfig.useGraphQLModules, true);
const { baseOutputDir } = options;
const { baseTypesPath, encapsulateModuleTypes } = options.presetConfig;

Expand Down Expand Up @@ -103,6 +104,7 @@ export const preset: Types.OutputPreset<ModulesConfig> = {
shouldDeclare,
schema,
baseVisitor,
useGraphQLModules,
rootTypes: [
schema.getQueryType()?.name,
schema.getMutationType()?.name,
Expand Down
48 changes: 48 additions & 0 deletions packages/presets/graphql-modules/tests/builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ test('should generate interface field resolvers', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
}
);

Expand All @@ -81,6 +82,39 @@ test('should generate interface field resolvers', () => {
expect(output).toContain(`export type BaseUserResolvers = Pick<core.BaseUserResolvers, DefinedFields['BaseUser']>;`);
});

test('should not generate graphql-modules code when useGraphQLModules=false', () => {
const output = buildModule(
'test',
parse(/* GraphQL */ `
interface BaseUser {
id: ID!
email: String!
}
type User implements BaseUser {
id: ID!
email: String!
}
type Query {
me: BaseUser!
}
`),
{
importPath: '../types',
importNamespace: 'core',
encapsulate: 'none',
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: false,
}
);

expect(output).not.toContain(`graphql-modules`);
expect(output).not.toContain(`gm.`);
});

test('should generate interface extensions field resolvers ', () => {
const output = buildModule(
'test',
Expand All @@ -100,6 +134,7 @@ test('should generate interface extensions field resolvers ', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
}
);

Expand All @@ -116,6 +151,7 @@ test('should include import statement', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand All @@ -131,6 +167,7 @@ test('should work with naming conventions', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toContain(`Pick<core.Query_RootResolvers, `);
Expand All @@ -145,6 +182,7 @@ test('encapsulate: should wrap correctly with namespace', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`export namespace TestModule {`);
Expand All @@ -159,6 +197,7 @@ test('encapsulate: should wrap correctly with a declared namespace', () => {
shouldDeclare: true,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`declare namespace TestModule {`);
Expand All @@ -172,6 +211,7 @@ test('encapsulate: should wrap correctly with prefix', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toMatchSnapshot();
Expand All @@ -195,6 +235,7 @@ test('should pick fields from defined and extended types', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand Down Expand Up @@ -227,6 +268,7 @@ test('should reexport used types but not defined in module', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand All @@ -245,6 +287,7 @@ test('should export partial types, only those defined in module or root types',
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand Down Expand Up @@ -275,6 +318,7 @@ test('should export partial types of scalars, only those defined in module or ro
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand All @@ -295,6 +339,7 @@ test('should use and export resolver signatures of types defined or extended in
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand Down Expand Up @@ -332,6 +377,7 @@ test('should not generate resolver signatures of types that are not defined or e
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).not.toContain('CommentResolvers');
Expand All @@ -345,6 +391,7 @@ test('should generate an aggregation of individual resolver signatures', () => {
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toBeSimilarStringTo(`
Expand All @@ -366,6 +413,7 @@ test('should generate a signature for ResolveMiddleware (with widlcards)', () =>
shouldDeclare: false,
rootTypes: ROOT_TYPES,
baseVisitor,
useGraphQLModules: true,
});

expect(output).toContain(`import * as gm from "graphql-modules";`);
Expand Down
24 changes: 24 additions & 0 deletions packages/presets/graphql-modules/tests/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,30 @@ describe('Integration', () => {
expect(output[4].content).toMatch(importStatement);
});

test('should allow to disable graphql-modules', async () => {
const output = await executeCodegen({
generates: {
'./tests/test-files/modules': {
schema: './tests/test-files/modules/*/types/*.graphql',
plugins: ['typescript', 'typescript-resolvers'],
preset: 'graphql-modules',
presetConfig: {
importBaseTypesFrom: '@types',
baseTypesPath: 'global-types.ts',
filename: 'module-types.ts',
encapsulateModuleTypes: 'none',
useGraphQLModules: false,
},
},
},
});

for (const record of output) {
expect(record).not.toContain(`graphql-modules`);
expect(record).not.toContain(`gm.`);
}
});

test('each module-types should include a relative import to glob-types module', async () => {
const output = await executeCodegen(options);
const importStatement = `import * as Types from "../global-types";`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,4 +542,4 @@ default: `inline`

Whether fragment types should be inlined into other operations.
"inline" is the default behavior and will perform deep inlining fragment types within operation type definitions.
"combine" is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types).
"combine" is the previous behavior that uses fragment type references without inlining the types (and might cauuse issues with deeply nested fragment that uses list types).
25 changes: 23 additions & 2 deletions website/docs/presets/graphql-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ id: graphql-modules
title: graphql-modules
---

The `@graphql-codegen/graphql-modules-preset` generates `.ts` file with TypeScript types, per each [GraphQL-Modules](http://graphql-modules.com/) module definition.
The `@graphql-codegen/graphql-modules-preset` generates `.ts` file with TypeScript types, per each directory that contains GraphQL SDL definitions.

The generates files will be generated based on each module definition, and based on the GraphQL schema defined in that specific module, allowing you to write type-safe resolvers, while keeping modules types boundaries.

:::caution Usage Requirements

This preset generates code for `graphql-modules` @ `v1`. Previous versions are not supported.
This preset generates code for `graphql-modules` @ `v1` (previous versions are not supported) by default.

If you are not using `graphql-modules`, you can set `useGraphQLModules: false` to disable this behaviour.

:::

Expand All @@ -19,6 +21,21 @@ This preset generates code for `graphql-modules` @ `v1`. Previous versions are n

## Usage Example

Given a folder structure with the following files:

```
- src/
- modules/
- user/
- resolvers.ts
- typedefs/
- user.graphql
- product/
- resolvers.ts
- typedefs/
- product.graphql
```

Here's a short example for generating types and resolvers for 2 modules:

```yaml
Expand Down Expand Up @@ -50,3 +67,7 @@ export const resolvers: MyModule.Resolvers = {
```

> You can find [an example project here](https://github.com/dotansimha/graphql-code-generator/tree/master/dev-test/modules).

## Using without GraphQL-Modules

By defualt, this preset it generating code for `graphql-modules`, but if you are not using it, you can set `useGraphQLModules: false` in your preset configuration to generate fully agnostic types that are based on folder strucutre only.
11 changes: 10 additions & 1 deletion website/static/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3450,6 +3450,10 @@
"encapsulateModuleTypes": {
"type": "string",
"description": "Configure how to encapsulate the module types, to avoid confusion.\n\n`namespace` (default): will wrap all types in a TypeScript namespace, using the module name.\n`prefix`: will prefix all types from a specific module with the module name.\n`none`: will skip encapsulation, and generate type as-is.\nDefault value: \"namespace\""
},
"useGraphQLModules": {
"type": "boolean",
"description": "By default, the generated types will be generate some code specific to `graphql-modules` library.\n\nIf you are not using GraphQL-Modules, you can disable this feature by setting this to `false`.\nDefault value: \"true\""
}
}
},
Expand Down Expand Up @@ -3497,7 +3501,12 @@
},
"GqlTagConfig": {
"type": "object",
"properties": {}
"properties": {
"augmentedModuleName": {
"description": "Instead of generating a `gql` function, this preset can also generate a d.ts that will enhance the `gql` function of your framework.\n\nE.g. `graphql-tag` or `@urql/core`.",
"type": "string"
}
}
},
"Types.InstanceOrArray": {
"anyOf": [
Expand Down

0 comments on commit 83e504b

Please sign in to comment.