@typespec/http-server-csharp 0.58.0-alpha.9-dev.0 → 0.58.0-dev.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.
Files changed (46) hide show
  1. package/README.md +69 -6
  2. package/dist/src/cli/cli.js +92 -43
  3. package/dist/src/cli/cli.js.map +1 -1
  4. package/dist/src/lib/attributes.d.ts.map +1 -1
  5. package/dist/src/lib/attributes.js +65 -31
  6. package/dist/src/lib/attributes.js.map +1 -1
  7. package/dist/src/lib/boilerplate.d.ts +1 -1
  8. package/dist/src/lib/boilerplate.d.ts.map +1 -1
  9. package/dist/src/lib/boilerplate.js +153 -31
  10. package/dist/src/lib/boilerplate.js.map +1 -1
  11. package/dist/src/lib/doc.d.ts +5 -0
  12. package/dist/src/lib/doc.d.ts.map +1 -0
  13. package/dist/src/lib/doc.js +237 -0
  14. package/dist/src/lib/doc.js.map +1 -0
  15. package/dist/src/lib/interfaces.d.ts +48 -4
  16. package/dist/src/lib/interfaces.d.ts.map +1 -1
  17. package/dist/src/lib/interfaces.js +89 -28
  18. package/dist/src/lib/interfaces.js.map +1 -1
  19. package/dist/src/lib/lib.d.ts +32 -3
  20. package/dist/src/lib/lib.d.ts.map +1 -1
  21. package/dist/src/lib/lib.js +57 -2
  22. package/dist/src/lib/lib.js.map +1 -1
  23. package/dist/src/lib/project.d.ts +5 -0
  24. package/dist/src/lib/project.d.ts.map +1 -0
  25. package/dist/src/lib/project.js +101 -0
  26. package/dist/src/lib/project.js.map +1 -0
  27. package/dist/src/lib/scaffolding.d.ts +7 -5
  28. package/dist/src/lib/scaffolding.d.ts.map +1 -1
  29. package/dist/src/lib/scaffolding.js +113 -40
  30. package/dist/src/lib/scaffolding.js.map +1 -1
  31. package/dist/src/lib/service.d.ts.map +1 -1
  32. package/dist/src/lib/service.js +496 -587
  33. package/dist/src/lib/service.js.map +1 -1
  34. package/dist/src/lib/type-helpers.d.ts +5 -1
  35. package/dist/src/lib/type-helpers.d.ts.map +1 -1
  36. package/dist/src/lib/type-helpers.js +32 -3
  37. package/dist/src/lib/type-helpers.js.map +1 -1
  38. package/dist/src/lib/utils.d.ts +79 -7
  39. package/dist/src/lib/utils.d.ts.map +1 -1
  40. package/dist/src/lib/utils.js +971 -36
  41. package/dist/src/lib/utils.js.map +1 -1
  42. package/package.json +39 -26
  43. package/dist/src/lib/testing/index.d.ts +0 -3
  44. package/dist/src/lib/testing/index.d.ts.map +0 -1
  45. package/dist/src/lib/testing/index.js +0 -7
  46. package/dist/src/lib/testing/index.js.map +0 -1
@@ -1,10 +1,14 @@
1
- import { NoTarget, getFriendlyName, isNullType, isNumericType, isTemplateInstance, isUnknownType, isVoidType, } from "@typespec/compiler";
2
- import { StringBuilder } from "@typespec/compiler/emitter-framework";
3
- import { Visibility, createMetadataInfo, isBody, isBodyRoot, isMetadata, isStatusCode, } from "@typespec/http";
1
+ import { StringBuilder, code, } from "@typespec/asset-emitter";
2
+ import { NoTarget, getFriendlyName, getMinValue, isArrayModelType, isErrorModel, isNullType, isNumericType, isTemplateInstance, isUnknownType, isVoidType, resolveCompilerOptions, resolvePath, serializeValueAsJson, } from "@typespec/compiler";
3
+ import { $ } from "@typespec/compiler/typekit";
4
+ import { Visibility, createMetadataInfo, getHeaderFieldName, isBody, isBodyRoot, isHeader, isMetadata, isPathParam, isQueryParam, isStatusCode, } from "@typespec/http";
5
+ import { getUniqueItems } from "@typespec/json-schema";
4
6
  import { camelCase, pascalCase } from "change-case";
7
+ import { createServer } from "net";
5
8
  import { getAttributes } from "./attributes.js";
6
- import { BooleanValue, CSharpType, NameCasingType, NullValue, NumericValue, StringValue, } from "./interfaces.js";
7
- import { reportDiagnostic } from "./lib.js";
9
+ import { BooleanValue, CSharpCollectionType, CSharpType, CollectionType, NameCasingType, NullValue, NumericValue, StringValue, checkOrAddNamespaceToScope, } from "./interfaces.js";
10
+ import { CSharpServiceOptions, reportDiagnostic } from "./lib.js";
11
+ import { getDoubleType, getEnumType } from "./type-helpers.js";
8
12
  const _scalars = new Map();
9
13
  export function getCSharpTypeForScalar(program, scalar) {
10
14
  if (_scalars.has(scalar))
@@ -21,7 +25,7 @@ export function getCSharpTypeForScalar(program, scalar) {
21
25
  target: scalar,
22
26
  });
23
27
  const result = new CSharpType({
24
- name: "Object",
28
+ name: "object",
25
29
  namespace: "System",
26
30
  isBuiltIn: true,
27
31
  isValueType: false,
@@ -31,9 +35,17 @@ export function getCSharpTypeForScalar(program, scalar) {
31
35
  }
32
36
  export const UnknownType = new CSharpType({
33
37
  name: "JsonNode",
34
- namespace: "System.Text.Json",
38
+ namespace: "System.Text.Json.Nodes",
39
+ isValueType: false,
40
+ isBuiltIn: false,
41
+ isClass: true,
42
+ });
43
+ export const RecordType = new CSharpType({
44
+ name: "JsonObject",
45
+ namespace: "System.Text.Json.Nodes",
46
+ isBuiltIn: false,
35
47
  isValueType: false,
36
- isBuiltIn: true,
48
+ isClass: true,
37
49
  });
38
50
  export function getCSharpType(program, type, namespace) {
39
51
  const known = getKnownType(program, type);
@@ -54,8 +66,6 @@ export function getCSharpType(program, type, namespace) {
54
66
  return { type: standardScalars.get("numeric"), value: new NumericValue(enumValue) };
55
67
  case "Intrinsic":
56
68
  return getCSharpTypeForIntrinsic(program, type);
57
- case "Object":
58
- return { type: UnknownType };
59
69
  case "ModelProperty":
60
70
  return getCSharpType(program, type.type, namespace);
61
71
  case "Scalar":
@@ -79,18 +89,21 @@ export function getCSharpType(program, type, namespace) {
79
89
  return {
80
90
  type: new CSharpType({
81
91
  name: ensureCSharpIdentifier(program, type, type.name, NameCasingType.Class),
82
- namespace: namespace || "Models",
92
+ namespace: `${namespace}`,
83
93
  isBuiltIn: false,
84
94
  isValueType: false,
95
+ isClass: true,
85
96
  }),
86
97
  };
87
98
  case "Enum":
99
+ if (getEnumType(type) === "double")
100
+ return { type: getDoubleType() };
88
101
  return {
89
102
  type: new CSharpType({
90
103
  name: ensureCSharpIdentifier(program, type, type.name, NameCasingType.Class),
91
- namespace: `${namespace}.Models`,
104
+ namespace: `${namespace}`,
92
105
  isBuiltIn: false,
93
- isValueType: false,
106
+ isValueType: true,
94
107
  }),
95
108
  };
96
109
  case "Model":
@@ -99,15 +112,32 @@ export function getCSharpType(program, type, namespace) {
99
112
  if (resolvedItem === undefined)
100
113
  return undefined;
101
114
  const { type: itemType, value: _ } = resolvedItem;
115
+ const uniqueItems = getUniqueItems(program, type);
116
+ const isByte = ["byte", "SByte"].includes(itemType.name);
117
+ const collectionType = CSharpServiceOptions.getInstance().collectionType;
118
+ const returnTypeCollection = uniqueItems
119
+ ? CollectionType.ISet
120
+ : isByte
121
+ ? CollectionType.Array
122
+ : collectionType;
123
+ const returnType = returnTypeCollection === CollectionType.Array
124
+ ? `${itemType.name}[]`
125
+ : `${returnTypeCollection}<${itemType.name}>`;
102
126
  return {
103
- type: new CSharpType({
104
- name: `${itemType.name}[]`,
127
+ type: new CSharpCollectionType({
128
+ name: returnType,
105
129
  namespace: itemType.namespace,
106
130
  isBuiltIn: itemType.isBuiltIn,
107
131
  isValueType: false,
108
- }),
132
+ isClass: itemType.isClass,
133
+ isCollection: true,
134
+ }, returnTypeCollection, itemType.name),
109
135
  };
110
136
  }
137
+ if (isRecord(type))
138
+ return {
139
+ type: RecordType,
140
+ };
111
141
  let name = type.name;
112
142
  if (isTemplateInstance(type)) {
113
143
  name = getModelInstantiationName(program, type, name);
@@ -115,15 +145,38 @@ export function getCSharpType(program, type, namespace) {
115
145
  return {
116
146
  type: new CSharpType({
117
147
  name: ensureCSharpIdentifier(program, type, name, NameCasingType.Class),
118
- namespace: `${namespace}.Models`,
148
+ namespace: `${namespace}`,
119
149
  isBuiltIn: false,
120
150
  isValueType: false,
151
+ isClass: true,
121
152
  }),
122
153
  };
123
154
  default:
124
155
  return undefined;
125
156
  }
126
157
  }
158
+ export function resolveReferenceFromScopes(targetDeclaration, declarationScopes, referenceScopes) {
159
+ function getSourceFile(scopes) {
160
+ for (const scope of scopes) {
161
+ if (scope.kind === "sourceFile") {
162
+ return { scope: scope, file: scope.sourceFile };
163
+ }
164
+ }
165
+ return undefined;
166
+ }
167
+ const decl = getSourceFile(declarationScopes);
168
+ const ref = getSourceFile(referenceScopes);
169
+ if (targetDeclaration.name && decl) {
170
+ const declNs = decl.file.meta["ResolvedNamespace"];
171
+ if (!ref)
172
+ return declNs ? `${declNs}.${targetDeclaration.name} ` : undefined;
173
+ if (checkOrAddNamespaceToScope(declNs, ref.scope)) {
174
+ return targetDeclaration.name;
175
+ }
176
+ return declNs ? `${declNs}.${targetDeclaration.name} ` : undefined;
177
+ }
178
+ return undefined;
179
+ }
127
180
  export function coalesceTypes(program, types, namespace) {
128
181
  const visited = new Map();
129
182
  let candidateType = undefined;
@@ -356,27 +409,33 @@ export function isValueType(program, type) {
356
409
  export function formatComment(text, lineLength = 76, lineEnd = "\n") {
357
410
  function getNextLine(target) {
358
411
  for (let i = lineLength - 1; i > 0; i--) {
359
- if ([" ", ".", "?", ",", ";"].includes(target.charAt(i))) {
360
- return `/// ${text.substring(0, i).replaceAll("\n", " ")}`;
412
+ if ([" ", ";"].includes(target.charAt(i))) {
413
+ return `${target.substring(0, i)}`;
414
+ }
415
+ }
416
+ for (let i = lineLength - 1; i < target.length; i++) {
417
+ if ([" ", ";"].includes(target.charAt(i))) {
418
+ return `${target.substring(0, i)}`;
361
419
  }
362
420
  }
363
- return `/// ${text.substring(0, lineLength)}`;
421
+ return `${target.substring(0, lineLength)}`;
364
422
  }
365
- let remaining = text;
423
+ let remaining = text.replaceAll("\n", " ");
366
424
  const lines = [];
367
425
  while (remaining.length > lineLength) {
368
426
  const currentLine = getNextLine(remaining);
369
427
  remaining =
370
428
  remaining.length > currentLine.length ? remaining.substring(currentLine.length + 1) : "";
371
- lines.push(currentLine);
429
+ lines.push(`/// ${currentLine}`);
372
430
  }
373
431
  if (remaining.length > 0)
374
432
  lines.push(`/// ${remaining}`);
375
433
  return `///<summary>${lineEnd}${lines.join(lineEnd)}${lineEnd}///</summary>`;
376
434
  }
377
- export function getCSharpIdentifier(name, context = NameCasingType.Class) {
435
+ export function getCSharpIdentifier(name, context = NameCasingType.Class, checkReserved = true) {
378
436
  if (name === undefined)
379
437
  return "Placeholder";
438
+ name = replaceCSharpReservedWord(name, context);
380
439
  switch (context) {
381
440
  case NameCasingType.Namespace:
382
441
  const parts = [];
@@ -393,6 +452,7 @@ export function getCSharpIdentifier(name, context = NameCasingType.Class) {
393
452
  }
394
453
  export function ensureCSharpIdentifier(program, target, name, context = NameCasingType.Class) {
395
454
  let location = "";
455
+ let includeDot = false;
396
456
  switch (target.kind) {
397
457
  case "Enum":
398
458
  location = `enum ${target.name}`;
@@ -426,11 +486,9 @@ export function ensureCSharpIdentifier(program, target, name, context = NameCasi
426
486
  case "Namespace":
427
487
  location = `namespace ${target.name}`;
428
488
  let invalid = false;
429
- const nsName = new StringBuilder();
430
489
  for (const part of name.split(".")) {
431
490
  if (!isValidCSharpIdentifier(part)) {
432
491
  invalid = true;
433
- nsName.pushLiteralSegment(transformInvalidIdentifier(part));
434
492
  }
435
493
  }
436
494
  if (invalid) {
@@ -439,9 +497,9 @@ export function ensureCSharpIdentifier(program, target, name, context = NameCasi
439
497
  format: { identifier: name, location: location },
440
498
  target: target.node ?? NoTarget,
441
499
  });
442
- return nsName.segments.join(".");
443
500
  }
444
- return name;
501
+ includeDot = true;
502
+ break;
445
503
  case "Operation": {
446
504
  const parent = target.interface
447
505
  ? `interface ${target.interface.name}`
@@ -453,15 +511,11 @@ export function ensureCSharpIdentifier(program, target, name, context = NameCasi
453
511
  location = `union ${target.name}`;
454
512
  break;
455
513
  case "UnionVariant": {
456
- if (target.node !== undefined) {
457
- const parent = program.checker.getTypeForNode(target.node.parent);
458
- if (parent?.kind === "Union")
459
- location = `variant ${String(target.name)} in union ${parent?.name}`;
460
- }
514
+ location = `variant ${String(target.name)} in union ${target.union.name}`;
461
515
  break;
462
516
  }
463
517
  }
464
- if (!isValidCSharpIdentifier(name)) {
518
+ if (!isValidCSharpIdentifier(name, includeDot)) {
465
519
  reportDiagnostic(program, {
466
520
  code: "invalid-identifier",
467
521
  format: { identifier: name, location: location },
@@ -474,6 +528,23 @@ export function ensureCSharpIdentifier(program, target, name, context = NameCasi
474
528
  export function getModelAttributes(program, entity, cSharpName) {
475
529
  return getAttributes(program, entity, cSharpName);
476
530
  }
531
+ export function getModelDeclarationName(program, model, defaultSuffix) {
532
+ if (model.name !== null && model.name.length > 0) {
533
+ return ensureCSharpIdentifier(program, model, model.name, NameCasingType.Class);
534
+ }
535
+ if (model.sourceModel && model.sourceModel.name && model.sourceModel.name.length > 0) {
536
+ return ensureCSharpIdentifier(program, model, `${model.sourceModel.name}${defaultSuffix}`, NameCasingType.Class);
537
+ }
538
+ if (model.sourceModels.length > 0) {
539
+ const sourceNames = model.sourceModels
540
+ .filter((m) => m.model.name !== undefined && m.model.name.length > 0)
541
+ .flatMap((m) => ensureCSharpIdentifier(program, model, m.model.name, NameCasingType.Class));
542
+ if (sourceNames.length > 0) {
543
+ return `${sourceNames.join()}${defaultSuffix}`;
544
+ }
545
+ }
546
+ return `Model${defaultSuffix}`;
547
+ }
477
548
  export function getModelInstantiationName(program, model, name) {
478
549
  const friendlyName = getFriendlyName(program, model);
479
550
  if (friendlyName && friendlyName.length > 0)
@@ -563,12 +634,16 @@ export class HttpMetadata {
563
634
  });
564
635
  switch (responseType.kind) {
565
636
  case "Model":
637
+ if (responseType.indexer && responseType.indexer.key.name !== "string")
638
+ return responseType;
639
+ if (isRecord(responseType))
640
+ return responseType;
566
641
  const bodyProp = new ModelInfo().filterAllProperties(program, responseType, (p) => isBody(program, p) || isBodyRoot(program, p));
567
642
  if (bodyProp !== undefined)
568
643
  return metaInfo.getEffectivePayloadType(bodyProp.type, Visibility.Read);
569
644
  const anyProp = new ModelInfo().filterAllProperties(program, responseType, (p) => !isMetadata(program, p) && !isStatusCode(program, p));
570
645
  if (anyProp === undefined)
571
- return program.checker.voidType;
646
+ return $(program).intrinsic.void;
572
647
  if (responseType.name === "") {
573
648
  return metaInfo.getEffectivePayloadType(responseType, Visibility.Read);
574
649
  }
@@ -615,8 +690,148 @@ export async function ensureCleanDirectory(program, targetPath) {
615
690
  catch { }
616
691
  await program.host.mkdirp(targetPath);
617
692
  }
618
- export function isValidCSharpIdentifier(identifier) {
619
- return identifier?.match(/^[A-Za-z_][\w]*$/) !== null;
693
+ export function isValidCSharpIdentifier(identifier, isNamespace = false) {
694
+ if (!isNamespace)
695
+ return identifier?.match(/^[A-Za-z_][\w]*$/) !== null;
696
+ return identifier?.match(/^[A-Za-z_][\w.]*$/) !== null;
697
+ }
698
+ export function replaceCSharpReservedWord(identifier, context) {
699
+ function generateReplacement(input) {
700
+ return [input, `${pascalCase(input)}Name`];
701
+ }
702
+ const contextualWords = [
703
+ "add",
704
+ "allows",
705
+ "alias",
706
+ "and",
707
+ "ascending",
708
+ "args",
709
+ "async",
710
+ "await",
711
+ "by",
712
+ "descending",
713
+ "dynamic",
714
+ "equals",
715
+ "field",
716
+ "file",
717
+ "from",
718
+ "get",
719
+ "global",
720
+ "group",
721
+ "init",
722
+ "into",
723
+ "join",
724
+ "let",
725
+ "managed",
726
+ "nameof",
727
+ "nint",
728
+ "not",
729
+ "notnull",
730
+ "nuint",
731
+ "on",
732
+ "or",
733
+ "orderby",
734
+ "partial",
735
+ "record",
736
+ "remove",
737
+ "required",
738
+ "scoped",
739
+ "select",
740
+ "set",
741
+ "unmanaged",
742
+ "value",
743
+ "var",
744
+ "when",
745
+ "where",
746
+ "with",
747
+ "yield",
748
+ ];
749
+ const reservedWords = [
750
+ "abstract",
751
+ "as",
752
+ "base",
753
+ "bool",
754
+ "boolean",
755
+ "break",
756
+ "byte",
757
+ "case",
758
+ "catch",
759
+ "char",
760
+ "checked",
761
+ "class",
762
+ "const",
763
+ "continue",
764
+ "decimal",
765
+ "default",
766
+ "do",
767
+ "double",
768
+ "else",
769
+ "enum",
770
+ "event",
771
+ "explicit",
772
+ "extern",
773
+ "false",
774
+ "finally",
775
+ "fixed",
776
+ "float",
777
+ "for",
778
+ "foreach",
779
+ "goto",
780
+ "if",
781
+ "implicit",
782
+ "in",
783
+ "int",
784
+ "interface",
785
+ "internal",
786
+ "is",
787
+ "lock",
788
+ "long",
789
+ "namespace",
790
+ "new",
791
+ "null",
792
+ "object",
793
+ "operator",
794
+ "out",
795
+ "override",
796
+ "params",
797
+ "private",
798
+ "protected",
799
+ "public",
800
+ "readonly",
801
+ "ref",
802
+ "return",
803
+ "sbyte",
804
+ "sealed",
805
+ "short",
806
+ "sizeof",
807
+ "stackalloc",
808
+ "static",
809
+ "string",
810
+ "struct",
811
+ "switch",
812
+ "this",
813
+ "throw",
814
+ "true",
815
+ "try",
816
+ "type",
817
+ "typeof",
818
+ "uint",
819
+ "ulong",
820
+ "unchecked",
821
+ "unsafe",
822
+ "ushort",
823
+ "using",
824
+ "virtual",
825
+ "void",
826
+ "volatile",
827
+ "while",
828
+ ];
829
+ const reserved = new Map(reservedWords.concat(contextualWords).map((w) => generateReplacement(w)));
830
+ const check = reserved.get(identifier.toLowerCase());
831
+ if (check !== undefined) {
832
+ return getCSharpIdentifier(check, context, false);
833
+ }
834
+ return identifier;
620
835
  }
621
836
  export function getValidChar(target, position) {
622
837
  if (position === 0) {
@@ -642,4 +857,724 @@ export function getCSharpStatusCode(entry) {
642
857
  return undefined;
643
858
  }
644
859
  }
860
+ /**
861
+ * Returns the full return statement for a controller action based on the HTTP status code.
862
+ * Maps well-known status codes to their idiomatic ASP.NET Core ControllerBase methods,
863
+ * and falls back to `StatusCode(code, ...)` for all other numeric codes.
864
+ */
865
+ export function getControllerReturnStatement(status, hasValue) {
866
+ if (typeof status === "number") {
867
+ switch (status) {
868
+ case 200:
869
+ return hasValue ? "return Ok(result);" : "return Ok();";
870
+ case 202:
871
+ return hasValue ? "return Accepted(result);" : "return Accepted();";
872
+ case 204:
873
+ return "return NoContent();";
874
+ default:
875
+ return hasValue ? `return StatusCode(${status}, result);` : `return StatusCode(${status});`;
876
+ }
877
+ }
878
+ // Fallback for ranges and "*"
879
+ return hasValue ? "return Ok(result);" : "return Ok();";
880
+ }
881
+ export function isEmptyResponseModel(program, model) {
882
+ if (model.kind !== "Model")
883
+ return false;
884
+ if (model.properties.size === 0)
885
+ return true;
886
+ return (model.properties.size === 1 &&
887
+ isStatusCode(program, [...model.properties.values()][0]) &&
888
+ !isErrorModel(program, model));
889
+ }
890
+ export function isContentTypeHeader(program, parameter) {
891
+ return (isHeader(program, parameter) &&
892
+ (parameter.name === "contentType" || getHeaderFieldName(program, parameter) === "Content-type"));
893
+ }
894
+ export function isValidParameter(program, parameter) {
895
+ return (!isContentTypeHeader(program, parameter) &&
896
+ (parameter.type.kind !== "Intrinsic" || parameter.type.name !== "never") &&
897
+ parameter.model?.name === "");
898
+ }
899
+ /** Determine whether the given parameter is http metadata */
900
+ export function isHttpMetadata(program, property) {
901
+ return (isPathParam(program, property) || isHeader(program, property) || isQueryParam(program, property));
902
+ }
903
+ export function getBusinessLogicCallParameters(parameters) {
904
+ const builder = new StringBuilder();
905
+ const blParameters = parameters.filter((p) => p.operationKind === "BusinessLogic" || p.operationKind === "All");
906
+ let i = 0;
907
+ for (const param of blParameters) {
908
+ builder.push(code `${getBusinessLogicCallParameter(param)}${++i < blParameters.length ? ", " : ""}`);
909
+ }
910
+ return builder.reduce();
911
+ }
912
+ export function getBusinessLogicDeclParameters(parameters) {
913
+ const builder = new StringBuilder();
914
+ const blParameters = parameters.filter((p) => p.operationKind === "BusinessLogic" || p.operationKind === "All");
915
+ let i = 0;
916
+ for (const param of blParameters) {
917
+ builder.push(code `${getBusinessLogicSignatureParameter(param)}${++i < blParameters.length ? ", " : ""}`);
918
+ }
919
+ return builder.reduce();
920
+ }
921
+ export function getHttpDeclParameters(parameters) {
922
+ const builder = new StringBuilder();
923
+ const blParameters = parameters.filter((p) => p.operationKind === "Http" || p.operationKind === "All");
924
+ let i = 0;
925
+ for (const param of blParameters) {
926
+ builder.push(code `${getHttpSignatureParameter(param)}${++i < blParameters.length ? ", " : ""}`);
927
+ }
928
+ return builder.reduce();
929
+ }
930
+ export function getBusinessLogicCallParameter(param) {
931
+ const builder = new StringBuilder();
932
+ builder.push(code `${param.callName}`);
933
+ return builder.reduce();
934
+ }
935
+ export function getBusinessLogicSignatureParameter(param) {
936
+ const builder = new StringBuilder();
937
+ builder.push(code `${param.typeName}${param.optional || param.nullable ? "? " : " "}${param.name}`);
938
+ return builder.reduce();
939
+ }
940
+ export function getHttpSignatureParameter(param) {
941
+ const builder = new StringBuilder();
942
+ builder.push(code `${getHttpParameterDecorator(param)}${getBusinessLogicSignatureParameter(param)}${param.defaultValue === undefined ? "" : code ` = ${typeof param.defaultValue === "boolean" ? code `${param.defaultValue.toString()}` : code `${param.defaultValue}`}`}`);
943
+ return builder.reduce();
944
+ }
945
+ export function getHttpParameterDecorator(parameter) {
946
+ switch (parameter.httpParameterKind) {
947
+ case "query":
948
+ return code `[FromQuery${parameter.httpParameterName ? code `(Name="${parameter.httpParameterName}")` : ""}] `;
949
+ case "header":
950
+ return code `[FromHeader${parameter.httpParameterName ? code `(Name="${parameter.httpParameterName}")` : ""}] `;
951
+ default:
952
+ return "";
953
+ }
954
+ }
955
+ export function getParameterKind(parameter) {
956
+ switch (parameter.type) {
957
+ case "path":
958
+ return "path";
959
+ case "cookie":
960
+ case "header":
961
+ return "header";
962
+ case "query":
963
+ return "query";
964
+ }
965
+ }
966
+ export function canHaveDefault(program, type) {
967
+ switch (type.kind) {
968
+ case "Boolean":
969
+ case "EnumMember":
970
+ case "Enum":
971
+ case "Number":
972
+ case "String":
973
+ case "Scalar":
974
+ case "StringTemplate":
975
+ return true;
976
+ case "ModelProperty":
977
+ return canHaveDefault(program, type.type);
978
+ default:
979
+ return false;
980
+ }
981
+ }
982
+ export class CSharpOperationHelpers {
983
+ constructor(inEmitter) {
984
+ this.emitter = inEmitter;
985
+ this.#anonymousModels = new Map();
986
+ this.#opCache = new Map();
987
+ }
988
+ emitter;
989
+ #anonymousModels;
990
+ #opCache;
991
+ getResponse(program, operation) {
992
+ return new CSharpType({
993
+ name: "void",
994
+ namespace: "System",
995
+ isBuiltIn: true,
996
+ isValueType: true,
997
+ });
998
+ }
999
+ getParameters(program, operation) {
1000
+ function safeConcat(...names) {
1001
+ return names
1002
+ .filter((n) => n !== undefined && n !== null && n.length > 0)
1003
+ .flatMap((s) => getCSharpIdentifier(s, NameCasingType.Class))
1004
+ .join();
1005
+ }
1006
+ const cached = this.#opCache.get(operation.operation);
1007
+ if (cached)
1008
+ return cached;
1009
+ const bodyParam = operation.parameters.body;
1010
+ const isExplicitBodyParam = bodyParam?.property !== undefined;
1011
+ const result = [];
1012
+ if (!cached && operation.verb === "get" && operation.parameters.body !== undefined) {
1013
+ reportDiagnostic(program, {
1014
+ code: "get-request-body",
1015
+ target: operation.operation,
1016
+ format: {},
1017
+ });
1018
+ this.#opCache.set(operation.operation, result);
1019
+ return result;
1020
+ }
1021
+ const validParams = operation.parameters.parameters.filter((p) => isValidParameter(program, p.param));
1022
+ const requiredParams = validParams.filter((p) => p.type === "path" || (!p.param.optional && p.param.defaultValue === undefined));
1023
+ const optionalParams = validParams.filter((p) => p.type !== "path" && (p.param.optional || p.param.defaultValue !== undefined));
1024
+ for (const parameter of requiredParams) {
1025
+ let { typeReference: paramType, defaultValue: paramValue } = this.getTypeInfo(program, parameter.param.type);
1026
+ // cSharp does not allow array defaults in operation parameters
1027
+ if (!canHaveDefault(program, parameter.param)) {
1028
+ paramValue = undefined;
1029
+ }
1030
+ const paramName = ensureCSharpIdentifier(program, parameter.param, parameter.param.name, NameCasingType.Parameter);
1031
+ result.push({
1032
+ isExplicitBody: false,
1033
+ name: paramName,
1034
+ callName: paramName,
1035
+ optional: false,
1036
+ typeName: paramType,
1037
+ defaultValue: paramValue,
1038
+ httpParameterKind: getParameterKind(parameter),
1039
+ httpParameterName: parameter.name,
1040
+ nullable: false,
1041
+ operationKind: "All",
1042
+ });
1043
+ }
1044
+ const overrideParameters = getExplicitBodyParameters(program, operation);
1045
+ if (overrideParameters !== undefined) {
1046
+ for (const overrideParam of overrideParameters) {
1047
+ result.push(overrideParam);
1048
+ }
1049
+ }
1050
+ else if (bodyParam !== undefined && isExplicitBodyParam) {
1051
+ let { typeReference: bodyType, defaultValue: bodyValue, nullableType: isNullable, } = this.getTypeInfo(program, bodyParam.type);
1052
+ if (!canHaveDefault(program, bodyParam.type)) {
1053
+ bodyValue = undefined;
1054
+ }
1055
+ result.push({
1056
+ isExplicitBody: true,
1057
+ httpParameterKind: "body",
1058
+ name: "body",
1059
+ callName: "body",
1060
+ typeName: bodyType,
1061
+ nullable: isNullable,
1062
+ defaultValue: bodyValue,
1063
+ optional: bodyParam.property?.optional ?? false,
1064
+ operationKind: "All",
1065
+ });
1066
+ }
1067
+ else if (bodyParam !== undefined) {
1068
+ switch (bodyParam.type.kind) {
1069
+ case "Model":
1070
+ let tsBody = bodyParam.type;
1071
+ if (!bodyParam.type.name) {
1072
+ tsBody = program.checker.cloneType(bodyParam.type, {
1073
+ name: safeConcat(operation.operation.interface?.name, operation.operation.name, "Request"),
1074
+ });
1075
+ }
1076
+ const { typeReference: bodyType } = this.getTypeInfo(program, tsBody);
1077
+ const bodyName = ensureCSharpIdentifier(program, bodyParam.type, "body", NameCasingType.Parameter);
1078
+ result.push({
1079
+ isExplicitBody: false,
1080
+ httpParameterKind: "body",
1081
+ name: bodyName,
1082
+ callName: bodyName,
1083
+ typeName: bodyType,
1084
+ nullable: false,
1085
+ defaultValue: undefined,
1086
+ optional: false,
1087
+ operationKind: "Http",
1088
+ });
1089
+ for (const [propName, propDef] of bodyParam.type.properties) {
1090
+ let { typeReference: csType, defaultValue: csValue, nullableType: isNullable, } = this.getTypeInfo(program, propDef.type, propDef);
1091
+ // cSharp does not allow array defaults in operation parameters
1092
+ if (!canHaveDefault(program, propDef)) {
1093
+ csValue = undefined;
1094
+ }
1095
+ const paramName = ensureCSharpIdentifier(program, propDef, propName, NameCasingType.Parameter);
1096
+ const refName = ensureCSharpIdentifier(program, propDef, propName, NameCasingType.Property);
1097
+ result.push({
1098
+ isExplicitBody: false,
1099
+ httpParameterKind: "body",
1100
+ name: paramName,
1101
+ callName: `body.${refName}`,
1102
+ typeName: csType,
1103
+ nullable: isNullable,
1104
+ defaultValue: csValue,
1105
+ optional: propDef.optional,
1106
+ operationKind: "BusinessLogic",
1107
+ });
1108
+ }
1109
+ break;
1110
+ case "ModelProperty":
1111
+ {
1112
+ let { typeReference: csType, defaultValue: csValue, nullableType: isNullable, } = this.getTypeInfo(program, bodyParam.type.type, bodyParam.type);
1113
+ if (!canHaveDefault(program, bodyParam.type)) {
1114
+ csValue = undefined;
1115
+ }
1116
+ const optName = ensureCSharpIdentifier(program, bodyParam.type.type, bodyParam.type.name, NameCasingType.Parameter);
1117
+ result.push({
1118
+ isExplicitBody: true,
1119
+ httpParameterKind: "body",
1120
+ name: optName,
1121
+ callName: optName,
1122
+ typeName: csType,
1123
+ nullable: isNullable,
1124
+ defaultValue: csValue,
1125
+ optional: bodyParam.type.optional,
1126
+ operationKind: "All",
1127
+ });
1128
+ }
1129
+ break;
1130
+ default: {
1131
+ let { typeReference: csType, defaultValue: csValue, nullableType: isNullable, } = this.getTypeInfo(program, bodyParam.type);
1132
+ if (!canHaveDefault(program, bodyParam.type)) {
1133
+ csValue = undefined;
1134
+ }
1135
+ result.push({
1136
+ isExplicitBody: true,
1137
+ httpParameterKind: "body",
1138
+ name: "body",
1139
+ callName: "body",
1140
+ typeName: csType,
1141
+ nullable: isNullable,
1142
+ defaultValue: csValue,
1143
+ optional: false,
1144
+ operationKind: "All",
1145
+ });
1146
+ }
1147
+ }
1148
+ }
1149
+ for (const parameter of optionalParams) {
1150
+ const { typeReference: paramType, defaultValue: paramValue, nullableType: isNullable, } = this.getTypeInfo(program, parameter.param.type, parameter.param);
1151
+ const optName = ensureCSharpIdentifier(program, parameter.param, parameter.param.name, NameCasingType.Parameter);
1152
+ result.push({
1153
+ isExplicitBody: false,
1154
+ name: optName,
1155
+ callName: optName,
1156
+ optional: true,
1157
+ typeName: paramType,
1158
+ defaultValue: paramValue,
1159
+ httpParameterKind: getParameterKind(parameter),
1160
+ httpParameterName: parameter.name,
1161
+ nullable: isNullable,
1162
+ operationKind: "All",
1163
+ });
1164
+ }
1165
+ return result;
1166
+ }
1167
+ getDefaultValue(program, tsType, defaultValue) {
1168
+ if (defaultValue === undefined)
1169
+ return undefined;
1170
+ switch (tsType.kind) {
1171
+ case "Enum":
1172
+ if (defaultValue.valueKind === "EnumValue") {
1173
+ const retVal = this.getTypeInfo(program, tsType);
1174
+ return `${retVal.typeReference}.${ensureCSharpIdentifier(program, defaultValue.value, defaultValue.value.name, NameCasingType.Property)}`;
1175
+ }
1176
+ return JSON.stringify(serializeValueAsJson(this.emitter.getProgram(), defaultValue, tsType));
1177
+ case "Union":
1178
+ const { typeReference: typeRef } = this.getUnionInfo(program, tsType);
1179
+ if (defaultValue.valueKind === "StringValue" && isStringEnumType(program, tsType)) {
1180
+ const matches = [...tsType.variants].filter((v) => typeof v[0] === "string" &&
1181
+ v[1].type.kind === "String" &&
1182
+ v[1].type.value === defaultValue.value);
1183
+ if (matches.length === 1) {
1184
+ return `${typeRef}.${ensureCSharpIdentifier(program, matches[0][1], matches[0][0], NameCasingType.Property)}`;
1185
+ }
1186
+ return undefined;
1187
+ }
1188
+ if (defaultValue.valueKind === "StringValue") {
1189
+ return JSON.stringify(serializeValueAsJson(this.emitter.getProgram(), defaultValue, tsType));
1190
+ }
1191
+ return undefined;
1192
+ default:
1193
+ return JSON.stringify(serializeValueAsJson(this.emitter.getProgram(), defaultValue, tsType));
1194
+ }
1195
+ }
1196
+ getTypeInfo(program, tsType, modelProperty) {
1197
+ const myEmitter = this.emitter;
1198
+ function extractStringValue(type, span) {
1199
+ switch (type.kind) {
1200
+ case "String":
1201
+ return type.value;
1202
+ case "Boolean":
1203
+ return `${type.value}`;
1204
+ case "Number":
1205
+ return type.valueAsString;
1206
+ case "StringTemplateSpan":
1207
+ if (type.isInterpolated) {
1208
+ return extractStringValue(type.type, span);
1209
+ }
1210
+ else {
1211
+ return type.type.value;
1212
+ }
1213
+ case "ModelProperty":
1214
+ return extractStringValue(type.type, span);
1215
+ case "EnumMember":
1216
+ if (type.value === undefined)
1217
+ return type.name;
1218
+ if (typeof type.value === "string")
1219
+ return type.value;
1220
+ if (typeof type.value === "number")
1221
+ return `${type.value}`;
1222
+ }
1223
+ reportDiagnostic(myEmitter.getProgram(), {
1224
+ code: "invalid-interpolation",
1225
+ target: span,
1226
+ format: {},
1227
+ });
1228
+ return "";
1229
+ }
1230
+ switch (tsType.kind) {
1231
+ case "String":
1232
+ return {
1233
+ typeReference: code `string`,
1234
+ defaultValue: `"${tsType.value}"`,
1235
+ nullableType: false,
1236
+ };
1237
+ case "StringTemplate":
1238
+ const template = tsType;
1239
+ if (template.stringValue !== undefined)
1240
+ return {
1241
+ typeReference: code `string`,
1242
+ defaultValue: `"${template.stringValue}"`,
1243
+ nullableType: false,
1244
+ };
1245
+ const spanResults = [];
1246
+ for (const span of template.spans) {
1247
+ spanResults.push(extractStringValue(span, span));
1248
+ }
1249
+ return {
1250
+ typeReference: code `string`,
1251
+ defaultValue: `"${spanResults.join("")}"`,
1252
+ nullableType: false,
1253
+ };
1254
+ case "Boolean":
1255
+ return {
1256
+ typeReference: code `bool`,
1257
+ defaultValue: `${tsType.value === true ? true : false}`,
1258
+ nullableType: false,
1259
+ };
1260
+ case "Number":
1261
+ const [type, value] = findNumericType(tsType);
1262
+ return { typeReference: code `${type}`, defaultValue: `${value}`, nullableType: false };
1263
+ case "Tuple":
1264
+ const defaults = [];
1265
+ const [csharpType, isObject] = coalesceTsTypes(program, tsType.values);
1266
+ if (isObject)
1267
+ return { typeReference: "object[]", defaultValue: undefined, nullableType: false };
1268
+ for (const value of tsType.values) {
1269
+ const { defaultValue: itemDefault } = this.getTypeInfo(program, value);
1270
+ defaults.push(itemDefault);
1271
+ }
1272
+ const collectionType = CSharpServiceOptions.getInstance().collectionType;
1273
+ switch (collectionType) {
1274
+ case CollectionType.IEnumerable:
1275
+ return {
1276
+ typeReference: code `IEnumerable<${csharpType.getTypeReference(myEmitter.getContext()?.scope)}>`,
1277
+ defaultValue: `new List<${csharpType.getTypeReference(myEmitter.getContext()?.scope)}> {${defaults.join(", ")}}`,
1278
+ nullableType: csharpType.isNullable,
1279
+ };
1280
+ case CollectionType.Array:
1281
+ default:
1282
+ return {
1283
+ typeReference: code `${csharpType.getTypeReference(myEmitter.getContext()?.scope)}[]`,
1284
+ defaultValue: `[${defaults.join(", ")}]`,
1285
+ nullableType: csharpType.isNullable,
1286
+ };
1287
+ }
1288
+ case "Model":
1289
+ let modelResult;
1290
+ const hasUniqueItems = modelProperty
1291
+ ? getUniqueItems(program, modelProperty) !== undefined
1292
+ : false;
1293
+ const cachedResult = this.#anonymousModels.get(tsType);
1294
+ if (cachedResult && cachedResult.hasUniqueItems === hasUniqueItems) {
1295
+ return cachedResult;
1296
+ }
1297
+ if (isRecord(tsType)) {
1298
+ modelResult = {
1299
+ typeReference: code `${RecordType.getTypeReference(myEmitter.getContext().scope)}`,
1300
+ nullableType: false,
1301
+ hasUniqueItems: hasUniqueItems,
1302
+ };
1303
+ }
1304
+ else if (isArrayModelType(tsType)) {
1305
+ const typeReference = code `${this.emitter.emitTypeReference(tsType.indexer.value)}`;
1306
+ modelResult = isByteType(tsType.indexer.value)
1307
+ ? {
1308
+ typeReference: code `${typeReference}[]`,
1309
+ nullableType: false,
1310
+ hasUniqueItems: hasUniqueItems,
1311
+ }
1312
+ : {
1313
+ typeReference: hasUniqueItems
1314
+ ? code `ISet<${typeReference}>`
1315
+ : code `${this.emitter.emitTypeReference(tsType)}`,
1316
+ nullableType: false,
1317
+ hasUniqueItems: hasUniqueItems,
1318
+ };
1319
+ }
1320
+ else {
1321
+ modelResult = {
1322
+ typeReference: code `${this.emitter.emitTypeReference(tsType, this.emitter.getContext())}`,
1323
+ nullableType: false,
1324
+ hasUniqueItems: hasUniqueItems,
1325
+ };
1326
+ }
1327
+ return modelResult;
1328
+ case "ModelProperty":
1329
+ return this.getTypeInfo(program, tsType.type, tsType);
1330
+ case "Enum":
1331
+ if (getEnumType(tsType) === "double")
1332
+ return { typeReference: getDoubleType().getTypeReference(), nullableType: false };
1333
+ return {
1334
+ typeReference: code `${this.emitter.emitTypeReference(tsType)}`,
1335
+ nullableType: false,
1336
+ };
1337
+ case "EnumMember":
1338
+ if (typeof tsType.value === "number") {
1339
+ const stringValue = tsType.value.toString();
1340
+ if (stringValue.includes(".") || stringValue.includes("e"))
1341
+ return { typeReference: "double", defaultValue: stringValue, nullableType: false };
1342
+ return { typeReference: "int", defaultValue: stringValue, nullableType: false };
1343
+ }
1344
+ if (typeof tsType.value === "string") {
1345
+ const retVal = this.getTypeInfo(program, tsType.enum);
1346
+ retVal.defaultValue = `${retVal.typeReference}.${ensureCSharpIdentifier(program, tsType, tsType.name, NameCasingType.Property)}`;
1347
+ return retVal;
1348
+ }
1349
+ return { typeReference: code `object`, nullableType: false };
1350
+ case "Union":
1351
+ return this.getUnionInfo(program, tsType);
1352
+ case "UnionVariant":
1353
+ if (isStringEnumType(program, tsType.union) &&
1354
+ tsType.type.kind === "String" &&
1355
+ typeof tsType.name === "string") {
1356
+ const retVal = this.getUnionInfo(program, tsType.union);
1357
+ retVal.defaultValue = `${retVal.typeReference}.${ensureCSharpIdentifier(program, tsType, tsType.name, NameCasingType.Property)}`;
1358
+ return retVal;
1359
+ }
1360
+ return this.getTypeInfo(program, tsType.type);
1361
+ default:
1362
+ return {
1363
+ typeReference: code `${this.emitter.emitTypeReference(tsType)}`,
1364
+ nullableType: false,
1365
+ };
1366
+ }
1367
+ }
1368
+ getUnionInfo(program, union) {
1369
+ const propResult = getNonNullableTsType(union);
1370
+ if (propResult === undefined || isStringEnumType(program, union)) {
1371
+ return {
1372
+ typeReference: code `${this.emitter.emitTypeReference(union)}`,
1373
+ nullableType: [...union.variants.values()].some((v) => isNullType(v.type)),
1374
+ };
1375
+ }
1376
+ const candidate = this.getTypeInfo(program, propResult.type);
1377
+ candidate.nullableType = propResult.nullable;
1378
+ return candidate;
1379
+ }
1380
+ }
1381
+ export function getExplicitBodyParameters(program, httpOperation) {
1382
+ if (httpOperation.parameters.body && httpOperation.parameters.body.bodyKind === "multipart") {
1383
+ return [
1384
+ {
1385
+ name: "reader",
1386
+ callName: "reader",
1387
+ nullable: false,
1388
+ optional: false,
1389
+ typeName: "MultipartReader",
1390
+ isExplicitBody: false,
1391
+ httpParameterKind: "body",
1392
+ operationKind: "BusinessLogic",
1393
+ },
1394
+ ];
1395
+ }
1396
+ return undefined;
1397
+ }
1398
+ export function findNumericType(type) {
1399
+ const stringValue = type.valueAsString;
1400
+ if (stringValue.includes(".") || stringValue.includes("e"))
1401
+ return ["double", stringValue];
1402
+ return ["int", stringValue];
1403
+ }
1404
+ export function isStringEnumType(program, union) {
1405
+ const baseType = coalesceUnionTypes(program, union);
1406
+ if (!baseType.isBuiltIn || baseType.name !== "string")
1407
+ return false;
1408
+ return ![...union.variants.values()].some((v) => (v.type.kind === "String" ||
1409
+ v.type.kind === "StringTemplate" ||
1410
+ v.type.kind === "StringTemplateSpan") &&
1411
+ typeof v.name !== "string");
1412
+ }
1413
+ export function coalesceUnionTypes(program, union) {
1414
+ const [result, _] = coalesceTsTypes(program, [...union.variants.values()].flatMap((v) => v.type));
1415
+ return result;
1416
+ }
1417
+ export function getNonNullableTsType(union) {
1418
+ const types = [...union.variants.values()];
1419
+ const nulls = types.flatMap((v) => v.type).filter((t) => isNullType(t));
1420
+ const nonNulls = types.flatMap((v) => v.type).filter((t) => !isNullType(t));
1421
+ if (nonNulls.length === 1)
1422
+ return { type: nonNulls[0], nullable: nulls.length > 0 };
1423
+ return undefined;
1424
+ }
1425
+ export function coalesceTsTypes(program, types) {
1426
+ const defaultValue = [
1427
+ new CSharpType({
1428
+ name: "object",
1429
+ namespace: "System",
1430
+ isBuiltIn: true,
1431
+ isValueType: false,
1432
+ }),
1433
+ true,
1434
+ ];
1435
+ let current = undefined;
1436
+ let nullable = false;
1437
+ for (const type of types) {
1438
+ let candidate;
1439
+ switch (type.kind) {
1440
+ case "Boolean":
1441
+ candidate = new CSharpType({ name: "bool", namespace: "System", isValueType: true });
1442
+ break;
1443
+ case "StringTemplate":
1444
+ case "String":
1445
+ candidate = new CSharpType({ name: "string", namespace: "System", isValueType: false });
1446
+ break;
1447
+ case "Number":
1448
+ const stringValue = type.valueAsString;
1449
+ if (stringValue.includes(".") || stringValue.includes("e")) {
1450
+ candidate = new CSharpType({
1451
+ name: "double",
1452
+ namespace: "System",
1453
+ isValueType: true,
1454
+ });
1455
+ }
1456
+ else {
1457
+ candidate = new CSharpType({ name: "int", namespace: "System", isValueType: true });
1458
+ }
1459
+ break;
1460
+ case "Union":
1461
+ candidate = coalesceUnionTypes(program, type);
1462
+ break;
1463
+ case "Scalar":
1464
+ candidate = getCSharpTypeForScalar(program, type);
1465
+ break;
1466
+ case "Intrinsic":
1467
+ if (isNullType(type)) {
1468
+ nullable = true;
1469
+ candidate = current;
1470
+ }
1471
+ else {
1472
+ return defaultValue;
1473
+ }
1474
+ break;
1475
+ default:
1476
+ return defaultValue;
1477
+ }
1478
+ current = current ?? candidate;
1479
+ if (current === undefined || (candidate !== undefined && !candidate.equals(current)))
1480
+ return defaultValue;
1481
+ }
1482
+ if (current !== undefined && nullable === true)
1483
+ current.isNullable = true;
1484
+ return current === undefined ? defaultValue : [current, false];
1485
+ }
1486
+ export function isRecord(type) {
1487
+ return type.kind === "Model" && type.name === "Record" && type.indexer !== undefined;
1488
+ }
1489
+ export async function getFreePort(minPort, maxPort, tries = 100) {
1490
+ const min = Math.floor(minPort);
1491
+ const max = Math.floor(maxPort);
1492
+ if (tries === 0)
1493
+ return min;
1494
+ const diff = Math.abs(max - min);
1495
+ const port = min + Math.floor(Math.random() * diff);
1496
+ const server = createServer();
1497
+ const free = await checkPort(port);
1498
+ if (free) {
1499
+ return port;
1500
+ }
1501
+ // This seems like a bug? tries-- does nothing?
1502
+ // eslint-disable-next-line no-useless-assignment
1503
+ return await getFreePort(min, max, tries--);
1504
+ async function checkPort(port, timeout = 100) {
1505
+ return new Promise((resolve, _) => {
1506
+ server.on("error", (_) => {
1507
+ server.close();
1508
+ resolve(false);
1509
+ });
1510
+ server.listen(port, async () => {
1511
+ try {
1512
+ setTimeout(() => resolve(true), timeout);
1513
+ }
1514
+ catch (e) {
1515
+ resolve(false);
1516
+ }
1517
+ finally {
1518
+ server.close();
1519
+ }
1520
+ });
1521
+ });
1522
+ }
1523
+ }
1524
+ export async function getOpenApiConfig(program) {
1525
+ const root = program.projectRoot;
1526
+ const [options, _] = await resolveCompilerOptions(program.host, {
1527
+ cwd: root,
1528
+ entrypoint: resolvePath(root, "main.tsp"),
1529
+ });
1530
+ const oaiOptions = options.options !== undefined && Object.keys(options.options).includes("@typespec/openapi3")
1531
+ ? options.options["@typespec/openapi3"]
1532
+ : undefined;
1533
+ return {
1534
+ emitted: options.emit !== undefined && options.emit.includes("@typespec/openapi3"),
1535
+ outputDir: oaiOptions?.["emitter-output-dir"],
1536
+ fileName: oaiOptions?.["output-file"],
1537
+ options: oaiOptions,
1538
+ };
1539
+ }
1540
+ export function getStatusCode(program, model) {
1541
+ const statusCodeProperty = new ModelInfo().filterAllProperties(program, model, (p) => isStatusCode(program, p));
1542
+ if (!statusCodeProperty)
1543
+ return undefined;
1544
+ const { type } = statusCodeProperty;
1545
+ switch (type.kind) {
1546
+ case "Union":
1547
+ return {
1548
+ name: statusCodeProperty.name,
1549
+ value: statusCodeProperty.name,
1550
+ requiresConstructorArgument: true,
1551
+ };
1552
+ case "Number":
1553
+ return {
1554
+ value: type.value,
1555
+ };
1556
+ default:
1557
+ return { value: getMinValue(program, statusCodeProperty) ?? `default` };
1558
+ }
1559
+ }
1560
+ export function isByteType(type) {
1561
+ return type.kind === "Scalar" && ["int8", "uint8"].includes(type.name);
1562
+ }
1563
+ export function getImports(scope, visited) {
1564
+ if (scope === undefined)
1565
+ return [];
1566
+ if (!visited)
1567
+ visited = new Set();
1568
+ if (visited.has(scope))
1569
+ return [];
1570
+ visited.add(scope);
1571
+ switch (scope.kind) {
1572
+ case "namespace":
1573
+ return getImports(scope.parentScope, visited);
1574
+ case "sourceFile":
1575
+ return [...scope.sourceFile.imports.keys()];
1576
+ default:
1577
+ return [];
1578
+ }
1579
+ }
645
1580
  //# sourceMappingURL=utils.js.map