Skip to content

Commit addf0c5

Browse files
authored
Remove immer, making the core slate package dependency-free (#5971)
* extracted modify functions into util file for reuse * changed type signature to work with any ancestor root node * switched from immer to existing modify functions * removed dependencies on immer and (unused) tiny-warning * changeset
1 parent d0d192b commit addf0c5

File tree

6 files changed

+139
-132
lines changed

6 files changed

+139
-132
lines changed

.changeset/purple-tigers-leave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'slate': patch
3+
---
4+
5+
Removed the last traces of immer and eliminated it as a dependency

packages/slate/package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
"files": [
1414
"dist/"
1515
],
16-
"dependencies": {
17-
"immer": "^10.0.3",
18-
"tiny-warning": "^1.0.3"
19-
},
2016
"devDependencies": {
2117
"@babel/runtime": "^7.23.2",
2218
"lodash": "^4.17.21",

packages/slate/src/interfaces/node.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { produce } from 'immer'
21
import { Editor, Path, Range, Scrubber, Text } from '..'
32
import { Element, ElementEntry } from './element'
3+
import { modifyChildren, modifyLeaf, removeChildren } from '../utils/modify'
44

55
/**
66
* The `Node` union type represents all of the different types of nodes that
@@ -357,35 +357,37 @@ export const Node: NodeInterface = {
357357
},
358358

359359
fragment<T extends Ancestor = Editor>(root: T, range: Range): T['children'] {
360-
const newRoot = produce({ children: root.children }, r => {
361-
const [start, end] = Range.edges(range)
362-
const nodeEntries = Node.nodes(r, {
363-
reverse: true,
364-
pass: ([, path]) => !Range.includes(range, path),
365-
})
366-
367-
for (const [, path] of nodeEntries) {
368-
if (!Range.includes(range, path)) {
369-
const parent = Node.parent(r, path)
370-
const index = path[path.length - 1]
371-
parent.children.splice(index, 1)
372-
}
360+
const newRoot = { children: root.children }
373361

374-
if (Path.equals(path, end.path)) {
375-
const leaf = Node.leaf(r, path)
376-
leaf.text = leaf.text.slice(0, end.offset)
377-
}
362+
const [start, end] = Range.edges(range)
363+
const nodeEntries = Node.nodes(newRoot, {
364+
reverse: true,
365+
pass: ([, path]) => !Range.includes(range, path),
366+
})
378367

379-
if (Path.equals(path, start.path)) {
380-
const leaf = Node.leaf(r, path)
381-
leaf.text = leaf.text.slice(start.offset)
382-
}
368+
for (const [, path] of nodeEntries) {
369+
if (!Range.includes(range, path)) {
370+
const index = path[path.length - 1]
371+
372+
modifyChildren(newRoot, Path.parent(path), children =>
373+
removeChildren(children, index, 1)
374+
)
383375
}
384376

385-
if (Editor.isEditor(r)) {
386-
r.selection = null
377+
if (Path.equals(path, end.path)) {
378+
modifyLeaf(newRoot, path, node => {
379+
const before = node.text.slice(0, end.offset)
380+
return { ...node, text: before }
381+
})
387382
}
388-
})
383+
384+
if (Path.equals(path, start.path)) {
385+
modifyLeaf(newRoot, path, node => {
386+
const before = node.text.slice(start.offset)
387+
return { ...node, text: before }
388+
})
389+
}
390+
}
389391

390392
return newRoot.children
391393
},

packages/slate/src/interfaces/transforms/general.ts

Lines changed: 8 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
Ancestor,
32
Descendant,
43
Editor,
54
Element,
@@ -13,6 +12,14 @@ import {
1312
Selection,
1413
Text,
1514
} from '../../index'
15+
import {
16+
insertChildren,
17+
modifyChildren,
18+
modifyDescendant,
19+
modifyLeaf,
20+
removeChildren,
21+
replaceChildren,
22+
} from '../../utils/modify'
1623

1724
export interface GeneralTransforms {
1825
/**
@@ -21,92 +28,6 @@ export interface GeneralTransforms {
2128
transform: (editor: Editor, op: Operation) => void
2229
}
2330

24-
const insertChildren = <T>(xs: T[], index: number, ...newValues: T[]) => [
25-
...xs.slice(0, index),
26-
...newValues,
27-
...xs.slice(index),
28-
]
29-
30-
const replaceChildren = <T>(
31-
xs: T[],
32-
index: number,
33-
removeCount: number,
34-
...newValues: T[]
35-
) => [...xs.slice(0, index), ...newValues, ...xs.slice(index + removeCount)]
36-
37-
const removeChildren = replaceChildren
38-
39-
/**
40-
* Replace a descendant with a new node, replacing all ancestors
41-
*/
42-
const modifyDescendant = <N extends Descendant>(
43-
editor: Editor,
44-
path: Path,
45-
f: (node: N) => N
46-
) => {
47-
if (path.length === 0) {
48-
throw new Error('Cannot modify the editor')
49-
}
50-
51-
const node = Node.get(editor, path) as N
52-
const slicedPath = path.slice()
53-
let modifiedNode: Node = f(node)
54-
55-
while (slicedPath.length > 1) {
56-
const index = slicedPath.pop()!
57-
const ancestorNode = Node.get(editor, slicedPath) as Ancestor
58-
59-
modifiedNode = {
60-
...ancestorNode,
61-
children: replaceChildren(ancestorNode.children, index, 1, modifiedNode),
62-
}
63-
}
64-
65-
const index = slicedPath.pop()!
66-
editor.children = replaceChildren(editor.children, index, 1, modifiedNode)
67-
}
68-
69-
/**
70-
* Replace the children of a node, replacing all ancestors
71-
*/
72-
const modifyChildren = (
73-
editor: Editor,
74-
path: Path,
75-
f: (children: Descendant[]) => Descendant[]
76-
) => {
77-
if (path.length === 0) {
78-
editor.children = f(editor.children)
79-
} else {
80-
modifyDescendant<Element>(editor, path, node => {
81-
if (Text.isText(node)) {
82-
throw new Error(
83-
`Cannot get the element at path [${path}] because it refers to a leaf node: ${Scrubber.stringify(
84-
node
85-
)}`
86-
)
87-
}
88-
89-
return { ...node, children: f(node.children) }
90-
})
91-
}
92-
}
93-
94-
/**
95-
* Replace a leaf, replacing all ancestors
96-
*/
97-
const modifyLeaf = (editor: Editor, path: Path, f: (leaf: Text) => Text) =>
98-
modifyDescendant(editor, path, node => {
99-
if (!Text.isText(node)) {
100-
throw new Error(
101-
`Cannot get the leaf node at path [${path}] because it refers to a non-leaf node: ${Scrubber.stringify(
102-
node
103-
)}`
104-
)
105-
}
106-
107-
return f(node)
108-
})
109-
11031
// eslint-disable-next-line no-redeclare
11132
export const GeneralTransforms: GeneralTransforms = {
11233
transform(editor: Editor, op: Operation): void {

packages/slate/src/utils/modify.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import {
2+
Ancestor,
3+
Descendant,
4+
Element,
5+
Node,
6+
Path,
7+
Scrubber,
8+
Text,
9+
} from '../interfaces'
10+
11+
export const insertChildren = <T>(
12+
xs: T[],
13+
index: number,
14+
...newValues: T[]
15+
) => [...xs.slice(0, index), ...newValues, ...xs.slice(index)]
16+
17+
export const replaceChildren = <T>(
18+
xs: T[],
19+
index: number,
20+
removeCount: number,
21+
...newValues: T[]
22+
) => [...xs.slice(0, index), ...newValues, ...xs.slice(index + removeCount)]
23+
24+
export const removeChildren = replaceChildren
25+
26+
/**
27+
* Replace a descendant with a new node, replacing all ancestors
28+
*/
29+
export const modifyDescendant = <N extends Descendant>(
30+
root: Ancestor,
31+
path: Path,
32+
f: (node: N) => N
33+
) => {
34+
if (path.length === 0) {
35+
throw new Error('Cannot modify the editor')
36+
}
37+
38+
const node = Node.get(root, path) as N
39+
const slicedPath = path.slice()
40+
let modifiedNode: Node = f(node)
41+
42+
while (slicedPath.length > 1) {
43+
const index = slicedPath.pop()!
44+
const ancestorNode = Node.get(root, slicedPath) as Ancestor
45+
46+
modifiedNode = {
47+
...ancestorNode,
48+
children: replaceChildren(ancestorNode.children, index, 1, modifiedNode),
49+
}
50+
}
51+
52+
const index = slicedPath.pop()!
53+
root.children = replaceChildren(root.children, index, 1, modifiedNode)
54+
}
55+
56+
/**
57+
* Replace the children of a node, replacing all ancestors
58+
*/
59+
export const modifyChildren = (
60+
root: Ancestor,
61+
path: Path,
62+
f: (children: Descendant[]) => Descendant[]
63+
) => {
64+
if (path.length === 0) {
65+
root.children = f(root.children)
66+
} else {
67+
modifyDescendant<Element>(root, path, node => {
68+
if (Text.isText(node)) {
69+
throw new Error(
70+
`Cannot get the element at path [${path}] because it refers to a leaf node: ${Scrubber.stringify(
71+
node
72+
)}`
73+
)
74+
}
75+
76+
return { ...node, children: f(node.children) }
77+
})
78+
}
79+
}
80+
81+
/**
82+
* Replace a leaf, replacing all ancestors
83+
*/
84+
export const modifyLeaf = (
85+
root: Ancestor,
86+
path: Path,
87+
f: (leaf: Text) => Text
88+
) =>
89+
modifyDescendant(root, path, node => {
90+
if (!Text.isText(node)) {
91+
throw new Error(
92+
`Cannot get the leaf node at path [${path}] because it refers to a non-leaf node: ${Scrubber.stringify(
93+
node
94+
)}`
95+
)
96+
}
97+
98+
return f(node)
99+
})

yarn.lock

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8240,13 +8240,6 @@ __metadata:
82408240
languageName: node
82418241
linkType: hard
82428242

8243-
"immer@npm:^10.0.3":
8244-
version: 10.0.3
8245-
resolution: "immer@npm:10.0.3"
8246-
checksum: 0be07be2f278bd1988112613648e0cf9a64fc316d5b4817f273b519fbfed0f1714275b041911f0b8c560c199b2e3430824ce620c23262c96c9d4efc9909ff1cc
8247-
languageName: node
8248-
linkType: hard
8249-
82508243
"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0":
82518244
version: 3.3.0
82528245
resolution: "import-fresh@npm:3.3.0"
@@ -13752,11 +13745,9 @@ __metadata:
1375213745
resolution: "slate@workspace:packages/slate"
1375313746
dependencies:
1375413747
"@babel/runtime": "npm:^7.23.2"
13755-
immer: "npm:^10.0.3"
1375613748
lodash: "npm:^4.17.21"
1375713749
slate-hyperscript: "npm:^0.115.0"
1375813750
source-map-loader: "npm:^4.0.1"
13759-
tiny-warning: "npm:^1.0.3"
1376013751
languageName: unknown
1376113752
linkType: soft
1376213753

@@ -14523,13 +14514,6 @@ __metadata:
1452314514
languageName: node
1452414515
linkType: hard
1452514516

14526-
"tiny-warning@npm:^1.0.3":
14527-
version: 1.0.3
14528-
resolution: "tiny-warning@npm:1.0.3"
14529-
checksum: da62c4acac565902f0624b123eed6dd3509bc9a8d30c06e017104bedcf5d35810da8ff72864400ad19c5c7806fc0a8323c68baf3e326af7cb7d969f846100d71
14530-
languageName: node
14531-
linkType: hard
14532-
1453314517
"titleize@npm:^3.0.0":
1453414518
version: 3.0.0
1453514519
resolution: "titleize@npm:3.0.0"

0 commit comments

Comments
 (0)