Skip to content

Commit 8798be8

Browse files
committed
ref: normalize emitted object keys through tsObjectKey
(cherry picked from commit 19a4f0e5fae0feea51c397589f81f0c28bffed36)
1 parent b854e02 commit 8798be8

3 files changed

Lines changed: 18 additions & 11 deletions

File tree

‎src/api/writer-generator/typescript/name.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,13 @@ export const tsExtensionFlatTypeName = (profileName: string, extensionName: stri
103103
export const tsSliceStaticName = (name: string): string => name.replace(/\[x\]/g, "").replace(/[^a-zA-Z0-9_$]/g, "_");
104104

105105
export const tsValueFieldName = (id: TypeIdentifier): string => `value${uppercaseFirstLetter(id.name)}`;
106+
107+
const TS_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
108+
109+
/** An object-literal property key for emitted value code: bare when it is a
110+
* valid identifier, quoted otherwise — and computed for "__proto__", whose
111+
* plain form is the prototype setter and would not create an own property. */
112+
export const tsObjectKey = (key: string): string => {
113+
if (key === "__proto__") return '["__proto__"]';
114+
return TS_IDENTIFIER_RE.test(key) ? key : JSON.stringify(key);
115+
};

‎src/api/writer-generator/typescript/writer.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
tsModuleFileName,
2828
tsModuleName,
2929
tsNameFromCanonical,
30+
tsObjectKey,
3031
tsPackageDir,
3132
tsProfileModuleFileName,
3233
tsResourceName,
@@ -557,7 +558,7 @@ export class TypeScript extends Writer<TypeScriptOptions> {
557558
this.curlyBlock(["displays:"], () => {
558559
for (const concept of concepts) {
559560
if (concept.display !== undefined)
560-
this.line(`[${JSON.stringify(concept.code)}]: ${JSON.stringify(concept.display)},`);
561+
this.line(`${tsObjectKey(concept.code)}: ${JSON.stringify(concept.display)},`);
561562
}
562563
}, [","]);
563564
}

‎test/unit/api/writer-generator/typescript/terminology.test.ts‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ describe("TypeScript terminology surface", () => {
112112
contentMode: "complete",
113113
codes: ["second", "first"],
114114
displays: {
115-
["second"]: "Second display",
116-
["first"]: "First display",
115+
second: "Second display",
116+
first: "First display",
117117
},
118118
} as const;
119119
export type CompleteExampleCode = (typeof CompleteExampleCodeSystem.codes)[number];
@@ -231,7 +231,7 @@ describe("TypeScript terminology surface", () => {
231231
output.indexOf(JSON.stringify(sourceConcepts[1].code)),
232232
);
233233
for (const concept of sourceConcepts) {
234-
expect(output).toContain(`[${JSON.stringify(concept.code)}]: ${JSON.stringify(concept.display)}`);
234+
expect(output).toContain(`${concept.code}: ${JSON.stringify(concept.display)}`);
235235
}
236236
});
237237

@@ -274,12 +274,8 @@ describe("TypeScript terminology surface", () => {
274274
]);
275275

276276
expect(output).toContain('codes: ["parent", "child", "sibling"]');
277-
expect(output.indexOf('["parent"]: "Parent display"')).toBeLessThan(
278-
output.indexOf('["child"]: "Child display"'),
279-
);
280-
expect(output.indexOf('["child"]: "Child display"')).toBeLessThan(
281-
output.indexOf('["sibling"]: "Sibling display"'),
282-
);
277+
expect(output.indexOf('parent: "Parent display"')).toBeLessThan(output.indexOf('child: "Child display"'));
278+
expect(output.indexOf('child: "Child display"')).toBeLessThan(output.indexOf('sibling: "Sibling display"'));
283279
});
284280

285281
it("handles deeply nested concepts without exhausting the stack", async () => {
@@ -308,7 +304,7 @@ describe("TypeScript terminology surface", () => {
308304
]);
309305

310306
expect(output).toContain('codes: ["code-0", "code-1"');
311-
expect(output).toContain(`["code-${depth}"]: "Display ${depth}"`);
307+
expect(output).toContain(`"code-${depth}": "Display ${depth}"`);
312308
});
313309

314310
it("fails deterministically when hierarchical concepts repeat a code", async () => {

0 commit comments

Comments
 (0)