From bb807bd7b07aec488b5f4715973bcd4414c48b10 Mon Sep 17 00:00:00 2001 From: Will Temple Date: Wed, 7 May 2025 13:25:13 -0700 Subject: [PATCH 1/2] hsjs: Improve handling of property serialization for JSON --- .../http-server-js/src/common/serialization/json.ts | 8 +++++--- packages/http-server-js/src/util/case.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/http-server-js/src/common/serialization/json.ts b/packages/http-server-js/src/common/serialization/json.ts index 9422271d8c9..d3222d62a90 100644 --- a/packages/http-server-js/src/common/serialization/json.ts +++ b/packages/http-server-js/src/common/serialization/json.ts @@ -20,7 +20,7 @@ import { import { getHeaderFieldOptions, getPathParamOptions, getQueryParamOptions } from "@typespec/http"; import { JsContext, Module } from "../../ctx.js"; import { reportDiagnostic } from "../../lib.js"; -import { access, parseCase } from "../../util/case.js"; +import { access, objectLiteralProperty, parseCase } from "../../util/case.js"; import { differentiateUnion, writeCodeTree } from "../../util/differentiate.js"; import { UnimplementedError } from "../../util/error.js"; import { indent } from "../../util/iter.js"; @@ -106,10 +106,12 @@ function propertyRequiresJsonSerialization( module: Module, property: ModelProperty, ): boolean { + const encodedName = resolveEncodedName(ctx.program, property, "application/json"); + const jsPropertyName = keywordSafe(parseCase(property.name).camelCase); return !!( isHttpMetadata(ctx, property) || getEncode(ctx.program, property) || - resolveEncodedName(ctx.program, property, "application/json") !== property.name || + encodedName !== jsPropertyName || (isJsonSerializable(property.type) && requiresJsonSerialization(ctx, module, property.type, property)) ); @@ -190,7 +192,7 @@ function* emitToJson( expr = transposeExpressionToJson(ctx, property.type, expr, module); } - yield ` ${encodedName}: ${expr},`; + yield ` ${objectLiteralProperty(encodedName)}: ${expr},`; } yield `};`; diff --git a/packages/http-server-js/src/util/case.ts b/packages/http-server-js/src/util/case.ts index 02f8878ddda..e1eaf8b8505 100644 --- a/packages/http-server-js/src/util/case.ts +++ b/packages/http-server-js/src/util/case.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation // Licensed under the MIT license. +import { KEYWORDS } from "./keywords.js"; + /** * Separators recognized by the case parser. */ @@ -30,6 +32,17 @@ export function isUnspeakable(name: string): boolean { const JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; +/** + * Returns the property name to be used in an object literal. + */ +export function objectLiteralProperty(name: string): string { + if (!JS_IDENTIFIER.test(name) || KEYWORDS.has(name)) { + return JSON.stringify(name); + } else { + return name; + } +} + /** * Returns an access expression for a given subject and key. * From 52c2798380b6c45342925b72bf36059d4106e9a7 Mon Sep 17 00:00:00 2001 From: Will Temple Date: Wed, 7 May 2025 13:40:25 -0700 Subject: [PATCH 2/2] chronus --- ...mple-msft-quote-property-name-json-2025-4-7-13-40-10.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .chronus/changes/witemple-msft-quote-property-name-json-2025-4-7-13-40-10.md diff --git a/.chronus/changes/witemple-msft-quote-property-name-json-2025-4-7-13-40-10.md b/.chronus/changes/witemple-msft-quote-property-name-json-2025-4-7-13-40-10.md new file mode 100644 index 00000000000..7e99ec61ee0 --- /dev/null +++ b/.chronus/changes/witemple-msft-quote-property-name-json-2025-4-7-13-40-10.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/http-server-js" +--- + +Fixed an issue in which differences between model and JSON serialized property names were not correctly detected and property names for JSON serialization were not correctly quoted as necessary. \ No newline at end of file