@arrirpc/codegen-ts 0.55.0 → 0.57.2
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 +1118 -758
- package/dist/index.d.cts +29 -40
- package/dist/index.d.mts +29 -40
- package/dist/index.d.ts +29 -40
- package/dist/index.mjs +1119 -744
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,316 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getSchemaParsingCode, getSchemaSerializationCode } from '@arrirpc/schema';
|
|
1
|
+
import { stringStartsWithNumber, removeDisallowedChars, pascalCase, camelCase, isServiceDefinition, isRpcDefinition, defineGeneratorPlugin, unflattenProcedures, isSchemaFormType, isSchemaFormEnum, isSchemaFormProperties, isSchemaFormElements, isSchemaFormValues, isSchemaFormDiscriminator, isSchemaFormRef } from '@arrirpc/codegen-utils';
|
|
3
2
|
import { writeFileSync } from 'fs';
|
|
4
3
|
import prettier from 'prettier';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!options.clientName) {
|
|
10
|
-
throw new Error("Name is requires");
|
|
11
|
-
}
|
|
12
|
-
if (!options.outputFile) {
|
|
13
|
-
throw new Error("No output file specified");
|
|
14
|
-
}
|
|
15
|
-
if (Object.keys(def.procedures).length <= 0) {
|
|
16
|
-
console.warn(
|
|
17
|
-
`No procedures defined in AppDefinition. Only data models will be outputted.`
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
const result = await createTypescriptClient(def, options);
|
|
21
|
-
writeFileSync(options.outputFile, result);
|
|
22
|
-
},
|
|
23
|
-
options
|
|
24
|
-
})
|
|
25
|
-
);
|
|
26
|
-
async function createTypescriptClient(def, options) {
|
|
27
|
-
const clientName = pascalCase(options.clientName);
|
|
28
|
-
const services = unflattenProcedures(def.procedures);
|
|
29
|
-
const serviceFieldParts = [];
|
|
30
|
-
const serviceInitializationParts = [];
|
|
31
|
-
const procedureParts = [];
|
|
32
|
-
const subContentParts = [];
|
|
33
|
-
const existingTypeNames = [];
|
|
34
|
-
const rpcOptions = {
|
|
35
|
-
...options,
|
|
36
|
-
versionNumber: def.info?.version ?? "",
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
38
|
-
typesNeedingParser: Object.keys(def.definitions),
|
|
39
|
-
hasSseProcedures: false,
|
|
40
|
-
hasWsProcedures: false
|
|
41
|
-
};
|
|
42
|
-
Object.keys(services).forEach((key) => {
|
|
43
|
-
const item = services[key];
|
|
44
|
-
if (isRpcDefinition(item)) {
|
|
45
|
-
const rpc = tsRpcFromDefinition(key, item, rpcOptions);
|
|
46
|
-
if (rpc) {
|
|
47
|
-
procedureParts.push(rpc);
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (isServiceDefinition(item)) {
|
|
52
|
-
const serviceName = pascalCase(`${clientName}_${key}`);
|
|
53
|
-
const service = tsServiceFromDefinition(
|
|
54
|
-
serviceName,
|
|
55
|
-
item,
|
|
56
|
-
rpcOptions
|
|
57
|
-
);
|
|
58
|
-
serviceFieldParts.push(`${key}: ${serviceName}Service;`);
|
|
59
|
-
serviceInitializationParts.push(
|
|
60
|
-
`this.${key} = new ${serviceName}Service(options);`
|
|
61
|
-
);
|
|
62
|
-
subContentParts.push(service);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
for (const key of rpcOptions.typesNeedingParser) {
|
|
66
|
-
const schema = def.definitions[key];
|
|
67
|
-
if (isSchemaFormProperties(schema) || isSchemaFormDiscriminator(schema)) {
|
|
68
|
-
const type = tsTypeFromJtdSchema(key, schema, rpcOptions, {
|
|
69
|
-
isOptional: false,
|
|
70
|
-
existingTypeNames
|
|
71
|
-
});
|
|
72
|
-
subContentParts.push(type.content);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const importParts = ["arriRequest"];
|
|
76
|
-
if (rpcOptions.hasSseProcedures) {
|
|
77
|
-
importParts.push("arriSseRequest");
|
|
78
|
-
importParts.push("type SseOptions");
|
|
79
|
-
importParts.push("type EventSourceController");
|
|
80
|
-
}
|
|
81
|
-
if (rpcOptions.hasWsProcedures) {
|
|
82
|
-
importParts.push("arriWsRequest");
|
|
83
|
-
importParts.push("type WsOptions");
|
|
84
|
-
}
|
|
85
|
-
if (procedureParts.length === 0 && serviceFieldParts.length === 0) {
|
|
86
|
-
const result2 = `/* eslint-disable */
|
|
87
|
-
// @ts-nocheck
|
|
88
|
-
// this file was autogenerated by arri-codegen-ts
|
|
89
|
-
|
|
90
|
-
${subContentParts.join("\n")}`;
|
|
91
|
-
return prettier.format(result2, {
|
|
92
|
-
parser: "typescript",
|
|
93
|
-
...options.prettierOptions
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
const result = `/* eslint-disable */
|
|
97
|
-
// @ts-nocheck
|
|
98
|
-
// this file was autogenerated by arri-codegen-ts
|
|
99
|
-
import { ${importParts.join(", ")} } from '@arrirpc/client';
|
|
100
|
-
|
|
101
|
-
interface ${clientName}Options {
|
|
102
|
-
baseUrl?: string;
|
|
103
|
-
headers?: Record<string, string | undefined> | (() => Record<string, string | undefined> | Promise<Record<string, string | undefined>>);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export class ${clientName} {
|
|
107
|
-
private readonly baseUrl: string;
|
|
108
|
-
private readonly headers: Record<string, string | undefined> | (() => Record<string, string | undefined> | Promise<Record<string, string | undefined>>)
|
|
109
|
-
private readonly clientVersion = '${rpcOptions.versionNumber}';
|
|
110
|
-
${serviceFieldParts.join("\n ")}
|
|
111
|
-
|
|
112
|
-
constructor(options: ${clientName}Options = {}) {
|
|
113
|
-
this.baseUrl = options.baseUrl ?? "";
|
|
114
|
-
this.headers = options.headers ?? {};
|
|
115
|
-
${serviceInitializationParts.join(";\n ")}
|
|
116
|
-
}
|
|
117
|
-
${procedureParts.join("\n ")}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
${subContentParts.join("\n")}
|
|
121
|
-
`;
|
|
122
|
-
return await prettier.format(result, {
|
|
123
|
-
parser: "typescript",
|
|
124
|
-
...options.prettierOptions
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function tsRpcFromDefinition(key, schema, options) {
|
|
128
|
-
if (schema.transport === "http") {
|
|
129
|
-
return tsHttpRpcFromDefinition(key, schema, options);
|
|
130
|
-
}
|
|
131
|
-
if (schema.transport === "ws") {
|
|
132
|
-
return tsWsRpcFromDefinition(key, schema, options);
|
|
133
|
-
}
|
|
134
|
-
console.warn(
|
|
135
|
-
`[codegen-ts] Unsupported transport "${schema.transport}". Ignoring rpc.`
|
|
136
|
-
);
|
|
137
|
-
return "";
|
|
138
|
-
}
|
|
139
|
-
function tsHttpRpcFromDefinition(key, schema, options) {
|
|
140
|
-
const paramName = pascalCase(schema.params ?? "");
|
|
141
|
-
const responseName = pascalCase(schema.response ?? "");
|
|
142
|
-
const paramsInput = schema.params ? `params: ${paramName}` : "";
|
|
143
|
-
const hasInput = paramName.length > 0;
|
|
144
|
-
const hasOutput = responseName.length > 0;
|
|
145
|
-
let serializerPart = `(_) => {}`;
|
|
146
|
-
let parserPart = `(_) => {}`;
|
|
147
|
-
if (hasInput) {
|
|
148
|
-
serializerPart = `$$${paramName}.serialize`;
|
|
149
|
-
}
|
|
150
|
-
if (hasOutput) {
|
|
151
|
-
parserPart = `$$${responseName}.parse`;
|
|
152
|
-
}
|
|
153
|
-
const paramsOutput = hasInput ? `params` : `params: undefined`;
|
|
154
|
-
if (schema.isEventStream) {
|
|
155
|
-
options.hasSseProcedures = true;
|
|
156
|
-
return `${getJsDocComment({ isDeprecated: schema.isDeprecated, description: schema.description })}${key}(${paramsInput.length ? `${paramsInput}, ` : ""}options: SseOptions<${schema.response ?? "undefined"}>): EventSourceController {
|
|
157
|
-
return arriSseRequest<${schema.response ?? "undefined"}, ${schema.params ?? "undefined"}>({
|
|
158
|
-
url: \`\${this.baseUrl}${schema.path}\`,
|
|
159
|
-
method: "${schema.method}",
|
|
160
|
-
headers: this.headers,
|
|
161
|
-
${paramsOutput},
|
|
162
|
-
parser: ${parserPart},
|
|
163
|
-
serializer: ${serializerPart},
|
|
164
|
-
clientVersion: this.clientVersion,
|
|
165
|
-
}, options);
|
|
166
|
-
}`;
|
|
167
|
-
}
|
|
168
|
-
return `${getJsDocComment({ isDeprecated: schema.isDeprecated, description: schema.description })}${key}(${paramsInput}) {
|
|
169
|
-
return arriRequest<${schema.response ?? "undefined"}, ${schema.params ?? "undefined"}>({
|
|
170
|
-
url: \`\${this.baseUrl}${schema.path}\`,
|
|
171
|
-
method: "${schema.method}",
|
|
172
|
-
headers: this.headers,
|
|
173
|
-
${paramsOutput},
|
|
174
|
-
parser: ${parserPart},
|
|
175
|
-
serializer: ${serializerPart},
|
|
176
|
-
clientVersion: this.clientVersion,
|
|
177
|
-
});
|
|
178
|
-
}`;
|
|
179
|
-
}
|
|
180
|
-
function tsWsRpcFromDefinition(key, schema, options) {
|
|
181
|
-
options.hasWsProcedures = true;
|
|
182
|
-
const paramName = schema.params ? pascalCase(schema.params) : "undefined";
|
|
183
|
-
const responseName = schema.response ? pascalCase(schema.response) : "undefined";
|
|
184
|
-
const hasInput = paramName.length > 0 && paramName !== "undefined";
|
|
185
|
-
const hasOutput = responseName.length > 0 && paramName !== "undefined";
|
|
186
|
-
let serializerPart = `(_) => {}`;
|
|
187
|
-
let parserPart = `(_) => {}`;
|
|
188
|
-
if (hasInput) {
|
|
189
|
-
serializerPart = `$$${paramName}.serialize`;
|
|
190
|
-
}
|
|
191
|
-
if (hasOutput) {
|
|
192
|
-
parserPart = `$$${responseName}.parse`;
|
|
193
|
-
}
|
|
194
|
-
return `${getJsDocComment(schema)}${key}(options: WsOptions<${responseName}> = {}) {
|
|
195
|
-
return arriWsRequest<${paramName}, ${responseName}>({
|
|
196
|
-
url: \`\${this.baseUrl}${schema.path}\`,
|
|
197
|
-
headers: this.headers,
|
|
198
|
-
parser: ${parserPart},
|
|
199
|
-
serializer: ${serializerPart},
|
|
200
|
-
onOpen: options.onOpen,
|
|
201
|
-
onClose: options.onClose,
|
|
202
|
-
onError: options.onError,
|
|
203
|
-
onConnectionError: options.onConnectionError,
|
|
204
|
-
onMessage: options.onMessage,
|
|
205
|
-
clientVersion: this.clientVersion,
|
|
206
|
-
})
|
|
207
|
-
}`;
|
|
208
|
-
}
|
|
209
|
-
function tsServiceFromDefinition(name, schema, options) {
|
|
210
|
-
const serviceFieldParts = [];
|
|
211
|
-
const serviceConstructorParts = [];
|
|
212
|
-
const subServiceContent = [];
|
|
213
|
-
const rpcContent = [];
|
|
214
|
-
Object.keys(schema).forEach((key) => {
|
|
215
|
-
const def = schema[key];
|
|
216
|
-
if (isRpcDefinition(def)) {
|
|
217
|
-
const rpc = tsRpcFromDefinition(key, def, options);
|
|
218
|
-
if (rpc) {
|
|
219
|
-
rpcContent.push(rpc);
|
|
220
|
-
}
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
if (isServiceDefinition(def)) {
|
|
224
|
-
const serviceName = pascalCase(`${name}_${key}`);
|
|
225
|
-
const service = tsServiceFromDefinition(serviceName, def, options);
|
|
226
|
-
serviceFieldParts.push(`${key}: ${serviceName}Service;`);
|
|
227
|
-
serviceConstructorParts.push(
|
|
228
|
-
`this.${key} = new ${serviceName}Service(options);`
|
|
229
|
-
);
|
|
230
|
-
subServiceContent.push(service);
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
return `export class ${name}Service {
|
|
234
|
-
private readonly baseUrl: string;
|
|
235
|
-
private readonly headers: Record<string, string | undefined> | (() => Record<string, string | undefined> | Promise<Record<string, string | undefined>>);
|
|
236
|
-
private readonly clientVersion = '${options.versionNumber}';
|
|
237
|
-
${serviceFieldParts.join("\n ")}
|
|
238
|
-
|
|
239
|
-
constructor(options: ${pascalCase(
|
|
240
|
-
`${options.clientName}_Options`
|
|
241
|
-
)} = {}) {
|
|
242
|
-
this.baseUrl = options.baseUrl ?? '';
|
|
243
|
-
this.headers = options.headers ?? {};
|
|
244
|
-
${serviceConstructorParts.join("\n ")}
|
|
245
|
-
}
|
|
246
|
-
${rpcContent.join("\n ")}
|
|
247
|
-
}
|
|
248
|
-
${subServiceContent.join("\n")}`;
|
|
249
|
-
}
|
|
250
|
-
function tsTypeFromJtdSchema(nodePath, def, options, additionalOptions) {
|
|
251
|
-
if (additionalOptions.logDef) {
|
|
252
|
-
console.log(def);
|
|
253
|
-
}
|
|
254
|
-
if (isSchemaFormType(def)) {
|
|
255
|
-
return tsScalarFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
256
|
-
}
|
|
257
|
-
if (isSchemaFormProperties(def)) {
|
|
258
|
-
return tsObjectFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
259
|
-
}
|
|
260
|
-
if (isSchemaFormEnum(def)) {
|
|
261
|
-
return tsEnumFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
262
|
-
}
|
|
263
|
-
if (isSchemaFormElements(def)) {
|
|
264
|
-
return tsArrayFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
265
|
-
}
|
|
266
|
-
if (isSchemaFormDiscriminator(def)) {
|
|
267
|
-
return tsDiscriminatedUnionFromJtdSchema(
|
|
268
|
-
nodePath,
|
|
269
|
-
def,
|
|
270
|
-
options,
|
|
271
|
-
additionalOptions
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
if (isSchemaFormValues(def)) {
|
|
275
|
-
return tsRecordFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
276
|
-
}
|
|
277
|
-
if (isSchemaFormRef(def)) {
|
|
278
|
-
return tsRefFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
279
|
-
}
|
|
280
|
-
return tsAnyFromJtdSchema(nodePath, def, options, additionalOptions);
|
|
281
|
-
}
|
|
282
|
-
function maybeOptionalKey(keyName, isOptional = false) {
|
|
283
|
-
if (isOptional) {
|
|
284
|
-
return `${keyName}?`;
|
|
285
|
-
}
|
|
286
|
-
return keyName;
|
|
287
|
-
}
|
|
288
|
-
function maybeNullType(typeName, isNullable = false) {
|
|
289
|
-
if (isNullable) {
|
|
290
|
-
return `${typeName} | null`;
|
|
291
|
-
}
|
|
292
|
-
return typeName;
|
|
293
|
-
}
|
|
294
|
-
function tsAnyFromJtdSchema(nodePath, def, options, additionalOptions) {
|
|
295
|
-
const key = nodePath.split(".").pop() ?? "";
|
|
296
|
-
const isNullable = def.nullable ?? false;
|
|
297
|
-
const isOptional = additionalOptions.isOptional;
|
|
5
|
+
function tsAnyFromSchema(schema, context) {
|
|
6
|
+
const typeName = "any";
|
|
7
|
+
const defaultValue = schema.nullable ? "null" : "undefined";
|
|
298
8
|
return {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
"
|
|
303
|
-
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
9
|
+
typeName,
|
|
10
|
+
defaultValue,
|
|
11
|
+
validationTemplate(_) {
|
|
12
|
+
return "true";
|
|
13
|
+
},
|
|
14
|
+
fromJsonTemplate(input, target) {
|
|
15
|
+
return `${target} = ${input}`;
|
|
16
|
+
},
|
|
17
|
+
toJsonTemplate(input, target) {
|
|
18
|
+
return `${target} += JSON.stringify(${input})`;
|
|
19
|
+
},
|
|
20
|
+
toQueryStringTemplate(_input, _target, _key) {
|
|
21
|
+
return `console.warn("[WARNING] Cannot serialize any's to query string. Skipping property at ${context.instancePath}.")`;
|
|
310
22
|
},
|
|
311
23
|
content: ""
|
|
312
24
|
};
|
|
313
25
|
}
|
|
26
|
+
|
|
314
27
|
function getJsDocComment(metadata) {
|
|
315
28
|
const descriptionParts = [];
|
|
316
29
|
if (metadata?.description?.length) {
|
|
@@ -330,507 +43,1169 @@ ${descriptionParts.join("\n")}
|
|
|
330
43
|
*/
|
|
331
44
|
`;
|
|
332
45
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
switch (def.type) {
|
|
338
|
-
case "boolean":
|
|
339
|
-
return {
|
|
340
|
-
tsType: "boolean",
|
|
341
|
-
schema: def,
|
|
342
|
-
fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
|
|
343
|
-
key,
|
|
344
|
-
isOptional
|
|
345
|
-
)}: ${maybeNullType("boolean", isNullable)}`,
|
|
346
|
-
fromJsonTemplate(input) {
|
|
347
|
-
if (isOptional) {
|
|
348
|
-
return `typeof ${input} === 'boolean' ? ${input} : undefined`;
|
|
349
|
-
}
|
|
350
|
-
if (isNullable) {
|
|
351
|
-
return `typeof ${input} === 'boolean' ? ${input} : null`;
|
|
352
|
-
}
|
|
353
|
-
return `typeof ${input} === 'boolean' ? ${input} : false`;
|
|
354
|
-
},
|
|
355
|
-
toJsonTemplate(input) {
|
|
356
|
-
if (isNullable) {
|
|
357
|
-
return `typeof ${input} === 'boolean' ? ${input} : null`;
|
|
358
|
-
}
|
|
359
|
-
return `typeof ${input} === 'boolean' ? ${input} : false`;
|
|
360
|
-
},
|
|
361
|
-
content: ""
|
|
362
|
-
};
|
|
363
|
-
case "string":
|
|
364
|
-
return {
|
|
365
|
-
tsType: "string",
|
|
366
|
-
schema: def,
|
|
367
|
-
fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
|
|
368
|
-
key,
|
|
369
|
-
isOptional
|
|
370
|
-
)}: ${maybeNullType("string", isNullable)}`,
|
|
371
|
-
fromJsonTemplate(input) {
|
|
372
|
-
if (isOptional) {
|
|
373
|
-
return `typeof ${input} === 'string' ? ${input} : undefined`;
|
|
374
|
-
}
|
|
375
|
-
if (isNullable) {
|
|
376
|
-
return `typeof ${input} === 'string' ? ${input} : null`;
|
|
377
|
-
}
|
|
378
|
-
return `typeof ${input} === 'string' ? ${input} : ''`;
|
|
379
|
-
},
|
|
380
|
-
toJsonTemplate(input) {
|
|
381
|
-
if (isNullable) {
|
|
382
|
-
return `typeof ${input} === 'string' ? \`"${input}"\` : null`;
|
|
383
|
-
}
|
|
384
|
-
return `typeof ${input} === 'string' ? \`"${input}"\` : ""`;
|
|
385
|
-
},
|
|
386
|
-
content: ""
|
|
387
|
-
};
|
|
388
|
-
case "timestamp":
|
|
389
|
-
return {
|
|
390
|
-
tsType: "Date",
|
|
391
|
-
schema: def,
|
|
392
|
-
fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
|
|
393
|
-
key,
|
|
394
|
-
isOptional
|
|
395
|
-
)}: ${maybeNullType("Date", isNullable)}`,
|
|
396
|
-
fromJsonTemplate(input) {
|
|
397
|
-
if (isOptional) {
|
|
398
|
-
return `typeof ${input} === 'string' ? new Date(${input}) : undefined`;
|
|
399
|
-
}
|
|
400
|
-
if (isNullable) {
|
|
401
|
-
return `typeof ${input} === 'string' ? new Date(${input}) : null`;
|
|
402
|
-
}
|
|
403
|
-
return `typeof ${input} === 'string' ? new Date(${input}) : new Date(0)`;
|
|
404
|
-
},
|
|
405
|
-
toJsonTemplate(input) {
|
|
406
|
-
if (isOptional || isNullable) {
|
|
407
|
-
return `typeof ${input} === 'object' && ${input} instanceof Date ? "${input}.toISOString()" : null`;
|
|
408
|
-
}
|
|
409
|
-
return `"${input}.toISOString()"`;
|
|
410
|
-
},
|
|
411
|
-
content: ""
|
|
412
|
-
};
|
|
413
|
-
case "float32":
|
|
414
|
-
case "float64":
|
|
415
|
-
case "int8":
|
|
416
|
-
case "int16":
|
|
417
|
-
case "int32":
|
|
418
|
-
case "uint8":
|
|
419
|
-
case "uint16":
|
|
420
|
-
case "uint32":
|
|
421
|
-
return {
|
|
422
|
-
tsType: "number",
|
|
423
|
-
schema: def,
|
|
424
|
-
fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
|
|
425
|
-
key,
|
|
426
|
-
isOptional
|
|
427
|
-
)}: ${maybeNullType("number", isNullable)}`,
|
|
428
|
-
fromJsonTemplate(input) {
|
|
429
|
-
if (isOptional) {
|
|
430
|
-
return `typeof ${input} === 'number' ? ${input} : undefined`;
|
|
431
|
-
}
|
|
432
|
-
if (isNullable) {
|
|
433
|
-
return `typeof ${input} === 'number' ? ${input} : null`;
|
|
434
|
-
}
|
|
435
|
-
return `typeof ${input} === 'number' ? ${input} : 0`;
|
|
436
|
-
},
|
|
437
|
-
toJsonTemplate(input) {
|
|
438
|
-
return `JSON.stringify(${input})`;
|
|
439
|
-
},
|
|
440
|
-
content: ""
|
|
441
|
-
};
|
|
442
|
-
case "int64":
|
|
443
|
-
case "uint64":
|
|
444
|
-
return {
|
|
445
|
-
tsType: "bigint",
|
|
446
|
-
schema: def,
|
|
447
|
-
fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
|
|
448
|
-
key,
|
|
449
|
-
isOptional
|
|
450
|
-
)}: ${maybeNullType("bigint", isNullable)}`,
|
|
451
|
-
fromJsonTemplate(input) {
|
|
452
|
-
if (isOptional) {
|
|
453
|
-
return `typeof ${input} === 'string' ? BigInt(${input}) : undefined`;
|
|
454
|
-
}
|
|
455
|
-
if (isNullable) {
|
|
456
|
-
return `typeof ${input} === 'string' ? BigInt(${input}) : null`;
|
|
457
|
-
}
|
|
458
|
-
return `typeof ${input} === 'string' ? BigInt(${input}) : BigInt("0")`;
|
|
459
|
-
},
|
|
460
|
-
toJsonTemplate(input) {
|
|
461
|
-
if (isOptional || isNullable) {
|
|
462
|
-
return `${input}?.toString()`;
|
|
463
|
-
}
|
|
464
|
-
return `${input}.toString()`;
|
|
465
|
-
},
|
|
466
|
-
content: ""
|
|
467
|
-
};
|
|
468
|
-
default:
|
|
469
|
-
def.type;
|
|
470
|
-
throw new Error(`Invalid type in SchemaFormType`);
|
|
46
|
+
const illegalChars = "!#^&*()-+=?/][{}|\\~`'\"";
|
|
47
|
+
function validVarName(name) {
|
|
48
|
+
if (stringStartsWithNumber(name)) {
|
|
49
|
+
return `_${removeDisallowedChars(name, illegalChars)}`;
|
|
471
50
|
}
|
|
51
|
+
return removeDisallowedChars(name, illegalChars);
|
|
472
52
|
}
|
|
473
|
-
function
|
|
474
|
-
if (
|
|
475
|
-
|
|
53
|
+
function getTsTypeName(schema, context) {
|
|
54
|
+
if (schema.metadata?.id) {
|
|
55
|
+
const name2 = pascalCase(schema.metadata.id, { normalize: true });
|
|
56
|
+
return validVarName(name2);
|
|
476
57
|
}
|
|
477
|
-
|
|
58
|
+
if (context.discriminatorParent && context.discriminatorValue) {
|
|
59
|
+
const name2 = pascalCase(
|
|
60
|
+
`${context.discriminatorParent}_${context.discriminatorValue}`,
|
|
61
|
+
{ normalize: true }
|
|
62
|
+
);
|
|
63
|
+
return validVarName(name2);
|
|
64
|
+
}
|
|
65
|
+
const name = pascalCase(context.instancePath.split("/").join("_"), {
|
|
66
|
+
normalize: true
|
|
67
|
+
});
|
|
68
|
+
return validVarName(name);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function tsArrayFromSchema(schema, context) {
|
|
72
|
+
const innerType = tsTypeFromSchema(schema.elements, {
|
|
73
|
+
clientName: context.clientName,
|
|
74
|
+
typePrefix: context.typePrefix,
|
|
75
|
+
generatedTypes: context.generatedTypes,
|
|
76
|
+
instancePath: `${context.instancePath}/[element]`,
|
|
77
|
+
schemaPath: `${context.schemaPath}/elements`,
|
|
78
|
+
discriminatorParent: "",
|
|
79
|
+
discriminatorKey: "",
|
|
80
|
+
discriminatorValue: "",
|
|
81
|
+
versionNumber: context.versionNumber,
|
|
82
|
+
usedFeatures: context.usedFeatures
|
|
83
|
+
});
|
|
84
|
+
const typeName = `(${innerType.typeName})[]`;
|
|
85
|
+
const defaultValue = schema.nullable ? "null" : "[]";
|
|
86
|
+
return {
|
|
87
|
+
typeName: schema.nullable ? `${typeName} | null` : typeName,
|
|
88
|
+
defaultValue,
|
|
89
|
+
validationTemplate(input) {
|
|
90
|
+
const mainPart = `Array.isArray(${input})
|
|
91
|
+
&& ${input}.every(
|
|
92
|
+
(_element) => ${innerType.validationTemplate("_element")}
|
|
93
|
+
)`;
|
|
94
|
+
if (schema.nullable) {
|
|
95
|
+
return `((${mainPart}) ||
|
|
96
|
+
${input} === null)`;
|
|
97
|
+
}
|
|
98
|
+
return mainPart;
|
|
99
|
+
},
|
|
100
|
+
fromJsonTemplate(input, target) {
|
|
101
|
+
return `if (Array.isArray(${input})) {
|
|
102
|
+
${target} = [];
|
|
103
|
+
for (const ${target}El of ${input}) {
|
|
104
|
+
let ${target}ElValue: ${innerType.typeName};
|
|
105
|
+
${innerType.fromJsonTemplate(`${target}El`, `${target}ElValue`)}
|
|
106
|
+
${target}.push(${target}ElValue);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
${target} = ${defaultValue};
|
|
110
|
+
}`;
|
|
111
|
+
},
|
|
112
|
+
toJsonTemplate(input, target) {
|
|
113
|
+
const elVar = `_${camelCase(validVarName(input.split(".").join("_")), { normalize: true })}El`;
|
|
114
|
+
const elKeyVar = `${elVar}Key`;
|
|
115
|
+
if (schema.nullable) {
|
|
116
|
+
return `if (${input} !== null) {
|
|
117
|
+
${target} += '[';
|
|
118
|
+
for (let i = 0; i < ${input}.length; i++) {
|
|
119
|
+
if (i !== 0) ${target} += ',';
|
|
120
|
+
const ${elVar} = ${input}[i];
|
|
121
|
+
${innerType.toJsonTemplate(elVar, target, elKeyVar)}
|
|
122
|
+
}
|
|
123
|
+
${target} += ']';
|
|
124
|
+
} else {
|
|
125
|
+
${target} += 'null';
|
|
126
|
+
}`;
|
|
127
|
+
}
|
|
128
|
+
return `${target} += '[';
|
|
129
|
+
for (let i = 0; i < ${input}.length; i++) {
|
|
130
|
+
if (i !== 0) ${target} += ',';
|
|
131
|
+
const ${elVar} = ${input}[i];
|
|
132
|
+
${innerType.toJsonTemplate(elVar, target, elKeyVar)}
|
|
133
|
+
}
|
|
134
|
+
${target} += ']';`;
|
|
135
|
+
},
|
|
136
|
+
toQueryStringTemplate(_input, _target, _key) {
|
|
137
|
+
return `console.warn('[WARNING] Cannot serialize arrays to query string. Skipping property at ${context.instancePath}.')`;
|
|
138
|
+
},
|
|
139
|
+
content: innerType.content
|
|
140
|
+
};
|
|
478
141
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
const
|
|
142
|
+
|
|
143
|
+
function tsObjectFromSchema(schema, context) {
|
|
144
|
+
const typeName = getTsTypeName(schema, context);
|
|
145
|
+
const prefixedTypeName = `${context.typePrefix}${typeName}`;
|
|
146
|
+
const defaultValue = schema.nullable ? "null" : `$$${prefixedTypeName}.new()`;
|
|
147
|
+
const result = {
|
|
148
|
+
typeName: schema.nullable ? `${prefixedTypeName} | null` : prefixedTypeName,
|
|
149
|
+
defaultValue,
|
|
150
|
+
validationTemplate(input) {
|
|
151
|
+
if (schema.nullable) {
|
|
152
|
+
return `($$${prefixedTypeName}.validate(${input}) || ${input} === null)`;
|
|
153
|
+
}
|
|
154
|
+
return `$$${prefixedTypeName}.validate(${input})`;
|
|
155
|
+
},
|
|
156
|
+
fromJsonTemplate(input, target) {
|
|
157
|
+
return `if (isObject(${input})) {
|
|
158
|
+
${target} = $$${prefixedTypeName}.fromJson(${input});
|
|
159
|
+
} else {
|
|
160
|
+
${target} = ${defaultValue};
|
|
161
|
+
}`;
|
|
162
|
+
},
|
|
163
|
+
toJsonTemplate(input, target) {
|
|
164
|
+
if (schema.nullable) {
|
|
165
|
+
return `if (${input} !== null) {
|
|
166
|
+
${target} += $$${prefixedTypeName}.toJsonString(${input});
|
|
167
|
+
} else {
|
|
168
|
+
${target} += 'null';
|
|
169
|
+
}`;
|
|
170
|
+
}
|
|
171
|
+
return `${target} += $$${prefixedTypeName}.toJsonString(${input});`;
|
|
172
|
+
},
|
|
173
|
+
toQueryStringTemplate(_input, _target) {
|
|
174
|
+
return `console.warn("[WARNING] Cannot serialize nested objects to query string. Skipping property at ${context.instancePath}.")`;
|
|
175
|
+
},
|
|
176
|
+
content: ""
|
|
177
|
+
};
|
|
178
|
+
if (context.generatedTypes.includes(typeName)) {
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
const newParts = [];
|
|
483
182
|
const fieldParts = [];
|
|
183
|
+
const fromJsonParts = [];
|
|
184
|
+
const constructionParts = [];
|
|
185
|
+
const toJsonParts = [];
|
|
186
|
+
const toQueryParts = [];
|
|
187
|
+
const validationParts = ["isObject(input)"];
|
|
484
188
|
const subContentParts = [];
|
|
485
|
-
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
|
|
189
|
+
let hasKey = false;
|
|
190
|
+
if (context.discriminatorParent && context.discriminatorValue && context.discriminatorKey) {
|
|
191
|
+
hasKey = true;
|
|
192
|
+
const key = validVarName(
|
|
193
|
+
camelCase(context.discriminatorKey, { normalize: true })
|
|
489
194
|
);
|
|
490
|
-
fieldParts.push(
|
|
491
|
-
|
|
195
|
+
fieldParts.push(`${key}: "${context.discriminatorValue}",`);
|
|
196
|
+
fromJsonParts.push(`const _${key} = "${context.discriminatorValue}"`);
|
|
197
|
+
toJsonParts.push(`json += '"${key}":"${context.discriminatorValue}"'`);
|
|
198
|
+
toQueryParts.push(
|
|
199
|
+
`queryParts.push('${context.discriminatorKey}=${context.discriminatorValue}');`
|
|
492
200
|
);
|
|
493
|
-
|
|
201
|
+
validationParts.push(
|
|
202
|
+
`input.${key} === '${context.discriminatorValue}'`
|
|
203
|
+
);
|
|
204
|
+
newParts.push(`${key}: "${context.discriminatorValue}",`);
|
|
205
|
+
constructionParts.push(`${key}: _${key},`);
|
|
494
206
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
207
|
+
for (const key of Object.keys(schema.properties)) {
|
|
208
|
+
const subSchema = schema.properties[key];
|
|
209
|
+
const prop = tsTypeFromSchema(subSchema, {
|
|
210
|
+
clientName: context.clientName,
|
|
211
|
+
typePrefix: context.typePrefix,
|
|
212
|
+
generatedTypes: context.generatedTypes,
|
|
213
|
+
instancePath: `/${typeName}/${key}`,
|
|
214
|
+
schemaPath: `/${typeName}/properties/${key}`,
|
|
215
|
+
discriminatorParent: "",
|
|
216
|
+
discriminatorKey: "",
|
|
217
|
+
discriminatorValue: "",
|
|
218
|
+
versionNumber: context.versionNumber,
|
|
219
|
+
usedFeatures: context.usedFeatures
|
|
220
|
+
});
|
|
221
|
+
if (prop.content)
|
|
222
|
+
subContentParts.push(prop.content);
|
|
223
|
+
const fieldName = validVarName(camelCase(key));
|
|
224
|
+
fieldParts.push(`${fieldName}: ${prop.typeName},`);
|
|
225
|
+
newParts.push(`${fieldName}: ${prop.defaultValue},`);
|
|
226
|
+
const tempKey = `_${validVarName(key)}`;
|
|
227
|
+
fromJsonParts.push(`let ${tempKey}: ${prop.typeName};`);
|
|
228
|
+
fromJsonParts.push(prop.fromJsonTemplate(`input.${key}`, tempKey));
|
|
229
|
+
if (hasKey) {
|
|
230
|
+
toJsonParts.push(`json += ',"${key}":';`);
|
|
231
|
+
} else {
|
|
232
|
+
toJsonParts.push(`json += '"${key}":';`);
|
|
515
233
|
}
|
|
234
|
+
toJsonParts.push(
|
|
235
|
+
prop.toJsonTemplate(`input.${fieldName}`, "json", key)
|
|
236
|
+
);
|
|
237
|
+
toQueryParts.push(
|
|
238
|
+
prop.toQueryStringTemplate(`input.${fieldName}`, "queryParts", key)
|
|
239
|
+
);
|
|
240
|
+
const validationPart = prop.validationTemplate(`input.${fieldName}`);
|
|
241
|
+
validationParts.push(validationPart);
|
|
242
|
+
constructionParts.push(`${fieldName}: ${tempKey},`);
|
|
243
|
+
hasKey = true;
|
|
516
244
|
}
|
|
517
|
-
if (
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
245
|
+
if (!hasKey) {
|
|
246
|
+
toJsonParts.push(`let _hasKey = false;`);
|
|
247
|
+
}
|
|
248
|
+
for (const key of Object.keys(schema.optionalProperties ?? {})) {
|
|
249
|
+
const subSchema = schema.optionalProperties[key];
|
|
250
|
+
const prop = tsTypeFromSchema(subSchema, {
|
|
251
|
+
clientName: context.clientName,
|
|
252
|
+
typePrefix: context.typePrefix,
|
|
253
|
+
generatedTypes: context.generatedTypes,
|
|
254
|
+
instancePath: `/${typeName}/${key}`,
|
|
255
|
+
schemaPath: `/${typeName}/optionalProperties/${key}`,
|
|
256
|
+
discriminatorParent: "",
|
|
257
|
+
discriminatorKey: "",
|
|
258
|
+
discriminatorValue: "",
|
|
259
|
+
versionNumber: context.versionNumber,
|
|
260
|
+
usedFeatures: context.usedFeatures
|
|
261
|
+
});
|
|
262
|
+
if (prop.content)
|
|
263
|
+
subContentParts.push(prop.content);
|
|
264
|
+
const fieldName = validVarName(camelCase(key));
|
|
265
|
+
fieldParts.push(`${fieldName}?: ${prop.typeName},`);
|
|
266
|
+
const tempKey = `_${validVarName(key)}`;
|
|
267
|
+
fromJsonParts.push(`let ${tempKey}: ${prop.typeName} | undefined;`);
|
|
268
|
+
fromJsonParts.push(`if (typeof input.${key} !== 'undefined') {
|
|
269
|
+
${prop.fromJsonTemplate(`input.${key}`, tempKey)}
|
|
270
|
+
}`);
|
|
271
|
+
if (hasKey) {
|
|
272
|
+
toJsonParts.push(`if (typeof input.${key} !== 'undefined') {
|
|
273
|
+
json += \`,"${key}":\`;
|
|
274
|
+
${prop.toJsonTemplate(`input.${key}`, "json", key)}
|
|
275
|
+
}`);
|
|
276
|
+
} else {
|
|
277
|
+
toJsonParts.push(`if (typeof input.${key} !== 'undefined') {
|
|
278
|
+
if (_hasKey) json += ',';
|
|
279
|
+
json += '"${key}":';
|
|
280
|
+
${prop.toJsonTemplate(`input.${key}`, "json", key)}
|
|
281
|
+
_hasKey = true;
|
|
282
|
+
}`);
|
|
537
283
|
}
|
|
284
|
+
toQueryParts.push(`if (typeof input.${fieldName} !== 'undefined') {
|
|
285
|
+
${prop.toQueryStringTemplate(`input.${fieldName}`, "queryParts", key)}
|
|
286
|
+
}`);
|
|
287
|
+
const validationPart = prop.validationTemplate(`input.${fieldName}`);
|
|
288
|
+
validationParts.push(
|
|
289
|
+
`((${validationPart}) || typeof input.${fieldName} === 'undefined')`
|
|
290
|
+
);
|
|
291
|
+
constructionParts.push(`${fieldName}: ${tempKey},`);
|
|
538
292
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
293
|
+
result.content = `${getJsDocComment(schema.metadata)}export interface ${prefixedTypeName} {
|
|
294
|
+
${fieldParts.map((part) => ` ${part}`).join("\n")}
|
|
295
|
+
}
|
|
296
|
+
${context.discriminatorParent && context.discriminatorValue ? "" : "export "}const $$${prefixedTypeName}: ArriModelValidator<${prefixedTypeName}> = {
|
|
297
|
+
new(): ${prefixedTypeName} {
|
|
298
|
+
return {
|
|
299
|
+
${newParts.map((part) => ` ${part}`).join("\n")}
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
validate(input): input is ${prefixedTypeName} {
|
|
303
|
+
return (
|
|
304
|
+
${validationParts.map((part) => ` ${part}`).join("&& \n")}
|
|
305
|
+
)
|
|
306
|
+
},
|
|
307
|
+
fromJson(input): ${prefixedTypeName} {
|
|
308
|
+
${fromJsonParts.map((part) => ` ${part}`).join("\n")}
|
|
309
|
+
return {
|
|
310
|
+
${constructionParts.map((part) => ` ${part}`).join("\n")}
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
fromJsonString(input): ${prefixedTypeName} {
|
|
314
|
+
return $$${prefixedTypeName}.fromJson(JSON.parse(input));
|
|
315
|
+
},
|
|
316
|
+
toJsonString(input): string {
|
|
317
|
+
let json = "{";
|
|
318
|
+
${toJsonParts.map((part) => ` ${part}`).join("\n")}
|
|
319
|
+
json += "}";
|
|
320
|
+
return json;
|
|
321
|
+
},
|
|
322
|
+
toUrlQueryString(input): string {
|
|
323
|
+
const queryParts: string[] = [];
|
|
324
|
+
${toQueryParts.map((part) => ` ${part}`).join("\n")}
|
|
325
|
+
return queryParts.join("&");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
${subContentParts.join("\n")}`;
|
|
330
|
+
context.generatedTypes.push(typeName);
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function tsTaggedUnionFromSchema(schema, context) {
|
|
335
|
+
const typeName = getTsTypeName(schema, context);
|
|
336
|
+
const prefixedTypeName = `${context.typePrefix}${typeName}`;
|
|
337
|
+
const defaultValue = schema.nullable ? "null" : `$$${prefixedTypeName}.new()`;
|
|
338
|
+
const result = {
|
|
339
|
+
typeName: schema.nullable ? `${prefixedTypeName} | null` : prefixedTypeName,
|
|
340
|
+
defaultValue,
|
|
341
|
+
validationTemplate(input) {
|
|
342
|
+
const mainPart = `$$${prefixedTypeName}.validate(${input})`;
|
|
343
|
+
if (schema.nullable) {
|
|
344
|
+
return `(${mainPart} || ${input} === null)`;
|
|
345
|
+
}
|
|
346
|
+
return mainPart;
|
|
347
|
+
},
|
|
348
|
+
fromJsonTemplate(input, target) {
|
|
349
|
+
return `if (isObject(${input})) {
|
|
350
|
+
${target} = $$${prefixedTypeName}.fromJson(${input});
|
|
351
|
+
} else {
|
|
352
|
+
${target} = ${defaultValue};
|
|
353
|
+
}`;
|
|
354
|
+
},
|
|
355
|
+
toJsonTemplate(input, target, _key) {
|
|
356
|
+
if (schema.nullable) {
|
|
357
|
+
return `if (${input} != null) {
|
|
358
|
+
${target} += $$${prefixedTypeName}.toJsonString(${input});
|
|
359
|
+
} else {
|
|
360
|
+
${target} += 'null';
|
|
361
|
+
}`;
|
|
362
|
+
}
|
|
363
|
+
return `${target} += $$${prefixedTypeName}.toJsonString(${input});`;
|
|
364
|
+
},
|
|
365
|
+
toQueryStringTemplate(_, __, ___) {
|
|
366
|
+
return `console.warn("[WARNING] Cannot serialize nested objects to query string. Skipping property at ${context.instancePath}.");`;
|
|
367
|
+
},
|
|
368
|
+
content: ""
|
|
547
369
|
};
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
370
|
+
if (context.generatedTypes.includes(typeName))
|
|
371
|
+
return result;
|
|
372
|
+
const subTypes = [];
|
|
373
|
+
const discriminatorKey = schema.discriminator;
|
|
374
|
+
for (const key of Object.keys(schema.mapping)) {
|
|
375
|
+
const subSchema = schema.mapping[key];
|
|
376
|
+
const subType = tsObjectFromSchema(subSchema, {
|
|
377
|
+
clientName: context.clientName,
|
|
378
|
+
typePrefix: context.typePrefix,
|
|
379
|
+
generatedTypes: context.generatedTypes,
|
|
380
|
+
instancePath: context.instancePath,
|
|
381
|
+
schemaPath: `${context.schemaPath}/mapping/${key}`,
|
|
382
|
+
discriminatorParent: typeName,
|
|
383
|
+
discriminatorKey,
|
|
384
|
+
discriminatorValue: key,
|
|
385
|
+
versionNumber: context.versionNumber,
|
|
386
|
+
usedFeatures: context.usedFeatures
|
|
387
|
+
});
|
|
388
|
+
subTypes.push({ value: key, data: subType });
|
|
563
389
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
390
|
+
result.content = `export type ${prefixedTypeName} = ${subTypes.map((type) => type.data.typeName).join(" |")};
|
|
391
|
+
export const $$${prefixedTypeName}: ArriModelValidator<${prefixedTypeName}> = {
|
|
392
|
+
new(): ${prefixedTypeName} {
|
|
393
|
+
return $$${subTypes[0].data.typeName}.new();
|
|
394
|
+
},
|
|
395
|
+
validate(input): input is ${prefixedTypeName} {
|
|
396
|
+
if (!isObject(input)) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
if (typeof input.${discriminatorKey} !== 'string') {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
switch (input.${discriminatorKey}) {
|
|
403
|
+
${subTypes.map(
|
|
404
|
+
(type) => ` case "${type.value}":
|
|
405
|
+
return $$${type.data.typeName}.validate(input);`
|
|
406
|
+
).join("\n")}
|
|
407
|
+
default:
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
fromJson(input): ${prefixedTypeName} {
|
|
412
|
+
switch (input.${discriminatorKey}) {
|
|
413
|
+
${subTypes.map(
|
|
414
|
+
(type) => ` case "${type.value}":
|
|
415
|
+
return $$${type.data.typeName}.fromJson(input);`
|
|
416
|
+
).join("\n")}
|
|
417
|
+
default:
|
|
418
|
+
return $$${subTypes[0].data.typeName}.new();
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
fromJsonString(input): ${prefixedTypeName} {
|
|
422
|
+
return $$${prefixedTypeName}.fromJson(JSON.parse(input));
|
|
423
|
+
},
|
|
424
|
+
toJsonString(input): string {
|
|
425
|
+
switch (input.${discriminatorKey}) {
|
|
426
|
+
${subTypes.map(
|
|
427
|
+
(type) => ` case "${type.value}":
|
|
428
|
+
return $$${type.data.typeName}.toJsonString(input);`
|
|
429
|
+
).join("\n")}
|
|
430
|
+
default:
|
|
431
|
+
throw new Error(\`Unhandled case "\${(input as any).${discriminatorKey}}"\`);
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
toUrlQueryString(input): string {
|
|
435
|
+
switch (input.${discriminatorKey}) {
|
|
436
|
+
${subTypes.map(
|
|
437
|
+
(type) => ` case "${type.value}":
|
|
438
|
+
return $$${type.data.typeName}.toUrlQueryString(input);`
|
|
439
|
+
).join("\n")}
|
|
440
|
+
default:
|
|
441
|
+
throw new Error('Unhandled case');
|
|
442
|
+
}
|
|
567
443
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
444
|
+
}
|
|
445
|
+
${subTypes.map((type) => type.data.content).join("\n")}
|
|
446
|
+
`;
|
|
447
|
+
context.generatedTypes.push(typeName);
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function tsEnumFromSchema(schema, context) {
|
|
452
|
+
if (schema.enum.length === 0)
|
|
453
|
+
throw new Error(
|
|
454
|
+
`Error at ${context.schemaPath}. Enum schemas must have at least one enum value.`
|
|
455
|
+
);
|
|
456
|
+
const enumName = getTsTypeName(schema, context);
|
|
457
|
+
const prefixedEnumName = `${context.typePrefix}${enumName}`;
|
|
458
|
+
const typeName = schema.nullable ? `${prefixedEnumName} | null` : prefixedEnumName;
|
|
459
|
+
const defaultValue = schema.nullable ? "null" : `$$${prefixedEnumName}.new()`;
|
|
460
|
+
const result = {
|
|
461
|
+
typeName,
|
|
462
|
+
defaultValue,
|
|
463
|
+
validationTemplate(input) {
|
|
464
|
+
if (schema.nullable) {
|
|
465
|
+
return `($$${prefixedEnumName}.validate(${input}) || ${input} === null)`;
|
|
466
|
+
}
|
|
467
|
+
return `$$${prefixedEnumName}.validate(${input})`;
|
|
468
|
+
},
|
|
469
|
+
fromJsonTemplate(input, target) {
|
|
470
|
+
return `if (typeof ${input} === 'string') {
|
|
471
|
+
${target} = $$${prefixedEnumName}.fromSerialValue(${input});
|
|
472
|
+
} else {
|
|
473
|
+
${target} = ${defaultValue};
|
|
474
|
+
}`;
|
|
475
|
+
},
|
|
476
|
+
toJsonTemplate(input, target) {
|
|
477
|
+
if (schema.nullable) {
|
|
478
|
+
return `if (typeof ${input} === 'string') {
|
|
479
|
+
${target} += \`"\${${input}}"\`;
|
|
480
|
+
} else {
|
|
481
|
+
${target} += 'null';
|
|
482
|
+
}`;
|
|
483
|
+
}
|
|
484
|
+
return `${target} += \`"\${${input}}"\``;
|
|
485
|
+
},
|
|
486
|
+
toQueryStringTemplate(input, target, key) {
|
|
487
|
+
return `${target}.push(\`${key}=\${${input}}\`)`;
|
|
488
|
+
},
|
|
489
|
+
content: ""
|
|
490
|
+
};
|
|
491
|
+
if (context.generatedTypes.includes(enumName)) {
|
|
492
|
+
return result;
|
|
571
493
|
}
|
|
494
|
+
const name = `${context.typePrefix}${enumName}`;
|
|
495
|
+
const valuesName = `$$${name}Values`;
|
|
496
|
+
result.content = `${getJsDocComment(schema.metadata)}export type ${name} = (typeof ${valuesName})[number];
|
|
497
|
+
const ${valuesName} = [${schema.enum.map((val) => `"${val}"`).join(", ")}] as const;
|
|
498
|
+
export const $$${name}: ArriEnumValidator<${name}> = {
|
|
499
|
+
new(): ${name} {
|
|
500
|
+
return ${valuesName}[0];
|
|
501
|
+
},
|
|
502
|
+
validate(input): input is ${enumName} {
|
|
503
|
+
return (
|
|
504
|
+
typeof input === 'string' &&
|
|
505
|
+
${valuesName}.includes(input as any)
|
|
506
|
+
);
|
|
507
|
+
},
|
|
508
|
+
values: ${valuesName},
|
|
509
|
+
fromSerialValue(input): ${name} {
|
|
510
|
+
if (${valuesName}.includes(input as any)) {
|
|
511
|
+
return input as ${name};
|
|
512
|
+
}
|
|
513
|
+
if (${valuesName}.includes(input.toLowerCase() as any)) {
|
|
514
|
+
return input.toLowerCase() as ${name};
|
|
515
|
+
}
|
|
516
|
+
if (${valuesName}.includes(input.toUpperCase() as any)) {
|
|
517
|
+
return input.toUpperCase() as ${name};
|
|
518
|
+
}
|
|
519
|
+
return "${schema.enum[0]}";
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
`;
|
|
523
|
+
context.generatedTypes.push(enumName);
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function tsStringFromSchema(schema, _context) {
|
|
528
|
+
const typeName = schema.nullable ? "string | null" : "string";
|
|
529
|
+
const defaultValue = schema.nullable ? "null" : '""';
|
|
572
530
|
return {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
)}: ${maybeNullType(typeName, def.nullable ?? false)}`,
|
|
579
|
-
fromJsonTemplate(input) {
|
|
580
|
-
if (additionalOptions.isOptional) {
|
|
581
|
-
return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
|
|
531
|
+
typeName,
|
|
532
|
+
defaultValue,
|
|
533
|
+
validationTemplate(input) {
|
|
534
|
+
if (schema.nullable) {
|
|
535
|
+
return `(typeof ${input} === 'string' || ${input} === null)`;
|
|
582
536
|
}
|
|
583
|
-
|
|
584
|
-
|
|
537
|
+
return `typeof ${input} === 'string'`;
|
|
538
|
+
},
|
|
539
|
+
fromJsonTemplate(input, target) {
|
|
540
|
+
return `if (typeof ${input} === 'string') {
|
|
541
|
+
${target} = ${input};
|
|
542
|
+
} else {
|
|
543
|
+
${target} = ${defaultValue};
|
|
544
|
+
}`;
|
|
545
|
+
},
|
|
546
|
+
toJsonTemplate(input, target) {
|
|
547
|
+
if (schema.nullable) {
|
|
548
|
+
return `if (typeof ${input} === 'string') {
|
|
549
|
+
${target} += serializeString(${input});
|
|
550
|
+
} else {
|
|
551
|
+
${target} += 'null';
|
|
552
|
+
}`;
|
|
585
553
|
}
|
|
586
|
-
return
|
|
554
|
+
return `${target} += serializeString(${input});`;
|
|
587
555
|
},
|
|
588
|
-
|
|
589
|
-
return
|
|
556
|
+
toQueryStringTemplate(input, target, key) {
|
|
557
|
+
return `${target}.push(\`${key}=\${${input}}\`);`;
|
|
590
558
|
},
|
|
591
|
-
content
|
|
559
|
+
content: ""
|
|
592
560
|
};
|
|
593
561
|
}
|
|
594
|
-
function
|
|
595
|
-
const
|
|
596
|
-
const
|
|
597
|
-
let content = `${getJsDocComment(def.metadata)}export type ${typeName} = ${def.enum.map((val) => `"${val}"`).join(" | ")}`;
|
|
598
|
-
if (additionalOptions.existingTypeNames.includes(typeName)) {
|
|
599
|
-
content = "";
|
|
600
|
-
} else {
|
|
601
|
-
additionalOptions.existingTypeNames.push(typeName);
|
|
602
|
-
}
|
|
562
|
+
function tsBooleanFromSchema(schema, _context) {
|
|
563
|
+
const typeName = schema.nullable ? `boolean | null` : "boolean";
|
|
564
|
+
const defaultValue = schema.nullable ? `null` : "false";
|
|
603
565
|
return {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
)}: ${maybeNullType(typeName, def.nullable ?? false)}`,
|
|
610
|
-
fromJsonTemplate(input) {
|
|
611
|
-
if (additionalOptions.isOptional) {
|
|
612
|
-
return `typeof ${input} === 'string' ? $$${typeName}.parse(${input}) : undefined`;
|
|
613
|
-
}
|
|
614
|
-
if (def.nullable) {
|
|
615
|
-
return `typeof ${input} === 'string' ? $$${typeName}.parse(${input}) : null`;
|
|
566
|
+
typeName,
|
|
567
|
+
defaultValue,
|
|
568
|
+
validationTemplate(input) {
|
|
569
|
+
if (schema.nullable) {
|
|
570
|
+
return `(typeof ${input} === 'boolean' || ${input} === null)`;
|
|
616
571
|
}
|
|
617
|
-
return
|
|
572
|
+
return `typeof ${input} === 'boolean'`;
|
|
618
573
|
},
|
|
619
|
-
|
|
620
|
-
return `
|
|
574
|
+
fromJsonTemplate(input, target) {
|
|
575
|
+
return `if (typeof ${input} === 'boolean') {
|
|
576
|
+
${target} = ${input};
|
|
577
|
+
} else {
|
|
578
|
+
${target} = ${defaultValue};
|
|
579
|
+
}`;
|
|
621
580
|
},
|
|
622
|
-
|
|
581
|
+
toJsonTemplate(input, target) {
|
|
582
|
+
return `${target} += \`\${${input}}\`;`;
|
|
583
|
+
},
|
|
584
|
+
toQueryStringTemplate(input, target, key) {
|
|
585
|
+
return `${target}.push(\`${key}=\${${input}}\`);`;
|
|
586
|
+
},
|
|
587
|
+
content: ""
|
|
623
588
|
};
|
|
624
589
|
}
|
|
625
|
-
function
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
`${nodePath}.item`,
|
|
629
|
-
def.elements,
|
|
630
|
-
options,
|
|
631
|
-
{
|
|
632
|
-
isOptional: false,
|
|
633
|
-
existingTypeNames: additionalOptions.existingTypeNames
|
|
634
|
-
}
|
|
635
|
-
);
|
|
636
|
-
const tsType = `Array<${maybeNullType(
|
|
637
|
-
subType.tsType,
|
|
638
|
-
def.elements.nullable
|
|
639
|
-
)}>`;
|
|
590
|
+
function tsDateFromSchema(schema, _context) {
|
|
591
|
+
const typeName = schema.nullable ? `Date | null` : "Date";
|
|
592
|
+
const defaultValue = schema.nullable ? `null` : "new Date()";
|
|
640
593
|
return {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
)}: ${maybeNullType(tsType, def.nullable ?? false)}`,
|
|
647
|
-
fromJsonTemplate(input) {
|
|
648
|
-
if (additionalOptions.isOptional) {
|
|
649
|
-
return `Array.isArray(${input}) ? ${input}.map((item) => ${subType.fromJsonTemplate(
|
|
650
|
-
"item"
|
|
651
|
-
)}) : undefined`;
|
|
594
|
+
typeName,
|
|
595
|
+
defaultValue,
|
|
596
|
+
validationTemplate(input) {
|
|
597
|
+
if (schema.nullable) {
|
|
598
|
+
return `(${input} instanceof Date || ${input} === null)`;
|
|
652
599
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
600
|
+
return `${input} instanceof Date`;
|
|
601
|
+
},
|
|
602
|
+
fromJsonTemplate(input, target) {
|
|
603
|
+
return `if (typeof ${input} === 'string') {
|
|
604
|
+
${target} = new Date(${input});
|
|
605
|
+
} else if (${input} instanceof Date) {
|
|
606
|
+
${target} = ${input};
|
|
607
|
+
} else {
|
|
608
|
+
${target} = ${defaultValue}
|
|
609
|
+
}`;
|
|
610
|
+
},
|
|
611
|
+
toJsonTemplate(input, target) {
|
|
612
|
+
if (schema.nullable) {
|
|
613
|
+
return `if (${input} instanceof Date) {
|
|
614
|
+
${target} += \`"\${${input}.toISOString()}"\`
|
|
615
|
+
} else {
|
|
616
|
+
${target} += 'null';
|
|
617
|
+
}`;
|
|
657
618
|
}
|
|
658
|
-
return
|
|
659
|
-
"item"
|
|
660
|
-
)}) : []`;
|
|
619
|
+
return `${target} += \`"\${${input}.toISOString()}"\``;
|
|
661
620
|
},
|
|
662
|
-
|
|
663
|
-
|
|
621
|
+
toQueryStringTemplate(input, target, key) {
|
|
622
|
+
if (schema.nullable) {
|
|
623
|
+
return `${target}.push(\`${key}=\${${input}?.toISOString()}\`)`;
|
|
624
|
+
}
|
|
625
|
+
return `${target}.push(\`${key}=\${${input}.toISOString()}\`)`;
|
|
664
626
|
},
|
|
665
|
-
content:
|
|
627
|
+
content: ""
|
|
666
628
|
};
|
|
667
629
|
}
|
|
668
|
-
function
|
|
669
|
-
const
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
const optionType = tsObjectFromJtdSchema(
|
|
680
|
-
`${nodePath}.${camelCase(val.toLowerCase())}`,
|
|
681
|
-
optionSchema,
|
|
682
|
-
options,
|
|
683
|
-
{
|
|
684
|
-
discriminatorKey: def.discriminator,
|
|
685
|
-
discriminatorKeyValue: val,
|
|
686
|
-
isOptional: false,
|
|
687
|
-
existingTypeNames: additionalOptions.existingTypeNames
|
|
630
|
+
function tsFloatFromSchema(schema, _context) {
|
|
631
|
+
const typeName = schema.nullable ? "number | null" : "number";
|
|
632
|
+
const defaultValue = schema.nullable ? "null" : "0";
|
|
633
|
+
return {
|
|
634
|
+
typeName,
|
|
635
|
+
defaultValue,
|
|
636
|
+
validationTemplate(input) {
|
|
637
|
+
if (schema.nullable) {
|
|
638
|
+
return `(typeof ${input} === 'number' || ${input} === null)`;
|
|
688
639
|
}
|
|
689
|
-
|
|
690
|
-
parserParts.push(`case '${val}':
|
|
691
|
-
return $$${optionType.tsType}.parse(input);`);
|
|
692
|
-
subTypeNames.push(optionType.tsType);
|
|
693
|
-
subContentParts.push(optionType.content);
|
|
694
|
-
}
|
|
695
|
-
let validatorPart = "";
|
|
696
|
-
if (options.typesNeedingParser.includes(typeName)) {
|
|
697
|
-
const modifiedDef = { ...def, nullable: false };
|
|
698
|
-
const parsingCode = getSchemaParsingCode(
|
|
699
|
-
"input",
|
|
700
|
-
modifiedDef
|
|
701
|
-
);
|
|
702
|
-
const serializationCode = getSchemaSerializationCode(
|
|
703
|
-
"input",
|
|
704
|
-
modifiedDef
|
|
705
|
-
);
|
|
706
|
-
validatorPart = `export const $$${typeName} = {
|
|
707
|
-
parse(input: Record<any, any>): ${typeName} {
|
|
708
|
-
${parsingCode}
|
|
640
|
+
return `typeof ${input} === 'number'`;
|
|
709
641
|
},
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
642
|
+
fromJsonTemplate(input, target) {
|
|
643
|
+
return `if (typeof ${input} === 'number') {
|
|
644
|
+
${target} = ${input};
|
|
645
|
+
} else {
|
|
646
|
+
${target} = ${defaultValue};
|
|
647
|
+
}`;
|
|
648
|
+
},
|
|
649
|
+
toJsonTemplate(input, target) {
|
|
650
|
+
return `${target} += \`\${${input}}\``;
|
|
651
|
+
},
|
|
652
|
+
toQueryStringTemplate(input, target, key) {
|
|
653
|
+
return `${target}.push(\`${key}=\${${input}}\`)`;
|
|
654
|
+
},
|
|
655
|
+
content: ""
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function tsIntFromSchema(schema, intType, _context) {
|
|
659
|
+
const typeName = schema.nullable ? "number | null" : "number";
|
|
660
|
+
const defaultValue = schema.nullable ? "null" : "0";
|
|
661
|
+
let min;
|
|
662
|
+
let max;
|
|
663
|
+
switch (intType) {
|
|
664
|
+
case "int8":
|
|
665
|
+
min = "INT8_MIN";
|
|
666
|
+
max = "INT8_MAX";
|
|
667
|
+
break;
|
|
668
|
+
case "uint8":
|
|
669
|
+
min = "0";
|
|
670
|
+
max = "UINT8_MAX";
|
|
671
|
+
break;
|
|
672
|
+
case "int16":
|
|
673
|
+
min = "INT16_MIN";
|
|
674
|
+
max = "INT16_MAX";
|
|
675
|
+
break;
|
|
676
|
+
case "uint16":
|
|
677
|
+
min = "0";
|
|
678
|
+
max = "UINT16_MAX";
|
|
679
|
+
break;
|
|
680
|
+
case "int32":
|
|
681
|
+
min = "INT32_MIN";
|
|
682
|
+
max = "INT32_MAX";
|
|
683
|
+
break;
|
|
684
|
+
case "uint32":
|
|
685
|
+
min = "0";
|
|
686
|
+
max = "UINT32_MAX";
|
|
687
|
+
break;
|
|
722
688
|
}
|
|
723
689
|
return {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
fromJsonTemplate(input) {
|
|
731
|
-
if (additionalOptions.isOptional) {
|
|
732
|
-
return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
|
|
690
|
+
typeName,
|
|
691
|
+
defaultValue,
|
|
692
|
+
validationTemplate(input) {
|
|
693
|
+
const mainPart = `typeof ${input} === 'number' && Number.isInteger(${input}) && ${input} >= ${min} && ${input} <= ${max}`;
|
|
694
|
+
if (schema.nullable) {
|
|
695
|
+
return `((${mainPart}) || ${input} === null)`;
|
|
733
696
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
return
|
|
697
|
+
return mainPart;
|
|
698
|
+
},
|
|
699
|
+
fromJsonTemplate(input, target) {
|
|
700
|
+
return `if (
|
|
701
|
+
typeof ${input} === 'number' &&
|
|
702
|
+
Number.isInteger(${input}) &&
|
|
703
|
+
${input} >= ${min} &&
|
|
704
|
+
${input} <= ${max}
|
|
705
|
+
) {
|
|
706
|
+
${target} = ${input};
|
|
707
|
+
} else {
|
|
708
|
+
${target} = ${defaultValue};
|
|
709
|
+
}`;
|
|
710
|
+
},
|
|
711
|
+
toJsonTemplate(input, target) {
|
|
712
|
+
return `${target} += \`\${${input}}\``;
|
|
738
713
|
},
|
|
739
|
-
|
|
740
|
-
return
|
|
714
|
+
toQueryStringTemplate(input, target, key) {
|
|
715
|
+
return `${target}.push(\`${key}=\${${input}}\`)`;
|
|
741
716
|
},
|
|
742
|
-
content
|
|
717
|
+
content: ""
|
|
743
718
|
};
|
|
744
719
|
}
|
|
745
|
-
function
|
|
746
|
-
const
|
|
747
|
-
const
|
|
748
|
-
const subType = tsTypeFromJtdSchema(
|
|
749
|
-
`${nodePath}.value`,
|
|
750
|
-
def.values,
|
|
751
|
-
options,
|
|
752
|
-
{
|
|
753
|
-
isOptional: false,
|
|
754
|
-
existingTypeNames: additionalOptions.existingTypeNames
|
|
755
|
-
}
|
|
756
|
-
);
|
|
757
|
-
let content = "";
|
|
758
|
-
if (!additionalOptions.existingTypeNames.includes(typeName)) {
|
|
759
|
-
let validatorPart = "";
|
|
760
|
-
if (options.typesNeedingParser.includes(typeName)) {
|
|
761
|
-
const modifiedDef = { ...def, nullable: false };
|
|
762
|
-
const parsingCode = getSchemaParsingCode(
|
|
763
|
-
"input",
|
|
764
|
-
modifiedDef
|
|
765
|
-
);
|
|
766
|
-
const serializationCode = getSchemaSerializationCode(
|
|
767
|
-
"input",
|
|
768
|
-
modifiedDef
|
|
769
|
-
);
|
|
770
|
-
validatorPart = `export const $$${typeName} = {
|
|
771
|
-
parse(input: Record<any, any>): ${typeName} {
|
|
772
|
-
${parsingCode}
|
|
773
|
-
},
|
|
774
|
-
serialize(input: ${typeName}): string {
|
|
775
|
-
${serializationCode}
|
|
776
|
-
}
|
|
777
|
-
}`;
|
|
778
|
-
}
|
|
779
|
-
content = `${getJsDocComment(def.metadata)}export type ${typeName} = Record<string, ${subType.tsType}>;
|
|
780
|
-
${validatorPart}
|
|
781
|
-
${subType.content}`;
|
|
782
|
-
}
|
|
720
|
+
function tsBigIntFromSchema(schema, isUnsigned, _context) {
|
|
721
|
+
const typeName = schema.nullable ? `bigint | null` : `bigint`;
|
|
722
|
+
const defaultValue = schema.nullable ? `null` : "BigInt(0)";
|
|
783
723
|
return {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
fromJsonTemplate(input) {
|
|
791
|
-
if (additionalOptions.isOptional) {
|
|
792
|
-
return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
|
|
724
|
+
typeName,
|
|
725
|
+
defaultValue,
|
|
726
|
+
validationTemplate(input) {
|
|
727
|
+
const mainPart = isUnsigned ? `typeof ${input} === 'bigint' && ${input} >= BigInt(0) && ${input} <= UINT64_MAX` : `typeof ${input} === 'bigint' && ${input} >= INT64_MIN && ${input} <= INT64_MAX`;
|
|
728
|
+
if (schema.nullable) {
|
|
729
|
+
return `((${mainPart}) || ${input} === null)`;
|
|
793
730
|
}
|
|
794
|
-
|
|
795
|
-
|
|
731
|
+
return mainPart;
|
|
732
|
+
},
|
|
733
|
+
fromJsonTemplate(input, target) {
|
|
734
|
+
if (isUnsigned) {
|
|
735
|
+
return `if (typeof ${input} === 'string' && BigInt(${input}) >= BigInt(0)) {
|
|
736
|
+
${target} = BigInt(${input});
|
|
737
|
+
} else if (typeof ${input} === 'bigint' && ${input} >= BigInt(0)) {
|
|
738
|
+
${target} = ${input};
|
|
739
|
+
} else {
|
|
740
|
+
${target} = ${defaultValue};
|
|
741
|
+
}`;
|
|
796
742
|
}
|
|
797
|
-
return `typeof ${input} === '
|
|
743
|
+
return `if (typeof ${input} === 'string') {
|
|
744
|
+
${target} = BigInt(${input});
|
|
745
|
+
} else if (typeof ${input} === 'bigint') {
|
|
746
|
+
${target} = ${input};
|
|
747
|
+
} else {
|
|
748
|
+
${target} = ${defaultValue};
|
|
749
|
+
}`;
|
|
798
750
|
},
|
|
799
|
-
toJsonTemplate(input) {
|
|
800
|
-
|
|
751
|
+
toJsonTemplate(input, target) {
|
|
752
|
+
if (schema.nullable) {
|
|
753
|
+
return `if (typeof ${input} === 'bigint') {
|
|
754
|
+
${target} += \`"\${${input}}"\`
|
|
755
|
+
} else {
|
|
756
|
+
${target} += 'null';
|
|
757
|
+
}`;
|
|
758
|
+
}
|
|
759
|
+
return `${target} += \`"\${${input}}"\``;
|
|
801
760
|
},
|
|
802
|
-
|
|
761
|
+
toQueryStringTemplate(input, target, key) {
|
|
762
|
+
return `${target}.push(\`${key}=\${${input}}\`)`;
|
|
763
|
+
},
|
|
764
|
+
content: ""
|
|
803
765
|
};
|
|
804
766
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const
|
|
808
|
-
|
|
767
|
+
|
|
768
|
+
function tsRecordFromSchema(schema, context) {
|
|
769
|
+
const innerType = tsTypeFromSchema(schema.values, {
|
|
770
|
+
clientName: context.clientName,
|
|
771
|
+
typePrefix: context.typePrefix,
|
|
772
|
+
generatedTypes: context.generatedTypes,
|
|
773
|
+
instancePath: `${context.instancePath}/[value]`,
|
|
774
|
+
schemaPath: `${context.schemaPath}/values`,
|
|
775
|
+
discriminatorParent: "",
|
|
776
|
+
discriminatorKey: "",
|
|
777
|
+
discriminatorValue: "",
|
|
778
|
+
versionNumber: context.versionNumber,
|
|
779
|
+
usedFeatures: context.usedFeatures
|
|
809
780
|
});
|
|
781
|
+
const typeName = `Record<string, ${innerType.typeName}>`;
|
|
782
|
+
const defaultValue = schema.nullable ? "null" : "{}";
|
|
810
783
|
return {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
784
|
+
typeName: schema.nullable ? `${typeName} | null` : typeName,
|
|
785
|
+
defaultValue,
|
|
786
|
+
validationTemplate(input) {
|
|
787
|
+
const mainPart = `isObject(${input}) && Object.values(${input}).every(
|
|
788
|
+
(_value) => ${innerType.validationTemplate("_value")},
|
|
789
|
+
)`;
|
|
790
|
+
if (schema.nullable) {
|
|
791
|
+
return `((${mainPart}) || ${input} === null)`;
|
|
817
792
|
}
|
|
818
|
-
|
|
819
|
-
|
|
793
|
+
return mainPart;
|
|
794
|
+
},
|
|
795
|
+
fromJsonTemplate(input, target) {
|
|
796
|
+
return `if (isObject(${input})) {
|
|
797
|
+
${target} = {};
|
|
798
|
+
for (const [_key, _value] of Object.entries(${input})) {
|
|
799
|
+
let ${target}Value: ${innerType.typeName};
|
|
800
|
+
if (typeof _value === 'boolean') {
|
|
801
|
+
${target}Value = _value;
|
|
802
|
+
} else {
|
|
803
|
+
${target}Value = false;
|
|
804
|
+
}
|
|
805
|
+
${target}[_key] = ${target}Value;
|
|
806
|
+
}
|
|
807
|
+
} else {
|
|
808
|
+
${target} = ${defaultValue};
|
|
809
|
+
}`;
|
|
810
|
+
},
|
|
811
|
+
toJsonTemplate(input, target, key) {
|
|
812
|
+
const countVal = `_${validVarName(key)}PropertyCount`;
|
|
813
|
+
if (schema.nullable) {
|
|
814
|
+
return `if (${input} !== null) {
|
|
815
|
+
${target} += '{';
|
|
816
|
+
let ${countVal} = 0;
|
|
817
|
+
for (const [_key, _value] of Object.entries(${input})) {
|
|
818
|
+
if (${countVal} !== 0) {
|
|
819
|
+
${target} += ',';
|
|
820
|
+
}
|
|
821
|
+
${target} += \`"\${_key}":\`;
|
|
822
|
+
${innerType.toJsonTemplate("_value", target, "_key")}
|
|
823
|
+
${countVal}++;
|
|
824
|
+
}
|
|
825
|
+
${target} += '}';
|
|
826
|
+
} else {
|
|
827
|
+
${target} += 'null';
|
|
828
|
+
}`;
|
|
820
829
|
}
|
|
821
|
-
return
|
|
830
|
+
return `${target} += '{'
|
|
831
|
+
let ${countVal} = 0;
|
|
832
|
+
for (const [_key, _value] of Object.entries(${input})) {
|
|
833
|
+
if (${countVal} !== 0) {
|
|
834
|
+
${target} += ',';
|
|
835
|
+
}
|
|
836
|
+
${target} += \`"\${_key}":\`;
|
|
837
|
+
${innerType.toJsonTemplate("_value", target, "_key")};
|
|
838
|
+
${countVal}++;
|
|
839
|
+
}
|
|
840
|
+
${target} += '}';
|
|
841
|
+
`;
|
|
842
|
+
},
|
|
843
|
+
toQueryStringTemplate(_, __, ___) {
|
|
844
|
+
return `console.warn('[WARNING] Cannot serialize nested objects to query string. Skipping property at ${context.instancePath}.')`;
|
|
822
845
|
},
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
846
|
+
content: innerType.content
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
function tsRefFromSchema(schema, context) {
|
|
851
|
+
const typeName = pascalCase(validVarName(schema.ref), { normalize: true });
|
|
852
|
+
const prefixedTypeName = `${context.typePrefix}${typeName}`;
|
|
853
|
+
const defaultValue = schema.nullable ? "null" : `${prefixedTypeName}.new()`;
|
|
854
|
+
return {
|
|
855
|
+
typeName: schema.nullable ? `${prefixedTypeName} | null` : prefixedTypeName,
|
|
856
|
+
defaultValue,
|
|
857
|
+
validationTemplate(input) {
|
|
858
|
+
if (schema.nullable) {
|
|
859
|
+
return `($$${prefixedTypeName}.validate(${input}) || ${input} === null)`;
|
|
826
860
|
}
|
|
827
|
-
|
|
828
|
-
|
|
861
|
+
return `$$${prefixedTypeName}.validate(${input})`;
|
|
862
|
+
},
|
|
863
|
+
fromJsonTemplate(input, target) {
|
|
864
|
+
return `if (isObject(${input})) {
|
|
865
|
+
${target} = $$${prefixedTypeName}.fromJson(${input});
|
|
866
|
+
} else {
|
|
867
|
+
${target} = ${defaultValue};
|
|
868
|
+
}`;
|
|
869
|
+
},
|
|
870
|
+
toJsonTemplate(input, target, _key) {
|
|
871
|
+
if (schema.nullable) {
|
|
872
|
+
return `if (${input} !== null) {
|
|
873
|
+
${target} += $$${prefixedTypeName}.toJsonString(${input});
|
|
874
|
+
} else {
|
|
875
|
+
${target} += 'null';
|
|
876
|
+
}`;
|
|
829
877
|
}
|
|
830
|
-
return
|
|
878
|
+
return `${target} += $$${prefixedTypeName}.toJsonString(${input});`;
|
|
879
|
+
},
|
|
880
|
+
toQueryStringTemplate(_, __, ___) {
|
|
881
|
+
return `console.warn("[WARNING] Nested objects cannot be serialized to query string. Ignoring property at ${context.instancePath}.");`;
|
|
831
882
|
},
|
|
832
883
|
content: ""
|
|
833
884
|
};
|
|
834
885
|
}
|
|
835
886
|
|
|
836
|
-
|
|
887
|
+
function tsRpcFromDefinition(def, context) {
|
|
888
|
+
switch (def.transport) {
|
|
889
|
+
case "http":
|
|
890
|
+
return httpRpcFromDefinition(def, context);
|
|
891
|
+
case "ws":
|
|
892
|
+
return wsRpcFromDefinition(def, context);
|
|
893
|
+
default:
|
|
894
|
+
console.warn(
|
|
895
|
+
`[ts-codegen] Warning: unsupported transport "${def.transport}". Ignoring ${context.instancePath}.`
|
|
896
|
+
);
|
|
897
|
+
return "";
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
function httpRpcFromDefinition(def, context) {
|
|
901
|
+
const key = getRpcKey(context);
|
|
902
|
+
const params = def.params ? `${context.typePrefix}${pascalCase(validVarName(def.params))}` : void 0;
|
|
903
|
+
const response = def.response ? `${context.typePrefix}${pascalCase(validVarName(def.response), { normalize: true })}` : void 0;
|
|
904
|
+
const serializerMethod = def.method === "get" ? "toUrlQueryString" : "toJsonString";
|
|
905
|
+
if (def.isEventStream) {
|
|
906
|
+
context.usedFeatures.sse = true;
|
|
907
|
+
return ` ${key}(${params ? `params: ${params},` : ""} options: SseOptions<${response ?? "undefined"}> = {}): EventSourceController {
|
|
908
|
+
return arriSseRequest<${response ?? "undefined"}, ${params ?? "undefined"}>(
|
|
909
|
+
{
|
|
910
|
+
url: \`\${this._baseUrl}${def.path}\`,
|
|
911
|
+
method: "${def.method.toLowerCase()}",
|
|
912
|
+
headers: this._headers,
|
|
913
|
+
${params ? "params: params," : ""}
|
|
914
|
+
responseFromJson: ${response ? `$$${response}.fromJson` : "() => {}"},
|
|
915
|
+
responseFromString: ${response ? `$$${response}.fromJsonString` : "() => {}"},
|
|
916
|
+
serializer: ${params ? `$$${params}.${serializerMethod}` : "() => {}"},
|
|
917
|
+
clientVersion: "${context.versionNumber}",
|
|
918
|
+
},
|
|
919
|
+
options,
|
|
920
|
+
)
|
|
921
|
+
}`;
|
|
922
|
+
}
|
|
923
|
+
return ` async ${key}(${params ? `params: ${params}` : ""}): Promise<${response ?? "undefined"}> {
|
|
924
|
+
return arriRequest<${response ?? "undefined"}, ${params ?? "undefined"}>({
|
|
925
|
+
url: \`\${this._baseUrl}${def.path}\`,
|
|
926
|
+
method: "${def.method.toLowerCase()}",
|
|
927
|
+
headers: this._headers,
|
|
928
|
+
${params ? "params: params," : ""}
|
|
929
|
+
responseFromJson: ${response ? `$$${response}.fromJson` : "() => {}"},
|
|
930
|
+
responseFromString: ${response ? `$$${response}.fromJsonString` : "() => {}"},
|
|
931
|
+
serializer: ${params ? `$$${params}.${serializerMethod}` : "() => {}"},
|
|
932
|
+
clientVersion: "${context.versionNumber}",
|
|
933
|
+
});
|
|
934
|
+
}`;
|
|
935
|
+
}
|
|
936
|
+
function wsRpcFromDefinition(def, context) {
|
|
937
|
+
context.usedFeatures.ws = true;
|
|
938
|
+
const key = getRpcKey(context);
|
|
939
|
+
const params = def.params ? `${context.typePrefix}${pascalCase(validVarName(def.params))}` : void 0;
|
|
940
|
+
const response = def.response ? `${context.typePrefix}${pascalCase(validVarName(def.response), { normalize: true })}` : void 0;
|
|
941
|
+
return ` async ${key}(options: WsOptions<${response ?? "undefined"}> = {}): Promise<WsController<${params ?? "undefined"},${response ?? "undefined"}>> {
|
|
942
|
+
return arriWsRequest<${params ?? "undefined"}, ${response ?? "undefined"}>({
|
|
943
|
+
url: \`\${this._baseUrl}${def.path}\`,
|
|
944
|
+
headers: this._headers,
|
|
945
|
+
responseFromJson: ${response ? `$$${response}.fromJson` : "() => {}"},
|
|
946
|
+
responseFromString: ${response ? `$$${response}.fromJsonString` : "() => {}"},
|
|
947
|
+
serializer: ${params ? `$$${params}.toJsonString` : "() => {}"},
|
|
948
|
+
onOpen: options.onOpen,
|
|
949
|
+
onClose: options.onClose,
|
|
950
|
+
onError: options.onError,
|
|
951
|
+
onConnectionError: options.onConnectionError,
|
|
952
|
+
onMessage: options.onMessage,
|
|
953
|
+
clientVersion: "${context.versionNumber}",
|
|
954
|
+
});
|
|
955
|
+
}`;
|
|
956
|
+
}
|
|
957
|
+
function getRpcKey(context) {
|
|
958
|
+
const name = context.instancePath.split(".").pop() ?? "";
|
|
959
|
+
return validVarName(name);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function tsServiceFromDefinition(def, context) {
|
|
963
|
+
const key = getServiceKey(context);
|
|
964
|
+
const serviceName = getServiceName(context);
|
|
965
|
+
const rpcParts = [];
|
|
966
|
+
const subServices = [];
|
|
967
|
+
for (const key2 of Object.keys(def)) {
|
|
968
|
+
const subDef = def[key2];
|
|
969
|
+
if (isServiceDefinition(subDef)) {
|
|
970
|
+
const subService = tsServiceFromDefinition(subDef, {
|
|
971
|
+
clientName: context.clientName,
|
|
972
|
+
typePrefix: context.typePrefix,
|
|
973
|
+
generatedTypes: context.generatedTypes,
|
|
974
|
+
instancePath: `${context.instancePath}.${key2}`,
|
|
975
|
+
schemaPath: `${context.instancePath}.${key2}`,
|
|
976
|
+
discriminatorParent: "",
|
|
977
|
+
discriminatorKey: "",
|
|
978
|
+
discriminatorValue: "",
|
|
979
|
+
versionNumber: context.versionNumber,
|
|
980
|
+
usedFeatures: context.usedFeatures
|
|
981
|
+
});
|
|
982
|
+
if (subService.content) {
|
|
983
|
+
subServices.push(subService);
|
|
984
|
+
}
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
if (isRpcDefinition(subDef)) {
|
|
988
|
+
const rpc = tsRpcFromDefinition(subDef, {
|
|
989
|
+
clientName: context.clientName,
|
|
990
|
+
typePrefix: context.typePrefix,
|
|
991
|
+
generatedTypes: context.generatedTypes,
|
|
992
|
+
instancePath: `${context.instancePath}.${key2}`,
|
|
993
|
+
schemaPath: `${context.schemaPath}.${key2}`,
|
|
994
|
+
discriminatorParent: "",
|
|
995
|
+
discriminatorKey: "",
|
|
996
|
+
discriminatorValue: "",
|
|
997
|
+
versionNumber: context.versionNumber,
|
|
998
|
+
usedFeatures: context.usedFeatures
|
|
999
|
+
});
|
|
1000
|
+
if (rpc) {
|
|
1001
|
+
rpcParts.push(rpc);
|
|
1002
|
+
}
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
console.warn(
|
|
1006
|
+
`Invalid definition found at procedures.${context.schemaPath}`
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
if (subServices.length === 0 && rpcParts.length === 0) {
|
|
1010
|
+
return {
|
|
1011
|
+
key,
|
|
1012
|
+
name: serviceName,
|
|
1013
|
+
content: ""
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
key,
|
|
1018
|
+
name: serviceName,
|
|
1019
|
+
content: `export class ${serviceName} {
|
|
1020
|
+
private readonly _baseUrl: string;
|
|
1021
|
+
private readonly _headers: HeaderMap | (() => HeaderMap | Promise<HeaderMap>);
|
|
1022
|
+
${subServices.map((service) => ` ${service.key}: ${service.name};`).join("\n")}
|
|
1023
|
+
constructor(
|
|
1024
|
+
options: {
|
|
1025
|
+
baseUrl?: string;
|
|
1026
|
+
headers?: HeaderMap | (() => HeaderMap | Promise<HeaderMap>);
|
|
1027
|
+
} = {},
|
|
1028
|
+
) {
|
|
1029
|
+
this._baseUrl = options.baseUrl ?? "";
|
|
1030
|
+
this._headers = options.headers ?? {};
|
|
1031
|
+
${subServices.map((service) => ` this.${service.key} = new ${service.name}(options);`).join("\n")}
|
|
1032
|
+
}
|
|
1033
|
+
${rpcParts.map((rpc) => ` ${rpc}`).join("\n")}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
${subServices.map((service) => service.content).join("\n")}`
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
function getServiceKey(context) {
|
|
1040
|
+
const name = context.instancePath.split(".").pop() ?? "";
|
|
1041
|
+
return validVarName(name);
|
|
1042
|
+
}
|
|
1043
|
+
function getServiceName(context) {
|
|
1044
|
+
if (context.instancePath.length === 0) {
|
|
1045
|
+
return context.clientName;
|
|
1046
|
+
}
|
|
1047
|
+
const serviceName = pascalCase(context.instancePath.split(".").join("_"), {
|
|
1048
|
+
normalize: true
|
|
1049
|
+
});
|
|
1050
|
+
return `${context.clientName}${serviceName}Service`;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
const typescriptClientGenerator = defineGeneratorPlugin(
|
|
1054
|
+
(options) => ({
|
|
1055
|
+
generator: async (def) => {
|
|
1056
|
+
if (!options.clientName) {
|
|
1057
|
+
throw new Error("Name is requires");
|
|
1058
|
+
}
|
|
1059
|
+
if (!options.outputFile) {
|
|
1060
|
+
throw new Error("No output file specified");
|
|
1061
|
+
}
|
|
1062
|
+
if (Object.keys(def.procedures).length <= 0) {
|
|
1063
|
+
console.warn(
|
|
1064
|
+
`No procedures defined in AppDefinition. Only data models will be outputted.`
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
const result = await createTypescriptClient(def, options);
|
|
1068
|
+
writeFileSync(options.outputFile, result);
|
|
1069
|
+
},
|
|
1070
|
+
options
|
|
1071
|
+
})
|
|
1072
|
+
);
|
|
1073
|
+
async function createTypescriptClient(def, options) {
|
|
1074
|
+
const types = [];
|
|
1075
|
+
const context = {
|
|
1076
|
+
clientName: options.clientName,
|
|
1077
|
+
typePrefix: options.typePrefix ?? "",
|
|
1078
|
+
generatedTypes: [],
|
|
1079
|
+
instancePath: "",
|
|
1080
|
+
schemaPath: "",
|
|
1081
|
+
discriminatorParent: "",
|
|
1082
|
+
discriminatorKey: "",
|
|
1083
|
+
discriminatorValue: "",
|
|
1084
|
+
versionNumber: def.info?.version ?? "",
|
|
1085
|
+
usedFeatures: {
|
|
1086
|
+
sse: false,
|
|
1087
|
+
ws: false
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
const serviceDefinitions = unflattenProcedures(def.procedures);
|
|
1091
|
+
const mainService = tsServiceFromDefinition(serviceDefinitions, context);
|
|
1092
|
+
for (const key of Object.keys(def.definitions)) {
|
|
1093
|
+
const typeDef = def.definitions[key];
|
|
1094
|
+
const result2 = tsTypeFromSchema(typeDef, {
|
|
1095
|
+
clientName: context.clientName,
|
|
1096
|
+
typePrefix: context.typePrefix,
|
|
1097
|
+
generatedTypes: context.generatedTypes,
|
|
1098
|
+
instancePath: `/${key}`,
|
|
1099
|
+
schemaPath: `/${key}`,
|
|
1100
|
+
discriminatorParent: "",
|
|
1101
|
+
discriminatorKey: "",
|
|
1102
|
+
discriminatorValue: "",
|
|
1103
|
+
versionNumber: context.versionNumber,
|
|
1104
|
+
usedFeatures: context.usedFeatures
|
|
1105
|
+
});
|
|
1106
|
+
if (result2.content) {
|
|
1107
|
+
types.push(result2.content);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const imports = `// This file was autogenerated by @arrirpc/codegen-ts. Do not modify directly.
|
|
1111
|
+
// For more information visit https://github.com/modiimedia/arri
|
|
1112
|
+
|
|
1113
|
+
/* eslint-disable */
|
|
1114
|
+
// @ts-nocheck
|
|
1115
|
+
import {
|
|
1116
|
+
ArriEnumValidator,
|
|
1117
|
+
ArriModelValidator,
|
|
1118
|
+
arriRequest,
|
|
1119
|
+
${context.usedFeatures.sse ? "arriSseRequest," : ""}
|
|
1120
|
+
${context.usedFeatures.ws ? "arriWsRequest," : ""}
|
|
1121
|
+
${context.usedFeatures.sse ? "type EventSourceController," : ""}
|
|
1122
|
+
INT8_MAX,
|
|
1123
|
+
INT8_MIN,
|
|
1124
|
+
INT16_MAX,
|
|
1125
|
+
INT16_MIN,
|
|
1126
|
+
INT32_MAX,
|
|
1127
|
+
INT32_MIN,
|
|
1128
|
+
INT64_MAX,
|
|
1129
|
+
INT64_MIN,
|
|
1130
|
+
isObject,
|
|
1131
|
+
serializeString,
|
|
1132
|
+
${context.usedFeatures.sse ? "type SseOptions," : ""}
|
|
1133
|
+
UINT8_MAX,
|
|
1134
|
+
UINT16_MAX,
|
|
1135
|
+
UINT32_MAX,
|
|
1136
|
+
UINT64_MAX,
|
|
1137
|
+
${context.usedFeatures.ws ? "type WsController," : ""}
|
|
1138
|
+
${context.usedFeatures.ws ? "type WsOptions," : ""}
|
|
1139
|
+
} from "@arrirpc/client";
|
|
1140
|
+
|
|
1141
|
+
type HeaderMap = Record<string, string | undefined>;`;
|
|
1142
|
+
if (!mainService.content) {
|
|
1143
|
+
const result2 = `${imports}
|
|
1144
|
+
|
|
1145
|
+
${types.join("\n")}`;
|
|
1146
|
+
return await prettier.format(result2, {
|
|
1147
|
+
...options.prettierOptions,
|
|
1148
|
+
parser: "typescript"
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
const result = `${imports}
|
|
1152
|
+
${mainService.content}
|
|
1153
|
+
|
|
1154
|
+
${types.join("\n")}`;
|
|
1155
|
+
return await prettier.format(result, {
|
|
1156
|
+
...options.prettierOptions,
|
|
1157
|
+
parser: "typescript"
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
function tsTypeFromSchema(schema, context) {
|
|
1161
|
+
if (isSchemaFormType(schema)) {
|
|
1162
|
+
switch (schema.type) {
|
|
1163
|
+
case "string":
|
|
1164
|
+
return tsStringFromSchema(schema);
|
|
1165
|
+
case "boolean":
|
|
1166
|
+
return tsBooleanFromSchema(schema);
|
|
1167
|
+
case "timestamp":
|
|
1168
|
+
return tsDateFromSchema(schema);
|
|
1169
|
+
case "float32":
|
|
1170
|
+
case "float64":
|
|
1171
|
+
return tsFloatFromSchema(schema);
|
|
1172
|
+
case "int8":
|
|
1173
|
+
return tsIntFromSchema(schema, "int8");
|
|
1174
|
+
case "uint8":
|
|
1175
|
+
return tsIntFromSchema(schema, "uint8");
|
|
1176
|
+
case "int16":
|
|
1177
|
+
return tsIntFromSchema(schema, "int16");
|
|
1178
|
+
case "uint16":
|
|
1179
|
+
return tsIntFromSchema(schema, "uint16");
|
|
1180
|
+
case "int32":
|
|
1181
|
+
return tsIntFromSchema(schema, "int32");
|
|
1182
|
+
case "uint32":
|
|
1183
|
+
return tsIntFromSchema(schema, "uint32");
|
|
1184
|
+
case "int64":
|
|
1185
|
+
return tsBigIntFromSchema(schema, false);
|
|
1186
|
+
case "uint64":
|
|
1187
|
+
return tsBigIntFromSchema(schema, true);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (isSchemaFormEnum(schema)) {
|
|
1191
|
+
return tsEnumFromSchema(schema, context);
|
|
1192
|
+
}
|
|
1193
|
+
if (isSchemaFormProperties(schema)) {
|
|
1194
|
+
return tsObjectFromSchema(schema, context);
|
|
1195
|
+
}
|
|
1196
|
+
if (isSchemaFormElements(schema)) {
|
|
1197
|
+
return tsArrayFromSchema(schema, context);
|
|
1198
|
+
}
|
|
1199
|
+
if (isSchemaFormValues(schema)) {
|
|
1200
|
+
return tsRecordFromSchema(schema, context);
|
|
1201
|
+
}
|
|
1202
|
+
if (isSchemaFormDiscriminator(schema)) {
|
|
1203
|
+
return tsTaggedUnionFromSchema(schema, context);
|
|
1204
|
+
}
|
|
1205
|
+
if (isSchemaFormRef(schema)) {
|
|
1206
|
+
return tsRefFromSchema(schema, context);
|
|
1207
|
+
}
|
|
1208
|
+
return tsAnyFromSchema(schema, context);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
export { createTypescriptClient, tsTypeFromSchema, typescriptClientGenerator };
|