@contractkit/plugin-csharp 0.1.0 → 0.1.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/.turbo/turbo-build$colon$ci.log +4 -4
- package/.turbo/turbo-test$colon$ci.log +9 -9
- package/CHANGELOG.md +19 -0
- package/dist/index.js +210 -477
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
|
|
4
1
|
// src/index.ts
|
|
5
2
|
import { dirname, join, resolve } from "path";
|
|
6
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, rmdirSync, writeFileSync } from "fs";
|
|
7
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
buildModelIndex as buildModelIndex2,
|
|
6
|
+
collectTransitiveModelRefs,
|
|
7
|
+
collectTypeRefs as collectTypeRefs2,
|
|
8
|
+
emptyIncrementalManifest,
|
|
9
|
+
hashFingerprint,
|
|
10
|
+
parseIncrementalManifest,
|
|
11
|
+
runIncrementalCodegen,
|
|
12
|
+
serializeIncrementalManifest
|
|
13
|
+
} from "@contractkit/core";
|
|
8
14
|
|
|
9
15
|
// src/codegen-models.ts
|
|
10
16
|
import { buildModelIndex, computeModelsWithInput, resolveEffectiveFields, topoSortModels } from "@contractkit/core";
|
|
@@ -89,18 +95,10 @@ var CSHARP_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
89
95
|
"volatile",
|
|
90
96
|
"while"
|
|
91
97
|
]);
|
|
92
|
-
var RESERVED_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
93
|
-
"Equals",
|
|
94
|
-
"GetHashCode",
|
|
95
|
-
"GetType",
|
|
96
|
-
"ToString",
|
|
97
|
-
"EqualityContract",
|
|
98
|
-
"PrintMembers"
|
|
99
|
-
]);
|
|
98
|
+
var RESERVED_MEMBER_NAMES = /* @__PURE__ */ new Set(["Equals", "GetHashCode", "GetType", "ToString", "EqualityContract", "PrintMembers"]);
|
|
100
99
|
function escapeCSharpIdentifier(name) {
|
|
101
100
|
return CSHARP_KEYWORDS.has(name) ? `@${name}` : name;
|
|
102
101
|
}
|
|
103
|
-
__name(escapeCSharpIdentifier, "escapeCSharpIdentifier");
|
|
104
102
|
function toCSharpPropertyName(name) {
|
|
105
103
|
const words = splitWords(name);
|
|
106
104
|
if (words.length === 0) return "_";
|
|
@@ -108,7 +106,6 @@ function toCSharpPropertyName(name) {
|
|
|
108
106
|
if (/^\d/.test(result)) result = `_${result}`;
|
|
109
107
|
return result;
|
|
110
108
|
}
|
|
111
|
-
__name(toCSharpPropertyName, "toCSharpPropertyName");
|
|
112
109
|
function toCSharpParameterName(name) {
|
|
113
110
|
const words = splitWords(name);
|
|
114
111
|
if (words.length === 0) return "_";
|
|
@@ -118,12 +115,10 @@ function toCSharpParameterName(name) {
|
|
|
118
115
|
if (/^\d/.test(result)) result = `_${result}`;
|
|
119
116
|
return escapeCSharpIdentifier(result);
|
|
120
117
|
}
|
|
121
|
-
__name(toCSharpParameterName, "toCSharpParameterName");
|
|
122
118
|
function safeMemberName(propertyName, ownerTypeName) {
|
|
123
119
|
if (propertyName === ownerTypeName || RESERVED_MEMBER_NAMES.has(propertyName)) return `${propertyName}Value`;
|
|
124
120
|
return propertyName;
|
|
125
121
|
}
|
|
126
|
-
__name(safeMemberName, "safeMemberName");
|
|
127
122
|
function toCSharpTypeName(name) {
|
|
128
123
|
const words = splitWords(name);
|
|
129
124
|
if (words.length === 0) return "_";
|
|
@@ -131,7 +126,6 @@ function toCSharpTypeName(name) {
|
|
|
131
126
|
if (/^\d/.test(result)) result = `_${result}`;
|
|
132
127
|
return result;
|
|
133
128
|
}
|
|
134
|
-
__name(toCSharpTypeName, "toCSharpTypeName");
|
|
135
129
|
function sanitizeCSharpTypeName(name) {
|
|
136
130
|
let result = name.replace(/[^a-zA-Z0-9]/g, "");
|
|
137
131
|
if (result.length === 0) return "_";
|
|
@@ -139,7 +133,6 @@ function sanitizeCSharpTypeName(name) {
|
|
|
139
133
|
if (/^\d/.test(result)) result = `_${result}`;
|
|
140
134
|
return result;
|
|
141
135
|
}
|
|
142
|
-
__name(sanitizeCSharpTypeName, "sanitizeCSharpTypeName");
|
|
143
136
|
function toCSharpEnumMemberName(value) {
|
|
144
137
|
const words = splitWords(value);
|
|
145
138
|
if (words.length === 0) return "_";
|
|
@@ -147,43 +140,30 @@ function toCSharpEnumMemberName(value) {
|
|
|
147
140
|
if (/^\d/.test(result)) result = `_${result}`;
|
|
148
141
|
return result;
|
|
149
142
|
}
|
|
150
|
-
__name(toCSharpEnumMemberName, "toCSharpEnumMemberName");
|
|
151
143
|
function deriveCSharpFileBase(file) {
|
|
152
144
|
const base = file.split("/").pop()?.replace(/\.(op\.)?ck$/, "") ?? "models";
|
|
153
145
|
return toCSharpTypeName(base);
|
|
154
146
|
}
|
|
155
|
-
__name(deriveCSharpFileBase, "deriveCSharpFileBase");
|
|
156
147
|
function xmlDocLines(text, indent, tag = "summary") {
|
|
157
148
|
if (text.length === 0) return [];
|
|
158
149
|
const safe = escapeXml(text);
|
|
159
150
|
const sourceLines = safe.split("\n");
|
|
160
|
-
if (sourceLines.length === 1) return [
|
|
161
|
-
|
|
162
|
-
];
|
|
163
|
-
return [
|
|
164
|
-
`${indent}/// <${tag}>`,
|
|
165
|
-
...sourceLines.map((line) => `${indent}/// ${line}`.trimEnd()),
|
|
166
|
-
`${indent}/// </${tag}>`
|
|
167
|
-
];
|
|
151
|
+
if (sourceLines.length === 1) return [`${indent}/// <${tag}>${sourceLines[0]}</${tag}>`];
|
|
152
|
+
return [`${indent}/// <${tag}>`, ...sourceLines.map((line) => `${indent}/// ${line}`.trimEnd()), `${indent}/// </${tag}>`];
|
|
168
153
|
}
|
|
169
|
-
__name(xmlDocLines, "xmlDocLines");
|
|
170
154
|
function escapeXml(text) {
|
|
171
155
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
172
156
|
}
|
|
173
|
-
__name(escapeXml, "escapeXml");
|
|
174
157
|
function quoteCSharpString(value) {
|
|
175
158
|
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\0/g, "\\0");
|
|
176
159
|
return `"${escaped}"`;
|
|
177
160
|
}
|
|
178
|
-
__name(quoteCSharpString, "quoteCSharpString");
|
|
179
161
|
function splitWords(name) {
|
|
180
162
|
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
181
163
|
}
|
|
182
|
-
__name(splitWords, "splitWords");
|
|
183
164
|
function capitalize(word) {
|
|
184
165
|
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
185
166
|
}
|
|
186
|
-
__name(capitalize, "capitalize");
|
|
187
167
|
|
|
188
168
|
// src/codegen-models.ts
|
|
189
169
|
var MODEL_USINGS = [
|
|
@@ -205,27 +185,18 @@ function generateCSharpModels(root, opts) {
|
|
|
205
185
|
warn: opts.warn
|
|
206
186
|
};
|
|
207
187
|
const bodies = [];
|
|
208
|
-
const append =
|
|
188
|
+
const append = (lines) => {
|
|
209
189
|
if (lines.length === 0) return;
|
|
210
190
|
bodies.push("", ...lines);
|
|
211
|
-
}
|
|
191
|
+
};
|
|
212
192
|
for (const model of topoSortModels(root.models)) append(generateModel(model, ctx));
|
|
213
193
|
for (const decl of opts.hoisted?.byFile.get(root.file) ?? []) append(generateHoisted(decl, ctx));
|
|
214
|
-
return renderFile(`${opts.namespace}.Models`, ctx.globalAliases, [
|
|
215
|
-
...MODEL_USINGS
|
|
216
|
-
], bodies);
|
|
194
|
+
return renderFile(`${opts.namespace}.Models`, ctx.globalAliases, [...MODEL_USINGS], bodies);
|
|
217
195
|
}
|
|
218
|
-
__name(generateCSharpModels, "generateCSharpModels");
|
|
219
196
|
function resolveModelsWithInput(models, external = /* @__PURE__ */ new Set()) {
|
|
220
197
|
const seed = new Set(external);
|
|
221
|
-
return /* @__PURE__ */ new Set([
|
|
222
|
-
|
|
223
|
-
...computeModelsWithInput([
|
|
224
|
-
...models
|
|
225
|
-
], seed)
|
|
226
|
-
]);
|
|
227
|
-
}
|
|
228
|
-
__name(resolveModelsWithInput, "resolveModelsWithInput");
|
|
198
|
+
return /* @__PURE__ */ new Set([...seed, ...computeModelsWithInput([...models], seed)]);
|
|
199
|
+
}
|
|
229
200
|
function createRenderContext(opts) {
|
|
230
201
|
return {
|
|
231
202
|
namespace: opts.namespace,
|
|
@@ -236,18 +207,10 @@ function createRenderContext(opts) {
|
|
|
236
207
|
warn: opts.warn
|
|
237
208
|
};
|
|
238
209
|
}
|
|
239
|
-
__name(createRenderContext, "createRenderContext");
|
|
240
210
|
function renderFile(namespaceName, globalAliases, usings, bodies) {
|
|
241
|
-
const lines = [
|
|
242
|
-
"// <auto-generated/>",
|
|
243
|
-
"// Generated by @contractkit/plugin-csharp. Do not edit manually.",
|
|
244
|
-
"#nullable enable",
|
|
245
|
-
""
|
|
246
|
-
];
|
|
211
|
+
const lines = ["// <auto-generated/>", "// Generated by @contractkit/plugin-csharp. Do not edit manually.", "#nullable enable", ""];
|
|
247
212
|
if (globalAliases.length > 0) {
|
|
248
|
-
lines.push(...[
|
|
249
|
-
...globalAliases
|
|
250
|
-
].sort());
|
|
213
|
+
lines.push(...[...globalAliases].sort());
|
|
251
214
|
lines.push("");
|
|
252
215
|
}
|
|
253
216
|
lines.push(...usings);
|
|
@@ -257,7 +220,6 @@ function renderFile(namespaceName, globalAliases, usings, bodies) {
|
|
|
257
220
|
lines.push("");
|
|
258
221
|
return lines.join("\n");
|
|
259
222
|
}
|
|
260
|
-
__name(renderFile, "renderFile");
|
|
261
223
|
function renderCSharpType(type, ctx, forInput = false) {
|
|
262
224
|
const decl = ctx.hoisted?.byNode.get(type);
|
|
263
225
|
if (decl) return hoistedTypeName(decl, ctx, forInput);
|
|
@@ -273,7 +235,9 @@ function renderCSharpType(type, ctx, forInput = false) {
|
|
|
273
235
|
const value = renderCSharpType(type.value, ctx, forInput);
|
|
274
236
|
const stringType = qualify("string", "System.String", ctx);
|
|
275
237
|
if (key !== stringType) {
|
|
276
|
-
ctx.warn?.(
|
|
238
|
+
ctx.warn?.(
|
|
239
|
+
`A record key of type '${key}' is not representable as a JSON object key; emitting Dictionary<string, ${value}>. Parse the key yourself, or declare the key as a string.`
|
|
240
|
+
);
|
|
277
241
|
}
|
|
278
242
|
return `${qualify("Dictionary", "System.Collections.Generic.Dictionary", ctx)}<${stringType}, ${value}>`;
|
|
279
243
|
}
|
|
@@ -302,25 +266,20 @@ function renderCSharpType(type, ctx, forInput = false) {
|
|
|
302
266
|
return jsonElement(ctx);
|
|
303
267
|
}
|
|
304
268
|
}
|
|
305
|
-
__name(renderCSharpType, "renderCSharpType");
|
|
306
269
|
function hoistedTypeName(decl, ctx, forInput) {
|
|
307
270
|
const bare = forInput && decl.needsInput ? `${decl.name}Input` : decl.name;
|
|
308
271
|
const name = ctx.qualify ? `${ctx.namespace}.Models.${bare}` : bare;
|
|
309
272
|
return decl.nullable ? `${name}?` : name;
|
|
310
273
|
}
|
|
311
|
-
__name(hoistedTypeName, "hoistedTypeName");
|
|
312
274
|
function qualify(short, full, ctx) {
|
|
313
275
|
return ctx.qualify ? full : short;
|
|
314
276
|
}
|
|
315
|
-
__name(qualify, "qualify");
|
|
316
277
|
function jsonElement(ctx) {
|
|
317
278
|
return qualify("JsonElement", "System.Text.Json.JsonElement", ctx);
|
|
318
279
|
}
|
|
319
|
-
__name(jsonElement, "jsonElement");
|
|
320
280
|
function isNullScalar(type) {
|
|
321
281
|
return type.kind === "scalar" && type.name === "null";
|
|
322
282
|
}
|
|
323
|
-
__name(isNullScalar, "isNullScalar");
|
|
324
283
|
function renderScalar(name, ctx) {
|
|
325
284
|
switch (name) {
|
|
326
285
|
case "string":
|
|
@@ -365,13 +324,11 @@ function renderScalar(name, ctx) {
|
|
|
365
324
|
}
|
|
366
325
|
}
|
|
367
326
|
}
|
|
368
|
-
__name(renderScalar, "renderScalar");
|
|
369
327
|
function literalCSharpType(value, ctx) {
|
|
370
328
|
if (typeof value === "string") return qualify("string", "System.String", ctx);
|
|
371
329
|
if (typeof value === "boolean") return qualify("bool", "System.Boolean", ctx);
|
|
372
330
|
return Number.isInteger(value) ? qualify("long", "System.Int64", ctx) : qualify("double", "System.Double", ctx);
|
|
373
331
|
}
|
|
374
|
-
__name(literalCSharpType, "literalCSharpType");
|
|
375
332
|
function renderDefault(value, type, ctx) {
|
|
376
333
|
const inner = type.kind === "lazy" ? type.inner : type;
|
|
377
334
|
if (typeof value === "boolean") return String(value);
|
|
@@ -418,28 +375,26 @@ function renderDefault(value, type, ctx) {
|
|
|
418
375
|
}
|
|
419
376
|
return quoteCSharpString(value);
|
|
420
377
|
}
|
|
421
|
-
__name(renderDefault, "renderDefault");
|
|
422
378
|
function applyWireCase(name, wireCase) {
|
|
423
379
|
if (!wireCase || wireCase === "camel") return name;
|
|
424
380
|
if (wireCase === "snake") return name.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
|
|
425
381
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
426
382
|
}
|
|
427
|
-
__name(applyWireCase, "applyWireCase");
|
|
428
383
|
function renamingCase(wireCase) {
|
|
429
384
|
return wireCase && wireCase !== "camel" ? wireCase : void 0;
|
|
430
385
|
}
|
|
431
|
-
__name(renamingCase, "renamingCase");
|
|
432
386
|
function wireCaseFor(model, forInput, split, ctx) {
|
|
433
387
|
const input = renamingCase(model.inputCase);
|
|
434
388
|
const output = renamingCase(model.outputCase);
|
|
435
389
|
if (split) return forInput ? input : output;
|
|
436
390
|
if (input && output && input !== output) {
|
|
437
|
-
ctx.warn?.(
|
|
391
|
+
ctx.warn?.(
|
|
392
|
+
`Contract '${model.name}' sets format(input=${input}) and format(output=${output}), but nothing about it splits into an Input variant, so one C# record carries both directions and can only spell one set of keys. The generated keys follow the output casing; a request built from this record will send the wrong ones.`
|
|
393
|
+
);
|
|
438
394
|
return output;
|
|
439
395
|
}
|
|
440
396
|
return output ?? input;
|
|
441
397
|
}
|
|
442
|
-
__name(wireCaseFor, "wireCaseFor");
|
|
443
398
|
function containsInlineObject(type) {
|
|
444
399
|
if (!type) return false;
|
|
445
400
|
switch (type.kind) {
|
|
@@ -461,13 +416,13 @@ function containsInlineObject(type) {
|
|
|
461
416
|
return false;
|
|
462
417
|
}
|
|
463
418
|
}
|
|
464
|
-
__name(containsInlineObject, "containsInlineObject");
|
|
465
419
|
function warnUncasedNesting(model, fields, wireCase, ctx) {
|
|
466
420
|
if (!wireCase) return;
|
|
467
421
|
if (!fields.some((f) => containsInlineObject(f.type)) && !containsInlineObject(model.type)) return;
|
|
468
|
-
ctx.warn?.(
|
|
422
|
+
ctx.warn?.(
|
|
423
|
+
`Contract '${model.name}' is declared format(${model.outputCase ? "output" : "input"}=${wireCase}) and holds an anonymous object. The record hoisted out of that object keeps its declared key names, so its keys will not be ${wireCase}-cased. Name the shape as its own contract to fix it.`
|
|
424
|
+
);
|
|
469
425
|
}
|
|
470
|
-
__name(warnUncasedNesting, "warnUncasedNesting");
|
|
471
426
|
function generateModel(model, ctx) {
|
|
472
427
|
if (model.type) return generateAliasModel(model, ctx);
|
|
473
428
|
const effective = effectiveFieldsFor(model, ctx);
|
|
@@ -481,7 +436,6 @@ function generateModel(model, ctx) {
|
|
|
481
436
|
...generateRecordForModel(`${model.name}Input`, inputFields, ctx, true, model, true)
|
|
482
437
|
];
|
|
483
438
|
}
|
|
484
|
-
__name(generateModel, "generateModel");
|
|
485
439
|
function effectiveFieldsFor(model, ctx) {
|
|
486
440
|
if (!model.bases || model.bases.length === 0) return model.fields;
|
|
487
441
|
const { fields, unresolved } = resolveEffectiveFields(model.name, ctx.modelIndex);
|
|
@@ -490,7 +444,6 @@ function effectiveFieldsFor(model, ctx) {
|
|
|
490
444
|
}
|
|
491
445
|
return fields;
|
|
492
446
|
}
|
|
493
|
-
__name(effectiveFieldsFor, "effectiveFieldsFor");
|
|
494
447
|
function generateAliasModel(model, ctx) {
|
|
495
448
|
const type = model.type;
|
|
496
449
|
const inner = type.kind === "lazy" ? type.inner : type;
|
|
@@ -504,40 +457,47 @@ function generateAliasModel(model, ctx) {
|
|
|
504
457
|
const needsSplit = ctx.modelsWithInput.has(model.name) || fields.some((f) => f.visibility !== "normal");
|
|
505
458
|
if (!needsSplit) return generateRecordForModel(model.name, fields, ctx, false, model, false);
|
|
506
459
|
return [
|
|
507
|
-
...generateRecordForModel(
|
|
460
|
+
...generateRecordForModel(
|
|
461
|
+
model.name,
|
|
462
|
+
fields.filter((f) => f.visibility !== "writeonly"),
|
|
463
|
+
ctx,
|
|
464
|
+
false,
|
|
465
|
+
model,
|
|
466
|
+
true
|
|
467
|
+
),
|
|
508
468
|
"",
|
|
509
|
-
...generateRecordForModel(
|
|
469
|
+
...generateRecordForModel(
|
|
470
|
+
`${model.name}Input`,
|
|
471
|
+
fields.filter((f) => f.visibility !== "readonly"),
|
|
472
|
+
ctx,
|
|
473
|
+
true,
|
|
474
|
+
model,
|
|
475
|
+
true
|
|
476
|
+
)
|
|
510
477
|
];
|
|
511
478
|
}
|
|
512
479
|
addAlias(model.name, type, ctx, false);
|
|
513
480
|
if (ctx.modelsWithInput.has(model.name)) addAlias(`${model.name}Input`, type, ctx, true);
|
|
514
481
|
return [];
|
|
515
482
|
}
|
|
516
|
-
__name(generateAliasModel, "generateAliasModel");
|
|
517
483
|
function addAlias(name, type, ctx, forInput) {
|
|
518
|
-
const target = renderCSharpType(type, {
|
|
519
|
-
...ctx,
|
|
520
|
-
qualify: true
|
|
521
|
-
}, forInput);
|
|
484
|
+
const target = renderCSharpType(type, { ...ctx, qualify: true }, forInput);
|
|
522
485
|
let aliased = target;
|
|
523
486
|
if (aliased.endsWith("?") && !isNullableValueType(type, ctx)) {
|
|
524
487
|
aliased = aliased.slice(0, -1);
|
|
525
|
-
ctx.warn?.(
|
|
488
|
+
ctx.warn?.(
|
|
489
|
+
`Contract '${name}' aliases a nullable type, which C# cannot express as a using alias; '${name}' is generated as '${aliased}'. Declare the nullability at each use site instead.`
|
|
490
|
+
);
|
|
526
491
|
}
|
|
527
492
|
ctx.globalAliases.push(`global using ${name} = ${aliased};`);
|
|
528
493
|
}
|
|
529
|
-
__name(addAlias, "addAlias");
|
|
530
494
|
function isNullableValueType(type, ctx) {
|
|
531
495
|
const inner = type.kind === "lazy" ? type.inner : type;
|
|
532
496
|
if (inner.kind !== "union") return false;
|
|
533
497
|
const nonNull = inner.members.filter((m) => !isNullScalar(m));
|
|
534
498
|
if (nonNull.length !== 1) return false;
|
|
535
|
-
return VALUE_TYPES.has(renderCSharpType(nonNull[0], {
|
|
536
|
-
...ctx,
|
|
537
|
-
qualify: false
|
|
538
|
-
}, false));
|
|
499
|
+
return VALUE_TYPES.has(renderCSharpType(nonNull[0], { ...ctx, qualify: false }, false));
|
|
539
500
|
}
|
|
540
|
-
__name(isNullableValueType, "isNullableValueType");
|
|
541
501
|
var VALUE_TYPES = /* @__PURE__ */ new Set([
|
|
542
502
|
"bool",
|
|
543
503
|
"byte",
|
|
@@ -558,7 +518,6 @@ function enumMemberNames(values) {
|
|
|
558
518
|
for (const value of values) out.set(value, uniqueName(toCSharpEnumMemberName(value), used));
|
|
559
519
|
return out;
|
|
560
520
|
}
|
|
561
|
-
__name(enumMemberNames, "enumMemberNames");
|
|
562
521
|
function generateEnum(name, values, ctx, description, deprecated) {
|
|
563
522
|
const entries = enumMemberNames(values);
|
|
564
523
|
const lines = [];
|
|
@@ -575,7 +534,6 @@ function generateEnum(name, values, ctx, description, deprecated) {
|
|
|
575
534
|
if (ctx.modelsWithInput.has(name)) ctx.globalAliases.push(`global using ${name}Input = ${ctx.namespace}.Models.${name};`);
|
|
576
535
|
return lines;
|
|
577
536
|
}
|
|
578
|
-
__name(generateEnum, "generateEnum");
|
|
579
537
|
function supertypesFor(readName, ctx, forInput) {
|
|
580
538
|
const unions = ctx.hoisted?.memberships.get(readName) ?? [];
|
|
581
539
|
return unions.map((union) => {
|
|
@@ -583,14 +541,12 @@ function supertypesFor(readName, ctx, forInput) {
|
|
|
583
541
|
return forInput && decl?.needsInput ? `${union}Input` : union;
|
|
584
542
|
});
|
|
585
543
|
}
|
|
586
|
-
__name(supertypesFor, "supertypesFor");
|
|
587
544
|
function generateRecordForModel(name, fields, ctx, forInput, model, split) {
|
|
588
545
|
const readName = forInput && name.endsWith("Input") ? name.slice(0, -"Input".length) : name;
|
|
589
546
|
const wireCase = wireCaseFor(model, forInput, split, ctx);
|
|
590
547
|
if (!forInput) warnUncasedNesting(model, fields, wireCase, ctx);
|
|
591
548
|
return renderRecord(name, fields, ctx, forInput, supertypesFor(readName, ctx, forInput), model.description, model.deprecated, wireCase);
|
|
592
549
|
}
|
|
593
|
-
__name(generateRecordForModel, "generateRecordForModel");
|
|
594
550
|
function renderRecord(name, fields, ctx, forInput, supertypes, description, deprecated, wireCase) {
|
|
595
551
|
const lines = [];
|
|
596
552
|
lines.push(...docLines(description, deprecated, ""));
|
|
@@ -608,7 +564,6 @@ function renderRecord(name, fields, ctx, forInput, supertypes, description, depr
|
|
|
608
564
|
lines.push("}");
|
|
609
565
|
return lines;
|
|
610
566
|
}
|
|
611
|
-
__name(renderRecord, "renderRecord");
|
|
612
567
|
function renderField(field, ctx, forInput, ownerTypeName, wireCase) {
|
|
613
568
|
const propName = safeMemberName(toCSharpPropertyName(field.name), ownerTypeName);
|
|
614
569
|
const wireName = applyWireCase(field.name, wireCase);
|
|
@@ -628,24 +583,25 @@ function renderField(field, ctx, forInput, ownerTypeName, wireCase) {
|
|
|
628
583
|
lines.push(` public ${isRequired ? "required " : ""}${typeStr} ${propName} { get; init; }${suffix}`);
|
|
629
584
|
return lines;
|
|
630
585
|
}
|
|
631
|
-
__name(renderField, "renderField");
|
|
632
586
|
function generateHoisted(decl, ctx) {
|
|
633
587
|
const read = generateHoistedVariant(decl, ctx, false);
|
|
634
588
|
if (!decl.needsInput) return read;
|
|
635
|
-
return [
|
|
636
|
-
...read,
|
|
637
|
-
"",
|
|
638
|
-
...generateHoistedVariant(decl, ctx, true)
|
|
639
|
-
];
|
|
589
|
+
return [...read, "", ...generateHoistedVariant(decl, ctx, true)];
|
|
640
590
|
}
|
|
641
|
-
__name(generateHoisted, "generateHoisted");
|
|
642
591
|
function generateHoistedVariant(decl, ctx, forInput) {
|
|
643
592
|
const name = forInput ? `${decl.name}Input` : decl.name;
|
|
644
593
|
switch (decl.kind) {
|
|
645
594
|
case "enum":
|
|
646
595
|
return generateEnum(name, decl.values ?? [], ctx, decl.description);
|
|
647
596
|
case "record":
|
|
648
|
-
return renderRecord(
|
|
597
|
+
return renderRecord(
|
|
598
|
+
name,
|
|
599
|
+
(decl.fields ?? []).filter((f) => forInput ? f.visibility !== "readonly" : f.visibility !== "writeonly"),
|
|
600
|
+
ctx,
|
|
601
|
+
forInput,
|
|
602
|
+
supertypesFor(decl.name, ctx, forInput),
|
|
603
|
+
decl.description
|
|
604
|
+
);
|
|
649
605
|
case "tuple":
|
|
650
606
|
return generateTupleRecord(decl, name, ctx, forInput);
|
|
651
607
|
case "plainUnion":
|
|
@@ -654,11 +610,9 @@ function generateHoistedVariant(decl, ctx, forInput) {
|
|
|
654
610
|
return generateDiscriminatedUnion(decl, name, ctx, forInput);
|
|
655
611
|
}
|
|
656
612
|
}
|
|
657
|
-
__name(generateHoistedVariant, "generateHoistedVariant");
|
|
658
613
|
function deserializeExpr(type, ctx, forInput) {
|
|
659
614
|
return `element.Deserialize<${renderCSharpType(type, ctx, forInput)}>(options)!`;
|
|
660
615
|
}
|
|
661
|
-
__name(deserializeExpr, "deserializeExpr");
|
|
662
616
|
function generateTupleRecord(decl, name, ctx, forInput) {
|
|
663
617
|
const items = decl.items ?? [];
|
|
664
618
|
const converterName = `${name}Converter`;
|
|
@@ -697,7 +651,6 @@ function generateTupleRecord(decl, name, ctx, forInput) {
|
|
|
697
651
|
lines.push("}");
|
|
698
652
|
return lines;
|
|
699
653
|
}
|
|
700
|
-
__name(generateTupleRecord, "generateTupleRecord");
|
|
701
654
|
function generatePlainUnion(decl, name, ctx, forInput) {
|
|
702
655
|
const converterName = `${name}Converter`;
|
|
703
656
|
const members = decl.members ?? [];
|
|
@@ -751,13 +704,9 @@ function generatePlainUnion(decl, name, ctx, forInput) {
|
|
|
751
704
|
lines.push("}");
|
|
752
705
|
return lines;
|
|
753
706
|
}
|
|
754
|
-
__name(generatePlainUnion, "generatePlainUnion");
|
|
755
707
|
function generateDiscriminatedUnion(decl, name, ctx, forInput) {
|
|
756
708
|
const converterName = `${name}Converter`;
|
|
757
|
-
const members = (decl.members ?? []).map((member) => ({
|
|
758
|
-
...member,
|
|
759
|
-
recordName: memberRecordName(member.typeName, ctx, forInput)
|
|
760
|
-
}));
|
|
709
|
+
const members = (decl.members ?? []).map((member) => ({ ...member, recordName: memberRecordName(member.typeName, ctx, forInput) }));
|
|
761
710
|
const discriminator = decl.discriminator ?? "";
|
|
762
711
|
const lines = [];
|
|
763
712
|
lines.push(...docLines(decl.description, void 0, ""));
|
|
@@ -773,7 +722,9 @@ function generateDiscriminatedUnion(decl, name, ctx, forInput) {
|
|
|
773
722
|
lines.push(" {");
|
|
774
723
|
lines.push(" using var document = JsonDocument.ParseValue(ref reader);");
|
|
775
724
|
lines.push(" var element = document.RootElement;");
|
|
776
|
-
lines.push(
|
|
725
|
+
lines.push(
|
|
726
|
+
` var tag = element.TryGetProperty(${quoteCSharpString(discriminator)}, out var tagElement) && tagElement.ValueKind == JsonValueKind.String`
|
|
727
|
+
);
|
|
777
728
|
lines.push(" ? tagElement.GetString()");
|
|
778
729
|
lines.push(" : null;");
|
|
779
730
|
lines.push("");
|
|
@@ -802,21 +753,18 @@ function generateDiscriminatedUnion(decl, name, ctx, forInput) {
|
|
|
802
753
|
lines.push("}");
|
|
803
754
|
return lines;
|
|
804
755
|
}
|
|
805
|
-
__name(generateDiscriminatedUnion, "generateDiscriminatedUnion");
|
|
806
756
|
function memberRecordName(typeName, ctx, forInput) {
|
|
807
757
|
if (!forInput) return typeName;
|
|
808
758
|
const decl = ctx.hoisted?.byName.get(typeName);
|
|
809
759
|
if (decl) return decl.needsInput ? `${typeName}Input` : typeName;
|
|
810
760
|
return ctx.modelsWithInput.has(typeName) ? `${typeName}Input` : typeName;
|
|
811
761
|
}
|
|
812
|
-
__name(memberRecordName, "memberRecordName");
|
|
813
762
|
function docLines(description, deprecated, indent) {
|
|
814
763
|
const lines = [];
|
|
815
764
|
if (description) lines.push(...xmlDocLines(description, indent));
|
|
816
765
|
if (deprecated) lines.push(...xmlDocLines("Deprecated in the contract.", indent, "remarks"));
|
|
817
766
|
return lines;
|
|
818
767
|
}
|
|
819
|
-
__name(docLines, "docLines");
|
|
820
768
|
function uniqueName(name, used) {
|
|
821
769
|
if (!used.has(name)) {
|
|
822
770
|
used.add(name);
|
|
@@ -827,7 +775,6 @@ function uniqueName(name, used) {
|
|
|
827
775
|
used.add(`${name}${n}`);
|
|
828
776
|
return `${name}${n}`;
|
|
829
777
|
}
|
|
830
|
-
__name(uniqueName, "uniqueName");
|
|
831
778
|
|
|
832
779
|
// src/codegen-client.ts
|
|
833
780
|
import { classifyContentType, observableResponses, resolveModifiers } from "@contractkit/core";
|
|
@@ -847,7 +794,6 @@ function clientUsings(namespaceName) {
|
|
|
847
794
|
`using ${namespaceName}.Runtime;`
|
|
848
795
|
];
|
|
849
796
|
}
|
|
850
|
-
__name(clientUsings, "clientUsings");
|
|
851
797
|
function hasPublicOperations(root, includeInternal = false) {
|
|
852
798
|
for (const route of root.routes) {
|
|
853
799
|
for (const op of route.operations) {
|
|
@@ -856,15 +802,12 @@ function hasPublicOperations(root, includeInternal = false) {
|
|
|
856
802
|
}
|
|
857
803
|
return false;
|
|
858
804
|
}
|
|
859
|
-
__name(hasPublicOperations, "hasPublicOperations");
|
|
860
805
|
function deriveClientClassName(file) {
|
|
861
806
|
return `${deriveCSharpFileBase(file)}Client`;
|
|
862
807
|
}
|
|
863
|
-
__name(deriveClientClassName, "deriveClientClassName");
|
|
864
808
|
function deriveClientPropertyName(file) {
|
|
865
809
|
return deriveCSharpFileBase(file);
|
|
866
810
|
}
|
|
867
|
-
__name(deriveClientPropertyName, "deriveClientPropertyName");
|
|
868
811
|
function generateCSharpClient(root, opts) {
|
|
869
812
|
const className = deriveClientClassName(root.file);
|
|
870
813
|
const includeInternal = opts.includeInternal ?? false;
|
|
@@ -873,29 +816,22 @@ function generateCSharpClient(root, opts) {
|
|
|
873
816
|
for (const route of root.routes) {
|
|
874
817
|
for (const op of route.operations) {
|
|
875
818
|
if (!includeInternal && resolveModifiers(route, op).includes("internal")) continue;
|
|
876
|
-
publicOps.push({
|
|
877
|
-
route,
|
|
878
|
-
op
|
|
879
|
-
});
|
|
819
|
+
publicOps.push({ route, op });
|
|
880
820
|
}
|
|
881
821
|
}
|
|
882
822
|
const shapeLines = [];
|
|
883
823
|
for (const { route, op } of publicOps) {
|
|
884
824
|
const base = methodBase(deriveMethodName(op, route));
|
|
885
825
|
for (const { source, suffix } of [
|
|
886
|
-
{
|
|
887
|
-
|
|
888
|
-
suffix: "Query"
|
|
889
|
-
},
|
|
890
|
-
{
|
|
891
|
-
source: op.headers,
|
|
892
|
-
suffix: "Headers"
|
|
893
|
-
}
|
|
826
|
+
{ source: op.query, suffix: "Query" },
|
|
827
|
+
{ source: op.headers, suffix: "Headers" }
|
|
894
828
|
]) {
|
|
895
829
|
if (source?.kind !== "params" || source.nodes.length === 0) continue;
|
|
896
830
|
const shapeName = `${base}${suffix}`;
|
|
897
831
|
shapeLines.push("");
|
|
898
|
-
shapeLines.push(
|
|
832
|
+
shapeLines.push(
|
|
833
|
+
...xmlDocLines(`The ${suffix === "Query" ? "query parameters" : "request headers"} declared on ${where(route, op)}.`, "")
|
|
834
|
+
);
|
|
899
835
|
shapeLines.push(`public sealed record ${shapeName}`);
|
|
900
836
|
shapeLines.push("{");
|
|
901
837
|
source.nodes.forEach((node, index) => {
|
|
@@ -918,7 +854,9 @@ function generateCSharpClient(root, opts) {
|
|
|
918
854
|
const methodName = deriveMethodName(op, route);
|
|
919
855
|
const clash = seen.get(methodName);
|
|
920
856
|
if (clash) {
|
|
921
|
-
throw new Error(
|
|
857
|
+
throw new Error(
|
|
858
|
+
`plugin-csharp: ${where(route, op)} and ${clash} both generate the client method '${methodName}' on ${className}. Give one of them a distinct 'sdk:' name.`
|
|
859
|
+
);
|
|
922
860
|
}
|
|
923
861
|
seen.set(methodName, where(route, op));
|
|
924
862
|
methodLines.push("");
|
|
@@ -934,39 +872,23 @@ function generateCSharpClient(root, opts) {
|
|
|
934
872
|
body.push(...shapeLines);
|
|
935
873
|
return renderFile(`${opts.namespace}.Clients`, ctx.globalAliases, clientUsings(opts.namespace), body);
|
|
936
874
|
}
|
|
937
|
-
__name(generateCSharpClient, "generateCSharpClient");
|
|
938
875
|
function where(route, op) {
|
|
939
876
|
return `${op.method.toUpperCase()} ${route.path}`;
|
|
940
877
|
}
|
|
941
|
-
__name(where, "where");
|
|
942
878
|
function methodBase(methodName) {
|
|
943
879
|
return methodName.endsWith("Async") ? methodName.slice(0, -"Async".length) : methodName;
|
|
944
880
|
}
|
|
945
|
-
__name(methodBase, "methodBase");
|
|
946
881
|
function responseShape(op) {
|
|
947
882
|
const observable = observableResponses(op);
|
|
948
|
-
if (observable.length > 1) return {
|
|
949
|
-
kind: "multiStatus",
|
|
950
|
-
responses: observable
|
|
951
|
-
};
|
|
883
|
+
if (observable.length > 1) return { kind: "multiStatus", responses: observable };
|
|
952
884
|
const response = observable[0];
|
|
953
|
-
if (response && response.bodies.length > 1) return {
|
|
954
|
-
|
|
955
|
-
response
|
|
956
|
-
};
|
|
957
|
-
return {
|
|
958
|
-
kind: "simple",
|
|
959
|
-
response
|
|
960
|
-
};
|
|
885
|
+
if (response && response.bodies.length > 1) return { kind: "multiMime", response };
|
|
886
|
+
return { kind: "simple", response };
|
|
961
887
|
}
|
|
962
|
-
__name(responseShape, "responseShape");
|
|
963
888
|
function observableOf(shape) {
|
|
964
889
|
if (shape.kind === "multiStatus") return shape.responses;
|
|
965
|
-
return shape.response ? [
|
|
966
|
-
shape.response
|
|
967
|
-
] : [];
|
|
890
|
+
return shape.response ? [shape.response] : [];
|
|
968
891
|
}
|
|
969
|
-
__name(observableOf, "observableOf");
|
|
970
892
|
function generateMethod(route, op, ctx, methodName) {
|
|
971
893
|
const base = methodBase(methodName);
|
|
972
894
|
const shape = responseShape(op);
|
|
@@ -974,19 +896,15 @@ function generateMethod(route, op, ctx, methodName) {
|
|
|
974
896
|
const observable = observableOf(shape);
|
|
975
897
|
const expectStatuses = observable.filter((r) => r.statusCode < 200 || r.statusCode >= 300).map((r) => r.statusCode);
|
|
976
898
|
const params = buildMethodParams(route, op, ctx);
|
|
977
|
-
const signature = [
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
].join(", ");
|
|
899
|
+
const signature = [...params.map((p) => `${p.type} ${p.name}${p.optional ? " = null" : ""}`), "CancellationToken cancellationToken = default"].join(
|
|
900
|
+
", "
|
|
901
|
+
);
|
|
981
902
|
const lines = [];
|
|
982
903
|
lines.push(...methodDoc(route, op, observable));
|
|
983
904
|
if (resolveModifiers(route, op).includes("deprecated")) lines.push('[Obsolete("Deprecated in the contract")]');
|
|
984
905
|
lines.push(`public async ${returnType === "void" ? "Task" : `Task<${returnType}>`} ${methodName}(${signature})`);
|
|
985
906
|
lines.push("{");
|
|
986
|
-
const callArgs = [
|
|
987
|
-
`HttpMethod.${httpMethodConstant(op.method)}`,
|
|
988
|
-
buildPathExpression(route.path, route.params)
|
|
989
|
-
];
|
|
907
|
+
const callArgs = [`HttpMethod.${httpMethodConstant(op.method)}`, buildPathExpression(route.path, route.params)];
|
|
990
908
|
if (op.query) callArgs.push("query: http.Params(query)");
|
|
991
909
|
if (op.headers) callArgs.push("headers: http.Params(customHeaders)");
|
|
992
910
|
const content = bodyArgument(op);
|
|
@@ -1002,7 +920,6 @@ function generateMethod(route, op, ctx, methodName) {
|
|
|
1002
920
|
lines.push("}");
|
|
1003
921
|
return lines;
|
|
1004
922
|
}
|
|
1005
|
-
__name(generateMethod, "generateMethod");
|
|
1006
923
|
function returnTypeFor(shape, base, ctx) {
|
|
1007
924
|
if (shape.kind !== "simple") return `${base}Response`;
|
|
1008
925
|
const response = shape.response;
|
|
@@ -1012,7 +929,6 @@ function returnTypeFor(shape, base, ctx) {
|
|
|
1012
929
|
const dataType = bodyCSharpType(body, ctx);
|
|
1013
930
|
return headers.length > 0 ? `${base}Result` : dataType;
|
|
1014
931
|
}
|
|
1015
|
-
__name(returnTypeFor, "returnTypeFor");
|
|
1016
932
|
function bodyCSharpType(body, ctx) {
|
|
1017
933
|
switch (classifyContentType(body.contentType)) {
|
|
1018
934
|
case "text":
|
|
@@ -1023,7 +939,6 @@ function bodyCSharpType(body, ctx) {
|
|
|
1023
939
|
return renderCSharpType(body.bodyType, ctx, false);
|
|
1024
940
|
}
|
|
1025
941
|
}
|
|
1026
|
-
__name(bodyCSharpType, "bodyCSharpType");
|
|
1027
942
|
function bodyReadExpr(body, ctx) {
|
|
1028
943
|
switch (classifyContentType(body.contentType)) {
|
|
1029
944
|
case "text":
|
|
@@ -1034,23 +949,14 @@ function bodyReadExpr(body, ctx) {
|
|
|
1034
949
|
return `http.ReadJson<${renderCSharpType(body.bodyType, ctx, false)}>(response)`;
|
|
1035
950
|
}
|
|
1036
951
|
}
|
|
1037
|
-
__name(bodyReadExpr, "bodyReadExpr");
|
|
1038
952
|
function returnStatements(shape, base, ctx, place) {
|
|
1039
953
|
if (shape.kind === "simple") {
|
|
1040
954
|
const response = shape.response;
|
|
1041
955
|
const body = response?.bodies[0];
|
|
1042
956
|
const headers = response?.headers ?? [];
|
|
1043
|
-
if (headers.length === 0) return body ? [
|
|
1044
|
-
` return ${bodyReadExpr(body, ctx)};`
|
|
1045
|
-
] : [];
|
|
957
|
+
if (headers.length === 0) return body ? [` return ${bodyReadExpr(body, ctx)};`] : [];
|
|
1046
958
|
const lines2 = readHeaderLines(headers, `${base}Headers`, ctx, place, " ");
|
|
1047
|
-
return body ? [
|
|
1048
|
-
...lines2,
|
|
1049
|
-
` return new ${base}Result(${bodyReadExpr(body, ctx)}, headers);`
|
|
1050
|
-
] : [
|
|
1051
|
-
...lines2,
|
|
1052
|
-
" return headers;"
|
|
1053
|
-
];
|
|
959
|
+
return body ? [...lines2, ` return new ${base}Result(${bodyReadExpr(body, ctx)}, headers);`] : [...lines2, " return headers;"];
|
|
1054
960
|
}
|
|
1055
961
|
if (shape.kind === "multiMime") {
|
|
1056
962
|
const headers = shape.response.headers ?? [];
|
|
@@ -1059,10 +965,7 @@ function returnStatements(shape, base, ctx, place) {
|
|
|
1059
965
|
return lines2;
|
|
1060
966
|
}
|
|
1061
967
|
const [fallback, ...rest] = shape.responses;
|
|
1062
|
-
const lines = [
|
|
1063
|
-
" switch (response.Status)",
|
|
1064
|
-
" {"
|
|
1065
|
-
];
|
|
968
|
+
const lines = [" switch (response.Status)", " {"];
|
|
1066
969
|
for (const response of rest) {
|
|
1067
970
|
lines.push(` case ${response.statusCode}:`);
|
|
1068
971
|
lines.push(" {");
|
|
@@ -1077,7 +980,6 @@ function returnStatements(shape, base, ctx, place) {
|
|
|
1077
980
|
lines.push(" }");
|
|
1078
981
|
return lines;
|
|
1079
982
|
}
|
|
1080
|
-
__name(returnStatements, "returnStatements");
|
|
1081
983
|
function statusBranch(response, base, statusCode, ctx, place, indent) {
|
|
1082
984
|
const lines = [];
|
|
1083
985
|
const headers = response.headers ?? [];
|
|
@@ -1085,23 +987,17 @@ function statusBranch(response, base, statusCode, ctx, place, indent) {
|
|
|
1085
987
|
lines.push(...mimeSwitch(response, base, statusCode, ctx, indent, headers.length > 0));
|
|
1086
988
|
return lines;
|
|
1087
989
|
}
|
|
1088
|
-
__name(statusBranch, "statusBranch");
|
|
1089
990
|
function mimeSwitch(response, base, statusCode, ctx, indent, hasHeaders) {
|
|
1090
991
|
const bodies = response.bodies;
|
|
1091
|
-
const construct =
|
|
992
|
+
const construct = (body) => {
|
|
1092
993
|
const args = [];
|
|
1093
994
|
if (body) args.push(bodyReadExpr(body, ctx));
|
|
1094
995
|
if (hasHeaders) args.push("headers");
|
|
1095
996
|
return `new ${base}Response.${leafRecordName(response, body, statusCode)}(${args.join(", ")})`;
|
|
1096
|
-
}
|
|
1097
|
-
if (bodies.length <= 1) return [
|
|
1098
|
-
`${indent}return ${construct(bodies[0])};`
|
|
1099
|
-
];
|
|
997
|
+
};
|
|
998
|
+
if (bodies.length <= 1) return [`${indent}return ${construct(bodies[0])};`];
|
|
1100
999
|
const [fallback, ...rest] = bodies;
|
|
1101
|
-
const lines = [
|
|
1102
|
-
`${indent}switch (response.ContentType)`,
|
|
1103
|
-
`${indent}{`
|
|
1104
|
-
];
|
|
1000
|
+
const lines = [`${indent}switch (response.ContentType)`, `${indent}{`];
|
|
1105
1001
|
for (const body of rest) {
|
|
1106
1002
|
lines.push(`${indent} case ${quoteCSharpString(body.contentType)}:`);
|
|
1107
1003
|
lines.push(`${indent} return ${construct(body)};`);
|
|
@@ -1111,7 +1007,6 @@ function mimeSwitch(response, base, statusCode, ctx, indent, hasHeaders) {
|
|
|
1111
1007
|
lines.push(`${indent}}`);
|
|
1112
1008
|
return lines;
|
|
1113
1009
|
}
|
|
1114
|
-
__name(mimeSwitch, "mimeSwitch");
|
|
1115
1010
|
function bodyArgument(op) {
|
|
1116
1011
|
const body = op.request?.bodies[0];
|
|
1117
1012
|
if (!body) return void 0;
|
|
@@ -1129,23 +1024,20 @@ function bodyArgument(op) {
|
|
|
1129
1024
|
return `content: http.JsonContent(body, ${mime})`;
|
|
1130
1025
|
}
|
|
1131
1026
|
}
|
|
1132
|
-
__name(bodyArgument, "bodyArgument");
|
|
1133
1027
|
function headersRecordName(base, statusCode) {
|
|
1134
1028
|
return statusCode === void 0 ? `${base}Headers` : `${base}${statusCode}Headers`;
|
|
1135
1029
|
}
|
|
1136
|
-
__name(headersRecordName, "headersRecordName");
|
|
1137
1030
|
function leafRecordName(response, body, statusCode) {
|
|
1138
1031
|
const statusPart = statusCode === void 0 ? "" : `Status${statusCode}`;
|
|
1139
1032
|
if (response.bodies.length <= 1 || !body) return statusPart || "Body";
|
|
1140
1033
|
return `${statusPart}${toCSharpTypeName(body.contentType.replace(/[+/.]/g, " "))}`;
|
|
1141
1034
|
}
|
|
1142
|
-
__name(leafRecordName, "leafRecordName");
|
|
1143
1035
|
function responseDeclarations(route, op, ctx) {
|
|
1144
1036
|
const shape = responseShape(op);
|
|
1145
1037
|
const base = methodBase(deriveMethodName(op, route));
|
|
1146
1038
|
const place = where(route, op);
|
|
1147
1039
|
const lines = [];
|
|
1148
|
-
const headerRecord =
|
|
1040
|
+
const headerRecord = (headers, name) => {
|
|
1149
1041
|
const parameters = headers.map((header) => {
|
|
1150
1042
|
const reader = headerReader(header, place);
|
|
1151
1043
|
const type = header.optional ? `${reader.type}?` : reader.type;
|
|
@@ -1154,7 +1046,7 @@ function responseDeclarations(route, op, ctx) {
|
|
|
1154
1046
|
lines.push("");
|
|
1155
1047
|
lines.push(...xmlDocLines(`Response headers declared on ${place}.`, ""));
|
|
1156
1048
|
lines.push(`public sealed record ${name}(${parameters});`);
|
|
1157
|
-
}
|
|
1049
|
+
};
|
|
1158
1050
|
if (shape.kind === "simple") {
|
|
1159
1051
|
const response = shape.response;
|
|
1160
1052
|
const headers = response?.headers ?? [];
|
|
@@ -1175,18 +1067,21 @@ function responseDeclarations(route, op, ctx) {
|
|
|
1175
1067
|
if (headers.length > 0) headerRecord(headers, headersRecordName(base, withStatus ? response.statusCode : void 0));
|
|
1176
1068
|
}
|
|
1177
1069
|
lines.push("");
|
|
1178
|
-
lines.push(
|
|
1179
|
-
|
|
1180
|
-
`
|
|
1070
|
+
lines.push(
|
|
1071
|
+
...xmlDocLines(
|
|
1072
|
+
`What ${place} returned.
|
|
1073
|
+
|
|
1074
|
+
` + (withStatus ? "The operation declares several statuses the service produces, so the status is part of the value." : "The status declares several content types, so which one arrived is part of the value."),
|
|
1075
|
+
""
|
|
1076
|
+
)
|
|
1077
|
+
);
|
|
1181
1078
|
lines.push(`public abstract record ${base}Response`);
|
|
1182
1079
|
lines.push("{");
|
|
1183
1080
|
lines.push(` private ${base}Response() { }`);
|
|
1184
1081
|
for (const response of responses) {
|
|
1185
1082
|
const statusCode = withStatus ? response.statusCode : void 0;
|
|
1186
1083
|
const headers = response.headers ?? [];
|
|
1187
|
-
const bodies = response.bodies.length > 0 ? response.bodies : [
|
|
1188
|
-
void 0
|
|
1189
|
-
];
|
|
1084
|
+
const bodies = response.bodies.length > 0 ? response.bodies : [void 0];
|
|
1190
1085
|
for (const body of bodies) {
|
|
1191
1086
|
const name = leafRecordName(response, body, statusCode);
|
|
1192
1087
|
const parameters = [];
|
|
@@ -1199,7 +1094,6 @@ function responseDeclarations(route, op, ctx) {
|
|
|
1199
1094
|
lines.push("}");
|
|
1200
1095
|
return lines;
|
|
1201
1096
|
}
|
|
1202
|
-
__name(responseDeclarations, "responseDeclarations");
|
|
1203
1097
|
function headerReader(header, place) {
|
|
1204
1098
|
const scalar = header.type.kind === "scalar" ? header.type.name : void 0;
|
|
1205
1099
|
switch (scalar) {
|
|
@@ -1208,66 +1102,36 @@ function headerReader(header, place) {
|
|
|
1208
1102
|
case "url":
|
|
1209
1103
|
case "interval":
|
|
1210
1104
|
case "unknown":
|
|
1211
|
-
return {
|
|
1212
|
-
type: "string",
|
|
1213
|
-
read: /* @__PURE__ */ __name((raw) => raw, "read")
|
|
1214
|
-
};
|
|
1105
|
+
return { type: "string", read: (raw) => raw };
|
|
1215
1106
|
case "number":
|
|
1216
|
-
return {
|
|
1217
|
-
type: "double",
|
|
1218
|
-
read: /* @__PURE__ */ __name((raw) => `double.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1219
|
-
};
|
|
1107
|
+
return { type: "double", read: (raw) => `double.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1220
1108
|
case "int":
|
|
1221
|
-
return {
|
|
1222
|
-
type: "long",
|
|
1223
|
-
read: /* @__PURE__ */ __name((raw) => `long.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1224
|
-
};
|
|
1109
|
+
return { type: "long", read: (raw) => `long.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1225
1110
|
case "bigint":
|
|
1226
|
-
return {
|
|
1227
|
-
type: "BigInteger",
|
|
1228
|
-
read: /* @__PURE__ */ __name((raw) => `BigInteger.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1229
|
-
};
|
|
1111
|
+
return { type: "BigInteger", read: (raw) => `BigInteger.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1230
1112
|
case "boolean":
|
|
1231
|
-
return {
|
|
1232
|
-
type: "bool",
|
|
1233
|
-
read: /* @__PURE__ */ __name((raw) => `${raw} == "true"`, "read")
|
|
1234
|
-
};
|
|
1113
|
+
return { type: "bool", read: (raw) => `${raw} == "true"` };
|
|
1235
1114
|
case "uuid":
|
|
1236
|
-
return {
|
|
1237
|
-
type: "Guid",
|
|
1238
|
-
read: /* @__PURE__ */ __name((raw) => `Guid.Parse(${raw})`, "read")
|
|
1239
|
-
};
|
|
1115
|
+
return { type: "Guid", read: (raw) => `Guid.Parse(${raw})` };
|
|
1240
1116
|
case "date":
|
|
1241
|
-
return {
|
|
1242
|
-
type: "DateOnly",
|
|
1243
|
-
read: /* @__PURE__ */ __name((raw) => `DateOnly.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1244
|
-
};
|
|
1117
|
+
return { type: "DateOnly", read: (raw) => `DateOnly.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1245
1118
|
case "time":
|
|
1246
|
-
return {
|
|
1247
|
-
type: "TimeOnly",
|
|
1248
|
-
read: /* @__PURE__ */ __name((raw) => `TimeOnly.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1249
|
-
};
|
|
1119
|
+
return { type: "TimeOnly", read: (raw) => `TimeOnly.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1250
1120
|
case "datetime":
|
|
1251
|
-
return {
|
|
1252
|
-
type: "DateTimeOffset",
|
|
1253
|
-
read: /* @__PURE__ */ __name((raw) => `DateTimeOffset.Parse(${raw}, CultureInfo.InvariantCulture)`, "read")
|
|
1254
|
-
};
|
|
1121
|
+
return { type: "DateTimeOffset", read: (raw) => `DateTimeOffset.Parse(${raw}, CultureInfo.InvariantCulture)` };
|
|
1255
1122
|
case "duration":
|
|
1256
|
-
return {
|
|
1257
|
-
type: "TimeSpan",
|
|
1258
|
-
read: /* @__PURE__ */ __name((raw) => `XmlConvert.ToTimeSpan(${raw})`, "read")
|
|
1259
|
-
};
|
|
1123
|
+
return { type: "TimeSpan", read: (raw) => `XmlConvert.ToTimeSpan(${raw})` };
|
|
1260
1124
|
default:
|
|
1261
|
-
throw new Error(
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`plugin-csharp: response header '${header.name}' on ${place} is declared as ${describeHeaderType(header.type)}, which cannot be read from an HTTP header. Header values arrive as strings \u2014 declare it as string, email, url, uuid, date, time, datetime, duration, interval, int, number, boolean or bigint.`
|
|
1127
|
+
);
|
|
1262
1128
|
}
|
|
1263
1129
|
}
|
|
1264
|
-
__name(headerReader, "headerReader");
|
|
1265
1130
|
function describeHeaderType(type) {
|
|
1266
1131
|
if (type.kind === "scalar") return `the '${type.name}' scalar`;
|
|
1267
1132
|
if (type.kind === "ref") return `the contract '${type.name}'`;
|
|
1268
1133
|
return `${type.kind === "array" || type.kind === "inlineObject" ? "an" : "a"} ${type.kind}`;
|
|
1269
1134
|
}
|
|
1270
|
-
__name(describeHeaderType, "describeHeaderType");
|
|
1271
1135
|
function readHeaderLines(headers, typeName, ctx, place, indent) {
|
|
1272
1136
|
const args = headers.map((header) => {
|
|
1273
1137
|
const reader = headerReader(header, place);
|
|
@@ -1276,13 +1140,10 @@ function readHeaderLines(headers, typeName, ctx, place, indent) {
|
|
|
1276
1140
|
const local = toCSharpParameterName(header.name);
|
|
1277
1141
|
return `response.Header(${name}) is { } ${local} ? ${reader.read(local)} : null`;
|
|
1278
1142
|
});
|
|
1279
|
-
const lines = [
|
|
1280
|
-
`${indent}var headers = new ${typeName}(`
|
|
1281
|
-
];
|
|
1143
|
+
const lines = [`${indent}var headers = new ${typeName}(`];
|
|
1282
1144
|
args.forEach((arg, index) => lines.push(`${indent} ${arg}${index === args.length - 1 ? ");" : ","}`));
|
|
1283
1145
|
return lines;
|
|
1284
1146
|
}
|
|
1285
|
-
__name(readHeaderLines, "readHeaderLines");
|
|
1286
1147
|
function methodDoc(route, op, observable) {
|
|
1287
1148
|
const lines = [];
|
|
1288
1149
|
const parts = [];
|
|
@@ -1294,12 +1155,10 @@ function methodDoc(route, op, observable) {
|
|
|
1294
1155
|
if (thrown.length > 0) lines.push(`/// <exception cref="SdkException">On ${thrown.join(", ")}.</exception>`);
|
|
1295
1156
|
return lines;
|
|
1296
1157
|
}
|
|
1297
|
-
__name(methodDoc, "methodDoc");
|
|
1298
1158
|
function httpMethodConstant(method) {
|
|
1299
1159
|
const lower = method.toLowerCase();
|
|
1300
1160
|
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
1301
1161
|
}
|
|
1302
|
-
__name(httpMethodConstant, "httpMethodConstant");
|
|
1303
1162
|
var PATH_PLACEHOLDER = /\{([a-zA-Z_$][a-zA-Z0-9_$.-]*)\}/g;
|
|
1304
1163
|
function buildPathExpression(path, params) {
|
|
1305
1164
|
const args = path.split("/").filter(Boolean).map((raw) => {
|
|
@@ -1311,65 +1170,36 @@ function buildPathExpression(path, params) {
|
|
|
1311
1170
|
});
|
|
1312
1171
|
return `http.Path(${args.join(", ")})`;
|
|
1313
1172
|
}
|
|
1314
|
-
__name(buildPathExpression, "buildPathExpression");
|
|
1315
1173
|
function buildMethodParams(route, op, ctx) {
|
|
1316
1174
|
const params = [];
|
|
1317
1175
|
if (route.params) {
|
|
1318
1176
|
if (route.params.kind === "params") {
|
|
1319
1177
|
for (const node of route.params.nodes) {
|
|
1320
|
-
params.push({
|
|
1321
|
-
name: toCSharpParameterName(node.name),
|
|
1322
|
-
type: renderCSharpType(node.type, ctx, true),
|
|
1323
|
-
optional: false
|
|
1324
|
-
});
|
|
1178
|
+
params.push({ name: toCSharpParameterName(node.name), type: renderCSharpType(node.type, ctx, true), optional: false });
|
|
1325
1179
|
}
|
|
1326
1180
|
} else {
|
|
1327
|
-
params.push({
|
|
1328
|
-
name: "pathParams",
|
|
1329
|
-
type: renderParamSourceType(route.params, ctx, ""),
|
|
1330
|
-
optional: false
|
|
1331
|
-
});
|
|
1181
|
+
params.push({ name: "pathParams", type: renderParamSourceType(route.params, ctx, ""), optional: false });
|
|
1332
1182
|
}
|
|
1333
1183
|
}
|
|
1334
1184
|
const body = op.request?.bodies[0];
|
|
1335
1185
|
if (body) {
|
|
1336
1186
|
switch (classifyContentType(body.contentType)) {
|
|
1337
1187
|
case "multipart":
|
|
1338
|
-
params.push({
|
|
1339
|
-
name: "body",
|
|
1340
|
-
type: "IEnumerable<SdkPart>",
|
|
1341
|
-
optional: false
|
|
1342
|
-
});
|
|
1188
|
+
params.push({ name: "body", type: "IEnumerable<SdkPart>", optional: false });
|
|
1343
1189
|
break;
|
|
1344
1190
|
case "binary":
|
|
1345
|
-
params.push({
|
|
1346
|
-
name: "body",
|
|
1347
|
-
type: "byte[]",
|
|
1348
|
-
optional: false
|
|
1349
|
-
});
|
|
1191
|
+
params.push({ name: "body", type: "byte[]", optional: false });
|
|
1350
1192
|
break;
|
|
1351
1193
|
case "text":
|
|
1352
|
-
params.push({
|
|
1353
|
-
name: "body",
|
|
1354
|
-
type: "string",
|
|
1355
|
-
optional: false
|
|
1356
|
-
});
|
|
1194
|
+
params.push({ name: "body", type: "string", optional: false });
|
|
1357
1195
|
break;
|
|
1358
1196
|
default:
|
|
1359
|
-
params.push({
|
|
1360
|
-
name: "body",
|
|
1361
|
-
type: renderCSharpType(body.bodyType, ctx, true),
|
|
1362
|
-
optional: false
|
|
1363
|
-
});
|
|
1197
|
+
params.push({ name: "body", type: renderCSharpType(body.bodyType, ctx, true), optional: false });
|
|
1364
1198
|
}
|
|
1365
1199
|
}
|
|
1366
1200
|
const base = methodBase(deriveMethodName(op, route));
|
|
1367
1201
|
if (op.query) {
|
|
1368
|
-
params.push({
|
|
1369
|
-
name: "query",
|
|
1370
|
-
type: renderParamSourceType(op.query, ctx, `${base}Query`),
|
|
1371
|
-
optional: allFieldsOptional(op.query)
|
|
1372
|
-
});
|
|
1202
|
+
params.push({ name: "query", type: renderParamSourceType(op.query, ctx, `${base}Query`), optional: allFieldsOptional(op.query) });
|
|
1373
1203
|
}
|
|
1374
1204
|
if (op.headers) {
|
|
1375
1205
|
params.push({
|
|
@@ -1378,63 +1208,47 @@ function buildMethodParams(route, op, ctx) {
|
|
|
1378
1208
|
optional: allFieldsOptional(op.headers)
|
|
1379
1209
|
});
|
|
1380
1210
|
}
|
|
1381
|
-
const widened = params.map((p) => p.optional && !p.type.endsWith("?") ? {
|
|
1382
|
-
|
|
1383
|
-
type: `${p.type}?`
|
|
1384
|
-
} : p);
|
|
1385
|
-
return [
|
|
1386
|
-
...widened.filter((p) => !p.optional),
|
|
1387
|
-
...widened.filter((p) => p.optional)
|
|
1388
|
-
];
|
|
1211
|
+
const widened = params.map((p) => p.optional && !p.type.endsWith("?") ? { ...p, type: `${p.type}?` } : p);
|
|
1212
|
+
return [...widened.filter((p) => !p.optional), ...widened.filter((p) => p.optional)];
|
|
1389
1213
|
}
|
|
1390
|
-
__name(buildMethodParams, "buildMethodParams");
|
|
1391
1214
|
function allFieldsOptional(source) {
|
|
1392
1215
|
if (source.kind !== "params") return true;
|
|
1393
1216
|
return source.nodes.every((node) => Boolean(node.optional) || node.default !== void 0);
|
|
1394
1217
|
}
|
|
1395
|
-
__name(allFieldsOptional, "allFieldsOptional");
|
|
1396
1218
|
function renderParamSourceType(source, ctx, generatedName) {
|
|
1397
|
-
if (source.kind === "ref") return renderCSharpType({
|
|
1398
|
-
kind: "ref",
|
|
1399
|
-
name: source.name
|
|
1400
|
-
}, ctx, true);
|
|
1219
|
+
if (source.kind === "ref") return renderCSharpType({ kind: "ref", name: source.name }, ctx, true);
|
|
1401
1220
|
if (source.kind === "type") return renderCSharpType(source.node, ctx, true);
|
|
1402
1221
|
return source.nodes.length > 0 ? generatedName : "IReadOnlyDictionary<string, string>";
|
|
1403
1222
|
}
|
|
1404
|
-
__name(renderParamSourceType, "renderParamSourceType");
|
|
1405
1223
|
function deriveMethodName(op, route) {
|
|
1406
1224
|
if (op.sdk) return `${toCSharpTypeName(op.sdk)}Async`;
|
|
1407
1225
|
if (op.name) return `${toCSharpTypeName(op.name)}Async`;
|
|
1408
1226
|
return `${inferMethodName(op.method, route.path)}Async`;
|
|
1409
1227
|
}
|
|
1410
|
-
__name(deriveMethodName, "deriveMethodName");
|
|
1411
1228
|
function inferMethodName(method, path) {
|
|
1412
|
-
const parts = [
|
|
1413
|
-
toCSharpTypeName(method)
|
|
1414
|
-
];
|
|
1229
|
+
const parts = [toCSharpTypeName(method)];
|
|
1415
1230
|
for (const segment of path.split("/").filter(Boolean)) {
|
|
1416
1231
|
if (segment.startsWith("{")) parts.push(`By${toCSharpTypeName(segment.slice(1, -1))}`);
|
|
1417
1232
|
else parts.push(toCSharpTypeName(segment));
|
|
1418
1233
|
}
|
|
1419
1234
|
return parts.join("");
|
|
1420
1235
|
}
|
|
1421
|
-
__name(inferMethodName, "inferMethodName");
|
|
1422
1236
|
|
|
1423
1237
|
// src/codegen-sdk.ts
|
|
1424
1238
|
function generateSdkCs(namespaceName, sdkName, clients) {
|
|
1425
|
-
const lines = [
|
|
1426
|
-
"// <auto-generated/>",
|
|
1427
|
-
"// Generated by @contractkit/plugin-csharp. Do not edit manually.",
|
|
1428
|
-
"#nullable enable",
|
|
1429
|
-
""
|
|
1430
|
-
];
|
|
1239
|
+
const lines = ["// <auto-generated/>", "// Generated by @contractkit/plugin-csharp. Do not edit manually.", "#nullable enable", ""];
|
|
1431
1240
|
lines.push("using System;");
|
|
1432
1241
|
if (clients.length > 0) lines.push(`using ${namespaceName}.Clients;`);
|
|
1433
1242
|
lines.push(`using ${namespaceName}.Runtime;`);
|
|
1434
1243
|
lines.push("");
|
|
1435
1244
|
lines.push(`namespace ${namespaceName};`);
|
|
1436
1245
|
lines.push("");
|
|
1437
|
-
lines.push(
|
|
1246
|
+
lines.push(
|
|
1247
|
+
...xmlDocLines(
|
|
1248
|
+
"Entry point to the generated SDK.\n\nHolds one SdkHttp, shared by every client, so the SDK keeps a single connection pool.\nDisposing it disposes the underlying HttpClient, unless you supplied your own.",
|
|
1249
|
+
""
|
|
1250
|
+
)
|
|
1251
|
+
);
|
|
1438
1252
|
lines.push(`public sealed class ${sdkName} : IDisposable`);
|
|
1439
1253
|
lines.push("{");
|
|
1440
1254
|
lines.push(` public ${sdkName}(SdkOptions options)`);
|
|
@@ -1457,7 +1271,6 @@ function generateSdkCs(namespaceName, sdkName, clients) {
|
|
|
1457
1271
|
lines.push("");
|
|
1458
1272
|
return lines.join("\n");
|
|
1459
1273
|
}
|
|
1460
|
-
__name(generateSdkCs, "generateSdkCs");
|
|
1461
1274
|
|
|
1462
1275
|
// src/hoist.ts
|
|
1463
1276
|
import { collectTypeRefs, resolveEffectiveFields as resolveEffectiveFields2 } from "@contractkit/core";
|
|
@@ -1480,14 +1293,8 @@ function collectHoistedTypes(roots, opts) {
|
|
|
1480
1293
|
}
|
|
1481
1294
|
}
|
|
1482
1295
|
}
|
|
1483
|
-
return {
|
|
1484
|
-
byNode: state.byNode,
|
|
1485
|
-
byName: state.byName,
|
|
1486
|
-
byFile: state.byFile,
|
|
1487
|
-
memberships: state.memberships
|
|
1488
|
-
};
|
|
1296
|
+
return { byNode: state.byNode, byName: state.byName, byFile: state.byFile, memberships: state.memberships };
|
|
1489
1297
|
}
|
|
1490
|
-
__name(collectHoistedTypes, "collectHoistedTypes");
|
|
1491
1298
|
function walkType(type, path, ownerFile, state, atAliasRoot, description) {
|
|
1492
1299
|
switch (type.kind) {
|
|
1493
1300
|
case "union":
|
|
@@ -1498,14 +1305,11 @@ function walkType(type, path, ownerFile, state, atAliasRoot, description) {
|
|
|
1498
1305
|
return;
|
|
1499
1306
|
case "enum":
|
|
1500
1307
|
if (!atAliasRoot) {
|
|
1501
|
-
hoist(
|
|
1502
|
-
|
|
1503
|
-
name: claimFor(path, state, false),
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
values: type.values,
|
|
1507
|
-
description
|
|
1508
|
-
}, state);
|
|
1308
|
+
hoist(
|
|
1309
|
+
type,
|
|
1310
|
+
{ kind: "enum", name: claimFor(path, state, false), ownerFile, needsInput: false, values: type.values, description },
|
|
1311
|
+
state
|
|
1312
|
+
);
|
|
1509
1313
|
}
|
|
1510
1314
|
return;
|
|
1511
1315
|
case "inlineObject":
|
|
@@ -1523,14 +1327,18 @@ function walkType(type, path, ownerFile, state, atAliasRoot, description) {
|
|
|
1523
1327
|
}
|
|
1524
1328
|
case "tuple":
|
|
1525
1329
|
type.items.forEach((item, i) => walkType(item, `${path}Item${i}`, ownerFile, state, false));
|
|
1526
|
-
hoist(
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1330
|
+
hoist(
|
|
1331
|
+
type,
|
|
1332
|
+
{
|
|
1333
|
+
kind: "tuple",
|
|
1334
|
+
name: claimFor(path, state, false),
|
|
1335
|
+
ownerFile,
|
|
1336
|
+
needsInput: type.items.some((t) => typeNeedsInput(t, state)),
|
|
1337
|
+
items: type.items,
|
|
1338
|
+
description
|
|
1339
|
+
},
|
|
1340
|
+
state
|
|
1341
|
+
);
|
|
1534
1342
|
return;
|
|
1535
1343
|
case "array":
|
|
1536
1344
|
walkType(type.item, path, ownerFile, state, false);
|
|
@@ -1545,20 +1353,22 @@ function walkType(type, path, ownerFile, state, atAliasRoot, description) {
|
|
|
1545
1353
|
return;
|
|
1546
1354
|
}
|
|
1547
1355
|
}
|
|
1548
|
-
__name(walkType, "walkType");
|
|
1549
1356
|
function hoistRecord(node, fields, path, ownerFile, state, description) {
|
|
1550
1357
|
const name = claimFor(path, state, false);
|
|
1551
1358
|
for (const f of fields) walkType(f.type, `${name}${toCSharpTypeName(f.name)}`, ownerFile, state, false, f.description);
|
|
1552
|
-
hoist(
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1359
|
+
hoist(
|
|
1360
|
+
node,
|
|
1361
|
+
{
|
|
1362
|
+
kind: "record",
|
|
1363
|
+
name,
|
|
1364
|
+
ownerFile,
|
|
1365
|
+
needsInput: fields.some((f) => f.visibility !== "normal" || typeNeedsInput(f.type, state)),
|
|
1366
|
+
fields,
|
|
1367
|
+
description
|
|
1368
|
+
},
|
|
1369
|
+
state
|
|
1370
|
+
);
|
|
1560
1371
|
}
|
|
1561
|
-
__name(hoistRecord, "hoistRecord");
|
|
1562
1372
|
function hoistPlainUnion(type, path, ownerFile, state, atAliasRoot, description) {
|
|
1563
1373
|
const nullable = type.members.some((m) => m.kind === "scalar" && m.name === "null");
|
|
1564
1374
|
const members = type.members.filter((m) => !(m.kind === "scalar" && m.name === "null"));
|
|
@@ -1568,15 +1378,7 @@ function hoistPlainUnion(type, path, ownerFile, state, atAliasRoot, description)
|
|
|
1568
1378
|
}
|
|
1569
1379
|
if (members.every((m) => m.kind === "literal" && typeof m.value === "string")) {
|
|
1570
1380
|
const values = members.map((m) => String(m.value));
|
|
1571
|
-
hoist(type, {
|
|
1572
|
-
kind: "enum",
|
|
1573
|
-
name: claimFor(path, state, atAliasRoot),
|
|
1574
|
-
ownerFile,
|
|
1575
|
-
needsInput: false,
|
|
1576
|
-
nullable,
|
|
1577
|
-
values,
|
|
1578
|
-
description
|
|
1579
|
-
}, state);
|
|
1381
|
+
hoist(type, { kind: "enum", name: claimFor(path, state, atAliasRoot), ownerFile, needsInput: false, nullable, values, description }, state);
|
|
1580
1382
|
return;
|
|
1581
1383
|
}
|
|
1582
1384
|
const name = claimFor(path, state, atAliasRoot);
|
|
@@ -1585,23 +1387,22 @@ function hoistPlainUnion(type, path, ownerFile, state, atAliasRoot, description)
|
|
|
1585
1387
|
for (const member of members) {
|
|
1586
1388
|
walkType(member, `${name}${toCSharpTypeName(memberLabel(member, state))}`, ownerFile, state, false);
|
|
1587
1389
|
const typeName = memberTypeName(member, state);
|
|
1588
|
-
hoisted.push({
|
|
1589
|
-
typeName,
|
|
1590
|
-
wrapperName: uniqueIn(`Of${toCSharpTypeName(memberLabel(member, state))}`, used),
|
|
1591
|
-
type: member
|
|
1592
|
-
});
|
|
1390
|
+
hoisted.push({ typeName, wrapperName: uniqueIn(`Of${toCSharpTypeName(memberLabel(member, state))}`, used), type: member });
|
|
1593
1391
|
}
|
|
1594
|
-
hoist(
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1392
|
+
hoist(
|
|
1393
|
+
type,
|
|
1394
|
+
{
|
|
1395
|
+
kind: "plainUnion",
|
|
1396
|
+
name,
|
|
1397
|
+
ownerFile,
|
|
1398
|
+
needsInput: members.some((m) => typeNeedsInput(m, state)),
|
|
1399
|
+
nullable,
|
|
1400
|
+
members: hoisted,
|
|
1401
|
+
description
|
|
1402
|
+
},
|
|
1403
|
+
state
|
|
1404
|
+
);
|
|
1603
1405
|
}
|
|
1604
|
-
__name(hoistPlainUnion, "hoistPlainUnion");
|
|
1605
1406
|
function hoistDiscriminatedUnion(type, path, ownerFile, state, atAliasRoot, description) {
|
|
1606
1407
|
const name = claimFor(path, state, atAliasRoot);
|
|
1607
1408
|
const members = [];
|
|
@@ -1610,17 +1411,16 @@ function hoistDiscriminatedUnion(type, path, ownerFile, state, atAliasRoot, desc
|
|
|
1610
1411
|
const discriminatorField = fields.find((f) => f.name === type.discriminator);
|
|
1611
1412
|
const tagType = discriminatorField?.type.kind === "lazy" ? discriminatorField.type.inner : discriminatorField?.type;
|
|
1612
1413
|
if (!tagType || tagType.kind !== "literal") {
|
|
1613
|
-
state.warn?.(
|
|
1414
|
+
state.warn?.(
|
|
1415
|
+
`Discriminated union '${name}' has a member whose '${type.discriminator}' is not a literal, so its tag is not known at build time; emitting a raw JSON value instead of an interface.`,
|
|
1416
|
+
ownerFile
|
|
1417
|
+
);
|
|
1614
1418
|
release(name, state, atAliasRoot);
|
|
1615
1419
|
return;
|
|
1616
1420
|
}
|
|
1617
1421
|
const tag = String(tagType.value);
|
|
1618
1422
|
if (member.kind === "ref") {
|
|
1619
|
-
members.push({
|
|
1620
|
-
typeName: member.name,
|
|
1621
|
-
tag,
|
|
1622
|
-
type: member
|
|
1623
|
-
});
|
|
1423
|
+
members.push({ typeName: member.name, tag, type: member });
|
|
1624
1424
|
} else {
|
|
1625
1425
|
const memberPath = `${name}${toCSharpTypeName(tag)}`;
|
|
1626
1426
|
hoistRecord(member, fields, memberPath, ownerFile, state, void 0);
|
|
@@ -1629,11 +1429,7 @@ function hoistDiscriminatedUnion(type, path, ownerFile, state, atAliasRoot, desc
|
|
|
1629
1429
|
release(name, state, atAliasRoot);
|
|
1630
1430
|
return;
|
|
1631
1431
|
}
|
|
1632
|
-
members.push({
|
|
1633
|
-
typeName: decl2.name,
|
|
1634
|
-
tag,
|
|
1635
|
-
type: member
|
|
1636
|
-
});
|
|
1432
|
+
members.push({ typeName: decl2.name, tag, type: member });
|
|
1637
1433
|
}
|
|
1638
1434
|
}
|
|
1639
1435
|
if (members.length === 0) {
|
|
@@ -1656,7 +1452,6 @@ function hoistDiscriminatedUnion(type, path, ownerFile, state, atAliasRoot, desc
|
|
|
1656
1452
|
state.memberships.set(member.typeName, list);
|
|
1657
1453
|
}
|
|
1658
1454
|
}
|
|
1659
|
-
__name(hoistDiscriminatedUnion, "hoistDiscriminatedUnion");
|
|
1660
1455
|
function memberLabel(type, state) {
|
|
1661
1456
|
switch (type.kind) {
|
|
1662
1457
|
case "ref":
|
|
@@ -1677,23 +1472,18 @@ function memberLabel(type, state) {
|
|
|
1677
1472
|
}
|
|
1678
1473
|
}
|
|
1679
1474
|
}
|
|
1680
|
-
__name(memberLabel, "memberLabel");
|
|
1681
1475
|
function memberTypeName(type, state) {
|
|
1682
1476
|
const decl = state.byNode.get(type);
|
|
1683
1477
|
if (decl) return decl.name;
|
|
1684
1478
|
if (type.kind === "ref") return type.name;
|
|
1685
1479
|
return "";
|
|
1686
1480
|
}
|
|
1687
|
-
__name(memberTypeName, "memberTypeName");
|
|
1688
1481
|
function typeNeedsInput(type, state) {
|
|
1689
1482
|
const refs = /* @__PURE__ */ new Set();
|
|
1690
1483
|
collectTypeRefs(type, refs);
|
|
1691
|
-
if ([
|
|
1692
|
-
...refs
|
|
1693
|
-
].some((r) => state.modelsWithInput.has(r))) return true;
|
|
1484
|
+
if ([...refs].some((r) => state.modelsWithInput.has(r))) return true;
|
|
1694
1485
|
return hasVisibilityField(type);
|
|
1695
1486
|
}
|
|
1696
|
-
__name(typeNeedsInput, "typeNeedsInput");
|
|
1697
1487
|
function hasVisibilityField(type) {
|
|
1698
1488
|
switch (type.kind) {
|
|
1699
1489
|
case "inlineObject":
|
|
@@ -1714,7 +1504,6 @@ function hasVisibilityField(type) {
|
|
|
1714
1504
|
return false;
|
|
1715
1505
|
}
|
|
1716
1506
|
}
|
|
1717
|
-
__name(hasVisibilityField, "hasVisibilityField");
|
|
1718
1507
|
function hoist(node, decl, state) {
|
|
1719
1508
|
state.byNode.set(node, decl);
|
|
1720
1509
|
state.byName.set(decl.name, decl);
|
|
@@ -1722,16 +1511,13 @@ function hoist(node, decl, state) {
|
|
|
1722
1511
|
list.push(decl);
|
|
1723
1512
|
state.byFile.set(decl.ownerFile, list);
|
|
1724
1513
|
}
|
|
1725
|
-
__name(hoist, "hoist");
|
|
1726
1514
|
function claimFor(path, state, atAliasRoot) {
|
|
1727
1515
|
if (atAliasRoot) return path;
|
|
1728
1516
|
return uniqueIn(sanitizeCSharpTypeName(path), state.taken);
|
|
1729
1517
|
}
|
|
1730
|
-
__name(claimFor, "claimFor");
|
|
1731
1518
|
function release(name, state, atAliasRoot) {
|
|
1732
1519
|
if (!atAliasRoot) state.taken.delete(name);
|
|
1733
1520
|
}
|
|
1734
|
-
__name(release, "release");
|
|
1735
1521
|
function uniqueIn(base, taken) {
|
|
1736
1522
|
if (!taken.has(base)) {
|
|
1737
1523
|
taken.add(base);
|
|
@@ -1742,7 +1528,6 @@ function uniqueIn(base, taken) {
|
|
|
1742
1528
|
taken.add(`${base}${n}`);
|
|
1743
1529
|
return `${base}${n}`;
|
|
1744
1530
|
}
|
|
1745
|
-
__name(uniqueIn, "uniqueIn");
|
|
1746
1531
|
|
|
1747
1532
|
// src/runtime.ts
|
|
1748
1533
|
function generateRuntimeCs(namespaceName) {
|
|
@@ -2117,7 +1902,6 @@ public sealed class SdkHttp : IDisposable
|
|
|
2117
1902
|
}
|
|
2118
1903
|
`;
|
|
2119
1904
|
}
|
|
2120
|
-
__name(generateRuntimeCs, "generateRuntimeCs");
|
|
2121
1905
|
|
|
2122
1906
|
// src/runtime-converters.ts
|
|
2123
1907
|
function generateConvertersCs(namespaceName) {
|
|
@@ -2253,7 +2037,6 @@ public sealed class IsoTimeSpanConverter : JsonConverter<TimeSpan>
|
|
|
2253
2037
|
}
|
|
2254
2038
|
`;
|
|
2255
2039
|
}
|
|
2256
|
-
__name(generateConvertersCs, "generateConvertersCs");
|
|
2257
2040
|
|
|
2258
2041
|
// src/scaffold.ts
|
|
2259
2042
|
var SCAFFOLD_VERSIONS = {
|
|
@@ -2274,7 +2057,6 @@ function generateCsproj(namespaceName, sdkName) {
|
|
|
2274
2057
|
</Project>
|
|
2275
2058
|
`;
|
|
2276
2059
|
}
|
|
2277
|
-
__name(generateCsproj, "generateCsproj");
|
|
2278
2060
|
|
|
2279
2061
|
// src/index.ts
|
|
2280
2062
|
var CSHARP_CODEGEN_VERSION = "1";
|
|
@@ -2298,14 +2080,15 @@ function createCSharpSdkPlugin(config, rootDir) {
|
|
|
2298
2080
|
}
|
|
2299
2081
|
};
|
|
2300
2082
|
}
|
|
2301
|
-
__name(createCSharpSdkPlugin, "createCSharpSdkPlugin");
|
|
2302
2083
|
var NAMESPACE_RE = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
2303
2084
|
var SDK_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2304
2085
|
function assertValidConfig(config) {
|
|
2305
2086
|
const { namespace, sdkName } = config;
|
|
2306
2087
|
if (namespace !== void 0) {
|
|
2307
2088
|
if (typeof namespace !== "string" || !NAMESPACE_RE.test(namespace)) {
|
|
2308
|
-
throw new Error(
|
|
2089
|
+
throw new Error(
|
|
2090
|
+
`plugin-csharp: namespace '${String(namespace)}' is not a valid C# namespace \u2014 expected dot-separated identifiers, e.g. 'Acme.Sdk'.`
|
|
2091
|
+
);
|
|
2309
2092
|
}
|
|
2310
2093
|
const keyword = namespace.split(".").find((segment) => CSHARP_KEYWORDS.has(segment));
|
|
2311
2094
|
if (keyword) {
|
|
@@ -2320,17 +2103,13 @@ function assertValidConfig(config) {
|
|
|
2320
2103
|
throw new Error(`plugin-csharp: sdkName '${sdkName}' is a C# keyword.`);
|
|
2321
2104
|
}
|
|
2322
2105
|
}
|
|
2323
|
-
for (const key of [
|
|
2324
|
-
"includeInternal",
|
|
2325
|
-
"scaffold"
|
|
2326
|
-
]) {
|
|
2106
|
+
for (const key of ["includeInternal", "scaffold"]) {
|
|
2327
2107
|
const value = config[key];
|
|
2328
2108
|
if (value !== void 0 && typeof value !== "boolean") {
|
|
2329
2109
|
throw new Error(`plugin-csharp: ${key} must be a boolean \u2014 got ${JSON.stringify(value)}.`);
|
|
2330
2110
|
}
|
|
2331
2111
|
}
|
|
2332
2112
|
}
|
|
2333
|
-
__name(assertValidConfig, "assertValidConfig");
|
|
2334
2113
|
async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
2335
2114
|
assertValidConfig(config);
|
|
2336
2115
|
const { contractRoots } = inputs;
|
|
@@ -2341,13 +2120,11 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2341
2120
|
const allModels = contractRoots.flatMap((root) => root.models);
|
|
2342
2121
|
const modelIndex = buildModelIndex2(allModels);
|
|
2343
2122
|
const modelsWithInput = resolveModelsWithInput(allModels, inputs.modelsWithInput);
|
|
2344
|
-
const modelsWithInputArray = [
|
|
2345
|
-
...modelsWithInput
|
|
2346
|
-
].sort();
|
|
2123
|
+
const modelsWithInputArray = [...modelsWithInput].sort();
|
|
2347
2124
|
const hoisted = collectHoistedTypes(contractRoots, {
|
|
2348
2125
|
modelIndex,
|
|
2349
2126
|
modelsWithInput,
|
|
2350
|
-
warn:
|
|
2127
|
+
warn: (message, file) => ctx.warn?.(message, file)
|
|
2351
2128
|
});
|
|
2352
2129
|
const prevManifest = ctx.cacheEnabled ? readManifest(manifestPath) : emptyIncrementalManifest(CSHARP_CODEGEN_VERSION);
|
|
2353
2130
|
const units = [];
|
|
@@ -2357,20 +2134,9 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2357
2134
|
const ownNames = new Set(root.models.map((m) => m.name));
|
|
2358
2135
|
const referenced = referencedModelNames(root);
|
|
2359
2136
|
const relevantInputModels = modelsWithInputArray.filter((name) => ownNames.has(name) || referenced.has(name));
|
|
2360
|
-
const externalBases = [
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
const ownedDeclarations = (hoisted.byFile.get(root.file) ?? []).map((d) => ({
|
|
2364
|
-
kind: d.kind,
|
|
2365
|
-
name: d.name,
|
|
2366
|
-
needsInput: d.needsInput
|
|
2367
|
-
}));
|
|
2368
|
-
const declaredMemberships = [
|
|
2369
|
-
...ownNames
|
|
2370
|
-
].sort().map((name) => [
|
|
2371
|
-
name,
|
|
2372
|
-
hoisted.memberships.get(name) ?? []
|
|
2373
|
-
]).filter(([, unions]) => unions.length > 0);
|
|
2137
|
+
const externalBases = [...referenced].filter((name) => !ownNames.has(name)).sort().map((name) => modelIndex.get(name)).filter((m) => m !== void 0);
|
|
2138
|
+
const ownedDeclarations = (hoisted.byFile.get(root.file) ?? []).map((d) => ({ kind: d.kind, name: d.name, needsInput: d.needsInput }));
|
|
2139
|
+
const declaredMemberships = [...ownNames].sort().map((name) => [name, hoisted.memberships.get(name) ?? []]).filter(([, unions]) => unions.length > 0);
|
|
2374
2140
|
const fingerprint = hashFingerprint({
|
|
2375
2141
|
kind: "models",
|
|
2376
2142
|
v: CSHARP_CODEGEN_VERSION,
|
|
@@ -2385,7 +2151,7 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2385
2151
|
units.push({
|
|
2386
2152
|
key: `models::${relPath}`,
|
|
2387
2153
|
fingerprint,
|
|
2388
|
-
render:
|
|
2154
|
+
render: () => [
|
|
2389
2155
|
{
|
|
2390
2156
|
relativePath: relPath,
|
|
2391
2157
|
content: generateCSharpModels(root, {
|
|
@@ -2393,24 +2159,19 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2393
2159
|
modelsWithInput,
|
|
2394
2160
|
modelIndex,
|
|
2395
2161
|
hoisted,
|
|
2396
|
-
warn:
|
|
2162
|
+
warn: (message) => ctx.warn?.(message, root.file)
|
|
2397
2163
|
})
|
|
2398
2164
|
}
|
|
2399
|
-
]
|
|
2165
|
+
]
|
|
2400
2166
|
});
|
|
2401
2167
|
}
|
|
2402
2168
|
for (const root of inputs.opRoots) {
|
|
2403
2169
|
if (!hasPublicOperations(root, config.includeInternal)) continue;
|
|
2404
2170
|
const relPath = `Clients/${deriveClientClassName(root.file)}.cs`;
|
|
2405
|
-
clients.push({
|
|
2406
|
-
className: deriveClientClassName(root.file),
|
|
2407
|
-
propertyName: deriveClientPropertyName(root.file)
|
|
2408
|
-
});
|
|
2171
|
+
clients.push({ className: deriveClientClassName(root.file), propertyName: deriveClientPropertyName(root.file) });
|
|
2409
2172
|
const referenced = referencedOpModels(root, modelIndex);
|
|
2410
2173
|
const relevantInputModels = modelsWithInputArray.filter((name) => referenced.has(name));
|
|
2411
|
-
const referencedModels = [
|
|
2412
|
-
...referenced
|
|
2413
|
-
].sort().map((name) => modelIndex.get(name)).filter((m) => m !== void 0);
|
|
2174
|
+
const referencedModels = [...referenced].sort().map((name) => modelIndex.get(name)).filter((m) => m !== void 0);
|
|
2414
2175
|
const fingerprint = hashFingerprint({
|
|
2415
2176
|
kind: "client",
|
|
2416
2177
|
v: CSHARP_CODEGEN_VERSION,
|
|
@@ -2424,7 +2185,7 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2424
2185
|
units.push({
|
|
2425
2186
|
key: `client::${relPath}`,
|
|
2426
2187
|
fingerprint,
|
|
2427
|
-
render:
|
|
2188
|
+
render: () => [
|
|
2428
2189
|
{
|
|
2429
2190
|
relativePath: relPath,
|
|
2430
2191
|
content: generateCSharpClient(root, {
|
|
@@ -2433,60 +2194,41 @@ async function runCSharpCodegen(inputs, ctx, config, rootDir) {
|
|
|
2433
2194
|
modelIndex,
|
|
2434
2195
|
hoisted,
|
|
2435
2196
|
includeInternal: config.includeInternal,
|
|
2436
|
-
warn:
|
|
2197
|
+
warn: (message) => ctx.warn?.(message, root.file)
|
|
2437
2198
|
})
|
|
2438
2199
|
}
|
|
2439
|
-
]
|
|
2200
|
+
]
|
|
2440
2201
|
});
|
|
2441
2202
|
}
|
|
2442
2203
|
const globalFiles = [
|
|
2443
|
-
{
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
},
|
|
2447
|
-
{
|
|
2448
|
-
relativePath: "Runtime/SdkRuntime.cs",
|
|
2449
|
-
content: generateRuntimeCs(namespaceName)
|
|
2450
|
-
},
|
|
2451
|
-
{
|
|
2452
|
-
relativePath: `${sdkName}.cs`,
|
|
2453
|
-
content: generateSdkCs(namespaceName, sdkName, clients)
|
|
2454
|
-
}
|
|
2204
|
+
{ relativePath: "Runtime/Converters.cs", content: generateConvertersCs(namespaceName) },
|
|
2205
|
+
{ relativePath: "Runtime/SdkRuntime.cs", content: generateRuntimeCs(namespaceName) },
|
|
2206
|
+
{ relativePath: `${sdkName}.cs`, content: generateSdkCs(namespaceName, sdkName, clients) }
|
|
2455
2207
|
];
|
|
2456
2208
|
if (config.scaffold) {
|
|
2457
|
-
globalFiles.push({
|
|
2458
|
-
relativePath: `${sdkName}.csproj`,
|
|
2459
|
-
content: generateCsproj(namespaceName, sdkName),
|
|
2460
|
-
ifAbsent: true
|
|
2461
|
-
});
|
|
2209
|
+
globalFiles.push({ relativePath: `${sdkName}.csproj`, content: generateCsproj(namespaceName, sdkName), ifAbsent: true });
|
|
2462
2210
|
}
|
|
2463
2211
|
const result = runIncrementalCodegen({
|
|
2464
2212
|
codegenVersion: CSHARP_CODEGEN_VERSION,
|
|
2465
2213
|
prevManifest,
|
|
2466
2214
|
globalFiles,
|
|
2467
2215
|
units,
|
|
2468
|
-
fileExists:
|
|
2216
|
+
fileExists: (relPath) => existsSync(resolve(outDir, relPath))
|
|
2469
2217
|
});
|
|
2470
2218
|
deleteStalePaths(outDir, result.deletedPaths);
|
|
2471
2219
|
for (const { relativePath, content, ifAbsent } of result.filesToWrite) {
|
|
2472
|
-
ctx.emitFile(resolve(outDir, relativePath), content, ifAbsent ? {
|
|
2473
|
-
ifAbsent: true
|
|
2474
|
-
} : void 0);
|
|
2220
|
+
ctx.emitFile(resolve(outDir, relativePath), content, ifAbsent ? { ifAbsent: true } : void 0);
|
|
2475
2221
|
}
|
|
2476
2222
|
writeManifest(manifestPath, result.manifest);
|
|
2477
2223
|
}
|
|
2478
|
-
__name(runCSharpCodegen, "runCSharpCodegen");
|
|
2479
2224
|
function referencedOpModels(root, modelIndex) {
|
|
2480
2225
|
const seeds = [];
|
|
2481
|
-
const addParamSource =
|
|
2226
|
+
const addParamSource = (source) => {
|
|
2482
2227
|
if (!source) return;
|
|
2483
2228
|
if (source.kind === "params") seeds.push(...source.nodes.map((n) => n.type));
|
|
2484
|
-
else if (source.kind === "ref") seeds.push({
|
|
2485
|
-
kind: "ref",
|
|
2486
|
-
name: source.name
|
|
2487
|
-
});
|
|
2229
|
+
else if (source.kind === "ref") seeds.push({ kind: "ref", name: source.name });
|
|
2488
2230
|
else seeds.push(source.node);
|
|
2489
|
-
}
|
|
2231
|
+
};
|
|
2490
2232
|
for (const route of root.routes) {
|
|
2491
2233
|
addParamSource(route.params);
|
|
2492
2234
|
for (const op of route.operations) {
|
|
@@ -2501,7 +2243,6 @@ function referencedOpModels(root, modelIndex) {
|
|
|
2501
2243
|
}
|
|
2502
2244
|
return collectTransitiveModelRefs(seeds, modelIndex);
|
|
2503
2245
|
}
|
|
2504
|
-
__name(referencedOpModels, "referencedOpModels");
|
|
2505
2246
|
function referencedModelNames(root) {
|
|
2506
2247
|
const refs = /* @__PURE__ */ new Set();
|
|
2507
2248
|
for (const model of root.models) {
|
|
@@ -2511,7 +2252,6 @@ function referencedModelNames(root) {
|
|
|
2511
2252
|
}
|
|
2512
2253
|
return refs;
|
|
2513
2254
|
}
|
|
2514
|
-
__name(referencedModelNames, "referencedModelNames");
|
|
2515
2255
|
function readManifest(manifestPath) {
|
|
2516
2256
|
if (!existsSync(manifestPath)) return emptyIncrementalManifest(CSHARP_CODEGEN_VERSION);
|
|
2517
2257
|
try {
|
|
@@ -2520,26 +2260,20 @@ function readManifest(manifestPath) {
|
|
|
2520
2260
|
return emptyIncrementalManifest(CSHARP_CODEGEN_VERSION);
|
|
2521
2261
|
}
|
|
2522
2262
|
}
|
|
2523
|
-
__name(readManifest, "readManifest");
|
|
2524
2263
|
function writeManifest(manifestPath, manifest) {
|
|
2525
2264
|
try {
|
|
2526
|
-
mkdirSync(dirname(manifestPath), {
|
|
2527
|
-
recursive: true
|
|
2528
|
-
});
|
|
2265
|
+
mkdirSync(dirname(manifestPath), { recursive: true });
|
|
2529
2266
|
writeFileSync(manifestPath, serializeIncrementalManifest(manifest), "utf-8");
|
|
2530
2267
|
} catch {
|
|
2531
2268
|
}
|
|
2532
2269
|
}
|
|
2533
|
-
__name(writeManifest, "writeManifest");
|
|
2534
2270
|
function deleteStalePaths(outDir, relPaths) {
|
|
2535
2271
|
if (relPaths.length === 0) return;
|
|
2536
2272
|
const removedDirs = /* @__PURE__ */ new Set();
|
|
2537
2273
|
for (const rel of relPaths) {
|
|
2538
2274
|
const abs = resolve(outDir, rel);
|
|
2539
2275
|
if (existsSync(abs)) {
|
|
2540
|
-
rmSync(abs, {
|
|
2541
|
-
force: true
|
|
2542
|
-
});
|
|
2276
|
+
rmSync(abs, { force: true });
|
|
2543
2277
|
removedDirs.add(join(abs, ".."));
|
|
2544
2278
|
}
|
|
2545
2279
|
}
|
|
@@ -2559,7 +2293,6 @@ function deleteStalePaths(outDir, relPaths) {
|
|
|
2559
2293
|
}
|
|
2560
2294
|
}
|
|
2561
2295
|
}
|
|
2562
|
-
__name(deleteStalePaths, "deleteStalePaths");
|
|
2563
2296
|
export {
|
|
2564
2297
|
CSHARP_CODEGEN_VERSION,
|
|
2565
2298
|
assertValidConfig,
|