Skip to content

Commit 2945be4

Browse files
authored
Merge pull request #1827 from john-cremit/feat/add-pagination-keywords-config
2 parents 052a7c6 + 9dd43db commit 2945be4

File tree

8 files changed

+108
-32
lines changed

8 files changed

+108
-32
lines changed

.changeset/sweet-cycles-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hey-api/openapi-ts": patch
3+
---
4+
5+
feat: allow customizing pagination keywords using `input.pagination.keywords`

packages/openapi-ts/src/ir/__tests__/pagination.test.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { describe, expect, it } from 'vitest';
22

3-
import { paginationKeywordsRegExp } from '../pagination';
3+
import type { Config } from '../../types/config';
4+
import { getPaginationKeywordsRegExp } from '../pagination';
45

56
describe('paginationKeywordsRegExp', () => {
6-
const scenarios: Array<{
7+
const defaultScenarios: Array<{
78
result: boolean;
89
value: string;
910
}> = [
@@ -41,11 +42,33 @@ describe('paginationKeywordsRegExp', () => {
4142
},
4243
];
4344

44-
it.each(scenarios)(
45+
it.each(defaultScenarios)(
4546
'is $value pagination param? $output',
4647
async ({ result, value }) => {
47-
paginationKeywordsRegExp.lastIndex = 0;
48-
expect(paginationKeywordsRegExp.test(value)).toEqual(result);
48+
const paginationRegExp = getPaginationKeywordsRegExp();
49+
expect(paginationRegExp.test(value)).toEqual(result);
50+
},
51+
);
52+
53+
const customScenarios: Array<{
54+
result: boolean;
55+
value: string;
56+
}> = [
57+
{ result: true, value: 'customPagination' },
58+
{ result: true, value: 'pageSize' },
59+
{ result: true, value: 'perPage' },
60+
{ result: false, value: 'page' },
61+
];
62+
63+
it.each(customScenarios)(
64+
'with custom config, $value should match? $result',
65+
async ({ result, value }) => {
66+
const pagination: Config['input']['pagination'] = {
67+
keywords: ['customPagination', 'pageSize', 'perPage'],
68+
};
69+
70+
const paginationRegExp = getPaginationKeywordsRegExp(pagination);
71+
expect(paginationRegExp.test(value)).toEqual(result);
4972
},
5073
);
5174
});

packages/openapi-ts/src/ir/pagination.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1+
import type { Config } from '../types/config';
12
import type { IR } from './types';
23

3-
export const paginationKeywordsRegExp =
4-
/^(after|before|cursor|offset|page|start)$/;
4+
export const DEFAULT_PAGINATION_KEYWORDS = [
5+
'after',
6+
'before',
7+
'cursor',
8+
'offset',
9+
'page',
10+
'start',
11+
] as const;
12+
13+
export function getPaginationKeywordsRegExp({
14+
keywords = DEFAULT_PAGINATION_KEYWORDS,
15+
}: Config['input']['pagination'] = {}): RegExp {
16+
if (keywords.length === 0) {
17+
keywords = DEFAULT_PAGINATION_KEYWORDS;
18+
}
19+
const pattern = `^(${keywords.join('|')})$`;
20+
return new RegExp(pattern);
21+
}
522

623
export interface Pagination {
724
in: string;

packages/openapi-ts/src/openApi/2.0.x/parser/pagination.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { paginationKeywordsRegExp } from '../../../ir/pagination';
1+
import { getPaginationKeywordsRegExp } from '../../../ir/pagination';
22
import type { IR } from '../../../ir/types';
33
import type { SchemaType } from '../../shared/types/schema';
44
import type { ParameterObject, ReferenceObject } from '../types/spec';
5-
import { type SchemaObject } from '../types/spec';
5+
import type { SchemaObject } from '../types/spec';
66
import { getSchemaType } from './schema';
77

88
const isPaginationType = (
@@ -29,8 +29,10 @@ export const paginationField = ({
2929
in: undefined;
3030
};
3131
}): boolean | string => {
32-
paginationKeywordsRegExp.lastIndex = 0;
33-
if (paginationKeywordsRegExp.test(name)) {
32+
const paginationRegExp = getPaginationKeywordsRegExp(
33+
context.config.input.pagination,
34+
);
35+
if (paginationRegExp.test(name)) {
3436
return true;
3537
}
3638

@@ -83,9 +85,11 @@ export const paginationField = ({
8385
}
8486

8587
for (const name in schema.properties) {
86-
paginationKeywordsRegExp.lastIndex = 0;
88+
const paginationRegExp = getPaginationKeywordsRegExp(
89+
context.config.input.pagination,
90+
);
8791

88-
if (paginationKeywordsRegExp.test(name)) {
92+
if (paginationRegExp.test(name)) {
8993
const property = schema.properties[name]!;
9094

9195
if (typeof property !== 'boolean' && !('$ref' in property)) {

packages/openapi-ts/src/openApi/3.0.x/parser/pagination.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { paginationKeywordsRegExp } from '../../../ir/pagination';
1+
import { getPaginationKeywordsRegExp } from '../../../ir/pagination';
22
import type { IR } from '../../../ir/types';
33
import type { SchemaType } from '../../shared/types/schema';
44
import type {
55
ParameterObject,
66
ReferenceObject,
77
RequestBodyObject,
88
} from '../types/spec';
9-
import { type SchemaObject } from '../types/spec';
9+
import type { SchemaObject } from '../types/spec';
1010
import { mediaTypeObject } from './mediaType';
1111
import { getSchemaType } from './schema';
1212

@@ -28,8 +28,10 @@ export const paginationField = ({
2828
name: string;
2929
schema: SchemaObject | ReferenceObject;
3030
}): boolean | string => {
31-
paginationKeywordsRegExp.lastIndex = 0;
32-
if (paginationKeywordsRegExp.test(name)) {
31+
const paginationRegExp = getPaginationKeywordsRegExp(
32+
context.config.input.pagination,
33+
);
34+
if (paginationRegExp.test(name)) {
3335
return true;
3436
}
3537

@@ -72,9 +74,11 @@ export const paginationField = ({
7274
}
7375

7476
for (const name in schema.properties) {
75-
paginationKeywordsRegExp.lastIndex = 0;
77+
const paginationRegExp = getPaginationKeywordsRegExp(
78+
context.config.input.pagination,
79+
);
7680

77-
if (paginationKeywordsRegExp.test(name)) {
81+
if (paginationRegExp.test(name)) {
7882
const property = schema.properties[name]!;
7983

8084
if (typeof property !== 'boolean' && !('$ref' in property)) {

packages/openapi-ts/src/openApi/3.1.x/parser/pagination.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { paginationKeywordsRegExp } from '../../../ir/pagination';
1+
import { getPaginationKeywordsRegExp } from '../../../ir/pagination';
22
import type { IR } from '../../../ir/types';
33
import type { SchemaType } from '../../shared/types/schema';
44
import type { ParameterObject, RequestBodyObject } from '../types/spec';
5-
import { type SchemaObject } from '../types/spec';
5+
import type { SchemaObject } from '../types/spec';
66
import { mediaTypeObject } from './mediaType';
77
import { getSchemaTypes } from './schema';
88

@@ -24,8 +24,10 @@ export const paginationField = ({
2424
name: string;
2525
schema: SchemaObject;
2626
}): boolean | string => {
27-
paginationKeywordsRegExp.lastIndex = 0;
28-
if (paginationKeywordsRegExp.test(name)) {
27+
const paginationRegExp = getPaginationKeywordsRegExp(
28+
context.config.input.pagination,
29+
);
30+
if (paginationRegExp.test(name)) {
2931
return true;
3032
}
3133

@@ -68,9 +70,11 @@ export const paginationField = ({
6870
}
6971

7072
for (const name in schema.properties) {
71-
paginationKeywordsRegExp.lastIndex = 0;
73+
const paginationRegExp = getPaginationKeywordsRegExp(
74+
context.config.input.pagination,
75+
);
7276

73-
if (paginationKeywordsRegExp.test(name)) {
77+
if (paginationRegExp.test(name)) {
7478
const property = schema.properties[name]!;
7579

7680
if (typeof property !== 'boolean') {

packages/openapi-ts/src/plugins/@tanstack/query-core/plugin-legacy.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ImportExportItem } from '../../../compiler/module';
55
import type { ImportExportItemObject } from '../../../compiler/utils';
66
import { clientApi, clientModulePath } from '../../../generate/client';
77
import { relativeModulePath } from '../../../generate/utils';
8-
import { paginationKeywordsRegExp } from '../../../ir/pagination';
8+
import { getPaginationKeywordsRegExp } from '../../../ir/pagination';
99
import type { IR } from '../../../ir/types';
1010
import { isOperationParameterRequired } from '../../../openApi';
1111
import { getOperationKey } from '../../../openApi/common/parser/operation';
@@ -900,8 +900,10 @@ export const handlerLegacy: Plugin.LegacyHandler<
900900
let paginationField!: Model | OperationParameter;
901901

902902
const paginationParameter = operation.parameters.find((parameter) => {
903-
paginationKeywordsRegExp.lastIndex = 0;
904-
if (paginationKeywordsRegExp.test(parameter.name)) {
903+
const paginationRegExp = getPaginationKeywordsRegExp(
904+
config.input.pagination,
905+
);
906+
if (paginationRegExp.test(parameter.name)) {
905907
paginationField = parameter;
906908
return true;
907909
}
@@ -916,17 +918,21 @@ export const handlerLegacy: Plugin.LegacyHandler<
916918
(model) => model.meta?.$ref === ref,
917919
);
918920
return refModel?.properties.find((property) => {
919-
paginationKeywordsRegExp.lastIndex = 0;
920-
if (paginationKeywordsRegExp.test(property.name)) {
921+
const paginationRegExp = getPaginationKeywordsRegExp(
922+
config.input.pagination,
923+
);
924+
if (paginationRegExp.test(property.name)) {
921925
paginationField = property;
922926
return true;
923927
}
924928
});
925929
}
926930

927931
return parameter.properties.find((property) => {
928-
paginationKeywordsRegExp.lastIndex = 0;
929-
if (paginationKeywordsRegExp.test(property.name)) {
932+
const paginationRegExp = getPaginationKeywordsRegExp(
933+
config.input.pagination,
934+
);
935+
if (paginationRegExp.test(property.name)) {
930936
paginationField = property;
931937
return true;
932938
}

packages/openapi-ts/src/types/config.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ interface Input {
6565
* Organization created in Hey API platform.
6666
*/
6767
organization?: string;
68+
/**
69+
* Pagination configuration
70+
*/
71+
pagination?: {
72+
/**
73+
* Array of keywords to be considered as pagination field names.
74+
* These will be used to detect pagination fields in schemas and parameters.
75+
*
76+
* @default ['after', 'before', 'cursor', 'offset', 'page', 'start']
77+
*/
78+
keywords?: ReadonlyArray<string>;
79+
};
6880
/**
6981
* Path to the OpenAPI specification. This can be either local or remote path.
7082
* Both JSON and YAML file formats are supported. You can also pass the parsed
@@ -88,6 +100,7 @@ interface Input {
88100
* the first match will be returned.
89101
*/
90102
tags?: ReadonlyArray<string>;
103+
91104
/**
92105
* **Requires `path` to start with `https://get.heyapi.dev` or be undefined**
93106
*

0 commit comments

Comments
 (0)