@sdk-it/spec 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/lib/create-operation.d.ts +28 -0
- package/dist/lib/create-operation.d.ts.map +1 -0
- package/dist/lib/create-operation.js +62 -0
- package/dist/lib/create-operation.js.map +7 -0
- package/dist/lib/for-each-operation.d.ts.map +1 -1
- package/dist/lib/for-each-operation.js +0 -3
- package/dist/lib/for-each-operation.js.map +2 -2
- package/dist/lib/get-ref-usage.d.ts +1 -1
- package/dist/lib/get-ref-usage.js.map +1 -1
- package/dist/lib/guess/guess-resource.d.ts +7 -0
- package/dist/lib/guess/guess-resource.d.ts.map +1 -0
- package/dist/lib/guess/guess-resource.js +76 -0
- package/dist/lib/guess/guess-resource.js.map +7 -0
- package/dist/lib/metadata.d.ts +2 -2
- package/dist/lib/metadata.d.ts.map +1 -1
- package/dist/lib/metadata.js +17 -5
- package/dist/lib/metadata.js.map +2 -2
- package/dist/lib/metadata.test.d.ts +2 -0
- package/dist/lib/metadata.test.d.ts.map +1 -0
- package/dist/lib/metadata.test.js +359 -0
- package/dist/lib/metadata.test.js.map +7 -0
- package/dist/lib/operation.d.ts +1 -32
- package/dist/lib/operation.d.ts.map +1 -1
- package/dist/lib/operation.js +32 -312
- package/dist/lib/operation.js.map +2 -2
- package/dist/lib/options.d.ts +42 -1
- package/dist/lib/options.d.ts.map +1 -1
- package/dist/lib/options.js +23 -8
- package/dist/lib/options.js.map +2 -2
- package/dist/lib/pagination/guess-pagination.d.ts +50 -0
- package/dist/lib/pagination/guess-pagination.d.ts.map +1 -0
- package/dist/lib/pagination/guess-pagination.js +222 -0
- package/dist/lib/pagination/guess-pagination.js.map +7 -0
- package/dist/lib/pagination/pagination.d.ts +2 -49
- package/dist/lib/pagination/pagination.d.ts.map +1 -1
- package/dist/lib/pagination/pagination.js +43 -209
- package/dist/lib/pagination/pagination.js.map +2 -2
- package/dist/lib/pagination/pagination.test.js +2 -1
- package/dist/lib/pagination/pagination.test.js.map +2 -2
- package/dist/lib/security.d.ts +1 -1
- package/dist/lib/security.js.map +1 -1
- package/dist/lib/sidebar.d.ts +5 -24
- package/dist/lib/sidebar.d.ts.map +1 -1
- package/dist/lib/sidebar.js +22 -65
- package/dist/lib/sidebar.js.map +3 -3
- package/dist/lib/tune-request-body.d.ts +5 -0
- package/dist/lib/tune-request-body.d.ts.map +1 -0
- package/dist/lib/tune-request-body.js +88 -0
- package/dist/lib/tune-request-body.js.map +7 -0
- package/dist/lib/tune-response.d.ts +5 -0
- package/dist/lib/tune-response.d.ts.map +1 -0
- package/dist/lib/tune-response.js +102 -0
- package/dist/lib/tune-response.js.map +7 -0
- package/dist/lib/types.d.ts +8 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SchemaObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import type { TunedOperationObject } from '../types.js';
|
|
3
|
+
interface PaginationResultBase {
|
|
4
|
+
type: 'offset' | 'page' | 'cursor' | 'none';
|
|
5
|
+
}
|
|
6
|
+
export interface OffsetPaginationResult extends PaginationResultBase {
|
|
7
|
+
type: 'offset';
|
|
8
|
+
offsetParamName: string;
|
|
9
|
+
offsetKeyword: string;
|
|
10
|
+
limitParamName: string;
|
|
11
|
+
limitKeyword: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PagePaginationResult extends PaginationResultBase {
|
|
14
|
+
type: 'page';
|
|
15
|
+
pageNumberParamName: string;
|
|
16
|
+
pageNumberKeyword: string;
|
|
17
|
+
pageSizeParamName: string;
|
|
18
|
+
pageSizeKeyword: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CursorPaginationResult extends PaginationResultBase {
|
|
21
|
+
type: 'cursor';
|
|
22
|
+
cursorParamName: string;
|
|
23
|
+
cursorKeyword: string;
|
|
24
|
+
limitParamName: string;
|
|
25
|
+
limitKeyword: string;
|
|
26
|
+
}
|
|
27
|
+
export interface NoPaginationResult extends PaginationResultBase {
|
|
28
|
+
type: 'none';
|
|
29
|
+
reason: string;
|
|
30
|
+
}
|
|
31
|
+
export type PaginationGuess = ((OffsetPaginationResult | PagePaginationResult | CursorPaginationResult) & {
|
|
32
|
+
items: string;
|
|
33
|
+
hasMore: string;
|
|
34
|
+
}) | NoPaginationResult;
|
|
35
|
+
export declare const OFFSET_PARAM_REGEXES: RegExp[];
|
|
36
|
+
export declare const GENERIC_LIMIT_PARAM_REGEXES: RegExp[];
|
|
37
|
+
export declare const PAGE_NUMBER_REGEXES: RegExp[];
|
|
38
|
+
export declare const PAGE_SIZE_REGEXES: RegExp[];
|
|
39
|
+
export declare const CURSOR_REGEXES: RegExp[];
|
|
40
|
+
export declare const CURSOR_LIMIT_REGEXES: RegExp[];
|
|
41
|
+
/**
|
|
42
|
+
* Guesses the pagination strategy of an OpenAPI operation based on its query parameters.
|
|
43
|
+
* It checks for offset, page-based, and cursor-based pagination in that order.
|
|
44
|
+
*
|
|
45
|
+
* @param operation The OpenAPI operation object.
|
|
46
|
+
* @returns A PaginationGuess object indicating the detected type and relevant parameters.
|
|
47
|
+
*/
|
|
48
|
+
export declare function guessPagination(operation: TunedOperationObject, body?: SchemaObject, response?: SchemaObject): PaginationGuess;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=guess-pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guess-pagination.d.ts","sourceRoot":"","sources":["../../../src/lib/pagination/guess-pagination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAK3B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GACvB,CAAC,CACG,sBAAsB,GACtB,oBAAoB,GACpB,sBAAsB,CACzB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACvC,kBAAkB,CAAC;AAIvB,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAKxC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAAM,EAU/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAMvC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAUrC,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,MAAM,EAWlC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAUxC,CAAC;AA4IF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,oBAAoB,EAC/B,IAAI,CAAC,EAAE,YAAY,EACnB,QAAQ,CAAC,EAAE,YAAY,GACtB,eAAe,CAqCjB"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { isRef } from "@sdk-it/core/ref.js";
|
|
2
|
+
import { isEmpty } from "@sdk-it/core/utils.js";
|
|
3
|
+
import { getHasMoreName, getItemsName } from "./pagination-result.js";
|
|
4
|
+
const OFFSET_PARAM_REGEXES = [
|
|
5
|
+
/\boffset\b/i,
|
|
6
|
+
/\bskip\b/i,
|
|
7
|
+
/\bstart(?:ing_at|_index)?\b/i,
|
|
8
|
+
// e.g., start, starting_at, start_index
|
|
9
|
+
/\bfrom\b/i
|
|
10
|
+
];
|
|
11
|
+
const GENERIC_LIMIT_PARAM_REGEXES = [
|
|
12
|
+
/\blimit\b/i,
|
|
13
|
+
/\bcount\b/i,
|
|
14
|
+
/\b(?:page_?)?size\b/i,
|
|
15
|
+
// e.g., size, page_size, pagesize
|
|
16
|
+
/\bmax_results\b/i,
|
|
17
|
+
/\bnum_results\b/i,
|
|
18
|
+
/\bshow\b/i,
|
|
19
|
+
// Can sometimes mean limit
|
|
20
|
+
/\bper_?page\b/i,
|
|
21
|
+
// e.g., per_page, perpage
|
|
22
|
+
/\bper-page\b/i,
|
|
23
|
+
/\btake\b/i
|
|
24
|
+
];
|
|
25
|
+
const PAGE_NUMBER_REGEXES = [
|
|
26
|
+
// /^(currentPage)?page$/i, // Exact match for "page"
|
|
27
|
+
// /^currentPage$/i, // Exact match for "currentPage"
|
|
28
|
+
/^p$/i,
|
|
29
|
+
// Exact match for "p" (common shorthand)
|
|
30
|
+
// /\bpage_?(?:number|no|num|idx|index)\b/i, // e.g., page_number, pageNumber, page_num, page_idx
|
|
31
|
+
/^(current)?_?page(_?)(?:number|no|num|idx|index)?\b/i
|
|
32
|
+
];
|
|
33
|
+
const PAGE_SIZE_REGEXES = [
|
|
34
|
+
/\bpage_?size\b/i,
|
|
35
|
+
// e.g., page_size, pagesize
|
|
36
|
+
/^size$/i,
|
|
37
|
+
// Exact "size"
|
|
38
|
+
// /\bsize\b/i, // Broader "size" - can be ambiguous, prefer more specific ones first
|
|
39
|
+
/\blimit\b/i,
|
|
40
|
+
// Limit is often used for page size
|
|
41
|
+
/\bcount\b/i,
|
|
42
|
+
// Count can also be used for page size
|
|
43
|
+
/\bper_?page\b/i,
|
|
44
|
+
// e.g., per_page, perpage
|
|
45
|
+
/\bper-page\b/i,
|
|
46
|
+
/\bnum_?(?:items|records|results)\b/i,
|
|
47
|
+
// e.g., num_items, numitems
|
|
48
|
+
/\bresults_?per_?page\b/i
|
|
49
|
+
];
|
|
50
|
+
const CURSOR_REGEXES = [
|
|
51
|
+
/\bmarker\b/i,
|
|
52
|
+
/\bcursor\b/i,
|
|
53
|
+
/\bafter(?:_?cursor)?\b/i,
|
|
54
|
+
// e.g., after, after_cursor
|
|
55
|
+
/\bbefore(?:_?cursor)?\b/i,
|
|
56
|
+
// e.g., before, before_cursor
|
|
57
|
+
/\b(next|prev|previous)_?(?:page_?)?token\b/i,
|
|
58
|
+
// e.g., next_page_token, nextPageToken, prev_token
|
|
59
|
+
/\b(next|prev|previous)_?cursor\b/i,
|
|
60
|
+
// e.g., next_cursor, previousCursor
|
|
61
|
+
/\bcontinuation(?:_?token)?\b/i,
|
|
62
|
+
// e.g., continuation, continuation_token
|
|
63
|
+
/\bpage(?:_?(token|id))?\b/i,
|
|
64
|
+
// e.g., after, after_cursor
|
|
65
|
+
/\bstart_?(?:key|cursor|token|after)\b/i
|
|
66
|
+
// e.g., start_key, startCursor, startToken, startAfter
|
|
67
|
+
];
|
|
68
|
+
const CURSOR_LIMIT_REGEXES = [
|
|
69
|
+
/\blimit\b/i,
|
|
70
|
+
/\bcount\b/i,
|
|
71
|
+
/\bsize\b/i,
|
|
72
|
+
// General size
|
|
73
|
+
/\bfirst\b/i,
|
|
74
|
+
// Common in Relay-style cursor pagination (forward pagination)
|
|
75
|
+
/\blast\b/i,
|
|
76
|
+
// Common in Relay-style cursor pagination (backward pagination)
|
|
77
|
+
/\bpage_?size\b/i,
|
|
78
|
+
// Sometimes page_size is used with cursors
|
|
79
|
+
/\bnum_?(?:items|records|results)\b/i,
|
|
80
|
+
// e.g., num_items
|
|
81
|
+
/\bmax_?items\b/i,
|
|
82
|
+
/\btake\b/i
|
|
83
|
+
];
|
|
84
|
+
function findParamAndKeyword(queryParams, regexes, excludeParamName) {
|
|
85
|
+
for (const param of queryParams) {
|
|
86
|
+
if (param.name === excludeParamName) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
for (const regex of regexes) {
|
|
90
|
+
const match = param.name.match(regex);
|
|
91
|
+
if (match) {
|
|
92
|
+
return { param, keyword: match[0] };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function coearceParameters(parameters) {
|
|
99
|
+
const cleanedParameters = [];
|
|
100
|
+
for (const param of parameters) {
|
|
101
|
+
if (!param.schema) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (isRef(param.schema)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!param.schema.type) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (param.schema) {
|
|
111
|
+
cleanedParameters.push({
|
|
112
|
+
...param,
|
|
113
|
+
schema: {
|
|
114
|
+
...param.schema,
|
|
115
|
+
type: Array.isArray(param.schema.type) ? param.schema.type : [param.schema.type]
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return cleanedParameters;
|
|
121
|
+
}
|
|
122
|
+
function isOffsetPagination(operation, parameters) {
|
|
123
|
+
const params = coearceParameters(parameters).filter(
|
|
124
|
+
(it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
|
|
125
|
+
);
|
|
126
|
+
const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);
|
|
127
|
+
if (!offsetMatch) return null;
|
|
128
|
+
const limitMatch = findParamAndKeyword(
|
|
129
|
+
params,
|
|
130
|
+
GENERIC_LIMIT_PARAM_REGEXES,
|
|
131
|
+
offsetMatch.param.name
|
|
132
|
+
);
|
|
133
|
+
if (!limitMatch) return null;
|
|
134
|
+
return {
|
|
135
|
+
type: "offset",
|
|
136
|
+
offsetParamName: offsetMatch.param.name,
|
|
137
|
+
offsetKeyword: offsetMatch.keyword,
|
|
138
|
+
limitParamName: limitMatch.param.name,
|
|
139
|
+
limitKeyword: limitMatch.keyword
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function isPagePagination(operation, parameters) {
|
|
143
|
+
const params = coearceParameters(parameters).filter(
|
|
144
|
+
(it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
|
|
145
|
+
);
|
|
146
|
+
if (params.length < 2) return null;
|
|
147
|
+
const pageNoMatch = findParamAndKeyword(params, PAGE_NUMBER_REGEXES);
|
|
148
|
+
if (!pageNoMatch) return null;
|
|
149
|
+
const pageSizeMatch = findParamAndKeyword(
|
|
150
|
+
params,
|
|
151
|
+
PAGE_SIZE_REGEXES,
|
|
152
|
+
pageNoMatch.param.name
|
|
153
|
+
);
|
|
154
|
+
if (!pageSizeMatch) return null;
|
|
155
|
+
return {
|
|
156
|
+
type: "page",
|
|
157
|
+
pageNumberParamName: pageNoMatch.param.name,
|
|
158
|
+
pageNumberKeyword: pageNoMatch.keyword,
|
|
159
|
+
pageSizeParamName: pageSizeMatch.param.name,
|
|
160
|
+
pageSizeKeyword: pageSizeMatch.keyword
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function isCursorPagination(operation, parameters = []) {
|
|
164
|
+
const queryParams = parameters;
|
|
165
|
+
if (queryParams.length < 2) return null;
|
|
166
|
+
const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);
|
|
167
|
+
if (!cursorMatch) return null;
|
|
168
|
+
const limitMatch = findParamAndKeyword(
|
|
169
|
+
queryParams,
|
|
170
|
+
CURSOR_LIMIT_REGEXES,
|
|
171
|
+
cursorMatch.param.name
|
|
172
|
+
);
|
|
173
|
+
if (!limitMatch) return null;
|
|
174
|
+
return {
|
|
175
|
+
type: "cursor",
|
|
176
|
+
cursorParamName: cursorMatch.param.name,
|
|
177
|
+
cursorKeyword: cursorMatch.keyword,
|
|
178
|
+
limitParamName: limitMatch.param.name,
|
|
179
|
+
limitKeyword: limitMatch.keyword
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function guessPagination(operation, body, response) {
|
|
183
|
+
const bodyParameters = body && body.properties ? Object.entries(body.properties).map(([it, schema]) => ({
|
|
184
|
+
name: it,
|
|
185
|
+
schema
|
|
186
|
+
})) : [];
|
|
187
|
+
const parameters = operation.parameters;
|
|
188
|
+
if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {
|
|
189
|
+
return { type: "none", reason: "no parameters" };
|
|
190
|
+
}
|
|
191
|
+
if (!response) {
|
|
192
|
+
return { type: "none", reason: "no response" };
|
|
193
|
+
}
|
|
194
|
+
if (!response.properties) {
|
|
195
|
+
return { type: "none", reason: "empty response" };
|
|
196
|
+
}
|
|
197
|
+
const properties = response.properties;
|
|
198
|
+
const itemsKey = getItemsName(properties);
|
|
199
|
+
if (!itemsKey) {
|
|
200
|
+
return { type: "none", reason: "no items key" };
|
|
201
|
+
}
|
|
202
|
+
const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));
|
|
203
|
+
if (!hasMoreKey) {
|
|
204
|
+
return { type: "none", reason: "no hasMore key" };
|
|
205
|
+
}
|
|
206
|
+
const pagination = isOffsetPagination(operation, [...parameters, ...bodyParameters]) || isPagePagination(operation, [...parameters, ...bodyParameters]) || isCursorPagination(operation, [...parameters, ...bodyParameters]);
|
|
207
|
+
return pagination ? { ...pagination, items: itemsKey, hasMore: hasMoreKey } : { type: "none", reason: "no pagination" };
|
|
208
|
+
}
|
|
209
|
+
function excludeKey(obj, key) {
|
|
210
|
+
const { [key]: _, ...rest } = obj;
|
|
211
|
+
return rest;
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
CURSOR_LIMIT_REGEXES,
|
|
215
|
+
CURSOR_REGEXES,
|
|
216
|
+
GENERIC_LIMIT_PARAM_REGEXES,
|
|
217
|
+
OFFSET_PARAM_REGEXES,
|
|
218
|
+
PAGE_NUMBER_REGEXES,
|
|
219
|
+
PAGE_SIZE_REGEXES,
|
|
220
|
+
guessPagination
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=guess-pagination.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/pagination/guess-pagination.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n ReferenceObject,\n SchemaObject,\n SchemasObject,\n} from 'openapi3-ts/oas31';\n\nimport { isRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport type { TunedOperationObject } from '../types.js';\nimport { getHasMoreName, getItemsName } from './pagination-result.js';\n\ninterface PaginationResultBase {\n type: 'offset' | 'page' | 'cursor' | 'none';\n}\n\nexport interface OffsetPaginationResult extends PaginationResultBase {\n type: 'offset';\n offsetParamName: string;\n offsetKeyword: string; // The actual part of param name that matched\n limitParamName: string;\n limitKeyword: string; // The actual part of param name that matched\n}\n\nexport interface PagePaginationResult extends PaginationResultBase {\n type: 'page';\n pageNumberParamName: string;\n pageNumberKeyword: string;\n pageSizeParamName: string;\n pageSizeKeyword: string;\n}\n\nexport interface CursorPaginationResult extends PaginationResultBase {\n type: 'cursor';\n cursorParamName: string;\n cursorKeyword: string;\n limitParamName: string;\n limitKeyword: string;\n}\n\nexport interface NoPaginationResult extends PaginationResultBase {\n type: 'none';\n reason: string;\n}\n\nexport type PaginationGuess =\n | ((\n | OffsetPaginationResult\n | PagePaginationResult\n | CursorPaginationResult\n ) & { items: string; hasMore: string })\n | NoPaginationResult;\n\n// --- Keyword Regex Definitions ---\n\nexport const OFFSET_PARAM_REGEXES: RegExp[] = [\n /\\boffset\\b/i,\n /\\bskip\\b/i,\n /\\bstart(?:ing_at|_index)?\\b/i, // e.g., start, starting_at, start_index\n /\\bfrom\\b/i,\n];\n\nexport const GENERIC_LIMIT_PARAM_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\b(?:page_?)?size\\b/i, // e.g., size, page_size, pagesize\n /\\bmax_results\\b/i,\n /\\bnum_results\\b/i,\n /\\bshow\\b/i, // Can sometimes mean limit\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\btake\\b/i,\n];\n\nexport const PAGE_NUMBER_REGEXES: RegExp[] = [\n // /^(currentPage)?page$/i, // Exact match for \"page\"\n // /^currentPage$/i, // Exact match for \"currentPage\"\n /^p$/i, // Exact match for \"p\" (common shorthand)\n // /\\bpage_?(?:number|no|num|idx|index)\\b/i, // e.g., page_number, pageNumber, page_num, page_idx\n /^(current)?_?page(_?)(?:number|no|num|idx|index)?\\b/i,\n];\n\n// Regexes for parameters indicating page size (when used with page number)\nexport const PAGE_SIZE_REGEXES: RegExp[] = [\n /\\bpage_?size\\b/i, // e.g., page_size, pagesize\n /^size$/i, // Exact \"size\"\n // /\\bsize\\b/i, // Broader \"size\" - can be ambiguous, prefer more specific ones first\n /\\blimit\\b/i, // Limit is often used for page size\n /\\bcount\\b/i, // Count can also be used for page size\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items, numitems\n /\\bresults_?per_?page\\b/i,\n];\n\n// Regexes for parameters indicating a cursor\nexport const CURSOR_REGEXES: RegExp[] = [\n /\\bmarker\\b/i,\n /\\bcursor\\b/i,\n /\\bafter(?:_?cursor)?\\b/i, // e.g., after, after_cursor\n /\\bbefore(?:_?cursor)?\\b/i, // e.g., before, before_cursor\n /\\b(next|prev|previous)_?(?:page_?)?token\\b/i, // e.g., next_page_token, nextPageToken, prev_token\n /\\b(next|prev|previous)_?cursor\\b/i, // e.g., next_cursor, previousCursor\n /\\bcontinuation(?:_?token)?\\b/i, // e.g., continuation, continuation_token\n /\\bpage(?:_?(token|id))?\\b/i, // e.g., after, after_cursor\n\n /\\bstart_?(?:key|cursor|token|after)\\b/i, // e.g., start_key, startCursor, startToken, startAfter\n];\n\n// Regexes for parameters indicating a limit when used with cursors\nexport const CURSOR_LIMIT_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\bsize\\b/i, // General size\n /\\bfirst\\b/i, // Common in Relay-style cursor pagination (forward pagination)\n /\\blast\\b/i, // Common in Relay-style cursor pagination (backward pagination)\n /\\bpage_?size\\b/i, // Sometimes page_size is used with cursors\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items\n /\\bmax_?items\\b/i,\n /\\btake\\b/i,\n];\n\n// --- Helper Function ---\nfunction findParamAndKeyword(\n queryParams: { name: string }[],\n regexes: RegExp[],\n excludeParamName?: string,\n) {\n for (const param of queryParams) {\n if (param.name === excludeParamName) {\n continue;\n }\n for (const regex of regexes) {\n const match = param.name.match(regex);\n if (match) {\n return { param, keyword: match[0] }; // match[0] is the actual matched substring\n }\n }\n }\n return null;\n}\n\nfunction coearceParameters(\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n) {\n const cleanedParameters: {\n name: string;\n schema: Omit<SchemaObject, 'type'> & {\n type: string[]; // Ensure type is always an array\n };\n }[] = [];\n for (const param of parameters) {\n if (!param.schema) {\n continue;\n }\n if (isRef(param.schema)) {\n continue;\n }\n if (!param.schema.type) {\n continue;\n }\n if (param.schema) {\n cleanedParameters.push({\n ...param,\n schema: {\n ...param.schema,\n type: Array.isArray(param.schema.type)\n ? param.schema.type\n : [param.schema.type],\n },\n });\n }\n }\n return cleanedParameters;\n}\n\nfunction isOffsetPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): OffsetPaginationResult | null {\n const params = coearceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);\n\n if (!offsetMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n params,\n GENERIC_LIMIT_PARAM_REGEXES,\n offsetMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'offset',\n offsetParamName: offsetMatch.param.name,\n offsetKeyword: offsetMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\nfunction isPagePagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): PagePaginationResult | null {\n const params = coearceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n\n if (params.length < 2) return null;\n\n const pageNoMatch = findParamAndKeyword(params, PAGE_NUMBER_REGEXES);\n if (!pageNoMatch) return null;\n\n const pageSizeMatch = findParamAndKeyword(\n params,\n PAGE_SIZE_REGEXES,\n pageNoMatch.param.name,\n );\n if (!pageSizeMatch) return null;\n\n return {\n type: 'page',\n pageNumberParamName: pageNoMatch.param.name,\n pageNumberKeyword: pageNoMatch.keyword,\n pageSizeParamName: pageSizeMatch.param.name,\n pageSizeKeyword: pageSizeMatch.keyword,\n };\n}\n\nfunction isCursorPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[] = [],\n): CursorPaginationResult | null {\n const queryParams = parameters;\n if (queryParams.length < 2) return null; // Need at least a cursor and a limit-like param\n\n const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);\n if (!cursorMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n queryParams,\n CURSOR_LIMIT_REGEXES,\n cursorMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'cursor',\n cursorParamName: cursorMatch.param.name,\n cursorKeyword: cursorMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\n/**\n * Guesses the pagination strategy of an OpenAPI operation based on its query parameters.\n * It checks for offset, page-based, and cursor-based pagination in that order.\n *\n * @param operation The OpenAPI operation object.\n * @returns A PaginationGuess object indicating the detected type and relevant parameters.\n */\nexport function guessPagination(\n operation: TunedOperationObject,\n body?: SchemaObject,\n response?: SchemaObject,\n): PaginationGuess {\n const bodyParameters =\n body && body.properties\n ? Object.entries(body.properties).map(([it, schema]) => ({\n name: it,\n schema,\n }))\n : [];\n const parameters = operation.parameters;\n\n if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {\n return { type: 'none', reason: 'no parameters' };\n }\n if (!response) {\n return { type: 'none', reason: 'no response' };\n }\n if (!response.properties) {\n return { type: 'none', reason: 'empty response' };\n }\n const properties = response.properties as SchemasObject;\n\n const itemsKey = getItemsName(properties);\n if (!itemsKey) {\n return { type: 'none', reason: 'no items key' };\n }\n const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));\n\n if (!hasMoreKey) {\n return { type: 'none', reason: 'no hasMore key' };\n }\n const pagination =\n isOffsetPagination(operation, [...parameters, ...bodyParameters]) ||\n isPagePagination(operation, [...parameters, ...bodyParameters]) ||\n isCursorPagination(operation, [...parameters, ...bodyParameters]);\n return pagination\n ? { ...pagination, items: itemsKey, hasMore: hasMoreKey }\n : { type: 'none', reason: 'no pagination' };\n}\n\nfunction excludeKey<T extends Record<string, any>>(\n obj: T,\n key: string,\n): Omit<T, typeof key> {\n const { [key]: _, ...rest } = obj;\n return rest;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,50 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
interface PaginationResultBase {
|
|
4
|
-
type: 'offset' | 'page' | 'cursor' | 'none';
|
|
5
|
-
}
|
|
6
|
-
export interface OffsetPaginationResult extends PaginationResultBase {
|
|
7
|
-
type: 'offset';
|
|
8
|
-
offsetParamName: string;
|
|
9
|
-
offsetKeyword: string;
|
|
10
|
-
limitParamName: string;
|
|
11
|
-
limitKeyword: string;
|
|
12
|
-
}
|
|
13
|
-
export interface PagePaginationResult extends PaginationResultBase {
|
|
14
|
-
type: 'page';
|
|
15
|
-
pageNumberParamName: string;
|
|
16
|
-
pageNumberKeyword: string;
|
|
17
|
-
pageSizeParamName: string;
|
|
18
|
-
pageSizeKeyword: string;
|
|
19
|
-
}
|
|
20
|
-
export interface CursorPaginationResult extends PaginationResultBase {
|
|
21
|
-
type: 'cursor';
|
|
22
|
-
cursorParamName: string;
|
|
23
|
-
cursorKeyword: string;
|
|
24
|
-
limitParamName: string;
|
|
25
|
-
limitKeyword: string;
|
|
26
|
-
}
|
|
27
|
-
export interface NoPaginationResult extends PaginationResultBase {
|
|
28
|
-
type: 'none';
|
|
29
|
-
reason: string;
|
|
30
|
-
}
|
|
31
|
-
export type PaginationGuess = ((OffsetPaginationResult | PagePaginationResult | CursorPaginationResult) & {
|
|
32
|
-
items: string;
|
|
33
|
-
hasMore: string;
|
|
34
|
-
}) | NoPaginationResult;
|
|
35
|
-
export declare const OFFSET_PARAM_REGEXES: RegExp[];
|
|
36
|
-
export declare const GENERIC_LIMIT_PARAM_REGEXES: RegExp[];
|
|
37
|
-
export declare const PAGE_NUMBER_REGEXES: RegExp[];
|
|
38
|
-
export declare const PAGE_SIZE_REGEXES: RegExp[];
|
|
39
|
-
export declare const CURSOR_REGEXES: RegExp[];
|
|
40
|
-
export declare const CURSOR_LIMIT_REGEXES: RegExp[];
|
|
41
|
-
/**
|
|
42
|
-
* Guesses the pagination strategy of an OpenAPI operation based on its query parameters.
|
|
43
|
-
* It checks for offset, page-based, and cursor-based pagination in that order.
|
|
44
|
-
*
|
|
45
|
-
* @param operation The OpenAPI operation object.
|
|
46
|
-
* @returns A PaginationGuess object indicating the detected type and relevant parameters.
|
|
47
|
-
*/
|
|
48
|
-
export declare function guessPagination(operation: TunedOperationObject, body?: SchemaObject, response?: SchemaObject): PaginationGuess;
|
|
49
|
-
export {};
|
|
1
|
+
import type { OurOpenAPIObject, TunedOperationObject } from '../types.js';
|
|
2
|
+
export declare function toPagination(spec: OurOpenAPIObject, tunedOperation: TunedOperationObject): any;
|
|
50
3
|
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/lib/pagination/pagination.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/lib/pagination/pagination.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAG1E,wBAAgB,YAAY,CAC1B,IAAI,EAAE,gBAAgB,EACtB,cAAc,EAAE,oBAAoB,OAyBrC"}
|
|
@@ -1,222 +1,56 @@
|
|
|
1
|
-
import { isRef } from "@sdk-it/core/ref.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/\bskip\b/i,
|
|
7
|
-
/\bstart(?:ing_at|_index)?\b/i,
|
|
8
|
-
// e.g., start, starting_at, start_index
|
|
9
|
-
/\bfrom\b/i
|
|
10
|
-
];
|
|
11
|
-
const GENERIC_LIMIT_PARAM_REGEXES = [
|
|
12
|
-
/\blimit\b/i,
|
|
13
|
-
/\bcount\b/i,
|
|
14
|
-
/\b(?:page_?)?size\b/i,
|
|
15
|
-
// e.g., size, page_size, pagesize
|
|
16
|
-
/\bmax_results\b/i,
|
|
17
|
-
/\bnum_results\b/i,
|
|
18
|
-
/\bshow\b/i,
|
|
19
|
-
// Can sometimes mean limit
|
|
20
|
-
/\bper_?page\b/i,
|
|
21
|
-
// e.g., per_page, perpage
|
|
22
|
-
/\bper-page\b/i,
|
|
23
|
-
/\btake\b/i
|
|
24
|
-
];
|
|
25
|
-
const PAGE_NUMBER_REGEXES = [
|
|
26
|
-
// /^(currentPage)?page$/i, // Exact match for "page"
|
|
27
|
-
// /^currentPage$/i, // Exact match for "currentPage"
|
|
28
|
-
/^p$/i,
|
|
29
|
-
// Exact match for "p" (common shorthand)
|
|
30
|
-
// /\bpage_?(?:number|no|num|idx|index)\b/i, // e.g., page_number, pageNumber, page_num, page_idx
|
|
31
|
-
/^(current)?_?page(_?)(?:number|no|num|idx|index)?\b/i
|
|
32
|
-
];
|
|
33
|
-
const PAGE_SIZE_REGEXES = [
|
|
34
|
-
/\bpage_?size\b/i,
|
|
35
|
-
// e.g., page_size, pagesize
|
|
36
|
-
/^size$/i,
|
|
37
|
-
// Exact "size"
|
|
38
|
-
// /\bsize\b/i, // Broader "size" - can be ambiguous, prefer more specific ones first
|
|
39
|
-
/\blimit\b/i,
|
|
40
|
-
// Limit is often used for page size
|
|
41
|
-
/\bcount\b/i,
|
|
42
|
-
// Count can also be used for page size
|
|
43
|
-
/\bper_?page\b/i,
|
|
44
|
-
// e.g., per_page, perpage
|
|
45
|
-
/\bper-page\b/i,
|
|
46
|
-
/\bnum_?(?:items|records|results)\b/i,
|
|
47
|
-
// e.g., num_items, numitems
|
|
48
|
-
/\bresults_?per_?page\b/i
|
|
49
|
-
];
|
|
50
|
-
const CURSOR_REGEXES = [
|
|
51
|
-
/\bmarker\b/i,
|
|
52
|
-
/\bcursor\b/i,
|
|
53
|
-
/\bafter(?:_?cursor)?\b/i,
|
|
54
|
-
// e.g., after, after_cursor
|
|
55
|
-
/\bbefore(?:_?cursor)?\b/i,
|
|
56
|
-
// e.g., before, before_cursor
|
|
57
|
-
/\b(next|prev|previous)_?(?:page_?)?token\b/i,
|
|
58
|
-
// e.g., next_page_token, nextPageToken, prev_token
|
|
59
|
-
/\b(next|prev|previous)_?cursor\b/i,
|
|
60
|
-
// e.g., next_cursor, previousCursor
|
|
61
|
-
/\bcontinuation(?:_?token)?\b/i,
|
|
62
|
-
// e.g., continuation, continuation_token
|
|
63
|
-
/\bpage(?:_?(token|id))?\b/i,
|
|
64
|
-
// e.g., after, after_cursor
|
|
65
|
-
/\bstart_?(?:key|cursor|token|after)\b/i
|
|
66
|
-
// e.g., start_key, startCursor, startToken, startAfter
|
|
67
|
-
];
|
|
68
|
-
const CURSOR_LIMIT_REGEXES = [
|
|
69
|
-
/\blimit\b/i,
|
|
70
|
-
/\bcount\b/i,
|
|
71
|
-
/\bsize\b/i,
|
|
72
|
-
// General size
|
|
73
|
-
/\bfirst\b/i,
|
|
74
|
-
// Common in Relay-style cursor pagination (forward pagination)
|
|
75
|
-
/\blast\b/i,
|
|
76
|
-
// Common in Relay-style cursor pagination (backward pagination)
|
|
77
|
-
/\bpage_?size\b/i,
|
|
78
|
-
// Sometimes page_size is used with cursors
|
|
79
|
-
/\bnum_?(?:items|records|results)\b/i,
|
|
80
|
-
// e.g., num_items
|
|
81
|
-
/\bmax_?items\b/i,
|
|
82
|
-
/\btake\b/i
|
|
83
|
-
];
|
|
84
|
-
function findParamAndKeyword(queryParams, regexes, excludeParamName) {
|
|
85
|
-
for (const param of queryParams) {
|
|
86
|
-
if (param.name === excludeParamName) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
for (const regex of regexes) {
|
|
90
|
-
const match = param.name.match(regex);
|
|
91
|
-
if (match) {
|
|
92
|
-
return { param, keyword: match[0] };
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
function coearceParameters(parameters) {
|
|
99
|
-
const cleanedParameters = [];
|
|
100
|
-
for (const param of parameters) {
|
|
101
|
-
if (!param.schema) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (isRef(param.schema)) {
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
if (!param.schema.type) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
if (param.schema) {
|
|
111
|
-
cleanedParameters.push({
|
|
112
|
-
...param,
|
|
113
|
-
schema: {
|
|
114
|
-
...param.schema,
|
|
115
|
-
type: Array.isArray(param.schema.type) ? param.schema.type : [param.schema.type]
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
}
|
|
1
|
+
import { followRef, isRef } from "@sdk-it/core/ref.js";
|
|
2
|
+
import { guessPagination } from "./guess-pagination.js";
|
|
3
|
+
function toPagination(spec, tunedOperation) {
|
|
4
|
+
if (tunedOperation["x-pagination"]) {
|
|
5
|
+
return tunedOperation["x-pagination"];
|
|
119
6
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
(it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
|
|
125
|
-
);
|
|
126
|
-
const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);
|
|
127
|
-
if (!offsetMatch) return null;
|
|
128
|
-
const limitMatch = findParamAndKeyword(
|
|
129
|
-
params,
|
|
130
|
-
GENERIC_LIMIT_PARAM_REGEXES,
|
|
131
|
-
offsetMatch.param.name
|
|
132
|
-
);
|
|
133
|
-
if (!limitMatch) return null;
|
|
134
|
-
return {
|
|
135
|
-
type: "offset",
|
|
136
|
-
offsetParamName: offsetMatch.param.name,
|
|
137
|
-
offsetKeyword: offsetMatch.keyword,
|
|
138
|
-
limitParamName: limitMatch.param.name,
|
|
139
|
-
limitKeyword: limitMatch.keyword
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
function isPagePagination(operation, parameters) {
|
|
143
|
-
const params = coearceParameters(parameters).filter(
|
|
144
|
-
(it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
|
|
7
|
+
const schema = getResponseContentSchema(
|
|
8
|
+
spec,
|
|
9
|
+
tunedOperation.responses["200"],
|
|
10
|
+
"application/json"
|
|
145
11
|
);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
154
|
-
if (!pageSizeMatch) return null;
|
|
155
|
-
return {
|
|
156
|
-
type: "page",
|
|
157
|
-
pageNumberParamName: pageNoMatch.param.name,
|
|
158
|
-
pageNumberKeyword: pageNoMatch.keyword,
|
|
159
|
-
pageSizeParamName: pageSizeMatch.param.name,
|
|
160
|
-
pageSizeKeyword: pageSizeMatch.keyword
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
function isCursorPagination(operation, parameters = []) {
|
|
164
|
-
const queryParams = parameters;
|
|
165
|
-
if (queryParams.length < 2) return null;
|
|
166
|
-
const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);
|
|
167
|
-
if (!cursorMatch) return null;
|
|
168
|
-
const limitMatch = findParamAndKeyword(
|
|
169
|
-
queryParams,
|
|
170
|
-
CURSOR_LIMIT_REGEXES,
|
|
171
|
-
cursorMatch.param.name
|
|
172
|
-
);
|
|
173
|
-
if (!limitMatch) return null;
|
|
174
|
-
return {
|
|
175
|
-
type: "cursor",
|
|
176
|
-
cursorParamName: cursorMatch.param.name,
|
|
177
|
-
cursorKeyword: cursorMatch.keyword,
|
|
178
|
-
limitParamName: limitMatch.param.name,
|
|
179
|
-
limitKeyword: limitMatch.keyword
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
function guessPagination(operation, body, response) {
|
|
183
|
-
const bodyParameters = body && body.properties ? Object.entries(body.properties).map(([it, schema]) => ({
|
|
184
|
-
name: it,
|
|
12
|
+
const pagination = guessPagination(
|
|
13
|
+
tunedOperation,
|
|
14
|
+
tunedOperation.requestBody ? getRequestContentSchema(
|
|
15
|
+
spec,
|
|
16
|
+
tunedOperation.requestBody,
|
|
17
|
+
"application/json"
|
|
18
|
+
) : void 0,
|
|
185
19
|
schema
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return { type: "none", reason: "no parameters" };
|
|
20
|
+
);
|
|
21
|
+
if (pagination && pagination.type !== "none" && schema) {
|
|
22
|
+
return pagination;
|
|
190
23
|
}
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
function getResponseContentSchema(spec, response, type) {
|
|
191
27
|
if (!response) {
|
|
192
|
-
return
|
|
28
|
+
return void 0;
|
|
193
29
|
}
|
|
194
|
-
|
|
195
|
-
|
|
30
|
+
const content = response.content;
|
|
31
|
+
if (!content) {
|
|
32
|
+
return void 0;
|
|
196
33
|
}
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));
|
|
203
|
-
if (!hasMoreKey) {
|
|
204
|
-
return { type: "none", reason: "no hasMore key" };
|
|
34
|
+
for (const contentType in content) {
|
|
35
|
+
if (contentType.toLowerCase() === type.toLowerCase()) {
|
|
36
|
+
return isRef(content[contentType].schema) ? followRef(spec, content[contentType].schema.$ref) : content[contentType].schema;
|
|
37
|
+
}
|
|
205
38
|
}
|
|
206
|
-
|
|
207
|
-
return pagination ? { ...pagination, items: itemsKey, hasMore: hasMoreKey } : { type: "none", reason: "no pagination" };
|
|
39
|
+
return void 0;
|
|
208
40
|
}
|
|
209
|
-
function
|
|
210
|
-
const
|
|
211
|
-
|
|
41
|
+
function getRequestContentSchema(spec, requestBody, type) {
|
|
42
|
+
const content = requestBody.content;
|
|
43
|
+
if (!content) {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
for (const contentType in content) {
|
|
47
|
+
if (contentType.toLowerCase() === type.toLowerCase()) {
|
|
48
|
+
return isRef(content[contentType].schema) ? followRef(spec, content[contentType].schema.$ref) : content[contentType].schema;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
212
52
|
}
|
|
213
53
|
export {
|
|
214
|
-
|
|
215
|
-
CURSOR_REGEXES,
|
|
216
|
-
GENERIC_LIMIT_PARAM_REGEXES,
|
|
217
|
-
OFFSET_PARAM_REGEXES,
|
|
218
|
-
PAGE_NUMBER_REGEXES,
|
|
219
|
-
PAGE_SIZE_REGEXES,
|
|
220
|
-
guessPagination
|
|
54
|
+
toPagination
|
|
221
55
|
};
|
|
222
56
|
//# sourceMappingURL=pagination.js.map
|