diff --git a/packages/typescript-resolver-files-e2e/project.json b/packages/typescript-resolver-files-e2e/project.json index 13a7e887..d8cbf604 100644 --- a/packages/typescript-resolver-files-e2e/project.json +++ b/packages/typescript-resolver-files-e2e/project.json @@ -165,6 +165,13 @@ "rimraf -g \"{projectRoot}/src/test-complex-synth-generic-wrapper/**/*.generated.*\"" ], "parallel": false + }, + "test-resolver-filename-case": { + "commands": [ + "rimraf -g \"{projectRoot}/src/test-resolver-filename-case/**/resolvers/\"", + "rimraf -g \"{projectRoot}/src/test-resolver-filename-case/**/*.generated.*\"" + ], + "parallel": false } } }, @@ -191,7 +198,8 @@ "nx graphql-codegen typescript-resolver-files-e2e -c test-resolvers-auto-wireup --verbose", "nx graphql-codegen typescript-resolver-files-e2e -c test-federation --verbose", "nx graphql-codegen typescript-resolver-files-e2e -c test-deep-modules --verbose", - "nx graphql-codegen typescript-resolver-files-e2e -c test-complex-synth-generic-wrapper --verbose" + "nx graphql-codegen typescript-resolver-files-e2e -c test-complex-synth-generic-wrapper --verbose", + "nx graphql-codegen typescript-resolver-files-e2e -c test-resolver-filename-case --verbose" ], "parallel": false }, @@ -269,6 +277,9 @@ }, "test-complex-synth-generic-wrapper": { "configFile": "{projectRoot}/src/test-complex-synth-generic-wrapper/codegen.ts" + }, + "test-resolver-filename-case": { + "configFile": "{projectRoot}/src/test-resolver-filename-case/codegen.ts" } }, "dependsOn": ["prepare-e2e-modules"] diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/codegen.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/codegen.ts new file mode 100644 index 00000000..fb76b9b3 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/codegen.ts @@ -0,0 +1,24 @@ +import type { CodegenConfig } from '@graphql-codegen/cli'; +import { defineConfig } from '@eddeee888/gcg-typescript-resolver-files'; + +const config: CodegenConfig = { + hooks: { + afterAllFileWrite: ['prettier --write'], + }, + generates: { + 'packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas': + defineConfig( + { + fileOutputCasing: 'kebab-case', + }, + { + schema: [ + 'packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/**/*.graphqls', + 'packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/**/*.graphqls.ts', + ], + } + ), + }, +}; + +export default config; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/base.graphqls b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/base.graphqls new file mode 100644 index 00000000..7756577f --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/base.graphqls @@ -0,0 +1,20 @@ +scalar DateTime + +type Query { + # Simple: "query" -> "query.ts" + query: RandomResult! + # Strange: "api-query.ts" + APIQuery: RandomResult! +} + +type Mutation { + # Strange: "prefixed-api-mutation.ts" + prefixedAPIMutation: RandomResult! +} + +type RandomResult { + id: ID! + name: String! + createdAt: DateTime! + updatedAt: DateTime! +} diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers.generated.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers.generated.ts new file mode 100644 index 00000000..e5be04f5 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers.generated.ts @@ -0,0 +1,25 @@ +/* This file was automatically generated. DO NOT UPDATE MANUALLY. */ +import type { Resolvers } from './types.generated'; +import { APIQuery as Query_APIQuery } from './resolvers/Query/api-query'; +import { query as Query_query } from './resolvers/Query/query'; +import { user as Query_user } from './resolvers/Query/user'; +import { userProfile as Query_userProfile } from './resolvers/Query/user-profile'; +import { prefixedAPIMutation as Mutation_prefixedAPIMutation } from './resolvers/Mutation/prefixed-api-mutation'; +import { RandomResult } from './resolvers/random-result'; +import { User } from './resolvers/user'; +import { UserProfile } from './resolvers/user-profile'; +import { DateTimeResolver } from 'graphql-scalars'; +export const resolvers: Resolvers = { + Query: { + APIQuery: Query_APIQuery, + query: Query_query, + user: Query_user, + userProfile: Query_userProfile, + }, + Mutation: { prefixedAPIMutation: Mutation_prefixedAPIMutation }, + + RandomResult: RandomResult, + User: User, + UserProfile: UserProfile, + DateTime: DateTimeResolver, +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Mutation/prefixed-api-mutation.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Mutation/prefixed-api-mutation.ts new file mode 100644 index 00000000..d9460c6c --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Mutation/prefixed-api-mutation.ts @@ -0,0 +1,6 @@ +import type { MutationResolvers } from './../../types.generated'; +export const prefixedAPIMutation: NonNullable< + MutationResolvers['prefixedAPIMutation'] +> = async (_parent, _arg, _ctx) => { + /* Implement Mutation.prefixedAPIMutation resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/api-query.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/api-query.ts new file mode 100644 index 00000000..8a6d166a --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/api-query.ts @@ -0,0 +1,8 @@ +import type { QueryResolvers } from './../../types.generated'; +export const APIQuery: NonNullable = async ( + _parent, + _arg, + _ctx +) => { + /* Implement Query.APIQuery resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/query.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/query.ts new file mode 100644 index 00000000..982ac809 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/query.ts @@ -0,0 +1,8 @@ +import type { QueryResolvers } from './../../types.generated'; +export const query: NonNullable = async ( + _parent, + _arg, + _ctx +) => { + /* Implement Query.query resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user-profile.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user-profile.ts new file mode 100644 index 00000000..2f7ee56f --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user-profile.ts @@ -0,0 +1,8 @@ +import type { QueryResolvers } from './../../types.generated'; +export const userProfile: NonNullable = async ( + _parent, + _arg, + _ctx +) => { + /* Implement Query.userProfile resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user.ts new file mode 100644 index 00000000..3acc82e4 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/Query/user.ts @@ -0,0 +1,8 @@ +import type { QueryResolvers } from './../../types.generated'; +export const user: NonNullable = async ( + _parent, + _arg, + _ctx +) => { + /* Implement Query.user resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/random-result.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/random-result.ts new file mode 100644 index 00000000..810f27d7 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/random-result.ts @@ -0,0 +1,4 @@ +import type { RandomResultResolvers } from './../types.generated'; +export const RandomResult: RandomResultResolvers = { + /* Implement RandomResult resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user-profile.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user-profile.ts new file mode 100644 index 00000000..de746325 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user-profile.ts @@ -0,0 +1,4 @@ +import type { UserProfileResolvers } from './../types.generated'; +export const UserProfile: UserProfileResolvers = { + /* Implement UserProfile resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user.ts new file mode 100644 index 00000000..0ac2a3fc --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/resolvers/user.ts @@ -0,0 +1,4 @@ +import type { UserResolvers } from './../types.generated'; +export const User: UserResolvers = { + /* Implement User resolver logic here */ +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/schema.generated.graphqls b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/schema.generated.graphqls new file mode 100644 index 00000000..da5fafbe --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/schema.generated.graphqls @@ -0,0 +1,27 @@ +scalar DateTime + +type Mutation { + prefixedAPIMutation: RandomResult! +} + +type Query { + APIQuery: RandomResult! + query: RandomResult! + user(id: ID!): User! + userProfile(id: ID!): UserProfile! +} + +type RandomResult { + createdAt: DateTime! + id: ID! + name: String! + updatedAt: DateTime! +} + +type User { + id: ID! +} + +type UserProfile { + id: ID! +} diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/typeDefs.generated.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/typeDefs.generated.ts new file mode 100644 index 00000000..e75f8f16 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/typeDefs.generated.ts @@ -0,0 +1,226 @@ +import type { DocumentNode } from 'graphql'; +export const typeDefs = { + kind: 'Document', + definitions: [ + { + kind: 'ScalarTypeDefinition', + name: { kind: 'Name', value: 'DateTime' }, + directives: [], + }, + { + name: { kind: 'Name', value: 'Query' }, + kind: 'ObjectTypeDefinition', + fields: [ + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'query' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'RandomResult' }, + }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'APIQuery' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'RandomResult' }, + }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'userProfile' }, + arguments: [ + { + kind: 'InputValueDefinition', + name: { kind: 'Name', value: 'id' }, + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'ID' }, + }, + }, + directives: [], + }, + ], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'UserProfile' }, + }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'user' }, + arguments: [ + { + kind: 'InputValueDefinition', + name: { kind: 'Name', value: 'id' }, + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'ID' }, + }, + }, + directives: [], + }, + ], + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'User' } }, + }, + directives: [], + }, + ], + directives: [], + interfaces: [], + }, + { + kind: 'ObjectTypeDefinition', + name: { kind: 'Name', value: 'Mutation' }, + interfaces: [], + directives: [], + fields: [ + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'prefixedAPIMutation' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'RandomResult' }, + }, + }, + directives: [], + }, + ], + }, + { + kind: 'ObjectTypeDefinition', + name: { kind: 'Name', value: 'RandomResult' }, + interfaces: [], + directives: [], + fields: [ + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'id' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'name' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'createdAt' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'DateTime' }, + }, + }, + directives: [], + }, + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'updatedAt' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'DateTime' }, + }, + }, + directives: [], + }, + ], + }, + { + kind: 'ObjectTypeDefinition', + name: { kind: 'Name', value: 'User' }, + interfaces: [], + directives: [], + fields: [ + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'id' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } }, + }, + directives: [], + }, + ], + }, + { + kind: 'ObjectTypeDefinition', + name: { kind: 'Name', value: 'UserProfile' }, + interfaces: [], + directives: [], + fields: [ + { + kind: 'FieldDefinition', + name: { kind: 'Name', value: 'id' }, + arguments: [], + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } }, + }, + directives: [], + }, + ], + }, + { + kind: 'SchemaDefinition', + operationTypes: [ + { + kind: 'OperationTypeDefinition', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Query' } }, + operation: 'query', + }, + { + kind: 'OperationTypeDefinition', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'Mutation' }, + }, + operation: 'mutation', + }, + ], + }, + ], +} as unknown as DocumentNode; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/types.generated.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/types.generated.ts new file mode 100644 index 00000000..1fc2e8e6 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/types.generated.ts @@ -0,0 +1,279 @@ +import { + GraphQLResolveInfo, + GraphQLScalarType, + GraphQLScalarTypeConfig, +} from 'graphql'; +export type Maybe = T | null | undefined; +export type InputMaybe = T | null | undefined; +export type Exact = { + [K in keyof T]: T[K]; +}; +export type MakeOptional = Omit & { + [SubKey in K]?: Maybe; +}; +export type MakeMaybe = Omit & { + [SubKey in K]: Maybe; +}; +export type MakeEmpty< + T extends { [key: string]: unknown }, + K extends keyof T +> = { [_ in K]?: never }; +export type Incremental = + | T + | { + [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never; + }; +export type RequireFields = Omit & { + [P in K]-?: NonNullable; +}; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string | number }; + String: { input: string; output: string }; + Boolean: { input: boolean; output: boolean }; + Int: { input: number; output: number }; + Float: { input: number; output: number }; + DateTime: { input: Date | string; output: Date | string }; +}; + +export type Mutation = { + __typename?: 'Mutation'; + prefixedAPIMutation: RandomResult; +}; + +export type Query = { + __typename?: 'Query'; + APIQuery: RandomResult; + query: RandomResult; + user: User; + userProfile: UserProfile; +}; + +export type QueryuserArgs = { + id: Scalars['ID']['input']; +}; + +export type QueryuserProfileArgs = { + id: Scalars['ID']['input']; +}; + +export type RandomResult = { + __typename?: 'RandomResult'; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + updatedAt: Scalars['DateTime']['output']; +}; + +export type User = { + __typename?: 'User'; + id: Scalars['ID']['output']; +}; + +export type UserProfile = { + __typename?: 'UserProfile'; + id: Scalars['ID']['output']; +}; + +export type ResolverTypeWrapper = Promise | T; + +export type ResolverWithResolve = { + resolve: ResolverFn; +}; +export type Resolver = + | ResolverFn + | ResolverWithResolve; + +export type ResolverFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => Promise | TResult; + +export type SubscriptionSubscribeFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => AsyncIterable | Promise>; + +export type SubscriptionResolveFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + +export interface SubscriptionSubscriberObject< + TResult, + TKey extends string, + TParent, + TContext, + TArgs +> { + subscribe: SubscriptionSubscribeFn< + { [key in TKey]: TResult }, + TParent, + TContext, + TArgs + >; + resolve?: SubscriptionResolveFn< + TResult, + { [key in TKey]: TResult }, + TContext, + TArgs + >; +} + +export interface SubscriptionResolverObject { + subscribe: SubscriptionSubscribeFn; + resolve: SubscriptionResolveFn; +} + +export type SubscriptionObject< + TResult, + TKey extends string, + TParent, + TContext, + TArgs +> = + | SubscriptionSubscriberObject + | SubscriptionResolverObject; + +export type SubscriptionResolver< + TResult, + TKey extends string, + TParent = {}, + TContext = {}, + TArgs = {} +> = + | (( + ...args: any[] + ) => SubscriptionObject) + | SubscriptionObject; + +export type TypeResolveFn = ( + parent: TParent, + context: TContext, + info: GraphQLResolveInfo +) => Maybe | Promise>; + +export type IsTypeOfResolverFn = ( + obj: T, + context: TContext, + info: GraphQLResolveInfo +) => boolean | Promise; + +export type NextResolverFn = () => Promise; + +export type DirectiveResolverFn< + TResult = {}, + TParent = {}, + TContext = {}, + TArgs = {} +> = ( + next: NextResolverFn, + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + +/** Mapping between all available schema types and the resolvers types */ +export type ResolversTypes = { + DateTime: ResolverTypeWrapper; + Mutation: ResolverTypeWrapper<{}>; + Query: ResolverTypeWrapper<{}>; + ID: ResolverTypeWrapper; + RandomResult: ResolverTypeWrapper; + String: ResolverTypeWrapper; + User: ResolverTypeWrapper; + UserProfile: ResolverTypeWrapper; + Boolean: ResolverTypeWrapper; +}; + +/** Mapping between all available schema types and the resolvers parents */ +export type ResolversParentTypes = { + DateTime: Scalars['DateTime']['output']; + Mutation: {}; + Query: {}; + ID: Scalars['ID']['output']; + RandomResult: RandomResult; + String: Scalars['String']['output']; + User: User; + UserProfile: UserProfile; + Boolean: Scalars['Boolean']['output']; +}; + +export interface DateTimeScalarConfig + extends GraphQLScalarTypeConfig { + name: 'DateTime'; +} + +export type MutationResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation'] +> = { + prefixedAPIMutation?: Resolver< + ResolversTypes['RandomResult'], + ParentType, + ContextType + >; +}; + +export type QueryResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query'] +> = { + APIQuery?: Resolver; + query?: Resolver; + user?: Resolver< + ResolversTypes['User'], + ParentType, + ContextType, + RequireFields + >; + userProfile?: Resolver< + ResolversTypes['UserProfile'], + ParentType, + ContextType, + RequireFields + >; +}; + +export type RandomResultResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['RandomResult'] = ResolversParentTypes['RandomResult'] +> = { + createdAt?: Resolver; + id?: Resolver; + name?: Resolver; + updatedAt?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type UserResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User'] +> = { + id?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type UserProfileResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['UserProfile'] = ResolversParentTypes['UserProfile'] +> = { + id?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type Resolvers = { + DateTime?: GraphQLScalarType; + Mutation?: MutationResolvers; + Query?: QueryResolvers; + RandomResult?: RandomResultResolvers; + User?: UserResolvers; + UserProfile?: UserProfileResolvers; +}; diff --git a/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/user.graphqls.ts b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/user.graphqls.ts new file mode 100644 index 00000000..6e3b1fb8 --- /dev/null +++ b/packages/typescript-resolver-files-e2e/src/test-resolver-filename-case/graphql/schemas/user.graphqls.ts @@ -0,0 +1,18 @@ +import gql from 'graphql-tag'; + +export const userTypeDefs = gql` + extend type Query { + # Multi-word type: UserProfile -> user-profile.ts + userProfile(id: ID!): UserProfile! + # Single-word type: User -> user.ts + user(id: ID!): User! + } + + type User { + id: ID! + } + + type UserProfile { + id: ID! + } +`; diff --git a/packages/typescript-resolver-files/README.md b/packages/typescript-resolver-files/README.md index d7471816..0d7ba6d9 100644 --- a/packages/typescript-resolver-files/README.md +++ b/packages/typescript-resolver-files/README.md @@ -261,6 +261,44 @@ Hint: To see why certain files are skipped, run codegen command with `DEBUG` tur DEBUG="@eddeee888/gcg-typescript-resolver-files" yarn graphql-codegen ``` +### fileOutputCasing + +`string` (Default: `pascal-case`) + +Controls the naming convention used for generated resolver filenames. By default, resolver files are generated using PascalCase (e.g., `UserProfile.ts`), but you can customize this to match your project's file naming conventions. + +Supported options: +- `pascal-case` (default): `UserProfile.ts`, `APIKey.ts` +- `kebab-case` or `param-case`: `user-profile.ts`, `api-key.ts` +- `camel-case`: `userProfile.ts`, `apiKey.ts` +- `snake-case`: `user_profile.ts`, `api_key.ts` +- `constant-case`: `USER_PROFILE.ts`, `API_KEY.ts` +- `dot-case`: `user.profile.ts`, `api.key.ts` +- `header-case`: `User-Profile.ts`, `Api-Key.ts` +- `lower-case`: `userprofile.ts`, `apikey.ts` +- `upper-case`: `USERPROFILE.ts`, `APIKEY.ts` +- `no-case`: `user profile.ts`, `api key.ts` +- `path-case`: `user/profile.ts`, `api/key.ts` +- `sentence-case`: `User profile.ts`, `Api key.ts` +- `title-case`: `UserProfile.ts`, `APIKey.ts` +- `capital-case`: `User Profile.ts`, `Api Key.ts` + +#### Example + +```ts +// codegen.ts +defineConfig({ + fileOutputCasing: 'kebab-case', +}); +``` + +This configuration will generate resolver files like: +- `src/schema/user/resolvers/user-profile.ts` (instead of `UserProfile.ts`) +- `src/schema/user/resolvers/Query/user-by-id.ts` (instead of `userById.ts`) +- `src/schema/api/resolvers/api-key.ts` (instead of `APIKey.ts`) + +Note: This option only affects the filename casing. The exported resolver variable names and TypeScript interfaces remain unchanged to maintain valid JavaScript identifiers. + ### typeDefsFileMode `merged` or `mergedWhitelisted` or `modules` (Default: `merged`) diff --git a/packages/typescript-resolver-files/package.json b/packages/typescript-resolver-files/package.json index d4ea6e4e..d38116d4 100644 --- a/packages/typescript-resolver-files/package.json +++ b/packages/typescript-resolver-files/package.json @@ -35,6 +35,7 @@ "@graphql-codegen/typescript-resolvers": "^4.4.2", "@graphql-tools/merge": "^9.0.4", "@graphql-tools/utils": "^10.0.0", + "change-case-all": "^1.0.0", "micromatch": "^4.0.0", "ts-morph": "^22.0.0", "tslib": "^2.3.0" diff --git a/packages/typescript-resolver-files/src/generateResolverFiles/visitNamedType.ts b/packages/typescript-resolver-files/src/generateResolverFiles/visitNamedType.ts index f37bd0bf..ac88ea2b 100644 --- a/packages/typescript-resolver-files/src/generateResolverFiles/visitNamedType.ts +++ b/packages/typescript-resolver-files/src/generateResolverFiles/visitNamedType.ts @@ -7,6 +7,7 @@ export const visitNamedType = ( moduleName, relativePathFromBaseToModule, normalizedResolverName, + originalResolverName, resolverFile, relativePathToResolverTypesFile, typeNamedImport, @@ -49,7 +50,7 @@ export const visitNamedType = ( moduleName, normalizedResolverName, relativePathFromBaseToModule, - resolverName: resolverFile.name, + resolverName: originalResolverName, resolversTypeMeta: { module: relativePathToResolverTypesFile, moduleType: 'file', diff --git a/packages/typescript-resolver-files/src/parseGraphQLSchema/parseGraphQLSchema.ts b/packages/typescript-resolver-files/src/parseGraphQLSchema/parseGraphQLSchema.ts index b66645cb..164fc89b 100644 --- a/packages/typescript-resolver-files/src/parseGraphQLSchema/parseGraphQLSchema.ts +++ b/packages/typescript-resolver-files/src/parseGraphQLSchema/parseGraphQLSchema.ts @@ -24,6 +24,7 @@ import { isNativeNamedType, isRootObjectType, relativeModulePath, + transformResolverFileName, type RootObjectType, } from '../utils'; import { parseLocationForOutputDir } from './parseLocationForOutputDir'; @@ -42,11 +43,13 @@ interface ParseGraphQLSchemaParams { resolverRelativeTargetDir: string; whitelistedModules: ParsedPresetConfig['whitelistedModules']; blacklistedModules: ParsedPresetConfig['blacklistedModules']; + fileOutputCasing: ParsedPresetConfig['fileOutputCasing']; } export interface ResolverDetails { schemaType: string; moduleName: string; + originalResolverName: string; resolverFile: { name: string; path: string; @@ -113,6 +116,7 @@ export const parseGraphQLSchema = async ({ resolverRelativeTargetDir, whitelistedModules, blacklistedModules, + fileOutputCasing, }: ParseGraphQLSchemaParams): Promise => { const scalarsModuleResolverMap = scalarsModule ? await getScalarResolverMapFromModule(scalarsModule) @@ -144,6 +148,7 @@ export const parseGraphQLSchema = async ({ nestedDirs: [schemaType], location: fieldNode.astNode?.loc, resolverName: fieldName, + fileOutputCasing, }); if (!resolverDetails) { return; @@ -187,6 +192,7 @@ export const parseGraphQLSchema = async ({ namedType, schemaType, result: res, + fileOutputCasing, }); return res; } @@ -220,6 +226,7 @@ export const parseGraphQLSchema = async ({ nestedDirs: [], location: namedType.astNode?.loc, resolverName: namedType.name, + fileOutputCasing, }); if (resolverDetails) { @@ -358,6 +365,7 @@ const handleObjectType = ({ namedType, schemaType, result, + fileOutputCasing, }: { mode: ParseGraphQLSchemaParams['mode']; sourceMap: ParseGraphQLSchemaParams['sourceMap']; @@ -369,6 +377,7 @@ const handleObjectType = ({ namedType: GraphQLObjectType; schemaType: string; result: ParsedGraphQLSchemaMeta; + fileOutputCasing: ParsedPresetConfig['fileOutputCasing']; }): void => { // parse for details const fieldsByGraphQLModule = Object.entries(namedType.getFields()).reduce< @@ -420,6 +429,7 @@ const handleObjectType = ({ nestedDirs: [], location: firstFieldLocation, resolverName: namedType.name, + fileOutputCasing, }); if (!resolverDetails) { @@ -457,6 +467,7 @@ const createResolverDetails = ({ nestedDirs, location, resolverName, + fileOutputCasing, }: { belongsToRootObject: RootObjectType | null; mode: ParseGraphQLSchemaParams['mode']; @@ -470,6 +481,7 @@ const createResolverDetails = ({ nestedDirs: string[]; location: Location | undefined; resolverName: string; + fileOutputCasing: ParsedPresetConfig['fileOutputCasing']; }): ResolverDetails | undefined => { const parsedDetails = parseLocationForOutputDir({ nestedDirs, @@ -494,16 +506,18 @@ const createResolverDetails = ({ belongsToRootObject ); + const transformedFileName = transformResolverFileName(resolverName, fileOutputCasing); const resolverFilePath = path.posix.join( resolversOutputDir, - `${resolverName}.ts` + `${transformedFileName}.ts` ); return { schemaType, moduleName, + originalResolverName: resolverName, resolverFile: { - name: resolverName, + name: transformedFileName, path: resolverFilePath, isOnFilesystem: fs.existsSync(resolverFilePath), }, diff --git a/packages/typescript-resolver-files/src/preset.ts b/packages/typescript-resolver-files/src/preset.ts index d8a4a717..3d9211d9 100644 --- a/packages/typescript-resolver-files/src/preset.ts +++ b/packages/typescript-resolver-files/src/preset.ts @@ -71,6 +71,7 @@ export const preset: Types.OutputPreset = { tsMorphProjectOptions, fixObjectTypeResolvers, emitLegacyCommonJSImports, + fileOutputCasing, } = validatePresetConfig(rawPresetConfig); const resolverTypesPath = path.posix.join( @@ -121,6 +122,7 @@ export const preset: Types.OutputPreset = { resolverRelativeTargetDir, whitelistedModules, blacklistedModules, + fileOutputCasing, }), createProfilerRunName('parseGraphQLSchema') ); diff --git a/packages/typescript-resolver-files/src/utils/index.ts b/packages/typescript-resolver-files/src/utils/index.ts index 6e998c4b..11159cef 100644 --- a/packages/typescript-resolver-files/src/utils/index.ts +++ b/packages/typescript-resolver-files/src/utils/index.ts @@ -9,3 +9,4 @@ export * from './printImportLine'; export * from './normalizeRelativePath'; export * from './relativeModulePath'; export * from './isMatchResolverNamePattern'; +export * from './transformResolverFileName'; diff --git a/packages/typescript-resolver-files/src/utils/transformResolverFileName.spec.ts b/packages/typescript-resolver-files/src/utils/transformResolverFileName.spec.ts new file mode 100644 index 00000000..2e30e661 --- /dev/null +++ b/packages/typescript-resolver-files/src/utils/transformResolverFileName.spec.ts @@ -0,0 +1,185 @@ +import { transformResolverFileName } from './transformResolverFileName'; + +describe('transformResolverFileName', () => { + describe('pascal-case', () => { + it('should return the original name for pascal-case', () => { + expect(transformResolverFileName('User', 'pascal-case')).toBe('User'); + expect(transformResolverFileName('UserProfile', 'pascal-case')).toBe('UserProfile'); + expect(transformResolverFileName('APIKey', 'pascal-case')).toBe('APIKey'); + }); + + it('should handle single character names', () => { + expect(transformResolverFileName('A', 'pascal-case')).toBe('A'); + }); + + it('should handle names with numbers', () => { + expect(transformResolverFileName('User2', 'pascal-case')).toBe('User2'); + expect(transformResolverFileName('API2Key', 'pascal-case')).toBe('API2Key'); + }); + }); + + describe('kebab-case', () => { + it('should convert PascalCase to kebab-case', () => { + expect(transformResolverFileName('User', 'kebab-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'kebab-case')).toBe('user-profile'); + expect(transformResolverFileName('APIKey', 'kebab-case')).toBe('api-key'); + }); + + it('should handle single character names', () => { + expect(transformResolverFileName('A', 'kebab-case')).toBe('a'); + }); + + it('should handle names with numbers', () => { + expect(transformResolverFileName('User2', 'kebab-case')).toBe('user2'); + expect(transformResolverFileName('API2Key', 'kebab-case')).toBe('api2-key'); + }); + + it('should handle already kebab-cased names', () => { + expect(transformResolverFileName('user-profile', 'kebab-case')).toBe('user-profile'); + }); + + it('should handle camelCase names', () => { + expect(transformResolverFileName('userProfile', 'kebab-case')).toBe('user-profile'); + expect(transformResolverFileName('myAPIKey', 'kebab-case')).toBe('my-api-key'); + }); + + it('should handle names with underscores', () => { + expect(transformResolverFileName('user_profile', 'kebab-case')).toBe('user-profile'); + expect(transformResolverFileName('API_KEY', 'kebab-case')).toBe('api-key'); + }); + + it('should handle names with spaces', () => { + expect(transformResolverFileName('User Profile', 'kebab-case')).toBe('user-profile'); + expect(transformResolverFileName('API Key', 'kebab-case')).toBe('api-key'); + }); + }); + + describe('camel-case', () => { + it('should convert to camelCase', () => { + expect(transformResolverFileName('User', 'camel-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'camel-case')).toBe('userProfile'); + expect(transformResolverFileName('APIKey', 'camel-case')).toBe('apiKey'); + }); + + it('should handle names with spaces', () => { + expect(transformResolverFileName('User Profile', 'camel-case')).toBe('userProfile'); + }); + }); + + describe('capital-case', () => { + it('should convert to Capital Case', () => { + expect(transformResolverFileName('User', 'capital-case')).toBe('User'); + expect(transformResolverFileName('UserProfile', 'capital-case')).toBe('User Profile'); + expect(transformResolverFileName('APIKey', 'capital-case')).toBe('Api Key'); + }); + }); + + describe('constant-case', () => { + it('should convert to CONSTANT_CASE', () => { + expect(transformResolverFileName('User', 'constant-case')).toBe('USER'); + expect(transformResolverFileName('UserProfile', 'constant-case')).toBe('USER_PROFILE'); + expect(transformResolverFileName('APIKey', 'constant-case')).toBe('API_KEY'); + }); + }); + + describe('dot-case', () => { + it('should convert to dot.case', () => { + expect(transformResolverFileName('User', 'dot-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'dot-case')).toBe('user.profile'); + expect(transformResolverFileName('APIKey', 'dot-case')).toBe('api.key'); + }); + }); + + describe('header-case', () => { + it('should convert to Header-Case', () => { + expect(transformResolverFileName('User', 'header-case')).toBe('User'); + expect(transformResolverFileName('UserProfile', 'header-case')).toBe('User-Profile'); + expect(transformResolverFileName('APIKey', 'header-case')).toBe('Api-Key'); + }); + }); + + describe('lower-case', () => { + it('should convert to lower case', () => { + expect(transformResolverFileName('User', 'lower-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'lower-case')).toBe('userprofile'); + expect(transformResolverFileName('APIKey', 'lower-case')).toBe('apikey'); + }); + }); + + describe('no-case', () => { + it('should convert to no case', () => { + expect(transformResolverFileName('User', 'no-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'no-case')).toBe('user profile'); + expect(transformResolverFileName('APIKey', 'no-case')).toBe('api key'); + }); + }); + + describe('path-case', () => { + it('should convert to path/case', () => { + expect(transformResolverFileName('User', 'path-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'path-case')).toBe('user/profile'); + expect(transformResolverFileName('APIKey', 'path-case')).toBe('api/key'); + }); + }); + + describe('sentence-case', () => { + it('should convert to Sentence case', () => { + expect(transformResolverFileName('User', 'sentence-case')).toBe('User'); + expect(transformResolverFileName('UserProfile', 'sentence-case')).toBe('User profile'); + expect(transformResolverFileName('APIKey', 'sentence-case')).toBe('Api key'); + }); + }); + + describe('snake-case', () => { + it('should convert to snake_case', () => { + expect(transformResolverFileName('User', 'snake-case')).toBe('user'); + expect(transformResolverFileName('UserProfile', 'snake-case')).toBe('user_profile'); + expect(transformResolverFileName('APIKey', 'snake-case')).toBe('api_key'); + }); + }); + + describe('title-case', () => { + it('should convert to Title Case', () => { + expect(transformResolverFileName('User', 'title-case')).toBe('User'); + expect(transformResolverFileName('UserProfile', 'title-case')).toBe('UserProfile'); + expect(transformResolverFileName('APIKey', 'title-case')).toBe('APIKey'); + }); + }); + + describe('upper-case', () => { + it('should convert to UPPER CASE', () => { + expect(transformResolverFileName('User', 'upper-case')).toBe('USER'); + expect(transformResolverFileName('UserProfile', 'upper-case')).toBe('USERPROFILE'); + expect(transformResolverFileName('APIKey', 'upper-case')).toBe('APIKEY'); + }); + }); + + describe('default behavior', () => { + it('should default to pascal-case for invalid casing option', () => { + // @ts-expect-error Testing invalid input + expect(transformResolverFileName('UserProfile', 'invalid')).toBe('UserProfile'); + }); + }); + + describe('edge cases', () => { + it('should handle empty strings', () => { + expect(transformResolverFileName('', 'pascal-case')).toBe(''); + expect(transformResolverFileName('', 'kebab-case')).toBe(''); + expect(transformResolverFileName('', 'camel-case')).toBe(''); + expect(transformResolverFileName('', 'upper-case')).toBe(''); + }); + + it('should handle special characters', () => { + expect(transformResolverFileName('User$Profile', 'kebab-case')).toBe('user-profile'); + expect(transformResolverFileName('API@Key', 'kebab-case')).toBe('api-key'); + expect(transformResolverFileName('User$Profile', 'snake-case')).toBe('user_profile'); + expect(transformResolverFileName('API@Key', 'constant-case')).toBe('API_KEY'); + }); + + it('should handle mixed case inputs', () => { + expect(transformResolverFileName('userProfile', 'pascal-case')).toBe('userProfile'); + expect(transformResolverFileName('USER_PROFILE', 'camel-case')).toBe('userProfile'); + expect(transformResolverFileName('user-profile', 'snake-case')).toBe('user_profile'); + }); + }); +}); diff --git a/packages/typescript-resolver-files/src/utils/transformResolverFileName.ts b/packages/typescript-resolver-files/src/utils/transformResolverFileName.ts new file mode 100644 index 00000000..c2f101c7 --- /dev/null +++ b/packages/typescript-resolver-files/src/utils/transformResolverFileName.ts @@ -0,0 +1,60 @@ +import { + paramCase, + camelCase, + capitalCase, + constantCase, + dotCase, + headerCase, + lowerCase, + noCase, + pathCase, + sentenceCase, + snakeCase, + titleCase, + upperCase +} from 'change-case-all'; +import type { FileOutputCasing } from '../validatePresetConfig'; + +/** + * Transforms a resolver name to the appropriate filename based on casing configuration + * @param resolverName - The original resolver name (typically a GraphQL type name like "User", "Profile") + * @param fileOutputCasing - The desired file naming case format + * @returns The transformed filename without extension + */ +export const transformResolverFileName = ( + resolverName: string, + fileOutputCasing: FileOutputCasing +): string => { + switch (fileOutputCasing) { + case 'param-case': + case 'kebab-case': + return paramCase(resolverName); + case 'camel-case': + return camelCase(resolverName); + case 'capital-case': + return capitalCase(resolverName); + case 'constant-case': + return constantCase(resolverName); + case 'dot-case': + return dotCase(resolverName); + case 'header-case': + return headerCase(resolverName); + case 'lower-case': + return lowerCase(resolverName); + case 'no-case': + return noCase(resolverName); + case 'path-case': + return pathCase(resolverName); + case 'sentence-case': + return sentenceCase(resolverName); + case 'snake-case': + return snakeCase(resolverName); + case 'title-case': + return titleCase(resolverName); + case 'upper-case': + return upperCase(resolverName); + case 'pascal-case': + default: + return resolverName; + } +}; diff --git a/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.spec.ts b/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.spec.ts index f3ea604f..c5cb7006 100644 --- a/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.spec.ts +++ b/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.spec.ts @@ -48,6 +48,7 @@ const defaultExpected: ParsedPresetConfig = { enum: 'smart', }, emitLegacyCommonJSImports: true, + fileOutputCasing: 'pascal-case', }; describe('validatePresetConfig - general', () => { diff --git a/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.ts b/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.ts index 3c854934..72b137e0 100644 --- a/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.ts +++ b/packages/typescript-resolver-files/src/validatePresetConfig/validatePresetConfig.ts @@ -19,7 +19,7 @@ const defaultScalarsModule = 'graphql-scalars'; type ParsedTypesPluginsConfig = Omit< typeScriptPlugin.TypeScriptPluginConfig & - typeScriptResolversPlugin.TypeScriptResolversPluginConfig, + typeScriptResolversPlugin.TypeScriptResolversPluginConfig, 'scalars' | 'emitLegacyCommonJSImports' >; type ConfigMode = 'merged' | 'modules'; @@ -42,6 +42,22 @@ type NormalizedResolverGeneration = { enum: string | string[]; }; export type ModuleNamingMode = number; +export type FileOutputCasing = + | 'pascal-case' + | 'param-case' + | 'kebab-case' + | 'camel-case' + | 'capital-case' + | 'constant-case' + | 'dot-case' + | 'header-case' + | 'lower-case' + | 'no-case' + | 'path-case' + | 'sentence-case' + | 'snake-case' + | 'title-case' + | 'upper-case'; export type ScalarsOverridesType = string | { input: string; output: string }; @@ -64,8 +80,8 @@ export interface ParsedPresetConfig { { resolver?: string; type?: ScalarsOverridesType } >; mergeSchema: - | { path: string; config: schemaAstPlugin.SchemaASTConfig } - | false; + | { path: string; config: schemaAstPlugin.SchemaASTConfig } + | false; mode: ConfigMode; whitelistedModules: string[]; blacklistedModules: string[]; @@ -74,6 +90,7 @@ export interface ParsedPresetConfig { tsMorphProjectOptions: ProjectOptions; fixObjectTypeResolvers: NormalizedFixObjectTypeResolvers; emitLegacyCommonJSImports: boolean; + fileOutputCasing: FileOutputCasing; } export interface RawPresetConfig { @@ -100,10 +117,11 @@ export interface RawPresetConfig { blacklistedModules?: string[]; externalResolvers?: Record; typesPluginsConfig?: typeScriptPlugin.TypeScriptPluginConfig & - typeScriptResolversPlugin.TypeScriptResolversPluginConfig; + typeScriptResolversPlugin.TypeScriptResolversPluginConfig; tsConfigFilePath?: string; fixObjectTypeResolvers?: string | Record; emitLegacyCommonJSImports?: boolean; + fileOutputCasing?: string; } export interface TypedPresetConfig extends RawPresetConfig { @@ -112,14 +130,14 @@ export interface TypedPresetConfig extends RawPresetConfig { resolverMainFileMode?: ResolverMainFileMode; typeDefsFileMode?: TypeDefsFileMode; fixObjectTypeResolvers?: - | StringFixObjectTypeResolvers - | NormalizedFixObjectTypeResolvers; + | StringFixObjectTypeResolvers + | NormalizedFixObjectTypeResolvers; typesPluginsConfig?: ParsedTypesPluginsConfig; resolverGeneration?: StringResolverGeneration | NormalizedResolverGeneration; mergeSchema?: - | boolean - | string - | { path: string; config: schemaAstPlugin.SchemaASTConfig }; + | boolean + | string + | { path: string; config: schemaAstPlugin.SchemaASTConfig }; } export const validatePresetConfig = ({ @@ -146,6 +164,7 @@ export const validatePresetConfig = ({ tsConfigFilePath = './tsconfig.json', fixObjectTypeResolvers = 'smart', emitLegacyCommonJSImports = true, + fileOutputCasing = 'pascal-case', }: RawPresetConfig): ParsedPresetConfig => { if (mode !== 'merged' && mode !== 'modules') { throw new Error( @@ -193,6 +212,32 @@ export const validatePresetConfig = ({ ); } + const validFileOutputCasings: Set = new Set([ + 'pascal-case', + 'kebab-case', + 'camel-case', + 'capital-case', + 'constant-case', + 'dot-case', + 'header-case', + 'lower-case', + 'no-case', + 'path-case', + 'sentence-case', + 'snake-case', + 'title-case', + 'upper-case' + ]); + + if (fileOutputCasing && !validFileOutputCasings.has(fileOutputCasing as FileOutputCasing)) { + throw new Error( + fmt.error( + `presetConfig.fileOutputCasing must be one of: ${Array.from(validFileOutputCasings).join(', ')} (default is "pascal-case")`, + 'Validation' + ) + ); + } + let typeDefsFileMode = inputTypeDefsFileMode; if (mode === 'merged') { // If mode is `merged`, `typeDefsFileMode` is also `merged` because there's no whitelisted or modules concepts @@ -327,6 +372,7 @@ export const validatePresetConfig = ({ tsMorphProjectOptions, fixObjectTypeResolvers: parseFixObjectTypeResolvers(fixObjectTypeResolvers), emitLegacyCommonJSImports, + fileOutputCasing: fileOutputCasing as FileOutputCasing, }; };