@sdk-it/dart 0.20.0 → 0.22.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.js +648 -822
- package/dist/index.js.map +4 -4
- package/dist/lib/dart-emitter.d.ts +9 -9
- package/dist/lib/dart-emitter.d.ts.map +1 -1
- package/dist/lib/generate.d.ts +5 -1
- package/dist/lib/generate.d.ts.map +1 -1
- package/dist/lib/security.d.ts +3 -0
- package/dist/lib/security.d.ts.map +1 -0
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,501 +1,299 @@
|
|
|
1
1
|
// packages/dart/src/lib/generate.ts
|
|
2
2
|
import { parse as partContentType } from "fast-content-type-parse";
|
|
3
|
-
import {
|
|
4
|
-
import assert2 from "node:assert";
|
|
5
|
-
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { readdir, writeFile } from "node:fs/promises";
|
|
6
4
|
import { join } from "node:path";
|
|
7
|
-
import { camelcase as
|
|
5
|
+
import { camelcase as camelcase2 } from "stringcase";
|
|
8
6
|
import yaml from "yaml";
|
|
9
7
|
import {
|
|
10
|
-
followRef as followRef3,
|
|
11
8
|
isEmpty as isEmpty2,
|
|
12
|
-
isRef as
|
|
13
|
-
notRef as notRef2,
|
|
9
|
+
isRef as isRef2,
|
|
14
10
|
pascalcase as pascalcase2,
|
|
11
|
+
resolveRef as resolveRef2,
|
|
15
12
|
snakecase as snakecase2
|
|
16
13
|
} from "@sdk-it/core";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
const metadata = operation["x-oaiMeta"];
|
|
34
|
-
if (metadata && metadata.name) {
|
|
35
|
-
return camelcase(metadata.name);
|
|
36
|
-
}
|
|
37
|
-
return camelcase(
|
|
38
|
-
[method, ...path.replace(/[\\/\\{\\}]/g, " ").split(" ")].filter(Boolean).join(" ").trim()
|
|
39
|
-
);
|
|
40
|
-
},
|
|
41
|
-
tag: (operation, path) => {
|
|
42
|
-
return operation.tags?.[0] ? sanitizeTag(operation.tags?.[0]) : determineGenericTag(path, operation);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
function resolveResponses(spec, operation) {
|
|
46
|
-
const responses = operation.responses ?? {};
|
|
47
|
-
const resolved = {};
|
|
48
|
-
for (const status in responses) {
|
|
49
|
-
const response = isRef(responses[status]) ? followRef(spec, responses[status].$ref) : responses[status];
|
|
50
|
-
resolved[status] = response;
|
|
51
|
-
}
|
|
52
|
-
return resolved;
|
|
53
|
-
}
|
|
54
|
-
function forEachOperation(config, callback) {
|
|
55
|
-
const result = [];
|
|
56
|
-
for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
|
|
57
|
-
const { parameters = [], ...methods } = pathItem;
|
|
58
|
-
const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
|
|
59
|
-
for (const [method, operation] of Object.entries(methods)) {
|
|
60
|
-
const formatOperationId = config.operationId ?? defaults.operationId;
|
|
61
|
-
const formatTag = config.tag ?? defaults.tag;
|
|
62
|
-
const operationName = formatOperationId(operation, fixedPath, method);
|
|
63
|
-
const operationTag = formatTag(operation, fixedPath);
|
|
64
|
-
const metadata = operation["x-oaiMeta"] ?? {};
|
|
65
|
-
result.push(
|
|
66
|
-
callback(
|
|
67
|
-
{
|
|
68
|
-
name: metadata.name,
|
|
69
|
-
method,
|
|
70
|
-
path: fixedPath,
|
|
71
|
-
groupName: operationTag,
|
|
72
|
-
tag: operationTag
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
...operation,
|
|
76
|
-
parameters: [...parameters, ...operation.parameters ?? []],
|
|
77
|
-
operationId: operationName,
|
|
78
|
-
responses: resolveResponses(config.spec, operation)
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return result;
|
|
85
|
-
}
|
|
86
|
-
var reservedKeywords = /* @__PURE__ */ new Set([
|
|
87
|
-
"await",
|
|
88
|
-
// Reserved in async functions
|
|
89
|
-
"break",
|
|
90
|
-
"case",
|
|
91
|
-
"catch",
|
|
92
|
-
"class",
|
|
93
|
-
"const",
|
|
94
|
-
"continue",
|
|
95
|
-
"debugger",
|
|
96
|
-
"default",
|
|
97
|
-
"delete",
|
|
98
|
-
"do",
|
|
99
|
-
"else",
|
|
100
|
-
"enum",
|
|
101
|
-
"export",
|
|
102
|
-
"extends",
|
|
103
|
-
"false",
|
|
104
|
-
"finally",
|
|
105
|
-
"for",
|
|
106
|
-
"function",
|
|
107
|
-
"if",
|
|
108
|
-
"implements",
|
|
109
|
-
// Strict mode
|
|
110
|
-
"import",
|
|
111
|
-
"in",
|
|
112
|
-
"instanceof",
|
|
113
|
-
"interface",
|
|
114
|
-
// Strict mode
|
|
115
|
-
"let",
|
|
116
|
-
// Strict mode
|
|
117
|
-
"new",
|
|
118
|
-
"null",
|
|
119
|
-
"package",
|
|
120
|
-
// Strict mode
|
|
121
|
-
"private",
|
|
122
|
-
// Strict mode
|
|
123
|
-
"protected",
|
|
124
|
-
// Strict mode
|
|
125
|
-
"public",
|
|
126
|
-
// Strict mode
|
|
127
|
-
"return",
|
|
128
|
-
"static",
|
|
129
|
-
// Strict mode
|
|
130
|
-
"super",
|
|
131
|
-
"switch",
|
|
132
|
-
"this",
|
|
133
|
-
"throw",
|
|
134
|
-
"true",
|
|
135
|
-
"try",
|
|
136
|
-
"typeof",
|
|
137
|
-
"var",
|
|
138
|
-
"void",
|
|
139
|
-
"while",
|
|
140
|
-
"with",
|
|
141
|
-
"yield",
|
|
142
|
-
// Strict mode / Generator functions
|
|
143
|
-
// 'arguments' is not technically a reserved word, but it's a special identifier within functions
|
|
144
|
-
// and assigning to it or declaring it can cause issues or unexpected behavior.
|
|
145
|
-
"arguments"
|
|
146
|
-
]);
|
|
147
|
-
function sanitizeTag(camelCasedTag) {
|
|
148
|
-
if (/^\d/.test(camelCasedTag)) {
|
|
149
|
-
return `_${camelCasedTag}`;
|
|
150
|
-
}
|
|
151
|
-
return reservedKeywords.has(camelcase(camelCasedTag)) ? `${camelCasedTag}_` : camelCasedTag;
|
|
152
|
-
}
|
|
153
|
-
function determineGenericTag(pathString, operation) {
|
|
154
|
-
const operationId = operation.operationId || "";
|
|
155
|
-
const VERSION_REGEX = /^[vV]\d+$/;
|
|
156
|
-
const commonVerbs = /* @__PURE__ */ new Set([
|
|
157
|
-
// Verbs to potentially strip from operationId prefix
|
|
158
|
-
"get",
|
|
159
|
-
"list",
|
|
160
|
-
"create",
|
|
161
|
-
"update",
|
|
162
|
-
"delete",
|
|
163
|
-
"post",
|
|
164
|
-
"put",
|
|
165
|
-
"patch",
|
|
166
|
-
"do",
|
|
167
|
-
"send",
|
|
168
|
-
"add",
|
|
169
|
-
"remove",
|
|
170
|
-
"set",
|
|
171
|
-
"find",
|
|
172
|
-
"search",
|
|
173
|
-
"check",
|
|
174
|
-
"make"
|
|
175
|
-
]);
|
|
176
|
-
const segments = pathString.split("/").filter(Boolean);
|
|
177
|
-
const potentialCandidates = segments.filter(
|
|
178
|
-
(segment) => segment && !segment.startsWith("{") && !segment.endsWith("}") && !VERSION_REGEX.test(segment)
|
|
179
|
-
);
|
|
180
|
-
for (let i = potentialCandidates.length - 1; i >= 0; i--) {
|
|
181
|
-
const segment = potentialCandidates[i];
|
|
182
|
-
if (!segment.startsWith("@")) {
|
|
183
|
-
return sanitizeTag(camelcase(segment));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
const canFallbackToPathSegment = potentialCandidates.length > 0;
|
|
187
|
-
if (operationId) {
|
|
188
|
-
const lowerOpId = operationId.toLowerCase();
|
|
189
|
-
const parts = operationId.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").replace(/([a-zA-Z])(\d)/g, "$1_$2").replace(/(\d)([a-zA-Z])/g, "$1_$2").toLowerCase().split(/[_-\s]+/);
|
|
190
|
-
const validParts = parts.filter(Boolean);
|
|
191
|
-
if (commonVerbs.has(lowerOpId) && validParts.length === 1 && canFallbackToPathSegment) {
|
|
192
|
-
} else if (validParts.length > 0) {
|
|
193
|
-
const firstPart = validParts[0];
|
|
194
|
-
const isFirstPartVerb = commonVerbs.has(firstPart);
|
|
195
|
-
if (isFirstPartVerb && validParts.length > 1) {
|
|
196
|
-
const verbPrefixLength = firstPart.length;
|
|
197
|
-
let nextPartStartIndex = -1;
|
|
198
|
-
if (operationId.length > verbPrefixLength) {
|
|
199
|
-
const charAfterPrefix = operationId[verbPrefixLength];
|
|
200
|
-
if (charAfterPrefix >= "A" && charAfterPrefix <= "Z") {
|
|
201
|
-
nextPartStartIndex = verbPrefixLength;
|
|
202
|
-
} else if (charAfterPrefix >= "0" && charAfterPrefix <= "9") {
|
|
203
|
-
nextPartStartIndex = verbPrefixLength;
|
|
204
|
-
} else if (["_", "-"].includes(charAfterPrefix)) {
|
|
205
|
-
nextPartStartIndex = verbPrefixLength + 1;
|
|
206
|
-
} else {
|
|
207
|
-
const match = operationId.substring(verbPrefixLength).match(/[A-Z0-9]/);
|
|
208
|
-
if (match && match.index !== void 0) {
|
|
209
|
-
nextPartStartIndex = verbPrefixLength + match.index;
|
|
210
|
-
}
|
|
211
|
-
if (nextPartStartIndex === -1 && operationId.length > verbPrefixLength) {
|
|
212
|
-
nextPartStartIndex = verbPrefixLength;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
if (nextPartStartIndex !== -1 && nextPartStartIndex < operationId.length) {
|
|
217
|
-
const remainingOriginalSubstring = operationId.substring(nextPartStartIndex);
|
|
218
|
-
const potentialTag = camelcase(remainingOriginalSubstring);
|
|
219
|
-
if (potentialTag) {
|
|
220
|
-
return sanitizeTag(potentialTag);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
const potentialTagJoined = camelcase(validParts.slice(1).join("_"));
|
|
224
|
-
if (potentialTagJoined) {
|
|
225
|
-
return sanitizeTag(potentialTagJoined);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const potentialTagFull = camelcase(operationId);
|
|
229
|
-
if (potentialTagFull) {
|
|
230
|
-
const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;
|
|
231
|
-
if (!(isResultSingleVerb && canFallbackToPathSegment)) {
|
|
232
|
-
if (potentialTagFull.length > 0) {
|
|
233
|
-
return sanitizeTag(potentialTagFull);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
const firstPartCamel = camelcase(firstPart);
|
|
238
|
-
if (firstPartCamel) {
|
|
239
|
-
const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);
|
|
240
|
-
if (!isFirstPartCamelVerb || validParts.length === 1 || !canFallbackToPathSegment) {
|
|
241
|
-
return sanitizeTag(firstPartCamel);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (isFirstPartVerb && validParts.length > 1 && validParts[1] && canFallbackToPathSegment) {
|
|
245
|
-
const secondPartCamel = camelcase(validParts[1]);
|
|
246
|
-
if (secondPartCamel) {
|
|
247
|
-
return sanitizeTag(secondPartCamel);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
if (potentialCandidates.length > 0) {
|
|
253
|
-
let firstCandidate = potentialCandidates[0];
|
|
254
|
-
if (firstCandidate.startsWith("@")) {
|
|
255
|
-
firstCandidate = firstCandidate.substring(1);
|
|
256
|
-
}
|
|
257
|
-
if (firstCandidate) {
|
|
258
|
-
return sanitizeTag(camelcase(firstCandidate));
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
console.warn(
|
|
262
|
-
`Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`
|
|
263
|
-
);
|
|
264
|
-
return "unknown";
|
|
265
|
-
}
|
|
266
|
-
function parseJsonContentType(contentType) {
|
|
267
|
-
if (!contentType) {
|
|
268
|
-
return null;
|
|
269
|
-
}
|
|
270
|
-
let mainType = contentType.trim();
|
|
271
|
-
const semicolonIndex = mainType.indexOf(";");
|
|
272
|
-
if (semicolonIndex !== -1) {
|
|
273
|
-
mainType = mainType.substring(0, semicolonIndex).trim();
|
|
274
|
-
}
|
|
275
|
-
mainType = mainType.toLowerCase();
|
|
276
|
-
if (mainType.endsWith("/json")) {
|
|
277
|
-
return mainType.split("/")[1];
|
|
278
|
-
} else if (mainType.endsWith("+json")) {
|
|
279
|
-
return mainType.split("+")[1];
|
|
280
|
-
}
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
function isStreamingContentType(contentType) {
|
|
284
|
-
return contentType === "application/octet-stream";
|
|
285
|
-
}
|
|
286
|
-
function isSuccessStatusCode(statusCode) {
|
|
287
|
-
statusCode = Number(statusCode);
|
|
288
|
-
return statusCode >= 200 && statusCode < 300;
|
|
289
|
-
}
|
|
14
|
+
import {
|
|
15
|
+
createWriterProxy,
|
|
16
|
+
getFolderExportsV2,
|
|
17
|
+
writeFiles
|
|
18
|
+
} from "@sdk-it/core/file-system.js";
|
|
19
|
+
import {
|
|
20
|
+
augmentSpec,
|
|
21
|
+
cleanFiles,
|
|
22
|
+
forEachOperation,
|
|
23
|
+
isSseContentType,
|
|
24
|
+
isStreamingContentType,
|
|
25
|
+
isSuccessStatusCode,
|
|
26
|
+
parseJsonContentType,
|
|
27
|
+
readWriteMetadata
|
|
28
|
+
} from "@sdk-it/spec";
|
|
290
29
|
|
|
291
30
|
// packages/dart/src/lib/dart-emitter.ts
|
|
292
31
|
import { merge } from "lodash-es";
|
|
293
32
|
import assert from "node:assert";
|
|
294
|
-
import { camelcase
|
|
33
|
+
import { camelcase, snakecase } from "stringcase";
|
|
295
34
|
import {
|
|
296
|
-
|
|
297
|
-
followRef as followRef2,
|
|
35
|
+
followRef,
|
|
298
36
|
isEmpty,
|
|
299
|
-
isRef
|
|
37
|
+
isRef,
|
|
38
|
+
joinSkipDigits,
|
|
300
39
|
notRef,
|
|
301
40
|
parseRef,
|
|
302
|
-
pascalcase
|
|
41
|
+
pascalcase,
|
|
42
|
+
resolveRef
|
|
303
43
|
} from "@sdk-it/core";
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
44
|
+
import {
|
|
45
|
+
coerceTypes,
|
|
46
|
+
formatName,
|
|
47
|
+
getRefUsage,
|
|
48
|
+
isPrimitiveSchema,
|
|
49
|
+
sanitizeTag
|
|
50
|
+
} from "@sdk-it/spec";
|
|
51
|
+
function coearceObject(schema) {
|
|
52
|
+
schema = structuredClone(schema);
|
|
53
|
+
if (schema["x-properties"]) {
|
|
54
|
+
schema.properties = {
|
|
55
|
+
...schema.properties ?? {},
|
|
56
|
+
...schema["x-properties"] ?? {}
|
|
57
|
+
};
|
|
314
58
|
}
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
let nameToFormat = it;
|
|
325
|
-
if (nameToFormat.startsWith("[")) {
|
|
326
|
-
nameToFormat = nameToFormat.slice(1);
|
|
327
|
-
}
|
|
328
|
-
if (nameToFormat.endsWith("]")) {
|
|
329
|
-
nameToFormat = nameToFormat.slice(0, -1);
|
|
330
|
-
}
|
|
331
|
-
return snakecase(nameToFormat);
|
|
59
|
+
if (schema["x-required"]) {
|
|
60
|
+
schema.required = Array.from(
|
|
61
|
+
/* @__PURE__ */ new Set([
|
|
62
|
+
...Array.isArray(schema.required) ? schema.required : [],
|
|
63
|
+
...schema["x-required"] || []
|
|
64
|
+
])
|
|
65
|
+
);
|
|
332
66
|
}
|
|
333
|
-
return
|
|
334
|
-
}
|
|
67
|
+
return schema;
|
|
68
|
+
}
|
|
335
69
|
var DartSerializer = class {
|
|
336
70
|
#spec;
|
|
337
|
-
#
|
|
338
|
-
|
|
71
|
+
#emitHandler;
|
|
72
|
+
#emitHistory = /* @__PURE__ */ new Set();
|
|
73
|
+
#emit(name, content, schema) {
|
|
74
|
+
if (this.#emitHistory.has(content)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.#emitHistory.add(content);
|
|
78
|
+
this.#emitHandler?.(name, content, schema);
|
|
79
|
+
}
|
|
80
|
+
constructor(spec) {
|
|
339
81
|
this.#spec = spec;
|
|
340
|
-
this.#emit = emit;
|
|
341
82
|
}
|
|
342
|
-
|
|
343
|
-
this.#
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const { model } = parseRef(schema.$ref);
|
|
349
|
-
return model === schemaName;
|
|
350
|
-
}
|
|
351
|
-
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
352
|
-
return schema.oneOf.some(
|
|
353
|
-
(subSchema) => checkSchema(subSchema)
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
if (schema.type === "array" && schema.items && notRef(schema.items) && schema.items.oneOf) {
|
|
357
|
-
return checkSchema(schema.items);
|
|
358
|
-
}
|
|
359
|
-
return false;
|
|
360
|
-
};
|
|
361
|
-
for (const [key, value] of Object.entries(this.#spec.components.schemas)) {
|
|
362
|
-
if (checkSchema(value)) {
|
|
363
|
-
list.push(key);
|
|
364
|
-
}
|
|
83
|
+
onEmit(emit) {
|
|
84
|
+
this.#emitHandler = emit;
|
|
85
|
+
}
|
|
86
|
+
#formatKeyName(name) {
|
|
87
|
+
if (name.startsWith("$")) {
|
|
88
|
+
return `\\${name}`;
|
|
365
89
|
}
|
|
366
|
-
return
|
|
90
|
+
return name;
|
|
367
91
|
}
|
|
368
92
|
#object(className, schema, context) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
use: "Map<String, dynamic>",
|
|
374
|
-
encode: "input",
|
|
375
|
-
toJson: `this.${camelcase2(context.name)}`,
|
|
376
|
-
fromJson: `json['${camelcase2(context.name)}']`,
|
|
377
|
-
matches: `json['${camelcase2(context.name)}'] is Map<String, dynamic>`
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
if (isEmpty(schema.properties)) {
|
|
381
|
-
if (context.noEmit !== true) {
|
|
382
|
-
this.#emit(
|
|
93
|
+
const { properties = {}, required = [] } = coearceObject(schema);
|
|
94
|
+
if (schema.additionalProperties || isEmpty(properties)) {
|
|
95
|
+
if (context.requestize) {
|
|
96
|
+
return this.#object(
|
|
383
97
|
className,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}`
|
|
98
|
+
{
|
|
99
|
+
type: "object",
|
|
100
|
+
properties: {
|
|
101
|
+
$body: { "x-special": true }
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
context
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (context.noEmit !== true && !context.propName) {
|
|
108
|
+
this.#emit(
|
|
109
|
+
pascalcase(formatName(className)),
|
|
110
|
+
`typedef ${pascalcase(className)} = Map<String, dynamic>;`,
|
|
111
|
+
schema
|
|
399
112
|
);
|
|
400
113
|
}
|
|
401
114
|
return {
|
|
402
115
|
content: "",
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
fromJson:
|
|
407
|
-
matches: `${
|
|
116
|
+
use: `Map<String, dynamic>`,
|
|
117
|
+
encode: "input",
|
|
118
|
+
encodeV2: "",
|
|
119
|
+
fromJson: context.parsable,
|
|
120
|
+
matches: `${context.parsable} is Map<String, dynamic>`
|
|
408
121
|
};
|
|
409
122
|
}
|
|
123
|
+
let requestContent = "";
|
|
410
124
|
const props = [];
|
|
411
125
|
const toJsonProperties = [];
|
|
412
126
|
const constructorParams = [];
|
|
413
127
|
const fromJsonParams = [];
|
|
414
128
|
const matches = [];
|
|
415
|
-
|
|
129
|
+
const headers = [];
|
|
130
|
+
const params = [];
|
|
131
|
+
const queryParams = [];
|
|
132
|
+
const bodyParams = [];
|
|
133
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
416
134
|
const propName = key.replace("[]", "");
|
|
417
|
-
const
|
|
418
|
-
const
|
|
135
|
+
const safePropName = camelcase(formatName(propName));
|
|
136
|
+
const requiredProp = required.includes(key);
|
|
137
|
+
const jsonKey = this.#formatKeyName(propName);
|
|
138
|
+
const serializedType = this.handle(className, propSchema, requiredProp, {
|
|
419
139
|
name: propName,
|
|
420
|
-
|
|
421
|
-
|
|
140
|
+
safeName: safePropName,
|
|
141
|
+
required: requiredProp,
|
|
142
|
+
propName: isRef(propSchema) ? pascalcase(propName) : joinSkipDigits([className, propName], "_"),
|
|
143
|
+
parsable: `json['${jsonKey}']`
|
|
422
144
|
});
|
|
423
|
-
const nullable2 =
|
|
424
|
-
const nullableSuffix = nullable2 ? "?" : "";
|
|
145
|
+
const nullable2 = serializedType.nullable || !requiredProp;
|
|
146
|
+
const nullableSuffix = serializedType.use === "dynamic" ? "" : nullable2 ? "?" : "";
|
|
147
|
+
const withValue = serializedType.literal !== void 0 ? ` = ${serializedType.literal}` : "";
|
|
425
148
|
props.push(
|
|
426
|
-
`final ${
|
|
149
|
+
`final ${serializedType.use}${nullableSuffix} ${safePropName} ${withValue};`
|
|
427
150
|
);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
constructorParams.push(
|
|
431
|
-
`${required ? "required " : ""}this.${camelcase2(propName)},`
|
|
151
|
+
toJsonProperties.push(
|
|
152
|
+
`'${jsonKey}': ${safePropName}${serializedType.encodeV2}`
|
|
432
153
|
);
|
|
433
|
-
if (
|
|
154
|
+
if (!withValue) {
|
|
155
|
+
fromJsonParams.push(`${safePropName}: ${serializedType.fromJson}`);
|
|
156
|
+
constructorParams.push(
|
|
157
|
+
`${requiredProp ? "required " : ""}this.${safePropName},`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (requiredProp) {
|
|
434
161
|
matches.push(`(
|
|
435
|
-
json.containsKey('${
|
|
436
|
-
? ${nullable2 ? `json['${
|
|
162
|
+
json.containsKey('${jsonKey}')
|
|
163
|
+
? ${nullable2 ? `json['${jsonKey}'] == null` : `json['${jsonKey}'] != null`} ${serializedType.matches ? `&& ${serializedType.matches}` : ""}
|
|
437
164
|
: false)`);
|
|
438
165
|
} else {
|
|
439
166
|
matches.push(`(
|
|
440
|
-
json.containsKey('${
|
|
441
|
-
? ${nullable2 ? `json['${
|
|
167
|
+
json.containsKey('${jsonKey}')
|
|
168
|
+
? ${nullable2 ? `json['${jsonKey}'] == null` : `json['${jsonKey}'] != null`} ${serializedType.matches ? `|| ${serializedType.matches}` : ""}
|
|
442
169
|
: true)`);
|
|
443
170
|
}
|
|
171
|
+
const { "x-in": source, "x-special": special } = propSchema;
|
|
172
|
+
if (source) {
|
|
173
|
+
switch (source) {
|
|
174
|
+
case "header":
|
|
175
|
+
headers.push(`'${jsonKey}': ${safePropName}`);
|
|
176
|
+
break;
|
|
177
|
+
case "path":
|
|
178
|
+
params.push(`'${jsonKey}': ${safePropName}`);
|
|
179
|
+
break;
|
|
180
|
+
case "query":
|
|
181
|
+
queryParams.push(`'${jsonKey}': ${safePropName}`);
|
|
182
|
+
break;
|
|
183
|
+
default:
|
|
184
|
+
bodyParams.push(`'${jsonKey}': ${safePropName}`);
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
if (special) {
|
|
188
|
+
bodyParams.push(`$body${serializedType.encodeV2}`);
|
|
189
|
+
} else {
|
|
190
|
+
bodyParams.push(
|
|
191
|
+
`'${jsonKey}': ${safePropName}${serializedType.encodeV2}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
444
195
|
}
|
|
445
|
-
|
|
446
|
-
|
|
196
|
+
if (context.requestize) {
|
|
197
|
+
const body = bodyParams.length === 1 && bodyParams[0].startsWith("$body") ? bodyParams[0] : `${bodyParams.length ? `{${bodyParams.join(", ")}}` : "{}"}`;
|
|
198
|
+
requestContent = `
|
|
199
|
+
RequestInput toRequest() =>
|
|
200
|
+
RequestInput(
|
|
201
|
+
headers: ${headers.length ? `{${headers.join(", ")}}` : "{}"},
|
|
202
|
+
query: ${queryParams.length ? `{${queryParams.join(", ")}}` : "{}"},
|
|
203
|
+
params: ${params.length ? `{${params.join(", ")}}` : "{}"},
|
|
204
|
+
body: ${body}
|
|
205
|
+
);`;
|
|
206
|
+
}
|
|
207
|
+
const constructorP = constructorParams.length ? `{${constructorParams.join("\n")}}` : "";
|
|
208
|
+
const fixedClassName = pascalcase(sanitizeTag(className));
|
|
209
|
+
const content = `class ${fixedClassName} {
|
|
447
210
|
${props.join("\n")}
|
|
448
|
-
${
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return ${className}(
|
|
211
|
+
const ${fixedClassName}(${constructorP}): super();
|
|
212
|
+
factory ${fixedClassName}.fromJson(Map<String, dynamic> json) {
|
|
213
|
+
return ${fixedClassName}(
|
|
452
214
|
${fromJsonParams.join(",\n")});
|
|
453
215
|
}
|
|
454
216
|
Map<String, dynamic> toJson() => {
|
|
455
217
|
${toJsonProperties.join(",\n")}
|
|
456
218
|
};
|
|
457
|
-
static bool matches(Map<String, dynamic> json) {
|
|
458
|
-
|
|
459
|
-
}
|
|
219
|
+
static bool matches(Map<String, dynamic> json) {return ${matches.join(" && ")};}
|
|
220
|
+
|
|
221
|
+
${requestContent}
|
|
222
|
+
|
|
460
223
|
}`;
|
|
461
|
-
if (context.noEmit !== true) {
|
|
462
|
-
this.#emit(
|
|
224
|
+
if (context.noEmit !== true && !context.propName) {
|
|
225
|
+
this.#emit(fixedClassName, content, schema);
|
|
463
226
|
}
|
|
464
227
|
const nullable = !context.required || context.nullable === true;
|
|
228
|
+
const generatedClassName = context.forJson || className;
|
|
465
229
|
return {
|
|
466
|
-
use:
|
|
230
|
+
use: fixedClassName,
|
|
467
231
|
content,
|
|
468
232
|
encode: "input.toJson()",
|
|
469
|
-
|
|
470
|
-
fromJson:
|
|
471
|
-
matches: `${
|
|
233
|
+
encodeV2: `${context.required ? "" : "?"}.toJson()`,
|
|
234
|
+
fromJson: `${generatedClassName}.fromJson(${context.parsable})`,
|
|
235
|
+
matches: `${generatedClassName}.matches(${context.parsable})`
|
|
472
236
|
};
|
|
473
237
|
}
|
|
474
|
-
#
|
|
475
|
-
|
|
238
|
+
#oneOfObject(className, varientName, schemaOrRef, context) {
|
|
239
|
+
const schema = resolveRef(this.#spec, schemaOrRef);
|
|
240
|
+
const entries = Object.entries(schema.properties || {});
|
|
241
|
+
if (entries.length === 1) {
|
|
242
|
+
const [key, prop] = entries[0];
|
|
243
|
+
const serializedType2 = this.handle(
|
|
244
|
+
pascalcase(`${className} ${varientName}`),
|
|
245
|
+
prop,
|
|
246
|
+
true,
|
|
247
|
+
{
|
|
248
|
+
...context,
|
|
249
|
+
propName: joinSkipDigits([varientName, key], "_"),
|
|
250
|
+
safeName: varientName,
|
|
251
|
+
parsable: `json['${varientName}']`
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
return {
|
|
255
|
+
typeStr: `${serializedType2.use}${serializedType2.nullable ? "?" : ""} ${key}`,
|
|
256
|
+
returnValue: `_Value({'${key}': ${key}${serializedType2.encodeV2}});`,
|
|
257
|
+
fromJson: serializedType2.fromJson
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const serializedType = this.handle(className, schemaOrRef, true, {
|
|
261
|
+
...context,
|
|
262
|
+
propName: joinSkipDigits([className, varientName], "_"),
|
|
263
|
+
safeName: varientName,
|
|
264
|
+
parsable: `json['${varientName}']`
|
|
265
|
+
});
|
|
266
|
+
return {
|
|
267
|
+
typeStr: `${serializedType.use} value`,
|
|
268
|
+
returnValue: `_Value(value.toJson());`,
|
|
269
|
+
fromJson: serializedType.fromJson
|
|
270
|
+
};
|
|
476
271
|
}
|
|
477
272
|
#array(className, schema, required = false, context) {
|
|
478
273
|
if (!schema.items) {
|
|
479
274
|
return {
|
|
480
275
|
content: "",
|
|
481
276
|
use: "List<dynamic>",
|
|
482
|
-
|
|
483
|
-
fromJson: `List<dynamic>.from(${context.
|
|
277
|
+
encodeV2: "",
|
|
278
|
+
fromJson: `List<dynamic>.from(${context.parsable})`,
|
|
484
279
|
matches: ""
|
|
485
280
|
};
|
|
486
281
|
}
|
|
487
|
-
const itemsType = this.handle(className, schema.items, true,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
.
|
|
493
|
-
|
|
494
|
-
|
|
282
|
+
const itemsType = this.handle(className, schema.items, true, {
|
|
283
|
+
...context,
|
|
284
|
+
parsable: "it"
|
|
285
|
+
});
|
|
286
|
+
const fromJson = required ? context.name ? `(${context.parsable} as List)
|
|
287
|
+
.map((it) => ${itemsType.simple ? `it as ${itemsType.use}` : `${itemsType.fromJson}`})
|
|
288
|
+
.toList()` : `(json as List)
|
|
289
|
+
.map((it) => ${itemsType.simple ? `it as ${itemsType.use}` : `${itemsType.fromJson}`})
|
|
290
|
+
.toList()` : context.name ? `${context.parsable} != null
|
|
291
|
+
? (${context.parsable} as List)
|
|
292
|
+
.map((it) => ${itemsType.simple ? `it as ${itemsType.use}` : `${itemsType.fromJson}`})
|
|
495
293
|
.toList()
|
|
496
294
|
: null` : `json != null
|
|
497
|
-
? (json as List
|
|
498
|
-
.map((it) => ${itemsType.simple ?
|
|
295
|
+
? (json as List)
|
|
296
|
+
.map((it) => ${itemsType.simple ? `it as ${itemsType.use}` : `${itemsType.fromJson}`})
|
|
499
297
|
.toList()
|
|
500
298
|
: null`;
|
|
501
299
|
return {
|
|
@@ -503,8 +301,9 @@ return ${matches.join(" && ")};
|
|
|
503
301
|
content: "",
|
|
504
302
|
use: `List<${itemsType.use}>`,
|
|
505
303
|
fromJson,
|
|
506
|
-
|
|
507
|
-
|
|
304
|
+
simple: true,
|
|
305
|
+
encodeV2: `${itemsType.simple ? "" : `${context.required ? "" : "?"}.map((it) => ${itemsType.simple ? "it" : `it.toJson()`}).toList()`}`,
|
|
306
|
+
matches: context.parsable ? `(${context.parsable} as List).every((it) => ${itemsType.matches})` : `${context.parsable} is List && ${context.parsable}.every((it) => ${itemsType.matches})`
|
|
508
307
|
};
|
|
509
308
|
}
|
|
510
309
|
/**
|
|
@@ -516,14 +315,15 @@ return ${matches.join(" && ")};
|
|
|
516
315
|
return this.#string(schema, context);
|
|
517
316
|
case "number":
|
|
518
317
|
case "integer":
|
|
519
|
-
return this
|
|
318
|
+
return this.#number(schema, context);
|
|
520
319
|
case "boolean":
|
|
521
320
|
return {
|
|
522
321
|
content: "",
|
|
523
322
|
use: "bool",
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
323
|
+
encodeV2: "",
|
|
324
|
+
simple: true,
|
|
325
|
+
fromJson: context.parsable,
|
|
326
|
+
matches: `${context.parsable} is bool`
|
|
527
327
|
};
|
|
528
328
|
case "object":
|
|
529
329
|
return this.#object(className, schema, context);
|
|
@@ -532,38 +332,51 @@ return ${matches.join(" && ")};
|
|
|
532
332
|
case "null":
|
|
533
333
|
return {
|
|
534
334
|
content: "",
|
|
335
|
+
encodeV2: "",
|
|
336
|
+
simple: true,
|
|
535
337
|
use: "Null",
|
|
536
|
-
|
|
537
|
-
fromJson: `json['${context.name}']`
|
|
338
|
+
fromJson: context.parsable
|
|
538
339
|
};
|
|
539
340
|
default:
|
|
540
341
|
return {
|
|
541
342
|
content: "",
|
|
542
343
|
use: "dynamic",
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
fromJson:
|
|
344
|
+
encodeV2: "",
|
|
345
|
+
simple: true,
|
|
346
|
+
fromJson: context.parsable,
|
|
347
|
+
matches: "",
|
|
348
|
+
nullable: false
|
|
546
349
|
};
|
|
547
350
|
}
|
|
548
351
|
}
|
|
549
352
|
#ref(className, $ref, required, context) {
|
|
550
|
-
const schemaName =
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
required,
|
|
555
|
-
{
|
|
353
|
+
const schemaName = pascalcase(sanitizeTag(parseRef($ref).model));
|
|
354
|
+
const schema = followRef(this.#spec, $ref);
|
|
355
|
+
if (isPrimitiveSchema(schema)) {
|
|
356
|
+
return this.handle(schemaName, schema, required, {
|
|
556
357
|
...context,
|
|
557
358
|
propName: schemaName,
|
|
558
|
-
noEmit:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
359
|
+
noEmit: true,
|
|
360
|
+
// default to json in case this method is root level
|
|
361
|
+
parsable: context.parsable || "json"
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
const generatedClassName = context.forJson || schemaName;
|
|
365
|
+
const isDynamicObject = schema.type === "object" ? !!schema.additionalProperties || isEmpty(schema.properties) : schema.anyOf ? false : !schema.oneOf;
|
|
366
|
+
return {
|
|
367
|
+
use: pascalcase(schemaName),
|
|
368
|
+
content: "",
|
|
369
|
+
encode: "input.toJson()",
|
|
370
|
+
encodeV2: isDynamicObject ? "" : `${context.required ? "" : "?"}.toJson()`,
|
|
371
|
+
fromJson: isDynamicObject ? `${generatedClassName}.from(json)` : `${generatedClassName}.fromJson(${context.parsable || "json"})`,
|
|
372
|
+
matches: isDynamicObject ? `${context.parsable} is ${generatedClassName}` : `${generatedClassName}.matches(${context.parsable})`,
|
|
373
|
+
simple: isDynamicObject
|
|
374
|
+
};
|
|
562
375
|
}
|
|
563
376
|
// fixme: this method should no longer be needed because the logic in it is being preprocessed before emitting begins
|
|
564
377
|
#allOf(className, schemas, context) {
|
|
565
378
|
const name = pascalcase(context.propName || className);
|
|
566
|
-
const refs = schemas.filter(
|
|
379
|
+
const refs = schemas.filter(isRef);
|
|
567
380
|
const nonRefs = schemas.filter(notRef);
|
|
568
381
|
if (nonRefs.some((it) => it.type && it.type !== "object")) {
|
|
569
382
|
assert(false, `allOf ${name} must be an object`);
|
|
@@ -571,174 +384,169 @@ return ${matches.join(" && ")};
|
|
|
571
384
|
const objectSchema = merge(
|
|
572
385
|
{},
|
|
573
386
|
...nonRefs,
|
|
574
|
-
...refs.map((ref) =>
|
|
387
|
+
...refs.map((ref) => followRef(this.#spec, ref.$ref))
|
|
575
388
|
);
|
|
576
389
|
delete objectSchema.allOf;
|
|
577
390
|
return this.handle(name, objectSchema, true, context);
|
|
578
391
|
}
|
|
579
|
-
#anyOf(className, schemas, context) {
|
|
580
|
-
if (schemas.length === 0) {
|
|
581
|
-
return {
|
|
582
|
-
content: "",
|
|
583
|
-
nullable: false,
|
|
584
|
-
use: "dynamic",
|
|
585
|
-
toJson: `${camelcase2(context.name)}`,
|
|
586
|
-
fromJson: `json['${context.name}']`
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
const nullSchemaIndex = schemas.findIndex((schema) => {
|
|
590
|
-
if (isRef2(schema)) {
|
|
591
|
-
const refSchema = followRef2(this.#spec, schema.$ref);
|
|
592
|
-
return refSchema.type === "null";
|
|
593
|
-
}
|
|
594
|
-
return schema.type === "null";
|
|
595
|
-
});
|
|
596
|
-
const anyOfSchemas = schemas.slice(0);
|
|
597
|
-
if (nullSchemaIndex >= 0) {
|
|
598
|
-
anyOfSchemas.splice(nullSchemaIndex, 1);
|
|
599
|
-
}
|
|
600
|
-
return this.handle(className, anyOfSchemas[0], true, {
|
|
601
|
-
...context,
|
|
602
|
-
nullable: nullSchemaIndex >= 0
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
392
|
#mixinise(name, context) {
|
|
606
|
-
const mixins = this.#
|
|
393
|
+
const mixins = getRefUsage(this.#spec, name);
|
|
607
394
|
if (context.mixin) {
|
|
608
395
|
mixins.unshift(context.mixin);
|
|
609
396
|
}
|
|
610
|
-
const withMixins = mixins.length > 1 ? `
|
|
397
|
+
const withMixins = mixins.length > 1 ? ` implements ${mixins.join(", ")}` : mixins.length === 1 ? `extends ${mixins[0]}` : "";
|
|
611
398
|
return {
|
|
612
399
|
withMixins,
|
|
613
400
|
mixins
|
|
614
401
|
};
|
|
615
402
|
}
|
|
616
|
-
#
|
|
617
|
-
|
|
403
|
+
#buildClass(options) {
|
|
404
|
+
return [
|
|
405
|
+
options.abstract ? "abstract" : "",
|
|
406
|
+
options.mixins?.length ? "" : "mixin",
|
|
407
|
+
`class ${options.name} ${options.withMixins} ${options.implements?.length ? `implements ${options.implements.join(", ")}` : ""}`,
|
|
408
|
+
"{",
|
|
409
|
+
options.content.join("\n"),
|
|
410
|
+
"}"
|
|
411
|
+
].filter(Boolean).join("\n");
|
|
412
|
+
}
|
|
413
|
+
#oneOf(className, schema, context) {
|
|
414
|
+
const varients = schema["x-varients"];
|
|
415
|
+
const schemas = schema.oneOf || schema.anyOf || [];
|
|
416
|
+
const name = pascalcase(sanitizeTag(context.propName || className));
|
|
618
417
|
if (schemas.length === 0) {
|
|
619
418
|
return {
|
|
620
419
|
content: "",
|
|
621
420
|
nullable: false,
|
|
622
421
|
use: "dynamic",
|
|
623
|
-
|
|
624
|
-
fromJson:
|
|
422
|
+
encodeV2: "",
|
|
423
|
+
fromJson: context.parsable
|
|
625
424
|
};
|
|
626
425
|
}
|
|
627
426
|
const content = [];
|
|
628
427
|
const patterns = [];
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
${name}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}}`);
|
|
664
|
-
patterns.push({
|
|
665
|
-
pattern: `case List(): return ${name}List(List<${itemsType.use}>.from(json));`,
|
|
666
|
-
name: `${name}List`
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
if (objects.length) {
|
|
671
|
-
const candidates = {};
|
|
672
|
-
for (const schema of objects) {
|
|
673
|
-
if (schema.additionalProperties === true) {
|
|
428
|
+
content.push(`class _Value implements ${name} {
|
|
429
|
+
final dynamic value;
|
|
430
|
+
const _Value(this.value);
|
|
431
|
+
@override
|
|
432
|
+
toJson() => value;
|
|
433
|
+
}`);
|
|
434
|
+
for (const { name: varientName, ...varient } of varients) {
|
|
435
|
+
switch (varientName) {
|
|
436
|
+
case "empty":
|
|
437
|
+
patterns.push({
|
|
438
|
+
name: `static ${name} ${formatName(varientName)}() => _Value("");`,
|
|
439
|
+
pattern: `case '': return ${name}.${formatName(varientName)}();`
|
|
440
|
+
});
|
|
441
|
+
continue;
|
|
442
|
+
case "uri":
|
|
443
|
+
patterns.push({
|
|
444
|
+
name: `static ${name} ${formatName(varientName)}(Uri value) => _Value(value);`,
|
|
445
|
+
pattern: `case String: return ${name}.${formatName(varientName)}(Uri.parse(json));`
|
|
446
|
+
});
|
|
447
|
+
continue;
|
|
448
|
+
case "number":
|
|
449
|
+
patterns.push({
|
|
450
|
+
name: `static ${name} ${formatName(varientName)}(num value) => _Value(value);`,
|
|
451
|
+
pattern: `case num: return ${name}.${formatName(varientName)}(json);`
|
|
452
|
+
});
|
|
453
|
+
continue;
|
|
454
|
+
case "object": {
|
|
455
|
+
const result = this.handle(className, schemas[varient.position]);
|
|
456
|
+
patterns.push({
|
|
457
|
+
name: `static ${name} ${formatName(varientName)}(${result.use} value) => _Value(value);`,
|
|
458
|
+
pattern: `case Map<String, dynamic> map: return ${name}.${formatName(varientName)}(${pascalcase(
|
|
459
|
+
`${name} ${formatName(varientName)}`
|
|
460
|
+
)}.fromJson(map));`
|
|
461
|
+
});
|
|
674
462
|
continue;
|
|
675
|
-
}
|
|
676
|
-
assert(
|
|
677
|
-
schema.properties,
|
|
678
|
-
`Schema ${name} has no properties which are required in oneOf in order to determine the discriminator.`
|
|
679
|
-
);
|
|
680
|
-
for (const [propName, propSchema] of Object.entries(
|
|
681
|
-
schema.properties
|
|
682
|
-
)) {
|
|
683
|
-
if (notRef(propSchema) && propSchema.enum && // fixme: the enum can have more than one value as long as it is not duplicated else where on the other schemas
|
|
684
|
-
propSchema.enum.length === 1) {
|
|
685
|
-
candidates[propName] ??= /* @__PURE__ */ new Set();
|
|
686
|
-
candidates[propName].add(String(propSchema.enum[0]));
|
|
687
|
-
}
|
|
688
463
|
}
|
|
689
464
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
discriminatorProp = name2;
|
|
465
|
+
switch (varient.type) {
|
|
466
|
+
case "string":
|
|
467
|
+
patterns.push({
|
|
468
|
+
name: `static ${name} ${formatName(varientName)}(String value) => _Value(value);`,
|
|
469
|
+
pattern: `case String: return ${name}.${formatName(varientName)}(json);`
|
|
470
|
+
});
|
|
697
471
|
break;
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
472
|
+
case "object": {
|
|
473
|
+
const { typeStr, returnValue, fromJson } = this.#oneOfObject(
|
|
474
|
+
name,
|
|
475
|
+
formatName(varientName),
|
|
476
|
+
schemas[varient.position],
|
|
477
|
+
context
|
|
478
|
+
);
|
|
479
|
+
const staticStr = varient.static ? `&& json['${varient.source}'] == '${formatName(varientName)}'` : "";
|
|
480
|
+
const caseStr = `case Map<String, dynamic> json when json.containsKey('${varient.source}') ${staticStr}`;
|
|
481
|
+
const returnStr = `return ${name}.${formatName(varientName)}(${fromJson})`;
|
|
704
482
|
patterns.push({
|
|
705
|
-
|
|
706
|
-
|
|
483
|
+
name: `static ${name} ${formatName(varientName)}(${typeStr}) => ${returnValue}`,
|
|
484
|
+
pattern: `${caseStr}: ${returnStr};`
|
|
707
485
|
});
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
case "array": {
|
|
489
|
+
const serializedType = this.handle(
|
|
490
|
+
className,
|
|
491
|
+
schemas[varient.position],
|
|
492
|
+
true,
|
|
493
|
+
{
|
|
494
|
+
...context,
|
|
495
|
+
noEmit: true,
|
|
496
|
+
parsable: "json"
|
|
497
|
+
}
|
|
498
|
+
);
|
|
499
|
+
patterns.push({
|
|
500
|
+
name: `static ${name} ${formatName(varientName)}(${serializedType.use} value) => _Value(value);`,
|
|
501
|
+
pattern: `case ${serializedType.use} json: return ${name}.${formatName(varientName)}(${serializedType.fromJson});`
|
|
712
502
|
});
|
|
713
|
-
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
default: {
|
|
714
506
|
}
|
|
715
507
|
}
|
|
716
508
|
}
|
|
717
509
|
const { mixins, withMixins } = this.#mixinise(name, context);
|
|
718
|
-
content.
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
510
|
+
content.push(
|
|
511
|
+
this.#buildClass({
|
|
512
|
+
name,
|
|
513
|
+
abstract: true,
|
|
514
|
+
mixins,
|
|
515
|
+
withMixins,
|
|
516
|
+
content: [
|
|
517
|
+
// 'dynamic get value;',
|
|
518
|
+
"dynamic toJson();",
|
|
519
|
+
...patterns.map((it) => it.name),
|
|
520
|
+
`${name}();`,
|
|
521
|
+
`factory ${name}.fromJson(dynamic json)`,
|
|
522
|
+
`{`,
|
|
523
|
+
`switch (json) {`,
|
|
524
|
+
...patterns.map((it) => it.pattern),
|
|
525
|
+
`default: throw ArgumentError("Invalid type: \${json}");`,
|
|
526
|
+
`}`,
|
|
527
|
+
`}`,
|
|
528
|
+
`static bool matches(dynamic value) {
|
|
529
|
+
try {
|
|
530
|
+
${name}.fromJson(value);
|
|
531
|
+
return true;
|
|
532
|
+
} catch (error) {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
}`
|
|
536
|
+
]
|
|
537
|
+
})
|
|
538
|
+
);
|
|
539
|
+
if (context.noEmit !== true) {
|
|
540
|
+
this.#emit(name, content.join("\n"), {
|
|
541
|
+
oneOf: schemas
|
|
542
|
+
});
|
|
543
|
+
}
|
|
736
544
|
return {
|
|
737
545
|
content: content.join("\n"),
|
|
738
546
|
use: name,
|
|
739
|
-
|
|
740
|
-
fromJson: `${name}.fromJson(
|
|
741
|
-
matches: `${name}.matches(
|
|
547
|
+
encodeV2: `${context.required ? "" : "?"}.toJson()`,
|
|
548
|
+
fromJson: `${name}.fromJson(${context.parsable})`,
|
|
549
|
+
matches: `${name}.matches(${context.parsable})`
|
|
742
550
|
};
|
|
743
551
|
}
|
|
744
552
|
#simple(type) {
|
|
@@ -751,6 +559,12 @@ return ${matches.join(" && ")};
|
|
|
751
559
|
return "int";
|
|
752
560
|
case "boolean":
|
|
753
561
|
return "bool";
|
|
562
|
+
case "object":
|
|
563
|
+
return "Map<String, dynamic>";
|
|
564
|
+
case "array":
|
|
565
|
+
return "List<dynamic>";
|
|
566
|
+
case "null":
|
|
567
|
+
return "Null";
|
|
754
568
|
default:
|
|
755
569
|
return "dynamic";
|
|
756
570
|
}
|
|
@@ -758,17 +572,17 @@ return ${matches.join(" && ")};
|
|
|
758
572
|
#enum(className, schema, context) {
|
|
759
573
|
const name = context.propName || className;
|
|
760
574
|
const values = schema.enum;
|
|
761
|
-
const valType = this.#simple(schema
|
|
762
|
-
const { mixins, withMixins } = this.#mixinise(
|
|
575
|
+
const valType = this.#simple(coerceTypes(schema)[0]);
|
|
576
|
+
const { mixins, withMixins } = this.#mixinise(name, context);
|
|
763
577
|
const content = `
|
|
764
|
-
class _EnumValue implements ${pascalcase(name)} {
|
|
578
|
+
class _EnumValue implements ${pascalcase(formatName(name))} {
|
|
765
579
|
final ${valType} value;
|
|
766
580
|
const _EnumValue(this.value);
|
|
767
581
|
@override
|
|
768
|
-
toJson()
|
|
582
|
+
toJson() => value;
|
|
769
583
|
}
|
|
770
|
-
abstract ${mixins.length ? "" : "mixin"} class ${pascalcase(name)} ${withMixins} {
|
|
771
|
-
${values.map((it) => `static const _EnumValue ${formatName(it)} = _EnumValue(${typeof it === "number" ? it : `'${it}'`});`).join("\n")}
|
|
584
|
+
abstract ${mixins.length ? "" : "mixin"} class ${pascalcase(formatName(name))} ${withMixins} {
|
|
585
|
+
${values.map((it) => `static const _EnumValue ${formatName(snakecase(formatName(it)))} = _EnumValue(${typeof it === "number" ? it : `'${it}'`});`).join("\n")}
|
|
772
586
|
dynamic toJson();
|
|
773
587
|
|
|
774
588
|
${valType} get value;
|
|
@@ -776,7 +590,7 @@ return ${matches.join(" && ")};
|
|
|
776
590
|
static _EnumValue fromJson(${valType} value) {
|
|
777
591
|
switch (value) {
|
|
778
592
|
${values.map(
|
|
779
|
-
(it) => `case ${typeof it === "number" ? it : `'${it}'`}: return ${formatName(it)};`
|
|
593
|
+
(it) => `case ${typeof it === "number" ? it : `'${it}'`}: return ${formatName(snakecase(formatName(it)))};`
|
|
780
594
|
).join("\n")}
|
|
781
595
|
default:
|
|
782
596
|
throw ArgumentError.value(value, "value", "No enum value with that name");
|
|
@@ -794,15 +608,28 @@ return false;
|
|
|
794
608
|
|
|
795
609
|
}`;
|
|
796
610
|
if (context.noEmit !== true) {
|
|
797
|
-
this.#emit(name, content);
|
|
611
|
+
this.#emit(pascalcase(formatName(name)), content, schema);
|
|
798
612
|
}
|
|
799
613
|
return {
|
|
800
|
-
|
|
614
|
+
use: pascalcase(formatName(name)),
|
|
615
|
+
type: this.#simple(coerceTypes(schema)[0]),
|
|
801
616
|
content,
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
617
|
+
encodeV2: `${context.required ? "" : "?"}.toJson()`,
|
|
618
|
+
fromJson: `${pascalcase(name)}.fromJson(${context.parsable})`,
|
|
619
|
+
matches: `${pascalcase(name)}.matches(${context.parsable})`
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
#const(className, schema, context) {
|
|
623
|
+
const valType = this.#simple(coerceTypes(schema)[0]);
|
|
624
|
+
return {
|
|
625
|
+
content: "",
|
|
626
|
+
literal: valType === "String" ? `'${schema.const}'` : schema.const,
|
|
627
|
+
use: valType,
|
|
628
|
+
encode: "input",
|
|
629
|
+
encodeV2: "",
|
|
630
|
+
fromJson: context.parsable,
|
|
631
|
+
matches: context.parsable,
|
|
632
|
+
simple: true
|
|
806
633
|
};
|
|
807
634
|
}
|
|
808
635
|
/**
|
|
@@ -817,46 +644,44 @@ return false;
|
|
|
817
644
|
content: "",
|
|
818
645
|
use: "DateTime",
|
|
819
646
|
simple: true,
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
fromJson: context.name ? `json['${context.name}'] != null ? DateTime.parse(json['${context.name}']) : null` : "json",
|
|
824
|
-
matches: `json['${context.name}'] is String`
|
|
647
|
+
encodeV2: `${context.required ? "" : "?"}.toIso8601String()`,
|
|
648
|
+
fromJson: context.parsable ? context.required ? `DateTime.parse(${context.parsable})` : `${context.parsable} != null ? DateTime.parse(${context.parsable}) : null` : "json",
|
|
649
|
+
matches: `${context.parsable} is String`
|
|
825
650
|
};
|
|
826
651
|
case "binary":
|
|
827
652
|
case "byte":
|
|
828
653
|
return {
|
|
829
654
|
content: "",
|
|
830
655
|
use: "File",
|
|
831
|
-
|
|
656
|
+
encodeV2: "",
|
|
832
657
|
simple: true,
|
|
833
|
-
fromJson: context.
|
|
834
|
-
matches:
|
|
658
|
+
fromJson: context.parsable,
|
|
659
|
+
matches: `${context.parsable} is Uint8List`
|
|
835
660
|
};
|
|
836
661
|
default:
|
|
837
662
|
return {
|
|
838
663
|
encode: "input",
|
|
839
664
|
use: `String`,
|
|
840
665
|
content: "",
|
|
666
|
+
encodeV2: "",
|
|
841
667
|
simple: true,
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
matches: `json['${context.name}'] is String`
|
|
668
|
+
fromJson: `${context.parsable} as String`,
|
|
669
|
+
matches: `${context.parsable} is String`
|
|
845
670
|
};
|
|
846
671
|
}
|
|
847
672
|
}
|
|
848
673
|
/**
|
|
849
674
|
* Handle number/integer types with formats
|
|
850
675
|
*/
|
|
851
|
-
number(schema, context) {
|
|
676
|
+
#number(schema, context) {
|
|
852
677
|
if (schema.type === "integer") {
|
|
853
678
|
return {
|
|
854
679
|
content: "",
|
|
855
680
|
use: "int",
|
|
856
681
|
simple: true,
|
|
857
|
-
|
|
858
|
-
fromJson:
|
|
859
|
-
matches:
|
|
682
|
+
encodeV2: "",
|
|
683
|
+
fromJson: context.parsable,
|
|
684
|
+
matches: `${context.parsable} is int`
|
|
860
685
|
};
|
|
861
686
|
}
|
|
862
687
|
if (["float", "double"].includes(schema.format)) {
|
|
@@ -864,37 +689,40 @@ return false;
|
|
|
864
689
|
content: "",
|
|
865
690
|
use: "double",
|
|
866
691
|
simple: true,
|
|
867
|
-
|
|
868
|
-
fromJson:
|
|
869
|
-
matches:
|
|
692
|
+
encodeV2: "",
|
|
693
|
+
fromJson: context.parsable,
|
|
694
|
+
matches: `${context.parsable} is double`
|
|
870
695
|
};
|
|
871
696
|
}
|
|
872
697
|
return {
|
|
873
698
|
content: "",
|
|
874
699
|
use: "num",
|
|
875
700
|
simple: true,
|
|
876
|
-
|
|
877
|
-
fromJson:
|
|
878
|
-
matches:
|
|
701
|
+
encodeV2: "",
|
|
702
|
+
fromJson: context.parsable,
|
|
703
|
+
matches: `${context.parsable} is double`
|
|
879
704
|
};
|
|
880
705
|
}
|
|
881
706
|
#serialize(className, schema, required = true, context = {}) {
|
|
882
|
-
if (
|
|
707
|
+
if (isRef(schema)) {
|
|
883
708
|
return this.#ref(className, schema.$ref, required, context);
|
|
884
709
|
}
|
|
885
710
|
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
886
711
|
return this.#allOf(className, schema.allOf, context);
|
|
887
712
|
}
|
|
888
713
|
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
889
|
-
return this.#oneOf(className, schema
|
|
714
|
+
return this.#oneOf(className, schema, context);
|
|
890
715
|
}
|
|
891
716
|
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
892
|
-
return this.#
|
|
717
|
+
return this.#oneOf(className, schema, context);
|
|
718
|
+
}
|
|
719
|
+
if (schema.const !== void 0) {
|
|
720
|
+
return this.#const(className, schema, context);
|
|
893
721
|
}
|
|
894
722
|
if (schema.enum && Array.isArray(schema.enum)) {
|
|
895
723
|
return this.#enum(className, schema, context);
|
|
896
724
|
}
|
|
897
|
-
const types =
|
|
725
|
+
const types = coerceTypes(schema, false);
|
|
898
726
|
let nullable = false;
|
|
899
727
|
if ("nullable" in schema && schema.nullable) {
|
|
900
728
|
nullable = true;
|
|
@@ -911,10 +739,12 @@ return false;
|
|
|
911
739
|
return this.#array(className, schema, true, context);
|
|
912
740
|
}
|
|
913
741
|
return {
|
|
742
|
+
// Unknown type -> fallback
|
|
914
743
|
content: "",
|
|
915
744
|
use: "dynamic",
|
|
916
|
-
|
|
917
|
-
|
|
745
|
+
encodeV2: "",
|
|
746
|
+
simple: true,
|
|
747
|
+
fromJson: context.parsable,
|
|
918
748
|
nullable: false,
|
|
919
749
|
matches: ""
|
|
920
750
|
// keep it empty as 'type is dynamic' is always true
|
|
@@ -936,165 +766,70 @@ return false;
|
|
|
936
766
|
forJson: alias
|
|
937
767
|
});
|
|
938
768
|
if (alias) {
|
|
939
|
-
this.#emit(
|
|
769
|
+
this.#emit(
|
|
770
|
+
pascalcase(formatName(className)),
|
|
771
|
+
`typedef ${pascalcase(alias)} = ${serialized.use};`,
|
|
772
|
+
resolveRef(this.#spec, schema)
|
|
773
|
+
);
|
|
940
774
|
return serialized;
|
|
941
775
|
}
|
|
942
776
|
return serialized;
|
|
943
777
|
}
|
|
944
778
|
};
|
|
945
779
|
function isObjectSchema(schema) {
|
|
946
|
-
return !
|
|
780
|
+
return !isRef(schema) && (schema.type === "object" || !!coearceObject(schema).properties);
|
|
947
781
|
}
|
|
948
782
|
|
|
949
783
|
// packages/dart/src/lib/http/dispatcher.txt
|
|
950
|
-
var dispatcher_default = "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:http/http.dart' as http;\nimport 'package:http_parser/http_parser.dart';\nimport 'package:mime/mime.dart' as mime;\n\nimport './interceptors.dart';\nimport './responses.dart';\n\nclass Dispatcher {\n final List<Interceptor> interceptors;\n\n Dispatcher(this.interceptors);\n\n
|
|
784
|
+
var dispatcher_default = "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:http/http.dart' as http;\nimport 'package:http_parser/http_parser.dart';\nimport 'package:mime/mime.dart' as mime;\n\nimport './interceptors.dart';\nimport './responses.dart';\n\nclass Dispatcher {\n final List<Interceptor> interceptors;\n\n Dispatcher(this.interceptors);\n\n void _setHeaders(\n http.BaseRequest request,\n RequestConfig config, [\n String? contentType,\n ]) {\n request.headers.addAll(config.headers);\n for (var entry in config.input.headers.entries) {\n final value = entry.value;\n if (value != null) {\n request.headers[entry.key] = value;\n }\n }\n if (contentType != null) {\n request.headers['Content-Type'] = contentType;\n }\n }\n\n void _setParams(RequestConfig config) {\n final params = config.input.params;\n if (params.isEmpty) return;\n\n String path = config.url.toString();\n for (var entry in params.entries) {\n path = path.replaceAll('{${entry.key}}', entry.value.toString());\n }\n config.url = Uri.parse(path);\n }\n\n void _setQuery(RequestConfig config) {\n final query = config.input.query;\n if (query.isEmpty) return;\n\n final uri = config.url;\n final queryParameters = Map<String, String>.from(uri.queryParameters);\n\n for (var entry in query.entries) {\n if (entry.value != null) {\n queryParameters[entry.key] = entry.value.toString();\n }\n }\n\n config.url = uri.replace(queryParameters: queryParameters);\n }\n\n Future<http.StreamedResponse> formdata(RequestConfig config) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n _setParams(modifiedConfig);\n _setQuery(modifiedConfig);\n final request = http.MultipartRequest(\n modifiedConfig.method,\n modifiedConfig.url,\n );\n _setHeaders(request, modifiedConfig);\n\n for (var entry in config.input.body.entries) {\n final key = entry.key;\n final value = entry.value;\n if (value is File) {\n final mimeType = mime.lookupMimeType(value.path);\n request.files.add(\n http.MultipartFile(\n key,\n value.openRead(),\n await value.length(),\n filename: value.uri.pathSegments.last,\n contentType: mimeType != null ? MediaType.parse(mimeType) : null,\n ),\n );\n } else {\n request.fields[key] = value.toString();\n }\n }\n\n return request.send();\n }\n\n Future<http.StreamedResponse> empty(RequestConfig config) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n _setParams(modifiedConfig);\n _setQuery(modifiedConfig);\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n _setHeaders(request, modifiedConfig);\n return request.send();\n }\n\n Future<http.StreamedResponse> json(RequestConfig config) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n _setParams(modifiedConfig);\n _setQuery(modifiedConfig);\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n _setHeaders(request, modifiedConfig, 'application/json');\n\n if ((config.input.body is Map || config.input.body is List)) {\n request.body = jsonEncode(config.input.body);\n } else if (config.input.body is String) {\n request.body = config.input.body;\n } else {\n throw ArgumentError(\n 'Unsupported body type: ${config.input.body.runtimeType}',\n );\n }\n\n return request.send();\n }\n\n Future<http.StreamedResponse> binary(RequestConfig config) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n _setParams(modifiedConfig);\n _setQuery(modifiedConfig);\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n _setHeaders(request, modifiedConfig, 'application/octet-stream');\n\n switch (config.input.body) {\n case List<int> bytes:\n request.bodyBytes = bytes;\n case Stream<List<int>> stream:\n request.bodyBytes = await stream.expand((x) => x).toList();\n case String body:\n request.body = body;\n case File file:\n request.bodyBytes = await file.readAsBytes();\n default:\n throw ArgumentError(\n 'Unsupported body type for binary request: ${config.input.body.runtimeType}',\n );\n }\n\n return request.send();\n }\n\n Future<http.StreamedResponse> urlencoded(RequestConfig config) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n _setParams(modifiedConfig);\n _setQuery(modifiedConfig);\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n _setHeaders(request, modifiedConfig, 'application/x-www-form-urlencoded');\n\n // Convert body to URL-encoded string\n final bodyMap = config.input.body;\n request.body = bodyMap.entries\n .map(\n (entry) =>\n '${Uri.encodeComponent(entry.key)}=${Uri.encodeComponent(entry.value.toString())}',\n )\n .join('&');\n\n return request.send();\n }\n}\n\nclass Receiver {\n final List<Interceptor> interceptors;\n Receiver(this.interceptors);\n\n dynamic _parse(http.Response response) {\n final contentTypeHeader = response.headers['content-type'];\n final parsed = parseContentType(contentTypeHeader);\n if (parsed.type.startsWith('application/json')) {\n return jsonDecode(response.body);\n } else if (parsed.type.startsWith('text/')) {\n return response.body;\n } else if (parsed.type == 'application/octet-stream') {\n return response.bodyBytes;\n } else {\n throw UnsupportedError('Unsupported content type: ${parsed.type}');\n }\n }\n\n Future<dynamic> json(http.StreamedResponse stream) async {\n if (stream.statusCode >= 200 && stream.statusCode < 300) {\n final response = await http.Response.fromStream(stream);\n return _parse(response);\n }\n throw _handleError(stream);\n }\n\n Future<String> text(http.StreamedResponse stream) async {\n if (stream.statusCode >= 200 && stream.statusCode < 300) {\n final response = await http.Response.fromStream(stream);\n return _parse(response);\n }\n throw _handleError(stream);\n }\n\n _handleError(http.StreamedResponse stream) {\n switch (stream.statusCode) {\n case 400:\n throw BadRequestError('');\n case 401:\n throw UnauthorizedError('');\n case 403:\n throw ForbiddenError('');\n case 404:\n throw NotFoundError('');\n case 500:\n throw InternalServerError('');\n case 402:\n throw PaymentRequiredError('');\n case 405:\n throw MethodNotAllowedError('');\n case 406:\n throw NotAcceptableError('');\n case 409:\n throw ConflictError('');\n case 410:\n throw GoneError('');\n case 422:\n throw UnprocessableEntityError('');\n case 429:\n throw TooManyRequestsError('');\n case 413:\n throw PayloadTooLargeError('');\n case 415:\n throw UnsupportedMediaTypeError('');\n case 501:\n throw NotImplementedError('');\n case 502:\n throw BadGatewayError('');\n case 503:\n throw ServiceUnavailableError('');\n case 504:\n throw GatewayTimeoutError('');\n default:\n throw UnknownApiError('', stream.statusCode);\n }\n }\n}\n\n({String type, Map<String, String> parameters}) parseContentType(\n String? contentTypeHeader,\n) {\n if (contentTypeHeader == null || contentTypeHeader.isEmpty) {\n return (type: '', parameters: {});\n }\n final parts = contentTypeHeader.split(';');\n final type = parts[0].trim();\n final parameters = <String, String>{};\n\n for (var i = 1; i < parts.length; i++) {\n final param = parts[i].split('=');\n if (param.length == 2) {\n parameters[param[0].trim()] = param[1].trim();\n }\n }\n\n return (type: type, parameters: parameters);\n}\n";
|
|
951
785
|
|
|
952
786
|
// packages/dart/src/lib/http/interceptors.txt
|
|
953
|
-
var interceptors_default = "abstract class Interceptor {\n RequestConfig before(RequestConfig config);\n void after();\n}\n\nclass BaseUrlInterceptor extends Interceptor {\n final String Function() getBaseUrl;\n BaseUrlInterceptor(this.getBaseUrl);\n\n @override\n RequestConfig before(RequestConfig config) {\n final baseUrl = getBaseUrl();\n if (config.url.scheme.isEmpty) {\n config.url = Uri.parse(baseUrl + config.url.toString());\n }\n return config;\n }\n\n @override\n void after() {\n //\n }\n}\n\nclass RequestConfig {\n final String method;\n Uri url;\n final Map<String, String> headers;\n RequestConfig({required this.method
|
|
787
|
+
var interceptors_default = "abstract class Interceptor {\n RequestConfig before(RequestConfig config);\n void after();\n}\n\nclass BaseUrlInterceptor extends Interceptor {\n final String Function() getBaseUrl;\n BaseUrlInterceptor(this.getBaseUrl);\n\n @override\n RequestConfig before(RequestConfig config) {\n final baseUrl = getBaseUrl();\n if (config.url.scheme.isEmpty) {\n config.url = Uri.parse(baseUrl + config.url.toString());\n }\n return config;\n }\n\n @override\n void after() {\n //\n }\n}\n\nclass LoggingInterceptor extends Interceptor {\n // ANSI color codes\n static const String _reset = '\\x1B[0m';\n static const String _green = '\\x1B[32m';\n static const String _yellow = '\\x1B[33m';\n static const String _blue = '\\x1B[34m';\n static const String _magenta = '\\x1B[35m';\n static const String _cyan = '\\x1B[36m';\n\n @override\n RequestConfig before(RequestConfig config) {\n print('${_cyan}[LOG] --- HTTP REQUEST ---$_reset');\n print('${_yellow}[LOG] Method: ${config.method.toUpperCase()}$_reset');\n print('${_green}[LOG] URL: ${config.url}$_reset');\n print('${_magenta}[ContentType] ${config.headers['content-type']}$_reset');\n if (config.headers.isNotEmpty) {\n print('${_blue}[LOG] Headers: ${config.headers}$_reset');\n } else {\n print('${_blue}[LOG] Headers: <none>$_reset');\n }\n print('${_cyan}[LOG] --------------$_reset');\n return config;\n }\n\n @override\n void after() {\n // Optionally log after the request\n }\n}\n\nclass RequestConfig {\n final String method;\n Uri url;\n final Map<String, String> headers;\n final RequestInput input;\n\n RequestConfig({\n required this.method,\n required this.url,\n required this.headers,\n this.input = const RequestInput.empty(),\n });\n}\n\nclass RequestInput {\n final Map<String, String?> headers;\n final Map<String, dynamic> query;\n final Map<String, dynamic> params;\n final dynamic body;\n RequestInput({\n this.headers = const {},\n this.query = const {},\n this.params = const {},\n required this.body,\n });\n\n const RequestInput.empty()\n : headers = const {},\n query = const {},\n params = const {},\n body = null;\n}\n";
|
|
954
788
|
|
|
955
789
|
// packages/dart/src/lib/http/responses.txt
|
|
956
790
|
var responses_default = "sealed class ApiError {\n final String message;\n final int? statusCode;\n final String status;\n const ApiError(this.message, {this.statusCode, this.status = ''});\n\n @override\n String toString() =>\n 'ApiError(status: $status, statusCode: $statusCode, message: $message)';\n}\n\nbase class BadRequestError extends ApiError {\n const BadRequestError(String message)\n : super(message, statusCode: 400, status: 'BadRequest');\n}\n\nbase class UnauthorizedError extends ApiError {\n const UnauthorizedError(String message)\n : super(message, statusCode: 401, status: 'Unauthorized');\n}\n\nbase class ForbiddenError extends ApiError {\n const ForbiddenError(String message)\n : super(message, statusCode: 403, status: 'Forbidden');\n}\n\nbase class NotFoundError extends ApiError {\n const NotFoundError(String message)\n : super(message, statusCode: 404, status: 'NotFound');\n}\n\nbase class InternalServerError extends ApiError {\n const InternalServerError(String message)\n : super(message, statusCode: 500, status: 'InternalServerError');\n}\n\nbase class UnknownApiError extends ApiError {\n const UnknownApiError(String message, int statusCode)\n : super(message, statusCode: statusCode, status: 'UnknownApiError');\n}\n\nbase class PaymentRequiredError extends ApiError {\n const PaymentRequiredError(String message)\n : super(message, statusCode: 402, status: 'PaymentRequired');\n}\n\nbase class MethodNotAllowedError extends ApiError {\n const MethodNotAllowedError(String message)\n : super(message, statusCode: 405, status: 'MethodNotAllowed');\n}\n\nbase class NotAcceptableError extends ApiError {\n const NotAcceptableError(String message)\n : super(message, statusCode: 406, status: 'NotAcceptable');\n}\n\nbase class ConflictError extends ApiError {\n const ConflictError(String message)\n : super(message, statusCode: 409, status: 'Conflict');\n}\n\nbase class GoneError extends ApiError {\n const GoneError(String message)\n : super(message, statusCode: 410, status: 'Gone');\n}\n\nbase class UnprocessableEntityError extends ApiError {\n const UnprocessableEntityError(String message)\n : super(message, statusCode: 422, status: 'UnprocessableEntity');\n}\n\nbase class TooManyRequestsError extends ApiError {\n const TooManyRequestsError(String message)\n : super(message, statusCode: 429, status: 'TooManyRequests');\n}\n\nbase class PayloadTooLargeError extends ApiError {\n const PayloadTooLargeError(String message)\n : super(message, statusCode: 413, status: 'PayloadTooLarge');\n}\n\nbase class UnsupportedMediaTypeError extends ApiError {\n const UnsupportedMediaTypeError(String message)\n : super(message, statusCode: 415, status: 'UnsupportedMediaType');\n}\n\nbase class NotImplementedError extends ApiError {\n const NotImplementedError(String message)\n : super(message, statusCode: 501, status: 'NotImplemented');\n}\n\nbase class BadGatewayError extends ApiError {\n const BadGatewayError(String message)\n : super(message, statusCode: 502, status: 'BadGateway');\n}\n\nbase class ServiceUnavailableError extends ApiError {\n const ServiceUnavailableError(String message)\n : super(message, statusCode: 503, status: 'ServiceUnavailable');\n}\n\nbase class GatewayTimeoutError extends ApiError {\n const GatewayTimeoutError(String message)\n : super(message, statusCode: 504, status: 'GatewayTimeout');\n}\n";
|
|
957
791
|
|
|
958
792
|
// packages/dart/src/lib/generate.ts
|
|
959
|
-
function
|
|
960
|
-
|
|
961
|
-
if (isRef3(schema))
|
|
962
|
-
continue;
|
|
963
|
-
if (!isEmpty2(schema.anyOf) && !isEmpty2(schema.oneOf)) {
|
|
964
|
-
delete schema.anyOf;
|
|
965
|
-
}
|
|
966
|
-
if (!isEmpty2(schema.allOf)) {
|
|
967
|
-
const schemas2 = schema.allOf;
|
|
968
|
-
const refs2 = schemas2.filter(isRef3);
|
|
969
|
-
const nonRefs = schemas2.filter(notRef2);
|
|
970
|
-
if (nonRefs.some((it) => it.type && it.type !== "object")) {
|
|
971
|
-
assert2(false, `allOf ${name} must be an object`);
|
|
972
|
-
}
|
|
973
|
-
const objectSchema = merge2(
|
|
974
|
-
{},
|
|
975
|
-
...nonRefs,
|
|
976
|
-
...refs2.map((ref) => followRef3(spec, ref.$ref))
|
|
977
|
-
);
|
|
978
|
-
delete objectSchema.allOf;
|
|
979
|
-
delete schema.allOf;
|
|
980
|
-
Object.assign(schema, objectSchema);
|
|
981
|
-
}
|
|
982
|
-
if (schema.type === "object") {
|
|
983
|
-
if (!isEmpty2(schema.oneOf)) {
|
|
984
|
-
for (const oneOfIdx in schema.oneOf) {
|
|
985
|
-
const oneOf = schema.oneOf[oneOfIdx];
|
|
986
|
-
if (isRef3(oneOf))
|
|
987
|
-
continue;
|
|
988
|
-
if (!isEmpty2(oneOf.required) && schema.properties) {
|
|
989
|
-
schema.oneOf[oneOfIdx] = schema.properties[oneOf.required[0]];
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
delete schema.type;
|
|
993
|
-
tuneSpec(spec, schemas, refs);
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
schema.properties ??= {};
|
|
997
|
-
for (const [propName, value] of Object.entries(schema.properties)) {
|
|
998
|
-
if (isRef3(value))
|
|
999
|
-
continue;
|
|
1000
|
-
const refName = pascalcase2(`${name} ${propName.replace("[]", "")}`);
|
|
1001
|
-
refs.push({ name: refName, value });
|
|
1002
|
-
schema.properties[propName] = {
|
|
1003
|
-
$ref: `#/components/schemas/${refName}`
|
|
1004
|
-
};
|
|
1005
|
-
const props = Object.fromEntries(
|
|
1006
|
-
Object.entries(value.properties ?? {}).map(([key, value2]) => {
|
|
1007
|
-
return [pascalcase2(`${refName} ${key}`), value2];
|
|
1008
|
-
})
|
|
1009
|
-
);
|
|
1010
|
-
tuneSpec(spec, props, refs);
|
|
1011
|
-
}
|
|
1012
|
-
} else if (schema.type === "array") {
|
|
1013
|
-
if (isRef3(schema.items))
|
|
1014
|
-
continue;
|
|
1015
|
-
const refName = name;
|
|
1016
|
-
refs.push({ name: refName, value: schema.items ?? {} });
|
|
1017
|
-
schema.items = {
|
|
1018
|
-
$ref: `#/components/schemas/${refName}`
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
async function generate(spec, settings) {
|
|
793
|
+
async function generate(openapi, settings) {
|
|
794
|
+
const spec = augmentSpec({ spec: openapi }, true);
|
|
1024
795
|
const clientName = settings.name || "Client";
|
|
1025
796
|
const output = join(settings.output, "lib");
|
|
797
|
+
const { writer, files: writtenFiles } = createWriterProxy(
|
|
798
|
+
settings.writer ?? writeFiles,
|
|
799
|
+
settings.output
|
|
800
|
+
);
|
|
801
|
+
settings.writer = writer;
|
|
802
|
+
settings.readFolder ??= async (folder) => {
|
|
803
|
+
const files = await readdir(folder, { withFileTypes: true });
|
|
804
|
+
return files.map((file) => ({
|
|
805
|
+
fileName: file.name,
|
|
806
|
+
filePath: join(file.parentPath, file.name),
|
|
807
|
+
isFolder: file.isDirectory()
|
|
808
|
+
}));
|
|
809
|
+
};
|
|
1026
810
|
const groups = {};
|
|
1027
|
-
spec
|
|
1028
|
-
spec.components.schemas ??= {};
|
|
1029
|
-
const inputs = {};
|
|
1030
|
-
const outputs = {};
|
|
1031
|
-
forEachOperation({ spec }, (entry, operation) => {
|
|
1032
|
-
operation.responses ??= {};
|
|
1033
|
-
spec.components ??= {};
|
|
1034
|
-
spec.components.schemas ??= {};
|
|
1035
|
-
for (const status in operation.responses) {
|
|
1036
|
-
if (!isSuccessStatusCode(status))
|
|
1037
|
-
continue;
|
|
1038
|
-
const response2 = operation.responses[status];
|
|
1039
|
-
if (!isEmpty2(response2.content)) {
|
|
1040
|
-
for (const [contentType, mediaType] of Object.entries(
|
|
1041
|
-
response2.content
|
|
1042
|
-
)) {
|
|
1043
|
-
if (parseJsonContentType(contentType)) {
|
|
1044
|
-
if (mediaType.schema && !isRef3(mediaType.schema)) {
|
|
1045
|
-
const outputName = pascalcase2(`${operation.operationId} output`);
|
|
1046
|
-
spec.components.schemas[outputName] = mediaType.schema;
|
|
1047
|
-
operation.responses[status].content ??= {};
|
|
1048
|
-
operation.responses[status].content[contentType].schema = {
|
|
1049
|
-
$ref: `#/components/schemas/${outputName}`
|
|
1050
|
-
};
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
811
|
+
forEachOperation(spec, (entry, operation) => {
|
|
1056
812
|
console.log(`Processing ${entry.method} ${entry.path}`);
|
|
1057
|
-
const group = groups[entry.groupName]
|
|
813
|
+
const group = groups[entry.groupName] ??= {
|
|
1058
814
|
methods: [],
|
|
1059
815
|
use: `final ${entry.groupName} = new ${pascalcase2(entry.groupName)}();`
|
|
1060
|
-
}
|
|
816
|
+
};
|
|
1061
817
|
const input = toInputs(spec, { entry, operation });
|
|
1062
|
-
Object.assign(inputs, input.inputs);
|
|
1063
818
|
const response = toOutput(spec, operation);
|
|
1064
|
-
if (response) {
|
|
1065
|
-
Object.assign(outputs, response.outputs);
|
|
1066
|
-
}
|
|
1067
819
|
group.methods.push(`
|
|
1068
|
-
Future<${response ? response.returnType : "http.StreamedResponse"}> ${
|
|
1069
|
-
${
|
|
820
|
+
Future<${response ? response.returnType : "http.StreamedResponse"}> ${camelcase2(operation.operationId)}(
|
|
821
|
+
${input.haveInput ? `${input.inputName} input` : ""}
|
|
1070
822
|
) async {
|
|
1071
823
|
final stream = await this.dispatcher.${input.contentType}(RequestConfig(
|
|
1072
824
|
method: '${entry.method}',
|
|
1073
825
|
url: Uri.parse('${entry.path}'),
|
|
1074
826
|
headers: {},
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
827
|
+
${input.haveInput ? "input: input.toRequest()" : ""}));
|
|
828
|
+
${response ? `${response.decode};` : "return stream;"}
|
|
829
|
+
}
|
|
830
|
+
`);
|
|
1079
831
|
});
|
|
1080
|
-
const
|
|
1081
|
-
tuneSpec(spec, spec.components.schemas, newRefs);
|
|
1082
|
-
for (const ref of newRefs) {
|
|
1083
|
-
spec.components.schemas[ref.name] = ref.value;
|
|
1084
|
-
}
|
|
1085
|
-
await writeFile(
|
|
1086
|
-
join(process.cwd(), "openai.json"),
|
|
1087
|
-
JSON.stringify(spec, null, 2)
|
|
1088
|
-
);
|
|
1089
|
-
const models = Object.entries(spec.components.schemas).reduce((acc, [name, schema]) => {
|
|
1090
|
-
const serializer = new DartSerializer(spec, (name2, content) => {
|
|
1091
|
-
acc[`models/${snakecase2(name2)}.dart`] = `import 'dart:io';import 'dart:typed_data'; import './index.dart';
|
|
1092
|
-
|
|
1093
|
-
${content}`;
|
|
1094
|
-
});
|
|
1095
|
-
serializer.handle(pascalcase2(name), schema);
|
|
1096
|
-
return acc;
|
|
1097
|
-
}, {});
|
|
832
|
+
const models = serializeModels(spec);
|
|
1098
833
|
const clazzez = Object.entries(groups).reduce(
|
|
1099
834
|
(acc, [name, { methods }]) => {
|
|
1100
835
|
return {
|
|
@@ -1128,14 +863,14 @@ import './http.dart';
|
|
|
1128
863
|
|
|
1129
864
|
class ${clientName} {
|
|
1130
865
|
final Options options;
|
|
1131
|
-
${Object.keys(groups).map((name) => `late final ${pascalcase2(name)}Client ${
|
|
866
|
+
${Object.keys(groups).map((name) => `late final ${pascalcase2(name)}Client ${camelcase2(name)};`).join("\n")}
|
|
1132
867
|
|
|
1133
868
|
${clientName}(this.options) {
|
|
1134
|
-
final interceptors = [BaseUrlInterceptor(() => this.options.baseUrl)];
|
|
869
|
+
final interceptors = [BaseUrlInterceptor(() => this.options.baseUrl), LoggingInterceptor()];
|
|
1135
870
|
final dispatcher = Dispatcher(interceptors);
|
|
1136
871
|
final receiver = Receiver(interceptors);
|
|
1137
872
|
${Object.keys(groups).map(
|
|
1138
|
-
(name) => `this.${
|
|
873
|
+
(name) => `this.${camelcase2(name)} = ${pascalcase2(name)}Client(dispatcher, receiver);`
|
|
1139
874
|
).join("\n")}
|
|
1140
875
|
|
|
1141
876
|
}
|
|
@@ -1154,39 +889,63 @@ class Options {
|
|
|
1154
889
|
}
|
|
1155
890
|
|
|
1156
891
|
`;
|
|
1157
|
-
await
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
"
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
892
|
+
await settings.writer(output, models);
|
|
893
|
+
const metadata = await readWriteMetadata(
|
|
894
|
+
settings.output,
|
|
895
|
+
Array.from(writtenFiles)
|
|
896
|
+
);
|
|
897
|
+
if (settings.cleanup !== false && writtenFiles.size > 0) {
|
|
898
|
+
await cleanFiles(metadata.content, settings.output, [
|
|
899
|
+
"/package.dart",
|
|
900
|
+
"/**/index.dart",
|
|
901
|
+
"pubspec.yaml",
|
|
902
|
+
"/metadata.json"
|
|
903
|
+
]);
|
|
904
|
+
}
|
|
905
|
+
await settings.writer(output, {
|
|
906
|
+
"models/index.dart": await getFolderExportsV2(
|
|
907
|
+
join(output, "models"),
|
|
908
|
+
settings.readFolder,
|
|
909
|
+
{
|
|
910
|
+
exportSyntax: "export",
|
|
911
|
+
extensions: "dart"
|
|
912
|
+
}
|
|
913
|
+
),
|
|
914
|
+
"inputs/index.dart": await getFolderExportsV2(
|
|
915
|
+
join(output, "inputs"),
|
|
916
|
+
settings.readFolder,
|
|
917
|
+
{
|
|
918
|
+
exportSyntax: "export",
|
|
919
|
+
extensions: "dart"
|
|
920
|
+
}
|
|
921
|
+
),
|
|
922
|
+
"outputs/index.dart": await getFolderExportsV2(
|
|
923
|
+
join(output, "outputs"),
|
|
924
|
+
settings.readFolder,
|
|
925
|
+
{
|
|
926
|
+
exportSyntax: "export",
|
|
927
|
+
extensions: "dart"
|
|
928
|
+
}
|
|
929
|
+
),
|
|
1175
930
|
"interceptors.dart": interceptors_default,
|
|
1176
931
|
"http.dart": dispatcher_default,
|
|
1177
932
|
"responses.dart": responses_default,
|
|
1178
933
|
...clazzez
|
|
1179
934
|
});
|
|
1180
|
-
await
|
|
1181
|
-
"package.dart": `${await getFolderExportsV2(
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
935
|
+
await settings.writer(output, {
|
|
936
|
+
"package.dart": `${await getFolderExportsV2(
|
|
937
|
+
join(output),
|
|
938
|
+
settings.readFolder,
|
|
939
|
+
{
|
|
940
|
+
exportSyntax: "export",
|
|
941
|
+
extensions: "dart",
|
|
942
|
+
ignore(dirent) {
|
|
943
|
+
return !dirent.isFolder && dirent.fileName === "package.dart";
|
|
944
|
+
}
|
|
1186
945
|
}
|
|
1187
|
-
|
|
946
|
+
)}${client}`
|
|
1188
947
|
});
|
|
1189
|
-
await
|
|
948
|
+
await settings.writer(settings.output, {
|
|
1190
949
|
"pubspec.yaml": {
|
|
1191
950
|
ignoreIfExists: true,
|
|
1192
951
|
content: yaml.stringify({
|
|
@@ -1202,85 +961,152 @@ class Options {
|
|
|
1202
961
|
})
|
|
1203
962
|
}
|
|
1204
963
|
});
|
|
964
|
+
await writeFile(
|
|
965
|
+
join(settings.output, "openapi.json"),
|
|
966
|
+
JSON.stringify(spec, null, 2)
|
|
967
|
+
);
|
|
1205
968
|
await settings.formatCode?.({
|
|
1206
969
|
output
|
|
1207
970
|
});
|
|
1208
971
|
}
|
|
1209
972
|
function toInputs(spec, { entry, operation }) {
|
|
1210
|
-
|
|
1211
|
-
const inputName = pascalcase2(`${operation.operationId} input`);
|
|
973
|
+
let inputName;
|
|
1212
974
|
let contentType = "empty";
|
|
1213
975
|
let encode = "";
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
976
|
+
let haveInput = false;
|
|
977
|
+
for (const type in operation.requestBody.content) {
|
|
978
|
+
const objectSchema = resolveRef2(
|
|
979
|
+
spec,
|
|
980
|
+
operation.requestBody.content[type].schema
|
|
981
|
+
);
|
|
982
|
+
const serializer = new DartSerializer(spec);
|
|
983
|
+
inputName = objectSchema["x-inputname"];
|
|
984
|
+
const serialized = serializer.handle(inputName, objectSchema, true, {
|
|
985
|
+
alias: isObjectSchema(objectSchema) ? void 0 : inputName,
|
|
986
|
+
requestize: objectSchema["x-requestbody"] === true,
|
|
987
|
+
noEmit: true
|
|
988
|
+
});
|
|
989
|
+
encode = serialized.encode;
|
|
990
|
+
const [mediaType, mediaSubType] = partContentType(type).type.split("/");
|
|
991
|
+
if (mediaSubType === "empty") {
|
|
992
|
+
contentType = "empty";
|
|
993
|
+
} else if (mediaSubType === "x-www-form-urlencoded") {
|
|
994
|
+
contentType = "urlencoded";
|
|
995
|
+
} else if (mediaSubType === "octet-stream") {
|
|
996
|
+
contentType = "binary";
|
|
997
|
+
} else if (mediaType === "application") {
|
|
998
|
+
contentType = parseJsonContentType(type);
|
|
999
|
+
} else if (mediaType === "multipart") {
|
|
1000
|
+
contentType = "formdata";
|
|
1001
|
+
} else {
|
|
1002
|
+
contentType = "binary";
|
|
1003
|
+
}
|
|
1004
|
+
if (!isEmpty2({ ...objectSchema.properties, ...objectSchema["x-properties"] })) {
|
|
1005
|
+
haveInput = true;
|
|
1239
1006
|
}
|
|
1240
1007
|
}
|
|
1241
|
-
|
|
1008
|
+
if (!inputName) {
|
|
1009
|
+
throw new Error(
|
|
1010
|
+
`No input name found for operation ${operation.operationId} in ${entry.path}`
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
return { inputName, contentType, encode, haveInput };
|
|
1242
1014
|
}
|
|
1243
1015
|
function toOutput(spec, operation) {
|
|
1244
|
-
const outputName = pascalcase2(`${operation.operationId} output`);
|
|
1245
1016
|
operation.responses ??= {};
|
|
1246
|
-
const outputs = {};
|
|
1247
1017
|
for (const status in operation.responses) {
|
|
1248
|
-
|
|
1018
|
+
if (!isSuccessStatusCode(status))
|
|
1019
|
+
continue;
|
|
1020
|
+
const response = operation.responses[status];
|
|
1021
|
+
const outputName = response["x-response-name"];
|
|
1022
|
+
if ((response.headers ?? {})["Transfer-Encoding"]) {
|
|
1023
|
+
return streamedOutput();
|
|
1024
|
+
}
|
|
1249
1025
|
for (const type in response.content) {
|
|
1250
|
-
const
|
|
1251
|
-
if (!schema) {
|
|
1252
|
-
console.warn(
|
|
1253
|
-
`Schema not found for ${type} in ${operation.operationId}`
|
|
1254
|
-
);
|
|
1255
|
-
continue;
|
|
1256
|
-
}
|
|
1257
|
-
const serializer = new DartSerializer(spec, (name, content) => {
|
|
1258
|
-
});
|
|
1026
|
+
const schema = response.content[type].schema;
|
|
1259
1027
|
if (isStreamingContentType(type)) {
|
|
1260
|
-
return
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
decode: `return stream`,
|
|
1265
|
-
returnType: `http.StreamedResponse`
|
|
1266
|
-
};
|
|
1028
|
+
return streamedOutput();
|
|
1029
|
+
}
|
|
1030
|
+
if (isSseContentType(type)) {
|
|
1031
|
+
continue;
|
|
1267
1032
|
}
|
|
1268
1033
|
if (parseJsonContentType(type)) {
|
|
1034
|
+
if (!schema) {
|
|
1035
|
+
return streamedOutput();
|
|
1036
|
+
}
|
|
1037
|
+
const serializer = new DartSerializer(spec);
|
|
1269
1038
|
const serialized = serializer.handle(outputName, schema, true, {
|
|
1270
1039
|
// alias: outputName,
|
|
1271
1040
|
noEmit: true
|
|
1272
1041
|
});
|
|
1273
1042
|
return {
|
|
1274
1043
|
type: "json",
|
|
1275
|
-
outputName,
|
|
1276
|
-
outputs,
|
|
1277
1044
|
decode: `final json = await this.receiver.json(stream); return ${serialized.fromJson}`,
|
|
1278
1045
|
returnType: serialized.use
|
|
1279
1046
|
};
|
|
1280
1047
|
}
|
|
1281
1048
|
}
|
|
1282
1049
|
}
|
|
1283
|
-
return
|
|
1050
|
+
return streamedOutput();
|
|
1051
|
+
}
|
|
1052
|
+
function streamedOutput() {
|
|
1053
|
+
return {
|
|
1054
|
+
type: "stream",
|
|
1055
|
+
decode: `return stream`,
|
|
1056
|
+
returnType: `http.StreamedResponse`
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function serializeModels(spec) {
|
|
1060
|
+
const serializer = new DartSerializer(spec);
|
|
1061
|
+
return Object.entries(spec.components.schemas).reduce(
|
|
1062
|
+
(acc, [name, schema]) => {
|
|
1063
|
+
serializer.onEmit((name2, content, schema2) => {
|
|
1064
|
+
const isResponseBody = schema2["x-responsebody"];
|
|
1065
|
+
const isRequestBody = schema2["x-requestbody"];
|
|
1066
|
+
const folder = isRequestBody ? "inputs" : isResponseBody ? "outputs" : "models";
|
|
1067
|
+
acc[join(folder, `${snakecase2(name2)}.dart`)] = [
|
|
1068
|
+
`import 'dart:io';`,
|
|
1069
|
+
`import 'dart:typed_data';`,
|
|
1070
|
+
// `import './index.dart';`,
|
|
1071
|
+
// `import '../interceptors.dart';`,
|
|
1072
|
+
`import '../package.dart';`,
|
|
1073
|
+
// folder === 'inputs' || folder === 'outputs'
|
|
1074
|
+
// ? `import '../models/index.dart';`
|
|
1075
|
+
// : `import '../inputs/index.dart';`,
|
|
1076
|
+
content
|
|
1077
|
+
].join("\n");
|
|
1078
|
+
});
|
|
1079
|
+
if (isRef2(schema)) {
|
|
1080
|
+
serializer.handle(pascalcase2(name), schema, true, {
|
|
1081
|
+
alias: isRef2(schema) ? name : void 0
|
|
1082
|
+
});
|
|
1083
|
+
return acc;
|
|
1084
|
+
}
|
|
1085
|
+
if (schema["x-requestbody"]) {
|
|
1086
|
+
serializer.handle(
|
|
1087
|
+
pascalcase2(name),
|
|
1088
|
+
schema.type !== "object" ? {
|
|
1089
|
+
type: "object",
|
|
1090
|
+
required: ["$body"],
|
|
1091
|
+
properties: {
|
|
1092
|
+
$body: {
|
|
1093
|
+
...schema,
|
|
1094
|
+
"x-special": true
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
} : schema,
|
|
1098
|
+
true,
|
|
1099
|
+
{
|
|
1100
|
+
requestize: true
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
} else {
|
|
1104
|
+
serializer.handle(pascalcase2(name), schema, true, {});
|
|
1105
|
+
}
|
|
1106
|
+
return acc;
|
|
1107
|
+
},
|
|
1108
|
+
{}
|
|
1109
|
+
);
|
|
1284
1110
|
}
|
|
1285
1111
|
export {
|
|
1286
1112
|
generate
|