Skip to content

Commit

Permalink
feat: add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
mainhanu@outlook.com committed Nov 7, 2023
1 parent 263d22a commit 16bd79d
Show file tree
Hide file tree
Showing 69 changed files with 265 additions and 167 deletions.
1 change: 1 addition & 0 deletions packages/slate/src/interfaces/transforms/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface NodeInsertNodesOptions<T extends Node> {
hanging?: boolean
select?: boolean
voids?: boolean
batchDirty?: boolean
}

export interface NodeTransforms {
Expand Down
1 change: 1 addition & 0 deletions packages/slate/src/interfaces/transforms/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface TextInsertFragmentOptions {
at?: Location
hanging?: boolean
voids?: boolean
batchDirty?: boolean
}

export interface TextInsertTextOptions {
Expand Down
97 changes: 56 additions & 41 deletions packages/slate/src/transforms-node/insert-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ export const insertNodes: NodeTransforms['insertNodes'] = (
options = {}
) => {
Editor.withoutNormalizing(editor, () => {
const { hanging = false, voids = false, mode = 'lowest' } = options
const {
hanging = false,
voids = false,
mode = 'lowest',
batchDirty = true,
} = options
let { at, match, select } = options

if (Node.isNode(nodes)) {
Expand Down Expand Up @@ -92,50 +97,60 @@ export const insertNodes: NodeTransforms['insertNodes'] = (
return
}

// PERF: batch update dirty paths
// batched ops used to transform existing dirty paths
const batchedOps: BaseInsertNodeOperation[] = []
const newDirtyPaths: Path[] = Path.levels(parentPath)
batchDirtyPaths(
editor,
() => {
for (const node of nodes as Node[]) {
const path = parentPath.concat(index)
index++

const op: BaseInsertNodeOperation = {
type: 'insert_node',
path,
node,
}
editor.apply(op)
at = Path.next(at as Path)

batchedOps.push(op)
if (!Text.isText) {
newDirtyPaths.push(path)
} else {
newDirtyPaths.push(
...Array.from(Node.nodes(node), ([, p]) => path.concat(p))
)
if (batchDirty) {
// PERF: batch update dirty paths
// batched ops used to transform existing dirty paths
const batchedOps: BaseInsertNodeOperation[] = []
const newDirtyPaths: Path[] = Path.levels(parentPath)
batchDirtyPaths(
editor,
() => {
for (const node of nodes as Node[]) {
const path = parentPath.concat(index)
index++

const op: BaseInsertNodeOperation = {
type: 'insert_node',
path,
node,
}
editor.apply(op)
at = Path.next(at as Path)

batchedOps.push(op)
if (!Text.isText) {
newDirtyPaths.push(path)
} else {
newDirtyPaths.push(
...Array.from(Node.nodes(node), ([, p]) => path.concat(p))
)
}
}
}
},
() => {
updateDirtyPaths(editor, newDirtyPaths, p => {
let newPath: Path | null = p
for (const op of batchedOps) {
if (Path.operationCanTransformPath(op)) {
newPath = Path.transform(newPath, op)
if (!newPath) {
return null
},
() => {
updateDirtyPaths(editor, newDirtyPaths, p => {
let newPath: Path | null = p
for (const op of batchedOps) {
if (Path.operationCanTransformPath(op)) {
newPath = Path.transform(newPath, op)
if (!newPath) {
return null
}
}
}
}
return newPath
})
return newPath
})
}
)
} else {
for (const node of nodes as Node[]) {
const path = parentPath.concat(index)
index++

editor.apply({ type: 'insert_node', path, node })
at = Path.next(at as Path)
}
)
}

at = Path.previous(at)

Expand Down
5 changes: 4 additions & 1 deletion packages/slate/src/transforms-text/insert-fragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const insertFragment: TextTransforms['insertFragment'] = (
) => {
Editor.withoutNormalizing(editor, () => {
const { hanging = false, voids = false } = options
let { at = getDefaultInsertLocation(editor) } = options
let { at = getDefaultInsertLocation(editor), batchDirty = true } = options

if (!fragment.length) {
return
Expand Down Expand Up @@ -187,6 +187,7 @@ export const insertFragment: TextTransforms['insertFragment'] = (
match: n => Text.isText(n) || Editor.isInline(editor, n),
mode: 'highest',
voids,
batchDirty,
})

if (isBlockEmpty && !starts.length && middles.length && !ends.length) {
Expand All @@ -198,13 +199,15 @@ export const insertFragment: TextTransforms['insertFragment'] = (
match: n => Element.isElement(n) && Editor.isBlock(editor, n),
mode: 'lowest',
voids,
batchDirty,
})

Transforms.insertNodes(editor, ends, {
at: endRef.current!,
match: n => Text.isText(n) || Editor.isInline(editor, n),
mode: 'highest',
voids,
batchDirty,
})

if (!options.at) {
Expand Down
36 changes: 35 additions & 1 deletion packages/slate/test/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import assert from 'assert'
import { cloneDeep } from 'lodash';

Check failure on line 2 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
import { fixtures } from '../../../support/fixtures'
import { Editor } from 'slate'
import { Editor, createEditor } from 'slate'
import { createHyperscript } from 'slate-hyperscript'

describe('slate', () => {
Expand Down Expand Up @@ -45,6 +46,31 @@ describe('slate', () => {
const result = test(input)
assert.deepEqual(result, output)
})
// make sure with or without batchDirty, the normalize result is the same
const testBatchDirty = ({ module }) => {
const { input, run } = module

const input2 = createEditor();

Check failure on line 53 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
input2.children = cloneDeep(input.children);

Check failure on line 54 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
input2.selection = cloneDeep(input.selection);

Check failure on line 55 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`

const dirties1 = [];

Check failure on line 57 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
const dirties2 = [];

Check failure on line 58 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`

const editor1 = withBatchTest(withTest(input), dirties1);

Check failure on line 60 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
const editor2 = withBatchTest(withTest(input2), dirties2);

Check failure on line 61 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`

run(editor1, { batchDirty: true })
run(editor2, { batchDirty: false })

Check failure on line 65 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `····`
assert.equal(dirties1.join(' '), dirties2.join(' '));

Check failure on line 66 in packages/slate/test/index.js

View workflow job for this annotation

GitHub Actions / lint:eslint

Delete `;`
}
fixtures(__dirname, 'transforms/insertNodes', ({ module }) => {
testBatchDirty({ module })
})
fixtures(__dirname, 'transforms/insertFragment', ({ module }) => {
testBatchDirty({ module })
})
})
const withTest = editor => {
const { isInline, isVoid, isElementReadOnly, isSelectable } = editor
Expand All @@ -62,6 +88,14 @@ const withTest = editor => {
}
return editor
}
const withBatchTest = (editor, dirties) => {
const { normalizeNode } = editor
editor.normalizeNode = ([node, path]) => {
dirties.push(JSON.stringify(path));
normalizeNode([node, path])
}
return editor
}
export const jsx = createHyperscript({
elements: {
block: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
Expand All @@ -11,7 +11,8 @@ export const run = editor => {
</block>
<block>two</block>
<block>three</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<block>one</block>
<block>two</block>
<block>three</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const fragment = (
<block>two</block>
</fragment>
)
export const run = editor => {
Transforms.insertFragment(editor, fragment)
export const run = (editor, options = {}) => {
Transforms.insertFragment(editor, fragment, options)
}
export const input = (
<editor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<block>one</block>
<block>two</block>
<block>three</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<block>one</block>
<block>two</block>
<block>three</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<block>one</block>
<block>two</block>
<block>three</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
Expand All @@ -15,7 +15,8 @@ export const run = editor => {
<block>
seven<inline>eight</inline>nine
</block>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<inline>fragment</inline>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<inline>fragment</inline>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import { Transforms } from 'slate'
import { jsx } from '../../..'

export const run = editor => {
export const run = (editor, options = {}) => {
Transforms.insertFragment(
editor,
<fragment>
<inline>fragment</inline>
</fragment>
</fragment>,
options,
)
}
export const input = (
Expand Down
Loading

0 comments on commit 16bd79d

Please sign in to comment.