Skip to content

Commit c0a9a53

Browse files
authored
Fix OpenAPI YAML converts strings to boolean (#5456)
Problem: yaml 1.1 treats some string as other types of value. Check out: https://perlpunk.github.io/yaml-test-schema/schemas.html Fix: #5377 Solution: make serialization compatible with YAML 1.1 Todo: test other types (in next PR).
1 parent 84ebce0 commit c0a9a53

File tree

4 files changed

+93
-4
lines changed

4 files changed

+93
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@typespec/openapi3"
5+
---
6+
7+
Fix: OpenAPI YAML converts strings to boolean

Diff for: packages/openapi3/src/openapi.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,7 @@ function serializeDocument(root: OpenAPI3Document, fileType: FileType): string {
18441844
singleQuote: true,
18451845
aliasDuplicateObjects: false,
18461846
lineWidth: 0,
1847+
compat: "yaml-1.1",
18471848
});
18481849
}
18491850
}

Diff for: packages/openapi3/test/emit-openapi.test.ts

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { describe, expect, it } from "vitest";
2+
import { emitOpenApiWithDiagnostics } from "./test-host.js";
3+
4+
describe("Scalar formats of serialized document in YAML", () => {
5+
it("should add single quote for y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF", async () => {
6+
const [_, __, content] = await emitOpenApiWithDiagnostics(`
7+
enum TestEnum {
8+
y: "y",
9+
Y: "Y",
10+
yes: "yes",
11+
Yes: "Yes",
12+
YES: "YES",
13+
yEs: "yEs",
14+
n: "n",
15+
N: "N",
16+
no: "no",
17+
No: "No",
18+
NO: "NO",
19+
nO: "nO",
20+
"true": "true",
21+
True: "True",
22+
TRUE: "TRUE",
23+
tRUE: "tRUE",
24+
"false": "false",
25+
False: "False",
26+
FALSE: "FALSE",
27+
fALSE: "fALSE",
28+
on: "on",
29+
On: "On",
30+
ON: "ON",
31+
oN: "oN",
32+
off: "off",
33+
Off: "Off",
34+
OFF: "OFF",
35+
oFF: "oFF"
36+
}
37+
`);
38+
expect(content).toBe(`openapi: 3.0.0
39+
info:
40+
title: (title)
41+
version: 0.0.0
42+
tags: []
43+
paths: {}
44+
components:
45+
schemas:
46+
TestEnum:
47+
type: string
48+
enum:
49+
- 'y'
50+
- 'Y'
51+
- 'yes'
52+
- 'Yes'
53+
- 'YES'
54+
- yEs
55+
- 'n'
56+
- 'N'
57+
- 'no'
58+
- 'No'
59+
- 'NO'
60+
- nO
61+
- 'true'
62+
- 'True'
63+
- 'TRUE'
64+
- tRUE
65+
- 'false'
66+
- 'False'
67+
- 'FALSE'
68+
- fALSE
69+
- 'on'
70+
- 'On'
71+
- 'ON'
72+
- oN
73+
- 'off'
74+
- 'Off'
75+
- 'OFF'
76+
- oFF
77+
`);
78+
});
79+
});

Diff for: packages/openapi3/test/test-host.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { RestTestLibrary } from "@typespec/rest/testing";
1111
import { VersioningTestLibrary } from "@typespec/versioning/testing";
1212
import { XmlTestLibrary } from "@typespec/xml/testing";
1313
import { ok } from "assert";
14+
import { parse } from "yaml";
1415
import { OpenAPI3EmitterOptions } from "../src/lib.js";
1516
import { OpenAPI3TestLibrary } from "../src/testing/index.js";
1617
import { OpenAPI3Document } from "../src/types.js";
@@ -56,9 +57,10 @@ export async function createOpenAPITestRunner({
5657
export async function emitOpenApiWithDiagnostics(
5758
code: string,
5859
options: OpenAPI3EmitterOptions = {},
59-
): Promise<[OpenAPI3Document, readonly Diagnostic[]]> {
60+
): Promise<[OpenAPI3Document, readonly Diagnostic[], string]> {
6061
const runner = await createOpenAPITestRunner();
61-
const outputFile = resolveVirtualPath("openapi.json");
62+
const fileType = options["file-type"] || "yaml";
63+
const outputFile = resolveVirtualPath("openapi" + fileType === "json" ? ".json" : ".yaml");
6264
const diagnostics = await runner.diagnose(code, {
6365
noEmit: false,
6466
emit: ["@typespec/openapi3"],
@@ -68,8 +70,8 @@ export async function emitOpenApiWithDiagnostics(
6870
});
6971
const content = runner.fs.get(outputFile);
7072
ok(content, "Expected to have found openapi output");
71-
const doc = JSON.parse(content);
72-
return [doc, diagnostics];
73+
const doc = fileType === "json" ? JSON.parse(content) : parse(content);
74+
return [doc, diagnostics, content];
7375
}
7476

7577
export async function diagnoseOpenApiFor(code: string, options: OpenAPI3EmitterOptions = {}) {

0 commit comments

Comments
 (0)