Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/openapi3"
---

Fix extension properties with JSON-like strings using escaped string literals to prevent triple-quote syntax issues
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export function stringLiteral(value: string): string {
if (value.includes("\n")) {
// Escape ${...} in multi-line strings to prevent interpolation
return `"""\n${value.replaceAll("${", "\\${")}\n"""`;
return `"""\n${value.replaceAll("${", "\\${").replaceAll('"""', '\\"""')}\n"""`;
}
// Escape both quotes and ${...} in single-line strings to prevent interpolation
return `"${value.replaceAll('"', '\\"').replaceAll("${", "\\${")}"`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,3 +597,64 @@ describe("unixtime format conversion", () => {
);
});
});

describe.each(versions)("Extension with JSON-like string values v%s", (version) => {
it("should treat JSON-like string in extension property as an escaped string literal", async () => {
const tsp = await convertOpenAPI3Document({
openapi: version,
info: {
title: "Test Service",
version: "1.0.0",
},
paths: {},
components: {
schemas: {
GraderPython: {
type: "object",
"x-oaiMeta": {
name: "Python Grader",
group: "graders",
example: `{
"type": "python",
"name": "Example python grader",
"image_tag": "2025-05-08",
"source": """
def grade(sample: dict, item: dict) -> float:
"""
Returns 1.0 if \`output_text\` equals \`label\`, otherwise 0.0.
"""
output = sample.get("output_text")
label = item.get("label")
return 1.0 if output == label else 0.0
""",
}`,
},
},
},
},
} as any);

// the example should escape the literal syntax contained withing the string value
strictEqual(
tsp.includes('source": \\"""'),
true,
"Expected 'example' to be an escaped string literal with newlines represented as \\n, but got: " +
tsp,
);

// Should use triple-quoted strings for object literal values
strictEqual(
tsp.includes('example: """'),
true,
"Should use triple-quoted strings in object literals as they can break with nested quotes. Got: " +
tsp,
);

// Should NOT have nested object structure
strictEqual(
tsp.includes("example: #{"),
false,
"Should not parse JSON string as object literal. Got: " + tsp,
);
});
});
Loading