Skip to content

Commit

Permalink
Merge pull request #895 from Maxim-Mazurok/679-proper
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxim-Mazurok authored Nov 30, 2023
2 parents 82b3b79 + 459854e commit ff2b7d3
Show file tree
Hide file tree
Showing 30 changed files with 449 additions and 189 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"cSpell.words": ["listitem", "Petstore", "tanstack"]
"cSpell.words": ["listitem", "openapi", "Orval", "Petstore", "tanstack"]
}
2 changes: 2 additions & 0 deletions docs/src/pages/reference/configuration/full-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ module.exports = {
delay: 500,
},
},
allParamsOptional: true,
urlEncodeParameters: true,
},
input: {
target: './petstore.yaml',
Expand Down
36 changes: 36 additions & 0 deletions docs/src/pages/reference/configuration/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -1379,3 +1379,39 @@ module.exports = {
},
};
```

### allParamsOptional

Type: `Boolean`

Valid values: true or false. Defaults to false. Applies to all clients, but probably only makes sense for Tanstack Query.

Use this property to make all parameters optional. This is useful to take advantage of the Orval's auto-enable feature for Tanstack Query, see https://github.com/anymaniax/orval/pull/894

```js
module.exports = {
petstore: {
output: {
allParamsOptional: true,
},
},
};
```

### urlEncodeParameters

Type: `Boolean`

Valid values: true or false. Defaults to false. **Note:** this only works for Tanstack Query clients for now.

Use this property to enable URL encoding of path/query parameters. This is highly recommended, and will probably become a default in the future, see https://github.com/anymaniax/orval/pull/895

```js
module.exports = {
petstore: {
output: {
urlEncodeParameters: true,
},
},
};
```
9 changes: 9 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ResponsesObject,
SchemaObject,
} from 'openapi3-ts';
// @ts-ignore // FIXME when running `yarn test` getting `orval:test: ../core/src/types.ts(12,34): error TS7016: Could not find a declaration file for module 'swagger2openapi'. '/home/maxim/orval/node_modules/swagger2openapi/index.js' implicitly has an 'any' type.`
import swagger2openapi from 'swagger2openapi';
import type { allLocales } from '@faker-js/faker';

Expand Down Expand Up @@ -55,6 +56,7 @@ export type NormalizedOutputOptions = {
indexFiles: boolean;
baseUrl?: string;
allParamsOptional: boolean;
urlEncodeParameters: boolean;
};

export type NormalizedParamsSerializerOptions = {
Expand Down Expand Up @@ -172,6 +174,7 @@ export type OutputOptions = {
indexFiles?: boolean;
baseUrl?: string;
allParamsOptional?: boolean;
urlEncodeParameters?: boolean;
};

export type SwaggerParserOptions = Omit<SwaggerParser.Options, 'validate'> & {
Expand All @@ -197,6 +200,7 @@ export const OutputClient = {
SVELTE_QUERY: 'svelte-query',
VUE_QUERY: 'vue-query',
SWR: 'swr',
ZOD: 'zod',
} as const;

export type OutputClient = typeof OutputClient[keyof typeof OutputClient];
Expand Down Expand Up @@ -606,6 +610,7 @@ export type ClientBuilder = (
verbOptions: GeneratorVerbOptions,
options: GeneratorOptions,
outputClient: OutputClient | OutputClientFunc,
output?: NormalizedOutputOptions,
) => GeneratorClient | Promise<GeneratorClient>;

export type ClientHeaderBuilder = (params: {
Expand Down Expand Up @@ -818,6 +823,7 @@ export type GeneratorClientTitle = (data: {
outputClient?: OutputClient | OutputClientFunc;
title: string;
customTitleFunc?: (title: string) => string;
output: NormalizedOutputOptions;
}) => GeneratorClientExtra;

export type GeneratorClientHeader = (data: {
Expand All @@ -828,6 +834,7 @@ export type GeneratorClientHeader = (data: {
provideIn: boolean | 'root' | 'any';
hasAwaitedType: boolean;
titles: GeneratorClientExtra;
output: NormalizedOutputOptions;
}) => GeneratorClientExtra;

export type GeneratorClientFooter = (data: {
Expand All @@ -836,6 +843,7 @@ export type GeneratorClientFooter = (data: {
hasMutator: boolean;
hasAwaitedType: boolean;
titles: GeneratorClientExtra;
output: NormalizedOutputOptions;
}) => GeneratorClientExtra;

export type GeneratorClientImports = (data: {
Expand All @@ -851,6 +859,7 @@ export type GeneratorClientImports = (data: {
hasGlobalMutator: boolean;
hasParamsSerializerOptions: boolean;
packageJson?: PackageJson;
output: NormalizedOutputOptions;
}) => string;

export type GenerateMockImports = (data: {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/writers/single-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const writeSingleMode = async ({
hasGlobalMutator: !!output.override.mutator,
hasParamsSerializerOptions: !!output.override.paramsSerializerOptions,
packageJson: output.packageJson,
output,
});

if (output.mock) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/writers/split-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const writeSplitMode = async ({
hasGlobalMutator: !!output.override.mutator,
hasParamsSerializerOptions: !!output.override.paramsSerializerOptions,
packageJson: output.packageJson,
output,
});
mockData += builder.importsMock({
implementation: implementationMock,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/writers/split-tags-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const writeSplitTagsMode = async ({
hasGlobalMutator: !!output.override.mutator,
hasParamsSerializerOptions: !!output.override.paramsSerializerOptions,
packageJson: output.packageJson,
output,
});
mockData += builder.importsMock({
implementation: implementationMock,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/writers/tags-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const writeTagsMode = async ({
hasGlobalMutator: !!output.override.mutator,
hasParamsSerializerOptions: !!output.override.paramsSerializerOptions,
packageJson: output.packageJson,
output,
});

if (output.mock) {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/writers/target-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const generateTargetForTags = (
outputClient: options.client,
title: pascal(tag),
customTitleFunc: options.override.title,
output: options,
});

const footer = builder.footer({
Expand All @@ -126,6 +127,7 @@ export const generateTargetForTags = (
hasMutator: !!target.mutators?.length,
hasAwaitedType,
titles,
output: options,
});

const header = builder.header({
Expand All @@ -136,6 +138,7 @@ export const generateTargetForTags = (
provideIn: options.override.angular.provideIn,
hasAwaitedType,
titles,
output: options,
});

acc[tag] = {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/writers/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const generateTarget = (
outputClient: options.client,
title: pascal(builder.info.title),
customTitleFunc: options.override.title,
output: options,
});

const target = Object.values(builder.operations).reduce(
Expand Down Expand Up @@ -67,6 +68,7 @@ export const generateTarget = (
provideIn: options.override.angular.provideIn,
hasAwaitedType,
titles,
output: options,
});
acc.implementation = header.implementation + acc.implementation;
acc.implementationMock.handler =
Expand All @@ -78,6 +80,7 @@ export const generateTarget = (
hasMutator: !!acc.mutators.length,
hasAwaitedType,
titles,
output: options,
});
acc.implementation += footer.implementation;
acc.implementationMock.handler += footer.implementationMock;
Expand Down
3 changes: 2 additions & 1 deletion packages/orval/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"build": "tsup ./src/bin/orval.ts ./src/index.ts --target node12 --clean --dts",
"dev": "tsup ./src/bin/orval.ts ./src/index.ts --target node12 --clean --watch ./src --onSuccess 'yarn generate-api'",
"lint": "eslint src/**/*.ts",
"generate-api": "node ./dist/bin/orval.js --config ../../samples/react-query/basic/orval.config.ts"
"generate-api": "node ./dist/bin/orval.js --config ../../samples/react-query/basic/orval.config.ts",
"test": "tsc --noEmit && vitest --passWithNoTests"
},
"devDependencies": {
"@types/inquirer": "^9.0.6",
Expand Down
2 changes: 2 additions & 0 deletions packages/orval/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ export const getApiBuilder = async ({
override: output.override,
context: resolvedContext,
mock: output.mock,
// @ts-expect-error // FIXME
output: output.target,
},
output,
);

acc.schemas.push(...schemas);
Expand Down
53 changes: 36 additions & 17 deletions packages/orval/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
GeneratorVerbOptions,
GeneratorVerbsOptions,
isFunction,
NormalizedOutputOptions,
OutputClient,
OutputClientFunc,
pascal,
Expand All @@ -24,18 +25,21 @@ import zod from '@orval/zod';

const DEFAULT_CLIENT = OutputClient.AXIOS;

export const GENERATOR_CLIENT: GeneratorClients = {
axios: axios({ type: 'axios' })(),
'axios-functions': axios({ type: 'axios-functions' })(),
angular: angular()(),
'react-query': query({ type: 'react-query' })(),
'svelte-query': query({ type: 'svelte-query' })(),
'vue-query': query({ type: 'vue-query' })(),
swr: swr()(),
zod: zod()(),
};
const getGeneratorClient = (
outputClient: OutputClient | OutputClientFunc,
output: NormalizedOutputOptions,
) => {
const GENERATOR_CLIENT: GeneratorClients = {
axios: axios({ type: 'axios' })(),
'axios-functions': axios({ type: 'axios-functions' })(),
angular: angular()(),
'react-query': query({ output, type: 'react-query' })(),
'svelte-query': query({ output, type: 'svelte-query' })(),
'vue-query': query({ output, type: 'vue-query' })(),
swr: swr()(),
zod: zod()(),
};

const getGeneratorClient = (outputClient: OutputClient | OutputClientFunc) => {
const generator = isFunction(outputClient)
? outputClient(GENERATOR_CLIENT)
: GENERATOR_CLIENT[outputClient];
Expand All @@ -57,8 +61,9 @@ export const generateClientImports: GeneratorClientImports = ({
hasGlobalMutator,
hasParamsSerializerOptions,
packageJson,
output,
}) => {
const { dependencies } = getGeneratorClient(client);
const { dependencies } = getGeneratorClient(client, output);
return generateDependencyImports(
implementation,
dependencies
Expand All @@ -85,8 +90,9 @@ export const generateClientHeader: GeneratorClientHeader = ({
provideIn,
hasAwaitedType,
titles,
output,
}) => {
const { header } = getGeneratorClient(outputClient);
const { header } = getGeneratorClient(outputClient, output);
return {
implementation: header
? header({
Expand All @@ -108,8 +114,9 @@ export const generateClientFooter: GeneratorClientFooter = ({
hasMutator,
hasAwaitedType,
titles,
output,
}) => {
const { footer } = getGeneratorClient(outputClient);
const { footer } = getGeneratorClient(outputClient, output);

if (!footer) {
return {
Expand Down Expand Up @@ -155,8 +162,9 @@ export const generateClientTitle: GeneratorClientTitle = ({
outputClient = DEFAULT_CLIENT,
title,
customTitleFunc,
output,
}) => {
const { title: generatorTitle } = getGeneratorClient(outputClient);
const { title: generatorTitle } = getGeneratorClient(outputClient, output);

if (!generatorTitle) {
return {
Expand Down Expand Up @@ -196,18 +204,27 @@ const generateMock = (
return options.mock(verbOption, options);
}

return mock.generateMock(verbOption, options);
return mock.generateMock(
verbOption,
options as typeof options & {
mock: Exclude<typeof options['mock'], Function | undefined>;
},
);
};

export const generateOperations = (
outputClient: OutputClient | OutputClientFunc = DEFAULT_CLIENT,
verbsOptions: GeneratorVerbsOptions,
options: GeneratorOptions,
output: NormalizedOutputOptions,
): Promise<GeneratorOperations> => {
return asyncReduce(
verbsOptions,
async (acc, verbOption) => {
const { client: generatorClient } = getGeneratorClient(outputClient);
const { client: generatorClient } = getGeneratorClient(
outputClient,
output,
);
const client = await generatorClient(verbOption, options, outputClient);
const generatedMock = generateMock(verbOption, options);

Expand All @@ -218,7 +235,9 @@ export const generateOperations = (
acc[verbOption.operationId] = {
implementation: verbOption.doc + client.implementation,
imports: client.imports,
// @ts-expect-error // FIXME
implementationMock: generatedMock.implementation,
// @ts-expect-error // FIXME
importsMock: generatedMock.imports,
tags: verbOption.tags,
mutator: verbOption.mutator,
Expand Down
1 change: 1 addition & 0 deletions packages/orval/src/import-open-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const importOpenApi = async ({
const schemas = getApiSchemas({ output, target, workspace, specs });

const api = await getApiBuilder({
// @ts-expect-error // FIXME
input,
output,
context: {
Expand Down
5 changes: 5 additions & 0 deletions packages/orval/src/import-specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,19 @@ export const importSpecs = async (
if (isObject(input.target)) {
return importOpenApi({
data: { [workspace]: input.target },
// @ts-expect-error // FIXME
input,
output,
target: workspace,
workspace,
});
}

// @ts-expect-error // FIXME
const isPathUrl = isUrl(input.target);

const data = await resolveSpecs(
// @ts-expect-error // FIXME
input.target,
input.parserOptions,
isPathUrl,
Expand All @@ -81,8 +84,10 @@ export const importSpecs = async (

return importOpenApi({
data,
// @ts-expect-error // FIXME
input,
output,
// @ts-expect-error // FIXME
target: input.target,
workspace,
});
Expand Down
1 change: 1 addition & 0 deletions packages/orval/src/utils/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export const normalizeOptions = async (
useNativeEnums: outputOptions.override?.useNativeEnums ?? false,
},
allParamsOptional: outputOptions.allParamsOptional ?? false,
urlEncodeParameters: outputOptions.urlEncodeParameters ?? false,
},
hooks: options.hooks ? normalizeHooks(options.hooks) : {},
};
Expand Down
Loading

0 comments on commit ff2b7d3

Please sign in to comment.