Skip to content

Commit

Permalink
Merge pull request #222 from prezly/refactor/serialization
Browse files Browse the repository at this point in the history
[MT-5076] Refactor - Move pre-serialization cleanup to Extension
  • Loading branch information
e1himself authored Jul 15, 2022
2 parents 0cbfa4d + 0c23cb0 commit 787d556
Show file tree
Hide file tree
Showing 24 changed files with 145 additions and 115 deletions.
13 changes: 5 additions & 8 deletions packages/slate-commons/src/lib/withoutNodes.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import type { Descendant, Node } from 'slate';
import type { Node } from 'slate';
import { Text } from 'slate';

export function withoutNodes<T extends Descendant>(
nodes: T[],
match: (node: Node) => boolean,
): T[] {
export function withoutNodes<T extends Node>(nodes: T[], match: (node: Node) => boolean): T[] {
return nodes
.map((node: T): T | null => {
if (Text.isText(node)) {
return node;
}
if (match(node)) {
return null;
}
if (Text.isText(node)) {
return node;
}
return { ...node, children: withoutNodes(node.children, match) };
})
.filter((node: T | null): node is T => node !== null);
Expand Down
2 changes: 2 additions & 0 deletions packages/slate-commons/src/types/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { OnDOMBeforeInput } from './OnDOMBeforeInput';
import type { OnKeyDown } from './OnKeyDown';
import type { RenderElement } from './RenderElement';
import type { RenderLeaf } from './RenderLeaf';
import type { Serialize } from './Serialize';
import type { WithOverrides } from './WithOverrides';

export interface Extension {
Expand All @@ -21,5 +22,6 @@ export interface Extension {
onKeyDown?: OnKeyDown | null;
renderElement?: RenderElement;
renderLeaf?: RenderLeaf;
serialize?: Serialize;
withOverrides?: WithOverrides;
}
7 changes: 7 additions & 0 deletions packages/slate-commons/src/types/Serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Node } from 'slate';

/**
* Cleanup editor value before reporting it to the outer world.
* Useful to clean up internal temporary nodes and properties.
*/
export type Serialize = (nodes: Node[]) => Node[];
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Extension } from '@prezly/slate-commons';
import { createDeserializeElement, EditorCommands } from '@prezly/slate-commons';
import { createDeserializeElement, EditorCommands, withoutNodes } from '@prezly/slate-commons';
import type { ImageNode, ParagraphNode } from '@prezly/slate-types';
import { IMAGE_NODE_TYPE, isImageNode } from '@prezly/slate-types';
import { isHotkey } from 'is-hotkey';
Expand Down Expand Up @@ -158,5 +158,6 @@ export const ImageExtension = ({

return undefined;
},
serialize: (nodes) => withoutNodes(nodes, isImageCandidateElement),
withOverrides: withImages,
});
1 change: 0 additions & 1 deletion packages/slate-editor/src/extensions/image/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ export {
getCurrentImageNodeEntry,
isImageCandidateElement,
} from './lib';
export { withoutImageCandidates } from './serialization';
export { removeImage } from './transforms';
export type { ImageExtensionConfiguration, ImageCandidateNode } from './types';

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Extension } from '@prezly/slate-commons';
import { type Extension, withoutNodes } from '@prezly/slate-commons';
import React from 'react';
import type { RenderElementProps } from 'slate-react';

Expand Down Expand Up @@ -33,5 +33,6 @@ export const LoaderExtension = ({

return undefined;
},
serialize: (nodes) => withoutNodes(nodes, isLoaderElement),
withOverrides: withLoaders,
});
1 change: 0 additions & 1 deletion packages/slate-editor/src/extensions/loader/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ export { LoaderExtension, EXTENSION_ID } from './LoaderExtension';

export { LOADER_NODE_TYPE } from './constants';
export { createLoader, findLoaderPath, isLoaderElement, loaderPromiseManager } from './lib';
export { withoutLoaders } from './serialization';
export { removeLoader, replaceLoader } from './transforms';
export { type LoaderNode, LoaderContentType } from './types';

This file was deleted.

This file was deleted.

11 changes: 8 additions & 3 deletions packages/slate-editor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import type { BaseEditor } from 'slate';
import type { HistoryEditor } from 'slate-history';
import type { ReactEditor } from 'slate-react';

export * from '@prezly/slate-types';
export * from './components';
export * as Icons from './icons';
export * from './modules/editor';
export { EditableWithExtensions } from './modules/editable';

export type { SearchProps as CoverageSearchProps } from './extensions/coverage';
export { type SearchProps as CoverageSearchProps, createCoverage } from './extensions/coverage';
export { createEmbed } from './extensions/embed';
export {
type SearchProps as PressContactsSearchProps,
Expand All @@ -17,11 +18,15 @@ export {
export type { User } from './extensions/user-mentions';
export { type ResultPromise, type UploadcareOptions, withUploadcare } from './modules/uploadcare';

import type { RichBlocksAwareEditor } from './modules/editor';
import type { RichBlocksAwareEditor, SerializingEditor } from './modules/editor';

declare module 'slate' {
interface CustomTypes {
Editor: BaseEditor & ReactEditor & HistoryEditor & RichBlocksAwareEditor;
Editor: BaseEditor &
ReactEditor &
HistoryEditor &
RichBlocksAwareEditor &
SerializingEditor;
Element: ElementNode;
Text: TextNode;
}
Expand Down
9 changes: 6 additions & 3 deletions packages/slate-editor/src/modules/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,10 @@ export const Editor = forwardRef<EditorRef, EditorProps>((props, forwardedRef) =
events,
focus: () => EditorCommands.focus(editor),
isEmpty: () => EditorCommands.isEmpty(editor),
isEqualTo: (value) => isEditorValueEqual(value, editor.children as Value),
isEqualTo: (value) => isEditorValueEqual(editor, value, editor.children as Value),
isFocused: () => ReactEditor.isFocused(editor),
isModified: () => !isEditorValueEqual(getInitialValue(), editor.children as Value),
isModified: () =>
!isEditorValueEqual(editor, getInitialValue(), editor.children as Value),
resetValue: (value) => {
EditorCommands.resetNodes(editor, value, editor.selection);
},
Expand Down Expand Up @@ -369,7 +370,9 @@ export const Editor = forwardRef<EditorRef, EditorProps>((props, forwardedRef) =
const hasCustomPlaceholder =
withFloatingAddMenu && (ReactEditor.isFocused(editor) || isFloatingAddMenuOpen);

const onChange = useOnChange(props.onChange);
const onChange = useOnChange((value) => {
props.onChange(editor.serialize(value) as Value);
});

return (
<div
Expand Down
9 changes: 8 additions & 1 deletion packages/slate-editor/src/modules/editor/createEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { flow } from '#lodash';

import { withNodesHierarchy, hierarchySchema } from '#modules/nodes-hierarchy';

import { withDeserializeHtml, withFilePasting, withNonEmptyValue, withRichBlocks } from './plugins';
import {
withDeserializeHtml,
withFilePasting,
withNonEmptyValue,
withRichBlocks,
withSerialization,
} from './plugins';

export function createEditor(
baseEditor: Editor,
Expand All @@ -39,6 +45,7 @@ export function createEditor(
withDeserializeHtml(getExtensions),
withFilePasting(getExtensions),
withRichBlocks(getExtensions),
withSerialization(getExtensions),
...overrides,
...plugins,
])(baseEditor);
Expand Down
11 changes: 2 additions & 9 deletions packages/slate-editor/src/modules/editor/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
export { Editor } from './Editor';
export { createEditor } from './createEditor';
export {
createEmptyValue,
createEmptyEditorValueAsString,
createEditorValueWithCoverageAsString,
serialize,
deserialize,
isEditorValueEqual,
} from './lib';
export type { RichBlocksAwareEditor } from './plugins';
export { createEmptyValue } from './lib';
export type { RichBlocksAwareEditor, SerializingEditor } from './plugins';
export type { EditorRef, EditorProps, Value } from './types';
export { useEditorEvents } from './useEditorEvents';

This file was deleted.

This file was deleted.

20 changes: 0 additions & 20 deletions packages/slate-editor/src/modules/editor/lib/deserialize.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/slate-editor/src/modules/editor/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
export { createEditorValueWithCoverageAsString } from './createEditorValueWithCoverageAsString';
export { createEmptyEditorValueAsString } from './createEmptyEditorValueAsString';
export { createEmptyValue } from './createEmptyValue';
export { createOnCut } from './createOnCut';

export { serialize } from './serialize';
export { deserialize } from './deserialize';

export { insertDivider } from './divider';
export {
handleAddAttachment,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,83 @@
import { deserialize } from './deserialize';
import { withoutNodes } from '@prezly/slate-commons';
import { isQuoteNode } from '@prezly/slate-types';
import { createEditor as createSlateEditor } from 'slate';

import { createEditor } from '#modules/editor';

import { isEditorValueEqual } from './isEditorValueEqual';

describe('slate-editor - isEditorValueEqual', () => {
it('should return true for equivalent values', () => {
const editor = createEditor(createSlateEditor(), () => []);

const a = [
{
type: 'paragraph',
children: [{ text: 'Hello', bold: true }],
},
];
const b = [
{
type: 'paragraph',
children: [{ text: 'Hello', bold: true }],
},
];

expect(isEditorValueEqual(editor, a, b)).toBe(true);
});

it('should return false for non-equivalent values', () => {
const editor = createEditor(createSlateEditor(), () => []);

const a = [
{
type: 'paragraph',
children: [{ text: 'Hello', bold: true }],
},
];
const b = [
{
type: 'paragraph',
children: [{ text: 'hello', bold: true }],
},
];

expect(isEditorValueEqual(editor, a, b)).toBe(false);
});

it('should consider structural equality', () => {
const a = '{ "type": "document", "children": [] }';
const b = '{ "children": [], "type": "document" }';
expect(isEditorValueEqual(deserialize(a), deserialize(b))).toBe(true);
const editor = createEditor(createSlateEditor(), () => []);

const a = [
{
type: 'paragraph',
children: [{ text: 'Hello', bold: true }],
},
];
const b = [
{
children: [{ bold: true, text: 'Hello' }],
type: 'paragraph',
},
];

expect(isEditorValueEqual(editor, a, b)).toBe(true);
});

it('should run pre-serialization cleanup from extensions', () => {
const editor = createEditor(createSlateEditor(), () => [
{
id: 'PreSerializationCleanup',
serialize: (nodes) => withoutNodes(nodes, isQuoteNode),
},
]);

const a = [
{ type: 'paragraph', children: [{ text: 'A wise man once said:' }] },
{ type: 'block-quote', children: [{ text: 'Hello' }] },
];
const b = [{ type: 'paragraph', children: [{ text: 'A wise man once said:' }] }];

expect(isEditorValueEqual(editor, a, b)).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { Value } from '../types';
import type { Editor } from 'slate';

import { isEqual } from '#lodash';

import { serialize } from './serialize';
import type { Value } from '../types';

export function isEditorValueEqual(a: Value, b: Value): boolean {
return a === b || serialize(a) === serialize(b);
export function isEditorValueEqual(editor: Editor, a: Value, b: Value): boolean {
return a === b || isEqual(editor.serialize(a), editor.serialize(b));
}
17 changes: 0 additions & 17 deletions packages/slate-editor/src/modules/editor/lib/serialize.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/slate-editor/src/modules/editor/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { withDeserializeHtml } from './withDeserializeHtml';
export { withFilePasting } from './withFilePasting';
export { withNonEmptyValue } from './withNonEmptyValue';
export { type RichBlocksAwareEditor, withRichBlocks } from './withRichBlocks';
export { type SerializingEditor, withSerialization } from './withSerialization';
Loading

0 comments on commit 787d556

Please sign in to comment.