@acrool/rtk-query-codegen-openapi 0.0.6 → 0.0.9
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/README.md +33 -0
- package/lib/index.d.mts +15 -5
- package/lib/index.d.ts +15 -5
- package/lib/index.js +219 -157
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +219 -157
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/generate.ts +180 -132
- package/src/generators/react-hooks.ts +10 -4
- package/src/index.ts +76 -77
- package/src/types.ts +20 -5
- package/src/utils/downloadSchema.ts +33 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/isQuery.ts +9 -1
package/src/index.ts
CHANGED
|
@@ -3,14 +3,12 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { generateApi } from './generate';
|
|
5
5
|
import type { CommonOptions, ConfigFile, GenerationOptions, OutputFileOptions } from './types';
|
|
6
|
-
import {
|
|
6
|
+
import { prettify, getV3Doc, downloadSchemaFile } from './utils';
|
|
7
7
|
import camelCase from 'lodash.camelcase';
|
|
8
8
|
export type { OutputFilesConfig, ConfigFile } from './types';
|
|
9
9
|
|
|
10
10
|
const require = createRequire(__filename);
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
12
|
// 確保目錄存在的函數
|
|
15
13
|
async function ensureDirectoryExists(filePath: string) {
|
|
16
14
|
const dirname = path.dirname(filePath);
|
|
@@ -19,7 +17,6 @@ async function ensureDirectoryExists(filePath: string) {
|
|
|
19
17
|
}
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
23
20
|
// 檢查檔案是否存在的函數
|
|
24
21
|
function fileExists(filePath: string): boolean {
|
|
25
22
|
try {
|
|
@@ -36,17 +33,23 @@ function getApiNameFromDir(dirPath: string): string {
|
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
// 確保基礎文件存在的函數
|
|
39
|
-
async function ensureBaseFilesExist(outputDir: string) {
|
|
36
|
+
async function ensureBaseFilesExist(outputDir: string, operationNames: string[]) {
|
|
40
37
|
const enhanceEndpointsPath = path.join(outputDir, 'enhanceEndpoints.ts');
|
|
41
38
|
const indexPath = path.join(outputDir, 'index.ts');
|
|
42
39
|
const apiName = getApiNameFromDir(outputDir);
|
|
43
40
|
|
|
44
41
|
// 如果 enhanceEndpoints.ts 不存在,創建它
|
|
45
42
|
if (!fileExists(enhanceEndpointsPath)) {
|
|
43
|
+
// 生成操作名稱的字符串
|
|
44
|
+
const operationNamesString = operationNames
|
|
45
|
+
.map(name => ` ${name}: {},`)
|
|
46
|
+
.join('\n');
|
|
47
|
+
|
|
46
48
|
const enhanceEndpointsContent = `import api from './query.generated';
|
|
47
49
|
|
|
48
50
|
const enhancedApi = api.enhanceEndpoints({
|
|
49
51
|
endpoints: {
|
|
52
|
+
${operationNamesString}
|
|
50
53
|
},
|
|
51
54
|
});
|
|
52
55
|
|
|
@@ -54,6 +57,7 @@ export default enhancedApi;
|
|
|
54
57
|
`;
|
|
55
58
|
await fs.promises.writeFile(enhanceEndpointsPath, enhanceEndpointsContent, 'utf-8');
|
|
56
59
|
}
|
|
60
|
+
// 如果文件已存在,不做任何修改
|
|
57
61
|
|
|
58
62
|
// 如果 index.ts 不存在,創建它
|
|
59
63
|
if (!fileExists(indexPath)) {
|
|
@@ -64,73 +68,63 @@ export {default as ${apiName}} from './enhanceEndpoints';
|
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// console.log('match', path, match);
|
|
74
|
-
|
|
75
|
-
if (match && match[1]) {
|
|
76
|
-
return camelCase(match[1]);
|
|
71
|
+
export async function generateEndpoints(options: GenerationOptions): Promise<string | void> {
|
|
72
|
+
// 如果有 remoteFile,先下載到 schemaFile 路徑
|
|
73
|
+
let actualSchemaFile = options.schemaFile;
|
|
74
|
+
|
|
75
|
+
if (options.remoteFile) {
|
|
76
|
+
actualSchemaFile = await downloadSchemaFile(options.remoteFile, options.schemaFile);
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
|
|
79
|
+
// 更新 options 中的 schemaFile 為實際的檔案路徑
|
|
80
|
+
const updatedOptions = {
|
|
81
|
+
...options,
|
|
82
|
+
schemaFile: actualSchemaFile
|
|
83
|
+
};
|
|
81
84
|
|
|
85
|
+
const schemaLocation = updatedOptions.schemaFile;
|
|
82
86
|
|
|
87
|
+
const schemaAbsPath = path.resolve(process.cwd(), schemaLocation);
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const schemaAbsPath = isValidUrl(options.schemaFile)
|
|
89
|
-
? options.schemaFile
|
|
90
|
-
: path.resolve(process.cwd(), schemaLocation);
|
|
91
|
-
|
|
92
|
-
// 如果是 URL 且使用 outputFiles 配置,需要特殊處理
|
|
93
|
-
if (isValidUrl(options.schemaFile) && 'outputFiles' in options) {
|
|
94
|
-
const { outputFiles, ...commonConfig } = options as any;
|
|
89
|
+
// 如果是使用 outputFiles 配置,需要特殊處理
|
|
90
|
+
if ('outputFiles' in options) {
|
|
91
|
+
const { outputFiles, ...commonConfig } = updatedOptions as any;
|
|
95
92
|
|
|
96
93
|
// 異步獲取 OpenAPI 文檔
|
|
97
|
-
const openApiDoc = await getV3Doc(
|
|
94
|
+
const openApiDoc = await getV3Doc(actualSchemaFile, updatedOptions.httpResolverOptions);
|
|
98
95
|
const paths = Object.keys(openApiDoc.paths);
|
|
99
96
|
|
|
100
97
|
// 從配置中獲取分類規則
|
|
101
|
-
const
|
|
102
|
-
const [outputPath, config] = outputFilesEntries[0];
|
|
103
|
-
const patterns = (config as any).groupMatch;
|
|
104
|
-
const filterEndpoint = (config as any).filterEndpoint;
|
|
98
|
+
const { groupKeyMatch, outputDir, filterEndpoint, queryMatch } = outputFiles;
|
|
105
99
|
|
|
106
|
-
const pattern = patterns;
|
|
107
100
|
// 根據路徑自動分類
|
|
108
101
|
const groupedPaths = paths.reduce((acc, path) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
// 使用 groupKeyMatch 方法獲取 groupKey,並轉換為小駝峰格式
|
|
103
|
+
const groupKey = camelCase(groupKeyMatch(path));
|
|
104
|
+
if (!acc[groupKey]) {
|
|
105
|
+
acc[groupKey] = [];
|
|
112
106
|
}
|
|
113
|
-
acc[
|
|
107
|
+
acc[groupKey].push(path);
|
|
114
108
|
return acc;
|
|
115
109
|
}, {} as Record<string, string[]>);
|
|
116
110
|
|
|
117
111
|
// 為每個分類生成配置並執行
|
|
118
|
-
for (const [
|
|
119
|
-
const finalOutputPath =
|
|
112
|
+
for (const [groupKey, paths] of Object.entries(groupedPaths)) {
|
|
113
|
+
const finalOutputPath = `${outputDir}/${groupKey}/query.generated.ts`;
|
|
120
114
|
|
|
121
115
|
if (filterEndpoint) {
|
|
122
116
|
// 如果有 filterEndpoint,使用基於路徑的篩選函數
|
|
123
117
|
const pathBasedFilter = (operationName: string, operationDefinition: any) => {
|
|
124
118
|
const path = operationDefinition.path;
|
|
125
|
-
|
|
119
|
+
|
|
126
120
|
// 檢查路徑是否匹配當前分組
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
121
|
+
const pathGroupKey = camelCase(groupKeyMatch(path));
|
|
122
|
+
if (pathGroupKey !== groupKey) {
|
|
129
123
|
return false;
|
|
130
124
|
}
|
|
131
125
|
|
|
132
126
|
// 使用 filterEndpoint 進行額外篩選
|
|
133
|
-
const endpointFilter = filterEndpoint(
|
|
127
|
+
const endpointFilter = filterEndpoint(groupKey);
|
|
134
128
|
if (endpointFilter instanceof RegExp) {
|
|
135
129
|
return endpointFilter.test(operationName);
|
|
136
130
|
}
|
|
@@ -141,7 +135,9 @@ export async function generateEndpoints(options: GenerationOptions): Promise<str
|
|
|
141
135
|
const groupOptions = {
|
|
142
136
|
...commonConfig,
|
|
143
137
|
outputFile: finalOutputPath,
|
|
138
|
+
sharedTypesFile: `${outputDir}/shared-types.ts`,
|
|
144
139
|
filterEndpoints: pathBasedFilter,
|
|
140
|
+
queryMatch,
|
|
145
141
|
};
|
|
146
142
|
|
|
147
143
|
await generateSingleEndpoint(groupOptions);
|
|
@@ -149,16 +145,18 @@ export async function generateEndpoints(options: GenerationOptions): Promise<str
|
|
|
149
145
|
// 如果沒有 filterEndpoint,只使用路徑分組
|
|
150
146
|
const pathBasedFilter = (operationName: string, operationDefinition: any) => {
|
|
151
147
|
const path = operationDefinition.path;
|
|
152
|
-
|
|
148
|
+
|
|
153
149
|
// 檢查路徑是否匹配當前分組
|
|
154
|
-
const
|
|
155
|
-
return
|
|
150
|
+
const pathGroupKey = camelCase(groupKeyMatch(path));
|
|
151
|
+
return pathGroupKey === groupKey;
|
|
156
152
|
};
|
|
157
153
|
|
|
158
154
|
const groupOptions = {
|
|
159
155
|
...commonConfig,
|
|
160
156
|
outputFile: finalOutputPath,
|
|
157
|
+
sharedTypesFile: `${outputDir}/shared-types.ts`,
|
|
161
158
|
filterEndpoints: pathBasedFilter,
|
|
159
|
+
queryMatch,
|
|
162
160
|
};
|
|
163
161
|
|
|
164
162
|
await generateSingleEndpoint(groupOptions);
|
|
@@ -168,19 +166,18 @@ export async function generateEndpoints(options: GenerationOptions): Promise<str
|
|
|
168
166
|
}
|
|
169
167
|
|
|
170
168
|
// 原有的邏輯處理非 outputFiles 配置或本地文件
|
|
171
|
-
await generateSingleEndpoint(
|
|
169
|
+
await generateSingleEndpoint(updatedOptions);
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
async function generateSingleEndpoint(options: GenerationOptions): Promise<string | void> {
|
|
175
173
|
const schemaLocation = options.schemaFile;
|
|
176
174
|
|
|
177
|
-
const schemaAbsPath =
|
|
178
|
-
? options.schemaFile
|
|
179
|
-
: path.resolve(process.cwd(), schemaLocation);
|
|
175
|
+
const schemaAbsPath = path.resolve(process.cwd(), schemaLocation);
|
|
180
176
|
|
|
181
|
-
const
|
|
177
|
+
const result = await enforceOazapftsTsVersion(async () => {
|
|
182
178
|
return generateApi(schemaAbsPath, options);
|
|
183
179
|
});
|
|
180
|
+
|
|
184
181
|
const { outputFile, prettierConfigFile } = options;
|
|
185
182
|
if (outputFile) {
|
|
186
183
|
const outputPath = path.resolve(process.cwd(), outputFile);
|
|
@@ -188,14 +185,14 @@ async function generateSingleEndpoint(options: GenerationOptions): Promise<strin
|
|
|
188
185
|
|
|
189
186
|
// 確保基礎文件存在
|
|
190
187
|
const outputDir = path.dirname(outputPath);
|
|
191
|
-
await ensureBaseFilesExist(outputDir);
|
|
188
|
+
await ensureBaseFilesExist(outputDir, result.operationNames);
|
|
192
189
|
|
|
193
190
|
fs.writeFileSync(
|
|
194
191
|
outputPath,
|
|
195
|
-
await prettify(outputFile, sourceCode, prettierConfigFile)
|
|
192
|
+
await prettify(outputFile, result.sourceCode, prettierConfigFile)
|
|
196
193
|
);
|
|
197
194
|
} else {
|
|
198
|
-
return await prettify(null, sourceCode, prettierConfigFile);
|
|
195
|
+
return await prettify(null, result.sourceCode, prettierConfigFile);
|
|
199
196
|
}
|
|
200
197
|
}
|
|
201
198
|
|
|
@@ -205,10 +202,11 @@ export function parseConfig(fullConfig: ConfigFile) {
|
|
|
205
202
|
if ('outputFiles' in fullConfig) {
|
|
206
203
|
const { outputFiles, ...commonConfig } = fullConfig;
|
|
207
204
|
|
|
208
|
-
// 讀取 OpenAPI 文檔 -
|
|
205
|
+
// 讀取 OpenAPI 文檔 - 支援本地文件
|
|
209
206
|
let openApiDoc: any;
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
|
|
208
|
+
// 如果有 remoteFile,直接返回原始配置,讓 generateEndpoints 處理下載
|
|
209
|
+
if (fullConfig.remoteFile) {
|
|
212
210
|
outFiles.push(fullConfig as any);
|
|
213
211
|
return outFiles;
|
|
214
212
|
} else {
|
|
@@ -219,39 +217,36 @@ export function parseConfig(fullConfig: ConfigFile) {
|
|
|
219
217
|
const paths = Object.keys(openApiDoc.paths);
|
|
220
218
|
|
|
221
219
|
// 從配置中獲取分類規則
|
|
222
|
-
const
|
|
223
|
-
const [outputPath, config] = outputFilesEntries[0];
|
|
224
|
-
const patterns = (config as any).groupMatch;
|
|
225
|
-
const filterEndpoint = (config as any).filterEndpoint;
|
|
220
|
+
const { groupKeyMatch, outputDir, filterEndpoint, queryMatch } = outputFiles;
|
|
226
221
|
|
|
227
|
-
const pattern = patterns;
|
|
228
222
|
// 根據路徑自動分類
|
|
229
223
|
const groupedPaths = paths.reduce((acc, path) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
224
|
+
// 使用 groupKeyMatch 方法獲取 groupKey,並轉換為小駝峰格式
|
|
225
|
+
const groupKey = camelCase(groupKeyMatch(path));
|
|
226
|
+
if (!acc[groupKey]) {
|
|
227
|
+
acc[groupKey] = [];
|
|
233
228
|
}
|
|
234
|
-
acc[
|
|
229
|
+
acc[groupKey].push(path);
|
|
235
230
|
return acc;
|
|
236
231
|
}, {} as Record<string, string[]>);
|
|
237
232
|
|
|
238
233
|
// 為每個分類生成配置
|
|
239
|
-
Object.entries(groupedPaths).forEach(([
|
|
240
|
-
const finalOutputPath =
|
|
234
|
+
Object.entries(groupedPaths).forEach(([groupKey, paths]) => {
|
|
235
|
+
const finalOutputPath = `${outputDir}/${groupKey}/query.generated.ts`;
|
|
241
236
|
|
|
242
237
|
if (filterEndpoint) {
|
|
243
238
|
// 如果有 filterEndpoint,使用基於路徑的篩選函數
|
|
244
239
|
const pathBasedFilter = (operationName: string, operationDefinition: any) => {
|
|
245
240
|
const path = operationDefinition.path;
|
|
246
|
-
|
|
241
|
+
|
|
247
242
|
// 檢查路徑是否匹配當前分組
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
243
|
+
const pathGroupKey = camelCase(groupKeyMatch(path));
|
|
244
|
+
if (pathGroupKey !== groupKey) {
|
|
250
245
|
return false;
|
|
251
246
|
}
|
|
252
247
|
|
|
253
248
|
// 使用 filterEndpoint 進行額外篩選
|
|
254
|
-
const endpointFilter = filterEndpoint(
|
|
249
|
+
const endpointFilter = filterEndpoint(groupKey);
|
|
255
250
|
if (endpointFilter instanceof RegExp) {
|
|
256
251
|
return endpointFilter.test(operationName);
|
|
257
252
|
}
|
|
@@ -262,22 +257,26 @@ export function parseConfig(fullConfig: ConfigFile) {
|
|
|
262
257
|
outFiles.push({
|
|
263
258
|
...commonConfig,
|
|
264
259
|
outputFile: finalOutputPath,
|
|
260
|
+
sharedTypesFile: `${outputDir}/shared-types.ts`,
|
|
265
261
|
filterEndpoints: pathBasedFilter,
|
|
262
|
+
queryMatch,
|
|
266
263
|
});
|
|
267
264
|
} else {
|
|
268
265
|
// 如果沒有 filterEndpoint,只使用路徑分組
|
|
269
266
|
const pathBasedFilter = (operationName: string, operationDefinition: any) => {
|
|
270
267
|
const path = operationDefinition.path;
|
|
271
|
-
|
|
268
|
+
|
|
272
269
|
// 檢查路徑是否匹配當前分組
|
|
273
|
-
const
|
|
274
|
-
return
|
|
270
|
+
const pathGroupKey = camelCase(groupKeyMatch(path));
|
|
271
|
+
return pathGroupKey === groupKey;
|
|
275
272
|
};
|
|
276
273
|
|
|
277
274
|
outFiles.push({
|
|
278
275
|
...commonConfig,
|
|
279
276
|
outputFile: finalOutputPath,
|
|
277
|
+
sharedTypesFile: `${outputDir}/shared-types.ts`,
|
|
280
278
|
filterEndpoints: pathBasedFilter,
|
|
279
|
+
queryMatch,
|
|
281
280
|
});
|
|
282
281
|
}
|
|
283
282
|
});
|
package/src/types.ts
CHANGED
|
@@ -34,9 +34,13 @@ export type GenerationOptions = Id<
|
|
|
34
34
|
export interface CommonOptions {
|
|
35
35
|
apiFile: string;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* local schema file path (only supports local files)
|
|
38
38
|
*/
|
|
39
39
|
schemaFile: string;
|
|
40
|
+
/**
|
|
41
|
+
* remote schema file URL (when provided, will download to schemaFile path)
|
|
42
|
+
*/
|
|
43
|
+
remoteFile?: string;
|
|
40
44
|
/**
|
|
41
45
|
* defaults to "api"
|
|
42
46
|
*/
|
|
@@ -111,6 +115,11 @@ export interface CommonOptions {
|
|
|
111
115
|
* resolution mechanism will be used.
|
|
112
116
|
*/
|
|
113
117
|
prettierConfigFile?: string;
|
|
118
|
+
/**
|
|
119
|
+
* defaults to "@acrool/react-fetcher"
|
|
120
|
+
* File path for importing IRestFulEndpointsQueryReturn type
|
|
121
|
+
*/
|
|
122
|
+
endpointsQueryReturnTypeFile?: string;
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
export type TextMatcher = string | RegExp | (string | RegExp)[];
|
|
@@ -127,6 +136,7 @@ export interface OutputFileOptions extends Partial<CommonOptions> {
|
|
|
127
136
|
outputFile: string;
|
|
128
137
|
filterEndpoints?: EndpointMatcher;
|
|
129
138
|
endpointOverrides?: EndpointOverrides[];
|
|
139
|
+
queryMatch?: (method: string, path: string) => boolean;
|
|
130
140
|
/**
|
|
131
141
|
* defaults to false
|
|
132
142
|
* If passed as true it will generate TS enums instead of union of strings
|
|
@@ -143,10 +153,10 @@ export type EndpointOverrides = {
|
|
|
143
153
|
}>;
|
|
144
154
|
|
|
145
155
|
export type OutputFilesConfig = {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
groupKeyMatch: (path: string) => string;
|
|
157
|
+
outputDir: string;
|
|
158
|
+
queryMatch?: (method: string, path: string) => boolean;
|
|
159
|
+
filterEndpoint?: (groupName: string) => RegExp;
|
|
150
160
|
};
|
|
151
161
|
|
|
152
162
|
export type ConfigFile =
|
|
@@ -157,3 +167,8 @@ export type ConfigFile =
|
|
|
157
167
|
outputFiles: OutputFilesConfig
|
|
158
168
|
}
|
|
159
169
|
>;
|
|
170
|
+
|
|
171
|
+
export type GenerateApiResult = {
|
|
172
|
+
sourceCode: string;
|
|
173
|
+
operationNames: string[];
|
|
174
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isValidUrl } from './isValidUrl';
|
|
4
|
+
|
|
5
|
+
export async function downloadSchemaFile(remoteFile: string, targetPath: string): Promise<string> {
|
|
6
|
+
// 如果不是網址,拋出錯誤
|
|
7
|
+
if (!isValidUrl(remoteFile)) {
|
|
8
|
+
throw new Error(`remoteFile must be a valid URL: ${remoteFile}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// 確保目錄存在
|
|
13
|
+
const dir = path.dirname(targetPath);
|
|
14
|
+
if (!fs.existsSync(dir)) {
|
|
15
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 下載檔案
|
|
19
|
+
const response = await fetch(remoteFile);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new Error(`Failed to download schema from ${remoteFile}: ${response.statusText}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const content = await response.text();
|
|
25
|
+
await fs.promises.writeFile(targetPath, content, 'utf-8');
|
|
26
|
+
|
|
27
|
+
console.log(`Schema downloaded from ${remoteFile} to ${targetPath}`);
|
|
28
|
+
return targetPath;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(`Error downloading schema from ${remoteFile}:`, error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/isQuery.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { EndpointOverrides, operationKeys } from '../types';
|
|
2
2
|
|
|
3
|
-
export function isQuery(
|
|
3
|
+
export function isQuery(
|
|
4
|
+
verb: (typeof operationKeys)[number],
|
|
5
|
+
path: string,
|
|
6
|
+
overrides: EndpointOverrides | undefined,
|
|
7
|
+
queryMatch?: (method: string, path: string) => boolean
|
|
8
|
+
) {
|
|
9
|
+
if (queryMatch) {
|
|
10
|
+
return queryMatch(verb, path);
|
|
11
|
+
}
|
|
4
12
|
if (overrides?.type) {
|
|
5
13
|
return overrides.type === 'query';
|
|
6
14
|
}
|