Skip to content

Refactor/single xml parser - #1123

Open
deepakprabhakara wants to merge 3 commits into
feat/remove-deprecated-apifrom
refactor/single-xml-parser
Open

deepakprabhakara wants to merge 3 commits into
feat/remove-deprecated-apifrom
refactor/single-xml-parser

Conversation

@deepakprabhakara

Copy link
Copy Markdown
Collaborator

No description provided.

deepakprabhakara and others added 2 commits October 12, 2026 18:01
xmlToObject parses with parseFromString and returns the object shape
xml2js produced with the options this library uses: tag names without
their namespace prefix, attributes under a configurable key ('@' or
'$'), text under '_', a plain string for an element that has only text,
whitespace-only text dropped unless it came from CDATA, and null for an
empty document. With `collapse` it also folds a child that occurs once
into the value itself, the same way response.ts's flattenObject does,
including flattenObject's habit of leaving a single empty child as [''].

parseFromString takes an optional prefix map; xmlToObject uses it to
predeclare xsi and xs, which SAML producers often use on AttributeValue
without declaring. Without it, xmldom rejects such a document with a
NamespaceError where xml2js, which ignores namespaces, accepted it.

Nothing uses xmlToObject yet. Compared with xml2js (and flattenObject
for '@') on the 268 strings the test suite parses, every file under
test/assets and a set of edge cases, the output is identical except
where XML requires normalization xml2js does not do: CRLF/CR become LF
in text, and newlines and tabs in attribute values become spaces.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LkWpdoa6VXK2GbJojJszvV
validate(), parseMetadata(), parseSAMLRequest(), parseLogoutRequest()
and parseLogoutResponse() now read XML through xmlToObject, so the
library has one XML parser. With it go:

- xml2js and @types/xml2js (and sax with them);
- the containsDoctype screen in each of the four xml2js callers and in
  validate()'s xmlToJs: parseFromString runs the same check, and throws
  the same doctypeNotAllowedError;
- flattenObject: xmlToObject's collapse option produces the same shape
  while building it.

Successful results are unchanged. A snapshot of parseMetadata,
parseSAMLRequest, parseLogoutRequest, parseLogoutResponse and
parseIssuer over every file in test/assets and every string the test
suite parses is identical for every input that parses, before and after.
What changes, for the four non-validate() parsers:

- A document with more than one root element is rejected with
  multirootedXMLError ("multirooted xml not allowed.").
- An undeclared namespace prefix other than xsi and xs is rejected with
  xmldom's NamespaceError.
- Text and attribute values are normalized as XML requires (CRLF to LF;
  newlines and tabs in attribute values to spaces).
- A bare "&" followed by whitespace in text is accepted as a literal
  "&", as validate() already did.
- Malformed input fails with xmldom's message instead of sax's, for
  example "missing root element" instead of "Non-whitespace before
  first tag."; four tests that matched sax's wording now match
  xmldom's.

The test that relied on the two parsers disagreeing about a bare "&" is
removed; the WrapError path it covered stays covered by the DTD keyword
that sanitizeXML can assemble between validate()'s two parses.

BREAKING CHANGE: parseMetadata(), parseSAMLRequest(),
parseLogoutRequest() and parseLogoutResponse() reject multi-rooted
documents and undeclared namespace prefixes (except xsi and xs), and
report malformed XML with different messages.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LkWpdoa6VXK2GbJojJszvV
@deepakprabhakara
deepakprabhakara added this pull request to stack #1124 October 12, 2026 17:01
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 10 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 74c3612d-1b73-4edd-9297-74400fa59f17

📥 Commits

Reviewing files that changed from the base of the PR and between b5a44c8 and a717508.


⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json

📒 Files selected for processing (14)
  • README.md
  • lib/logout.ts
  • lib/metadata.ts
  • lib/request.ts
  • lib/response.ts
  • lib/utils.ts
  • lib/xml.ts
  • package.json
  • test/lib/logout.spec.ts
  • test/lib/metadata.spec.ts
  • test/lib/request.spec.ts
  • test/lib/response.spec.ts
  • test/lib/utils.spec.ts
  • test/lib/xml.spec.ts

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

xml2js ignored an XML declaration wherever it appeared; xmldom rejects
one that is not the very first thing in the document ("processing
instruction at position N is an xml declaration which is only at the
start of the document"). After b2e7366 (the switch to xmldom),
parseMetadata, parseSAMLRequest and the logout parsers rejected a
document with a newline, a BOM followed by whitespace, or a comment
before the declaration. Pasted or hand-edited metadata often looks like
that, and two of Polis's own metadata fixtures
(test/sso/data/metadata/noentityID and nobinding) start with a comment
and then the declaration; both parse at 44c0bd6 and failed here.

xmlToObject now drops such a misplaced declaration before parsing. The
comment pattern cannot run past its own "-->", so it cannot backtrack
exponentially; a first version that could took seconds on 22 leading
comments, and a test with 40 now pins that.

Found by differential fuzzing against xml2js 0.6.2, which the earlier
checks (the suite's own inputs and test/assets) did not cover.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LkWpdoa6VXK2GbJojJszvV
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.

1 participant