Skip to content

🐛 Only strip enclosing delimiters that enclose the whole value - #604

Merged
MiWeiss merged 3 commits into
mainfrom
fix/enclosing-concatenation
Sep 3, 2026
Merged

🐛 Only strip enclosing delimiters that enclose the whole value#604
MiWeiss merged 3 commits into
mainfrom
fix/enclosing-concatenation

Conversation

@MiWeiss

@MiWeiss MiWeiss commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

_strip_enclosing only tests startswith/endswith, so any value built from several delimited parts is corrupted, then classified as enclosed and re-wrapped as a literal.

>>> _strip_enclosing("{intro} # {outro}")
('intro} # {outro', '{')
>>> _strip_enclosing('"')
('', '"')   # silent data loss

This contradicts the middleware's own docstring on concatenations.

Fix: strip only a pair enclosing the whole value. Brace depth, escape-aware; for quotes, no unescaped " at depth 0 inside. Everything else falls through to no-enclosing and is written verbatim.

Tests: 27 cases, including shapes that must still strip ({a {b} c}, {{nested}}, {}, "", escaped braces). Suite 2603 passed, from 2576.


🤖 Generated with Claude Code

@MiWeiss
MiWeiss force-pushed the fix/enclosing-concatenation branch 3 times, most recently from 94d484d to f313c6f Compare September 2, 2026 20:00
`_strip_enclosing` assumed a leading `{`/`"` is closed by the trailing one,
so concatenation expressions like `pages = {intro} # {outro}` or
`title = "x" # "y"` were stripped to corrupted, non-concatenation values and
misclassified as enclosed (and thus re-wrapped on write). A lone `"` was also
stripped to the empty string.

Brace stripping now tracks brace depth (ignoring backslash-escaped braces) and
only strips when the brace opened at index 0 is the one closed at the last
index; quote stripping only strips when no unescaped `"` occurs at brace-depth
zero in between. Everything else falls through to `no-enclosing`, which - as
the middleware docstring already demanded - makes such values round-trip
verbatim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MiWeiss
MiWeiss force-pushed the fix/enclosing-concatenation branch 2 times, most recently from 192ab12 to 5aa75ef Compare September 2, 2026 20:38
MiWeiss and others added 2 commits September 2, 2026 23:19
The `no-enclosing` demand and the delimiters it was derived from live in two
separate places: `{Foo} # {, Bar}` keeps its braces inside `field.value`, while
the demand sits on the field. The value-transforming middlewares deliberately
carry the demand across a value rewrite, so once such a middleware removes the
braces the demand is stale and the writer emits unparseable bibtex:

    author = {Doe, John} and {Roe, Jane}   ->   author = Doe, John and Roe, Jane

Rather than chase every middleware, `AddEnclosingMiddleware` now falls back to
the default enclosing whenever a `no-enclosing` value could not be read back in
one piece, i.e. when it has an unbalanced brace or a comma, equals sign or
newline outside braces and quotes.

The two `_is_enclosed_in_*` helpers now scan delimiters with a regex instead of
every character. This aligns their escaping with the splitter's mark regex,
where a delimiter is escaped iff directly preceded by a backslash (so `{\\}a}`
is stripped again), and removes the parse-time cost of the per-character scan:
3000 entries with a 1.2 KB abstract go back from 0.220 s to 0.105 s, against
0.104 s before this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MiWeiss
MiWeiss merged commit c5a3092 into main Sep 3, 2026
16 checks passed
@MiWeiss
MiWeiss deleted the fix/enclosing-concatenation branch September 3, 2026 18:48
MiWeiss added a commit that referenced this pull request Sep 3, 2026
`_is_enclosed_in_quotes` (added in #604) scanned every quoted value with
a regex, making the default parse stack ~4x slower on files with quoted
values. Skip the scan when the value contains no inner quote, and avoid
the slice copy in the corresponding brace fast path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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