@sdk-it/dart 0.17.0 → 0.19.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 CHANGED
@@ -2,20 +2,142 @@
2
2
  import { parse as partContentType } from "fast-content-type-parse";
3
3
  import { merge as merge2 } from "lodash-es";
4
4
  import assert2 from "node:assert";
5
- import { writeFile } from "node:fs/promises";
6
- import { join } from "node:path";
5
+ import { writeFile as writeFile2 } from "node:fs/promises";
6
+ import { join as join2 } from "node:path";
7
7
  import { camelcase as camelcase3 } from "stringcase";
8
8
  import yaml from "yaml";
9
+
10
+ // packages/core/dist/index.js
9
11
  import {
10
- followRef as followRef2,
11
- getFolderExportsV2,
12
- isEmpty as isEmpty2,
13
- isRef as isRef2,
14
- notRef as notRef2,
15
- pascalcase as pascalcase2,
16
- snakecase as snakecase2,
17
- writeFiles
18
- } from "@sdk-it/core";
12
+ pascalcase as _pascalcase,
13
+ snakecase as _snakecase,
14
+ spinalcase as _spinalcase
15
+ } from "stringcase";
16
+ import ts, { TypeFlags, symbolName } from "typescript";
17
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
18
+ import { dirname, extname, isAbsolute, join } from "node:path";
19
+ import debug from "debug";
20
+ import ts2 from "typescript";
21
+ import { get } from "lodash-es";
22
+ var deriveSymbol = Symbol.for("serialize");
23
+ var $types = Symbol.for("types");
24
+ async function exist(file) {
25
+ return stat(file).then(() => true).catch(() => false);
26
+ }
27
+ async function writeFiles(dir, contents) {
28
+ await Promise.all(
29
+ Object.entries(contents).map(async ([file, content]) => {
30
+ if (content === null) {
31
+ return;
32
+ }
33
+ const filePath = isAbsolute(file) ? file : join(dir, file);
34
+ await mkdir(dirname(filePath), { recursive: true });
35
+ if (typeof content === "string") {
36
+ await writeFile(filePath, content, "utf-8");
37
+ } else {
38
+ if (content.ignoreIfExists) {
39
+ if (!await exist(filePath)) {
40
+ await writeFile(filePath, content.content, "utf-8");
41
+ }
42
+ } else {
43
+ await writeFile(filePath, content.content, "utf-8");
44
+ }
45
+ }
46
+ })
47
+ );
48
+ }
49
+ async function getFolderExportsV2(folder, options = {
50
+ extensions: "ts",
51
+ ignore: () => false,
52
+ includeExtension: true,
53
+ exportSyntax: "export * from "
54
+ }) {
55
+ options.includeExtension ??= true;
56
+ if (!await exist(folder)) {
57
+ return "";
58
+ }
59
+ const files = await readdir(folder, { withFileTypes: true });
60
+ const exports = [];
61
+ for (const file of files) {
62
+ if (options.ignore?.(file)) {
63
+ continue;
64
+ }
65
+ if (file.isDirectory()) {
66
+ if (await exist(
67
+ `${file.parentPath}/${file.name}/index.${options.extensions}`
68
+ )) {
69
+ exports.push(
70
+ `${options.exportSyntax} './${file.name}/index${options.includeExtension ? `.${options.extensions}` : ""}';`
71
+ );
72
+ }
73
+ } else if (file.name !== `index.${options.extensions}` && options.extensions.includes(getExt(file.name))) {
74
+ exports.push(
75
+ `${options.exportSyntax} './${options.includeExtension ? file.name : file.name.replace(extname(file.name), "")}';`
76
+ );
77
+ }
78
+ }
79
+ return exports.join("\n");
80
+ }
81
+ var getExt = (fileName) => {
82
+ if (!fileName) {
83
+ return "";
84
+ }
85
+ const lastDot = fileName.lastIndexOf(".");
86
+ if (lastDot === -1) {
87
+ return "";
88
+ }
89
+ const ext = fileName.slice(lastDot + 1).split("/").filter(Boolean).join("");
90
+ if (ext === fileName) {
91
+ return "";
92
+ }
93
+ return ext || "txt";
94
+ };
95
+ var logger = debug("january:client");
96
+ function isRef(obj) {
97
+ return obj && "$ref" in obj;
98
+ }
99
+ function notRef(obj) {
100
+ return !isRef(obj);
101
+ }
102
+ function cleanRef(ref) {
103
+ return ref.replace(/^#\//, "");
104
+ }
105
+ function parseRef(ref) {
106
+ const parts = ref.split("/");
107
+ const [model] = parts.splice(-1);
108
+ const [namespace] = parts.splice(-1);
109
+ return {
110
+ model,
111
+ namespace,
112
+ path: cleanRef(parts.join("/"))
113
+ };
114
+ }
115
+ function followRef(spec, ref) {
116
+ const pathParts = cleanRef(ref).split("/");
117
+ const entry = get(spec, pathParts);
118
+ if (entry && "$ref" in entry) {
119
+ return followRef(spec, entry.$ref);
120
+ }
121
+ return entry;
122
+ }
123
+ function isEmpty(value) {
124
+ if (value === null || value === void 0 || value === "") {
125
+ return true;
126
+ }
127
+ if (Array.isArray(value) && value.length === 0) {
128
+ return true;
129
+ }
130
+ if (typeof value === "object" && Object.keys(value).length === 0) {
131
+ return true;
132
+ }
133
+ return false;
134
+ }
135
+ function pascalcase(value) {
136
+ return _pascalcase(value.split("/").join(" "));
137
+ }
138
+ function snakecase(value) {
139
+ return _snakecase(value.split("/").join(" "));
140
+ }
19
141
 
20
142
  // packages/spec/dist/lib/loaders/local-loader.js
21
143
  import { parse } from "yaml";
@@ -312,16 +434,7 @@ function isSuccessStatusCode(statusCode) {
312
434
  // packages/dart/src/lib/dart-emitter.ts
313
435
  import { merge } from "lodash-es";
314
436
  import assert from "node:assert";
315
- import { camelcase as camelcase2, snakecase } from "stringcase";
316
- import {
317
- cleanRef,
318
- followRef,
319
- isEmpty,
320
- isRef,
321
- notRef,
322
- parseRef,
323
- pascalcase
324
- } from "@sdk-it/core";
437
+ import { camelcase as camelcase2, snakecase as snakecase2 } from "stringcase";
325
438
  var formatName = (it) => {
326
439
  const startsWithDigitPattern = /^-?\d/;
327
440
  if (typeof it === "number") {
@@ -349,9 +462,9 @@ var formatName = (it) => {
349
462
  if (nameToFormat.endsWith("]")) {
350
463
  nameToFormat = nameToFormat.slice(0, -1);
351
464
  }
352
- return snakecase(nameToFormat);
465
+ return snakecase2(nameToFormat);
353
466
  }
354
- return snakecase(String(it));
467
+ return snakecase2(String(it));
355
468
  };
356
469
  var DartSerializer = class {
357
470
  #spec;
@@ -454,12 +567,12 @@ var DartSerializer = class {
454
567
  if (required) {
455
568
  matches.push(`(
456
569
  json.containsKey('${camelcase2(propName)}')
457
- ? ${nullable2 ? `json['${propName}'] == null` : `json['${propName}'] != null`} && ${typeStr.matches}
570
+ ? ${nullable2 ? `json['${propName}'] == null` : `json['${propName}'] != null`} ${typeStr.matches ? `&& ${typeStr.matches}` : ""}
458
571
  : false)`);
459
572
  } else {
460
573
  matches.push(`(
461
574
  json.containsKey('${camelcase2(propName)}')
462
- ? ${nullable2 ? `json['${propName}'] == null` : `json['${propName}'] != null`} || ${typeStr.matches}
575
+ ? ${nullable2 ? `json['${propName}'] == null` : `json['${propName}'] != null`} ${typeStr.matches ? `|| ${typeStr.matches}` : ""}
463
576
  : true)`);
464
577
  }
465
578
  }
@@ -496,18 +609,17 @@ return ${matches.join(" && ")};
496
609
  return required ? `this.${camelcase2(accces)}.toJson()` : `this.${camelcase2(accces)} != null ? this.${camelcase2(accces)}!.toJson() : null`;
497
610
  }
498
611
  #array(className, schema, required = false, context) {
499
- let serialized;
500
612
  if (!schema.items) {
501
- serialized = {
613
+ return {
502
614
  content: "",
503
615
  use: "List<dynamic>",
504
616
  toJson: "",
505
617
  fromJson: `List<dynamic>.from(${context.name ? `json['${context.name}']` : `json`})})`,
506
618
  matches: ""
507
619
  };
508
- } else {
509
- const itemsType = this.handle(className, schema.items, true, context);
510
- const fromJson = required ? context.name ? `(json['${context.name}'] as List<${itemsType.simple ? itemsType.use : "dynamic"}>)
620
+ }
621
+ const itemsType = this.handle(className, schema.items, true, context);
622
+ const fromJson = required ? context.name ? `(json['${context.name}'] as List<${itemsType.simple ? itemsType.use : "dynamic"}>)
511
623
  .map((it) => ${itemsType.simple ? "it" : `${itemsType.use}.fromJson(it)`})
512
624
  .toList()` : `(json as List<${itemsType.simple ? itemsType.use : "dynamic"}>)
513
625
  .map((it) => ${itemsType.simple ? "it" : `${itemsType.use}.fromJson(it)`})
@@ -520,16 +632,14 @@ return ${matches.join(" && ")};
520
632
  .map((it) => ${itemsType.simple ? "it" : `${itemsType.use}.fromJson(it)`})
521
633
  .toList()
522
634
  : null`;
523
- serialized = {
524
- encode: `input.map((it) => ${itemsType.simple ? "it" : `it.toJson()`}).toList()`,
525
- content: "",
526
- use: `List<${itemsType.use}>`,
527
- fromJson,
528
- toJson: `${context.required ? `this.${camelcase2(context.name)}${itemsType.simple ? "" : ".map((it) => it.toJson()).toList()"}` : `this.${camelcase2(context.name)}!= null? this.${camelcase2(context.name)}${itemsType.simple ? "" : "!.map((it) => it.toJson()).toList()"} : null`}`,
529
- matches: `json['${camelcase2(context.name)}'].every((it) => ${itemsType.matches})`
530
- };
531
- }
532
- return serialized;
635
+ return {
636
+ encode: `input.map((it) => ${itemsType.simple ? "it" : `it.toJson()`}).toList()`,
637
+ content: "",
638
+ use: `List<${itemsType.use}>`,
639
+ fromJson,
640
+ toJson: `${context.required ? `this.${camelcase2(context.name)}${itemsType.simple ? "" : ".map((it) => it.toJson()).toList()"}` : `this.${camelcase2(context.name)}!= null? this.${camelcase2(context.name)}${itemsType.simple ? "" : "!.map((it) => it.toJson()).toList()"} : null`}`,
641
+ matches: `json['${camelcase2(context.name)}'].every((it) => ${itemsType.matches})`
642
+ };
533
643
  }
534
644
  /**
535
645
  * Convert a basic type to Dart
@@ -564,6 +674,7 @@ return ${matches.join(" && ")};
564
674
  return {
565
675
  content: "",
566
676
  use: "dynamic",
677
+ nullable: false,
567
678
  toJson: `${camelcase2(context.name)}`,
568
679
  fromJson: `json['${context.name}']`
569
680
  };
@@ -603,6 +714,7 @@ return ${matches.join(" && ")};
603
714
  if (schemas.length === 0) {
604
715
  return {
605
716
  content: "",
717
+ nullable: false,
606
718
  use: "dynamic",
607
719
  toJson: `${camelcase2(context.name)}`,
608
720
  fromJson: `json['${context.name}']`
@@ -640,6 +752,7 @@ return ${matches.join(" && ")};
640
752
  if (schemas.length === 0) {
641
753
  return {
642
754
  content: "",
755
+ nullable: false,
643
756
  use: "dynamic",
644
757
  toJson: `${camelcase2(context.name)}`,
645
758
  fromJson: `json['${context.name}']`
@@ -906,12 +1019,12 @@ return false;
906
1019
  if (schema.allOf && Array.isArray(schema.allOf)) {
907
1020
  return this.#allOf(className, schema.allOf, context);
908
1021
  }
909
- if (schema.anyOf && Array.isArray(schema.anyOf)) {
910
- return this.#anyOf(className, schema.anyOf, context);
911
- }
912
1022
  if (schema.oneOf && Array.isArray(schema.oneOf)) {
913
1023
  return this.#oneOf(className, schema.oneOf, context);
914
1024
  }
1025
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
1026
+ return this.#anyOf(className, schema.anyOf, context);
1027
+ }
915
1028
  if (schema.enum && Array.isArray(schema.enum)) {
916
1029
  return this.#enum(className, schema, context);
917
1030
  }
@@ -935,7 +1048,10 @@ return false;
935
1048
  content: "",
936
1049
  use: "dynamic",
937
1050
  toJson: `${camelcase2(context.name)}`,
938
- fromJson: `json['${context.name}']`
1051
+ fromJson: `json['${context.name}']`,
1052
+ nullable: false,
1053
+ matches: ""
1054
+ // keep it empty as 'type is dynamic' is always true
939
1055
  };
940
1056
  }
941
1057
  return this.#primitive(
@@ -965,39 +1081,45 @@ function isObjectSchema(schema) {
965
1081
  }
966
1082
 
967
1083
  // packages/dart/src/lib/http/dispatcher.txt
968
- var dispatcher_default = "import 'package:mime/mime.dart' as mime;\nimport 'dart:convert';\nimport 'dart:io';\n\nimport './interceptors.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:http_parser/http_parser.dart';\n\nclass Dispatcher {\n final List<Interceptor> interceptors;\n\n Dispatcher(this.interceptors);\n\n Future<http.StreamedResponse> multipart(\n RequestConfig config,\n Map<String, dynamic> body,\n ) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.MultipartRequest(\n modifiedConfig.method,\n modifiedConfig.url,\n );\n request.headers.addAll(modifiedConfig.headers);\n for (var entry in 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 final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n return request.send();\n }\n\n Future<http.StreamedResponse> json(RequestConfig config, dynamic body) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n\n if ((body is Map || body is List)) {\n request.headers['Content-Type'] = 'application/json';\n request.body = jsonEncode(body);\n } else if (body is String) {\n request.body = body;\n } else {\n throw ArgumentError('Unsupported body type: ${body.runtimeType}');\n }\n\n return request.send();\n }\n}\n";
1084
+ 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 Future<http.StreamedResponse> multipart(\n RequestConfig config,\n Map<String, dynamic> body,\n ) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.MultipartRequest(\n modifiedConfig.method,\n modifiedConfig.url,\n );\n request.headers.addAll(modifiedConfig.headers);\n for (var entry in 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 final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n return request.send();\n }\n\n Future<http.StreamedResponse> json(RequestConfig config, dynamic body) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n\n request.headers['Content-Type'] = 'application/json';\n if ((body is Map || body is List)) {\n request.body = jsonEncode(body);\n } else if (body is String) {\n request.body = body;\n } else {\n throw ArgumentError('Unsupported body type: ${body.runtimeType}');\n }\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 == 'application/json') {\n return jsonDecode(response.body);\n } else if (parsed.type == 'text/plain') {\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 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 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 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";
969
1085
 
970
1086
  // packages/dart/src/lib/http/interceptors.txt
971
1087
  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, required this.url, required this.headers});\n}\n";
972
1088
 
1089
+ // packages/dart/src/lib/http/responses.txt
1090
+ 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";
1091
+
973
1092
  // packages/dart/src/lib/generate.ts
974
1093
  function tuneSpec(spec, schemas, refs) {
975
1094
  for (const [name, schema] of Object.entries(schemas)) {
976
- if (isRef2(schema))
1095
+ if (isRef(schema))
977
1096
  continue;
978
- if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length) {
1097
+ if (!isEmpty(schema.anyOf) && !isEmpty(schema.oneOf)) {
1098
+ delete schema.anyOf;
1099
+ }
1100
+ if (!isEmpty(schema.allOf)) {
979
1101
  const schemas2 = schema.allOf;
980
- const refs2 = schemas2.filter(isRef2);
981
- const nonRefs = schemas2.filter(notRef2);
1102
+ const refs2 = schemas2.filter(isRef);
1103
+ const nonRefs = schemas2.filter(notRef);
982
1104
  if (nonRefs.some((it) => it.type && it.type !== "object")) {
983
1105
  assert2(false, `allOf ${name} must be an object`);
984
1106
  }
985
1107
  const objectSchema = merge2(
986
1108
  {},
987
1109
  ...nonRefs,
988
- ...refs2.map((ref) => followRef2(spec, ref.$ref))
1110
+ ...refs2.map((ref) => followRef(spec, ref.$ref))
989
1111
  );
990
1112
  delete objectSchema.allOf;
991
1113
  delete schema.allOf;
992
1114
  Object.assign(schema, objectSchema);
993
1115
  }
994
1116
  if (schema.type === "object") {
995
- if (!isEmpty2(schema.oneOf)) {
1117
+ if (!isEmpty(schema.oneOf)) {
996
1118
  for (const oneOfIdx in schema.oneOf) {
997
1119
  const oneOf = schema.oneOf[oneOfIdx];
998
- if (isRef2(oneOf))
1120
+ if (isRef(oneOf))
999
1121
  continue;
1000
- if (!isEmpty2(oneOf.required) && schema.properties) {
1122
+ if (!isEmpty(oneOf.required) && schema.properties) {
1001
1123
  schema.oneOf[oneOfIdx] = schema.properties[oneOf.required[0]];
1002
1124
  }
1003
1125
  }
@@ -1007,22 +1129,22 @@ function tuneSpec(spec, schemas, refs) {
1007
1129
  }
1008
1130
  schema.properties ??= {};
1009
1131
  for (const [propName, value] of Object.entries(schema.properties)) {
1010
- if (isRef2(value))
1132
+ if (isRef(value))
1011
1133
  continue;
1012
- const refName = pascalcase2(`${name} ${propName.replace("[]", "")}`);
1134
+ const refName = pascalcase(`${name} ${propName.replace("[]", "")}`);
1013
1135
  refs.push({ name: refName, value });
1014
1136
  schema.properties[propName] = {
1015
1137
  $ref: `#/components/schemas/${refName}`
1016
1138
  };
1017
1139
  const props = Object.fromEntries(
1018
1140
  Object.entries(value.properties ?? {}).map(([key, value2]) => {
1019
- return [pascalcase2(`${refName} ${key}`), value2];
1141
+ return [pascalcase(`${refName} ${key}`), value2];
1020
1142
  })
1021
1143
  );
1022
1144
  tuneSpec(spec, props, refs);
1023
1145
  }
1024
1146
  } else if (schema.type === "array") {
1025
- if (isRef2(schema.items))
1147
+ if (isRef(schema.items))
1026
1148
  continue;
1027
1149
  const refName = name;
1028
1150
  refs.push({ name: refName, value: schema.items ?? {} });
@@ -1034,7 +1156,7 @@ function tuneSpec(spec, schemas, refs) {
1034
1156
  }
1035
1157
  async function generate(spec, settings) {
1036
1158
  const clientName = settings.name || "Client";
1037
- const output = join(settings.output, "lib");
1159
+ const output = join2(settings.output, "lib");
1038
1160
  const groups = {};
1039
1161
  spec.components ??= {};
1040
1162
  spec.components.schemas ??= {};
@@ -1042,19 +1164,19 @@ async function generate(spec, settings) {
1042
1164
  const outputs = {};
1043
1165
  forEachOperation({ spec }, (entry, operation) => {
1044
1166
  operation.responses ??= {};
1167
+ spec.components ??= {};
1168
+ spec.components.schemas ??= {};
1045
1169
  for (const status in operation.responses) {
1046
1170
  if (!isSuccessStatusCode(status))
1047
1171
  continue;
1048
- const response2 = isRef2(operation.responses[status]) ? followRef2(spec, operation.responses[status].$ref) : operation.responses[status];
1049
- if (response2.content && Object.keys(response2.content).length) {
1172
+ const response2 = isRef(operation.responses[status]) ? followRef(spec, operation.responses[status].$ref) : operation.responses[status];
1173
+ if (!isEmpty(response2.content)) {
1050
1174
  for (const [contentType, mediaType] of Object.entries(
1051
1175
  response2.content
1052
1176
  )) {
1053
1177
  if (parseJsonContentType(contentType)) {
1054
- if (mediaType.schema && !isRef2(mediaType.schema)) {
1055
- spec.components ??= {};
1056
- spec.components.schemas ??= {};
1057
- const outputName = pascalcase2(`${operation.operationId} output`);
1178
+ if (mediaType.schema && !isRef(mediaType.schema)) {
1179
+ const outputName = pascalcase(`${operation.operationId} output`);
1058
1180
  spec.components.schemas[outputName] = mediaType.schema;
1059
1181
  operation.responses[status].content[contentType].schema = {
1060
1182
  $ref: `#/components/schemas/${outputName}`
@@ -1067,7 +1189,7 @@ async function generate(spec, settings) {
1067
1189
  console.log(`Processing ${entry.method} ${entry.path}`);
1068
1190
  const group = groups[entry.groupName] ?? (groups[entry.groupName] = {
1069
1191
  methods: [],
1070
- use: `final ${entry.groupName} = new ${pascalcase2(entry.groupName)}();`
1192
+ use: `final ${entry.groupName} = new ${pascalcase(entry.groupName)}();`
1071
1193
  });
1072
1194
  const input = toInputs(spec, { entry, operation });
1073
1195
  Object.assign(inputs, input.inputs);
@@ -1077,7 +1199,7 @@ async function generate(spec, settings) {
1077
1199
  }
1078
1200
  group.methods.push(`
1079
1201
  Future<${response ? response.returnType : "http.StreamedResponse"}> ${camelcase3(operation.operationId)}(
1080
- ${isEmpty2(operation.requestBody) ? "" : `${input.inputName} input`}
1202
+ ${isEmpty(operation.requestBody) ? "" : `${input.inputName} input`}
1081
1203
  ) async {
1082
1204
  final stream = await this.dispatcher.${input.contentType}(RequestConfig(
1083
1205
  method: '${entry.method}',
@@ -1093,24 +1215,24 @@ async function generate(spec, settings) {
1093
1215
  for (const ref of newRefs) {
1094
1216
  spec.components.schemas[ref.name] = ref.value;
1095
1217
  }
1096
- await writeFile(
1097
- join(process.cwd(), "openai.json"),
1218
+ await writeFile2(
1219
+ join2(process.cwd(), "openai.json"),
1098
1220
  JSON.stringify(spec, null, 2)
1099
1221
  );
1100
1222
  const models = Object.entries(spec.components.schemas).reduce((acc, [name, schema]) => {
1101
1223
  const serializer = new DartSerializer(spec, (name2, content) => {
1102
- acc[`models/${snakecase2(name2)}.dart`] = `import 'dart:io';import 'dart:typed_data'; import './index.dart';
1224
+ acc[`models/${snakecase(name2)}.dart`] = `import 'dart:io';import 'dart:typed_data'; import './index.dart';
1103
1225
 
1104
1226
  ${content}`;
1105
1227
  });
1106
- serializer.handle(pascalcase2(name), schema);
1228
+ serializer.handle(pascalcase(name), schema);
1107
1229
  return acc;
1108
1230
  }, {});
1109
1231
  const clazzez = Object.entries(groups).reduce(
1110
1232
  (acc, [name, { methods }]) => {
1111
1233
  return {
1112
1234
  ...acc,
1113
- [`api/${snakecase2(name)}.dart`]: `
1235
+ [`api/${snakecase(name)}.dart`]: `
1114
1236
  import 'dart:convert';
1115
1237
 
1116
1238
  import 'package:http/http.dart' as http;
@@ -1121,9 +1243,10 @@ import '../outputs/index.dart';
1121
1243
  import '../models/index.dart';
1122
1244
  import '../http.dart';
1123
1245
 
1124
- class ${pascalcase2(name)}Client {
1246
+ class ${pascalcase(name)}Client {
1125
1247
  final Dispatcher dispatcher;
1126
- ${pascalcase2(name)}Client(this.dispatcher);
1248
+ final Receiver receiver;
1249
+ ${pascalcase(name)}Client(this.dispatcher, this.receiver);
1127
1250
  ${methods.join("\n")}
1128
1251
  }
1129
1252
  `
@@ -1132,19 +1255,20 @@ import '../http.dart';
1132
1255
  {}
1133
1256
  );
1134
1257
  const client = `
1135
- ${Object.keys(groups).map((name) => `import './api/${snakecase2(name)}.dart';`).join("\n")}
1258
+ ${Object.keys(groups).map((name) => `import './api/${snakecase(name)}.dart';`).join("\n")}
1136
1259
  import './interceptors.dart';
1137
1260
  import './http.dart';
1138
1261
 
1139
1262
  class ${clientName} {
1140
1263
  final Options options;
1141
- ${Object.keys(groups).map((name) => `late final ${pascalcase2(name)}Client ${camelcase3(name)};`).join("\n")}
1264
+ ${Object.keys(groups).map((name) => `late final ${pascalcase(name)}Client ${camelcase3(name)};`).join("\n")}
1142
1265
 
1143
1266
  ${clientName}(this.options) {
1144
- final interceptors = [new BaseUrlInterceptor(() => this.options.baseUrl)];
1145
- final dispatcher = new Dispatcher(interceptors);
1267
+ final interceptors = [BaseUrlInterceptor(() => this.options.baseUrl)];
1268
+ final dispatcher = Dispatcher(interceptors);
1269
+ final receiver = Receiver(interceptors);
1146
1270
  ${Object.keys(groups).map(
1147
- (name) => `this.${camelcase3(name)} = new ${pascalcase2(name)}Client(dispatcher);`
1271
+ (name) => `this.${camelcase3(name)} = ${pascalcase(name)}Client(dispatcher, receiver);`
1148
1272
  ).join("\n")}
1149
1273
 
1150
1274
  }
@@ -1169,24 +1293,25 @@ class Options {
1169
1293
  ...outputs
1170
1294
  });
1171
1295
  await writeFiles(output, {
1172
- "models/index.dart": await getFolderExportsV2(join(output, "models"), {
1296
+ "models/index.dart": await getFolderExportsV2(join2(output, "models"), {
1173
1297
  exportSyntax: "export",
1174
1298
  extensions: "dart"
1175
1299
  }),
1176
- "inputs/index.dart": await getFolderExportsV2(join(output, "inputs"), {
1300
+ "inputs/index.dart": await getFolderExportsV2(join2(output, "inputs"), {
1177
1301
  exportSyntax: "export",
1178
1302
  extensions: "dart"
1179
1303
  }),
1180
- "outputs/index.dart": await getFolderExportsV2(join(output, "outputs"), {
1304
+ "outputs/index.dart": await getFolderExportsV2(join2(output, "outputs"), {
1181
1305
  exportSyntax: "export",
1182
1306
  extensions: "dart"
1183
1307
  }),
1184
1308
  "interceptors.dart": interceptors_default,
1185
1309
  "http.dart": dispatcher_default,
1310
+ "responses.dart": responses_default,
1186
1311
  ...clazzez
1187
1312
  });
1188
1313
  await writeFiles(output, {
1189
- "package.dart": `${await getFolderExportsV2(join(output), {
1314
+ "package.dart": `${await getFolderExportsV2(join2(output), {
1190
1315
  exportSyntax: "export",
1191
1316
  extensions: "dart",
1192
1317
  ignore(dirent) {
@@ -1198,7 +1323,7 @@ class Options {
1198
1323
  "pubspec.yaml": {
1199
1324
  ignoreIfExists: true,
1200
1325
  content: yaml.stringify({
1201
- name: settings.name ? `${snakecase2(clientName.toLowerCase())}_sdk` : "sdk",
1326
+ name: settings.name ? `${snakecase(clientName.toLowerCase())}_sdk` : "sdk",
1202
1327
  version: "0.0.1",
1203
1328
  environment: {
1204
1329
  sdk: "^3.7.2"
@@ -1216,13 +1341,13 @@ class Options {
1216
1341
  }
1217
1342
  function toInputs(spec, { entry, operation }) {
1218
1343
  const inputs = {};
1219
- const inputName = pascalcase2(`${operation.operationId} input`);
1344
+ const inputName = pascalcase(`${operation.operationId} input`);
1220
1345
  let contentType = "empty";
1221
1346
  let encode = "";
1222
- if (!isEmpty2(operation.requestBody)) {
1223
- const requestBody = isRef2(operation.requestBody) ? followRef2(spec, operation.requestBody.$ref) : operation.requestBody;
1347
+ if (!isEmpty(operation.requestBody)) {
1348
+ const requestBody = isRef(operation.requestBody) ? followRef(spec, operation.requestBody.$ref) : operation.requestBody;
1224
1349
  for (const type in requestBody.content) {
1225
- const ctSchema = isRef2(requestBody.content[type].schema) ? followRef2(spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
1350
+ const ctSchema = isRef(requestBody.content[type].schema) ? followRef(spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
1226
1351
  if (!ctSchema) {
1227
1352
  console.warn(
1228
1353
  `Schema not found for ${type} in ${entry.method} ${entry.path}`
@@ -1230,7 +1355,7 @@ function toInputs(spec, { entry, operation }) {
1230
1355
  continue;
1231
1356
  }
1232
1357
  const serializer = new DartSerializer(spec, (name, content) => {
1233
- inputs[join(`inputs/${name}.dart`)] = `import 'dart:io';import 'dart:typed_data';import '../models/index.dart'; import './index.dart';
1358
+ inputs[join2(`inputs/${name}.dart`)] = `import 'dart:io';import 'dart:typed_data';import '../models/index.dart'; import './index.dart';
1234
1359
 
1235
1360
  ${content}`;
1236
1361
  });
@@ -1238,11 +1363,6 @@ ${content}`;
1238
1363
  alias: isObjectSchema(ctSchema) ? void 0 : inputName
1239
1364
  });
1240
1365
  encode = serialized.encode;
1241
- if (contentType) {
1242
- console.warn(
1243
- `${entry.method} ${entry.path} have more than one content type`
1244
- );
1245
- }
1246
1366
  const [mediaType, mediaSubType] = partContentType(type).type.split("/");
1247
1367
  if (mediaType === "application") {
1248
1368
  contentType = parseJsonContentType(type);
@@ -1254,11 +1374,11 @@ ${content}`;
1254
1374
  return { inputs, inputName, contentType, encode };
1255
1375
  }
1256
1376
  function toOutput(spec, operation) {
1257
- const outputName = pascalcase2(`${operation.operationId} output`);
1377
+ const outputName = pascalcase(`${operation.operationId} output`);
1258
1378
  operation.responses ??= {};
1259
1379
  const outputs = {};
1260
1380
  for (const status in operation.responses) {
1261
- const response = isRef2(operation.responses[status]) ? followRef2(spec, operation.responses[status].$ref) : operation.responses[status];
1381
+ const response = isRef(operation.responses[status]) ? followRef(spec, operation.responses[status].$ref) : operation.responses[status];
1262
1382
  for (const type in response.content) {
1263
1383
  const { schema } = response.content[type];
1264
1384
  if (!schema) {
@@ -1287,7 +1407,7 @@ function toOutput(spec, operation) {
1287
1407
  type: "json",
1288
1408
  outputName,
1289
1409
  outputs,
1290
- decode: `final response = await http.Response.fromStream(stream);final dynamic json = jsonDecode(response.body); return ${serialized.fromJson}`,
1410
+ decode: `final json = await this.receiver.json(stream); return ${serialized.fromJson}`,
1291
1411
  returnType: serialized.use
1292
1412
  };
1293
1413
  }