diff --git a/.changeset/dirty-windows-marry.md b/.changeset/dirty-windows-marry.md new file mode 100644 index 0000000..1c03d7d --- /dev/null +++ b/.changeset/dirty-windows-marry.md @@ -0,0 +1,5 @@ +--- +"neogrok": patch +--- + +Handle breaking change in ChunkMatch newlines diff --git a/src/lib/server/content-parser.test.ts b/src/lib/server/content-parser.test.ts index b53eafc..74ec30f 100644 --- a/src/lib/server/content-parser.test.ts +++ b/src/lib/server/content-parser.test.ts @@ -37,23 +37,23 @@ describe("parseFileNameMatch", () => { describe("parseChunkMatch", () => { it("parses chunk matches", () => { // Single line. - expect(parseChunkMatch(Buffer.from("foo"), [])).toEqual([ + expect(parseChunkMatch(Buffer.from("foo\n"), [])).toEqual([ { text: "foo", matchRanges: [] }, ]); - expect(parseChunkMatch(Buffer.from("foo"), [{ start: 0, end: 3 }])).toEqual( - [{ text: "foo", matchRanges: [{ start: 0, end: 3 }] }], - ); - expect(parseChunkMatch(Buffer.from("foo"), [{ start: 0, end: 2 }])).toEqual( - [{ text: "foo", matchRanges: [{ start: 0, end: 2 }] }], - ); - expect(parseChunkMatch(Buffer.from("foo"), [{ start: 1, end: 3 }])).toEqual( - [{ text: "foo", matchRanges: [{ start: 1, end: 3 }] }], - ); - expect(parseChunkMatch(Buffer.from("foo"), [{ start: 1, end: 2 }])).toEqual( - [{ text: "foo", matchRanges: [{ start: 1, end: 2 }] }], - ); expect( - parseChunkMatch(Buffer.from("foo"), [ + parseChunkMatch(Buffer.from("foo\n"), [{ start: 0, end: 3 }]), + ).toEqual([{ text: "foo", matchRanges: [{ start: 0, end: 3 }] }]); + expect( + parseChunkMatch(Buffer.from("foo\n"), [{ start: 0, end: 2 }]), + ).toEqual([{ text: "foo", matchRanges: [{ start: 0, end: 2 }] }]); + expect( + parseChunkMatch(Buffer.from("foo\n"), [{ start: 1, end: 3 }]), + ).toEqual([{ text: "foo", matchRanges: [{ start: 1, end: 3 }] }]); + expect( + parseChunkMatch(Buffer.from("foo\n"), [{ start: 1, end: 2 }]), + ).toEqual([{ text: "foo", matchRanges: [{ start: 1, end: 2 }] }]); + expect( + parseChunkMatch(Buffer.from("foo\n"), [ { start: 1, end: 2 }, { start: 2, end: 3 }, ]), @@ -68,42 +68,42 @@ describe("parseChunkMatch", () => { ]); // Multi-line. - expect(parseChunkMatch(Buffer.from("foo\n"), [])).toEqual([ + expect(parseChunkMatch(Buffer.from("foo\n\n"), [])).toEqual([ { text: "foo", matchRanges: [] }, { text: "", matchRanges: [] }, ]); expect( - parseChunkMatch(Buffer.from("foo\n"), [{ start: 0, end: 3 }]), + parseChunkMatch(Buffer.from("foo\n\n"), [{ start: 0, end: 3 }]), ).toEqual([ { text: "foo", matchRanges: [{ start: 0, end: 3 }] }, { text: "", matchRanges: [] }, ]); expect( - parseChunkMatch(Buffer.from("foo\n"), [{ start: 0, end: 4 }]), + parseChunkMatch(Buffer.from("foo\n\n"), [{ start: 0, end: 4 }]), ).toEqual([ { text: "foo", matchRanges: [{ start: 0, end: 3 }] }, { text: "", matchRanges: [] }, ]); - expect(parseChunkMatch(Buffer.from("foo\nbar"), [])).toEqual([ + expect(parseChunkMatch(Buffer.from("foo\nbar\n"), [])).toEqual([ { text: "foo", matchRanges: [] }, { text: "bar", matchRanges: [] }, ]); expect( - parseChunkMatch(Buffer.from("foo\nbar"), [{ start: 0, end: 3 }]), + parseChunkMatch(Buffer.from("foo\nbar\n"), [{ start: 0, end: 3 }]), ).toEqual([ { text: "foo", matchRanges: [{ start: 0, end: 3 }] }, { text: "bar", matchRanges: [] }, ]); expect( - parseChunkMatch(Buffer.from("foo\nbar"), [{ start: 0, end: 4 }]), + parseChunkMatch(Buffer.from("foo\nbar\n"), [{ start: 0, end: 4 }]), ).toEqual([ { text: "foo", matchRanges: [{ start: 0, end: 3 }] }, { text: "bar", matchRanges: [] }, ]); expect( - parseChunkMatch(Buffer.from("foo\nbar"), [ + parseChunkMatch(Buffer.from("foo\nbar\n"), [ { start: 0, end: 1 }, { start: 2, end: 5 }, ]), diff --git a/src/lib/server/content-parser.ts b/src/lib/server/content-parser.ts index 0216057..11980f7 100644 --- a/src/lib/server/content-parser.ts +++ b/src/lib/server/content-parser.ts @@ -132,11 +132,10 @@ Array => { } } - // Conclude the current line. Note that if `currentLineText` is length 0, - // that is still semantically a line, namely an empty line. `Content` never - // naturally has a trailing newline; if there's a newline at the last byte, - // this indicates that there is a final line that is empty. - lines.push({ text: currentLineText, matchRanges: currentLineMatchRanges }); + if (currentLineText.length > 0) { + // Conclude the current line. + lines.push({ text: currentLineText, matchRanges: currentLineMatchRanges }); + } return lines; };