@typespec/http-server-js 0.58.0-alpha.18-dev.2 → 0.58.0-alpha.18-dev.3

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.
@@ -45,6 +45,7 @@ import { getJsScalar } from "../../common/scalar.js";
45
45
  import {
46
46
  requiresJsonSerialization,
47
47
  transposeExpressionFromJson,
48
+ transposeExpressionToJson,
48
49
  } from "../../common/serialization/json.js";
49
50
  import { getFullyQualifiedTypeName } from "../../util/name.js";
50
51
  import { canonicalizeHttpOperation } from "../operation.js";
@@ -250,13 +251,6 @@ function* emitRawServerOperation(
250
251
 
251
252
  if (requiresJsonSerialization(ctx, module, body.type)) {
252
253
  if (body.type.kind === "Model" && isArrayModelType(ctx.program, body.type)) {
253
- const innerTypeName = emitTypeReference(
254
- ctx,
255
- body.type.indexer.value,
256
- body.type,
257
- module,
258
- { requireDeclaration: true },
259
- );
260
254
  yield ` const __arrayBody = JSON.parse(body);`;
261
255
  yield ` if (!Array.isArray(__arrayBody)) {`;
262
256
  yield ` ${names.ctx}.errorHandlers.onInvalidRequest(`;
@@ -266,16 +260,8 @@ function* emitRawServerOperation(
266
260
  yield ` );`;
267
261
  yield ` return reject();`;
268
262
  yield ` }`;
269
- value = `__arrayBody.map((item) => ${innerTypeName}.fromJsonObject(JSON.parse(item)))`;
263
+ value = transposeExpressionFromJson(ctx, body.type, `__arrayBody`, module);
270
264
  } else if (body.type.kind === "Model" && isRecordModelType(ctx.program, body.type)) {
271
- const innerTypeName = emitTypeReference(
272
- ctx,
273
- body.type.indexer.value,
274
- body.type,
275
- module,
276
- { requireDeclaration: true },
277
- );
278
-
279
265
  yield ` const __recordBody = JSON.parse(body);`;
280
266
  yield ` if (typeof __recordBody !== "object" || __recordBody === null) {`;
281
267
  yield ` ${names.ctx}.errorHandlers.onInvalidRequest(`;
@@ -285,11 +271,11 @@ function* emitRawServerOperation(
285
271
  yield ` );`;
286
272
  yield ` return reject();`;
287
273
  yield ` }`;
288
- value = `Object.fromEntries(Object.entries(__recordBody).map(([key, value]) => [key, ${innerTypeName}.fromJsonObject(value)]))`;
274
+ value = transposeExpressionFromJson(ctx, body.type, `__recordBody`, module);
289
275
  } else if (body.type.kind === "Scalar") {
290
276
  value = transposeExpressionFromJson(ctx, body.type, `JSON.parse(body)`, module);
291
277
  } else {
292
- value = `${bodyTypeName}.fromJsonObject(JSON.parse(body))`;
278
+ value = `${bodyTypeName}.fromJsonObject(globalThis.JSON.parse(body))`;
293
279
  }
294
280
  } else {
295
281
  value = `JSON.parse(body)`;
@@ -580,7 +566,7 @@ function* emitResultProcessingForType(
580
566
  case "unknown":
581
567
  yield `${names.ctx}.response.statusCode = 200;`;
582
568
  yield `${names.ctx}.response.setHeader("content-type", "application/json");`;
583
- yield `${names.ctx}.response.end(JSON.stringify(${names.result}));`;
569
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${names.result}));`;
584
570
  return;
585
571
  case "never":
586
572
  yield `return ${names.ctx}.errorHandlers.onInternalError(${names.ctx}, "Internal server error.");`;
@@ -647,9 +633,45 @@ function* emitResultProcessingForType(
647
633
  altName: namer.getAltName("Body"),
648
634
  requireDeclaration: true,
649
635
  });
650
- yield `${names.ctx}.response.end(JSON.stringify(${typeReference}.toJsonObject(${names.result}.${bodyCase.camelCase})))`;
636
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${typeReference}.toJsonObject(${names.result}.${bodyCase.camelCase})))`;
637
+ } else {
638
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${names.result}.${bodyCase.camelCase}));`;
639
+ }
640
+ } else if (isArrayModelType(ctx.program, target)) {
641
+ const itemType = target.indexer.value;
642
+
643
+ const serializationRequired = isSerializationRequired(
644
+ ctx,
645
+ module,
646
+ itemType,
647
+ "application/json",
648
+ );
649
+ requireSerialization(ctx, itemType, "application/json");
650
+
651
+ yield `${names.ctx}.response.setHeader("content-type", "application/json");`;
652
+
653
+ if (serializationRequired) {
654
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${transposeExpressionToJson(ctx, target, names.result, module)}));`;
655
+ } else {
656
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${names.result}));`;
657
+ }
658
+ } else if (isRecordModelType(ctx.program, target)) {
659
+ const itemType = target.indexer.value;
660
+
661
+ const serializationRequired = isSerializationRequired(
662
+ ctx,
663
+ module,
664
+ itemType,
665
+ "application/json",
666
+ );
667
+ requireSerialization(ctx, itemType, "application/json");
668
+
669
+ yield `${names.ctx}.response.setHeader("content-type", "application/json");`;
670
+
671
+ if (serializationRequired) {
672
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${transposeExpressionToJson(ctx, target, names.result, module)}));`;
651
673
  } else {
652
- yield `${names.ctx}.response.end(JSON.stringify(${names.result}.${bodyCase.camelCase}));`;
674
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${names.result}));`;
653
675
  }
654
676
  } else {
655
677
  if (allMetadataIsRemoved) {
@@ -670,9 +692,9 @@ function* emitResultProcessingForType(
670
692
  altName: namer.getAltName("Result"),
671
693
  requireDeclaration: true,
672
694
  });
673
- yield `${names.ctx}.response.end(JSON.stringify(${typeReference}.toJsonObject(${names.result} as ${typeReference})));`;
695
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${typeReference}.toJsonObject(${names.result} as ${typeReference})));`;
674
696
  } else {
675
- yield `${names.ctx}.response.end(JSON.stringify(${names.result}));`;
697
+ yield `${names.ctx}.response.end(globalThis.JSON.stringify(${names.result}));`;
676
698
  }
677
699
  }
678
700
  }
@@ -17,6 +17,7 @@ import {
17
17
  getDiscriminator,
18
18
  getMaxValue,
19
19
  getMinValue,
20
+ isArrayModelType,
20
21
  isNeverType,
21
22
  isUnknownType,
22
23
  } from "@typespec/compiler";
@@ -136,6 +137,7 @@ export interface SwitchCase {
136
137
  export type Expression =
137
138
  | BinaryOp
138
139
  | UnaryOp
140
+ | IsArray
139
141
  | TypeOf
140
142
  | Literal
141
143
  | VerbatimExpression
@@ -192,6 +194,17 @@ export interface UnaryOp {
192
194
  operand: Expression;
193
195
  }
194
196
 
197
+ /**
198
+ * An array test expression.
199
+ */
200
+ export interface IsArray {
201
+ kind: "is-array";
202
+ /**
203
+ * The expression to test.
204
+ */
205
+ expr: Expression;
206
+ }
207
+
195
208
  /**
196
209
  * A type-of operation.
197
210
  */
@@ -660,7 +673,14 @@ export function differentiateModelTypes(
660
673
  const propertyRanges = new Map<RenderedPropertyName, Map<IntegerRange, Model>>();
661
674
  const uniqueRanges = new Map<Model, Set<RenderedPropertyName>>();
662
675
 
676
+ let arrayVariant: Model | undefined = undefined;
677
+
663
678
  for (const model of models) {
679
+ if (isArrayModelType(ctx.program, model) && model.properties.size === 0 && !arrayVariant) {
680
+ arrayVariant = model;
681
+ continue;
682
+ }
683
+
664
684
  const props = new Set<string>();
665
685
 
666
686
  for (const prop of getAllProperties(model).filter(options.filter)) {
@@ -758,6 +778,16 @@ export function differentiateModelTypes(
758
778
 
759
779
  let defaultCase: CodeTree | undefined = options.else;
760
780
 
781
+ if (arrayVariant) {
782
+ branches.push({
783
+ condition: {
784
+ kind: "is-array",
785
+ expr: SUBJECT,
786
+ },
787
+ body: { kind: "result", type: arrayVariant },
788
+ });
789
+ }
790
+
761
791
  for (const [model, unique] of uniqueProps) {
762
792
  const literals = uniqueLiterals.get(model);
763
793
  const ranges = uniqueRanges.get(model);
@@ -958,6 +988,8 @@ function writeExpression(ctx: JsContext, expression: Expression, options: CodeTr
958
988
  )})`;
959
989
  case "unary-op":
960
990
  return `${expression.operator}(${writeExpression(ctx, expression.operand, options)})`;
991
+ case "is-array":
992
+ return `globalThis.Array.isArray(${writeExpression(ctx, expression.expr, options)})`;
961
993
  case "typeof":
962
994
  return `typeof (${writeExpression(ctx, expression.operand, options)})`;
963
995
  case "literal":