A basic $dfs (#1351)

This commit is contained in:
Gerard Rovira
2022-02-23 18:34:52 +00:00
committed by acywatson
parent e72688de8e
commit a6867f18bc
3 changed files with 65 additions and 55 deletions

View File

@ -11,13 +11,17 @@ import type {LexicalNode} from 'lexical';
import {$getRoot, $isElementNode, $isLineBreakNode, $isTextNode} from 'lexical'; import {$getRoot, $isElementNode, $isLineBreakNode, $isTextNode} from 'lexical';
export function $dfs__DEPRECATED( export function $dfs(
startingNode: LexicalNode, startingNode?: LexicalNode,
nextNode: (LexicalNode) => null | LexicalNode, endingNode?: LexicalNode,
): void { ): Array<LexicalNode> {
let node = startingNode; const nodes = [];
nextNode(node); const start = (startingNode || $getRoot()).getLatest();
while (node !== null) { const end =
endingNode || ($isElementNode(start) ? start.getLastDescendant() : start);
let node = start;
while (node !== null && !node.is(end)) {
nodes.push(node);
if ($isElementNode(node) && node.getChildrenSize() > 0) { if ($isElementNode(node) && node.getChildrenSize() > 0) {
node = node.getFirstChild(); node = node.getFirstChild();
} else { } else {
@ -32,10 +36,11 @@ export function $dfs__DEPRECATED(
} }
} }
} }
if (node !== null) {
node = nextNode(node);
}
} }
if (node !== null && node.is(end)) {
nodes.push(node);
}
return nodes;
} }
export function $getNearestNodeOfType<T: LexicalNode>( export function $getNearestNodeOfType<T: LexicalNode>(

View File

@ -7,25 +7,26 @@
* @flow strict * @flow strict
*/ */
import type {LexicalEditor, LexicalNode, NodeKey, State} from 'lexical';
import { import {
$areSiblingsNullOrSpace, $areSiblingsNullOrSpace,
$dfs__DEPRECATED,
$getNearestNodeOfType, $getNearestNodeOfType,
} from '@lexical/helpers/nodes'; } from '@lexical/helpers/nodes';
import {$createListItemNode, $createListNode, ListNode} from '@lexical/list'; import {$createListItemNode, $createListNode, ListNode} from '@lexical/list';
import { import {
$createParagraphNode, $createParagraphNode,
$createTextNode, $createTextNode,
$getNodeByKey,
$getRoot, $getRoot,
$isParagraphNode, LexicalEditor,
NodeKey,
State,
} from 'lexical'; } from 'lexical';
import { import {
$createTestElementNode, $createTestElementNode,
initializeUnitTest, initializeUnitTest,
} from '../../../../lexical/src/__tests__/utils'; } from '../../../../lexical/src/__tests__/utils';
import {$dfs} from '../../LexicalNodeHelpers';
describe('LexicalNodeHelpers tests', () => { describe('LexicalNodeHelpers tests', () => {
initializeUnitTest((testEnv) => { initializeUnitTest((testEnv) => {
@ -78,47 +79,57 @@ describe('LexicalNodeHelpers tests', () => {
text6.getKey(), text6.getKey(),
]; ];
}); });
editor.getEditorState().read(() => {
const dfsKeys = []; const expectedNodes = expectedKeys.map((nodeKey) =>
await editor.update((state: State) => { $getNodeByKey(nodeKey).getLatest(),
const root = $getRoot(); );
$dfs__DEPRECATED(root, (node: LexicalNode) => { const first = expectedNodes[0];
dfsKeys.push(node.getKey()); const second = expectedNodes[1];
return node; const last = expectedNodes[expectedNodes.length - 1];
}); const secondToLast = expectedNodes[expectedNodes.length - 2];
expect($dfs(first, last)).toEqual(expectedNodes);
expect($dfs(second, secondToLast)).toEqual(
expectedNodes.slice(1, expectedKeys.length - 1),
);
expect($dfs()).toEqual(expectedNodes);
expect($dfs($getRoot())).toEqual(expectedNodes);
}); });
expect(dfsKeys).toEqual(expectedKeys);
}); });
test('Skip some DFS nodes', async () => { test('DFS triggers getLatest()', async () => {
const editor: LexicalEditor = testEnv.editor; const editor: LexicalEditor = testEnv.editor;
let expectedKeys: Array<NodeKey> = []; let rootKey;
await editor.update((state: State) => { let paragraphKey;
let block1Key;
let block2Key;
await editor.update(() => {
const root = $getRoot(); const root = $getRoot();
const paragraph1 = $createParagraphNode(); const paragraph = $createParagraphNode();
const block1 = $createTestElementNode(); const block1 = $createTestElementNode();
const block2 = $createTestElementNode(); const block2 = $createTestElementNode();
rootKey = root.getKey();
paragraphKey = paragraph.getKey();
block1Key = block1.getKey();
block2Key = block2.getKey();
root.append(paragraph);
paragraph.append(block1, block2);
});
await editor.update(() => {
const root = $getNodeByKey(rootKey);
const paragraph = $getNodeByKey(paragraphKey);
const block1 = $getNodeByKey(block1Key);
const block2 = $getNodeByKey(block2Key);
const block3 = $createTestElementNode(); const block3 = $createTestElementNode();
root.append(paragraph1); block1.append(block3);
paragraph1.append(block1, block2, block3);
expectedKeys = [root.getKey(), paragraph1.getKey(), block3.getKey()]; expect($dfs(root)).toEqual([
root.getLatest(),
paragraph.getLatest(),
block1.getLatest(),
block3.getLatest(),
block2.getLatest(),
]);
}); });
const dfsKeys = [];
await editor.update((state: State) => {
const root = $getRoot();
$dfs__DEPRECATED(root, (node: LexicalNode) => {
dfsKeys.push(node.getKey());
if ($isParagraphNode(node)) {
return (
node.getLastChild() && node.getLastChild().getPreviousSibling()
);
}
return node;
});
});
expect(dfsKeys).toEqual(expectedKeys);
}); });
test('getNearestNodeOfType should return the top node if it is of the given type.', async () => { test('getNearestNodeOfType should return the top node if it is of the given type.', async () => {

View File

@ -9,11 +9,10 @@
import type {LexicalEditor, LexicalNode} from 'lexical'; import type {LexicalEditor, LexicalNode} from 'lexical';
import {$dfs__DEPRECATED} from '@lexical/helpers/nodes'; import {$dfs} from '@lexical/helpers/nodes';
import {$textContentCurry} from '@lexical/helpers/root'; import {$textContentCurry} from '@lexical/helpers/root';
import withSubscriptions from '@lexical/react/withSubscriptions'; import withSubscriptions from '@lexical/react/withSubscriptions';
import { import {
$getRoot,
$getSelection, $getSelection,
$isLeafNode, $isLeafNode,
$isRangeSelection, $isRangeSelection,
@ -127,15 +126,10 @@ function findOffset(
} }
function $wrapOverflowedNodes(offset: number): void { function $wrapOverflowedNodes(offset: number): void {
const root = $getRoot(); const dfsNodes = $dfs();
const dfsNodesLength = dfsNodes.length;
let accumulatedLength = 0; let accumulatedLength = 0;
for (let i = 0; i < dfsNodesLength; i += 1) {
const dfsNodes = [];
$dfs__DEPRECATED(root, (node: LexicalNode) => {
dfsNodes.push(node);
return node;
});
for (let i = 0; i < dfsNodes.length; i += 1) {
const node = dfsNodes[i]; const node = dfsNodes[i];
if ($isOverflowNode(node)) { if ($isOverflowNode(node)) {
const previousLength = accumulatedLength; const previousLength = accumulatedLength;