@typespec/http-server-js 0.58.0-alpha.13-dev.3 → 0.58.0-alpha.13-dev.4

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.
@@ -112,7 +112,7 @@ export interface Switch {
112
112
  */
113
113
  export interface Verbatim {
114
114
  kind: "verbatim";
115
- body: Iterable<string>;
115
+ body: Iterable<string> | (() => Iterable<string>);
116
116
  }
117
117
 
118
118
  /**
@@ -380,7 +380,7 @@ export function differentiateTypes(
380
380
  const intrinsics = (categories.Intrinsic as (VoidType | NullType)[]) ?? [];
381
381
 
382
382
  if (literals.length + scalars.length + intrinsics.length === 0) {
383
- return differentiateModelTypes(ctx, module, select(models, cases), renderPropertyName);
383
+ return differentiateModelTypes(ctx, module, select(models, cases), { renderPropertyName });
384
384
  } else {
385
385
  const branches: IfBranch[] = [];
386
386
 
@@ -505,7 +505,7 @@ export function differentiateTypes(
505
505
  branches,
506
506
  else:
507
507
  models.length > 0
508
- ? differentiateModelTypes(ctx, module, select(models, cases), renderPropertyName)
508
+ ? differentiateModelTypes(ctx, module, select(models, cases), { renderPropertyName })
509
509
  : undefined,
510
510
  };
511
511
  }
@@ -589,6 +589,38 @@ function overlaps(range: IntegerRange, other: IntegerRange): boolean {
589
589
  return range[0] <= other[1] && range[1] >= other[0];
590
590
  }
591
591
 
592
+ /**
593
+ * Optional paramters for model differentiation.
594
+ */
595
+ interface DifferentiateModelOptions {
596
+ /**
597
+ * A function that converts a model property reference over the subject to a string.
598
+ *
599
+ * Default: `(prop) => prop.name`
600
+ */
601
+ renderPropertyName?: (prop: ModelProperty) => string;
602
+
603
+ /**
604
+ * A filter function that determines which properties to consider for differentiation.
605
+ *
606
+ * Default: `() => true`
607
+ */
608
+ filter?: (prop: ModelProperty) => boolean;
609
+
610
+ /**
611
+ * The default case to use if no other cases match.
612
+ *
613
+ * Default: undefined.
614
+ */
615
+ else?: CodeTree | undefined;
616
+ }
617
+
618
+ const DEFAULT_DIFFERENTIATE_OPTIONS = {
619
+ renderPropertyName: PROPERTY_ID,
620
+ filter: () => true,
621
+ else: undefined,
622
+ } as const;
623
+
592
624
  /**
593
625
  * Differentiate a set of model types based on their properties. This function returns a CodeTree that will test an input
594
626
  * "subject" and determine which of the cases it matches, executing the corresponding code block.
@@ -602,8 +634,15 @@ export function differentiateModelTypes(
602
634
  ctx: JsContext,
603
635
  module: Module,
604
636
  models: Set<Model>,
605
- renderPropertyName: (prop: ModelProperty) => string = PROPERTY_ID,
637
+ options?: DifferentiateModelOptions,
638
+ ): CodeTree;
639
+ export function differentiateModelTypes(
640
+ ctx: JsContext,
641
+ module: Module,
642
+ models: Set<Model>,
643
+ _options: DifferentiateModelOptions = {},
606
644
  ): CodeTree {
645
+ const options = { ...DEFAULT_DIFFERENTIATE_OPTIONS, ..._options };
607
646
  // Horrible n^2 operation to get the unique properties of all models in the map, but hopefully n is small, so it should
608
647
  // be okay until you have a lot of models to differentiate.
609
648
 
@@ -623,14 +662,14 @@ export function differentiateModelTypes(
623
662
  for (const model of models) {
624
663
  const props = new Set<string>();
625
664
 
626
- for (const prop of getAllProperties(model)) {
665
+ for (const prop of getAllProperties(model).filter(options.filter)) {
627
666
  // Don't consider optional properties for differentiation.
628
667
  if (prop.optional) continue;
629
668
 
630
669
  // Ignore properties that have no parseable name.
631
670
  if (isUnspeakable(prop.name)) continue;
632
671
 
633
- const renderedPropName = renderPropertyName(prop) as RenderedPropertyName;
672
+ const renderedPropName = options.renderPropertyName(prop) as RenderedPropertyName;
634
673
 
635
674
  // CASE - literal value
636
675
 
@@ -716,7 +755,7 @@ export function differentiateModelTypes(
716
755
 
717
756
  const branches: IfBranch[] = [];
718
757
 
719
- let defaultCase: Model | undefined = undefined;
758
+ let defaultCase: CodeTree | undefined = options.else;
720
759
 
721
760
  for (const [model, unique] of uniqueProps) {
722
761
  const literals = uniqueLiterals.get(model);
@@ -727,14 +766,11 @@ export function differentiateModelTypes(
727
766
  code: "undifferentiable-model",
728
767
  target: model,
729
768
  });
730
- return {
731
- kind: "result",
732
- type: defaultCase,
733
- };
769
+ return defaultCase;
734
770
  } else {
735
771
  // Allow a single default case. This covers more APIs that have a single model that is not differentiated by a
736
772
  // unique property, in which case we can make it the `else` case.
737
- defaultCase = model;
773
+ defaultCase = { kind: "result", type: model };
738
774
  continue;
739
775
  }
740
776
  }
@@ -744,7 +780,7 @@ export function differentiateModelTypes(
744
780
  const firstUniqueLiteral = literals.values().next().value as RenderedPropertyName;
745
781
 
746
782
  const property = [...model.properties.values()].find(
747
- (p) => (renderPropertyName(p) as RenderedPropertyName) === firstUniqueLiteral,
783
+ (p) => (options.renderPropertyName(p) as RenderedPropertyName) === firstUniqueLiteral,
748
784
  )!;
749
785
 
750
786
  branches.push({
@@ -752,7 +788,7 @@ export function differentiateModelTypes(
752
788
  kind: "binary-op",
753
789
  left: {
754
790
  kind: "binary-op",
755
- left: { kind: "literal", value: renderPropertyName(property) },
791
+ left: { kind: "literal", value: options.renderPropertyName(property) },
756
792
  operator: "in",
757
793
  right: SUBJECT,
758
794
  },
@@ -774,7 +810,7 @@ export function differentiateModelTypes(
774
810
  const firstUniqueRange = ranges.values().next().value as RenderedPropertyName;
775
811
 
776
812
  const property = [...model.properties.values()].find(
777
- (p) => renderPropertyName(p) === firstUniqueRange,
813
+ (p) => options.renderPropertyName(p) === firstUniqueRange,
778
814
  )!;
779
815
 
780
816
  const range = [...propertyRanges.get(firstUniqueRange)!.entries()].find(
@@ -786,7 +822,7 @@ export function differentiateModelTypes(
786
822
  kind: "binary-op",
787
823
  left: {
788
824
  kind: "binary-op",
789
- left: { kind: "literal", value: renderPropertyName(property) },
825
+ left: { kind: "literal", value: options.renderPropertyName(property) },
790
826
  operator: "in",
791
827
  right: SUBJECT,
792
828
  },
@@ -817,12 +853,7 @@ export function differentiateModelTypes(
817
853
  return {
818
854
  kind: "if-chain",
819
855
  branches,
820
- else: defaultCase
821
- ? {
822
- kind: "result",
823
- type: defaultCase,
824
- }
825
- : undefined,
856
+ else: defaultCase,
826
857
  };
827
858
  }
828
859
 
@@ -903,7 +934,11 @@ export function* writeCodeTree(
903
934
  break;
904
935
  }
905
936
  case "verbatim":
906
- yield* tree.body;
937
+ if (typeof tree.body === "function") {
938
+ yield* tree.body();
939
+ } else {
940
+ yield* tree.body;
941
+ }
907
942
  break;
908
943
  default:
909
944
  throw new UnreachableError("writeCodeTree for " + (tree satisfies never as CodeTree).kind, {