From 5b1038787da21f80726a5f5d1a79408e0cd5a91a Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Thu, 23 Mar 2023 14:15:46 +0200 Subject: [PATCH 01/10] add support for useImplementingTypes --- src/index.ts | 104 +++++++++++++----- .../__snapshots__/spec.ts.snap | 83 ++++++++++++++ tests/useImplementingTypes/schema.ts | 35 ++++++ tests/useImplementingTypes/spec.ts | 26 +++++ 4 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 tests/useImplementingTypes/__snapshots__/spec.ts.snap create mode 100644 tests/useImplementingTypes/schema.ts create mode 100644 tests/useImplementingTypes/spec.ts diff --git a/src/index.ts b/src/index.ts index cdfc874..437c9c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,12 @@ -import { ASTKindToNode, ListTypeNode, NamedTypeNode, parse, printSchema, TypeNode } from 'graphql'; +import { + parse, + printSchema, + TypeNode, + ASTKindToNode, + ListTypeNode, + NamedTypeNode, + ObjectTypeDefinitionNode, +} from 'graphql'; import { faker } from '@faker-js/faker'; import casual from 'casual'; import { oldVisit, PluginFunction, resolveExternalModuleAndFn } from '@graphql-codegen/plugin-helpers'; @@ -26,6 +34,7 @@ type Options = { generateLibrary: 'casual' | 'faker'; fieldGeneration?: TypeFieldMap; enumsAsTypes?: boolean; + useImplementingTypes: boolean; }; const convertName = (value: string, fn: (v: string) => string, transformUnderscore: boolean): string => { @@ -230,6 +239,16 @@ const handleValueGeneration = ( return baseGenerator(); }; +const getNamedImplementType = (opts: Options): string => { + if (!opts.currentType || !('name' in opts.currentType)) { + return ''; + } + + const name = opts.currentType.name.value; + const casedName = createNameConverter(opts.typeNamesConvention, opts.transformUnderscore)(name); + return `${toMockName(name, casedName, opts.prefix)}()`; +}; + const getNamedType = (opts: Options): string | number | boolean => { if (!opts.currentType) { return ''; @@ -264,8 +283,14 @@ const getNamedType = (opts: Options): string | number | boolean = return handleValueGeneration(opts, customScalar, mockValueGenerator.integer); } default: { - const foundType = opts.types.find((enumType: TypeItem) => enumType.name === name); - if (foundType) { + const foundTypes = opts.types.filter((enumType: TypeItem) => { + if (enumType.types && 'interfaces' in enumType.types) + return enumType.types.interfaces.every((item) => item.name.value === name); + return enumType.name === name; + }); + + if (foundTypes.length) { + const foundType = foundTypes[0]; switch (foundType.type) { case 'enum': { // It's an enum @@ -300,23 +325,27 @@ const getNamedType = (opts: Options): string | number | boolean = foundType.name === 'Date' ? mockValueGenerator.date : mockValueGenerator.word, ); } + case 'implement': + return foundTypes + .map((implementType: TypeItem) => + getNamedImplementType({ + ...opts, + currentType: implementType.types, + }), + ) + .join(' || '); default: throw `foundType is unknown: ${foundType.name}: ${foundType.type}`; } } if (opts.terminateCircularRelationships) { - return handleValueGeneration( - opts, - null, - () => - `relationshipsToOmit.has('${casedName}') ? {} as ${casedName} : ${toMockName( - name, - casedName, - opts.prefix, - )}({}, relationshipsToOmit)`, - ); + return `relationshipsToOmit.has('${casedName}') ? {} as ${casedName} : ${toMockName( + name, + casedName, + opts.prefix, + )}({}, relationshipsToOmit)`; } else { - return handleValueGeneration(opts, null, () => `${toMockName(name, casedName, opts.prefix)}()`); + return `${toMockName(name, casedName, opts.prefix)}()`; } } } @@ -470,13 +499,14 @@ export interface TypescriptMocksPluginConfig { fieldGeneration?: TypeFieldMap; locale?: string; enumsAsTypes?: boolean; + useImplementingTypes?: boolean; } interface TypeItem { name: string; - type: 'enum' | 'scalar' | 'union'; + type: 'enum' | 'scalar' | 'union' | 'implement'; values?: string[]; - types?: readonly NamedTypeNode[]; + types?: readonly NamedTypeNode[] | ObjectTypeDefinitionNode; } type VisitFn = ( @@ -516,6 +546,7 @@ export const plugin: PluginFunction = (schema, docu const dynamicValues = !!config.dynamicValues; const generateLibrary = config.generateLibrary || 'casual'; const enumsAsTypes = config.enumsAsTypes ?? false; + const useImplementingTypes = config.useImplementingTypes ?? false; if (generateLibrary === 'faker' && config.locale) { faker.setLocale(config.locale); @@ -523,7 +554,7 @@ export const plugin: PluginFunction = (schema, docu // List of types that are enums const types: TypeItem[] = []; - const visitor: VisitorType = { + const typeVisitor: VisitorType = { EnumTypeDefinition: (node) => { const name = node.name.value; if (!types.find((enumType: TypeItem) => enumType.name === name)) { @@ -544,6 +575,32 @@ export const plugin: PluginFunction = (schema, docu }); } }, + ObjectTypeDefinition: (node) => { + // This function triggered per each type + const typeName = node.name.value; + + if (config.useImplementingTypes) { + if (!types.find((enumType) => enumType.name === typeName)) { + node.interfaces.length && + types.push({ + name: typeName, + type: 'implement', + types: node, + }); + } + } + }, + ScalarTypeDefinition: (node) => { + const name = node.name.value; + if (!types.find((enumType) => enumType.name === name)) { + types.push({ + name, + type: 'scalar', + }); + } + }, + }; + const visitor: VisitorType = { FieldDefinition: (node) => { const fieldName = node.name.value; @@ -568,6 +625,7 @@ export const plugin: PluginFunction = (schema, docu generateLibrary, fieldGeneration: config.fieldGeneration, enumsAsTypes, + useImplementingTypes, }); return ` ${fieldName}: overrides && overrides.hasOwnProperty('${fieldName}') ? overrides.${fieldName}! : ${value},`; @@ -601,6 +659,7 @@ export const plugin: PluginFunction = (schema, docu generateLibrary, fieldGeneration: config.fieldGeneration, enumsAsTypes, + useImplementingTypes, }); return ` ${field.name.value}: overrides && overrides.hasOwnProperty('${field.name.value}') ? overrides.${field.name.value}! : ${value},`; @@ -665,17 +724,10 @@ export const plugin: PluginFunction = (schema, docu }, }; }, - ScalarTypeDefinition: (node) => { - const name = node.name.value; - if (!types.find((enumType) => enumType.name === name)) { - types.push({ - name, - type: 'scalar', - }); - } - }, }; + // run on the types first + oldVisit(astNode, { leave: typeVisitor }); const result = oldVisit(astNode, { leave: visitor }); const definitions = result.definitions.filter((definition: any) => !!definition); const typesFile = config.typesFile ? config.typesFile.replace(/\.[\w]+$/, '') : null; diff --git a/tests/useImplementingTypes/__snapshots__/spec.ts.snap b/tests/useImplementingTypes/__snapshots__/spec.ts.snap new file mode 100644 index 0000000..2d0640c --- /dev/null +++ b/tests/useImplementingTypes/__snapshots__/spec.ts.snap @@ -0,0 +1,83 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should support useImplementingTypes 1`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(), + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; + +exports[`shouldn't support useImplementingTypes 1`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; diff --git a/tests/useImplementingTypes/schema.ts b/tests/useImplementingTypes/schema.ts new file mode 100644 index 0000000..6cd59ea --- /dev/null +++ b/tests/useImplementingTypes/schema.ts @@ -0,0 +1,35 @@ +import { buildSchema } from 'graphql'; + +export default buildSchema(/* GraphQL */ ` + interface AConfig { + configTypes: [configTypes!]! + } + + enum configTypes { + TEST + TEST2 + } + + type A { + id: ID! + str: String! + obj: B! + config: AConfig! + } + + type B { + int: Int! + flt: Float! + bool: Boolean! + } + + type TestAConfig implements AConfig { + detectionTypes: [configTypes!]! + active: Boolean! + } + + type TestTwoAConfig implements AConfig { + detectionTypes: [configTypes!]! + username: String! + } +`); diff --git a/tests/useImplementingTypes/spec.ts b/tests/useImplementingTypes/spec.ts new file mode 100644 index 0000000..1645a49 --- /dev/null +++ b/tests/useImplementingTypes/spec.ts @@ -0,0 +1,26 @@ +import { plugin } from '../../src'; +import testSchema from './schema'; + +it('should support useImplementingTypes', async () => { + const result = await plugin(testSchema, [], { prefix: 'mock', useImplementingTypes: true }); + + expect(result).toBeDefined(); + // Boolean + expect(result).toContain( + "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(),", + ); + + expect(result).toMatchSnapshot(); +}); + +it(`shouldn't support useImplementingTypes`, async () => { + const result = await plugin(testSchema, [], { prefix: 'mock' }); + + expect(result).toBeDefined(); + // Boolean + expect(result).toContain( + "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(),", + ); + + expect(result).toMatchSnapshot(); +}); From 152b4d8cf2d9c7e1c10a637fe1fcbe566b6e7c0e Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Thu, 23 Mar 2023 16:20:37 +0200 Subject: [PATCH 02/10] git fix types --- src/index.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index 437c9c8..16f236a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -246,6 +246,7 @@ const getNamedImplementType = (opts: Options): string => { const name = opts.currentType.name.value; const casedName = createNameConverter(opts.typeNamesConvention, opts.transformUnderscore)(name); + return `${toMockName(name, casedName, opts.prefix)}()`; }; @@ -339,13 +340,18 @@ const getNamedType = (opts: Options): string | number | boolean = } } if (opts.terminateCircularRelationships) { - return `relationshipsToOmit.has('${casedName}') ? {} as ${casedName} : ${toMockName( - name, - casedName, - opts.prefix, - )}({}, relationshipsToOmit)`; + return handleValueGeneration( + opts, + null, + () => + `relationshipsToOmit.has('${casedName}') ? {} as ${casedName} : ${toMockName( + name, + casedName, + opts.prefix, + )}({}, relationshipsToOmit)`, + ); } else { - return `${toMockName(name, casedName, opts.prefix)}()`; + return handleValueGeneration(opts, null, () => `${toMockName(name, casedName, opts.prefix)}()`); } } } @@ -579,8 +585,8 @@ export const plugin: PluginFunction = (schema, docu // This function triggered per each type const typeName = node.name.value; - if (config.useImplementingTypes) { - if (!types.find((enumType) => enumType.name === typeName)) { + if (config.useImplementingTypes && config.fieldGeneration) { + if (!types.find((objectType) => objectType.name === typeName)) { node.interfaces.length && types.push({ name: typeName, @@ -592,7 +598,7 @@ export const plugin: PluginFunction = (schema, docu }, ScalarTypeDefinition: (node) => { const name = node.name.value; - if (!types.find((enumType) => enumType.name === name)) { + if (!types.find((scalarType) => scalarType.name === name)) { types.push({ name, type: 'scalar', From 56619a4cd573e2e8b525e4c373fdf14989722a90 Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Thu, 23 Mar 2023 20:01:37 +0200 Subject: [PATCH 03/10] fix type name --- src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 16f236a..4cf3296 100644 --- a/src/index.ts +++ b/src/index.ts @@ -284,10 +284,10 @@ const getNamedType = (opts: Options): string | number | boolean = return handleValueGeneration(opts, customScalar, mockValueGenerator.integer); } default: { - const foundTypes = opts.types.filter((enumType: TypeItem) => { - if (enumType.types && 'interfaces' in enumType.types) - return enumType.types.interfaces.every((item) => item.name.value === name); - return enumType.name === name; + const foundTypes = opts.types.filter((foundType: TypeItem) => { + if (foundType.types && 'interfaces' in foundType.types) + return foundType.types.interfaces.every((item) => item.name.value === name); + return foundType.name === name; }); if (foundTypes.length) { From 6d935c588c40623e2ea20fbcb3ead98ccdd386e8 Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Thu, 23 Mar 2023 20:15:28 +0200 Subject: [PATCH 04/10] fix test --- tests/perTypeFieldGeneration/spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perTypeFieldGeneration/spec.ts b/tests/perTypeFieldGeneration/spec.ts index 54d970d..3679b08 100644 --- a/tests/perTypeFieldGeneration/spec.ts +++ b/tests/perTypeFieldGeneration/spec.ts @@ -421,7 +421,7 @@ describe('per type field generation with faker', () => { expect(result).toBeDefined(); expect(result).toContain( - "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '01/01/2022'", + "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '1/1/2022'", ); expect(result).toMatchSnapshot(); From 8f129720e103fa08b9700d8eaf81a2b8c7692f71 Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Fri, 24 Mar 2023 01:47:03 +0200 Subject: [PATCH 05/10] add test --- src/index.ts | 2 +- tests/perTypeFieldGeneration/spec.ts | 2 +- .../__snapshots__/spec.ts.snap | 164 ++++++++++++++++++ tests/useImplementingTypes/spec.ts | 17 ++ 4 files changed, 183 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 4cf3296..eec2e1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -585,7 +585,7 @@ export const plugin: PluginFunction = (schema, docu // This function triggered per each type const typeName = node.name.value; - if (config.useImplementingTypes && config.fieldGeneration) { + if (config.useImplementingTypes && !config.fieldGeneration) { if (!types.find((objectType) => objectType.name === typeName)) { node.interfaces.length && types.push({ diff --git a/tests/perTypeFieldGeneration/spec.ts b/tests/perTypeFieldGeneration/spec.ts index 3679b08..54d970d 100644 --- a/tests/perTypeFieldGeneration/spec.ts +++ b/tests/perTypeFieldGeneration/spec.ts @@ -421,7 +421,7 @@ describe('per type field generation with faker', () => { expect(result).toBeDefined(); expect(result).toContain( - "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '1/1/2022'", + "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '01/01/2022'", ); expect(result).toMatchSnapshot(); diff --git a/tests/useImplementingTypes/__snapshots__/spec.ts.snap b/tests/useImplementingTypes/__snapshots__/spec.ts.snap index 2d0640c..e3bf704 100644 --- a/tests/useImplementingTypes/__snapshots__/spec.ts.snap +++ b/tests/useImplementingTypes/__snapshots__/spec.ts.snap @@ -41,6 +41,47 @@ export const mockTestTwoAConfig = (overrides?: Partial): TestTwo " `; +exports[`shouldn't support useImplementingTypes 1`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; + exports[`shouldn't support useImplementingTypes 1`] = ` " export const mockAConfig = (overrides?: Partial): AConfig => { @@ -81,3 +122,126 @@ export const mockTestTwoAConfig = (overrides?: Partial): TestTwo }; " `; + +exports[`shouldn't support useImplementingTypes 2`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; + +exports[`shouldn't support useImplementingTypes with fieldGeneration prop 1`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Karelle_Kassulke@Carolyne.io', + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; + +exports[`shouldn't support useImplementingTypes with fieldGeneration props 1`] = ` +" +export const mockAConfig = (overrides?: Partial): AConfig => { + return { + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], + }; +}; + +export const mockA = (overrides?: Partial): A => { + return { + id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', + str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', + obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), + config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), + }; +}; + +export const mockB = (overrides?: Partial): B => { + return { + int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, + flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, + bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, + }; +}; + +export const mockTestAConfig = (overrides?: Partial): TestAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, + }; +}; + +export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { + return { + detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', + }; +}; +" +`; diff --git a/tests/useImplementingTypes/spec.ts b/tests/useImplementingTypes/spec.ts index 1645a49..6249fcd 100644 --- a/tests/useImplementingTypes/spec.ts +++ b/tests/useImplementingTypes/spec.ts @@ -24,3 +24,20 @@ it(`shouldn't support useImplementingTypes`, async () => { expect(result).toMatchSnapshot(); }); + +it(`shouldn't support useImplementingTypes with fieldGeneration prop`, async () => { + const result = await plugin(testSchema, [], { + prefix: 'mock', + useImplementingTypes: true, + fieldGeneration: { + A: { config: 'email' }, + }, + }); + expect(result).toBeDefined(); + // Boolean + expect(result).toContain( + "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Karelle_Kassulke@Carolyne.io'", + ); + + expect(result).toMatchSnapshot(); +}); From 94b12756d5ed12d8fe0dcab7c07f3867a02af6f2 Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Sun, 2 Apr 2023 03:55:25 +0300 Subject: [PATCH 06/10] useImplementingTypes with fieldGeneration --- src/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index eec2e1d..3927167 100644 --- a/src/index.ts +++ b/src/index.ts @@ -327,6 +327,13 @@ const getNamedType = (opts: Options): string | number | boolean = ); } case 'implement': + if ( + opts.fieldGeneration && + opts.fieldGeneration[opts.typeName] && + opts.fieldGeneration[opts.typeName][opts.fieldName] + ) + break; + return foundTypes .map((implementType: TypeItem) => getNamedImplementType({ @@ -585,7 +592,7 @@ export const plugin: PluginFunction = (schema, docu // This function triggered per each type const typeName = node.name.value; - if (config.useImplementingTypes && !config.fieldGeneration) { + if (config.useImplementingTypes) { if (!types.find((objectType) => objectType.name === typeName)) { node.interfaces.length && types.push({ From 6631b2da72da92a6106f7c19fe2fbc59bc353081 Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Sun, 2 Apr 2023 03:55:46 +0300 Subject: [PATCH 07/10] fix test, schema and snap --- .../__snapshots__/spec.ts.snap | 88 +------------------ tests/useImplementingTypes/schema.ts | 4 +- tests/useImplementingTypes/spec.ts | 31 +++++-- 3 files changed, 30 insertions(+), 93 deletions(-) diff --git a/tests/useImplementingTypes/__snapshots__/spec.ts.snap b/tests/useImplementingTypes/__snapshots__/spec.ts.snap index e3bf704..3cb7c52 100644 --- a/tests/useImplementingTypes/__snapshots__/spec.ts.snap +++ b/tests/useImplementingTypes/__snapshots__/spec.ts.snap @@ -26,56 +26,15 @@ export const mockB = (overrides?: Partial): B => { }; export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, - }; -}; - -export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', - }; -}; -" -`; - -exports[`shouldn't support useImplementingTypes 1`] = ` -" -export const mockAConfig = (overrides?: Partial): AConfig => { return { configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], - }; -}; - -export const mockA = (overrides?: Partial): A => { - return { - id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', - str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', - obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), - config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), - }; -}; - -export const mockB = (overrides?: Partial): B => { - return { - int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, - flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, - bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, - }; -}; - -export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, }; }; export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', }; }; @@ -164,7 +123,7 @@ export const mockTestTwoAConfig = (overrides?: Partial): TestTwo " `; -exports[`shouldn't support useImplementingTypes with fieldGeneration prop 1`] = ` +exports[`support useImplementingTypes with fieldGeneration prop 1`] = ` " export const mockAConfig = (overrides?: Partial): AConfig => { return { @@ -190,56 +149,15 @@ export const mockB = (overrides?: Partial): B => { }; export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, - }; -}; - -export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', - }; -}; -" -`; - -exports[`shouldn't support useImplementingTypes with fieldGeneration props 1`] = ` -" -export const mockAConfig = (overrides?: Partial): AConfig => { return { configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], - }; -}; - -export const mockA = (overrides?: Partial): A => { - return { - id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', - str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', - obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), - config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), - }; -}; - -export const mockB = (overrides?: Partial): B => { - return { - int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, - flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, - bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, - }; -}; - -export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, }; }; export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', }; }; diff --git a/tests/useImplementingTypes/schema.ts b/tests/useImplementingTypes/schema.ts index 6cd59ea..f5a7e21 100644 --- a/tests/useImplementingTypes/schema.ts +++ b/tests/useImplementingTypes/schema.ts @@ -24,12 +24,12 @@ export default buildSchema(/* GraphQL */ ` } type TestAConfig implements AConfig { - detectionTypes: [configTypes!]! + configTypes: [configTypes!]! active: Boolean! } type TestTwoAConfig implements AConfig { - detectionTypes: [configTypes!]! + configTypes: [configTypes!]! username: String! } `); diff --git a/tests/useImplementingTypes/spec.ts b/tests/useImplementingTypes/spec.ts index 6249fcd..d907994 100644 --- a/tests/useImplementingTypes/spec.ts +++ b/tests/useImplementingTypes/spec.ts @@ -5,7 +5,7 @@ it('should support useImplementingTypes', async () => { const result = await plugin(testSchema, [], { prefix: 'mock', useImplementingTypes: true }); expect(result).toBeDefined(); - // Boolean + expect(result).toContain( "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(),", ); @@ -17,7 +17,7 @@ it(`shouldn't support useImplementingTypes`, async () => { const result = await plugin(testSchema, [], { prefix: 'mock' }); expect(result).toBeDefined(); - // Boolean + expect(result).toContain( "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(),", ); @@ -25,8 +25,25 @@ it(`shouldn't support useImplementingTypes`, async () => { expect(result).toMatchSnapshot(); }); -it(`shouldn't support useImplementingTypes with fieldGeneration prop`, async () => { - const result = await plugin(testSchema, [], { +it(`support useImplementingTypes with fieldGeneration prop`, async () => { + let result = await plugin(testSchema, [], { + prefix: 'mock', + useImplementingTypes: true, + fieldGeneration: { + A: { str: 'email' }, + }, + }); + expect(result).toBeDefined(); + + expect(result).toContain( + "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Krystel.Farrell@Frederique.biz'", + ); + + expect(result).toContain( + "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(),", + ); + + result = await plugin(testSchema, [], { prefix: 'mock', useImplementingTypes: true, fieldGeneration: { @@ -34,9 +51,11 @@ it(`shouldn't support useImplementingTypes with fieldGeneration prop`, async () }, }); expect(result).toBeDefined(); - // Boolean + + expect(result).toContain("str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea'"); + expect(result).toContain( - "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Karelle_Kassulke@Carolyne.io'", + "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Karelle_Kassulke@Carolyne.io',", ); expect(result).toMatchSnapshot(); From 2cd61176cd9a31051218a5f5eff74cd63e86996f Mon Sep 17 00:00:00 2001 From: Maor Daniel Date: Mon, 3 Apr 2023 19:28:37 +0300 Subject: [PATCH 08/10] update snapshot --- .../__snapshots__/spec.ts.snap | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/tests/useImplementingTypes/__snapshots__/spec.ts.snap b/tests/useImplementingTypes/__snapshots__/spec.ts.snap index 3cb7c52..071e5fa 100644 --- a/tests/useImplementingTypes/__snapshots__/spec.ts.snap +++ b/tests/useImplementingTypes/__snapshots__/spec.ts.snap @@ -67,56 +67,15 @@ export const mockB = (overrides?: Partial): B => { }; export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, - }; -}; - -export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], - username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', - }; -}; -" -`; - -exports[`shouldn't support useImplementingTypes 2`] = ` -" -export const mockAConfig = (overrides?: Partial): AConfig => { return { configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], - }; -}; - -export const mockA = (overrides?: Partial): A => { - return { - id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'cae147b0-1c04-459e-82db-624dd87433b4', - str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea', - obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), - config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), - }; -}; - -export const mockB = (overrides?: Partial): B => { - return { - int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 696, - flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.55, - bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, - }; -}; - -export const mockTestAConfig = (overrides?: Partial): TestAConfig => { - return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, }; }; export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { return { - detectionTypes: overrides && overrides.hasOwnProperty('detectionTypes') ? overrides.detectionTypes! : [ConfigTypes.Test], + configTypes: overrides && overrides.hasOwnProperty('configTypes') ? overrides.configTypes! : [ConfigTypes.Test], username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'et', }; }; From ccaf619cfaef0e7206f673685e0a2b45adf17558 Mon Sep 17 00:00:00 2001 From: Maor Daniel <47079236+maordaniel@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:09:28 +0300 Subject: [PATCH 09/10] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 22b7fa9..f34a788 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,11 @@ When disabled, underscores will be retained for type names when the case is chan When enabled, values will be generated dynamically when the mock function is called rather than statically when the mock function is generated. The values are generated consistently from a [casual seed](https://github.com/boo1ean/casual#seeding) that can be manually configured using the generated `seedMocks(seed: number)` function, as shown in [this test](https://github.com/JimmyPaolini/graphql-codegen-typescript-mock-data/blob/dynamic-mode/tests/dynamicValues/spec.ts#L13). +###useImplementingTypes (`boolean`, defaultValue: `false`) + +When enabled, it will support the useImplementingTypes GraphQL codegen configuration. +- When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself. + ### fieldGeneration (`{ [typeName: string]: { [fieldName: string]: GeneratorOptions } }`, defaultValue: `undefined`) This setting allows you to add specific generation to a field for a given type. For example if you have a type called `User` and a field called `birthDate` you can override any generated value there as follows: From b151cc6061fe7cf71269b447e35434b5875f54f4 Mon Sep 17 00:00:00 2001 From: Maor Daniel <47079236+maordaniel@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:12:01 +0300 Subject: [PATCH 10/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f34a788..ce194f3 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ When disabled, underscores will be retained for type names when the case is chan When enabled, values will be generated dynamically when the mock function is called rather than statically when the mock function is generated. The values are generated consistently from a [casual seed](https://github.com/boo1ean/casual#seeding) that can be manually configured using the generated `seedMocks(seed: number)` function, as shown in [this test](https://github.com/JimmyPaolini/graphql-codegen-typescript-mock-data/blob/dynamic-mode/tests/dynamicValues/spec.ts#L13). -###useImplementingTypes (`boolean`, defaultValue: `false`) +### useImplementingTypes (`boolean`, defaultValue: `false`) When enabled, it will support the useImplementingTypes GraphQL codegen configuration. - When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself.