Repository navigation
release 0.14.0 - #3
Merged
Merged
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Smart quote stack corrupts after pairing
- Leave no longer restores quotes.length to the watermark after a transparent mark; it drops that frame's remaining delimiters and never grows the stack, so a later quote no longer reads undefined.
Or push these changes by commenting:
@cursor push 642d3342f7
Preview (642d3342f7)
diff --git a/src/engine/native/__tests__/smart-punctuation.test.ts b/src/engine/native/__tests__/smart-punctuation.test.ts
--- a/src/engine/native/__tests__/smart-punctuation.test.ts
+++ b/src/engine/native/__tests__/smart-punctuation.test.ts
@@ -173,6 +173,36 @@
expect((inlines(doc)[1] as { children: Inline[] }).children[0]).toMatchObject({ value: 'b” c' });
});
+ test('pairing across a mark does not leave a hole for a later quote', () => {
+ // The inner closer splices the outer opener, so the stack is shorter than
+ // the mark's watermark. Restoring `quotes.length` to that watermark used
+ // to insert `undefined`; the next `"` then threw in `resolveQuote`.
+ const doc = parse('"hello *world" and* more"\n');
+ expect(inlines(doc)[0]).toMatchObject({ kind: 'text', value: '“hello ' });
+ expect((inlines(doc)[1] as { children: Inline[] }).children[0]).toMatchObject({
+ value: 'world” and',
+ });
+ expect(inlines(doc)[2]).toMatchObject({ kind: 'text', value: ' more”' });
+ });
+
+ test('text after a cross-mark pair still flushes', () => {
+ const doc = parse('"a *b" c* d\n');
+ expect(inlines(doc)[0]).toMatchObject({ kind: 'text', value: '“a ' });
+ expect((inlines(doc)[1] as { children: Inline[] }).children[0]).toMatchObject({ value: 'b” c' });
+ expect(inlines(doc)[2]).toMatchObject({ kind: 'text', value: ' d' });
+ });
+
+ test('an enclosed opener that shifted into the watermark cannot pair past the mark', () => {
+ // The `"` closer consumes the outer opener; the inner `'` slides into that
+ // slot. Truncating to the watermark would keep it and pair `baz'`.
+ const doc = parse('"hello *\'foo" bar* baz\'\n');
+ expect(inlines(doc)[0]).toMatchObject({ kind: 'text', value: '“hello ' });
+ expect((inlines(doc)[1] as { children: Inline[] }).children[0]).toMatchObject({
+ value: '’foo” bar',
+ });
+ expect(inlines(doc)[2]).toMatchObject({ kind: 'text', value: ' baz’' });
+ });
+
test('an opener inside a resolved emphasis cannot pair past it', () => {
// cmark drops every delimiter inside a resolved emphasis, so the `"` opened there is gone.
const doc = parse('*a "b* c"\n');
diff --git a/src/engine/native/decode.ts b/src/engine/native/decode.ts
--- a/src/engine/native/decode.ts
+++ b/src/engine/native/decode.ts
@@ -198,7 +198,15 @@
closeFrame(frame, stack[stack.length - 1], ctx);
if (smart) {
// Transparent emphasis too: cmark drops the delimiters a resolved emphasis encloses.
- ctx.quotes.length = frame.quotesAtOpen;
+ // A closer inside the mark may have spliced an opener from below `quotesAtOpen`,
+ // so the stack can be shorter than that watermark. Never grow it back — that
+ // inserts a hole the next closer would read — and drop this frame's remaining
+ // delimiters even if they shifted into those reserved slots.
+ let w = 0;
+ for (let i = 0; i < ctx.quotes.length; i += 1) {
+ if (ctx.quotes[i].frame !== frame) ctx.quotes[w++] = ctx.quotes[i];
+ }
+ ctx.quotes.length = Math.min(w, frame.quotesAtOpen);
ctx.quoteBottom = frame.quoteBottomAtOpen;
}
break;You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit a5682b0. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Note
Medium Risk
Touches the md4c wire format, span widening, and native Android/iOS hosts that every consumer compiles; release now gates on full app builds but still does not exercise runtime selection behavior on device.
Overview
Release 0.14.0 bumps the package and documents a large set of engine, native-host, and packaging fixes in
CHANGELOG.md, with README and architecture docs brought in line.Release gates: Adds
native-build.ymland wires it intorelease.ymlso publish waits on packing the tarball into a fresh React Native app and building Android (Gradle + library unit tests) and iOS (CocoaPods + xcodebuild). Local parity vianpm run check:app:android/check:app:ios(scripts/build-test-app.sh). CI pinsnode-gyp@13.1.0;check-unreleased-breakingnow rejects BREAKING notes on non-minor (pre-1.0) version numbers.Android / iOS hosts: Fixes Kotlin compile failures in
SelectableRunHostView.kt(undefinedpressed,textClassifierunder Kotlin 2). iOS skips redundant attributed-string work when Fabric republishes the same state handle.Native parser & decoder: Vendors md4c patch
0001-fence-closedand exposeskDetailFenceClosedso fenced-code widening no longer mis-closes blocks or scans exponentially on long>lines. Link-tail widening follows link grammar (linear on pathological inputs); thematic breaks inside lists/blockquotes get real spans. AddsmaxSourceLength(default 1 MiB UTF-16) enforced before parse.html: { allow }/extractLinksuse iterative transforms to avoid stack overflow; decoder hardens bad event ranges and invalid UTF-8 in the string table. Smart quotes pair likecmark --smart.Packaging: Podspec floor iOS 15.1;
package.jsonexports./dist/view/codeBlocksunder thereact-nativecondition; Node harness documented as shipped behind./node.Reviewed by Cursor Bugbot for commit 22d8d93. Bugbot is set up for automated code reviews on this repo. Configure here.