diff --git a/CHANGELOG.md b/CHANGELOG.md index a08d4cd..5b5f909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## unreleased +- CLI: Fix YAML output to keep quotes for $ref values (#230) + ## [1.33.4] - 2026-06-19 - CLI: add yamlCompat option for YAML 1.1 diff --git a/test/_split/snap.yaml b/test/_split/snap.yaml index 08db034..270746f 100644 --- a/test/_split/snap.yaml +++ b/test/_split/snap.yaml @@ -5,11 +5,11 @@ info: description: A compact version of the Train Travel API paths: /stations/{station_id}: - $ref: paths/stations_{station_id}.yaml + $ref: 'paths/stations_{station_id}.yaml' components: schemas: Station: - $ref: components/schemas/Station.yaml + $ref: 'components/schemas/Station.yaml' parameters: StationId: - $ref: components/parameters/StationId.yaml + $ref: 'components/parameters/StationId.yaml' diff --git a/test/_split/snap_station.yaml b/test/_split/snap_station.yaml index 5a0fd87..f75df38 100644 --- a/test/_split/snap_station.yaml +++ b/test/_split/snap_station.yaml @@ -2,13 +2,13 @@ get: summary: Get station information operationId: getStation parameters: - - $ref: ../components/parameters/StationId.yaml + - $ref: '../components/parameters/StationId.yaml' responses: '200': description: Successful operation content: application/json: schema: - $ref: ../components/schemas/Station.yaml + $ref: '../components/schemas/Station.yaml' '404': description: Station not found diff --git a/test/util-file.test.js b/test/util-file.test.js index 7322551..247962e 100644 --- a/test/util-file.test.js +++ b/test/util-file.test.js @@ -772,6 +772,53 @@ describe('openapi-format CLI file tests', () => { expect(result).toContain("$ref: '#/components/schemas/Example'"); }); + + test('should stringify external $ref values with quotes in YAML output', async () => { + const obj = { + paths: { + '/some/path': { + get: { + parameters: [ + { + $ref: './util/headers.yaml#/components/parameters/requestId' + } + ] + } + } + } + }; + + const result = await stringify(obj, {format: 'yaml'}); + + expect(result).toContain( + "$ref: './util/headers.yaml#/components/parameters/requestId'" + ); + }); + + test('should stringify external $ref values with the configured double quote style', async () => { + const obj = { + paths: { + '/some/path': { + get: { + parameters: [ + { + $ref: './util/headers.yaml#/components/parameters/requestId' + } + ] + } + } + } + }; + + const result = await stringify(obj, { + format: 'yaml', + yamlQuoteStyle: 'double' + }); + + expect(result).toContain( + '$ref: "./util/headers.yaml#/components/parameters/requestId"' + ); + }); }); describe('analyzeOpenApi function', () => { diff --git a/test/yaml-path-ref-quotes/input.yaml b/test/yaml-path-ref-quotes/input.yaml new file mode 100644 index 0000000..5b36fc6 --- /dev/null +++ b/test/yaml-path-ref-quotes/input.yaml @@ -0,0 +1,14 @@ +openapi: 3.0.3 +info: + title: API + version: 1.0.0 +paths: + /some/path: + get: + operationId: someOperation + tags: + - some-rest-controller + parameters: + - $ref: "./util/headers.yaml#/components/parameters/requestId" + - $ref: './util/headers.yaml#/components/parameters/correlationId' + - $ref: ./util/headers.yaml#/components/parameters/authorization diff --git a/test/yaml-path-ref-quotes/options.yaml b/test/yaml-path-ref-quotes/options.yaml new file mode 100644 index 0000000..a66a8cd --- /dev/null +++ b/test/yaml-path-ref-quotes/options.yaml @@ -0,0 +1,4 @@ +verbose: true +output: output.yaml +bundle: false +no-sort: true diff --git a/test/yaml-path-ref-quotes/output.yaml b/test/yaml-path-ref-quotes/output.yaml new file mode 100644 index 0000000..8554f74 --- /dev/null +++ b/test/yaml-path-ref-quotes/output.yaml @@ -0,0 +1,14 @@ +openapi: 3.0.3 +info: + title: API + version: 1.0.0 +paths: + /some/path: + get: + operationId: someOperation + tags: + - some-rest-controller + parameters: + - $ref: './util/headers.yaml#/components/parameters/requestId' + - $ref: './util/headers.yaml#/components/parameters/correlationId' + - $ref: './util/headers.yaml#/components/parameters/authorization' diff --git a/test/yaml-ref-quotes/output.yaml b/test/yaml-ref-quotes/output.yaml index 4a4b3b2..9682b83 100644 --- a/test/yaml-ref-quotes/output.yaml +++ b/test/yaml-ref-quotes/output.yaml @@ -6,6 +6,6 @@ components: type: object properties: extern: - $ref: domain-types.openapi.yaml#/components/schemas/Extern + $ref: 'domain-types.openapi.yaml#/components/schemas/Extern' intern: - $ref: domain-types.openapi.yaml#/components/schemas/Extern + $ref: 'domain-types.openapi.yaml#/components/schemas/Extern' diff --git a/utils/file.js b/utils/file.js index 6fb5f27..59a8e84 100644 --- a/utils/file.js +++ b/utils/file.js @@ -396,6 +396,9 @@ async function stringify(obj, options = {}) { output = newDoc.toString(yamlStringifyOptions); } + // Preserve quotes around $ref values so external references stay editor-friendly. + output = addQuotesToRefInString(output, yamlStringifyOptions.singleQuote ? "'" : '"'); + // Decode large number YAML values safely before writing output output = decodeLargeNumbers(output); } else { @@ -744,10 +747,11 @@ function decodeLargeNumbers(output, isJson = false) { /** * Add quotes to $ref in string * @param {string} yamlString - The input YAML string. + * @param {string} quoteChar - Quote character to use around $ref values. * @returns {string} YAML string with quotes. */ -function addQuotesToRefInString(yamlString) { - return yamlString.replace(/(\$ref:\s*)([^"'\s>]+)/g, "$1'$2'"); +function addQuotesToRefInString(yamlString, quoteChar = "'") { + return yamlString.replace(/(\$ref:\s*)([^"'\s>]+)/g, `$1${quoteChar}$2${quoteChar}`); } /**