Merge pull request #17910 from overleaf/em-comment-ids

Include id in history Comment instances

GitOrigin-RevId: 25b897e8e9e8d7b19dfe2d90d7f0cafeb5e6e97f
This commit is contained in:
Eric Mc Sween 2024-04-16 09:03:34 -04:00 committed by Copybot
parent 616bd0df16
commit 88fe3e2942
20 changed files with 222 additions and 188 deletions

View file

@ -21,10 +21,12 @@ class Comment {
resolved = false
/**
* @param {string} id
* @param {ReadonlyArray<Range>} 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
)

View file

@ -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()

View file

@ -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<string, Comment>} comments
* @param {Comment[]} comments
*/
constructor(comments) {
this.comments = comments
this.comments = new Map(comments.map(comment => [comment.id, comment]))
}
/**
* @returns {CommentsListRawData}
* @returns {IterableIterator<Comment>}
*/
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))
}
/**

View file

@ -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() {

View file

@ -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)

View file

@ -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<Range>} 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
)
}
}

View file

@ -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
)
}
/**

View file

@ -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]

View file

@ -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)
}
}

View file

@ -11,7 +11,7 @@ export type BlobStore = {
export type ReadonlyBlobStore = Pick<BlobStore, 'getString' | 'getObject'>
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

View file

@ -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

View file

@ -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),

View file

@ -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 }],

View file

@ -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 () {

View file

@ -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)

View file

@ -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([])
})
})

View file

@ -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([])
})
})
})

View file

@ -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

View file

@ -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
},

View file

@ -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 },
])