Skip to content

Commit

Permalink
Merge pull request #735 from streamich/peritext-high-level-api
Browse files Browse the repository at this point in the history
Peritext high-level API
  • Loading branch information
streamich authored Oct 31, 2024
2 parents 178a4be + a5553af commit 6ab990e
Show file tree
Hide file tree
Showing 20 changed files with 2,792 additions and 284 deletions.
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"test:cli:patch": "./bin/json-patch-test.js ./bin/json-patch.js",
"test:cli:pack": "./bin/json-pack-test.js ./bin/json-pack.js",
"demo:json-patch": "npx ts-node src/json-patch/__demos__/json-patch.ts",
"demo:ui:peritext": "webpack serve --config ./src/json-crdt-peritext-ui/__demos__/webpack.config.js",
"bench:json-crdt:traces:crdt-libs": "cd src/json-crdt/__bench__ && yarn && yarn bench:traces:crdt-libs",
"bench:json-crdt:traces:non-crdt-libs": "cd src/json-crdt/__bench__ && yarn && yarn bench:traces:non-crdt-libs",
"bench:json-crdt:concurrent-traces": "cd src/json-crdt/__bench__ && yarn && yarn bench:concurrent-traces",
Expand Down Expand Up @@ -138,21 +139,31 @@
"devDependencies": {
"@types/benchmark": "^2.1.5",
"@types/jest": "^29.5.12",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
"benchmark": "^2.1.4",
"config-housekeeping": "https://github.com/streamich/housekeeping#3532d2abeac159315ddf403d70517859d079c801",
"editing-traces": "https://github.com/streamich/editing-traces#6494020428530a6e382378b98d1d7e31334e2d7b",
"fast-json-patch": "^3.1.1",
"html-webpack-plugin": "^5.6.0",
"jest": "^29.7.0",
"json-crdt-traces": "https://github.com/streamich/json-crdt-traces#ec825401dc05cbb74b9e0b3c4d6527399f54d54d",
"json-logic-js": "^2.0.2",
"nano-theme": "^1.4.3",
"quill-delta": "^5.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"rxjs": "^7.8.1",
"ts-jest": "^29.1.2",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tslib": "^2.6.2",
"tslint": "^6.1.3",
"tslint-config-common": "^1.6.2",
"typescript": "^5.4.5",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.1.0",
"yjs": "^13.6.18"
},
"jest": {
Expand Down
5 changes: 5 additions & 0 deletions src/json-crdt-extensions/peritext/Peritext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ export class Peritext<T = string> implements Printable {
return Range.at(this.str, start, length);
}

/**
* Creates selection of relative start and end of the whole document.
*
* @returns Range, which selects the whole document, if any.
*/
public rangeAll(): Range<T> | undefined {
const start = this.pointStart();
const end = this.pointEnd();
Expand Down
55 changes: 29 additions & 26 deletions src/json-crdt-extensions/peritext/__tests__/Peritext.cursor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {InlineAttrPos} from '../block/Inline';
import {CursorAnchor, SliceTypes} from '../slice/constants';
import {InlineAttrStartPoint, InlineAttrContained} from '../block/Inline';
import {SliceTypes} from '../slice/constants';
import {setupKit} from './setup';

const setup = () => {
Expand All @@ -24,10 +24,8 @@ test('cursor at the start of string and slice annotation at the start of string'
expect(inline1.text()).toBe('');
expect(inline2.text()).toBe('a');
expect(inline3.text()).toBe('b');
expect(inline1.attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect(inline2.attr()).toEqual({bold: [1, InlineAttrPos.Contained]});
expect(inline1.attr()[SliceTypes.Cursor][0]).toBeInstanceOf(InlineAttrStartPoint);
expect(inline2.attr().bold[0]).toBeInstanceOf(InlineAttrContained);
expect(inline3.attr()).toEqual({});
});

Expand All @@ -49,10 +47,12 @@ test('cursor walking over character marked as bold', () => {
expect(inline1.text()).toBe('');
expect(inline2.text()).toBe('a');
expect(inline3.text()).toBe('b');
expect(inline2.attr()).toEqual({bold: [[void 0], InlineAttrPos.Contained]});
expect(inline3.attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect(inline2.attr().bold[0]).toBeInstanceOf(InlineAttrContained);
expect(inline3.attr()[SliceTypes.Cursor][0]).toBeInstanceOf(InlineAttrStartPoint);
// expect(inline2.attr()).toEqual({bold: [[void 0], InlineAttrPos.Contained]});
// expect(inline3.attr()).toEqual({
// [SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
// });
editor.cursor.move(1);
peritext.refresh();
});
Expand All @@ -75,11 +75,13 @@ test('cursor walking over character marked as bold and one more', () => {
expect(inline2.text()).toBe('a');
expect(inline3.text()).toBe('b');
expect(inline4.text()).toBe('');
expect(inline2.attr()).toEqual({bold: [1, InlineAttrPos.Contained]});
expect(inline2.attr().bold[0]).toBeInstanceOf(InlineAttrContained);
// expect(inline2.attr()).toEqual({bold: [1, InlineAttrPos.Contained]});
expect(inline3.attr()).toEqual({});
expect(inline4.attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect(inline4.attr()[SliceTypes.Cursor][0]).toBeInstanceOf(InlineAttrStartPoint);
// expect(inline4.attr()).toEqual({
// [SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
// });
});

test('cursor can move across block boundary forwards', () => {
Expand All @@ -92,19 +94,20 @@ test('cursor can move across block boundary forwards', () => {
expect(peritext.blocks.root.children.length).toBe(2);
expect([...peritext.blocks.root.children[0].texts()].length).toBe(1);
expect([...peritext.blocks.root.children[0].texts()][0].text()).toBe('a');
expect([...peritext.blocks.root.children[0].texts()][0].attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect([...peritext.blocks.root.children[0].texts()][0].attr()[SliceTypes.Cursor][0]).toBeInstanceOf(
InlineAttrStartPoint,
);

editor.cursor.move(1);
peritext.refresh();
expect(peritext.blocks.root.children.length).toBe(2);
expect([...peritext.blocks.root.children[0].texts()].length).toBe(2);
expect([...peritext.blocks.root.children[0].texts()][0].text()).toBe('a');
expect([...peritext.blocks.root.children[0].texts()][0].attr()).toEqual({});
expect([...peritext.blocks.root.children[0].texts()][1].text()).toBe('');
expect([...peritext.blocks.root.children[0].texts()][1].attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect([...peritext.blocks.root.children[0].texts()][1].attr()[SliceTypes.Cursor][0]).toBeInstanceOf(
InlineAttrStartPoint,
);
expect([...peritext.blocks.root.children[1].texts()].length).toBe(1);
expect([...peritext.blocks.root.children[1].texts()][0].text()).toBe('b');
expect([...peritext.blocks.root.children[1].texts()][0].attr()).toEqual({});
Expand All @@ -118,9 +121,9 @@ test('cursor can move across block boundary forwards', () => {
expect([...peritext.blocks.root.children[1].texts()][0].text()).toBe('');
expect([...peritext.blocks.root.children[1].texts()][0].attr()).toEqual({});
expect([...peritext.blocks.root.children[1].texts()][1].text()).toBe('b');
expect([...peritext.blocks.root.children[1].texts()][1].attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect([...peritext.blocks.root.children[1].texts()][1].attr()[SliceTypes.Cursor][0]).toBeInstanceOf(
InlineAttrStartPoint,
);
editor.cursor.move(1);
peritext.refresh();
expect(peritext.blocks.root.children.length).toBe(2);
Expand All @@ -131,7 +134,7 @@ test('cursor can move across block boundary forwards', () => {
expect([...peritext.blocks.root.children[1].texts()][0].text()).toBe('b');
expect([...peritext.blocks.root.children[1].texts()][0].attr()).toEqual({});
expect([...peritext.blocks.root.children[1].texts()][1].text()).toBe('');
expect([...peritext.blocks.root.children[1].texts()][1].attr()).toEqual({
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
expect([...peritext.blocks.root.children[1].texts()][1].attr()[SliceTypes.Cursor][0]).toBeInstanceOf(
InlineAttrStartPoint,
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const runInlineSlicesTests = (
"<>
<0>
"abcde" { }
"fghij" { BOLD = [ 1, 3 ] }
"fghij" { BOLD = [ !u ] }
"klmno" { }
<paragraph> [ ]
"pqrstuvwxyz" { }
Expand All @@ -97,7 +97,7 @@ const runInlineSlicesTests = (
"<>
<0>
"abcde" { }
"fghij" { BOLD = [ 1, 3 ] }
"fghij" { BOLD = [ !u ] }
"" { }
<paragraph> [ ]
"klmnopqrstuvwxyz" { }
Expand All @@ -117,7 +117,7 @@ const runInlineSlicesTests = (
"abcdefghij" { }
<paragraph> [ ]
"klmno" { }
"pqrst" { BOLD = [ 1, 3 ] }
"pqrst" { BOLD = [ !u ] }
"uvwxyz" { }
"
`);
Expand All @@ -135,7 +135,7 @@ const runInlineSlicesTests = (
"abcdefghijklmno" { }
<paragraph> [ ]
"" { }
"pqrst" { BOLD = [ 1, 3 ] }
"pqrst" { BOLD = [ !u ] }
"uvwxyz" { }
"
`);
Expand All @@ -151,9 +151,9 @@ const runInlineSlicesTests = (
"<>
<0>
"abcde" { }
"fghij" { BOLD = [ 1, 1 ] }
"fghij" { BOLD = [ !u ] }
<paragraph> [ ]
"klmno" { BOLD = [ 1, 2 ] }
"klmno" { BOLD = [ !u ] }
"pqrstuvwxyz" { }
"
`);
Expand All @@ -171,11 +171,11 @@ const runInlineSlicesTests = (
"<>
<0>
"abcdefgh" { }
"ij" { BOLD = [ 1, 1 ] }
"ij" { BOLD = [ !u ] }
<p> [ ]
"klmn" { BOLD = [ 1, 0 ] }
"klmn" { BOLD = [ !u ] }
<p> [ ]
"opqrstu" { BOLD = [ 1, 2 ] }
"opqrstu" { BOLD = [ !u ] }
"vwxyz" { }
"
`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
"<>
<0>
"a" { }
"bcdefghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"bcdefghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
editor.cursor.move(1);
Expand All @@ -39,7 +39,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
"<>
<0>
"ab" { }
"cdefghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"cdefghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
editor.cursor.move(2);
Expand All @@ -48,7 +48,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
"<>
<0>
"abcd" { }
"efghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"efghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
});
Expand All @@ -61,7 +61,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
expect(view()).toMatchInlineSnapshot(`
"<>
<0>
"abcdefghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"abcdefghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
editor.cursor.move(1);
Expand All @@ -72,7 +72,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
"<>
<0>
"a" { }
"bcdefghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"bcdefghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
editor.cursor.move(2);
Expand All @@ -82,7 +82,7 @@ const runInlineSlicesTests = (desc: string, getKit: () => Kit) => {
"<>
<0>
"abc" { }
"defghijklmnopqrstuvwxyz" { -1 = [ [ [ 0, !u ] ], 4 ] }
"defghijklmnopqrstuvwxyz" { -1 = [ !u ] }
"
`);
});
Expand Down
Loading

0 comments on commit 6ab990e

Please sign in to comment.