Skip to content

Commit

Permalink
chore: add more tests and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
s.vanriessen committed Sep 20, 2024
1 parent 69fd16c commit b27e199
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 31 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,26 @@ export const aUser = (overrides?: Partial<User>): User => {
}
```
### typeNamesMapping (`{ [typeName: string]: string }`, defaultValue: `{}`)
Allows you to define mappings to rename the types. This is useful when you want to override the generated type name. For example, if you have a type called `User` and you want to rename it to `RenamedUser` you can do the following:
```
plugins:
- typescript-mock-data:
typesFile: '../generated-types.ts'
typeNamesMapping:
User: RenamedUser
```
This will generate the following mock function:
```
export const aUser = (overrides?: Partial<RenamedUser>): RenamedUser => {
```
**Note:** It is not possible to rename your enums using this option.
### transformUnderscore (`boolean`, defaultValue: `true`)
When disabled, underscores will be retained for type names when the case is changed. It has no effect if `typeNames` is set to `keep`.
Expand Down
51 changes: 33 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Options<T = TypeNode> = {
useImplementingTypes: boolean;
defaultNullableToNull: boolean;
nonNull: boolean;
typeNamesMapping?: Record<string, string>;
};

const getTerminateCircularRelationshipsConfig = ({ terminateCircularRelationships }: TypescriptMocksPluginConfig) =>
Expand All @@ -64,6 +65,15 @@ const createNameConverter =
return `${prefix}${convertName(value, resolveExternalModuleAndFn(convention), transformUnderscore)}`;
};

const renameImports = (list: string[], typeNamesMapping: Record<string, string>) => {
return list.map((type) => {
if (typeNamesMapping && typeNamesMapping[type]) {
return `${type} as ${typeNamesMapping[type]}`;
}
return type;
});
};

const toMockName = (typedName: string, casedName: string, prefix?: string) => {
if (prefix) {
return `${prefix}${casedName}`;
Expand Down Expand Up @@ -380,14 +390,20 @@ const getNamedType = (opts: Options<NamedTypeNode | ObjectTypeDefinitionNode>):
opts.typeNamesConvention,
opts.transformUnderscore,
);
const casedNameWithPrefix = typeNameConverter(name, opts.typesPrefix);
const renamedType = renameImports([name], opts.typeNamesMapping)[0];
const casedNameWithPrefix = typeNameConverter(renamedType, opts.typesPrefix);
return `relationshipsToOmit.has('${casedName}') ? {} as ${casedNameWithPrefix} : ${toMockName(
name,
casedName,
opts.prefix,
)}({}, relationshipsToOmit)`;
} else {
return `relationshipsToOmit.has('${casedName}') ? {} as ${casedName} : ${toMockName(
const renamedType = renameImports([name], opts.typeNamesMapping)[0];
const renamedCasedName = createNameConverter(
opts.typeNamesConvention,
opts.transformUnderscore,
)(renamedType);
return `relationshipsToOmit.has('${casedName}') ? {} as ${renamedCasedName} : ${toMockName(
name,
casedName,
opts.prefix,
Expand Down Expand Up @@ -443,10 +459,10 @@ const getMockString = (
prefix,
typesPrefix = '',
transformUnderscore: boolean,
newTypeNames?: Record<string, string>,
typeNamesMapping?: Record<string, string>,
) => {
const typeNameConverter = createNameConverter(typeNamesConvention, transformUnderscore);
const NewTypeName = newTypeNames[typeName] || typeName;
const NewTypeName = typeNamesMapping[typeName] || typeName;
const casedName = typeNameConverter(typeName);
const casedNameWithPrefix = typeNameConverter(NewTypeName, typesPrefix);
const typename = addTypename ? `\n __typename: '${typeName}',` : '';
Expand Down Expand Up @@ -491,7 +507,7 @@ const getImportTypes = ({
transformUnderscore,
enumsAsTypes,
useTypeImports,
newTypeNames,
typeNamesMapping,
}: {
typeNamesConvention: NamingConvention;
definitions: any;
Expand All @@ -502,24 +518,21 @@ const getImportTypes = ({
transformUnderscore: boolean;
enumsAsTypes: boolean;
useTypeImports: boolean;
newTypeNames?: Record<string, string>;
typeNamesMapping?: Record<string, string>;
}) => {
const typenameConverter = createNameConverter(typeNamesConvention, transformUnderscore);
const typeImports = typesPrefix?.endsWith('.')
? [typesPrefix.slice(0, -1)]
: definitions
.filter(({ typeName }: { typeName: string }) => !!typeName)
.map(({ typeName }: { typeName: string }) => typenameConverter(typeName, typesPrefix));
const renamedTypeImports = typeImports.map((type) => {
if (newTypeNames[type]) {
return `${type} as ${newTypeNames[type]}`;
}
return type;
});

const enumTypes = enumsPrefix?.endsWith('.')
? [enumsPrefix.slice(0, -1)]
: types.filter(({ type }) => type === 'enum').map(({ name }) => typenameConverter(name, enumsPrefix));

const renamedTypeImports = renameImports(typeImports, typeNamesMapping);

if (!enumsAsTypes || useTypeImports) {
renamedTypeImports.push(...enumTypes);
}
Expand Down Expand Up @@ -576,7 +589,7 @@ export interface TypescriptMocksPluginConfig {
useImplementingTypes?: boolean;
defaultNullableToNull?: boolean;
useTypeImports?: boolean;
newTypeNames?: Record<string, string>;
typeNamesMapping?: Record<string, string>;
}

interface TypeItem {
Expand Down Expand Up @@ -627,7 +640,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
const useImplementingTypes = config.useImplementingTypes ?? false;
const defaultNullableToNull = config.defaultNullableToNull ?? false;
const generatorLocale = config.locale || 'en';
const newTypeNames = config.newTypeNames || {};
const typeNamesMapping = config.typeNamesMapping || {};

// List of types that are enums
const types: TypeItem[] = [];
Expand Down Expand Up @@ -707,6 +720,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
useImplementingTypes,
defaultNullableToNull,
nonNull: false,
typeNamesMapping: config.typeNamesMapping,
});

return ` ${fieldName}: overrides && overrides.hasOwnProperty('${fieldName}') ? overrides.${fieldName}! : ${value},`;
Expand Down Expand Up @@ -745,6 +759,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
useImplementingTypes,
defaultNullableToNull,
nonNull: false,
typeNamesMapping: config.typeNamesMapping,
});

return ` ${field.name.value}: overrides && overrides.hasOwnProperty('${field.name.value}') ? overrides.${field.name.value}! : ${value},`;
Expand All @@ -761,7 +776,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
config.prefix,
config.typesPrefix,
transformUnderscore,
newTypeNames,
typeNamesMapping,
);
},
};
Expand All @@ -785,7 +800,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
config.prefix,
config.typesPrefix,
transformUnderscore,
newTypeNames,
typeNamesMapping,
);
},
};
Expand All @@ -807,7 +822,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
config.prefix,
config.typesPrefix,
transformUnderscore,
newTypeNames,
typeNamesMapping,
);
},
};
Expand All @@ -830,7 +845,7 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
transformUnderscore: transformUnderscore,
useTypeImports: config.useTypeImports,
enumsAsTypes,
newTypeNames,
typeNamesMapping,
});
// Function that will generate the mocks.
// We generate it after having visited because we need to distinct types from enums
Expand Down
31 changes: 31 additions & 0 deletions tests/typeNamesMapping/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { buildSchema } from 'graphql/index';

export default buildSchema(/* GraphQL */ `
enum EnumExample {
LOREM
IPSUM
}
type A {
id: ID!
str: String!
email: String!
}
type B {
id: ID!
str: String!
email: String!
}
type C {
id: ID!
str: String!
enum: EnumExample!
D: D!
}
type D {
nested: C!
}
`);
36 changes: 36 additions & 0 deletions tests/typeNamesMapping/spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { plugin } from '../../src';
import testSchema from './schema';

it('should support typeNamesMapping', async () => {
const result = await plugin(testSchema, [], {
typesFile: './types/graphql.ts',
typeNamesMapping: { A: 'RenamedAType' },
});

expect(result).toBeDefined();
expect(result).toContain("import { A as RenamedAType, B, C, D, EnumExample } from './types/graphql';");
});

it('should support typeNamesMapping with circular relationships', async () => {
const result = await plugin(testSchema, [], {
typesFile: './types/graphql.ts',
typeNamesMapping: { D: 'RenamedDType' },
terminateCircularRelationships: 'immediate',
});

expect(result).toBeDefined();
expect(result).toContain("import { A, B, C, D as RenamedDType, EnumExample } from './types/graphql';");
expect(result).toContain(
"D: overrides && overrides.hasOwnProperty('D') ? overrides.D! : relationshipsToOmit.has('D') ? {} as DAsRenamedDType : aD({}, relationshipsToOmit),",
);
});

it('should not support typeNamesMapping when enum type is given', async () => {
const result = await plugin(testSchema, [], {
typesFile: './types/graphql.ts',
typeNamesMapping: { EnumExample: 'RenamedEnum' },
});

expect(result).toBeDefined();
expect(result).toContain("import { A, B, C, D, EnumExample } from './types/graphql';");
});
13 changes: 0 additions & 13 deletions tests/useTypeImports/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,3 @@ it('should support useTypeImports', async () => {
);
expect(result).toMatchSnapshot();
});

it('should support useTypeImports', async () => {
const result = await plugin(testSchema, [], {
typesFile: './types/graphql.ts',
useTypeImports: true,
newTypeNames: { Partial: 'RenamedPartial' },
});

expect(result).toBeDefined();
expect(result).toContain(
"import type { Avatar, User, Partial as RenamedPartial, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, Mutation, Query, AbcStatus, Status, PrefixedEnum } from './types/graphql';",
);
});

0 comments on commit b27e199

Please sign in to comment.