diff --git a/README.md b/README.md index e7045ed..e366dd3 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,34 @@ Adds `__typename` property to mock data Changes enums to TypeScript string union types +### includedTypes (`string[]`, defaultValue: `undefined`) + +Specifies an array of types to **include** in the mock generation. When provided, only the types listed in this array will have mock data generated. + +Example: + +```yaml +plugins: + - typescript-mock-data: + includedTypes: + - User + - Avatar +``` + +### excludedTypes (`string[]`, defaultValue: `undefined`) + +Specifies an array of types to **exclude** in the mock generation. When provided, the types listed in this array will not have mock data generated. + +Example: + +```yaml +plugins: + - typescript-mock-data: + excludedTypes: + - User + - Avatar +``` + ### terminateCircularRelationships (`boolean | 'immediate'`, defaultValue: `false`) When enabled, prevents circular relationships from triggering infinite recursion. After the first resolution of a diff --git a/src/index.ts b/src/index.ts index 1d3a4b4..a6b795f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -588,6 +588,8 @@ export interface TypescriptMocksPluginConfig { defaultNullableToNull?: boolean; useTypeImports?: boolean; typeNamesMapping?: Record; + includedTypes?: string[]; + excludedTypes?: string[]; } interface TypeItem { @@ -835,7 +837,24 @@ export const plugin: PluginFunction = (schema, docu // run on the types first oldVisit(astNode, { leave: typeVisitor }); const result = oldVisit(astNode, { leave: visitor }); - const definitions = result.definitions.filter((definition: any) => !!definition); + + const { includedTypes, excludedTypes } = config; + const shouldGenerateMockForType = (typeName?: string) => { + if (!typeName) { + return true; + } + if (includedTypes && includedTypes.length > 0) { + return includedTypes.includes(typeName); + } + if (excludedTypes && excludedTypes.length > 0) { + return !excludedTypes.includes(typeName); + } + return true; + }; + + const definitions = result.definitions.filter( + (definition: any) => !!definition && shouldGenerateMockForType(definition.typeName), + ); const typesFile = config.typesFile ? config.typesFile.replace(/\.[\w]+$/, '') : null; const typesFileImport = getImportTypes({ diff --git a/tests/__snapshots__/typescript-mock-data.spec.ts.snap b/tests/__snapshots__/typescript-mock-data.spec.ts.snap index 62093bd..a6157c8 100644 --- a/tests/__snapshots__/typescript-mock-data.spec.ts.snap +++ b/tests/__snapshots__/typescript-mock-data.spec.ts.snap @@ -1714,6 +1714,32 @@ export const aQuery = (overrides?: Partial): Query => { " `; +exports[`should generate mock data only for included types 1`] = ` +" +export const anAvatar = (overrides?: Partial): Avatar => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '1550ff93-cd31-49b4-a3c3-8ef1cb68bdc3', + url: overrides && overrides.hasOwnProperty('url') ? overrides.url! : 'consectetur', + }; +}; + +export const aUser = (overrides?: Partial): User => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'b5756f00-51a6-422a-81a7-dc13ee6a6375', + creationDate: overrides && overrides.hasOwnProperty('creationDate') ? overrides.creationDate! : '2021-06-27T14:29:24.774Z', + login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : 'sordeo', + avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), + status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : Status.Online, + customStatus: overrides && overrides.hasOwnProperty('customStatus') ? overrides.customStatus! : AbcStatus.HasXyzStatus, + scalarValue: overrides && overrides.hasOwnProperty('scalarValue') ? overrides.scalarValue! : 'arx', + camelCaseThing: overrides && overrides.hasOwnProperty('camelCaseThing') ? overrides.camelCaseThing! : aCamelCaseThing(), + unionThing: overrides && overrides.hasOwnProperty('unionThing') ? overrides.unionThing! : anAvatar(), + prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : PrefixedEnum.PrefixedValue, + }; +}; +" +`; + exports[`should generate mock data with PascalCase enum values by default 1`] = ` " export const anAvatar = (overrides?: Partial): Avatar => { diff --git a/tests/typescript-mock-data.spec.ts b/tests/typescript-mock-data.spec.ts index 53a169a..aeb76a1 100644 --- a/tests/typescript-mock-data.spec.ts +++ b/tests/typescript-mock-data.spec.ts @@ -612,3 +612,39 @@ it('overriding works as expected when defaultNullableToNull is true', async () = expect(result).toMatchSnapshot(); }); + +it('should generate mock data only for included types', async () => { + const result = await plugin(testSchema, [], { + includedTypes: ['User', 'Avatar'], + }); + + expect(result).toMatchSnapshot(); + expect(result).toBeDefined(); + expect(result).toContain('export const aUser'); + expect(result).toContain('export const anAvatar'); + expect(result).not.toContain('export const aPrefixedResponse'); + expect(result).not.toContain('export const aCamelCaseThing'); +}); + +it('should exclude specified types from mock generation', async () => { + const result = await plugin(testSchema, [], { + excludedTypes: ['User', 'Avatar'], + }); + + expect(result).toBeDefined(); + expect(result).not.toContain('export const aUser'); + expect(result).not.toContain('export const anAvatar'); + expect(result).toContain('export const aPrefixedResponse'); + expect(result).toContain('export const aCamelCaseThing'); +}); + +it('should prioritize includedTypes over excludedTypes if both are specified', async () => { + const result = await plugin(testSchema, [], { + includedTypes: ['User'], + excludedTypes: ['User', 'Avatar'], + }); + expect(result).toBeDefined(); + expect(result).toContain('export const aUser'); + expect(result).not.toContain('export const anAvatar'); + expect(result).not.toContain('export const aPrefixedResponse'); +});