@typespec/http-server-js 0.58.0-alpha.12-dev.0 → 0.58.0-alpha.12-dev.1

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 (61) hide show
  1. package/dist/generated-defs/helpers/datetime.d.ts +4 -0
  2. package/dist/generated-defs/helpers/datetime.d.ts.map +1 -0
  3. package/dist/generated-defs/helpers/datetime.js +256 -0
  4. package/dist/generated-defs/helpers/datetime.js.map +1 -0
  5. package/dist/generated-defs/helpers/index.d.ts.map +1 -1
  6. package/dist/generated-defs/helpers/index.js +1 -0
  7. package/dist/generated-defs/helpers/index.js.map +1 -1
  8. package/dist/src/common/declaration.js +1 -1
  9. package/dist/src/common/declaration.js.map +1 -1
  10. package/dist/src/common/reference.js +1 -1
  11. package/dist/src/common/reference.js.map +1 -1
  12. package/dist/src/common/scalar.d.ts +175 -22
  13. package/dist/src/common/scalar.d.ts.map +1 -1
  14. package/dist/src/common/scalar.js +420 -93
  15. package/dist/src/common/scalar.js.map +1 -1
  16. package/dist/src/common/serialization/index.d.ts +2 -2
  17. package/dist/src/common/serialization/index.d.ts.map +1 -1
  18. package/dist/src/common/serialization/index.js +9 -3
  19. package/dist/src/common/serialization/index.js.map +1 -1
  20. package/dist/src/common/serialization/json.d.ts +2 -2
  21. package/dist/src/common/serialization/json.d.ts.map +1 -1
  22. package/dist/src/common/serialization/json.js +144 -42
  23. package/dist/src/common/serialization/json.js.map +1 -1
  24. package/dist/src/helpers/datetime.d.ts +92 -0
  25. package/dist/src/helpers/datetime.d.ts.map +1 -0
  26. package/dist/src/helpers/datetime.js +151 -0
  27. package/dist/src/helpers/datetime.js.map +1 -0
  28. package/dist/src/http/server/index.d.ts.map +1 -1
  29. package/dist/src/http/server/index.js +17 -12
  30. package/dist/src/http/server/index.js.map +1 -1
  31. package/dist/src/http/server/multipart.js +1 -1
  32. package/dist/src/http/server/multipart.js.map +1 -1
  33. package/dist/src/lib.d.ts +10 -1
  34. package/dist/src/lib.d.ts.map +1 -1
  35. package/dist/src/lib.js +6 -0
  36. package/dist/src/lib.js.map +1 -1
  37. package/dist/src/util/case.d.ts +9 -0
  38. package/dist/src/util/case.d.ts.map +1 -1
  39. package/dist/src/util/case.js +18 -0
  40. package/dist/src/util/case.js.map +1 -1
  41. package/dist/src/util/differentiate.d.ts +4 -4
  42. package/dist/src/util/differentiate.d.ts.map +1 -1
  43. package/dist/src/util/differentiate.js +10 -10
  44. package/dist/src/util/differentiate.js.map +1 -1
  45. package/generated-defs/helpers/datetime.ts +263 -0
  46. package/generated-defs/helpers/index.ts +1 -0
  47. package/package.json +7 -7
  48. package/src/common/declaration.ts +1 -1
  49. package/src/common/reference.ts +1 -1
  50. package/src/common/scalar.ts +709 -103
  51. package/src/common/serialization/index.ts +11 -4
  52. package/src/common/serialization/json.ts +174 -52
  53. package/src/helpers/datetime.ts +235 -0
  54. package/src/http/server/index.ts +29 -15
  55. package/src/http/server/multipart.ts +1 -1
  56. package/src/lib.ts +6 -0
  57. package/src/util/case.ts +19 -0
  58. package/src/util/differentiate.ts +15 -8
  59. package/temp/tsconfig.tsbuildinfo +1 -1
  60. package/test/datetime.test.ts +226 -0
  61. package/test/scalar.test.ts +345 -0
@@ -12,7 +12,6 @@ import {
12
12
  } from "@typespec/http";
13
13
  import { createOrGetModuleForNamespace } from "../../common/namespace.js";
14
14
  import { emitTypeReference, isValueLiteralType } from "../../common/reference.js";
15
- import { parseTemplateForScalar } from "../../common/scalar.js";
16
15
  import {
17
16
  SerializableType,
18
17
  isSerializationRequired,
@@ -33,6 +32,7 @@ import { emitMultipart, emitMultipartLegacy } from "./multipart.js";
33
32
 
34
33
  import { module as headerHelpers } from "../../../generated-defs/helpers/header.js";
35
34
  import { module as httpHelpers } from "../../../generated-defs/helpers/http.js";
35
+ import { getJsScalar } from "../../common/scalar.js";
36
36
  import { requiresJsonSerialization } from "../../common/serialization/json.js";
37
37
 
38
38
  const DEFAULT_CONTENT_TYPE = "application/json";
@@ -127,7 +127,7 @@ function* emitRawServerOperation(
127
127
 
128
128
  const queryParams: Extract<HttpOperationParameter, { type: "query" }>[] = [];
129
129
 
130
- const parsedParams = new Set<ModelProperty>();
130
+ const parsedParams = new Map<ModelProperty, HttpOperationParameter>();
131
131
 
132
132
  for (const parameter of operation.parameters.parameters) {
133
133
  const resolvedParameter =
@@ -140,11 +140,11 @@ function* emitRawServerOperation(
140
140
  throw new UnimplementedError("cookie parameters");
141
141
  case "query":
142
142
  queryParams.push(parameter);
143
- parsedParams.add(resolvedParameter);
143
+ parsedParams.set(resolvedParameter, parameter);
144
144
  break;
145
145
  case "path":
146
146
  // Already handled above.
147
- parsedParams.add(resolvedParameter);
147
+ parsedParams.set(resolvedParameter, parameter);
148
148
  break;
149
149
  default:
150
150
  throw new Error(
@@ -228,7 +228,7 @@ function* emitRawServerOperation(
228
228
 
229
229
  let value: string;
230
230
 
231
- if (requiresJsonSerialization(ctx, body.type)) {
231
+ if (requiresJsonSerialization(ctx, module, body.type)) {
232
232
  value = `${bodyTypeName}.fromJsonObject(JSON.parse(body))`;
233
233
  } else {
234
234
  value = `JSON.parse(body)`;
@@ -283,13 +283,17 @@ function* emitRawServerOperation(
283
283
  } else {
284
284
  const resolvedParameter = param.type.kind === "ModelProperty" ? param.type : param;
285
285
 
286
- paramBaseExpression =
287
- resolvedParameter.type.kind === "Scalar" && parsedParams.has(resolvedParameter)
288
- ? parseTemplateForScalar(ctx, resolvedParameter.type).replace(
289
- "{}",
290
- paramNameCase.camelCase,
291
- )
292
- : paramNameCase.camelCase;
286
+ const httpOperationParam = parsedParams.get(resolvedParameter);
287
+
288
+ if (resolvedParameter.type.kind === "Scalar" && httpOperationParam) {
289
+ const jsScalar = getJsScalar(ctx, module, resolvedParameter.type, resolvedParameter);
290
+
291
+ const encoder = jsScalar.http[httpOperationParam.type];
292
+
293
+ paramBaseExpression = encoder.decode(paramNameCase.camelCase);
294
+ } else {
295
+ paramBaseExpression = paramNameCase.camelCase;
296
+ }
293
297
  }
294
298
 
295
299
  if (param.optional) {
@@ -360,7 +364,7 @@ function* emitResultProcessing(
360
364
  // Single target type
361
365
  yield* emitResultProcessingForType(ctx, names, t, module);
362
366
  } else {
363
- const codeTree = differentiateUnion(ctx, t);
367
+ const codeTree = differentiateUnion(ctx, module, t);
364
368
 
365
369
  yield* writeCodeTree(ctx, codeTree, {
366
370
  subject: names.result,
@@ -452,7 +456,12 @@ function* emitResultProcessingForType(
452
456
 
453
457
  if (body) {
454
458
  const bodyCase = parseCase(body.name);
455
- const serializationRequired = isSerializationRequired(ctx, body.type, "application/json");
459
+ const serializationRequired = isSerializationRequired(
460
+ ctx,
461
+ module,
462
+ body.type,
463
+ "application/json",
464
+ );
456
465
  requireSerialization(ctx, body.type, "application/json");
457
466
 
458
467
  yield `${names.ctx}.response.setHeader("content-type", "application/json");`;
@@ -469,7 +478,12 @@ function* emitResultProcessingForType(
469
478
  if (allMetadataIsRemoved) {
470
479
  yield `${names.ctx}.response.end();`;
471
480
  } else {
472
- const serializationRequired = isSerializationRequired(ctx, target, "application/json");
481
+ const serializationRequired = isSerializationRequired(
482
+ ctx,
483
+ module,
484
+ target,
485
+ "application/json",
486
+ );
473
487
  requireSerialization(ctx, target, "application/json");
474
488
 
475
489
  yield `${names.ctx}.response.setHeader("content-type", "application/json");`;
@@ -167,7 +167,7 @@ export function* emitMultipart(
167
167
  yield ` const __object = JSON.parse(Buffer.concat(__chunks).toString("utf-8"));`;
168
168
  yield "";
169
169
 
170
- if (requiresJsonSerialization(ctx, namedPart.body.type)) {
170
+ if (requiresJsonSerialization(ctx, module, namedPart.body.type)) {
171
171
  const bodyTypeReference = emitTypeReference(
172
172
  ctx,
173
173
  namedPart.body.type,
package/src/lib.ts CHANGED
@@ -125,6 +125,12 @@ export const $lib = createTypeSpecLibrary({
125
125
  "An OpenAPI3 document could not be generated for this service because versioned services are not yet supported by the HTTP server emitter for JavaScript.",
126
126
  },
127
127
  },
128
+ "unknown-encoding": {
129
+ severity: "error",
130
+ messages: {
131
+ default: paramMessage`Unknown encoding '${"encoding"}' to type '${"target"}' for type '${"type"}'.`,
132
+ },
133
+ },
128
134
  },
129
135
  });
130
136
 
package/src/util/case.ts CHANGED
@@ -28,6 +28,25 @@ export function isUnspeakable(name: string): boolean {
28
28
  return true;
29
29
  }
30
30
 
31
+ const JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
32
+
33
+ /**
34
+ * Returns an access expression for a given subject and key.
35
+ *
36
+ * If the access can be performed using dot notation, it will. Otherwise, bracket notation will be used.
37
+ *
38
+ * @param subject - the expression to access
39
+ * @param key - the key to access within the subject, must be an index value literal, not an expression
40
+ */
41
+ export function access(subject: string, key: string | number): string {
42
+ subject = JS_IDENTIFIER.test(subject) ? subject : `(${subject})`;
43
+ if (typeof key === "string" && JS_IDENTIFIER.test(key)) {
44
+ return `${subject}.${key}`;
45
+ } else {
46
+ return `${subject}[${JSON.stringify(key)}]`;
47
+ }
48
+ }
49
+
31
50
  /**
32
51
  * Destructures a name into its components.
33
52
  *
@@ -21,7 +21,7 @@ import {
21
21
  isUnknownType,
22
22
  } from "@typespec/compiler";
23
23
  import { getJsScalar } from "../common/scalar.js";
24
- import { JsContext } from "../ctx.js";
24
+ import { JsContext, Module } from "../ctx.js";
25
25
  import { reportDiagnostic } from "../lib.js";
26
26
  import { isUnspeakable, parseCase } from "./case.js";
27
27
  import { UnimplementedError, UnreachableError } from "./error.js";
@@ -287,6 +287,7 @@ const PROPERTY_ID = (prop: ModelProperty) => parseCase(prop.name).camelCase;
287
287
  */
288
288
  export function differentiateUnion(
289
289
  ctx: JsContext,
290
+ module: Module,
290
291
  union: Union,
291
292
  renderPropertyName: (prop: ModelProperty) => string = PROPERTY_ID,
292
293
  ): CodeTree {
@@ -313,7 +314,7 @@ export function differentiateUnion(
313
314
  }
314
315
  }
315
316
 
316
- return differentiateTypes(ctx, cases, renderPropertyName);
317
+ return differentiateTypes(ctx, module, cases, renderPropertyName);
317
318
  } else {
318
319
  const property = (variants[0].type as Model).properties.get(discriminator)!;
319
320
 
@@ -353,6 +354,7 @@ export function differentiateUnion(
353
354
  */
354
355
  export function differentiateTypes(
355
356
  ctx: JsContext,
357
+ module: Module,
356
358
  cases: Set<PreciseType>,
357
359
  renderPropertyName: (prop: ModelProperty) => string = PROPERTY_ID,
358
360
  ): CodeTree {
@@ -378,7 +380,7 @@ export function differentiateTypes(
378
380
  const intrinsics = (categories.Intrinsic as (VoidType | NullType)[]) ?? [];
379
381
 
380
382
  if (literals.length + scalars.length + intrinsics.length === 0) {
381
- return differentiateModelTypes(ctx, select(models, cases), renderPropertyName);
383
+ return differentiateModelTypes(ctx, module, select(models, cases), renderPropertyName);
382
384
  } else {
383
385
  const branches: IfBranch[] = [];
384
386
 
@@ -419,7 +421,7 @@ export function differentiateTypes(
419
421
  const scalarRepresentations = new Map<string, Scalar>();
420
422
 
421
423
  for (const scalar of scalars) {
422
- const jsScalar = getJsScalar(ctx.program, scalar, scalar);
424
+ const jsScalar = getJsScalar(ctx, module, scalar, scalar).type;
423
425
 
424
426
  if (scalarRepresentations.has(jsScalar)) {
425
427
  reportDiagnostic(ctx.program, {
@@ -503,7 +505,7 @@ export function differentiateTypes(
503
505
  branches,
504
506
  else:
505
507
  models.length > 0
506
- ? differentiateModelTypes(ctx, select(models, cases), renderPropertyName)
508
+ ? differentiateModelTypes(ctx, module, select(models, cases), renderPropertyName)
507
509
  : undefined,
508
510
  };
509
511
  }
@@ -563,10 +565,14 @@ function getJsValue(ctx: JsContext, literal: JsLiteralType | EnumMember): Litera
563
565
  */
564
566
  type IntegerRange = [number, number];
565
567
 
566
- function getIntegerRange(ctx: JsContext, property: ModelProperty): IntegerRange | false {
568
+ function getIntegerRange(
569
+ ctx: JsContext,
570
+ module: Module,
571
+ property: ModelProperty,
572
+ ): IntegerRange | false {
567
573
  if (
568
574
  property.type.kind === "Scalar" &&
569
- getJsScalar(ctx.program, property.type, property) === "number"
575
+ getJsScalar(ctx, module, property.type, property).type === "number"
570
576
  ) {
571
577
  const minValue = getMinValue(ctx.program, property);
572
578
  const maxValue = getMaxValue(ctx.program, property);
@@ -594,6 +600,7 @@ function overlaps(range: IntegerRange, other: IntegerRange): boolean {
594
600
  */
595
601
  export function differentiateModelTypes(
596
602
  ctx: JsContext,
603
+ module: Module,
597
604
  models: Set<Model>,
598
605
  renderPropertyName: (prop: ModelProperty) => string = PROPERTY_ID,
599
606
  ): CodeTree {
@@ -656,7 +663,7 @@ export function differentiateModelTypes(
656
663
 
657
664
  // CASE - unique range
658
665
 
659
- const range = getIntegerRange(ctx, prop);
666
+ const range = getIntegerRange(ctx, module, prop);
660
667
  if (range) {
661
668
  let ranges = propertyRanges.get(renderedPropName);
662
669
  if (!ranges) {