init
This commit is contained in:
+155
@@ -0,0 +1,155 @@
|
||||
// 简单文本操作的实现
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export abstract class SimpleTextOperation {
|
||||
id: string = uuidv4();
|
||||
abstract toString(): string;
|
||||
abstract equals(other: SimpleTextOperation): boolean;
|
||||
abstract apply(doc: string): string;
|
||||
|
||||
static transform(a: SimpleTextOperation, b: SimpleTextOperation): [SimpleTextOperation, SimpleTextOperation] {
|
||||
if (a instanceof Noop || b instanceof Noop) {
|
||||
return [a, b];
|
||||
}
|
||||
|
||||
if (a instanceof Insert && b instanceof Insert) {
|
||||
if (a.position < b.position || (a.position === b.position && a.str < b.str)) {
|
||||
return [a, new Insert(b.str, b.position + a.str.length)];
|
||||
}
|
||||
if (a.position > b.position || (a.position === b.position && a.str > b.str)) {
|
||||
return [new Insert(a.str, a.position + b.str.length), b];
|
||||
}
|
||||
return [noop, noop];
|
||||
}
|
||||
|
||||
if (a instanceof Insert && b instanceof Delete) {
|
||||
if (a.position <= b.position) {
|
||||
return [a, new Delete(b.count, b.position + a.str.length)];
|
||||
}
|
||||
if (a.position >= b.position + b.count) {
|
||||
return [new Insert(a.str, a.position - b.count), b];
|
||||
}
|
||||
// 这里,我们必须删除操作 a 插入的字符串。
|
||||
// 这不能保留操作 a 的意图,但这是获得有效转换函数的唯一方法。
|
||||
return [noop, new Delete(b.count + a.str.length, b.position)];
|
||||
}
|
||||
|
||||
if (a instanceof Delete && b instanceof Insert) {
|
||||
if (a.position >= b.position) {
|
||||
return [new Delete(a.count, a.position + b.str.length), b];
|
||||
}
|
||||
if (a.position + a.count <= b.position) {
|
||||
return [a, new Insert(b.str, b.position - a.count)];
|
||||
}
|
||||
// 与上面相同的问题。我们必须删除操作 b 中插入的字符串。
|
||||
return [new Delete(a.count + b.str.length, a.position), noop];
|
||||
}
|
||||
|
||||
if (a instanceof Delete && b instanceof Delete) {
|
||||
if (a.position === b.position) {
|
||||
if (a.count === b.count) {
|
||||
return [noop, noop];
|
||||
} else if (a.count < b.count) {
|
||||
return [noop, new Delete(b.count - a.count, b.position)];
|
||||
}
|
||||
return [new Delete(a.count - b.count, a.position), noop];
|
||||
}
|
||||
if (a.position < b.position) {
|
||||
if (a.position + a.count <= b.position) {
|
||||
return [a, new Delete(b.count, b.position - a.count)];
|
||||
}
|
||||
if (a.position + a.count >= b.position + b.count) {
|
||||
return [new Delete(a.count - b.count, a.position), noop];
|
||||
}
|
||||
return [
|
||||
new Delete(b.position - a.position, a.position),
|
||||
new Delete(b.position + b.count - (a.position + a.count), a.position)
|
||||
];
|
||||
}
|
||||
if (a.position > b.position) {
|
||||
if (a.position >= b.position + b.count) {
|
||||
return [new Delete(a.count, a.position - b.count), b];
|
||||
}
|
||||
if (a.position + a.count <= b.position + b.count) {
|
||||
return [noop, new Delete(b.count - a.count, b.position)];
|
||||
}
|
||||
return [
|
||||
new Delete(a.position + a.count - (b.position + b.count), b.position),
|
||||
new Delete(a.position - b.position, b.position)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unsupported operation types for transformation');
|
||||
}
|
||||
}
|
||||
|
||||
// 在文档的从零开始的位置 `position` 插入字符串 `str`
|
||||
export class Insert extends SimpleTextOperation {
|
||||
public str: string;
|
||||
public position: number;
|
||||
|
||||
constructor(str: string, position: number) {
|
||||
super();
|
||||
this.str = str;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return 'Insert(' + JSON.stringify(this.str) + ', ' + this.position + ')';
|
||||
}
|
||||
|
||||
equals(other: SimpleTextOperation): boolean {
|
||||
return other instanceof Insert &&
|
||||
this.str === other.str &&
|
||||
this.position === other.position;
|
||||
}
|
||||
|
||||
apply(doc: string): string {
|
||||
return doc.slice(0, this.position) + this.str + doc.slice(this.position);
|
||||
}
|
||||
}
|
||||
|
||||
// 在文档的从零开始的位置 `position` 删除 `count` 个字符
|
||||
export class Delete extends SimpleTextOperation {
|
||||
public count: number;
|
||||
public position: number;
|
||||
|
||||
constructor(count: number, position: number) {
|
||||
super();
|
||||
this.count = count;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return 'Delete(' + this.count + ', ' + this.position + ')';
|
||||
}
|
||||
|
||||
equals(other: SimpleTextOperation): boolean {
|
||||
return other instanceof Delete &&
|
||||
this.count === other.count &&
|
||||
this.position === other.position;
|
||||
}
|
||||
|
||||
apply(doc: string): string {
|
||||
return doc.slice(0, this.position) + doc.slice(this.position + this.count);
|
||||
}
|
||||
}
|
||||
|
||||
// 不执行任何操作的操作。这对于转换两个删除相同字符的结果是必需的
|
||||
export class Noop extends SimpleTextOperation {
|
||||
toString(): string {
|
||||
return 'Noop()';
|
||||
}
|
||||
|
||||
equals(other: SimpleTextOperation): boolean {
|
||||
return other instanceof Noop;
|
||||
}
|
||||
|
||||
apply(doc: string): string {
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
const noop = new Noop();
|
||||
|
||||
Reference in New Issue
Block a user