Skip to content

Commit

Permalink
Filter out invalid facets in RichText (bluesky-social#2933)
Browse files Browse the repository at this point in the history
* add failing test

* simplify test

* check facet was removed

* filter out invalid facets

* changeset
  • Loading branch information
mozzius authored Oct 31, 2024
1 parent 9ffeb52 commit e680d55
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-sheep-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@atproto/api": patch
---

Fix handling of invalid facets in RichText
8 changes: 6 additions & 2 deletions packages/api/src/rich-text/rich-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export class RichText {
this.facets = entitiesToFacets(this.unicodeText, props.entities)
}
if (this.facets) {
this.facets.sort(facetSort)
this.facets = this.facets.filter(facetFilter).sort(facetSort)
}
if (opts?.cleanNewlines) {
sanitizeRichText(this, { cleanNewlines: true }).copyInto(this)
Expand Down Expand Up @@ -378,7 +378,11 @@ export class RichText {
}
}

const facetSort = (a, b) => a.index.byteStart - b.index.byteStart
const facetSort = (a: Facet, b: Facet) => a.index.byteStart - b.index.byteStart

const facetFilter = (facet: Facet) =>
// discard negative-length facets. zero-length facets are valid
facet.index.byteStart <= facet.index.byteEnd

function entitiesToFacets(text: UnicodeString, entities: Entity[]): Facet[] {
const facets: Facet[] = []
Expand Down
44 changes: 44 additions & 0 deletions packages/api/tests/rich-text.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,48 @@ describe('RichText#segments', () => {
},
])
})

it("doesn't duplicate text when negative-length facets are present", () => {
const input = {
text: 'hello world',
facets: [
// invalid zero-length
{
features: [],
index: {
byteStart: 6,
byteEnd: 0,
},
},
// valid normal facet
{
features: [],
index: {
byteEnd: 11,
byteStart: 6,
},
},
// valid zero-length
{
features: [],
index: {
byteEnd: 0,
byteStart: 0,
},
},
],
}

const rt = new RichText(input)

let output = ''
for (const segment of rt.segments()) {
output += segment.text
}

expect(output).toEqual(input.text)

// invalid one should have been removed
expect(rt.facets?.length).toEqual(2)
})
})

0 comments on commit e680d55

Please sign in to comment.