Skip to content

Commit

Permalink
refactor: transform textRuns
Browse files Browse the repository at this point in the history
  • Loading branch information
Jocs committed Oct 30, 2024
1 parent 5daed44 commit ee65e42
Show file tree
Hide file tree
Showing 8 changed files with 295 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import type { TextXAction } from '../action-types';
import { describe, expect, it } from 'vitest';
import { UpdateDocsAttributeType } from '../../../../shared';
import { BooleanNumber } from '../../../../types/enum/text-style';
import { TextXActionType } from '../action-types';
import { TextX } from '../text-x';
Expand Down Expand Up @@ -325,6 +326,7 @@ describe('compose test cases', () => {

const expect_actions: TextXAction[] = [{
t: TextXActionType.RETAIN,
coverType: UpdateDocsAttributeType.COVER,
body: {
dataStream: '',
textRuns: [{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ describe('transform paragraph in body', () => {
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
coverType: UpdateDocsAttributeType.COVER,
body: {
dataStream: '',
paragraphs: [{
Expand Down Expand Up @@ -237,7 +237,7 @@ describe('transform paragraph in body', () => {
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
coverType: UpdateDocsAttributeType.COVER,
body: {
dataStream: '',
paragraphs: [{
Expand Down Expand Up @@ -346,6 +346,9 @@ describe('transform paragraph in body', () => {
spaceBelow: {
v: 20,
},
spaceAbove: {
v: 30,
},
},
}],
},
Expand All @@ -366,6 +369,9 @@ describe('transform paragraph in body', () => {
spaceBelow: {
v: 20,
},
spaceAbove: {
v: 30,
},
},
}],
},
Expand All @@ -385,6 +391,9 @@ describe('transform paragraph in body', () => {
spaceBelow: {
v: 20,
},
spaceAbove: {
v: 30,
},
},
}],
},
Expand All @@ -405,11 +414,6 @@ describe('transform paragraph in body', () => {
const composedAction1 = TextX.compose(actionsA, TextX.transform(actionsB, actionsA, 'left'));
const composedAction2 = TextX.compose(actionsB, TextX.transform(actionsA, actionsB, 'right'));

// console.log(JSON.stringify(actionsA, null, 2));
// console.log(JSON.stringify(TextX.transform(actionsB, actionsA, 'left'), null, 2));
// console.log(JSON.stringify(composedAction1, null, 2));
// console.log(JSON.stringify(composedAction2, null, 2));

const resultC = TextX.apply(doc3, composedAction1);
const resultD = TextX.apply(doc4, composedAction2);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { IDocumentBody } from '../../../../types/interfaces/i-document-data';
import type { TextXAction } from '../action-types';
import { describe, expect, it } from 'vitest';
import { UpdateDocsAttributeType } from '../../../../shared';
import { BooleanNumber } from '../../../../types/enum';
import { TextXActionType } from '../action-types';
import { TextX } from '../text-x';

function getDefaultDocWithTextRuns() {
const doc: IDocumentBody = {
dataStream: 'w\r\n',
textRuns: [
{
st: 0,
ed: 1,
ts: {
bl: BooleanNumber.TRUE,
},
},
],
};

return doc;
}

// Test Retain + Retain with different coverType in transform textRun.
describe('transform textRun in body', () => {
it('should pass test when REPLACE + REPLACE', () => {
const actionsA: TextXAction[] = [
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
body: {
dataStream: '',
textRuns: [{
st: 0,
ed: 1,
ts: {
it: BooleanNumber.TRUE,
fs: 10,
},
}],
},
},
];

const actionsB: TextXAction[] = [
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
body: {
dataStream: '',
textRuns: [{
st: 0,
ed: 1,
ts: {
it: BooleanNumber.FALSE,
fs: 14,
},
}],
},
},
];

const expectedTransformedActionFalse: TextXAction[] = [
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
body: {
dataStream: '',
textRuns: [{
st: 0,
ed: 1,
ts: {
it: BooleanNumber.TRUE,
fs: 10,
},
}],
},
},
];

const expectedTransformedActionTrue: TextXAction[] = [
{
t: TextXActionType.RETAIN,
len: 1,
coverType: UpdateDocsAttributeType.REPLACE,
body: {
dataStream: '',
textRuns: [{
st: 0,
ed: 1,
ts: {
it: BooleanNumber.FALSE,
fs: 14,
},
}],
},
},
];

expect(TextX.transform(actionsB, actionsA, 'left')).toEqual(expectedTransformedActionTrue);
expect(TextX.transform(actionsB, actionsA, 'right')).toEqual(expectedTransformedActionFalse);

const doc1 = getDefaultDocWithTextRuns();
const doc2 = getDefaultDocWithTextRuns();
const doc3 = getDefaultDocWithTextRuns();
const doc4 = getDefaultDocWithTextRuns();

const resultA = TextX.apply(TextX.apply(doc1, actionsA), TextX.transform(actionsB, actionsA, 'left'));
const resultB = TextX.apply(TextX.apply(doc2, actionsB), TextX.transform(actionsA, actionsB, 'right'));

const composedAction1 = TextX.compose(actionsA, TextX.transform(actionsB, actionsA, 'left'));
const composedAction2 = TextX.compose(actionsB, TextX.transform(actionsA, actionsB, 'right'));

// console.log(JSON.stringify(TextX.transform(actionsB, actionsA, 'left'), null, 2));
// console.log(JSON.stringify(composedAction1, null, 2));
// console.log(JSON.stringify(composedAction2, null, 2));

const resultC = TextX.apply(doc3, composedAction1);
const resultD = TextX.apply(doc4, composedAction2);

expect(resultA).toEqual(resultB);
expect(resultC).toEqual(resultD);
expect(resultA).toEqual(resultC);
expect(composedAction1).toEqual(composedAction2);
});
});
59 changes: 58 additions & 1 deletion packages/core/src/docs/data-model/text-x/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { IDocumentBody } from '../../../../types/interfaces/i-document-data
import type { IRetainAction } from '../action-types';
import { describe, expect, it } from 'vitest';
import { BooleanNumber } from '../../../../types/enum/text-style';
import { PresetListType } from '../../preset-list-type';
import { TextXActionType } from '../action-types';
import { composeBody, getBodySlice, isUselessRetainAction } from '../utils';

Expand Down Expand Up @@ -237,7 +238,7 @@ describe('test text-x utils', () => {
}).toThrowError();
});

it('test composeBody fn both width paragraphs', () => {
it('test composeBody both with paragraphs', () => {
const thisBody: IDocumentBody = {
dataStream: 'hello\nworld',
paragraphs: [{
Expand Down Expand Up @@ -272,6 +273,62 @@ describe('test text-x utils', () => {
});
});

it('test composeBody both with paragraphs and one has bullet list', () => {
const thisBody: IDocumentBody = {
dataStream: '',
paragraphs: [{
startIndex: 0,
paragraphStyle: {
lineSpacing: 2,
},
bullet: {
listType: PresetListType.BULLET_LIST,
listId: 'testBullet',
nestingLevel: 0,
textStyle: {
fs: 15,
},
},
}],
};

const otherBody: IDocumentBody = {
dataStream: '',
paragraphs: [{
startIndex: 0,
paragraphStyle: {
lineSpacing: 1,
spaceBelow: {
v: 20,
},
},
}],
};

const composedBody = composeBody(thisBody, otherBody);

expect(composedBody).toEqual({
dataStream: '',
paragraphs: [{
startIndex: 0,
paragraphStyle: {
lineSpacing: 1,
spaceBelow: {
v: 20,
},
},
bullet: {
listType: PresetListType.BULLET_LIST,
listId: 'testBullet',
nestingLevel: 0,
textStyle: {
fs: 15,
},
},
}],
});
});

it('test composeBody fn both width paragraphs and from retain', () => {
const thisBody: IDocumentBody = {
dataStream: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,19 @@ function updateTextRuns(
// eslint-disable-next-line max-lines-per-function, complexity
export function coverTextRuns(
updateDataTextRuns: ITextRun[],
removeTextRuns: ITextRun[],
originTextRuns: ITextRun[],
coverType: UpdateDocsAttributeType
) {
if (removeTextRuns.length === 0) {
if (originTextRuns.length === 0) {
return updateDataTextRuns;
}

updateDataTextRuns = Tools.deepClone(updateDataTextRuns);
removeTextRuns = Tools.deepClone(removeTextRuns);
originTextRuns = Tools.deepClone(originTextRuns);

const newUpdateTextRuns: ITextRun[] = [];
const updateLength = updateDataTextRuns.length;
const removeLength = removeTextRuns.length;
const removeLength = originTextRuns.length;
let updateIndex = 0;
let removeIndex = 0;
let pending: Nullable<ITextRun> = null;
Expand All @@ -131,13 +131,13 @@ export function coverTextRuns(

while (updateIndex < updateLength && removeIndex < removeLength) {
const { st: updateSt, ed: updateEd, ts: updateStyle } = updateDataTextRuns[updateIndex];
const { st: removeSt, ed: removeEd, ts: removeStyle, sId } = removeTextRuns[removeIndex];
const { st: removeSt, ed: removeEd, ts: originStyle, sId } = originTextRuns[removeIndex];
let newTs;

if (coverType === UpdateDocsAttributeType.COVER) {
newTs = { ...removeStyle, ...updateStyle };
newTs = { ...originStyle, ...updateStyle };
} else {
newTs = { ...updateStyle, ...removeStyle };
newTs = { ...updateStyle };
}

if (updateEd < removeSt) {
Expand All @@ -148,15 +148,15 @@ export function coverTextRuns(
updateIndex++;
} else if (removeEd < updateSt) {
if (!pushPendingAndReturnStatus()) {
newUpdateTextRuns.push(removeTextRuns[removeIndex]);
newUpdateTextRuns.push(originTextRuns[removeIndex]);
}

removeIndex++;
} else {
const newTextRun = {
st: Math.min(updateSt, removeSt),
ed: Math.max(updateSt, removeSt),
ts: updateSt < removeSt ? { ...updateStyle } : { ...removeStyle },
ts: updateSt < removeSt ? { ...updateStyle } : { ...originStyle },
sId: updateSt < removeSt ? undefined : sId,
};

Expand All @@ -173,8 +173,8 @@ export function coverTextRuns(

if (updateEd < removeEd) {
updateIndex++;
removeTextRuns[removeIndex].st = updateEd;
if (removeTextRuns[removeIndex].st === removeTextRuns[removeIndex].ed) {
originTextRuns[removeIndex].st = updateEd;
if (originTextRuns[removeIndex].st === originTextRuns[removeIndex].ed) {
removeIndex++;
}
} else {
Expand All @@ -188,7 +188,7 @@ export function coverTextRuns(
const pendingTextRun = {
st: Math.min(updateEd, removeEd),
ed: Math.max(updateEd, removeEd),
ts: updateEd < removeEd ? { ...removeStyle } : { ...updateStyle },
ts: updateEd < removeEd ? { ...originStyle } : { ...updateStyle },
sId: updateEd < removeEd ? sId : undefined,
};

Expand All @@ -201,7 +201,7 @@ export function coverTextRuns(
// If the last textRun is also disjoint, then the last textRun needs to be pushed in `newUpdateTextRun`
const tempTopTextRun = newUpdateTextRuns[newUpdateTextRuns.length - 1];
const updateLastTextRun = updateDataTextRuns[updateLength - 1];
const removeLastTextRun = removeTextRuns[removeLength - 1];
const removeLastTextRun = originTextRuns[removeLength - 1];

if (tempTopTextRun && (tempTopTextRun.ed !== Math.max(updateLastTextRun.ed, removeLastTextRun.ed))) {
if (updateLastTextRun.ed > removeLastTextRun.ed) {
Expand Down
Loading

0 comments on commit ee65e42

Please sign in to comment.