Skip to content

Commit

Permalink
feat(clients): align awaited type everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
anymaniax committed May 14, 2022
1 parent 292130d commit 4cc91cf
Show file tree
Hide file tree
Showing 13 changed files with 6,004 additions and 6,091 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"cac": "^6.7.12",
"chalk": "^4.1.2",
"chokidar": "^3.5.3",
"compare-versions": "^4.1.3",
"cuid": "^2.1.8",
"debug": "^4.3.3",
"esbuild": "^0.14.25",
Expand Down
11 changes: 10 additions & 1 deletion src/core/generators/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,21 @@ export const generateAxiosHeader = ({
isRequestOptions,
isMutator,
noFunction,
hasAwaitedType,
}: {
title: string;
isRequestOptions: boolean;
isMutator: boolean;
noFunction?: boolean;
}) => `${
hasAwaitedType: boolean;
}) => `
${
!hasAwaitedType
? `export type AwaitedInput<T> = PromiseLike<T> | T;\n
export type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;\n\n`
: ''
}
${
isRequestOptions && isMutator
? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
type SecondParameter<T extends (...args: any) => any> = T extends (
Expand Down
9 changes: 4 additions & 5 deletions src/core/generators/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,7 @@ export const GENERATOR_CLIENT: GeneratorClients = {
imports,
};
},
header: (options: {
title: string;
isMutator: boolean;
isRequestOptions: boolean;
}) => generateAxiosHeader({ ...options, noFunction: true }),
header: (options) => generateAxiosHeader({ ...options, noFunction: true }),
dependencies: getAxiosDependencies,
footer: (options) => generateAxiosFooter({ ...options, noFunction: true }),
title: generateAxiosTitle,
Expand Down Expand Up @@ -152,6 +148,7 @@ export const generateClientHeader = ({
isMutator,
provideInRoot,
provideIn,
hasAwaitedType,
}: {
outputClient?: OutputClient | OutputClientFunc;
isRequestOptions: boolean;
Expand All @@ -161,6 +158,7 @@ export const generateClientHeader = ({
provideIn: boolean | 'root' | 'any';
title: string;
customTitleFunc?: (title: string) => string;
hasAwaitedType: boolean;
}): GeneratorClientExtra => {
const titles = generateClientTitle(outputClient, title, customTitleFunc);
const { header } = getGeneratorClient(outputClient);
Expand All @@ -172,6 +170,7 @@ export const generateClientHeader = ({
isMutator,
provideInRoot,
provideIn,
hasAwaitedType,
}),
implementationMSW: `export const ${titles.implementationMSW} = () => [\n`,
};
Expand Down
48 changes: 28 additions & 20 deletions src/core/generators/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,18 @@ const generateQueryArguments = ({
}) => {
const isMutatorHook = mutator?.isHook;
const definition = type
? `Use${pascal(type)}Options<AsyncReturnType<${
? `Use${pascal(type)}Options<Awaited<ReturnType<${
isMutatorHook
? `ReturnType<typeof use${pascal(operationName)}Hook>`
: `typeof ${operationName}`
}>, TError, TData>`
: `UseMutationOptions<AsyncReturnType<${
}>>, TError, TData>`
: `UseMutationOptions<Awaited<ReturnType<${
isMutatorHook
? `ReturnType<typeof use${pascal(operationName)}Hook>`
: `typeof ${operationName}`
}>, TError,${definitions ? `{${definitions}}` : 'TVariables'}, TContext>`;
}>>, TError,${
definitions ? `{${definitions}}` : 'TVariables'
}, TContext>`;

if (!isRequestOptions) {
return `${type ? 'queryOptions' : 'mutationOptions'}?: ${definition}`;
Expand Down Expand Up @@ -347,11 +349,11 @@ const generateQueryReturnType = ({
}) => {
switch (outputClient) {
case OutputClient.SVELTE_QUERY:
return `Use${pascal(type)}StoreResult<AsyncReturnType<${
return `Use${pascal(type)}StoreResult<Awaited<ReturnType<${
isMutatorHook
? `ReturnType<typeof use${pascal(operationName)}Hook>`
: `typeof ${operationName}`
}>, TError, TData, QueryKey>`;
}>>, TError, TData, QueryKey>`;
case OutputClient.VUE_QUERY:
return ` UseQueryReturnType<TData, TError, Use${pascal(
type,
Expand Down Expand Up @@ -424,12 +426,12 @@ const generateQueryImplementation = ({
return `
export type ${pascal(
name,
)}QueryResult = NonNullable<AsyncReturnType<${dataType}>>
)}QueryResult = NonNullable<Awaited<ReturnType<${dataType}>>>
export type ${pascal(name)}QueryError = ${errorType}
export const ${camel(
`use-${name}`,
)} = <TData = AsyncReturnType<${dataType}>, TError = ${errorType}>(\n ${queryProps} ${generateQueryArguments(
)} = <TData = Awaited<ReturnType<${dataType}>>, TError = ${errorType}>(\n ${queryProps} ${generateQueryArguments(
{
operationName,
definitions: '',
Expand Down Expand Up @@ -459,11 +461,11 @@ export const ${camel(
: ''
}
const queryFn: QueryFunction<AsyncReturnType<${
const queryFn: QueryFunction<Awaited<ReturnType<${
mutator?.isHook
? `ReturnType<typeof use${pascal(operationName)}Hook>`
: `typeof ${operationName}`
}>> = (${
}>>> = (${
queryParam && props.some(({ type }) => type === 'queryParam')
? `{ signal, pageParam }`
: '{ signal }'
Expand All @@ -477,11 +479,11 @@ export const ${camel(
: ''
});
const query = ${camel(`use-${type}`)}<AsyncReturnType<${
const query = ${camel(`use-${type}`)}<Awaited<ReturnType<${
mutator?.isHook
? `ReturnType<typeof use${pascal(operationName)}Hook>`
: `typeof ${operationName}`
}>, TError, TData>(queryKey, queryFn, ${generateQueryOptions({
}>>, TError, TData>(queryKey, queryFn, ${generateQueryOptions({
params,
options,
type,
Expand All @@ -507,7 +509,7 @@ const generateQueryHook = (
response,
operationId,
}: GeneratorVerbOptions,
{ route, override: { operations = {} } }: GeneratorOptions,
{ route, override: { operations = {} }, context }: GeneratorOptions,
outputClient: OutputClient | OutputClientFunc,
) => {
const query = override?.query;
Expand Down Expand Up @@ -606,7 +608,7 @@ const generateQueryHook = (
return `
export type ${pascal(
operationName,
)}MutationResult = NonNullable<AsyncReturnType<${dataType}>>
)}MutationResult = NonNullable<Awaited<ReturnType<${dataType}>>>
${
body.definition
? `export type ${pascal(operationName)}MutationBody = ${
Expand Down Expand Up @@ -645,7 +647,7 @@ const generateQueryHook = (
}
const mutationFn: MutationFunction<AsyncReturnType<${dataType}>, ${
const mutationFn: MutationFunction<Awaited<ReturnType<${dataType}>>, ${
definitions ? `{${definitions}}` : 'TVariables'
}> = (${properties ? 'props' : ''}) => {
${properties ? `const {${properties}} = props ?? {}` : ''};
Expand All @@ -661,7 +663,7 @@ const generateQueryHook = (
})
}
return useMutation<AsyncReturnType<typeof ${operationName}>, TError, ${
return useMutation<Awaited<ReturnType<typeof ${operationName}>>, TError, ${
definitions ? `{${definitions}}` : 'TVariables'
}, TContext>(mutationFn, mutationOptions)
}
Expand All @@ -673,13 +675,18 @@ export const generateQueryTitle = () => '';
export const generateQueryHeader = ({
isRequestOptions,
isMutator,
hasAwaitedType,
}: {
isRequestOptions: boolean;
isMutator: boolean;
}) => `// eslint-disable-next-line @typescript-eslint/no-explicit-any
type AsyncReturnType<
T extends (...args: any) => Promise<any>
> = T extends (...args: any) => Promise<infer R> ? R : any;\n\n
hasAwaitedType: boolean;
}) => {
return `${
!hasAwaitedType
? `export type AwaitedInput<T> = PromiseLike<T> | T;\n
export type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;\n\n`
: ''
}
${
isRequestOptions && isMutator
? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -691,6 +698,7 @@ ${
: never;\n\n`
: ''
}`;
};

export const generateQueryFooter = () => '';

Expand Down
30 changes: 18 additions & 12 deletions src/core/generators/swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const generateSwrArguments = ({
mutator?: GeneratorMutator;
isRequestOptions: boolean;
}) => {
const definition = `SWRConfiguration<AsyncReturnType<typeof ${operationName}>, TError> & {swrKey: Key}`;
const definition = `SWRConfiguration<Awaited<ReturnType<typeof ${operationName}>>, TError> & {swrKey: Key}`;

if (!isRequestOptions) {
return `swrOptions?: ${definition}`;
Expand Down Expand Up @@ -210,7 +210,7 @@ const generateSwrImplementation = ({
return `
export type ${pascal(
operationName,
)}QueryResult = NonNullable<AsyncReturnType<typeof ${operationName}>>
)}QueryResult = NonNullable<Awaited<ReturnType<typeof ${operationName}>>>
export type ${pascal(operationName)}QueryError = ${errorType}
export const ${camel(
Expand Down Expand Up @@ -246,7 +246,7 @@ export const ${camel(
: ''
});
const query = useSwr<AsyncReturnType<typeof swrFn>, TError>(swrKey, swrFn, swrOptions)
const query = useSwr<Awaited<ReturnType<typeof swrFn>>, TError>(swrKey, swrFn, swrOptions)
return {
swrKey,
Expand Down Expand Up @@ -307,24 +307,30 @@ export const generateSwrTitle = () => '';
export const generateSwrHeader = ({
isRequestOptions,
isMutator,
hasAwaitedType,
}: {
isRequestOptions: boolean;
isMutator: boolean;
}) => `// eslint-disable-next-line @typescript-eslint/no-explicit-any
type AsyncReturnType<
T extends (...args: any) => Promise<any>
> = T extends (...args: any) => Promise<infer R> ? R : any;\n\n
${
isRequestOptions && isMutator
? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
hasAwaitedType: boolean;
}) =>
`
${
!hasAwaitedType
? `export type AwaitedInput<T> = PromiseLike<T> | T;\n
export type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;\n\n`
: ''
}
${
isRequestOptions && isMutator
? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
type SecondParameter<T extends (...args: any) => any> = T extends (
config: any,
args: infer P,
) => any
? P
: never;\n\n`
: ''
}`;
: ''
}`;

export const generateSwrFooter = () => '';

Expand Down
6 changes: 4 additions & 2 deletions src/core/importers/openApi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import omit from 'lodash.omit';
import { OpenAPIObject } from 'openapi3-ts';
import { ImportOpenApi, InputOptions } from '../../types';
import { ContextSpecs, ImportOpenApi, InputOptions } from '../../types';
import { GeneratorSchema } from '../../types/generator';
import { WriteSpecsProps } from '../../types/writers';
import { asyncReduce } from '../../utils/async-reduce';
Expand Down Expand Up @@ -60,14 +60,15 @@ export const importOpenApi = async ({
const schemas = await asyncReduce(
Object.entries(specs),
async (acc, [specKey, spec]) => {
const context = {
const context: ContextSpecs = {
specKey,
target,
workspace,
specs,
override: output.override,
tslint: output.tslint,
tsconfig: output.tsconfig,
packageJson: output.packageJson,
};

// First version to try to handle non-openapi files
Expand Down Expand Up @@ -137,6 +138,7 @@ export const importOpenApi = async ({
override: output.override,
tslint: output.tslint,
tsconfig: output.tsconfig,
packageJson: output.packageJson,
},
});

Expand Down
7 changes: 7 additions & 0 deletions src/core/writers/target.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { compare } from 'compare-versions';
import { InfoObject } from 'openapi3-ts';
import { NormalizedOutputOptions, OutputClient } from '../../types';
import {
Expand Down Expand Up @@ -44,6 +45,11 @@ export const generateTarget = (
const isMutator = acc.mutators.some((mutator) =>
isAngularClient ? mutator.hasThirdArg : mutator.hasSecondArg,
);

const typescriptVersion =
options.packageJson?.dependencies?.['typescript'] ?? '4.4.0';
const hasAwaitedType = compare(typescriptVersion, '4.5.0', '>=');

const header = generateClientHeader({
outputClient: options.client,
isRequestOptions: options.override.requestOptions !== false,
Expand All @@ -53,6 +59,7 @@ export const generateTarget = (
customTitleFunc: options.override.title,
provideInRoot: !!options.override.angular.provideIn,
provideIn: options.override.angular.provideIn,
hasAwaitedType,
});
acc.implementation = header.implementation + acc.implementation;
acc.implementationMSW.handler =
Expand Down
6 changes: 6 additions & 0 deletions src/core/writers/targetTags.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { compare } from 'compare-versions';
import { NormalizedOutputOptions, OutputClient } from '../../types';
import {
GeneratorOperation,
Expand Down Expand Up @@ -98,6 +99,10 @@ export const generateTargetForTags = (
customTitleFunc: options.override.title,
});

const typescriptVersion =
options.packageJson?.dependencies?.['typescript'] ?? '4.4.0';
const hasAwaitedType = compare(typescriptVersion, '4.5.0', '>=');

const header = generateClientHeader({
outputClient: options.client,
isRequestOptions: options.override.requestOptions !== false,
Expand All @@ -107,6 +112,7 @@ export const generateTargetForTags = (
customTitleFunc: options.override.title,
provideInRoot: !!options.override.angular.provideIn,
provideIn: options.override.angular.provideIn,
hasAwaitedType,
});

acc[tag] = {
Expand Down
1 change: 1 addition & 0 deletions src/types/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export type ClientHeaderBuilder = (params: {
isGlobalMutator: boolean;
provideInRoot: boolean;
provideIn: boolean | 'root' | 'any';
hasAwaitedType: boolean;
}) => string;

export type ClientFooterBuilder = (params: {
Expand Down
Loading

0 comments on commit 4cc91cf

Please sign in to comment.