Skip to content

Commit

Permalink
feat(namedParameters): Add global named parameters option (orval-labs…
Browse files Browse the repository at this point in the history
…#914)

* fix: correct `jsStringEscape` import

* feat(namedParameters): add global `useNamedParameters` option

* feat(namedParameters): add NAMED_PATH_PARAMS prop type

* test(axios): add named parameters test

* test(angular): add named parameters test

* test(react-query): add named parameters test

* fix(query): introduce destructured usage

* test(svelte-query): add named parameters test

* test(vue-query): add named parameters test

* fix(vue-query): rework MaybeRef logic

* fix(swr): introduce destructured usage

* test(swr): add named parameters test

* chore(cra): update react-scripts

* fix(angular-app): update sample

* fix(react-app): update sample

* fix(react-app-with-swr): update sample

* fix(react-query/basic-app): update sample

* fix(react-query/custom-client-app): update sample

* fix(react-query/form-data-app): update sample

* fix(react-query/form-data-mutator-app): update sample

* fix(react-query/form-url-encoded-mutator-app): update sample

* fix(react-query/hook-mutator-app): update sample

* fix(svelte-query): update sample

* fix(vue-query-app): update sample

* fix(namedParameters): optional arg when all params are optional
  • Loading branch information
Marcel-G authored Sep 11, 2023
1 parent 4285634 commit 663cafa
Show file tree
Hide file tree
Showing 58 changed files with 25,466 additions and 31,250 deletions.
22 changes: 22 additions & 0 deletions docs/src/pages/reference/configuration/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,28 @@ module.exports = {
};
```

#### useNamedParameters

Type: `Boolean`.

Default Value: `false`.

Generates the operation interfaces with named path parameters instead of individual arguments for each path parameter.

Example:

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

#### useTypeOverInterfaces

Type: `Boolean`
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/generators/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
GeneratorImport,
GeneratorMutator,
GeneratorVerbOptions,
GetterPropType,
} from '../types';
import { camel, upath } from '../utils';

Expand Down Expand Up @@ -275,11 +276,17 @@ export const generateVerbImports = ({
response,
body,
queryParams,
props,
headers,
params,
}: GeneratorVerbOptions): GeneratorImport[] => [
...response.imports,
...body.imports,
...props.flatMap((prop) =>
prop.type === GetterPropType.NAMED_PATH_PARAMS
? [{ name: prop.schema.name }]
: [],
),
...(queryParams ? [{ name: queryParams.schema.name }] : []),
...(headers ? [{ name: headers.schema.name }] : []),
...params.flatMap<GeneratorImport>(({ imports }) => imports),
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/generators/verbs-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ const generateVerbOptions = async ({
context,
});

const props = getProps({ body, queryParams, params, headers });
const props = getProps({
body,
queryParams,
params,
headers,
operationId,
context,
});

const mutator = await generateMutator({
output: output.target,
Expand Down
55 changes: 53 additions & 2 deletions packages/core/src/getters/props.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import {
ContextSpecs,
GetterBody,
GetterParams,
GetterProps,
GetterPropType,
GetterQueryParam,
} from '../types';
import { isUndefined, sortByPriority } from '../utils';
import { isUndefined, pascal, sortByPriority } from '../utils';

export const getProps = ({
body,
queryParams,
params,
operationId,
headers,
context,
}: {
body: GetterBody;
queryParams?: GetterQueryParam;
params: GetterParams;
operationId: string;
headers?: GetterQueryParam;
context: ContextSpecs;
}): GetterProps => {
const bodyProp = {
name: body.implementation,
Expand Down Expand Up @@ -55,8 +60,54 @@ export const getProps = ({
type: GetterPropType.HEADER,
};

let paramGetterProps: GetterProps;
if (context.override.useNamedParameters && params.length > 0) {
const parameterTypeName = `${pascal(operationId)}PathParameters`;

const name = 'pathParams';

// needs a special model
const namedParametersTypeDefinition = `export type ${parameterTypeName} = {\n ${params
.map((property) => property.definition)
.join(',\n ')},\n }`;

const isOptional = params.every((param) => param.default);

const implementation = `{ ${params
.map((property) =>
property.default ? property.implementation : property.name,
)
.join(', ')} }: ${parameterTypeName}${isOptional ? ' = {}' : ''}`;

const destructured = `{ ${params
.map((property) => property.name)
.join(', ')} }`;

paramGetterProps = [
{
type: GetterPropType.NAMED_PATH_PARAMS,
name,
definition: `${name}: ${parameterTypeName}`,
implementation,
default: false,
destructured,
required: true,
schema: {
name: parameterTypeName,
model: namedParametersTypeDefinition,
imports: params.flatMap((property) => property.imports),
},
},
];
} else {
paramGetterProps = params.map((param) => ({
...param,
type: GetterPropType.PARAM,
}));
}

const props = [
...params.map((param) => ({ ...param, type: GetterPropType.PARAM })),
...paramGetterProps,
...(body.definition ? [bodyProp] : []),
...(queryParams ? [queryParamsProp] : []),
...(headers ? [headersProp] : []),
Expand Down
31 changes: 22 additions & 9 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export type NormalizedOverrideOutput = {
useTypeOverInterfaces?: boolean;
useDeprecatedOperations?: boolean;
useBigInt?: boolean;
useNamedParameters?: boolean;
};

export type NormalizedMutator = {
Expand Down Expand Up @@ -281,6 +282,7 @@ export type OverrideOutput = {
useTypeOverInterfaces?: boolean;
useDeprecatedOperations?: boolean;
useBigInt?: boolean;
useNamedParameters?: boolean;
};

export type OverrideOutputContentType = {
Expand Down Expand Up @@ -660,24 +662,35 @@ export type GetterQueryParam = {
originalSchema?: SchemaObject;
};

export type GetterPropType = 'param' | 'body' | 'queryParam' | 'header';
export type GetterPropType =
| 'param'
| 'body'
| 'queryParam'
| 'header'
| 'namedPathParams';

export const GetterPropType = {
PARAM: 'param' as GetterPropType,
BODY: 'body' as GetterPropType,
QUERY_PARAM: 'queryParam' as GetterPropType,
HEADER: 'header' as GetterPropType,
};

export type GetterProp = {
PARAM: 'param',
NAMED_PATH_PARAMS: 'namedPathParams',
BODY: 'body',
QUERY_PARAM: 'queryParam',
HEADER: 'header',
} as const;

type GetterPropBase = {
name: string;
definition: string;
implementation: string;
default: boolean;
required: boolean;
type: GetterPropType;
};

export type GetterProp = GetterPropBase &
(
| { type: 'namedPathParams'; destructured: string; schema: GeneratorSchema }
| { type: Exclude<GetterPropType, 'namedPathParams'> }
);

export type GetterProps = GetterProp[];

export type SchemaType =
Expand Down
12 changes: 11 additions & 1 deletion packages/orval/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GeneratorApiOperations,
GeneratorSchema,
getRoute,
GetterPropType,
isReference,
NormalizedInputOptions,
NormalizedOutputOptions,
Expand Down Expand Up @@ -69,7 +70,16 @@ export const getApiBuilder = async ({
}

const schemas = verbsOptions.reduce(
(acc, { queryParams, headers, body, response }) => {
(acc, { queryParams, headers, body, response, props }) => {
if (props) {
acc.push(
...props.flatMap((param) =>
param.type === GetterPropType.NAMED_PATH_PARAMS
? param.schema
: [],
),
);
}
if (queryParams) {
acc.push(queryParams.schema, ...queryParams.deps);
}
Expand Down
Loading

0 comments on commit 663cafa

Please sign in to comment.