From 88fe3e294293683be0cebfeae0b119266c06fce1 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween <5454374+emcsween@users.noreply.github.com> Date: Tue, 16 Apr 2024 09:03:34 -0400 Subject: [PATCH] Merge pull request #17910 from overleaf/em-comment-ids Include id in history Comment instances GitOrigin-RevId: 25b897e8e9e8d7b19dfe2d90d7f0cafeb5e6e97f --- libraries/overleaf-editor-core/lib/comment.js | 10 +- libraries/overleaf-editor-core/lib/file.js | 3 +- .../lib/file_data/comment_list.js | 52 +++++--- .../lib/file_data/index.js | 5 +- .../lib/file_data/string_file_data.js | 13 +- .../lib/operation/add_comment_operation.js | 35 ++++-- .../lib/operation/delete_comment_operation.js | 6 +- .../operation/edit_operation_transformer.js | 19 ++- .../operation/set_comment_state_operation.js | 4 +- libraries/overleaf-editor-core/lib/types.ts | 18 ++- .../test/add_comment_operation.test.js | 39 ++---- .../overleaf-editor-core/test/comment.test.js | 37 +++--- .../test/comments_list.test.js | 115 ++++++++---------- .../test/delete_comment_operation.test.js | 9 +- .../test/edit_operation.test.js | 25 ++-- .../overleaf-editor-core/test/file.test.js | 2 +- .../test/hash_file_data.test.js | 4 +- .../test/lazy_string_file_data.test.js | 4 +- .../test/operation.test.js | 4 +- .../test/string_file_data.test.js | 6 +- 20 files changed, 222 insertions(+), 188 deletions(-) diff --git a/libraries/overleaf-editor-core/lib/comment.js b/libraries/overleaf-editor-core/lib/comment.js index d638064f63..6523382754 100644 --- a/libraries/overleaf-editor-core/lib/comment.js +++ b/libraries/overleaf-editor-core/lib/comment.js @@ -21,10 +21,12 @@ class Comment { resolved = false /** + * @param {string} id * @param {ReadonlyArray} ranges * @param {boolean} [resolved] */ - constructor(ranges, resolved = false) { + constructor(id, ranges, resolved = false) { + this.id = id this.resolved = resolved this.ranges = this.mergeRanges(ranges) } @@ -87,7 +89,7 @@ class Comment { newRanges.push(new Range(cursor, length)) } - return new Comment(newRanges, this.resolved) + return new Comment(this.id, newRanges, this.resolved) } /** @@ -108,7 +110,7 @@ class Comment { } } - return new Comment(newRanges, this.resolved) + return new Comment(this.id, newRanges, this.resolved) } /** @@ -148,6 +150,7 @@ class Comment { */ toRaw() { return { + id: this.id, resolved: this.resolved, ranges: this.ranges.map(range => range.toRaw()), } @@ -189,6 +192,7 @@ class Comment { */ static fromRaw(rawComment) { return new Comment( + rawComment.id, rawComment.ranges.map(range => Range.fromRaw(range)), rawComment.resolved ) diff --git a/libraries/overleaf-editor-core/lib/file.js b/libraries/overleaf-editor-core/lib/file.js index 4fa8394e5d..b5fb0c6ffa 100644 --- a/libraries/overleaf-editor-core/lib/file.js +++ b/libraries/overleaf-editor-core/lib/file.js @@ -15,6 +15,7 @@ const StringFileData = require('./file_data/string_file_data') * @typedef {import("./types").ReadonlyBlobStore} ReadonlyBlobStore * @typedef {import("./types").StringFileRawData} StringFileRawData * @typedef {import("./types").CommentRawData} CommentRawData + * @typedef {import("./file_data/comment_list")} CommentList * @typedef {import("./operation/text_operation")} TextOperation * @typedef {{filterTrackedDeletes?: boolean}} FileGetContentOptions */ @@ -203,7 +204,7 @@ class File { /** * Get the comments for this file. * - * @return {CommentRawData[]} + * @return {CommentList} */ getComments() { return this.data.getComments() diff --git a/libraries/overleaf-editor-core/lib/file_data/comment_list.js b/libraries/overleaf-editor-core/lib/file_data/comment_list.js index b7be65b5dc..80b89dd434 100644 --- a/libraries/overleaf-editor-core/lib/file_data/comment_list.js +++ b/libraries/overleaf-editor-core/lib/file_data/comment_list.js @@ -2,28 +2,45 @@ const Comment = require('../comment') /** - * @typedef {import("../types").CommentsListRawData} CommentsListRawData + * @typedef {import("../types").CommentRawData} CommentRawData * @typedef {import("../range")} Range */ class CommentList { /** - * @param {Map} comments + * @param {Comment[]} comments */ constructor(comments) { - this.comments = comments + this.comments = new Map(comments.map(comment => [comment.id, comment])) } /** - * @returns {CommentsListRawData} + * @returns {IterableIterator} */ - getComments() { - return Array.from(this.comments).map(([commentId, comment]) => { - return { - id: commentId, - ...comment.toRaw(), - } - }) + [Symbol.iterator]() { + return this.comments.values() + } + + /** + * Return the length of the comment list + * + * @returns {number} + */ + get length() { + return this.comments.size + } + + /** + * Return the raw version of the comment list + * + * @returns {CommentRawData[]} + */ + toRaw() { + const raw = [] + for (const comment of this.comments.values()) { + raw.push(comment.toRaw()) + } + return raw } /** @@ -35,11 +52,10 @@ class CommentList { } /** - * @param {string} id * @param {Comment} newComment */ - add(id, newComment) { - this.comments.set(id, newComment) + add(newComment) { + this.comments.set(newComment.id, newComment) } /** @@ -50,14 +66,10 @@ class CommentList { } /** - * @param {CommentsListRawData} rawComments + * @param {CommentRawData[]} rawComments */ static fromRaw(rawComments) { - const comments = new Map() - for (const rawComment of rawComments) { - comments.set(rawComment.id, Comment.fromRaw(rawComment)) - } - return new CommentList(comments) + return new CommentList(rawComments.map(Comment.fromRaw)) } /** diff --git a/libraries/overleaf-editor-core/lib/file_data/index.js b/libraries/overleaf-editor-core/lib/file_data/index.js index 7d743ae34a..5137c778f7 100644 --- a/libraries/overleaf-editor-core/lib/file_data/index.js +++ b/libraries/overleaf-editor-core/lib/file_data/index.js @@ -1,3 +1,5 @@ +// @ts-check + 'use strict' const assert = require('check-types').assert @@ -17,6 +19,7 @@ let StringFileData = null * @typedef {import("../types").BlobStore} BlobStore * @typedef {import("../types").ReadonlyBlobStore} ReadonlyBlobStore * @typedef {import("../operation/edit_operation")} EditOperation + * @typedef {import("../file_data/comment_list")} CommentList * @typedef {import("../types").CommentRawData} CommentRawData */ @@ -190,7 +193,7 @@ class FileData { /** * @see File#getComments * @function - * @return {CommentRawData[]} + * @return {CommentList} * @abstract */ getComments() { diff --git a/libraries/overleaf-editor-core/lib/file_data/string_file_data.js b/libraries/overleaf-editor-core/lib/file_data/string_file_data.js index ef93b8790d..6e8859f219 100644 --- a/libraries/overleaf-editor-core/lib/file_data/string_file_data.js +++ b/libraries/overleaf-editor-core/lib/file_data/string_file_data.js @@ -11,7 +11,7 @@ const TrackedChangeList = require('./tracked_change_list') * @typedef {import("../types").StringFileRawData} StringFileRawData * @typedef {import("../operation/edit_operation")} EditOperation * @typedef {import("../types").BlobStore} BlobStore - * @typedef {import("../types").CommentsListRawData} CommentsListRawData + * @typedef {import("../types").CommentRawData} CommentRawData * @typedef {import("../types").TrackedChangeRawData} TrackedChangeRawData * @typedef {import('../types').RangesBlob} RangesBlob */ @@ -19,7 +19,7 @@ const TrackedChangeList = require('./tracked_change_list') class StringFileData extends FileData { /** * @param {string} content - * @param {CommentsListRawData} [rawComments] + * @param {CommentRawData[]} [rawComments] * @param {TrackedChangeRawData[]} [rawTrackedChanges] */ constructor(content, rawComments = [], rawTrackedChanges = []) { @@ -49,9 +49,8 @@ class StringFileData extends FileData { toRaw() { const raw = { content: this.content } - const comments = this.getComments() - if (comments.length) { - raw.comments = comments + if (this.comments.length) { + raw.comments = this.comments.toRaw() } if (this.trackedChanges.length) { @@ -110,7 +109,7 @@ class StringFileData extends FileData { /** @inheritdoc */ getComments() { - return this.comments.getComments() + return this.comments } /** @@ -135,7 +134,7 @@ class StringFileData extends FileData { if (this.comments.comments.size || this.trackedChanges.length) { /** @type {RangesBlob} */ const ranges = { - comments: this.getComments(), + comments: this.getComments().toRaw(), trackedChanges: this.trackedChanges.toRaw(), } const rangesBlob = await blobStore.putObject(ranges) diff --git a/libraries/overleaf-editor-core/lib/operation/add_comment_operation.js b/libraries/overleaf-editor-core/lib/operation/add_comment_operation.js index 0e15aebc94..f8b0cc5878 100644 --- a/libraries/overleaf-editor-core/lib/operation/add_comment_operation.js +++ b/libraries/overleaf-editor-core/lib/operation/add_comment_operation.js @@ -1,6 +1,7 @@ // @ts-check const core = require('../../index') const Comment = require('../comment') +const Range = require('../range') const EditOperation = require('./edit_operation') /** @@ -16,12 +17,20 @@ const EditOperation = require('./edit_operation') class AddCommentOperation extends EditOperation { /** * @param {string} commentId - * @param {Comment} comment + * @param {ReadonlyArray} ranges + * @param {boolean} resolved */ - constructor(commentId, comment) { + constructor(commentId, ranges, resolved = false) { super() + + /** @readonly */ this.commentId = commentId - this.comment = comment + + /** @readonly */ + this.ranges = ranges + + /** @readonly */ + this.resolved = resolved } /** @@ -30,8 +39,9 @@ class AddCommentOperation extends EditOperation { */ toJSON() { return { - ...this.comment.toRaw(), commentId: this.commentId, + ranges: this.ranges.map(range => range.toRaw()), + resolved: this.resolved, } } @@ -39,7 +49,9 @@ class AddCommentOperation extends EditOperation { * @param {StringFileData} fileData */ apply(fileData) { - fileData.comments.add(this.commentId, this.comment) + fileData.comments.add( + new Comment(this.commentId, this.ranges, this.resolved) + ) } /** @@ -90,8 +102,11 @@ class AddCommentOperation extends EditOperation { other instanceof core.SetCommentStateOperation && other.commentId === this.commentId ) { - const comment = new Comment(this.comment.ranges, other.resolved) - return new AddCommentOperation(this.commentId, comment) + return new AddCommentOperation( + this.commentId, + this.ranges, + other.resolved + ) } throw new Error( @@ -105,7 +120,11 @@ class AddCommentOperation extends EditOperation { * @returns {AddCommentOperation} */ static fromJSON(raw) { - return new AddCommentOperation(raw.commentId, Comment.fromRaw(raw)) + return new AddCommentOperation( + raw.commentId, + raw.ranges.map(Range.fromRaw), + raw.resolved ?? false + ) } } diff --git a/libraries/overleaf-editor-core/lib/operation/delete_comment_operation.js b/libraries/overleaf-editor-core/lib/operation/delete_comment_operation.js index d18c264d26..30dd58c860 100644 --- a/libraries/overleaf-editor-core/lib/operation/delete_comment_operation.js +++ b/libraries/overleaf-editor-core/lib/operation/delete_comment_operation.js @@ -50,7 +50,11 @@ class DeleteCommentOperation extends EditOperation { return new EditNoOperation() } - return new core.AddCommentOperation(this.commentId, comment) + return new core.AddCommentOperation( + comment.id, + comment.ranges.slice(), + comment.resolved + ) } /** diff --git a/libraries/overleaf-editor-core/lib/operation/edit_operation_transformer.js b/libraries/overleaf-editor-core/lib/operation/edit_operation_transformer.js index 8bf1d187d9..719ef5b50a 100644 --- a/libraries/overleaf-editor-core/lib/operation/edit_operation_transformer.js +++ b/libraries/overleaf-editor-core/lib/operation/edit_operation_transformer.js @@ -29,8 +29,16 @@ class EditOperationTransformer { createTransformer(TextOperation, SetCommentStateOperation, noConflict), createTransformer(TextOperation, AddCommentOperation, (a, b) => { // apply the text operation to the comment - const movedComment = b.comment.applyTextOperation(a, b.commentId) - return [a, new AddCommentOperation(b.commentId, movedComment)] + const originalComment = new Comment(b.commentId, b.ranges, b.resolved) + const movedComment = originalComment.applyTextOperation(a, b.commentId) + return [ + a, + new AddCommentOperation( + movedComment.id, + movedComment.ranges, + movedComment.resolved + ), + ] }), createTransformer(AddCommentOperation, AddCommentOperation, (a, b) => { if (a.commentId === b.commentId) { @@ -50,8 +58,11 @@ class EditOperationTransformer { SetCommentStateOperation, (a, b) => { if (a.commentId === b.commentId) { - const mergedComment = new Comment(a.comment.ranges, b.resolved) - const newA = new AddCommentOperation(a.commentId, mergedComment) + const newA = new AddCommentOperation( + a.commentId, + a.ranges, + b.resolved + ) return [newA, b] } return [a, b] diff --git a/libraries/overleaf-editor-core/lib/operation/set_comment_state_operation.js b/libraries/overleaf-editor-core/lib/operation/set_comment_state_operation.js index 9d9313add1..5bc1ec48c6 100644 --- a/libraries/overleaf-editor-core/lib/operation/set_comment_state_operation.js +++ b/libraries/overleaf-editor-core/lib/operation/set_comment_state_operation.js @@ -42,8 +42,8 @@ class SetCommentStateOperation extends EditOperation { apply(fileData) { const comment = fileData.comments.getComment(this.commentId) if (comment) { - const newComment = new Comment(comment.ranges, this.resolved) - fileData.comments.add(this.commentId, newComment) + const newComment = new Comment(comment.id, comment.ranges, this.resolved) + fileData.comments.add(newComment) } } diff --git a/libraries/overleaf-editor-core/lib/types.ts b/libraries/overleaf-editor-core/lib/types.ts index f38696a815..4c63928983 100644 --- a/libraries/overleaf-editor-core/lib/types.ts +++ b/libraries/overleaf-editor-core/lib/types.ts @@ -11,7 +11,7 @@ export type BlobStore = { export type ReadonlyBlobStore = Pick export type RangesBlob = { - comments: CommentsListRawData + comments: CommentRawData[] trackedChanges: TrackedChangeRawData[] } @@ -21,6 +21,7 @@ type Range = { } export type CommentRawData = { + id: string ranges: Range[] resolved?: boolean } @@ -36,11 +37,9 @@ export type TrackingPropsRawData = { ts: string } -export type CommentsListRawData = Array<{ id: string } & CommentRawData> - export type StringFileRawData = { content: string - comments?: CommentsListRawData + comments?: CommentRawData[] trackedChanges?: TrackedChangeRawData[] } @@ -69,11 +68,18 @@ export type RawTextOperation = { textOperation: RawScanOp[] } -export type RawAddCommentOperation = CommentRawData & { commentId: string } +export type RawAddCommentOperation = { + commentId: string + ranges: Range[] + resolved?: boolean +} export type RawDeleteCommentOperation = { deleteComment: string } -export type RawSetCommentStateOperation = { commentId: string; resolved: boolean } +export type RawSetCommentStateOperation = { + commentId: string + resolved: boolean +} export type RawEditOperation = | RawTextOperation diff --git a/libraries/overleaf-editor-core/test/add_comment_operation.test.js b/libraries/overleaf-editor-core/test/add_comment_operation.test.js index b7439b4b0c..28ca7857fc 100644 --- a/libraries/overleaf-editor-core/test/add_comment_operation.test.js +++ b/libraries/overleaf-editor-core/test/add_comment_operation.test.js @@ -1,7 +1,7 @@ // @ts-check const { expect } = require('chai') const { AddCommentOperation, DeleteCommentOperation } = require('..') -const Comment = require('../lib/comment') +const Range = require('../lib/range') const StringFileData = require('../lib/file_data/string_file_data') describe('AddCommentOperation', function () { @@ -13,22 +13,12 @@ describe('AddCommentOperation', function () { }) expect(op).to.be.instanceOf(AddCommentOperation) expect(op.commentId).to.equal('123') - expect(op.comment).to.be.instanceOf(Comment) - expect(op.comment.resolved).to.be.true + expect(op.ranges[0]).to.be.instanceOf(Range) + expect(op.resolved).to.be.true }) it('should convert to JSON', function () { - const op = new AddCommentOperation( - '123', - Comment.fromRaw({ - ranges: [ - { - pos: 0, - length: 1, - }, - ], - }) - ) + const op = new AddCommentOperation('123', [new Range(0, 1)]) expect(op.toJSON()).to.eql({ commentId: '123', resolved: false, @@ -43,12 +33,9 @@ describe('AddCommentOperation', function () { it('should apply operation', function () { const fileData = new StringFileData('abc') - const op = new AddCommentOperation( - '123', - Comment.fromRaw({ ranges: [{ pos: 0, length: 1 }] }) - ) + const op = new AddCommentOperation('123', [new Range(0, 1)]) op.apply(fileData) - expect(fileData.getComments()).to.eql([ + expect(fileData.getComments().toRaw()).to.eql([ { id: '123', ranges: [{ pos: 0, length: 1 }], @@ -59,12 +46,9 @@ describe('AddCommentOperation', function () { it('should invert operation', function () { const fileData = new StringFileData('abc') - const op = new AddCommentOperation( - '123', - Comment.fromRaw({ ranges: [{ pos: 0, length: 1 }] }) - ) + const op = new AddCommentOperation('123', [new Range(0, 1)]) op.apply(fileData) - expect(fileData.getComments()).to.eql([ + expect(fileData.getComments().toRaw()).to.eql([ { id: '123', ranges: [{ pos: 0, length: 1 }], @@ -74,14 +58,11 @@ describe('AddCommentOperation', function () { const invertedOp = op.invert() invertedOp.apply(fileData) - expect(fileData.getComments()).to.eql([]) + expect(fileData.getComments().toRaw()).to.eql([]) }) it('should compose with DeleteCommentOperation', function () { - const addOp = new AddCommentOperation( - '123', - Comment.fromRaw({ ranges: [{ pos: 0, length: 1 }] }) - ) + const addOp = new AddCommentOperation('123', [new Range(0, 1)]) const deleteOp = new DeleteCommentOperation('123') expect(addOp.canBeComposedWith(deleteOp)).to.be.true diff --git a/libraries/overleaf-editor-core/test/comment.test.js b/libraries/overleaf-editor-core/test/comment.test.js index 909de6d548..f235c9efd6 100644 --- a/libraries/overleaf-editor-core/test/comment.test.js +++ b/libraries/overleaf-editor-core/test/comment.test.js @@ -7,77 +7,77 @@ const Range = require('../lib/range') describe('Comment', function () { it('should move ranges to the right of insert', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const resComment = comment.applyInsert(3, 5, false) expect(resComment.ranges).to.eql([new Range(10, 10)]) }) describe('applyInsert', function () { it('should insert 1 char before the range', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) expect(comment.applyInsert(4, 1).ranges).to.eql([new Range(6, 10)]) }) it('should insert 1 char at the edge, without expandCommand', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) expect(comment.applyInsert(5, 1).ranges).to.eql([new Range(6, 10)]) }) it('should insert 1 char at the edge, with expandCommand', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) expect(comment.applyInsert(5, 1, true).ranges).to.eql([new Range(5, 11)]) }) it('should expand the range after insert inside it', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) expect(comment.applyInsert(6, 1, true).ranges).to.eql([new Range(5, 11)]) }) }) it('should split the range if inside another and expandComment is false', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyInsert(6, 10, false) expect(commentRes.ranges).to.eql([new Range(5, 1), new Range(16, 9)]) }) it('should insert the range if expandComment is false', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyInsert(14, 10, false) expect(commentRes.ranges).to.eql([new Range(5, 9), new Range(24, 1)]) }) it('should move the range if insert is at range start and expandComment is false', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyInsert(5, 10, false) expect(commentRes.ranges).to.eql([new Range(15, 10)]) }) it('should ignore the range if insert is at range end and expandComment is false', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyInsert(15, 10, false) expect(commentRes.ranges).to.eql([new Range(5, 10)]) }) it('should expand the range after inserting on the edge of it if expandComment is true', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyInsert(15, 10, true) expect(commentRes.ranges).to.eql([new Range(5, 20)]) }) it('should move comment ranges if delete is before it', function () { - const comment = new Comment([new Range(5, 10)]) + const comment = new Comment('c1', [new Range(5, 10)]) const commentRes = comment.applyDelete(new Range(3, 5)) expect(commentRes.ranges).to.eql([new Range(3, 7)]) }) it('should merge ranges after delete', function () { - const comment = new Comment([new Range(5, 10), new Range(20, 10)]) + const comment = new Comment('c1', [new Range(5, 10), new Range(20, 10)]) const commentRes = comment.applyDelete(new Range(7, 18)) expect(commentRes.ranges).to.eql([new Range(5, 7)]) }) it('should merge overlapping ranges', function () { - const comment = new Comment([ + const comment = new Comment('c1', [ new Range(5, 10), new Range(15, 20), new Range(50, 10), @@ -86,7 +86,7 @@ describe('Comment', function () { }) it('should merge unsorted ranges', function () { - const comment = new Comment([ + const comment = new Comment('c1', [ new Range(15, 20), new Range(50, 10), new Range(5, 10), @@ -96,12 +96,17 @@ describe('Comment', function () { it('should throw error when ranges overlap', function () { expect( - () => new Comment([new Range(5, 10), new Range(10, 5), new Range(50, 10)]) + () => + new Comment('c1', [ + new Range(5, 10), + new Range(10, 5), + new Range(50, 10), + ]) ).to.throw() }) it('should join touching ranges', function () { - const comment = new Comment([ + const comment = new Comment('c1', [ new Range(5, 10), new Range(15, 5), new Range(50, 10), diff --git a/libraries/overleaf-editor-core/test/comments_list.test.js b/libraries/overleaf-editor-core/test/comments_list.test.js index 6c29b79873..31f7ac8626 100644 --- a/libraries/overleaf-editor-core/test/comments_list.test.js +++ b/libraries/overleaf-editor-core/test/comments_list.test.js @@ -8,15 +8,13 @@ const Range = require('../lib/range') describe('commentList', function () { it('checks if toRaw() returns a correct comment list', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)])], - ['comm2', new Comment([new Range(20, 5)])], - ['comm3', new Comment([new Range(30, 15)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)]), + new Comment('comm2', [new Range(20, 5)]), + new Comment('comm3', [new Range(30, 15)]), + ]) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, { @@ -28,16 +26,15 @@ describe('commentList', function () { }) it('should get a comment by id', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)])], - ['comm3', new Comment([new Range(30, 15)])], - ['comm2', new Comment([new Range(20, 5)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)]), + new Comment('comm3', [new Range(30, 15)]), + new Comment('comm2', [new Range(20, 5)]), + ]) const comment = commentList.getComment('comm2') expect(comment?.toRaw()).to.eql({ + id: 'comm2', ranges: [ { pos: 20, @@ -49,16 +46,14 @@ describe('commentList', function () { }) it('should add new comment to the list', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)])], - ['comm2', new Comment([new Range(20, 5)])], - ['comm3', new Comment([new Range(30, 15)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)]), + new Comment('comm2', [new Range(20, 5)]), + new Comment('comm3', [new Range(30, 15)]), + ]) - commentList.add('comm4', new Comment([new Range(40, 10)])) - expect(commentList.getComments()).to.eql([ + commentList.add(new Comment('comm4', [new Range(40, 10)])) + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, { @@ -75,18 +70,16 @@ describe('commentList', function () { }) it('should overwrite existing comment if new one is added', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)], false)], - ['comm2', new Comment([new Range(20, 5)], true)], - ['comm3', new Comment([new Range(30, 15)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)], false), + new Comment('comm2', [new Range(20, 5)], true), + new Comment('comm3', [new Range(30, 15)]), + ]) - commentList.add('comm1', new Comment([new Range(5, 10)], true)) - commentList.add('comm2', new Comment([new Range(40, 10)], true)) + commentList.add(new Comment('comm1', [new Range(5, 10)], true)) + commentList.add(new Comment('comm2', [new Range(40, 10)], true)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: true }, { id: 'comm2', @@ -102,33 +95,29 @@ describe('commentList', function () { }) it('should delete a comment from the list', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)])], - ['comm2', new Comment([new Range(20, 5)])], - ['comm3', new Comment([new Range(30, 15)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)]), + new Comment('comm2', [new Range(20, 5)]), + new Comment('comm3', [new Range(30, 15)]), + ]) commentList.delete('comm3') - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, ]) }) it('should not throw an error if comment id does not exist', function () { - const commentList = new CommentList( - new Map([ - ['comm1', new Comment([new Range(5, 10)])], - ['comm2', new Comment([new Range(20, 5)])], - ['comm3', new Comment([new Range(30, 15)])], - ]) - ) + const commentList = new CommentList([ + new Comment('comm1', [new Range(5, 10)]), + new Comment('comm2', [new Range(20, 5)]), + new Comment('comm3', [new Range(30, 15)]), + ]) commentList.delete('comm5') - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, { @@ -153,7 +142,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(15, 5), { commentIds: ['comm1'] }) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 15 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 10 }], resolved: false }, ]) @@ -172,7 +161,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(15, 5), { commentIds: ['comm2'] }) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 15, length: 15 }], resolved: false }, ]) @@ -192,7 +181,7 @@ describe('commentList', function () { ]) commentList.applyDelete(new Range(10, 10)) // 10-19 - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 5 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 10, length: 5 }], resolved: false }, ]) @@ -216,7 +205,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(7, 5), { commentIds: ['comm1'] }) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 15 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 25, length: 5 }], resolved: false }, { id: 'comm3', ranges: [{ pos: 35, length: 15 }], resolved: false }, @@ -240,7 +229,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(7, 5), { commentIds: ['comm2'] }) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [ @@ -280,7 +269,7 @@ describe('commentList', function () { commentList.applyInsert(new Range(7, 5), { commentIds: ['comm1', 'comm2'], }) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 20 }], @@ -315,7 +304,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(16, 5)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 25, length: 5 }], resolved: false }, { id: 'comm3', ranges: [{ pos: 35, length: 15 }], resolved: false }, @@ -339,7 +328,7 @@ describe('commentList', function () { ]) commentList.applyInsert(new Range(50, 5)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, { id: 'comm3', ranges: [{ pos: 30, length: 15 }], resolved: false }, @@ -363,7 +352,7 @@ describe('commentList', function () { ]) commentList.applyDelete(new Range(0, 4)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 1, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 16, length: 5 }], resolved: false }, { id: 'comm3', ranges: [{ pos: 26, length: 15 }], resolved: false }, @@ -380,7 +369,7 @@ describe('commentList', function () { ]) commentList.applyDelete(new Range(0, 6)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 0, length: 9 }], resolved: false }, ]) }) @@ -393,7 +382,7 @@ describe('commentList', function () { }, ]) commentList.applyDelete(new Range(7, 10)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 2 }], resolved: false }, ]) }) @@ -406,7 +395,7 @@ describe('commentList', function () { }, ]) commentList.applyDelete(new Range(6, 2)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 8 }], resolved: false }, ]) }) @@ -429,7 +418,7 @@ describe('commentList', function () { ]) commentList.applyDelete(new Range(19, 10)) - expect(commentList.getComments()).to.eql([ + expect(commentList.toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], diff --git a/libraries/overleaf-editor-core/test/delete_comment_operation.test.js b/libraries/overleaf-editor-core/test/delete_comment_operation.test.js index f47fbf78cd..c6d22604c0 100644 --- a/libraries/overleaf-editor-core/test/delete_comment_operation.test.js +++ b/libraries/overleaf-editor-core/test/delete_comment_operation.test.js @@ -23,20 +23,19 @@ describe('DeleteCommentOperation', function () { it('should apply operation', function () { const fileData = new StringFileData('abc') const op = new DeleteCommentOperation('123') - fileData.comments.add('123', new Comment([new Range(0, 1)])) + fileData.comments.add(new Comment('123', [new Range(0, 1)])) op.apply(fileData) - expect(fileData.getComments()).to.eql([]) + expect(fileData.getComments().toRaw()).to.eql([]) }) it('should invert operation', function () { const fileData = new StringFileData('abc') const op = new DeleteCommentOperation('123') - fileData.comments.add('123', new Comment([new Range(0, 1)])) + fileData.comments.add(new Comment('123', [new Range(0, 1)])) const invertedOp = /** @type {AddCommentOperation} */ (op.invert(fileData)) expect(invertedOp).to.be.instanceOf(AddCommentOperation) expect(invertedOp.commentId).to.equal('123') - expect(invertedOp.comment).to.be.instanceOf(Comment) - expect(invertedOp.comment.ranges).to.eql([new Range(0, 1)]) + expect(invertedOp.ranges).to.eql([new Range(0, 1)]) }) it('should not throw if comment not found', function () { diff --git a/libraries/overleaf-editor-core/test/edit_operation.test.js b/libraries/overleaf-editor-core/test/edit_operation.test.js index 86ed54403d..161e8e9f73 100644 --- a/libraries/overleaf-editor-core/test/edit_operation.test.js +++ b/libraries/overleaf-editor-core/test/edit_operation.test.js @@ -8,7 +8,6 @@ const random = require('./support/random') const AddCommentOperation = require('../lib/operation/add_comment_operation') const DeleteCommentOperation = require('../lib/operation/delete_comment_operation') const SetCommentStateOperation = require('../lib/operation/set_comment_state_operation') -const Comment = require('../lib/comment') const Range = require('../lib/range') const EditNoOperation = require('../lib/operation/edit_no_operation') @@ -38,16 +37,16 @@ describe('EditOperationTransformer', function () { }) it('Transforms two AddCommentOperations with same commentId', function () { - const a = new AddCommentOperation('comm1', new Comment([new Range(0, 1)])) - const b = new AddCommentOperation('comm1', new Comment([new Range(2, 3)])) + const a = new AddCommentOperation('comm1', [new Range(0, 1)]) + const b = new AddCommentOperation('comm1', [new Range(2, 3)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(EditNoOperation) expect(bPrime).to.be.an.instanceof(AddCommentOperation) }) it('Transforms two AddCommentOperations with different commentId', function () { - const a = new AddCommentOperation('comm1', new Comment([new Range(0, 1)])) - const b = new AddCommentOperation('comm2', new Comment([new Range(2, 3)])) + const a = new AddCommentOperation('comm1', [new Range(0, 1)]) + const b = new AddCommentOperation('comm2', [new Range(2, 3)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(AddCommentOperation) expect(aPrime.toJSON()).to.eql(a.toJSON()) @@ -74,7 +73,7 @@ describe('EditOperationTransformer', function () { }) it('Transforms AddCommentOperation and DeleteCommentOperation with same commentId', function () { - const a = new AddCommentOperation('comm1', new Comment([new Range(0, 1)])) + const a = new AddCommentOperation('comm1', [new Range(0, 1)]) const b = new DeleteCommentOperation('comm1') const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(EditNoOperation) @@ -84,7 +83,7 @@ describe('EditOperationTransformer', function () { it('Transforms DeleteCommentOperation and AddCommentOperation with same commentId', function () { const a = new DeleteCommentOperation('comm1') - const b = new AddCommentOperation('comm1', new Comment([new Range(0, 1)])) + const b = new AddCommentOperation('comm1', [new Range(0, 1)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(DeleteCommentOperation) expect(aPrime.toJSON()).to.eql(a.toJSON()) @@ -96,7 +95,7 @@ describe('EditOperationTransformer', function () { // abc hello |xyz| - addComment(10, 3, "comment_id") const a = new TextOperation().retain(9).insert(' world') - const b = new AddCommentOperation('comm1', new Comment([new Range(10, 3)])) + const b = new AddCommentOperation('comm1', [new Range(10, 3)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(TextOperation) @@ -113,7 +112,7 @@ describe('EditOperationTransformer', function () { // abc hello |xyz| - addComment(10, 3, "comment_id") // abc hello[ world] xyz - insert(9, " world") - const a = new AddCommentOperation('comm1', new Comment([new Range(10, 3)])) + const a = new AddCommentOperation('comm1', [new Range(10, 3)]) const b = new TextOperation().retain(9).insert(' world') const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) @@ -132,7 +131,7 @@ describe('EditOperationTransformer', function () { // abc |hello| xyz - addComment(5, 5, "comment_id") const a = new TextOperation().remove(13) - const b = new AddCommentOperation('comm1', new Comment([new Range(5, 5)])) + const b = new AddCommentOperation('comm1', [new Range(5, 5)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(TextOperation) @@ -151,7 +150,7 @@ describe('EditOperationTransformer', function () { // abc hell|z| const a = new TextOperation().retain(8).remove(4) - const b = new AddCommentOperation('comm1', new Comment([new Range(10, 3)])) + const b = new AddCommentOperation('comm1', [new Range(10, 3)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(TextOperation) @@ -170,7 +169,7 @@ describe('EditOperationTransformer', function () { // foo abc hell|z| const a = new TextOperation().insert('foo ').retain(8).remove(4) - const b = new AddCommentOperation('comm1', new Comment([new Range(10, 3)])) + const b = new AddCommentOperation('comm1', [new Range(10, 3)]) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) expect(aPrime).to.be.an.instanceof(TextOperation) @@ -206,7 +205,7 @@ describe('EditOperationTransformer', function () { }) it('Transforms SetCommentStateOperation and AddCommentOperation', function () { - const a = new AddCommentOperation('comm1', new Comment([new Range(0, 1)])) + const a = new AddCommentOperation('comm1', [new Range(0, 1)]) const b = new SetCommentStateOperation('comm1', true) const [aPrime, bPrime] = EditOperationTransformer.transform(a, b) diff --git a/libraries/overleaf-editor-core/test/file.test.js b/libraries/overleaf-editor-core/test/file.test.js index e9dab90151..6c96d97b50 100644 --- a/libraries/overleaf-editor-core/test/file.test.js +++ b/libraries/overleaf-editor-core/test/file.test.js @@ -91,6 +91,6 @@ describe('File', function () { it('getComments() returns an empty comment list', function () { const file = File.fromString('foo') - expect(file.getComments()).to.eql([]) + expect(file.getComments().toRaw()).to.eql([]) }) }) diff --git a/libraries/overleaf-editor-core/test/hash_file_data.test.js b/libraries/overleaf-editor-core/test/hash_file_data.test.js index db7c15e6d7..be644b5e26 100644 --- a/libraries/overleaf-editor-core/test/hash_file_data.test.js +++ b/libraries/overleaf-editor-core/test/hash_file_data.test.js @@ -106,7 +106,7 @@ describe('HashFileData', function () { expect(eagerFileData).to.be.instanceOf(StringFileData) expect(eagerFileData.getContent()).to.equal('content') expect(eagerFileData.trackedChanges.toRaw()).to.deep.equal(trackedChanges) - expect(eagerFileData.getComments()).to.deep.equal(comments) + expect(eagerFileData.getComments().toRaw()).to.deep.equal(comments) }) it('should convert HashFileData to StringFileData without ranges', async function () { @@ -119,7 +119,7 @@ describe('HashFileData', function () { expect(eagerFileData).to.be.instanceOf(StringFileData) expect(eagerFileData.getContent()).to.equal('content') expect(eagerFileData.trackedChanges.toRaw()).to.deep.equal([]) - expect(eagerFileData.getComments()).to.deep.equal([]) + expect(eagerFileData.getComments().toRaw()).to.deep.equal([]) }) }) }) diff --git a/libraries/overleaf-editor-core/test/lazy_string_file_data.test.js b/libraries/overleaf-editor-core/test/lazy_string_file_data.test.js index 58f79da868..048f9a17f6 100644 --- a/libraries/overleaf-editor-core/test/lazy_string_file_data.test.js +++ b/libraries/overleaf-editor-core/test/lazy_string_file_data.test.js @@ -120,7 +120,7 @@ describe('LazyStringFileData', function () { const eagerString = await fileData.toEager(this.blobStore) expect(eagerString).to.be.instanceOf(EagerStringFileData) expect(eagerString.getContent()).to.equal('the quick brown fox') - expect(eagerString.getComments()).to.deep.equal([ + expect(eagerString.getComments().toRaw()).to.deep.equal([ { id: 'foo', ranges: [{ pos: 0, length: 3 }], resolved: false }, ]) expect(eagerString.trackedChanges.toRaw()).to.deep.equal([ @@ -143,7 +143,7 @@ describe('LazyStringFileData', function () { const eagerString = await fileData.toEager(this.blobStore) expect(eagerString).to.be.instanceOf(EagerStringFileData) expect(eagerString.getContent()).to.equal('the quick brown fox') - expect(eagerString.getComments()).to.be.empty + expect(eagerString.getComments().toRaw()).to.be.empty expect(eagerString.trackedChanges.length).to.equal(0) expect(this.blobStore.getObject.called).to.be.false expect(this.blobStore.getString.calledWith(testHash)).to.be.true diff --git a/libraries/overleaf-editor-core/test/operation.test.js b/libraries/overleaf-editor-core/test/operation.test.js index bf4c5b9922..71c0af3dc3 100644 --- a/libraries/overleaf-editor-core/test/operation.test.js +++ b/libraries/overleaf-editor-core/test/operation.test.js @@ -98,7 +98,9 @@ describe('Operation', function () { const file = this.snapshot.getFile(pathname) expect(file.getContent()).to.equal(expectedFile.content) expect(file.getMetadata()).to.eql(expectedFile.metadata) - expect(file.getComments()).to.deep.equal(expectedFile.comments) + expect(file.getComments().toRaw()).to.deep.equal( + expectedFile.comments + ) }) return this }, diff --git a/libraries/overleaf-editor-core/test/string_file_data.test.js b/libraries/overleaf-editor-core/test/string_file_data.test.js index 9c898c66dd..802be1e39e 100644 --- a/libraries/overleaf-editor-core/test/string_file_data.test.js +++ b/libraries/overleaf-editor-core/test/string_file_data.test.js @@ -38,7 +38,7 @@ describe('StringFileData', function () { it('getComments() should return an empty array', function () { const fileData = new StringFileData('test') - expect(fileData.getComments()).to.eql([]) + expect(fileData.getComments().toRaw()).to.eql([]) }) it('creates StringFileData with comments', function () { @@ -63,7 +63,7 @@ describe('StringFileData', function () { }, ]) - expect(fileData.getComments()).to.eql([ + expect(fileData.getComments().toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: false }, ]) @@ -96,7 +96,7 @@ describe('StringFileData', function () { ], }) - expect(fileData.getComments()).to.eql([ + expect(fileData.getComments().toRaw()).to.eql([ { id: 'comm1', ranges: [{ pos: 5, length: 10 }], resolved: false }, { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: true }, ])