Skip to content

Commit 4494ae4

Browse files
authored
fix(enumValues): update behaviour to match typescript plugin (#103)
There was some differences with typescript plugin when we were generating enum values. For example `_id` was transformed to `Id` by typescript plugin, but we were generating `_Id` We now use the same logic as typescript plugin, and changed the default to use `change-case-all#pascalCase` as the `change-case-all` package supports a lot of case converter. We also use dynamic module resolution so you can pass anything in `enumValues` as long as it's compatible with `module#function` syntax Fixes #82
1 parent 2521dea commit 4494ae4

File tree

10 files changed

+1215
-191
lines changed

10 files changed

+1215
-191
lines changed

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,21 @@ typescript definition from `@graphql-codegen/typescript`
3232

3333
How many elements should be generated for lists. For example, with `listElementCount: 3` a schema field `names: [String!]!` would generate `3` names in each mock.
3434

35-
### enumValues (`string`, defaultValue: `pascal-case#pascalCase`)
35+
### enumValues (`string`, defaultValue: `change-case-all#pascalCase`)
3636

37-
Changes the case of the enums. Accepts `upper-case#upperCase`, `pascal-case#pascalCase` or `keep`
37+
Changes the case of the enums. The format of the converter must be a valid `module#method`. You can also use `keep` to
38+
keep all GraphQL names as-is. Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`,
39+
`dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`,
40+
`localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`
41+
[See more](https://github.com/btxtiger/change-case-all)
3842

39-
### typenames (`string`, defaultValue: `pascal-case#pascalCase`)
43+
### typenames (`string`, defaultValue: `change-case-all#pascalCase`)
4044

41-
Changes the case of the enums. Accepts `upper-case#upperCase`, `pascal-case#pascalCase` or `keep`
45+
Changes the case of types. The format of the converter must be a valid `module#method`. You can also use `keep` to
46+
keep all GraphQL names as-is. Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`,
47+
`dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`,
48+
`localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`
49+
[See more](https://github.com/btxtiger/change-case-all)
4250

4351
### scalars (`{ [Scalar: string]: ScalarDefinition }`, defaultValue: `undefined`)
4452

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
],
2424
"dependencies": {
2525
"@faker-js/faker": "^7.5.0",
26-
"@graphql-codegen/plugin-helpers": "^2.4.1",
26+
"@graphql-codegen/plugin-helpers": "^2.7.2",
2727
"casual": "^1.6.2",
28+
"change-case-all": "^1.0.15",
2829
"indefinite": "^2.4.1",
2930
"pascal-case": "^3.1.1",
3031
"sentence-case": "^3.0.3",
@@ -36,7 +37,8 @@
3637
},
3738
"devDependencies": {
3839
"@auto-it/conventional-commits": "^10.33.0",
39-
"@graphql-codegen/testing": "^1.17.7",
40+
"@graphql-codegen/testing": "^1.18.0",
41+
"@graphql-codegen/typescript": "^2.8.3",
4042
"@types/jest": "^27.0.2",
4143
"@typescript-eslint/eslint-plugin": "^5.1.0",
4244
"@typescript-eslint/parser": "^5.1.0",
@@ -50,6 +52,7 @@
5052
"graphql": "^16.3.0",
5153
"husky": "^7.0.0",
5254
"jest": "^27.3.1",
55+
"jest-diff": "^27.5.1",
5356
"lint-staged": "^11.2.3",
5457
"prettier": "^2.4.1",
5558
"prettier-config-landr": "^0.2.0",

src/index.ts

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { ASTKindToNode, ListTypeNode, NamedTypeNode, parse, printSchema, TypeNode } from 'graphql';
22
import { faker } from '@faker-js/faker';
33
import casual from 'casual';
4-
import { PluginFunction, oldVisit } from '@graphql-codegen/plugin-helpers';
5-
import { pascalCase } from 'pascal-case';
6-
import { upperCase } from 'upper-case';
4+
import { PluginFunction, oldVisit, resolveExternalModuleAndFn } from '@graphql-codegen/plugin-helpers';
75
import { sentenceCase } from 'sentence-case';
86
import a from 'indefinite';
97
import { setupFunctionTokens, setupMockValueGenerator } from './mockValueGenerator';
108

11-
type NamingConvention = 'upper-case#upperCase' | 'pascal-case#pascalCase' | 'keep';
9+
type NamingConvention = 'change-case-all#pascalCase' | 'keep' | string;
1210

1311
type Options<T = TypeNode> = {
1412
typeName: string;
@@ -42,18 +40,10 @@ const convertName = (value: string, fn: (v: string) => string, transformUndersco
4240
const createNameConverter =
4341
(convention: NamingConvention, transformUnderscore: boolean) =>
4442
(value: string, prefix = '') => {
45-
switch (convention) {
46-
case 'upper-case#upperCase': {
47-
return `${prefix}${convertName(value, (s) => upperCase(s || ''), transformUnderscore)}`;
48-
}
49-
case 'keep':
50-
return `${prefix}${value}`;
51-
case 'pascal-case#pascalCase':
52-
// fallthrough
53-
default:
54-
// default to pascal case in case of unknown values
55-
return `${prefix}${convertName(value, (s) => pascalCase(s || ''), transformUnderscore)}`;
43+
if (convention === 'keep') {
44+
return `${prefix}${value}`;
5645
}
46+
return `${prefix}${convertName(value, resolveExternalModuleAndFn(convention), transformUnderscore)}`;
5747
};
5848

5949
const toMockName = (typedName: string, casedName: string, prefix?: string) => {
@@ -64,19 +54,6 @@ const toMockName = (typedName: string, casedName: string, prefix?: string) => {
6454
return `${a(firstWord, { articleOnly: true })}${casedName}`;
6555
};
6656

67-
const updateTextCase = (str: string, enumValuesConvention: NamingConvention, transformUnderscore: boolean) => {
68-
const convert = createNameConverter(enumValuesConvention, transformUnderscore);
69-
70-
if (str.charAt(0) === '_') {
71-
return str.replace(
72-
/^(_*)(.*)/,
73-
(_match, underscorePrefix, typeName) => `${underscorePrefix}${convert(typeName)}`,
74-
);
75-
}
76-
77-
return convert(str);
78-
};
79-
8057
const hashedString = (value: string) => {
8158
let hash = 0;
8259
if (value.length === 0) {
@@ -180,7 +157,6 @@ const getCustomScalarValue = (customScalar: ScalarDefinition, opts: Options<Name
180157
return getCasualCustomScalarValue(customScalar, opts);
181158
}
182159

183-
184160
if (opts.generateLibrary === 'faker') {
185161
return getFakerCustomScalarValue(customScalar, opts);
186162
}
@@ -231,12 +207,9 @@ const getNamedType = (opts: Options<NamedTypeNode>): string | number | boolean =
231207
opts.typenamesConvention,
232208
opts.transformUnderscore,
233209
);
210+
const enumConverter = createNameConverter(opts.enumValuesConvention, opts.transformUnderscore);
234211
const value = foundType.values ? foundType.values[0] : '';
235-
return `${typenameConverter(foundType.name, opts.enumsPrefix)}.${updateTextCase(
236-
value,
237-
opts.enumValuesConvention,
238-
true,
239-
)}`;
212+
return `${typenameConverter(foundType.name, opts.enumsPrefix)}.${enumConverter(value)}`;
240213
}
241214
case 'union':
242215
// Return the first union type node.
@@ -440,8 +413,8 @@ export const plugin: PluginFunction<TypescriptMocksPluginConfig> = (schema, docu
440413
const printedSchema = printSchema(schema); // Returns a string representation of the schema
441414
const astNode = parse(printedSchema); // Transforms the string into ASTNode
442415

443-
const enumValuesConvention = config.enumValues || 'pascal-case#pascalCase';
444-
const typenamesConvention = config.typenames || 'pascal-case#pascalCase';
416+
const enumValuesConvention = config.enumValues || 'change-case-all#pascalCase';
417+
const typenamesConvention = config.typenames || 'change-case-all#pascalCase';
445418
const transformUnderscore = config.transformUnderscore ?? true;
446419
const listElementCount = config.listElementCount > 0 ? config.listElementCount : 1;
447420
const dynamicValues = !!config.dynamicValues;

tests/__snapshots__/typescript-mock-data.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2546,7 +2546,7 @@ export const aUser = (overrides?: Partial<User>): User => {
25462546
scalarValue: overrides && overrides.hasOwnProperty('scalarValue') ? overrides.scalarValue! : 'neque',
25472547
camelCaseThing: overrides && overrides.hasOwnProperty('camelCaseThing') ? overrides.camelCaseThing! : aCamelCaseThing(),
25482548
unionThing: overrides && overrides.hasOwnProperty('unionThing') ? overrides.unionThing! : anAvatar(),
2549-
prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : Prefixed_Enum.PrefixedValue,
2549+
prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : Prefixed_Enum.Prefixed_Value,
25502550
};
25512551
};
25522552

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`enumValues config having 'change-case-all#pascalCase' value should keep underscores if 'transformUnderscore' is false 1`] = `
4+
"
5+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
6+
return {
7+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._Id,
8+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
9+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase,
10+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.Snake_Case,
11+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.Screaming_Snake_Case,
12+
};
13+
};
14+
"
15+
`;
16+
17+
exports[`enumValues config having 'change-case-all#pascalCase' value should update case in pascal case 1`] = `
18+
"
19+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
20+
return {
21+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id,
22+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
23+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase,
24+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase,
25+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase,
26+
};
27+
};
28+
"
29+
`;
30+
31+
exports[`enumValues config having 'change-case-all#upperCase' value should keep underscores if 'transformUnderscore' is false 1`] = `
32+
"
33+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
34+
return {
35+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._ID,
36+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PASCALCASE,
37+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CAMELCASE,
38+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SNAKE_CASE,
39+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE,
40+
};
41+
};
42+
"
43+
`;
44+
45+
exports[`enumValues config having 'change-case-all#upperCase' value should update case in upper case 1`] = `
46+
"
47+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
48+
return {
49+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._ID,
50+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PASCALCASE,
51+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CAMELCASE,
52+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SNAKE_CASE,
53+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE,
54+
};
55+
};
56+
"
57+
`;
58+
59+
exports[`enumValues config having 'keep' value should have no effect if 'transformUnderscore' is false 1`] = `
60+
"
61+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
62+
return {
63+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._id,
64+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
65+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.camelCase,
66+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.snake_case,
67+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE,
68+
};
69+
};
70+
"
71+
`;
72+
73+
exports[`enumValues config having 'keep' value should keep case 1`] = `
74+
"
75+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
76+
return {
77+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._id,
78+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
79+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.camelCase,
80+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.snake_case,
81+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE,
82+
};
83+
};
84+
"
85+
`;
86+
87+
exports[`enumValues config having default value should keep underscores if 'transformUnderscore' is false 1`] = `
88+
"
89+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
90+
return {
91+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._Id,
92+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
93+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase,
94+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.Snake_Case,
95+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.Screaming_Snake_Case,
96+
};
97+
};
98+
"
99+
`;
100+
101+
exports[`enumValues config having default value should update case in pascal case 1`] = `
102+
"
103+
export const aMyType = (overrides?: Partial<MyType>): MyType => {
104+
return {
105+
underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id,
106+
pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase,
107+
camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase,
108+
snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase,
109+
screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase,
110+
};
111+
};
112+
"
113+
`;

tests/enumValues/schema.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { buildSchema } from 'graphql';
2+
3+
export default buildSchema(/* GraphQL */ `
4+
enum UnderscoreEnum {
5+
_id
6+
}
7+
8+
enum PascalCaseEnum {
9+
PascalCase
10+
}
11+
12+
enum CamelCaseEnum {
13+
camelCase
14+
}
15+
16+
enum SnakeCaseEnum {
17+
snake_case
18+
}
19+
20+
enum ScreamingSnakeCaseEnum {
21+
SCREAMING_SNAKE_CASE
22+
}
23+
24+
type MyType {
25+
underscoreEnum: UnderscoreEnum!
26+
pascalCaseEnum: PascalCaseEnum!
27+
camelCaseEnum: CamelCaseEnum!
28+
snakeCaseEnum: SnakeCaseEnum!
29+
screamingSnakeCaseEnum: ScreamingSnakeCaseEnum!
30+
}
31+
`);

0 commit comments

Comments
 (0)