Skip to content

fix: Turtle serializer abbreviates typed literals without validating lexical forms (#772) - #827

Draft
jeswr wants to merge 2 commits into
mainfrom
fix/issue-772-boolean-true-serialization
Draft

fix: Turtle serializer abbreviates typed literals without validating lexical forms (#772)#827
jeswr wants to merge 2 commits into
mainfrom
fix/issue-772-boolean-true-serialization

Conversation

@jeswr

@jeswr jeswr commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🚧 DRAFT — Note: this is an agent-generated draft PR (part of the agent-assisted triage announced in #823). It is for @jeswr to review — please do not merge or mark ready-for-review until he has signed off.

Fixes #772. Part of the triage programme tracked in #824.

Problem

atomicTermToN3 (src/serializer.js) abbreviates xsd:integer / xsd:decimal / xsd:double / xsd:boolean literals to native Turtle tokens based only on the datatype URI, without checking that the lexical form is valid for that datatype. Originally reported for booleans in #772, generalized to the whole class after review:

Input literal Before After
"true"^^xsd:boolean falsevalue flipped (the #772 report) true
"false" / "1" / "0" ^^xsd:boolean false / true / false unchanged
"yes"^^xsd:boolean (invalid) false — value lost "yes"^^xsd:boolean
"abc"^^xsd:integer (invalid) bare abc — invalid Turtle, datatype lost "abc"^^xsd:integer
"1.2.3"^^xsd:decimal (invalid) 1.2.3 — invalid Turtle "1.2.3"^^xsd:decimal
"2."^^xsd:decimal (valid XSD; Turtle needs a digit after the dot) 2. — invalid Turtle 2.0
"NaN" / "INF" / "-INF" ^^xsd:double (valid XSD; no Turtle DOUBLE form) NaN.0e0 etc. — mangled "NaN"^^xsd:double etc.
"abc"^^xsd:double (invalid) abc.0e0 — mangled "abc"^^xsd:double

Fix

Each of the four abbreviation cases now abbreviates only when the lexical form is valid for the datatype and expressible as a Turtle token:

  • xsd:integer/^[+-]?[0-9]+$/
  • xsd:decimal/^[+-]?(?:[0-9]+\.?[0-9]*|\.[0-9]+)$/, then normalized so the token has a digit after the dot (55.0, 2.2.0)
  • xsd:double/^[+-]?(?:[0-9]+\.?[0-9]*|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/ (excludes INF/-INF/NaN), then the existing ./e normalization
  • xsd:booleantrue/1true, false/0false

Anything else falls through to the existing verbose "value"^^datatype path, so serialization is lossless and always emits valid Turtle. Diff: src/serializer.js +17/−1; everything else is tests.

Ecosystem backward-compatibility assessment

  • Serializer-only — parsing is untouched (read lenient, write strict).
  • Valid, correctly-serialized forms are byte-identical. No tests/serialize/*-ref.* golden fixture changes; the full fixture corpus serializes identically (CI test:serialize green on this head).
  • Output changes only where the previous output was wrong — the table rows above: a flipped value, lost data, or non-conformant Turtle. Every changed output is valid Turtle and round-trips with value and datatype preserved.
  • Who the Turtle serializer mis‑normalizes xsd:boolean literal "true" as "false" #772 flip actually hit: booleans stored with the standard lexical form true — e.g. minted by applications via lit('true', undefined, XSD.boolean), or imported from RDF/JS-ecosystem libraries (N3.js et al.) that keep the canonical lexical form. Booleans from rdflib's own Turtle parser or Literal.fromBoolean are stored as '1'/'0' and always serialized correctly, so SolidOS/NSS round-trips through rdflib's own parser are unaffected.
  • Related: Boolean literals parsed as "0", "1" #147 (the parser normalizes true/false to '1'/'0' on parse) is untouched here — but both lexical conventions now serialize to correct tokens.
  • Semver: no API change; suggest release-patch (pure bug fix), though release-minor is defensible if any serializer-output delta is treated as behavioural.

Tests

Extends the existing tests/unit/serialize-test.js (no new file):

  • booleans: valid forms (true/false/1/0) unchanged; invalid forms (yes, TRUE, 2, "", 01) serialize verbosely
  • new integer/decimal/double blocks: valid forms abbreviate exactly as before; invalid forms serialize verbosely
  • serialize→parse round-trip tests asserting value + datatype are preserved for every invalid lexical form (no data loss)

CI is green on this head (Node 22.x / 24.x: unit + serialize golden fixtures + type tests + typedoc).

Relationship to #830

#830 (term-level serialization rework) supersedes this PR and subsumes this fix at its term layer. This PR stands as the minimal, self-contained alternative if the larger rework is not taken — whichever lands, the other should be closed or rebased accordingly.


@jeswr — over to you for review; leaving as draft.

#772)

The Turtle serializer normalized xsd:boolean literals by only checking
for the lexical form "1", so literals with the (most common) lexical
form "true" were silently serialized as "false", corrupting data on
round-trip.

Accept both canonical ("true"/"false") and numeric ("1"/"0") lexical
forms of the xsd:boolean lexical space when normalizing, and add unit
tests covering all four forms.

Fixes #772

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread src/serializer.js Outdated
Addresses @jeswr's review on #827: the Turtle serializer abbreviated
xsd:integer/decimal/double/boolean literals to native tokens based only
on the datatype URI, without checking the lexical form. Invalid forms
were mangled or silently lost:

- lit('yes', xsd:boolean) serialized as false (value lost)
- lit('abc', xsd:integer) serialized as bare abc (invalid Turtle)
- lit('1.2.3', xsd:decimal) serialized as 1.2.3 (invalid Turtle)
- lit('NaN'/'INF', xsd:double) serialized as NaN.0e0 (mangled)

Now each case abbreviates only when the value is a valid lexical form
that Turtle can express natively, and otherwise falls through to the
verbose "value"^^datatype serialization, so round-trips are lossless.
INF/-INF/NaN are valid xsd:double values but have no native Turtle
DOUBLE token, so they also serialize verbosely. Trailing-dot decimals
(e.g. "2.") are valid xsd:decimal and now normalize to a Turtle-valid
token ("2.0") instead of emitting invalid syntax.

Adds native/verbose serialization tests for all four datatypes plus
serialize-parse round-trip tests asserting no data loss for invalid
lexical forms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jeswr

jeswr commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Note: agent-generated update, for @jeswr to review.

Addressed the review comment by broadening the fix from booleans to the whole class of datatype-abbreviation bugs: in atomicTermToN3, native Turtle abbreviation of xsd:integer / xsd:decimal / xsd:double / xsd:boolean literals is now guarded by lexical-form validation. Invalid (or Turtle-inexpressible) lexical forms fall through to the verbose "value"^^datatype serialization — no data loss, no invalid Turtle.

Concretely fixed:

  • "yes"^^xsd:boolean no longer flips to false; "TRUE", "2", "", "01" also go verbose
  • "abc"/"1.5"/"0x10"^^xsd:integer no longer emit bare invalid tokens
  • "1.2.3"/"."/"1e5"^^xsd:decimal go verbose; valid-XSD-but-not-Turtle "2." normalizes to 2.0
  • "NaN"/"INF"/"-INF"^^xsd:double (valid xsd:double, no Turtle DOUBLE form) and "abc" no longer emit NaN.0e0-style garbage

Valid lexical forms serialize exactly as before. Tests: per-datatype native/verbose assertions plus serialize→parse round-trips asserting value+datatype preservation for every invalid form (30 new tests; unit suite 338 passing, full npm test + npm run lint clean).

@jeswr jeswr changed the title fix: Turtle serializer mis-normalizes xsd:boolean "true" as "false" (#772) fix: Turtle serializer abbreviates typed literals without validating lexical forms (#772) Jul 4, 2026

@jeswr jeswr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

This should be flagged on the linkeddata/rdflib, solidOs and discourse channels before merging in case this affects consumers of the library in unexpected ways.

May need to reserve for an mver.

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.

Turtle serializer mis‑normalizes xsd:boolean literal "true" as "false"

1 participant