@arrirpc/codegen-ts 0.45.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 ADDED
@@ -0,0 +1,858 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const codegenUtils = require('@arrirpc/codegen-utils');
5
+ const schema = require('@arrirpc/schema');
6
+ const prettier = require('prettier');
7
+
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
9
+
10
+ const prettier__default = /*#__PURE__*/_interopDefaultCompat(prettier);
11
+
12
+ const typescriptClientGenerator = codegenUtils.defineClientGeneratorPlugin(
13
+ (options) => ({
14
+ generator: async (def) => {
15
+ if (!options.clientName) {
16
+ throw new Error("Name is requires");
17
+ }
18
+ if (!options.outputFile) {
19
+ throw new Error("No output file specified");
20
+ }
21
+ if (Object.keys(def.procedures).length <= 0) {
22
+ console.warn(
23
+ `No procedures defined in AppDefinition. Only data models will be outputted.`
24
+ );
25
+ }
26
+ const result = await createTypescriptClient(def, options);
27
+ fs.writeFileSync(options.outputFile, result);
28
+ },
29
+ options
30
+ })
31
+ );
32
+ async function createTypescriptClient(def, options) {
33
+ const clientName = codegenUtils.pascalCase(options.clientName);
34
+ const services = codegenUtils.unflattenProcedures(def.procedures);
35
+ const serviceFieldParts = [];
36
+ const serviceInitializationParts = [];
37
+ const procedureParts = [];
38
+ const subContentParts = [];
39
+ const existingTypeNames = [];
40
+ const rpcOptions = {
41
+ ...options,
42
+ versionNumber: def.info?.version ?? "",
43
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
44
+ typesNeedingParser: Object.keys(def.definitions),
45
+ hasSseProcedures: false,
46
+ hasWsProcedures: false
47
+ };
48
+ Object.keys(services).forEach((key) => {
49
+ const item = services[key];
50
+ if (codegenUtils.isRpcDefinition(item)) {
51
+ const rpc = tsRpcFromDefinition(key, item, rpcOptions);
52
+ if (rpc) {
53
+ procedureParts.push(rpc);
54
+ }
55
+ return;
56
+ }
57
+ if (codegenUtils.isServiceDefinition(item)) {
58
+ const serviceName = codegenUtils.pascalCase(`${clientName}_${key}`);
59
+ const service = tsServiceFromDefinition(
60
+ serviceName,
61
+ item,
62
+ rpcOptions
63
+ );
64
+ serviceFieldParts.push(`${key}: ${serviceName}Service;`);
65
+ serviceInitializationParts.push(
66
+ `this.${key} = new ${serviceName}Service(options);`
67
+ );
68
+ subContentParts.push(service);
69
+ }
70
+ });
71
+ for (const key of rpcOptions.typesNeedingParser) {
72
+ const schema = def.definitions[key];
73
+ if (codegenUtils.isSchemaFormProperties(schema) || codegenUtils.isSchemaFormDiscriminator(schema)) {
74
+ const type = tsTypeFromJtdSchema(key, schema, rpcOptions, {
75
+ isOptional: false,
76
+ existingTypeNames
77
+ });
78
+ subContentParts.push(type.content);
79
+ }
80
+ }
81
+ const importParts = ["arriRequest"];
82
+ if (rpcOptions.hasSseProcedures) {
83
+ importParts.push("arriSseRequest");
84
+ importParts.push("type SseOptions");
85
+ }
86
+ if (rpcOptions.hasWsProcedures) {
87
+ importParts.push("arriWsRequest");
88
+ importParts.push("type WsOptions");
89
+ }
90
+ if (procedureParts.length === 0 && serviceFieldParts.length === 0) {
91
+ const result2 = `/* eslint-disable */
92
+ // @ts-nocheck
93
+ // this file was autogenerated by arri-codegen-ts
94
+
95
+ ${subContentParts.join("\n")}`;
96
+ return prettier__default.format(result2, {
97
+ parser: "typescript",
98
+ ...options.prettierOptions
99
+ });
100
+ }
101
+ const result = `/* eslint-disable */
102
+ // @ts-nocheck
103
+ // this file was autogenerated by arri-codegen-ts
104
+ import { ${importParts.join(", ")} } from '@arrirpc/client';
105
+
106
+ interface ${clientName}Options {
107
+ baseUrl?: string;
108
+ headers?: Record<string, string> | (() => Record<string, string>);
109
+ }
110
+
111
+ export class ${clientName} {
112
+ private readonly baseUrl: string;
113
+ private readonly headers: Record<string, string> | (() => Record<string, string>)
114
+ private readonly clientVersion = '${rpcOptions.versionNumber}';
115
+ ${serviceFieldParts.join("\n ")}
116
+
117
+ constructor(options: ${clientName}Options = {}) {
118
+ this.baseUrl = options.baseUrl ?? "";
119
+ this.headers = options.headers ?? {};
120
+ ${serviceInitializationParts.join(";\n ")}
121
+ }
122
+ ${procedureParts.join("\n ")}
123
+ }
124
+
125
+ ${subContentParts.join("\n")}
126
+ `;
127
+ return await prettier__default.format(result, {
128
+ parser: "typescript",
129
+ ...options.prettierOptions
130
+ });
131
+ }
132
+ function tsRpcFromDefinition(key, schema, options) {
133
+ if (schema.transport === "http") {
134
+ return tsHttpRpcFromDefinition(key, schema, options);
135
+ }
136
+ if (schema.transport === "ws") {
137
+ return tsWsRpcFromDefinition(key, schema, options);
138
+ }
139
+ console.warn(
140
+ `[codegen-ts] Unsupported transport "${schema.transport}". Ignoring rpc.`
141
+ );
142
+ return "";
143
+ }
144
+ function tsHttpRpcFromDefinition(key, schema, options) {
145
+ const paramName = codegenUtils.pascalCase(schema.params ?? "");
146
+ const responseName = codegenUtils.pascalCase(schema.response ?? "");
147
+ const paramsInput = schema.params ? `params: ${paramName}` : "";
148
+ const hasInput = paramName.length > 0;
149
+ const hasOutput = responseName.length > 0;
150
+ let serializerPart = `(_) => {}`;
151
+ let parserPart = `(_) => {}`;
152
+ if (hasInput) {
153
+ serializerPart = `$$${paramName}.serialize`;
154
+ }
155
+ if (hasOutput) {
156
+ parserPart = `$$${responseName}.parse`;
157
+ }
158
+ const paramsOutput = hasInput ? `params` : `params: undefined`;
159
+ if (schema.isEventStream) {
160
+ options.hasSseProcedures = true;
161
+ return `${getJsDocComment({ isDeprecated: schema.isDeprecated, description: schema.description })}${key}(${paramsInput.length ? `${paramsInput}, ` : ""}options: SseOptions<${schema.response ?? "undefined"}>) {
162
+ return arriSseRequest<${schema.response ?? "undefined"}, ${schema.params ?? "undefined"}>({
163
+ url: \`\${this.baseUrl}${schema.path}\`,
164
+ method: "${schema.method}",
165
+ headers: this.headers,
166
+ ${paramsOutput},
167
+ parser: ${parserPart},
168
+ serializer: ${serializerPart},
169
+ clientVersion: this.clientVersion,
170
+ }, options);
171
+ }`;
172
+ }
173
+ return `${getJsDocComment({ isDeprecated: schema.isDeprecated, description: schema.description })}${key}(${paramsInput}) {
174
+ return arriRequest<${schema.response ?? "undefined"}, ${schema.params ?? "undefined"}>({
175
+ url: \`\${this.baseUrl}${schema.path}\`,
176
+ method: "${schema.method}",
177
+ headers: this.headers,
178
+ ${paramsOutput},
179
+ parser: ${parserPart},
180
+ serializer: ${serializerPart},
181
+ clientVersion: this.clientVersion,
182
+ });
183
+ }`;
184
+ }
185
+ function tsWsRpcFromDefinition(key, schema, options) {
186
+ options.hasWsProcedures = true;
187
+ const paramName = schema.params ? codegenUtils.pascalCase(schema.params) : "undefined";
188
+ const responseName = schema.response ? codegenUtils.pascalCase(schema.response) : "undefined";
189
+ const hasInput = paramName.length > 0 && paramName !== "undefined";
190
+ const hasOutput = responseName.length > 0 && paramName !== "undefined";
191
+ let serializerPart = `(_) => {}`;
192
+ let parserPart = `(_) => {}`;
193
+ if (hasInput) {
194
+ serializerPart = `$$${paramName}.serialize`;
195
+ }
196
+ if (hasOutput) {
197
+ parserPart = `$$${responseName}.parse`;
198
+ }
199
+ return `${getJsDocComment(schema)}${key}(options: WsOptions<${responseName}> = {}) {
200
+ return arriWsRequest<${paramName}, ${responseName}>({
201
+ url: \`\${this.baseUrl}${schema.path}\`,
202
+ headers: this.headers,
203
+ parser: ${parserPart},
204
+ serializer: ${serializerPart},
205
+ onOpen: options.onOpen,
206
+ onClose: options.onClose,
207
+ onError: options.onError,
208
+ onConnectionError: options.onConnectionError,
209
+ onMessage: options.onMessage,
210
+ clientVersion: this.clientVersion,
211
+ })
212
+ }`;
213
+ }
214
+ function tsServiceFromDefinition(name, schema, options) {
215
+ const serviceFieldParts = [];
216
+ const serviceConstructorParts = [];
217
+ const subServiceContent = [];
218
+ const rpcContent = [];
219
+ Object.keys(schema).forEach((key) => {
220
+ const def = schema[key];
221
+ if (codegenUtils.isRpcDefinition(def)) {
222
+ const rpc = tsRpcFromDefinition(key, def, options);
223
+ if (rpc) {
224
+ rpcContent.push(rpc);
225
+ }
226
+ return;
227
+ }
228
+ if (codegenUtils.isServiceDefinition(def)) {
229
+ const serviceName = codegenUtils.pascalCase(`${name}_${key}`);
230
+ const service = tsServiceFromDefinition(serviceName, def, options);
231
+ serviceFieldParts.push(`${key}: ${serviceName}Service;`);
232
+ serviceConstructorParts.push(
233
+ `this.${key} = new ${serviceName}Service(options);`
234
+ );
235
+ subServiceContent.push(service);
236
+ }
237
+ });
238
+ return `export class ${name}Service {
239
+ private readonly baseUrl: string;
240
+ private readonly headers: Record<string, string> | (() => Record<string, string>);
241
+ private readonly clientVersion = '${options.versionNumber}';
242
+ ${serviceFieldParts.join("\n ")}
243
+
244
+ constructor(options: ${codegenUtils.pascalCase(
245
+ `${options.clientName}_Options`
246
+ )} = {}) {
247
+ this.baseUrl = options.baseUrl ?? '';
248
+ this.headers = options.headers ?? {};
249
+ ${serviceConstructorParts.join("\n ")}
250
+ }
251
+ ${rpcContent.join("\n ")}
252
+ }
253
+ ${subServiceContent.join("\n")}`;
254
+ }
255
+ function tsTypeFromJtdSchema(nodePath, def, options, additionalOptions) {
256
+ if (additionalOptions.logDef) {
257
+ console.log(def);
258
+ }
259
+ if (codegenUtils.isSchemaFormType(def)) {
260
+ return tsScalarFromJtdSchema(nodePath, def, options, additionalOptions);
261
+ }
262
+ if (codegenUtils.isSchemaFormProperties(def)) {
263
+ return tsObjectFromJtdSchema(nodePath, def, options, additionalOptions);
264
+ }
265
+ if (codegenUtils.isSchemaFormEnum(def)) {
266
+ return tsEnumFromJtdSchema(nodePath, def, options, additionalOptions);
267
+ }
268
+ if (codegenUtils.isSchemaFormElements(def)) {
269
+ return tsArrayFromJtdSchema(nodePath, def, options, additionalOptions);
270
+ }
271
+ if (codegenUtils.isSchemaFormDiscriminator(def)) {
272
+ return tsDiscriminatedUnionFromJtdSchema(
273
+ nodePath,
274
+ def,
275
+ options,
276
+ additionalOptions
277
+ );
278
+ }
279
+ if (codegenUtils.isSchemaFormValues(def)) {
280
+ return tsRecordFromJtdSchema(nodePath, def, options, additionalOptions);
281
+ }
282
+ if (codegenUtils.isSchemaFormRef(def)) {
283
+ return tsRefFromJtdSchema(nodePath, def, options, additionalOptions);
284
+ }
285
+ return tsAnyFromJtdSchema(nodePath, def, options, additionalOptions);
286
+ }
287
+ function maybeOptionalKey(keyName, isOptional = false) {
288
+ if (isOptional) {
289
+ return `${keyName}?`;
290
+ }
291
+ return keyName;
292
+ }
293
+ function maybeNullType(typeName, isNullable = false) {
294
+ if (isNullable) {
295
+ return `${typeName} | null`;
296
+ }
297
+ return typeName;
298
+ }
299
+ function tsAnyFromJtdSchema(nodePath, def, options, additionalOptions) {
300
+ const key = nodePath.split(".").pop() ?? "";
301
+ const isNullable = def.nullable ?? false;
302
+ const isOptional = additionalOptions.isOptional;
303
+ return {
304
+ tsType: "any",
305
+ schema: def,
306
+ fieldTemplate: `${maybeOptionalKey(key, isOptional)}: ${maybeNullType(
307
+ "any",
308
+ isNullable
309
+ )}`,
310
+ fromJsonTemplate(input) {
311
+ return input;
312
+ },
313
+ toJsonTemplate(input) {
314
+ return `JSON.stringify(${input})`;
315
+ },
316
+ content: ""
317
+ };
318
+ }
319
+ function getJsDocComment(metadata) {
320
+ const descriptionParts = [];
321
+ if (metadata?.description?.length) {
322
+ const parts = metadata.description.split("\n");
323
+ for (const part of parts) {
324
+ descriptionParts.push(`* ${part}`);
325
+ }
326
+ }
327
+ if (metadata?.isDeprecated) {
328
+ descriptionParts.push("* @deprecated");
329
+ }
330
+ if (descriptionParts.length === 0) {
331
+ return "";
332
+ }
333
+ return `/**
334
+ ${descriptionParts.join("\n")}
335
+ */
336
+ `;
337
+ }
338
+ function tsScalarFromJtdSchema(nodePath, def, options, additionalOptions) {
339
+ const key = nodePath.split(".").pop() ?? "";
340
+ const isNullable = def.nullable ?? false;
341
+ const isOptional = additionalOptions.isOptional;
342
+ switch (def.type) {
343
+ case "boolean":
344
+ return {
345
+ tsType: "boolean",
346
+ schema: def,
347
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
348
+ key,
349
+ isOptional
350
+ )}: ${maybeNullType("boolean", isNullable)}`,
351
+ fromJsonTemplate(input) {
352
+ if (isOptional) {
353
+ return `typeof ${input} === 'boolean' ? ${input} : undefined`;
354
+ }
355
+ if (isNullable) {
356
+ return `typeof ${input} === 'boolean' ? ${input} : null`;
357
+ }
358
+ return `typeof ${input} === 'boolean' ? ${input} : false`;
359
+ },
360
+ toJsonTemplate(input) {
361
+ if (isNullable) {
362
+ return `typeof ${input} === 'boolean' ? ${input} : null`;
363
+ }
364
+ return `typeof ${input} === 'boolean' ? ${input} : false`;
365
+ },
366
+ content: ""
367
+ };
368
+ case "string":
369
+ return {
370
+ tsType: "string",
371
+ schema: def,
372
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
373
+ key,
374
+ isOptional
375
+ )}: ${maybeNullType("string", isNullable)}`,
376
+ fromJsonTemplate(input) {
377
+ if (isOptional) {
378
+ return `typeof ${input} === 'string' ? ${input} : undefined`;
379
+ }
380
+ if (isNullable) {
381
+ return `typeof ${input} === 'string' ? ${input} : null`;
382
+ }
383
+ return `typeof ${input} === 'string' ? ${input} : ''`;
384
+ },
385
+ toJsonTemplate(input) {
386
+ if (isNullable) {
387
+ return `typeof ${input} === 'string' ? \`"${input}"\` : null`;
388
+ }
389
+ return `typeof ${input} === 'string' ? \`"${input}"\` : ""`;
390
+ },
391
+ content: ""
392
+ };
393
+ case "timestamp":
394
+ return {
395
+ tsType: "Date",
396
+ schema: def,
397
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
398
+ key,
399
+ isOptional
400
+ )}: ${maybeNullType("Date", isNullable)}`,
401
+ fromJsonTemplate(input) {
402
+ if (isOptional) {
403
+ return `typeof ${input} === 'string' ? new Date(${input}) : undefined`;
404
+ }
405
+ if (isNullable) {
406
+ return `typeof ${input} === 'string' ? new Date(${input}) : null`;
407
+ }
408
+ return `typeof ${input} === 'string' ? new Date(${input}) : new Date(0)`;
409
+ },
410
+ toJsonTemplate(input) {
411
+ if (isOptional || isNullable) {
412
+ return `typeof ${input} === 'object' && ${input} instanceof Date ? "${input}.toISOString()" : null`;
413
+ }
414
+ return `"${input}.toISOString()"`;
415
+ },
416
+ content: ""
417
+ };
418
+ case "float32":
419
+ case "float64":
420
+ case "int8":
421
+ case "int16":
422
+ case "int32":
423
+ case "uint8":
424
+ case "uint16":
425
+ case "uint32":
426
+ return {
427
+ tsType: "number",
428
+ schema: def,
429
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
430
+ key,
431
+ isOptional
432
+ )}: ${maybeNullType("number", isNullable)}`,
433
+ fromJsonTemplate(input) {
434
+ if (isOptional) {
435
+ return `typeof ${input} === 'number' ? ${input} : undefined`;
436
+ }
437
+ if (isNullable) {
438
+ return `typeof ${input} === 'number' ? ${input} : null`;
439
+ }
440
+ return `typeof ${input} === 'number' ? ${input} : 0`;
441
+ },
442
+ toJsonTemplate(input) {
443
+ return `JSON.stringify(${input})`;
444
+ },
445
+ content: ""
446
+ };
447
+ case "int64":
448
+ case "uint64":
449
+ return {
450
+ tsType: "bigint",
451
+ schema: def,
452
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
453
+ key,
454
+ isOptional
455
+ )}: ${maybeNullType("bigint", isNullable)}`,
456
+ fromJsonTemplate(input) {
457
+ if (isOptional) {
458
+ return `typeof ${input} === 'string' ? BigInt(${input}) : undefined`;
459
+ }
460
+ if (isNullable) {
461
+ return `typeof ${input} === 'string' ? BigInt(${input}) : null`;
462
+ }
463
+ return `typeof ${input} === 'string' ? BigInt(${input}) : BigInt("0")`;
464
+ },
465
+ toJsonTemplate(input) {
466
+ if (isOptional || isNullable) {
467
+ return `${input}?.toString()`;
468
+ }
469
+ return `${input}.toString()`;
470
+ },
471
+ content: ""
472
+ };
473
+ default:
474
+ def.type;
475
+ throw new Error(`Invalid type in SchemaFormType`);
476
+ }
477
+ }
478
+ function getTypeName(nodePath, def) {
479
+ if (def.metadata?.id) {
480
+ return codegenUtils.pascalCase(def.metadata.id);
481
+ }
482
+ return codegenUtils.pascalCase(nodePath.split(".").join("_"));
483
+ }
484
+ function tsObjectFromJtdSchema(nodePath, def, options, additionalOptions) {
485
+ const typeName = getTypeName(nodePath, def);
486
+ const key = nodePath.split(".").pop() ?? "";
487
+ const fieldNames = [];
488
+ const fieldParts = [];
489
+ const subContentParts = [];
490
+ const parserParts = [];
491
+ if (additionalOptions.discriminatorKey && additionalOptions.discriminatorKeyValue) {
492
+ parserParts.push(
493
+ `${additionalOptions.discriminatorKey}: '${additionalOptions.discriminatorKeyValue}'`
494
+ );
495
+ fieldParts.push(
496
+ `${additionalOptions.discriminatorKey}: "${additionalOptions.discriminatorKeyValue}"`
497
+ );
498
+ fieldNames.push(additionalOptions.discriminatorKey);
499
+ }
500
+ if (def.properties) {
501
+ for (const propKey of Object.keys(def.properties)) {
502
+ const propSchema = def.properties[propKey];
503
+ const type = tsTypeFromJtdSchema(
504
+ `${nodePath}.${propKey}`,
505
+ propSchema,
506
+ options,
507
+ {
508
+ isOptional: false,
509
+ existingTypeNames: additionalOptions.existingTypeNames
510
+ }
511
+ );
512
+ parserParts.push(
513
+ `${propKey}: ${type.fromJsonTemplate(`input.${propKey}`)}`
514
+ );
515
+ fieldParts.push(type.fieldTemplate);
516
+ fieldNames.push(propKey);
517
+ if (type.content) {
518
+ subContentParts.push(type.content);
519
+ }
520
+ }
521
+ }
522
+ if (def.optionalProperties) {
523
+ for (const propKey of Object.keys(def.optionalProperties)) {
524
+ const propSchema = def.optionalProperties[propKey];
525
+ const type = tsTypeFromJtdSchema(
526
+ `${nodePath}.${propKey}`,
527
+ propSchema,
528
+ options,
529
+ {
530
+ isOptional: true,
531
+ existingTypeNames: additionalOptions.existingTypeNames
532
+ }
533
+ );
534
+ parserParts.push(
535
+ `${propKey}: ${type.fromJsonTemplate(`input.${propKey}`)}`
536
+ );
537
+ fieldParts.push(type.fieldTemplate);
538
+ fieldNames.push(propKey);
539
+ if (type.content) {
540
+ subContentParts.push(type.content);
541
+ }
542
+ }
543
+ }
544
+ let content = "";
545
+ const modifiedDef = {
546
+ ...def,
547
+ metadata: {
548
+ id: def.metadata?.id ?? typeName,
549
+ description: def.metadata?.description
550
+ },
551
+ nullable: false
552
+ };
553
+ let validatorPart = "";
554
+ if (options.typesNeedingParser.includes(typeName)) {
555
+ const parsingCode = schema.getSchemaParsingCode("input", modifiedDef);
556
+ const serializationCode = schema.getSchemaSerializationCode(
557
+ "input",
558
+ modifiedDef
559
+ );
560
+ validatorPart = `export const $$${typeName} = {
561
+ parse(input: Record<any, any>): ${typeName} {
562
+ ${parsingCode}
563
+ },
564
+ serialize(input: ${typeName}): string {
565
+ ${serializationCode}
566
+ }
567
+ }`;
568
+ }
569
+ if (!additionalOptions.existingTypeNames.includes(typeName)) {
570
+ content = `${getJsDocComment(def.metadata)}export interface ${typeName} {
571
+ ${fieldParts.join(";\n ")};
572
+ }
573
+ ${validatorPart}
574
+ ${subContentParts.join("\n")}`;
575
+ additionalOptions.existingTypeNames.push(typeName);
576
+ }
577
+ return {
578
+ tsType: typeName,
579
+ schema: def,
580
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
581
+ key,
582
+ additionalOptions.isOptional
583
+ )}: ${maybeNullType(typeName, def.nullable ?? false)}`,
584
+ fromJsonTemplate(input) {
585
+ if (additionalOptions.isOptional) {
586
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
587
+ }
588
+ if (def.nullable) {
589
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : null`;
590
+ }
591
+ return `$$${typeName}.parse(${input})`;
592
+ },
593
+ toJsonTemplate(input) {
594
+ return `JSON.stringify(${input})`;
595
+ },
596
+ content
597
+ };
598
+ }
599
+ function tsEnumFromJtdSchema(nodePath, def, options, additionalOptions) {
600
+ const keyName = nodePath.split(".").pop() ?? "";
601
+ const typeName = getTypeName(nodePath, def);
602
+ let content = `${getJsDocComment(def.metadata)}export type ${typeName} = ${def.enum.map((val) => `"${val}"`).join(" | ")}`;
603
+ if (additionalOptions.existingTypeNames.includes(typeName)) {
604
+ content = "";
605
+ } else {
606
+ additionalOptions.existingTypeNames.push(typeName);
607
+ }
608
+ return {
609
+ tsType: typeName,
610
+ schema: def,
611
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
612
+ keyName,
613
+ additionalOptions.isOptional
614
+ )}: ${maybeNullType(typeName, def.nullable ?? false)}`,
615
+ fromJsonTemplate(input) {
616
+ if (additionalOptions.isOptional) {
617
+ return `typeof ${input} === 'string' ? $$${typeName}.parse(${input}) : undefined`;
618
+ }
619
+ if (def.nullable) {
620
+ return `typeof ${input} === 'string' ? $$${typeName}.parse(${input}) : null`;
621
+ }
622
+ return `$$${typeName}.parse(${input})`;
623
+ },
624
+ toJsonTemplate(input) {
625
+ return `JSON.stringify(${input})`;
626
+ },
627
+ content
628
+ };
629
+ }
630
+ function tsArrayFromJtdSchema(nodePath, def, options, additionalOptions) {
631
+ const key = nodePath.split(".").pop() ?? "";
632
+ const subType = tsTypeFromJtdSchema(
633
+ `${nodePath}.item`,
634
+ def.elements,
635
+ options,
636
+ {
637
+ isOptional: false,
638
+ existingTypeNames: additionalOptions.existingTypeNames
639
+ }
640
+ );
641
+ const tsType = `Array<${maybeNullType(
642
+ subType.tsType,
643
+ def.elements.nullable
644
+ )}>`;
645
+ return {
646
+ tsType,
647
+ schema: def,
648
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
649
+ key,
650
+ additionalOptions.isOptional ?? false
651
+ )}: ${maybeNullType(tsType, def.nullable ?? false)}`,
652
+ fromJsonTemplate(input) {
653
+ if (additionalOptions.isOptional) {
654
+ return `Array.isArray(${input}) ? ${input}.map((item) => ${subType.fromJsonTemplate(
655
+ "item"
656
+ )}) : undefined`;
657
+ }
658
+ if (def.nullable) {
659
+ return `Array.isArray(${input}) ? ${input}.map((item) => ${subType.fromJsonTemplate(
660
+ "item"
661
+ )}) : null`;
662
+ }
663
+ return `Array.isArray(${input}) ? ${input}.map((item) => ${subType.fromJsonTemplate(
664
+ "item"
665
+ )}) : []`;
666
+ },
667
+ toJsonTemplate(input) {
668
+ return `JSON.stringify(${input})`;
669
+ },
670
+ content: subType.content
671
+ };
672
+ }
673
+ function tsDiscriminatedUnionFromJtdSchema(nodePath, def, options, additionalOptions) {
674
+ const key = nodePath.split(".").pop() ?? "";
675
+ const typeName = getTypeName(nodePath, def);
676
+ const subTypeNames = [];
677
+ const subContentParts = [];
678
+ const parserParts = [];
679
+ for (const val of Object.keys(def.mapping)) {
680
+ const optionSchema = def.mapping[val];
681
+ if (!codegenUtils.isSchemaFormProperties(optionSchema)) {
682
+ continue;
683
+ }
684
+ const optionType = tsObjectFromJtdSchema(
685
+ `${nodePath}.${codegenUtils.camelCase(val.toLowerCase())}`,
686
+ optionSchema,
687
+ options,
688
+ {
689
+ discriminatorKey: def.discriminator,
690
+ discriminatorKeyValue: val,
691
+ isOptional: false,
692
+ existingTypeNames: additionalOptions.existingTypeNames
693
+ }
694
+ );
695
+ parserParts.push(`case '${val}':
696
+ return $$${optionType.tsType}.parse(input);`);
697
+ subTypeNames.push(optionType.tsType);
698
+ subContentParts.push(optionType.content);
699
+ }
700
+ let validatorPart = "";
701
+ if (options.typesNeedingParser.includes(typeName)) {
702
+ const modifiedDef = { ...def, nullable: false };
703
+ const parsingCode = schema.getSchemaParsingCode(
704
+ "input",
705
+ modifiedDef
706
+ );
707
+ const serializationCode = schema.getSchemaSerializationCode(
708
+ "input",
709
+ modifiedDef
710
+ );
711
+ validatorPart = `export const $$${typeName} = {
712
+ parse(input: Record<any, any>): ${typeName} {
713
+ ${parsingCode}
714
+ },
715
+ serialize(input: ${typeName}): string {
716
+ ${serializationCode}
717
+ }
718
+ }`;
719
+ }
720
+ let content = `${getJsDocComment(def.metadata)}export type ${typeName} = ${subTypeNames.join(" | ")};
721
+ ${validatorPart}
722
+ ${subContentParts.join("\n")}`;
723
+ if (additionalOptions.existingTypeNames.includes(typeName)) {
724
+ content = "";
725
+ } else {
726
+ additionalOptions.existingTypeNames.push(typeName);
727
+ }
728
+ return {
729
+ tsType: typeName,
730
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
731
+ key,
732
+ additionalOptions.isOptional
733
+ )}: ${maybeNullType(typeName, def.nullable)}`,
734
+ schema: def,
735
+ fromJsonTemplate(input) {
736
+ if (additionalOptions.isOptional) {
737
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
738
+ }
739
+ if (def.nullable) {
740
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : null`;
741
+ }
742
+ return `$$${typeName}.parse(${input})`;
743
+ },
744
+ toJsonTemplate(input) {
745
+ return `JSON.stringify(${input})`;
746
+ },
747
+ content
748
+ };
749
+ }
750
+ function tsRecordFromJtdSchema(nodePath, def, options, additionalOptions) {
751
+ const key = nodePath.split(".").pop() ?? "";
752
+ const typeName = getTypeName(nodePath, def);
753
+ const subType = tsTypeFromJtdSchema(
754
+ `${nodePath}.value`,
755
+ def.values,
756
+ options,
757
+ {
758
+ isOptional: false,
759
+ existingTypeNames: additionalOptions.existingTypeNames
760
+ }
761
+ );
762
+ let content = "";
763
+ if (!additionalOptions.existingTypeNames.includes(typeName)) {
764
+ let validatorPart = "";
765
+ if (options.typesNeedingParser.includes(typeName)) {
766
+ const modifiedDef = { ...def, nullable: false };
767
+ const parsingCode = schema.getSchemaParsingCode(
768
+ "input",
769
+ modifiedDef
770
+ );
771
+ const serializationCode = schema.getSchemaSerializationCode(
772
+ "input",
773
+ modifiedDef
774
+ );
775
+ validatorPart = `export const $$${typeName} = {
776
+ parse(input: Record<any, any>): ${typeName} {
777
+ ${parsingCode}
778
+ },
779
+ serialize(input: ${typeName}): string {
780
+ ${serializationCode}
781
+ }
782
+ }`;
783
+ }
784
+ content = `${getJsDocComment(def.metadata)}export type ${typeName} = Record<string, ${subType.tsType}>;
785
+ ${validatorPart}
786
+ ${subType.content}`;
787
+ }
788
+ return {
789
+ tsType: typeName,
790
+ schema: def,
791
+ fieldTemplate: `${getJsDocComment(def.metadata)}${maybeOptionalKey(
792
+ key,
793
+ additionalOptions.isOptional
794
+ )}: ${maybeNullType(typeName, def.nullable)}`,
795
+ fromJsonTemplate(input) {
796
+ if (additionalOptions.isOptional) {
797
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
798
+ }
799
+ if (def.nullable) {
800
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : null`;
801
+ }
802
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : {}`;
803
+ },
804
+ toJsonTemplate(input) {
805
+ return `JSON.stringify(${input})`;
806
+ },
807
+ content
808
+ };
809
+ }
810
+ function tsRefFromJtdSchema(nodePath, def, options, additionalOptions) {
811
+ const key = nodePath.split(".").pop() ?? "";
812
+ const typeName = codegenUtils.pascalCase(def.ref, {
813
+ normalize: true
814
+ });
815
+ return {
816
+ tsType: typeName,
817
+ schema: def,
818
+ fieldTemplate: `${maybeOptionalKey(key, additionalOptions.isOptional)}: ${maybeNullType(typeName, def.nullable)}`,
819
+ fromJsonTemplate(input) {
820
+ if (additionalOptions.isOptional) {
821
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : undefined`;
822
+ }
823
+ if (def.nullable) {
824
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : null`;
825
+ }
826
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.parse(${input}) : {}`;
827
+ },
828
+ toJsonTemplate(input) {
829
+ if (additionalOptions.isOptional) {
830
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.serialize(${input}) : 'undefined'`;
831
+ }
832
+ if (def.nullable) {
833
+ return `typeof ${input} === 'object' && ${input} !== null ? $$${typeName}.serialize(${input}) : 'null'`;
834
+ }
835
+ return `$$${typeName}.serialize(${input})`;
836
+ },
837
+ content: ""
838
+ };
839
+ }
840
+
841
+ exports.createTypescriptClient = createTypescriptClient;
842
+ exports.getJsDocComment = getJsDocComment;
843
+ exports.maybeNullType = maybeNullType;
844
+ exports.maybeOptionalKey = maybeOptionalKey;
845
+ exports.tsAnyFromJtdSchema = tsAnyFromJtdSchema;
846
+ exports.tsArrayFromJtdSchema = tsArrayFromJtdSchema;
847
+ exports.tsDiscriminatedUnionFromJtdSchema = tsDiscriminatedUnionFromJtdSchema;
848
+ exports.tsEnumFromJtdSchema = tsEnumFromJtdSchema;
849
+ exports.tsHttpRpcFromDefinition = tsHttpRpcFromDefinition;
850
+ exports.tsObjectFromJtdSchema = tsObjectFromJtdSchema;
851
+ exports.tsRecordFromJtdSchema = tsRecordFromJtdSchema;
852
+ exports.tsRefFromJtdSchema = tsRefFromJtdSchema;
853
+ exports.tsRpcFromDefinition = tsRpcFromDefinition;
854
+ exports.tsScalarFromJtdSchema = tsScalarFromJtdSchema;
855
+ exports.tsServiceFromDefinition = tsServiceFromDefinition;
856
+ exports.tsTypeFromJtdSchema = tsTypeFromJtdSchema;
857
+ exports.tsWsRpcFromDefinition = tsWsRpcFromDefinition;
858
+ exports.typescriptClientGenerator = typescriptClientGenerator;