@arrirpc/codegen-dart 0.49.1 → 0.51.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.cjs CHANGED
@@ -1,1032 +1,1232 @@
1
1
  'use strict';
2
2
 
3
+ const node_child_process = require('node:child_process');
4
+ const fs = require('node:fs/promises');
3
5
  const codegenUtils = require('@arrirpc/codegen-utils');
4
- const schema = require('@arrirpc/schema');
5
- const child_process = require('child_process');
6
- const fs = require('fs');
6
+ const path = require('pathe');
7
7
 
8
- var __defProp = Object.defineProperty;
9
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
- var __publicField = (obj, key, value) => {
11
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
12
- return value;
13
- };
14
- function camelCaseWrapper(input) {
15
- if (input.toUpperCase() === input) {
16
- return codegenUtils.camelCase(input, { normalize: true });
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
9
+
10
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
11
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
12
+
13
+ function outputIsNullable(schema, context) {
14
+ if (schema.nullable) {
15
+ return true;
16
+ }
17
+ if (context.isOptional) {
18
+ return true;
17
19
  }
18
- return codegenUtils.camelCase(input);
20
+ return false;
19
21
  }
20
- const dartClientGenerator = codegenUtils.defineClientGeneratorPlugin(
21
- (options) => {
22
- return {
23
- generator: async (def) => {
24
- if (!options.clientName) {
25
- throw new Error(
26
- 'Missing "clientName" cannot generate dart client'
27
- );
28
- }
29
- if (!options.outputFile) {
30
- throw new Error(
31
- 'Missing "outputFile" cannot generate dart client'
32
- );
33
- }
34
- const numProcedures = Object.keys(def.procedures).length;
35
- if (numProcedures <= 0) {
36
- console.warn(
37
- "No procedures found in definition file. Dart client will not be generated"
38
- );
39
- }
40
- const result = createDartClient(def, options);
41
- fs.writeFileSync(options.outputFile, result);
42
- try {
43
- child_process.execSync(`dart format ${options.outputFile}`);
44
- } catch (err) {
45
- console.error("Error formatting dart client", err);
46
- }
47
- },
48
- options
49
- };
22
+ const reservedIdentifierKeywords = {
23
+ abstract: 2,
24
+ as: 2,
25
+ assert: 0,
26
+ async: 3,
27
+ await: 1,
28
+ base: 3,
29
+ break: 0,
30
+ case: 0,
31
+ catch: 0,
32
+ class: 0,
33
+ const: 0,
34
+ continue: 0,
35
+ covariant: 2,
36
+ default: 0,
37
+ deferred: 2,
38
+ do: 0,
39
+ dynamic: 2,
40
+ else: 0,
41
+ enum: 0,
42
+ export: 2,
43
+ extends: 0,
44
+ extension: 2,
45
+ external: 2,
46
+ factory: 2,
47
+ false: 0,
48
+ final: 0,
49
+ finally: 0,
50
+ for: 0,
51
+ Function: 2,
52
+ get: 2,
53
+ hide: 3,
54
+ if: 0,
55
+ implements: 2,
56
+ import: 2,
57
+ in: 0,
58
+ interface: 2,
59
+ is: 0,
60
+ late: 2,
61
+ library: 2,
62
+ mixin: 2,
63
+ new: 0,
64
+ null: 0,
65
+ of: 3,
66
+ on: 3,
67
+ operator: 2,
68
+ part: 2,
69
+ required: 2,
70
+ rethrow: 0,
71
+ return: 0,
72
+ sealed: 3,
73
+ set: 2,
74
+ show: 3,
75
+ static: 2,
76
+ super: 0,
77
+ switch: 0,
78
+ sync: 3,
79
+ this: 0,
80
+ throw: 0,
81
+ true: 0,
82
+ try: 0,
83
+ type: 2,
84
+ typedef: 2,
85
+ var: 0,
86
+ void: 0,
87
+ when: 3,
88
+ with: 0,
89
+ while: 0,
90
+ yield: 1
91
+ };
92
+ function canUseIdentifier(input) {
93
+ const reservedId = reservedIdentifierKeywords[input];
94
+ if (typeof reservedId === "undefined") {
95
+ return true;
50
96
  }
51
- );
52
- class DartClientGenerator {
53
- constructor() {
54
- __publicField(this, "generatedModels", []);
97
+ switch (reservedId) {
98
+ case 0:
99
+ return false;
100
+ case 1:
101
+ return true;
102
+ case 2:
103
+ return true;
104
+ case 3:
105
+ return true;
106
+ default:
107
+ throw new Error("Unhandled case");
55
108
  }
56
109
  }
57
- function getAnnotations(metadata) {
58
- const commentParts = [];
59
- if (metadata?.description?.length) {
60
- const parts = metadata.description.split("\n");
61
- for (const part of parts) {
62
- commentParts.push(`/// ${part}`);
63
- }
110
+ function sanitizeIdentifier(input) {
111
+ const bannedCharacters = "!@#$%^&*()-=+[{}]\\|/?.><,;`~";
112
+ const result = codegenUtils.removeDisallowedChars(input, bannedCharacters);
113
+ const numbers = "0123456789";
114
+ if (numbers.includes(result.charAt(0))) {
115
+ return `k_${result}`;
64
116
  }
65
- if (metadata?.isDeprecated) {
66
- commentParts.push("@deprecated");
117
+ return result;
118
+ }
119
+ function canUseClassName(input) {
120
+ const reservedId = reservedIdentifierKeywords[input];
121
+ if (typeof reservedId === "undefined") {
122
+ return true;
67
123
  }
68
- if (commentParts.length === 0) {
69
- return "";
124
+ switch (reservedId) {
125
+ case 0:
126
+ return false;
127
+ case 1:
128
+ return false;
129
+ case 2:
130
+ return false;
131
+ case 3:
132
+ return true;
133
+ default:
134
+ throw new Error("Unhandled case");
70
135
  }
71
- return `${commentParts.join("\n")}
72
- `;
73
136
  }
74
- function createDartClient(def, opts) {
75
- const existingClassNames = [];
76
- const clientVersion = def.info?.version ?? "";
77
- const services = codegenUtils.unflattenProcedures(def.procedures);
78
- const rpcParts = [];
79
- const serviceGetterParts = [];
80
- const serviceParts = [];
81
- const modelParts = [];
82
- for (const key of Object.keys(services)) {
83
- const item = services[key];
84
- if (codegenUtils.isRpcDefinition(item)) {
85
- const rpc = dartRpcFromDefinition(key, item);
86
- if (rpc) {
87
- rpcParts.push(rpc);
88
- }
89
- continue;
90
- }
91
- if (codegenUtils.isServiceDefinition(item)) {
92
- const serviceName = codegenUtils.pascalCase(`${opts.clientName}_${key}`);
93
- const service = dartServiceFromDefinition(serviceName, item, {
94
- versionNumber: clientVersion,
95
- ...opts
96
- });
97
- serviceParts.push(service);
98
- serviceGetterParts.push(`${serviceName}Service get ${key} {
99
- return ${serviceName}Service(
100
- httpClient: _httpClient,
101
- baseUrl: _baseUrl,
102
- headers: _headers,
137
+ function validDartIdentifier(input) {
138
+ const finalIdentifier = sanitizeIdentifier(
139
+ codegenUtils.camelCase(input, { normalize: true })
103
140
  );
104
- }`);
105
- }
141
+ if (!canUseIdentifier(finalIdentifier)) {
142
+ return `k_${finalIdentifier}`;
106
143
  }
107
- for (const key of Object.keys(def.definitions)) {
108
- const item = def.definitions[key];
109
- if (codegenUtils.isSchemaFormProperties(item) || codegenUtils.isSchemaFormDiscriminator(item) || codegenUtils.isSchemaFormValues(item)) {
110
- const result = dartTypeFromJtdSchema(key, item, {
111
- isOptional: false,
112
- existingClassNames
113
- });
114
- modelParts.push(result.content);
115
- }
144
+ return finalIdentifier;
145
+ }
146
+ function validDartClassName(input, modelPrefix) {
147
+ const className = sanitizeIdentifier(
148
+ codegenUtils.pascalCase(input, { normalize: true })
149
+ );
150
+ if (canUseClassName(className) || modelPrefix.length) {
151
+ return className;
116
152
  }
117
- if (rpcParts.length === 0 && serviceGetterParts.length === 0) {
118
- return `// this file was autogenerated by arri
119
- // ignore_for_file: type=lint
120
- import "package:arri_client/arri_client.dart";
121
-
122
- ${modelParts.join("\n")}`;
153
+ return `Class${className}`;
154
+ }
155
+ function getDartClassName(schema, context) {
156
+ if (schema.metadata?.id) {
157
+ return validDartClassName(schema.metadata.id, context.modelPrefix);
123
158
  }
124
- return `// this file was autogenerated by arri
125
- // ignore_for_file: type=lint, unused_field
126
- import "dart:async";
127
- import "dart:convert";
128
- import "package:arri_client/arri_client.dart";
129
- import "package:http/http.dart" as http;
130
-
131
- class ${opts.clientName} {
132
- final http.Client? _httpClient;
133
- final String _baseUrl;
134
- final String _clientVersion = "${def.info?.version ?? ""}";
135
- late final FutureOr<Map<String, String>> Function()? _headers;
136
- ${opts.clientName}({
137
- http.Client? httpClient,
138
- String baseUrl = "",
139
- FutureOr<Map<String, String>> Function()? headers,
140
- }) : _httpClient = httpClient,
141
- _baseUrl = baseUrl,
142
- _headers = headers;
143
- ${rpcParts.join("\n ")}
144
- ${serviceGetterParts.join("\n ")}
159
+ if (context.discriminatorParentId) {
160
+ return validDartClassName(
161
+ `${context.discriminatorParentId}_${context.discriminatorValue}`,
162
+ context.modelPrefix
163
+ );
164
+ }
165
+ return validDartClassName(
166
+ context.instancePath.split("/").join("_"),
167
+ context.modelPrefix
168
+ );
145
169
  }
146
170
 
147
- ${serviceParts.join("\n")}
171
+ function dartAnyFromSchema(schema, context) {
172
+ const typeName = `dynamic`;
173
+ const isNullable = outputIsNullable(schema, context);
174
+ const defaultValue = `null`;
175
+ return {
176
+ typeName,
177
+ isNullable,
178
+ defaultValue,
179
+ fromJson(input) {
180
+ return `${input}`;
181
+ },
182
+ toJson(input) {
183
+ return input;
184
+ },
185
+ toQueryString() {
186
+ return `print("[WARNING] any's cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
187
+ },
188
+ content: ""
189
+ };
190
+ }
148
191
 
149
- ${modelParts.join("\n")}
150
- `;
192
+ function dartListFromSchema(schema, context) {
193
+ const isNullable = outputIsNullable(schema, context);
194
+ const innerType = dartTypeFromSchema(schema.elements, {
195
+ clientName: context.clientName,
196
+ modelPrefix: context.modelPrefix,
197
+ generatedTypes: context.generatedTypes,
198
+ instancePath: `${context.instancePath}/[Element]`,
199
+ schemaPath: `${context.schemaPath}/elements`
200
+ });
201
+ const typeName = isNullable ? `List<${innerType.typeName}>?` : `List<${innerType.typeName}>`;
202
+ const defaultValue = isNullable ? "null" : "[]";
203
+ return {
204
+ typeName,
205
+ isNullable,
206
+ defaultValue,
207
+ fromJson(input) {
208
+ if (isNullable) {
209
+ return `${input} is List
210
+ ? (${input} as List)
211
+ .map((_el_) => ${innerType.fromJson(`_el_`)})
212
+ .toList()
213
+ : null`;
214
+ }
215
+ return `${input} is List
216
+ ? (${input} as List)
217
+ .map((_el_) => ${innerType.fromJson(`_el_`)})
218
+ .toList()
219
+ : <${innerType.typeName}>[]`;
220
+ },
221
+ toJson(input) {
222
+ if (context.isOptional) {
223
+ return `${input}!.map((_el_) => ${innerType.toJson("_el_", "", "")}).toList()`;
224
+ }
225
+ if (schema.nullable) {
226
+ return `${input}?.map((_el_) => ${innerType.toJson("_el_", "", "")}).toList()`;
227
+ }
228
+ return `${input}.map((_el_) => ${innerType.toJson("_el_", "", "")}).toList()`;
229
+ },
230
+ toQueryString() {
231
+ return `print(
232
+ "[WARNING] arrays cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
233
+ },
234
+ content: innerType.content
235
+ };
151
236
  }
152
- function dartServiceFromDefinition(name, def, opts) {
153
- const rpcParts = [];
154
- const subServiceParts = [];
155
- const serviceName = `${name}`;
156
- Object.keys(def).forEach((key) => {
157
- const item = def[key];
158
- if (codegenUtils.isRpcDefinition(item)) {
159
- const rpc = dartRpcFromDefinition(key, item);
160
- if (rpc) {
161
- rpcParts.push(rpc);
237
+
238
+ function dartClassFromSchema(schema, context) {
239
+ const isNullable = outputIsNullable(schema, context);
240
+ const className = getDartClassName(schema, context);
241
+ const finalClassName = `${context.modelPrefix}${className}`;
242
+ const typeName = isNullable ? `${finalClassName}?` : finalClassName;
243
+ const defaultValue = isNullable ? "null" : `${finalClassName}.empty()`;
244
+ const result = {
245
+ typeName,
246
+ isNullable,
247
+ defaultValue,
248
+ fromJson(input) {
249
+ if (isNullable) {
250
+ return `${input} is Map<String, dynamic>
251
+ ? ${finalClassName}.fromJson(${input})
252
+ : null`;
162
253
  }
163
- return;
164
- }
165
- if (codegenUtils.isServiceDefinition(item)) {
166
- const subServiceName = codegenUtils.pascalCase(`${serviceName}_${key}`);
167
- const subService = dartServiceFromDefinition(
168
- subServiceName,
169
- item,
170
- opts
171
- );
172
- subServiceParts.push({
173
- name: subServiceName,
174
- key,
175
- content: subService
176
- });
177
- }
178
- });
179
- return `class ${serviceName}Service {
180
- final http.Client? _httpClient;
181
- final String _baseUrl;
182
- final String _clientVersion = "${opts.versionNumber}";
183
- late final FutureOr<Map<String, String>> Function()? _headers;
184
- ${serviceName}Service({
185
- http.Client? httpClient,
186
- String baseUrl = "",
187
- FutureOr<Map<String, String>> Function()? headers,
188
- }) : _httpClient = httpClient,
189
- _baseUrl = baseUrl,
190
- _headers = headers;
191
- ${subServiceParts.map(
192
- (sub) => `${sub.name}Service get ${sub.key} {
193
- return ${sub.name}Service(
194
- httpClient: _httpClient,
195
- baseUrl: _baseUrl,
196
- headers: _headers,
254
+ return `${input} is Map<String, dynamic>
255
+ ? ${finalClassName}.fromJson(${input})
256
+ : ${finalClassName}.empty()`;
257
+ },
258
+ toJson(input) {
259
+ if (context.isOptional) {
260
+ return `${input}!.toJson()`;
261
+ }
262
+ if (schema.nullable) {
263
+ return `${input}?.toJson()`;
264
+ }
265
+ return `${input}.toJson()`;
266
+ },
267
+ toQueryString() {
268
+ return `print(
269
+ "[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
270
+ },
271
+ content: ""
272
+ };
273
+ if (context.generatedTypes.includes(className)) {
274
+ return result;
275
+ }
276
+ const propNames = [];
277
+ const fieldParts = [];
278
+ const constructorParts = [];
279
+ const defaultParts = [];
280
+ const fromJsonParts = [];
281
+ const toJsonRequiredParts = [];
282
+ if (context.discriminatorKey && context.discriminatorValue) {
283
+ toJsonRequiredParts.push(
284
+ ` "${context.discriminatorKey}": ${validDartIdentifier(context.discriminatorKey)},`
197
285
  );
198
- }`
199
- ).join("\n")}
200
- ${rpcParts.join("\n ")}
201
- }
202
- ${subServiceParts.map((sub) => sub.content).join("\n")}
203
- `;
204
- }
205
- function dartRpcFromDefinition(key, def, opts) {
206
- if (def.transport === "http") {
207
- return dartHttpRpcFromSchema(key, def);
208
286
  }
209
- if (def.transport === "ws") {
210
- return dartWsRpcFromSchema(key, def);
287
+ const toJsonOptionalParts = [];
288
+ const toUrlQueryParts = [];
289
+ if (context.discriminatorKey && context.discriminatorValue) {
290
+ toUrlQueryParts.push(
291
+ `_queryParts_.add("${context.discriminatorKey}=$${validDartIdentifier(context.discriminatorKey)}");`
292
+ );
211
293
  }
212
- console.warn(
213
- `[codegen-dart] WARNING: unsupported transport "${def.transport}". Skipping "${def.path}".`
214
- );
215
- return "";
216
- }
217
- function dartHttpRpcFromSchema(key, def, _opts) {
218
- let returnType = `Future<String>`;
219
- let returnTypeName = "String";
220
- if (def.response) {
221
- returnTypeName = codegenUtils.pascalCase(def.response);
222
- if (def.isEventStream) {
223
- returnType = `EventSource<${returnTypeName}>`;
294
+ const copyWithParamParts = [];
295
+ const copyWithReturnParts = [];
296
+ const subContentParts = [];
297
+ for (const key of Object.keys(schema.properties)) {
298
+ const innerSchema = schema.properties[key];
299
+ const typeResult = dartTypeFromSchema(innerSchema, {
300
+ clientName: context.clientName,
301
+ modelPrefix: context.modelPrefix,
302
+ generatedTypes: context.generatedTypes,
303
+ instancePath: `/${className}/${key}`,
304
+ schemaPath: `${context.schemaPath}/properties/${key}`
305
+ });
306
+ const propName = validDartIdentifier(key);
307
+ propNames.push(propName);
308
+ fieldParts.push(` final ${typeResult.typeName} ${propName};`);
309
+ constructorParts.push(` required this.${propName},`);
310
+ defaultParts.push(` ${propName}: ${typeResult.defaultValue},`);
311
+ fromJsonParts.push(
312
+ ` final ${propName} = ${typeResult.fromJson(`_input_["${key}"]`, key)};`
313
+ );
314
+ toJsonRequiredParts.push(
315
+ ` "${key}": ${typeResult.toJson(propName, "", key)},`
316
+ );
317
+ toUrlQueryParts.push(
318
+ ` ${typeResult.toQueryString(propName, "_queryParts_", key)};`
319
+ );
320
+ if (typeResult.isNullable) {
321
+ copyWithParamParts.push(
322
+ ` ${typeResult.typeName} Function()? ${propName},`
323
+ );
324
+ copyWithReturnParts.push(
325
+ ` ${propName}: ${propName} != null ? ${propName}() : this.${propName},`
326
+ );
224
327
  } else {
225
- returnType = `Future<${returnTypeName}>`;
328
+ copyWithParamParts.push(
329
+ ` ${typeResult.typeName}${typeResult.typeName !== "dynamic" ? "?" : ""} ${propName},`
330
+ );
331
+ copyWithReturnParts.push(
332
+ ` ${propName}: ${propName} ?? this.${propName},`
333
+ );
334
+ }
335
+ if (typeResult.content) {
336
+ subContentParts.push(typeResult.content);
226
337
  }
227
- } else {
228
- returnType = "Future<void>";
229
338
  }
230
- let paramsInput = "";
231
- if (def.params) {
232
- paramsInput = `${codegenUtils.pascalCase(def.params)} params`;
339
+ for (const key of Object.keys(schema.optionalProperties ?? {})) {
340
+ const innerSchema = schema.optionalProperties[key];
341
+ const typeResult = dartTypeFromSchema(innerSchema, {
342
+ clientName: context.clientName,
343
+ modelPrefix: context.modelPrefix,
344
+ generatedTypes: context.generatedTypes,
345
+ instancePath: `/${className}/${key}`,
346
+ schemaPath: `${context.schemaPath}/optionalProperties/${key}`,
347
+ isOptional: true
348
+ });
349
+ const propName = validDartIdentifier(key);
350
+ propNames.push(propName);
351
+ fieldParts.push(` final ${typeResult.typeName} ${propName};`);
352
+ constructorParts.push(` this.${propName},`);
353
+ fromJsonParts.push(
354
+ ` final ${propName} = ${typeResult.fromJson(`_input_["${key}"]`, key)};`
355
+ );
356
+ toJsonOptionalParts.push(
357
+ ` if (${propName} != null) _output_["${key}"] = ${typeResult.toJson(propName, "_output_", key)};`
358
+ );
359
+ toUrlQueryParts.push(
360
+ ` ${typeResult.toQueryString(propName, "_queryParts_", key)};`
361
+ );
362
+ copyWithParamParts.push(
363
+ ` ${typeResult.typeName} Function()? ${propName},`
364
+ );
365
+ copyWithReturnParts.push(
366
+ ` ${propName}: ${propName} != null ? ${propName}() : this.${propName},`
367
+ );
368
+ if (typeResult.content) {
369
+ subContentParts.push(typeResult.content);
370
+ }
233
371
  }
234
- let responseParser = "(body) => body;";
235
- switch (returnType) {
236
- case "Future<String>":
237
- break;
238
- case "Future<int>":
239
- responseParser = `(body) => Int.parse(body)`;
240
- break;
241
- case "Future<double>":
242
- responseParser = `(body) => Double.parse(body)`;
243
- break;
244
- case "Future<void>":
245
- responseParser = `(body) {}`;
246
- break;
247
- case "Future<bool>":
248
- responseParser = `(body) {
249
- switch(body) {
250
- case "true":
251
- case "1":
252
- return true;
253
- case "false":
254
- case "0":
255
- default:
256
- return false;
257
- }
258
- }`;
259
- break;
260
- default:
261
- responseParser = `(body) => ${returnTypeName}.fromJson(
262
- json.decode(body),
263
- )`;
264
- break;
372
+ let discriminatorPart = "";
373
+ if (context.discriminatorKey && context.discriminatorValue) {
374
+ discriminatorPart = `
375
+ @override
376
+ String get ${validDartIdentifier(context.discriminatorKey)} => "${context.discriminatorValue}";
377
+ `;
265
378
  }
266
- if (def.isEventStream) {
267
- const hookParts = [
268
- `SseHookOnData<${returnTypeName}>? onData`,
269
- `SseHookOnError<${returnTypeName}>? onError`,
270
- `SseHookOnConnectionError<${returnTypeName}>? onConnectionError`,
271
- `SseHookOnOpen<${returnTypeName}>? onOpen`,
272
- `SseHookOnClose<${returnTypeName}>? onClose`,
273
- `String? lastEventId`
274
- ];
275
- return `${getAnnotations({ description: def.description, isDeprecated: def.isDeprecated })}${returnType} ${key}(${paramsInput.length ? `${paramsInput}, ` : ""}{${hookParts.join(", ")},}) {
276
- return parsedArriSseRequest<${returnTypeName}>(
277
- "$_baseUrl${def.path}",
278
- httpClient: _httpClient,
279
- method: HttpMethod.${def.method},
280
- headers: _headers,
281
- params: ${paramsInput.length ? `params.toJson()` : "null"},
282
- parser: ${responseParser},
283
- onData: onData,
284
- onError: onError,
285
- onConnectionError: onConnectionError,
286
- onOpen: onOpen,
287
- onClose: onClose,
288
- lastEventId: lastEventId,
289
- clientVersion: _clientVersion,
290
- );
291
- }`;
379
+ result.content = `class ${finalClassName} implements ${context.discriminatorParentId ?? "ArriModel"} {
380
+ ${fieldParts.join("\n")}
381
+ const ${finalClassName}({
382
+ ${constructorParts.join("\n")}
383
+ });
384
+ ${discriminatorPart}
385
+ factory ${finalClassName}.empty() {
386
+ return ${finalClassName}(
387
+ ${defaultParts.join("\n")}
388
+ );
292
389
  }
293
- return `${getAnnotations({ description: def.description, isDeprecated: def.isDeprecated })}${returnType} ${key}(${paramsInput}) {
294
- return parsedArriRequest(
295
- "$_baseUrl${def.path}",
296
- httpClient: _httpClient,
297
- method: HttpMethod.${def.method},
298
- headers: _headers,
299
- params: ${paramsInput.length ? `params.toJson()` : "null"},
300
- parser: ${responseParser},
301
- clientVersion: _clientVersion,
390
+
391
+ factory ${finalClassName}.fromJson(Map<String, dynamic> _input_) {
392
+ ${fromJsonParts.join("\n")}
393
+ return ${finalClassName}(
394
+ ${propNames.map((prop) => ` ${prop}: ${prop},`).join("\n")}
302
395
  );
303
- }`;
304
- }
305
- function dartWsRpcFromSchema(key, def, _opts) {
306
- const serverMsg = def.response ? codegenUtils.pascalCase(def.response, { normalize: true }) : "Null";
307
- const clientMsg = def.params ? codegenUtils.pascalCase(def.params, { normalize: true }) : "Null";
308
- const returnType = `Future<ArriWebsocketController<${serverMsg}, ${clientMsg}>>`;
309
- const parser = def.response ? `(body) => ${serverMsg}.fromJson(json.decode(body))` : `(_) => null`;
310
- const serializer = def.params ? `(body) => json.encode(body.toJson())` : `(_) => ""`;
311
- return `${getAnnotations({ description: def.description, isDeprecated: def.isDeprecated })}${returnType} ${key}() {
312
- return arriWebsocketRequest<${serverMsg}, ${clientMsg}>(
313
- "$_baseUrl${def.path}",
314
- headers: _headers,
315
- parser: ${parser},
316
- serializer: ${serializer},
317
- clientVersion: _clientVersion,
318
- );
319
- }`;
320
- }
321
- function dartTypeFromJtdSchema(nodePath, def, additionalOptions) {
322
- if (codegenUtils.isSchemaFormType(def)) {
323
- return dartScalarFromJtdScalar(nodePath, def, additionalOptions);
324
396
  }
325
- if (codegenUtils.isSchemaFormProperties(def)) {
326
- return dartClassFromJtdSchema(nodePath, def, additionalOptions);
397
+
398
+ factory ${finalClassName}.fromJsonString(String input) {
399
+ return ${finalClassName}.fromJson(json.decode(input));
400
+ }
401
+
402
+ @override
403
+ Map<String, dynamic> toJson() {
404
+ final _output_ = <String, dynamic>{
405
+ ${toJsonRequiredParts.join("\n")}
406
+ };
407
+ ${toJsonOptionalParts.join("\n")}
408
+ return _output_;
327
409
  }
328
- if (codegenUtils.isSchemaFormElements(def)) {
329
- return dartArrayFromJtdSchema(nodePath, def, additionalOptions);
410
+
411
+ @override
412
+ String toJsonString() {
413
+ return json.encode(toJson());
330
414
  }
331
- if (codegenUtils.isSchemaFormEnum(def)) {
332
- return dartEnumFromJtdSchema(nodePath, def, additionalOptions);
415
+
416
+ @override
417
+ String toUrlQueryParams() {
418
+ final _queryParts_ = <String>[];
419
+ ${toUrlQueryParts.join("\n")}
420
+ return _queryParts_.join("&");
333
421
  }
334
- if (codegenUtils.isSchemaFormValues(def)) {
335
- return dartMapFromJtdSchema(nodePath, def, additionalOptions);
422
+
423
+ @override
424
+ ${finalClassName} copyWith({
425
+ ${copyWithParamParts.join("\n")}
426
+ }) {
427
+ return ${finalClassName}(
428
+ ${copyWithReturnParts.join("\n")}
429
+ );
336
430
  }
337
- if (codegenUtils.isSchemaFormDiscriminator(def)) {
338
- return dartSealedClassFromJtdSchema(nodePath, def, additionalOptions);
431
+
432
+ @override
433
+ List<Object?> get props => [
434
+ ${propNames.map((prop) => ` ${prop},`).join("\n")}
435
+ ];
436
+
437
+ @override
438
+ bool operator ==(Object other) {
439
+ return other is ${finalClassName} &&
440
+ listsAreEqual(props, other.props);
339
441
  }
340
- if (codegenUtils.isSchemaFormRef(def)) {
341
- return dartRefFromJtdSchema(nodePath, def, additionalOptions);
442
+
443
+ @override
444
+ int get hashCode => listToHashCode(props);
445
+
446
+ @override
447
+ String toString() {
448
+ return "${finalClassName} \${toJsonString()}";
342
449
  }
343
- return dartDynamicFromAny(nodePath, schema.a.any(), additionalOptions);
344
450
  }
345
- function dartClassFromJtdSchema(nodePath, def, additionalOptions) {
346
- const isException = additionalOptions?.isException ?? false;
347
- const discOptions = additionalOptions?.discriminatorOptions;
348
- const isDiscriminatorChild = (discOptions?.discriminatorKey.length ?? 0) > 0;
349
- const jsonKey = nodePath.split(".").pop() ?? "";
350
- const key = camelCaseWrapper(jsonKey);
351
- let className = def.metadata?.id ? codegenUtils.pascalCase(def.metadata.id) : void 0;
352
- if (!className) {
353
- const relativePath = nodePath.split(".").pop();
354
- if (additionalOptions.parentId && relativePath) {
355
- className = codegenUtils.pascalCase(
356
- `${additionalOptions.parentId}_${relativePath}`
357
- );
358
- } else {
359
- className = codegenUtils.pascalCase(nodePath.split(".").join("_"));
360
- }
361
- }
362
- const properties = [];
363
- const optionalProperties = [];
451
+
452
+ ${subContentParts.join("\n\n")}`;
453
+ context.generatedTypes.push(className);
454
+ return result;
455
+ }
456
+
457
+ function dartSealedClassFromSchema(schema, context) {
458
+ const isNullable = outputIsNullable(schema, context);
459
+ const className = getDartClassName(schema, context);
460
+ const finalClassName = `${context.modelPrefix}${className}`;
461
+ const typeName = isNullable ? `${finalClassName}?` : finalClassName;
462
+ const defaultValue = isNullable ? `null` : `${finalClassName}.empty()`;
463
+ const discriminatorKey = schema.discriminator;
464
+ const subTypeParts = [];
364
465
  const subContentParts = [];
365
- if (!def.properties) {
366
- return {
367
- typeName: "",
368
- fieldTemplate: "",
369
- constructorTemplate: "",
370
- fromJsonTemplate: () => "",
371
- toJsonTemplate: () => "",
372
- content: ""
373
- };
374
- }
375
- for (const key2 of Object.keys(def.properties ?? {})) {
376
- const keyPath = `${nodePath}.${key2}`;
377
- const prop = def.properties[key2];
378
- const mappedProp = dartTypeFromJtdSchema(keyPath, prop, {
379
- parentId: className,
380
- isOptional: false,
381
- existingClassNames: additionalOptions.existingClassNames
466
+ for (const key of Object.keys(schema.mapping)) {
467
+ const subSchema = schema.mapping[key];
468
+ const discriminatorValue = key;
469
+ const subTypeResult = dartClassFromSchema(subSchema, {
470
+ clientName: context.clientName,
471
+ modelPrefix: context.modelPrefix,
472
+ generatedTypes: context.generatedTypes,
473
+ instancePath: context.instancePath,
474
+ schemaPath: `${context.schemaPath}/mapping/${key}`,
475
+ discriminatorKey,
476
+ discriminatorValue,
477
+ discriminatorParentId: className
382
478
  });
383
- properties.push({
384
- key: key2,
385
- templates: mappedProp
479
+ subTypeParts.push({
480
+ name: subTypeResult.typeName,
481
+ value: discriminatorValue
386
482
  });
387
- if (mappedProp?.content) {
388
- subContentParts.push(mappedProp.content);
483
+ if (subTypeResult.content) {
484
+ subContentParts.push(subTypeResult.content);
389
485
  }
390
486
  }
391
- if (def.optionalProperties) {
392
- for (const key2 of Object.keys(def.optionalProperties ?? {})) {
393
- const keyPath = `${nodePath}.${key2}`;
394
- const prop = def.optionalProperties[key2];
395
- const mappedProp = dartTypeFromJtdSchema(keyPath, prop, {
396
- parentId: className,
397
- isOptional: true,
398
- existingClassNames: additionalOptions.existingClassNames
399
- });
400
- optionalProperties.push({ key: key2, templates: mappedProp });
401
- if (mappedProp?.content) {
402
- subContentParts.push(mappedProp.content);
487
+ const result = {
488
+ typeName,
489
+ isNullable,
490
+ defaultValue,
491
+ fromJson(input) {
492
+ if (isNullable) {
493
+ return `${input} is Map<String, dynamic>
494
+ ? ${finalClassName}.fromJson(${input})
495
+ : null`;
403
496
  }
404
- }
405
- }
406
- const fieldParts = [];
407
- const constructorParts = [];
408
- const fromJsonParts = [];
409
- const copyWithParamParts = [];
410
- const copyWithInitParts = [];
411
- if (discOptions) {
412
- fieldParts.push(`@override
413
- final String ${camelCaseWrapper(discOptions.discriminatorKey)} = "${discOptions.discriminatorValue}"`);
414
- }
415
- for (const prop of properties) {
416
- fieldParts.push(prop.templates.fieldTemplate);
417
- constructorParts.push(prop.templates.constructorTemplate);
418
- const subJsonKey = prop.key;
419
- const subKey = camelCaseWrapper(prop.key);
420
- fromJsonParts.push(
421
- `${subKey}: ${prop.templates.fromJsonTemplate(
422
- `json["${subJsonKey}"]`
423
- )}`
424
- );
425
- if (prop.templates.typeName === "dynamic") {
426
- copyWithParamParts.push(`dynamic ${subKey}`);
427
- copyWithInitParts.push(`${subKey}: ${subKey} ?? this.${subKey}`);
428
- } else {
429
- if (prop.templates.typeName.endsWith("?")) {
430
- copyWithParamParts.push(
431
- `ArriBox<${prop.templates.typeName}>? ${subKey}`
432
- );
433
- copyWithInitParts.push(
434
- `${subKey}: ${subKey} != null ? ${subKey}.value : this.${subKey}`
435
- );
436
- } else {
437
- copyWithParamParts.push(
438
- `${prop.templates.typeName}? ${subKey}`
439
- );
440
- copyWithInitParts.push(
441
- `${subKey}: ${subKey} ?? this.${subKey}`
442
- );
497
+ return `${input} is Map<String, dynamic>
498
+ ? ${finalClassName}.fromJson(${input})
499
+ : ${finalClassName}.empty()`;
500
+ },
501
+ toJson(input) {
502
+ if (context.isOptional) {
503
+ return `${input}!.toJson()`;
443
504
  }
444
- }
445
- }
446
- for (const prop of optionalProperties) {
447
- fieldParts.push(prop.templates.fieldTemplate);
448
- constructorParts.push(prop.templates.constructorTemplate);
449
- const subKey = camelCaseWrapper(prop.key);
450
- const subJsonKey = prop.key;
451
- fromJsonParts.push(
452
- `${subKey}: ${prop.templates.fromJsonTemplate(
453
- `json["${subJsonKey}"]`
454
- )}`
455
- );
456
- if (prop.templates.typeName === "dynamic") {
457
- copyWithParamParts.push(`dynamic ${subKey}`);
458
- copyWithInitParts.push(`${subKey}: ${subKey} ?? this.${subKey}`);
459
- } else {
460
- if (prop.templates.typeName.endsWith("?")) {
461
- copyWithParamParts.push(
462
- `ArriBox<${prop.templates.typeName}>? ${subKey}`
463
- );
464
- copyWithInitParts.push(
465
- `${subKey}: ${subKey} != null ? ${subKey}.value : this.${subKey}`
466
- );
467
- } else {
468
- copyWithParamParts.push(
469
- `${prop.templates.typeName}? ${subKey}`
470
- );
471
- copyWithInitParts.push(
472
- `${subKey}: ${subKey} ?? this.${subKey}`
473
- );
505
+ if (schema.nullable) {
506
+ return `${input}?.toJson()`;
474
507
  }
475
- }
476
- }
477
- let classNamePart = `class ${className}`;
478
- if (isDiscriminatorChild) {
479
- classNamePart += ` implements ${discOptions?.discriminatorParentClassName}`;
480
- } else if (isException) {
481
- classNamePart += ` implements Exception`;
508
+ return `${input}.toJson()`;
509
+ },
510
+ toQueryString() {
511
+ return `print(
512
+ "[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
513
+ },
514
+ content: ""
515
+ };
516
+ if (context.generatedTypes.includes(className)) {
517
+ return result;
482
518
  }
483
- let content = `${getAnnotations(def.metadata)}${classNamePart} {
484
- ${fieldParts.join(";\n ")};
485
- const ${className}({
486
- ${constructorParts.join(",\n ")},
487
- });
488
- factory ${className}.fromJson(Map<String, dynamic> json) {
489
- return ${className}(
490
- ${fromJsonParts.join(",\n ")},
519
+ const discriminatorProp = validDartIdentifier(schema.discriminator);
520
+ result.content = `sealed class ${finalClassName} implements ArriModel {
521
+ String get ${discriminatorProp};
522
+ const ${finalClassName}();
523
+
524
+ factory ${finalClassName}.empty() {
525
+ return ${subTypeParts[0]?.name}.empty();
526
+ }
527
+
528
+ factory ${finalClassName}.fromJson(Map<String, dynamic> _input_) {
529
+ final ${discriminatorProp} = typeFromDynamic<String>(_input_["${schema.discriminator}"], "");
530
+ switch (${discriminatorProp}) {
531
+ ${subTypeParts.map(
532
+ (type) => ` case "${type.value}":
533
+ return ${type.name}.fromJson(_input_);`
534
+ ).join("\n")}
535
+ default:
536
+ return ${finalClassName}.empty();
537
+ }
538
+ }
539
+
540
+ factory ${finalClassName}.fromJsonString(String input) {
541
+ return ${finalClassName}.fromJson(json.decode(input));
542
+ }
543
+ }
544
+
545
+ ${subContentParts.join("\n\n")}`;
546
+ context.generatedTypes.push(className);
547
+ return result;
548
+ }
549
+
550
+ function dartEnumFromSchema(schema, context) {
551
+ const isNullable = outputIsNullable(schema, context);
552
+ const enumName = getDartClassName(schema, context);
553
+ const typeName = isNullable ? `${enumName}?` : enumName;
554
+ const enumValues = schema.enum.map((val) => ({
555
+ name: codegenUtils.camelCase(val, { normalize: true }),
556
+ serialValue: val
557
+ }));
558
+ if (!enumValues.length) {
559
+ throw new Error(
560
+ `Enum schemas must have at least one enum value. At ${context.instancePath}.`
491
561
  );
492
562
  }
493
- ${isDiscriminatorChild ? `@override` : ""}
494
- Map<String, dynamic> toJson() {
495
- final __result = <String, dynamic>{${isDiscriminatorChild ? `
496
- "${discOptions?.discriminatorKey}": ${camelCaseWrapper(
497
- discOptions?.discriminatorKey ?? ""
498
- )},` : ""}
499
- ${properties.map(
500
- (prop) => `"${prop.key}": ${prop.templates.toJsonTemplate(
501
- camelCaseWrapper(prop.key)
502
- )}`
503
- ).join(",\n ")}${properties.length ? "," : ""}
504
- };
505
- ${optionalProperties.map(
506
- (prop) => `if (${camelCaseWrapper(prop.key)} != null) {
507
- __result["${prop.key}"] = ${prop.templates.toJsonTemplate(
508
- camelCaseWrapper(prop.key)
509
- )};
510
- }`
511
- ).join("\n")}
512
- return __result;
563
+ const defaultValue = isNullable ? "null" : `${context.modelPrefix}${enumName}.${enumValues[0]?.name}`;
564
+ const output = {
565
+ typeName,
566
+ isNullable,
567
+ defaultValue,
568
+ fromJson(input, _key) {
569
+ if (isNullable) {
570
+ return `${input} is String ? ${context.modelPrefix}${enumName}.fromString(${input}) : null`;
571
+ }
572
+ return `${context.modelPrefix}${enumName}.fromString(typeFromDynamic<String>(${input}, ""))`;
573
+ },
574
+ toJson(input) {
575
+ if (context.isOptional) {
576
+ return `${input}!.serialValue`;
577
+ }
578
+ if (schema.nullable) {
579
+ return `${input}?.serialValue`;
580
+ }
581
+ return `${input}.serialValue`;
582
+ },
583
+ toQueryString(input, target, key) {
584
+ if (context.isOptional) {
585
+ return `if (${input} != null) ${target}.add("${key}=\${${input}!.serialValue}")`;
586
+ }
587
+ if (schema.nullable) {
588
+ return `${target}.add("${key}=\${${input}?.serialValue}")`;
589
+ }
590
+ return `${target}.add("${key}=\${${input}.serialValue}")`;
591
+ },
592
+ content: ""
593
+ };
594
+ if (context.generatedTypes.includes(enumName)) {
595
+ return output;
513
596
  }
514
- ${className} copyWith({
515
- ${copyWithParamParts.join(",\n ")},
516
- }) {
517
- return ${className}(
518
- ${copyWithInitParts.join(",\n ")},
519
- );
597
+ output.content = `enum ${context.modelPrefix}${enumName} implements Comparable<${context.modelPrefix}${enumName}> {
598
+ ${enumValues.map((val) => ` ${val.name}("${val.serialValue}")`).join(",\n")};
599
+
600
+ const ${context.modelPrefix}${enumName}(this.serialValue);
601
+ final String serialValue;
602
+
603
+ factory ${context.modelPrefix}${enumName}.fromString(String input) {
604
+ for (final val in values) {
605
+ if (val.serialValue == input) {
606
+ return val;
607
+ }
608
+ }
609
+ return ${enumValues[0].name};
520
610
  }
611
+
612
+ @override
613
+ int compareTo(${enumName} other) => name.compareTo(other.name);
614
+ }`;
615
+ context.generatedTypes.push(enumName);
616
+ return output;
521
617
  }
522
- ${subContentParts.join("\n")}
523
618
 
524
- `;
525
- if (additionalOptions.existingClassNames.includes(className)) {
526
- content = "";
527
- } else {
528
- additionalOptions.existingClassNames.push(className);
529
- }
530
- const isNullable = def.nullable ?? additionalOptions?.isOptional;
531
- const typeName = isNullable ? `${className}?` : className;
619
+ function dartStringFromSchema(schema, context) {
620
+ const isNullable = outputIsNullable(schema, context);
621
+ const typeName = isNullable ? `String?` : "String";
622
+ const defaultValue = isNullable ? "null" : '""';
532
623
  return {
533
624
  typeName,
534
- fieldTemplate: fieldTemplateString(
535
- typeName,
536
- key,
537
- def.metadata?.description,
538
- def.metadata?.isDeprecated
539
- ),
540
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
541
- fromJsonTemplate: (input) => isNullable ? `${input} is Map<String, dynamic> ? ${className}.fromJson(${input}) : null` : `${className}.fromJson(${input})`,
542
- toJsonTemplate: (input) => `${input}${isNullable ? "?" : ""}.toJson()`,
543
- content
625
+ isNullable,
626
+ defaultValue,
627
+ fromJson(input, _key) {
628
+ if (isNullable) {
629
+ return `nullableTypeFromDynamic<String>(${input})`;
630
+ }
631
+ return `typeFromDynamic<String>(${input}, "")`;
632
+ },
633
+ toJson(input, _target, _key) {
634
+ return input;
635
+ },
636
+ toQueryString(input, target, key) {
637
+ if (context.isOptional) {
638
+ return `if (${input} != null) ${target}.add("${key}=$${input}")`;
639
+ }
640
+ return `${target}.add("${key}=$${input}")`;
641
+ },
642
+ content: ""
544
643
  };
545
644
  }
546
- function dartDynamicFromAny(nodePath, def, additionalOptions) {
547
- const jsonKey = nodePath.split(".").pop() ?? "";
548
- const key = camelCaseWrapper(jsonKey);
645
+ function dartBoolFromSchema(schema, context) {
646
+ const isNullable = outputIsNullable(schema, context);
647
+ const typeName = isNullable ? "bool?" : "bool";
648
+ const defaultValue = isNullable ? "null" : "false";
549
649
  return {
550
- typeName: "dynamic",
551
- fieldTemplate: fieldTemplateString(
552
- "dynamic",
553
- key,
554
- def.metadata?.description,
555
- def.metadata?.isDeprecated
556
- ),
557
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
558
- fromJsonTemplate: (input) => `${input}`,
559
- toJsonTemplate: (input) => input,
650
+ typeName,
651
+ isNullable,
652
+ defaultValue,
653
+ fromJson(input, _key) {
654
+ if (isNullable) {
655
+ return `nullableTypeFromDynamic<bool>(${input})`;
656
+ }
657
+ return `typeFromDynamic<bool>(${input}, false)`;
658
+ },
659
+ toJson(input, _target, _key) {
660
+ return input;
661
+ },
662
+ toQueryString(input, target, key) {
663
+ if (context.isOptional) {
664
+ return `if (${input} != null) ${target}.add("${key}=$${input}")`;
665
+ }
666
+ return `${target}.add("${key}=$${input}")`;
667
+ },
560
668
  content: ""
561
669
  };
562
670
  }
563
- function fieldTemplateString(typeName, key, description, deprecated) {
564
- let result = "";
565
- if (deprecated) {
566
- result += `@deprecated
567
- `;
568
- }
569
- if (description) {
570
- const parts = description.split("\n");
571
- for (const part of parts) {
572
- result += `/// ${part}
573
- `;
574
- }
575
- }
576
- result += `final ${typeName} ${key}`;
577
- return result;
578
- }
579
- function dartArrayFromJtdSchema(nodePath, def, additionalOptions) {
580
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
581
- const jsonKey = nodePath.split(".").pop() ?? "";
582
- const key = camelCaseWrapper(jsonKey);
583
- const subtype = dartTypeFromJtdSchema(`${nodePath}.Item`, def.elements, {
584
- existingClassNames: additionalOptions.existingClassNames,
585
- isOptional: false
586
- });
587
- const typeName = isNullable ? `List<${subtype.typeName}>?` : `List<${subtype.typeName}>`;
671
+ function dartDateTimeFromSchema(schema, context) {
672
+ const isNullable = outputIsNullable(schema, context);
673
+ const typeName = isNullable ? "DateTime?" : "DateTime";
674
+ const defaultValue = isNullable ? "null" : "DateTime.now()";
588
675
  return {
589
676
  typeName,
590
- fieldTemplate: fieldTemplateString(
591
- typeName,
592
- key,
593
- def.metadata?.description,
594
- def.metadata?.isDeprecated
595
- ),
596
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
597
- fromJsonTemplate: (input) => {
677
+ isNullable,
678
+ defaultValue,
679
+ fromJson(input, _key) {
598
680
  if (isNullable) {
599
- return `${input} is List ?
600
- // ignore: unnecessary_cast
601
- (${input} as List).map((item) => ${subtype.fromJsonTemplate(
602
- "item"
603
- )}).toList() as ${typeName} : null`;
681
+ return `nullableDateTimeFromDynamic(${input})`;
604
682
  }
605
- return `${input} is List ?
606
- // ignore: unnecessary_cast
607
- (${input} as List).map((item) => ${subtype.fromJsonTemplate(
608
- "item"
609
- )}).toList() as ${typeName} : <${subtype.typeName}>[]`;
683
+ return `dateTimeFromDynamic(${input}, DateTime.now())`;
610
684
  },
611
- toJsonTemplate: (input) => {
612
- return `${input}${isNullable ? "?" : ""}.map((item) => ${subtype.toJsonTemplate("item")}).toList()`;
685
+ toJson(input, _target, _key) {
686
+ if (context.isOptional) {
687
+ return `${input}!.toUtc().toIso8601String()`;
688
+ }
689
+ if (schema.nullable) {
690
+ return `${input}?.toUtc().toIso8601String()`;
691
+ }
692
+ return `${input}.toUtc().toIso8601String()`;
693
+ },
694
+ toQueryString(input, target, key) {
695
+ if (context.isOptional) {
696
+ return `if (${input} != null) ${target}.add("${key}=\${${input}!.toUtc().toIso8601String()}")`;
697
+ }
698
+ if (schema.nullable) {
699
+ return `${target}.add("${key}=\${${input}?.toUtc().toIso8601String()}")`;
700
+ }
701
+ return `${target}.add("${key}=\${${input}.toUtc().toIso8601String()}")`;
613
702
  },
614
- content: subtype.content
703
+ content: ""
615
704
  };
616
705
  }
617
- function dartScalarFromJtdScalar(nodePath, def, additionalOptions) {
618
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
619
- const jsonKey = nodePath.split(".").pop() ?? "";
620
- const key = camelCaseWrapper(jsonKey);
621
- const defaultInitializationTemplate = additionalOptions.isOptional ? `this.${key}` : `required this.${key}`;
622
- const { description } = def.metadata ?? {};
623
- const defaultToJsonTemplate = (input) => input;
624
- switch (def.type) {
625
- case "boolean":
706
+ function dartDoubleFromSchema(schema, context) {
707
+ const isNullable = outputIsNullable(schema, context);
708
+ const typeName = isNullable ? "double?" : "double";
709
+ const defaultValue = isNullable ? "null" : "0.0";
710
+ return {
711
+ typeName,
712
+ isNullable,
713
+ defaultValue,
714
+ fromJson(input, _key) {
626
715
  if (isNullable) {
627
- return {
628
- typeName: "bool?",
629
- fieldTemplate: fieldTemplateString(
630
- "bool?",
631
- key,
632
- description,
633
- def.metadata?.isDeprecated
634
- ),
635
- constructorTemplate: defaultInitializationTemplate,
636
- fromJsonTemplate: (input) => `nullableTypeFromDynamic<bool>(${input})`,
637
- toJsonTemplate: defaultToJsonTemplate,
638
- content: ""
639
- };
716
+ return `nullableDoubleFromDynamic(${input})`;
640
717
  }
641
- return {
642
- typeName: "bool",
643
- fieldTemplate: fieldTemplateString(
644
- "bool",
645
- key,
646
- description,
647
- def.metadata?.isDeprecated
648
- ),
649
- constructorTemplate: defaultInitializationTemplate,
650
- fromJsonTemplate: (input) => `typeFromDynamic<bool>(${input}, false)`,
651
- toJsonTemplate: defaultToJsonTemplate,
652
- content: ""
653
- };
654
- case "float32":
655
- case "float64":
656
- if (isNullable) {
657
- return {
658
- typeName: "double?",
659
- fieldTemplate: fieldTemplateString(
660
- "double?",
661
- key,
662
- description,
663
- def.metadata?.isDeprecated
664
- ),
665
- constructorTemplate: defaultInitializationTemplate,
666
- fromJsonTemplate: (input) => `nullableDoubleFromDynamic(${input})`,
667
- toJsonTemplate: defaultToJsonTemplate,
668
- content: ""
669
- };
718
+ return `doubleFromDynamic(${input}, 0.0)`;
719
+ },
720
+ toJson(input, _, __) {
721
+ return input;
722
+ },
723
+ toQueryString(input, target, key) {
724
+ if (context.isOptional) {
725
+ return `if (${input} != null) ${target}.add("${key}=$${input}")`;
670
726
  }
671
- return {
672
- typeName: "double",
673
- fieldTemplate: fieldTemplateString(
674
- "double",
675
- key,
676
- description,
677
- def.metadata?.isDeprecated
678
- ),
679
- constructorTemplate: defaultInitializationTemplate,
680
- fromJsonTemplate: (input) => `doubleFromDynamic(${input}, 0)`,
681
- toJsonTemplate: defaultToJsonTemplate,
682
- content: ""
683
- };
684
- case "int16":
685
- case "int32":
686
- case "int8":
687
- case "uint16":
688
- case "uint32":
689
- case "uint8":
727
+ return `${target}.add("${key}=$${input}")`;
728
+ },
729
+ content: ""
730
+ };
731
+ }
732
+ function dartIntFromSchema(schema, context) {
733
+ const isNullable = outputIsNullable(schema, context);
734
+ const typeName = isNullable ? "int?" : "int";
735
+ const defaultValue = isNullable ? "null" : "0";
736
+ return {
737
+ typeName,
738
+ isNullable,
739
+ defaultValue,
740
+ fromJson(input, _key) {
690
741
  if (isNullable) {
691
- return {
692
- typeName: "int?",
693
- fieldTemplate: fieldTemplateString(
694
- "int?",
695
- key,
696
- description,
697
- def.metadata?.isDeprecated
698
- ),
699
- constructorTemplate: defaultInitializationTemplate,
700
- fromJsonTemplate: (input) => `nullableIntFromDynamic(${input})`,
701
- toJsonTemplate: defaultToJsonTemplate,
702
- content: ""
703
- };
742
+ return `nullableIntFromDynamic(${input})`;
704
743
  }
705
- return {
706
- typeName: "int",
707
- fieldTemplate: fieldTemplateString(
708
- `int`,
709
- key,
710
- description,
711
- def.metadata?.isDeprecated
712
- ),
713
- constructorTemplate: defaultInitializationTemplate,
714
- fromJsonTemplate: (input) => `intFromDynamic(${input}, 0)`,
715
- toJsonTemplate: defaultToJsonTemplate,
716
- content: ""
717
- };
718
- case "int64":
719
- case "uint64":
720
- if (isNullable) {
721
- return {
722
- typeName: "BigInt?",
723
- fieldTemplate: fieldTemplateString(
724
- `BigInt?`,
725
- key,
726
- description,
727
- def.metadata?.isDeprecated
728
- ),
729
- constructorTemplate: defaultInitializationTemplate,
730
- fromJsonTemplate: (input) => `nullableBigIntFromDynamic(${input})`,
731
- toJsonTemplate: (input) => `${input}?.toString()`,
732
- content: ""
733
- };
744
+ return `intFromDynamic(${input}, 0)`;
745
+ },
746
+ toJson(input) {
747
+ return input;
748
+ },
749
+ toQueryString(input, target, key) {
750
+ if (context.isOptional) {
751
+ return `if (${input} != null) ${target}.add("${key}=$${input}")`;
734
752
  }
735
- return {
736
- typeName: "BigInt",
737
- fieldTemplate: fieldTemplateString(
738
- `BigInt`,
739
- key,
740
- description,
741
- def.metadata?.isDeprecated
742
- ),
743
- constructorTemplate: defaultInitializationTemplate,
744
- fromJsonTemplate: (input) => `bigIntFromDynamic(${input}, BigInt.zero)`,
745
- toJsonTemplate: (input) => `${input}.toString()`,
746
- content: ""
747
- };
748
- case "timestamp":
753
+ return `${target}.add("${key}=$${input}")`;
754
+ },
755
+ content: ""
756
+ };
757
+ }
758
+ function dartBigIntFromSchema(schema, context) {
759
+ const isNullable = outputIsNullable(schema, context);
760
+ const typeName = isNullable ? "BigInt?" : "BigInt";
761
+ const defaultValue = isNullable ? "null" : "BigInt.zero";
762
+ return {
763
+ typeName,
764
+ isNullable,
765
+ defaultValue,
766
+ fromJson(input, _key) {
749
767
  if (isNullable) {
750
- return {
751
- typeName: "DateTime?",
752
- fieldTemplate: fieldTemplateString(
753
- "DateTime?",
754
- key,
755
- description,
756
- def.metadata?.isDeprecated
757
- ),
758
- constructorTemplate: defaultInitializationTemplate,
759
- fromJsonTemplate: (input) => `nullableDateTimeFromDynamic(${input})`,
760
- toJsonTemplate: (input) => `${input}?.toUtc().toIso8601String()`,
761
- content: ""
762
- };
768
+ return `nullableBigIntFromDynamic(${input})`;
763
769
  }
764
- return {
765
- typeName: "DateTime",
766
- fieldTemplate: fieldTemplateString(
767
- "DateTime",
768
- key,
769
- description,
770
- def.metadata?.isDeprecated
771
- ),
772
- constructorTemplate: defaultInitializationTemplate,
773
- fromJsonTemplate: (input) => `dateTimeFromDynamic(
774
- ${input},
775
- DateTime.fromMillisecondsSinceEpoch(0),
776
- )`,
777
- toJsonTemplate: (input) => `${input}.toUtc().toIso8601String()`,
778
- content: ""
779
- };
780
- case "string":
781
- if (isNullable) {
782
- return {
783
- typeName: "String?",
784
- fieldTemplate: fieldTemplateString(
785
- "String?",
786
- key,
787
- description,
788
- def.metadata?.isDeprecated
789
- ),
790
- constructorTemplate: defaultInitializationTemplate,
791
- fromJsonTemplate: (input) => `nullableTypeFromDynamic<String>(${input})`,
792
- toJsonTemplate: defaultToJsonTemplate,
793
- content: ""
794
- };
770
+ return `bigIntFromDynamic(${input}, BigInt.zero)`;
771
+ },
772
+ toJson(input, _target, _key) {
773
+ if (context.isOptional) {
774
+ return `${input}!.toString()`;
775
+ }
776
+ if (schema.nullable) {
777
+ return `${input}?.toString()`;
795
778
  }
796
- return {
797
- typeName: "String",
798
- fieldTemplate: fieldTemplateString(
799
- "String",
800
- key,
801
- description,
802
- def.metadata?.isDeprecated
803
- ),
804
- constructorTemplate: defaultInitializationTemplate,
805
- fromJsonTemplate: (input) => `typeFromDynamic<String>(${input}, "")`,
806
- toJsonTemplate: defaultToJsonTemplate,
807
- content: ""
808
- };
779
+ return `${input}.toString()`;
780
+ },
781
+ toQueryString(input, target, key) {
782
+ if (context.isOptional) {
783
+ return `if (${input} != null) ${target}.add("${key}=$${input}")`;
784
+ }
785
+ return `${target}.add("${key}=$${input}")`;
786
+ },
787
+ content: ""
788
+ };
789
+ }
790
+
791
+ function dartRpcFromSchema(schema, context) {
792
+ switch (schema.transport) {
793
+ case "http":
794
+ return dartHttpRpcFromSchema(schema, context);
795
+ case "ws":
796
+ return dartWsRpcFromSchema(schema, context);
809
797
  default:
810
- return {
811
- typeName: "dynamic",
812
- fieldTemplate: fieldTemplateString(
813
- "dynamic",
814
- key,
815
- description,
816
- def.metadata?.isDeprecated
817
- ),
818
- constructorTemplate: defaultInitializationTemplate,
819
- fromJsonTemplate: (input) => input,
820
- toJsonTemplate: defaultToJsonTemplate,
821
- content: ""
822
- };
798
+ console.warn(
799
+ `[WARNING] unsupported transport "${schema.transport}". Skipping ${context.instancePath}.`
800
+ );
801
+ return "";
823
802
  }
824
803
  }
825
- function dartEnumFromJtdSchema(nodePath, def, additionalOptions) {
826
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
827
- const jsonKey = nodePath.split(".").pop() ?? "";
828
- const key = camelCaseWrapper(jsonKey);
829
- let className = def.metadata?.id ? codegenUtils.pascalCase(def.metadata.id) : void 0;
830
- if (!className) {
831
- className = codegenUtils.pascalCase(nodePath.split(".").join("_"));
804
+ function dartHttpRpcFromSchema(schema, context) {
805
+ const functionName = getFunctionName(context.instancePath);
806
+ let responseType = "void";
807
+ let paramsType = "";
808
+ if (schema.response) {
809
+ responseType = `${context.modelPrefix}${validDartClassName(schema.response, context.modelPrefix)}`;
832
810
  }
833
- const valNames = [];
834
- const fieldParts = [];
835
- for (const val of def.enum) {
836
- valNames.push(`${camelCaseWrapper(val)}`);
837
- fieldParts.push(`${camelCaseWrapper(val)}("${val}")`);
811
+ if (schema.params) {
812
+ paramsType = `${context.modelPrefix}${validDartClassName(schema.params, context.modelPrefix)}`;
838
813
  }
839
- let content = `${getAnnotations(def.metadata)}enum ${className} implements Comparable<${className}> {
840
- ${fieldParts.join(",\n ")};
841
- const ${className}(this.value);
842
- final String value;
843
-
844
- factory ${className}.fromJson(dynamic json) {
845
- for(final v in values) {
846
- if(v.value == json) {
847
- return v;
848
- }
849
- }
850
- return ${valNames[0]};
851
- }
852
-
853
- @override
854
- compareTo(${className} other) => name.compareTo(other.name);
855
- }`;
856
- if (additionalOptions.existingClassNames.includes(className)) {
857
- content = "";
858
- } else {
859
- additionalOptions.existingClassNames.push(className);
814
+ if (schema.isEventStream) {
815
+ return `EventSource<${responseType}> ${functionName}(
816
+ ${paramsType ? `${paramsType} params, ` : ""} {
817
+ void Function(${responseType} data, EventSource<${responseType}> connection)? onMessage,
818
+ void Function(http.StreamedResponse response, EventSource<${responseType}> connection)? onOpen,
819
+ void Function(EventSource<${responseType}> connection)? onClose,
820
+ void Function(ArriError error, EventSource<${responseType}> connection)? onError,
821
+ Duration? retryDelay,
822
+ int? maxRetryCount,
823
+ String? lastEventId,
824
+ }) {
825
+ return parsedArriSseRequest(
826
+ "$_baseUrl${schema.path}",
827
+ method: HttpMethod.${schema.method.toLowerCase()},
828
+ httpClient: _httpClient,
829
+ headers: _headers,
830
+ clientVersion: _clientVersion,
831
+ retryDelay: retryDelay,
832
+ maxRetryCount: maxRetryCount,
833
+ lastEventId: lastEventId,
834
+ ${paramsType ? "params: params.toJson()," : ""}
835
+ parser: (body) ${schema.response ? `=> ${responseType}.fromJsonString(body)` : `{}`},
836
+ onMessage: onMessage,
837
+ onOpen: onOpen,
838
+ onClose: onClose,
839
+ onError: onError,
840
+ );
841
+ }`;
860
842
  }
861
- return {
862
- typeName: className,
863
- fieldTemplate: fieldTemplateString(
864
- isNullable ? `${className}?` : className,
865
- key,
866
- def.metadata?.description,
867
- def.metadata?.isDeprecated
868
- ),
869
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
870
- fromJsonTemplate: (input) => {
871
- if (isNullable) {
872
- return `${input} is String ? ${className}.fromJson(${input}) : null`;
873
- }
874
- return `${className}.fromJson(${input})`;
875
- },
876
- toJsonTemplate: (input) => `${input}${isNullable ? "?" : ""}.value`,
877
- content
878
- };
843
+ return `Future<${responseType}> ${functionName}(${paramsType ? `${paramsType} params` : ""}) async {
844
+ return parsedArriRequest(
845
+ "$_baseUrl${schema.path}",
846
+ method: HttpMethod.${schema.method.toLowerCase()},
847
+ httpClient: _httpClient,
848
+ headers: _headers,
849
+ clientVersion: _clientVersion,
850
+ ${paramsType ? "params: params.toJson()," : ""}
851
+ parser: (body) ${schema.response ? `=> ${responseType}.fromJsonString(body)` : "{}"},
852
+ );
853
+ }`;
879
854
  }
880
- function dartMapFromJtdSchema(nodePath, def, additionalOptions) {
881
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
882
- const jsonKey = nodePath.split(".").pop() ?? "";
883
- const key = camelCaseWrapper(jsonKey);
884
- const innerType = dartTypeFromJtdSchema(`${nodePath}.Value`, def.values, {
885
- existingClassNames: additionalOptions.existingClassNames,
886
- isOptional: false
887
- });
888
- const typeName = `Map<String, ${innerType.typeName}>${isNullable ? "?" : ""}`;
889
- return {
890
- typeName: isNullable ? `Map<String, ${innerType.typeName}>?` : `Map<String, ${innerType.typeName}>`,
891
- fieldTemplate: fieldTemplateString(
892
- typeName,
893
- key,
894
- def.metadata?.description,
895
- def.metadata?.isDeprecated
896
- ),
897
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
898
- fromJsonTemplate: (input) => `${input} is Map<String, dynamic>
899
- ? (${input} as Map<String, dynamic>).map(
900
- (key, value) => MapEntry(key, ${innerType.fromJsonTemplate(
901
- "value"
902
- )}))
903
- : <String, ${innerType.typeName}>{}`,
904
- toJsonTemplate: (input) => `${input}${isNullable ? "?" : ""}.map((key, value) => MapEntry(key, ${innerType.toJsonTemplate(
905
- "value"
906
- )}))`,
907
- content: innerType.content
908
- };
855
+ function getFunctionName(instancePath) {
856
+ const parts = instancePath.split(".");
857
+ return parts.pop() ?? "";
909
858
  }
910
- function dartSealedClassFromJtdSchema(nodePath, def, additionalOptions) {
911
- const className = def.metadata?.id ? codegenUtils.pascalCase(def.metadata?.id) : codegenUtils.pascalCase(nodePath.split(".").join("_"));
912
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
913
- const jsonKey = nodePath.split(".").pop() ?? "";
914
- const key = camelCaseWrapper(jsonKey);
915
- const discriminatorJsonKey = def.discriminator;
916
- const discriminatorKey = camelCaseWrapper(def.discriminator);
917
- const fromJsonCaseParts = [];
918
- const childContentParts = [];
919
- Object.keys(def.mapping).forEach((discKeyValue) => {
920
- const childDef = def.mapping[discKeyValue];
921
- if (!codegenUtils.isSchemaFormProperties(childDef)) {
922
- return;
923
- }
924
- const child = dartClassFromJtdSchema(
925
- `${nodePath}.${camelCaseWrapper(discKeyValue.toLowerCase())}`,
926
- childDef,
927
- {
928
- parentId: className,
929
- isOptional: false,
930
- existingClassNames: additionalOptions.existingClassNames,
931
- discriminatorOptions: {
932
- discriminatorKey,
933
- discriminatorValue: discKeyValue,
934
- discriminatorParentClassName: className
935
- }
859
+ function dartWsRpcFromSchema(schema, context) {
860
+ const functionName = getFunctionName(context.instancePath);
861
+ let responseType;
862
+ let paramsType;
863
+ if (schema.response) {
864
+ responseType = `${context.modelPrefix}${validDartClassName(schema.response, context.modelPrefix)}`;
865
+ }
866
+ if (schema.params) {
867
+ paramsType = `${context.modelPrefix}${validDartClassName(schema.params, context.modelPrefix)}`;
868
+ }
869
+ return `Future<ArriWebsocketController<${responseType ?? "void"}, ${paramsType ?? "void"}>> ${functionName}() {
870
+ return arriWebsocketRequest(
871
+ "$_baseUrl${schema.path}",
872
+ headers: _headers,
873
+ clientVersion: _clientVersion,
874
+ parser: (msg) ${responseType ? `=> ${responseType}.fromJsonString(msg)` : "{}"},
875
+ serializer: (msg) ${paramsType ? "=> msg.toJsonString()" : '=> ""'},
876
+ );
877
+ }`;
878
+ }
879
+ function dartServiceFromSchema(schema, context) {
880
+ const rpcParts = [];
881
+ const subServices = [];
882
+ const subServiceParts = [];
883
+ const serviceName = getServiceName(
884
+ context.instancePath,
885
+ context.clientName
886
+ );
887
+ for (const key of Object.keys(schema)) {
888
+ const subSchema = schema[key];
889
+ if (codegenUtils.isServiceDefinition(subSchema)) {
890
+ const subSchemaResult = dartServiceFromSchema(subSchema, {
891
+ clientName: context.clientName,
892
+ modelPrefix: context.modelPrefix,
893
+ generatedTypes: context.generatedTypes,
894
+ instancePath: `${context.instancePath}.${key}`,
895
+ schemaPath: `${context.schemaPath}.${key}`
896
+ });
897
+ if (subSchemaResult) {
898
+ subServiceParts.push(subSchemaResult);
899
+ subServices.push({
900
+ key: validDartIdentifier(key),
901
+ name: getServiceName(
902
+ `${context.instancePath}.${key}`,
903
+ context.clientName
904
+ )
905
+ });
936
906
  }
937
- );
938
- fromJsonCaseParts.push(`case "${discKeyValue}":
939
- return ${child.typeName}.fromJson(json);`);
940
- childContentParts.push(child.content);
941
- });
942
- let content = "";
943
- if (!additionalOptions.existingClassNames.includes(className)) {
944
- content = `${getAnnotations(def.metadata)}sealed class ${className} {
945
- final String ${discriminatorKey};
946
- const ${className}({
947
- required this.${discriminatorKey},
948
- });
949
- factory ${className}.fromJson(Map<String, dynamic> json) {
950
- if(json["${discriminatorJsonKey}"] is! String) {
951
- throw Exception(
952
- "Unable to decode ${className}. Expected String from \\"${discriminatorJsonKey}\\". Received \${json["${discriminatorJsonKey}"]}}",
953
- );
907
+ continue;
954
908
  }
955
- switch (json["${discriminatorJsonKey}"]) {
956
- ${fromJsonCaseParts.join("\n ")}
909
+ if (codegenUtils.isRpcDefinition(subSchema)) {
910
+ const subSchemaResult = dartRpcFromSchema(subSchema, {
911
+ clientName: context.clientName,
912
+ modelPrefix: context.modelPrefix,
913
+ generatedTypes: context.generatedTypes,
914
+ instancePath: `${context.instancePath}.${key}`,
915
+ schemaPath: `${context.schemaPath}.${key}`
916
+ });
917
+ if (subSchemaResult) {
918
+ rpcParts.push(subSchemaResult);
919
+ }
920
+ continue;
957
921
  }
958
- throw Exception(
959
- "Unable to decode ${className}. \\"\${json["${discriminatorJsonKey}"]}\\" doesn't match any of the accepted discriminator values.",
922
+ console.warn(
923
+ `Unknown schema in procedures at "${context.instancePath}".`
960
924
  );
961
925
  }
962
- Map<String, dynamic> toJson();
926
+ return `class ${serviceName}{
927
+ final http.Client? _httpClient;
928
+ final String _baseUrl;
929
+ final String _clientVersion = "${context.clientVersion ?? ""}";
930
+ late final FutureOr<Map<String, String>> Function()? _headers;
931
+ ${serviceName}({
932
+ http.Client? httpClient,
933
+ required String baseUrl,
934
+ FutureOr<Map<String, String>> Function()? headers,
935
+ }) : _httpClient = httpClient,
936
+ _baseUrl = baseUrl,
937
+ _headers = headers;
938
+
939
+ ${rpcParts.join("\n\n")}
940
+
941
+ ${subServices.map(
942
+ (service) => ` ${service.name} get ${service.key} => ${service.name}(
943
+ baseUrl: _baseUrl,
944
+ headers: _headers,
945
+ httpClient: _httpClient,
946
+ );`
947
+ ).join("\n\n")}
963
948
  }
964
- ${childContentParts.join("\n")}`;
965
- additionalOptions.existingClassNames.push(className);
966
- }
967
- const typeName = `${className}${isNullable ? "?" : ""}`;
949
+ ${subServiceParts.join("\n\n")}`;
950
+ }
951
+ function getServiceName(instancePath, clientName) {
952
+ return validDartClassName(
953
+ `${clientName}_${instancePath.split(".").join("_")}_Service`,
954
+ ""
955
+ );
956
+ }
957
+
958
+ function dartMapFromSchema(schema, context) {
959
+ const isNullable = outputIsNullable(schema, context);
960
+ const innerType = dartTypeFromSchema(schema.values, {
961
+ clientName: context.clientName,
962
+ modelPrefix: context.modelPrefix,
963
+ generatedTypes: context.generatedTypes,
964
+ instancePath: `${context.instancePath}/[entry]`,
965
+ schemaPath: `${context.schemaPath}/values`
966
+ });
967
+ const typeName = isNullable ? `Map<String, ${innerType.typeName}>?` : `Map<String, ${innerType.typeName}>`;
968
+ const defaultValue = isNullable ? "null" : "{}";
968
969
  return {
969
970
  typeName,
970
- fieldTemplate: fieldTemplateString(
971
- typeName,
972
- key,
973
- def.metadata?.description,
974
- def.metadata?.isDeprecated
975
- ),
976
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
977
- fromJsonTemplate: (input) => {
971
+ isNullable,
972
+ defaultValue,
973
+ fromJson(input) {
978
974
  if (isNullable) {
979
- return `${input} is Map<String, dynamic> ? ${className}.fromJson(${input}) : null`;
975
+ return `${input} is Map<String, dynamic>
976
+ ? (${input} as Map<String, dynamic>).map(
977
+ (_key_, _val_) => MapEntry(
978
+ _key_,
979
+ ${innerType.fromJson("_val_")},
980
+ ),
981
+ )
982
+ : null`;
980
983
  }
981
- return `${className}.fromJson(${input})`;
984
+ return `${input} is Map<String, dynamic>
985
+ ? (${input} as Map<String, dynamic>).map(
986
+ (_key_, _val_) => MapEntry(
987
+ _key_,
988
+ ${innerType.fromJson("_val_")},
989
+ ),
990
+ )
991
+ : <String, ${innerType.typeName}>{}`;
982
992
  },
983
- toJsonTemplate: (input) => {
984
- if (isNullable) {
985
- return `${input}?.toJson()`;
993
+ toJson(input) {
994
+ if (context.isOptional) {
995
+ return `${input}!.map((_key_, _val_) => MapEntry(_key_, ${innerType.toJson("_val_", "", "")},),)`;
986
996
  }
987
- return `${input}.toJson()`;
997
+ if (schema.nullable) {
998
+ return `${input}?.map((_key_, _val_) => MapEntry(_key_, ${innerType.toJson("_val_", "", "")},),)`;
999
+ }
1000
+ return `${input}.map((_key_, _val_) => MapEntry(_key_, ${innerType.toJson("_val_", "", "")},),)`;
1001
+ },
1002
+ toQueryString() {
1003
+ return `print(
1004
+ "[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
988
1005
  },
989
- content
1006
+ content: innerType.content
990
1007
  };
991
1008
  }
992
- function dartRefFromJtdSchema(nodePath, def, additionalOptions) {
993
- const jsonKey = nodePath.split(".").pop() ?? "";
994
- const key = camelCaseWrapper(jsonKey);
995
- const className = codegenUtils.pascalCase(def.ref, { normalize: true });
996
- const isNullable = additionalOptions.isOptional || (def.nullable ?? false);
997
- const typeName = `${className}${isNullable ? "?" : ""}`;
1009
+
1010
+ function dartRefFromSchema(schema, context) {
1011
+ const isNullable = outputIsNullable(schema, context);
1012
+ const className = sanitizeIdentifier(
1013
+ codegenUtils.pascalCase(schema.ref, { normalize: true })
1014
+ );
1015
+ const finalClassName = `${context.modelPrefix}${className}`;
1016
+ const typeName = isNullable ? `${finalClassName}?` : finalClassName;
1017
+ const defaultValue = isNullable ? `null` : `${finalClassName}.empty()`;
998
1018
  return {
999
1019
  typeName,
1000
- fieldTemplate: fieldTemplateString(
1001
- typeName,
1002
- key,
1003
- def.metadata?.description,
1004
- def.metadata?.isDeprecated
1005
- ),
1006
- constructorTemplate: additionalOptions.isOptional ? `this.${key}` : `required this.${key}`,
1007
- fromJsonTemplate(input) {
1020
+ isNullable,
1021
+ defaultValue,
1022
+ fromJson(input) {
1008
1023
  if (isNullable) {
1009
- return `${input} is Map<String, dynamic> ? ${className}.fromJson(${input}) : null`;
1024
+ return `${input} is Map<String, dynamic>
1025
+ ? ${finalClassName}.fromJson(${input})
1026
+ : null`;
1010
1027
  }
1011
- return `${className}.fromJson(${input})`;
1028
+ return `${input} is Map<String, dynamic>
1029
+ ? ${finalClassName}.fromJson(${input})
1030
+ : ${finalClassName}.empty()`;
1012
1031
  },
1013
- toJsonTemplate(input) {
1014
- if (isNullable) {
1032
+ toJson(input) {
1033
+ if (context.isOptional) {
1034
+ return `${input}!.toJson()`;
1035
+ }
1036
+ if (schema.nullable) {
1015
1037
  return `${input}?.toJson()`;
1016
1038
  }
1017
1039
  return `${input}.toJson()`;
1018
1040
  },
1041
+ toQueryString() {
1042
+ return `print(
1043
+ "[WARNING] nested objects cannot be serialized to query params. Skipping field at ${context.instancePath}.")`;
1044
+ },
1019
1045
  content: ""
1020
1046
  };
1021
1047
  }
1022
1048
 
1023
- exports.DartClientGenerator = DartClientGenerator;
1049
+ const dartClientGenerator = codegenUtils.defineGeneratorPlugin(
1050
+ (options) => {
1051
+ return {
1052
+ async generator(def) {
1053
+ if (!options.outputFile) {
1054
+ throw new Error(
1055
+ 'Missing "outputFile" cannot generate dart code'
1056
+ );
1057
+ }
1058
+ try {
1059
+ const result = createDartClient(def, options);
1060
+ const destination = path__default.resolve(options.outputFile);
1061
+ await fs__default.writeFile(destination, result);
1062
+ if (options.format !== false) {
1063
+ node_child_process.execSync(`dart format ${destination}`, {
1064
+ stdio: "inherit"
1065
+ });
1066
+ }
1067
+ } catch (err) {
1068
+ console.error(err);
1069
+ }
1070
+ },
1071
+ options
1072
+ };
1073
+ }
1074
+ );
1075
+ function createDartClient(def, options) {
1076
+ const typeParts = [];
1077
+ const context = {
1078
+ clientName: options.clientName ?? "Client",
1079
+ modelPrefix: options.modelPrefix ?? "",
1080
+ generatedTypes: [],
1081
+ instancePath: "",
1082
+ schemaPath: "",
1083
+ clientVersion: def.info?.version
1084
+ };
1085
+ const services = codegenUtils.unflattenProcedures(def.procedures);
1086
+ const subServices = [];
1087
+ const subServiceParts = [];
1088
+ const rpcParts = [];
1089
+ for (const key of Object.keys(services)) {
1090
+ const subSchema = services[key];
1091
+ if (codegenUtils.isServiceDefinition(subSchema)) {
1092
+ const service = dartServiceFromSchema(subSchema, {
1093
+ clientName: context.clientName,
1094
+ modelPrefix: context.modelPrefix,
1095
+ generatedTypes: context.generatedTypes,
1096
+ instancePath: key,
1097
+ schemaPath: `procedures.${key}`,
1098
+ clientVersion: context.clientVersion
1099
+ });
1100
+ if (service) {
1101
+ subServiceParts.push(service);
1102
+ subServices.push({
1103
+ key: validDartIdentifier(key),
1104
+ name: getServiceName(key, context.clientName)
1105
+ });
1106
+ }
1107
+ continue;
1108
+ }
1109
+ if (codegenUtils.isRpcDefinition(subSchema)) {
1110
+ const rpc = dartRpcFromSchema(subSchema, {
1111
+ clientName: context.clientName,
1112
+ modelPrefix: context.modelPrefix,
1113
+ generatedTypes: context.generatedTypes,
1114
+ instancePath: key,
1115
+ schemaPath: `procedures.${key}`
1116
+ });
1117
+ if (rpc) {
1118
+ rpcParts.push(rpc);
1119
+ }
1120
+ continue;
1121
+ }
1122
+ console.warn(`Unknown schema in procedures at "${key}"`);
1123
+ }
1124
+ for (const key of Object.keys(def.definitions)) {
1125
+ const subDef = def.definitions[key];
1126
+ const result = dartTypeFromSchema(subDef, {
1127
+ clientName: context.clientName,
1128
+ modelPrefix: context.modelPrefix,
1129
+ generatedTypes: context.generatedTypes,
1130
+ instancePath: `/${key}`,
1131
+ schemaPath: `/${key}`
1132
+ });
1133
+ if (result.content) {
1134
+ typeParts.push(result.content);
1135
+ }
1136
+ }
1137
+ if (rpcParts.length === 0 && subServiceParts.length === 0) {
1138
+ const heading = `// this file was autogenerated by arri
1139
+ // ignore_for_file: type=lint, unused_field, unnecessary_cast
1140
+ import 'dart:convert';
1141
+ import 'package:arri_client/arri_client.dart';`;
1142
+ return `${heading}
1143
+
1144
+ ${typeParts.join("\n\n")}`;
1145
+ }
1146
+ const clientName = validDartClassName(context.clientName, "");
1147
+ return `// this file was autogenerated by arri
1148
+ // ignore_for_file: type=lint, unused_field, unnecessary_cast
1149
+ import 'dart:async';
1150
+ import 'dart:convert';
1151
+ import 'package:arri_client/arri_client.dart';
1152
+ import 'package:http/http.dart' as http;
1153
+
1154
+ class ${clientName} {
1155
+ final http.Client? _httpClient;
1156
+ final String _baseUrl;
1157
+ final String _clientVersion = "${context.clientVersion ?? ""}";
1158
+ late final FutureOr<Map<String, String>> Function()? _headers;
1159
+ ${clientName}({
1160
+ http.Client? httpClient,
1161
+ required String baseUrl,
1162
+ FutureOr<Map<String, String>> Function()? headers,
1163
+ }) : _httpClient = httpClient,
1164
+ _baseUrl = baseUrl,
1165
+ _headers = headers;
1166
+
1167
+ ${rpcParts.join("\n\n")}
1168
+
1169
+ ${subServices.map(
1170
+ (service) => ` ${service.name} get ${service.key} => ${service.name}(
1171
+ baseUrl: _baseUrl,
1172
+ headers: _headers,
1173
+ httpClient: _httpClient,
1174
+ );`
1175
+ ).join("\n\n")}
1176
+ }
1177
+
1178
+ ${subServiceParts.join("\n\n")}
1179
+
1180
+ ${typeParts.join("\n\n")}`;
1181
+ }
1182
+ function dartTypeFromSchema(schema, context) {
1183
+ if (codegenUtils.isSchemaFormType(schema)) {
1184
+ switch (schema.type) {
1185
+ case "string":
1186
+ return dartStringFromSchema(schema, context);
1187
+ case "boolean":
1188
+ return dartBoolFromSchema(schema, context);
1189
+ case "timestamp":
1190
+ return dartDateTimeFromSchema(schema, context);
1191
+ case "float32":
1192
+ case "float64":
1193
+ return dartDoubleFromSchema(schema, context);
1194
+ case "int8":
1195
+ case "uint8":
1196
+ case "int16":
1197
+ case "uint16":
1198
+ case "int32":
1199
+ case "uint32":
1200
+ return dartIntFromSchema(schema, context);
1201
+ case "int64":
1202
+ case "uint64":
1203
+ return dartBigIntFromSchema(schema, context);
1204
+ default:
1205
+ schema.type;
1206
+ throw new Error(`Unhandled schema.type ${schema.type}`);
1207
+ }
1208
+ }
1209
+ if (codegenUtils.isSchemaFormEnum(schema)) {
1210
+ return dartEnumFromSchema(schema, context);
1211
+ }
1212
+ if (codegenUtils.isSchemaFormProperties(schema)) {
1213
+ return dartClassFromSchema(schema, context);
1214
+ }
1215
+ if (codegenUtils.isSchemaFormElements(schema)) {
1216
+ return dartListFromSchema(schema, context);
1217
+ }
1218
+ if (codegenUtils.isSchemaFormValues(schema)) {
1219
+ return dartMapFromSchema(schema, context);
1220
+ }
1221
+ if (codegenUtils.isSchemaFormDiscriminator(schema)) {
1222
+ return dartSealedClassFromSchema(schema, context);
1223
+ }
1224
+ if (codegenUtils.isSchemaFormRef(schema)) {
1225
+ return dartRefFromSchema(schema, context);
1226
+ }
1227
+ return dartAnyFromSchema(schema, context);
1228
+ }
1229
+
1024
1230
  exports.createDartClient = createDartClient;
1025
- exports.dartClassFromJtdSchema = dartClassFromJtdSchema;
1026
1231
  exports.dartClientGenerator = dartClientGenerator;
1027
- exports.dartHttpRpcFromSchema = dartHttpRpcFromSchema;
1028
- exports.dartRpcFromDefinition = dartRpcFromDefinition;
1029
- exports.dartServiceFromDefinition = dartServiceFromDefinition;
1030
- exports.dartTypeFromJtdSchema = dartTypeFromJtdSchema;
1031
- exports.dartWsRpcFromSchema = dartWsRpcFromSchema;
1032
- exports.getAnnotations = getAnnotations;
1232
+ exports.dartTypeFromSchema = dartTypeFromSchema;