Skip to content

fix: prevent $ref property names from corrupting YAML output - #236

Open
musa-cf wants to merge 1 commit into
thim81:mainfrom
musa-cf:fix/dollar-ref-property-name
Open

musa-cf wants to merge 1 commit into
thim81:mainfrom
musa-cf:fix/dollar-ref-property-name

Conversation

@musa-cf

@musa-cf musa-cf commented Sep 25, 2026

Copy link
Copy Markdown

Problem

When a YAML schema contains a property literally named $ref (e.g. the SCIM Group member $ref field per RFC 7643), openapi-format silently produces {} as output (exit 0, no error on stderr).

This is a data-loss bug: the entire OpenAPI document is replaced with an empty object.

Reproducer

openapi: 3.0.3
info:
  title: SCIM API
  version: 1.0.0
paths: {}
components:
  schemas:
    member:
      type: object
      properties:
        value:
          type: string
        "$ref":
          type: string
          format: uri
          description: The URI of the member resource.
openapi-format input.yaml --output output.yaml
cat output.yaml
# => {}

Root cause

addQuotesToRefInString uses the regex /(\$ref:\s*)([^"'\s>]+)/g. The \s* includes \n, so when $ref: is a YAML mapping key (property name) with its value on the next line, the regex reaches across the newline and wraps the following line's key in quotes:

# Before addQuotesToRefInString:
              $ref:
                description: The URI of the member resource.

# After addQuotesToRefInString:
              $ref:
                'description:' The URI of the member resource.

This produces invalid YAML. In >=1.33.6, the new doc.errors.length > 0 check in parseString returns a SyntaxError object instead of the parsed document. The caller treats this error object as the formatted output, which serializes to {}.

The bug was latent since addQuotesToRefInString was introduced but became fatal in 1.33.6 when the error check was added.

Fix

Replace \s* with [ \t]* in the regex so it only matches horizontal whitespace and stays on the same line. When $ref is a property name, its value is a block mapping on the next line, so the regex correctly skips it. When $ref is a JSON Reference, the value is on the same line and still gets quoted as intended.

Tests added

  • Integration test (test/yaml-dollar-ref-property-name/): full input/output fixture with a SCIM-style schema containing a $ref property name
  • Unit test (test/util-file.test.js): addQuotesToRefInString should not modify $ref used as a YAML property name
  • Unit test (test/util-file.test.js): parseString should parse YAML with $ref as a property name without error

All 509 existing tests continue to pass.

@musa-cf
musa-cf marked this pull request as ready for review September 25, 2026 04:44
@musa-cf musa-cf changed the title fix: prevent \$ref property names from corrupting YAML output fix: prevent $ref property names from corrupting YAML output Sep 25, 2026
When a YAML schema contains a property literally named "$ref" (e.g. the
SCIM Group member $ref field per RFC 7643), addQuotesToRefInString
corrupts the document by matching across newlines and quoting the next
line's key as if it were a $ref value.

Root cause: the regex /(\$ref:\s*)([^"'\\s>]+)/g uses \\s* which
includes \\n, so "$ref:" at the end of a line (a YAML mapping key)
matches into the following line.

Fix: replace \\s* with [ \\t]* so the regex only matches horizontal
whitespace and stays on the same line. When $ref is a property name its
value is a block mapping on the next line, so the regex correctly skips
it.

This bug was latent since the function was introduced but became fatal
in 1.33.6 when a doc.errors.length check was added to parseString,
turning the parse error into a SyntaxError return that propagates as
"{}" in the output file.
@musa-cf
musa-cf force-pushed the fix/dollar-ref-property-name branch from 240f75f to 454f491 Compare September 25, 2026 04:56
@thim81

thim81 commented Sep 27, 2026

Copy link
Copy Markdown
Owner

Hi @musa-cf

Thanks for taking the time to create this PR. The PR overall looks in great shape, with a logical improvement and test coverage to showcase the result.

I m going to do one more extended investigation, since there might be a case with " or ' that might bypass the regex.

@musa-cf

musa-cf commented Oct 1, 2026

Copy link
Copy Markdown
Author

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants