Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/slate/markdown-to-slate/handle-close.ts
1697 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Descendant } from "slate";
7
import { State } from "./types";
8
import { getMarkdownToSlate } from "../elements/register";
9
import { register } from "./register";
10
import { parse } from "./parse";
11
import getSource from "./source";
12
import { setCache } from "./cache";
13
14
function handleClose({ token, state, cache }) {
15
if (!state.close_type) return;
16
if (state.contents == null) {
17
throw Error("bug -- state.contents must not be null");
18
}
19
20
// Currently collecting the contents to parse when we hit the close_type.
21
22
if (token.type == state.open_type) {
23
// Hitting same open type *again* (it's nested), so increase nesting.
24
state.nesting += 1;
25
}
26
27
if (token.type === state.close_type) {
28
// Hit the close_type
29
if (state.nesting > 0) {
30
// We're nested, so just go up one.
31
state.nesting -= 1;
32
} else {
33
// Not nested, so done: parse the accumulated array of children
34
// using a new state:
35
const child_state: State = {
36
nesting: 0,
37
marks: state.marks,
38
lines: state.lines,
39
};
40
const children: Descendant[] = [];
41
let isEmpty = true;
42
// Note a RULE: "Block nodes can only contain other blocks, or inline and text nodes."
43
// See https://docs.slatejs.org/concepts/10-normalizing
44
// This means that all children nodes here have to be either *inline/text* or they
45
// all have to be blocks themselves -- no mixing. Our markdown parser I think also
46
// does this, except for one weird special case which involves hidden:true that is
47
// used for tight lists.
48
49
state.tight = false;
50
for (const token2 of state.contents) {
51
for (const node of parse(token2, child_state, cache)) {
52
if (child_state.tight) {
53
state.tight = true;
54
}
55
isEmpty = false;
56
children.push(node);
57
}
58
}
59
// console.log("children = ", JSON.stringify(children), isEmpty);
60
if (isEmpty) {
61
// it is illegal for the children to be empty.
62
if (token.type == "list_item_close") {
63
// This is to match with the rule in ../normalize defined in
64
// ensureListContainsListItems that "if the the children of the
65
// list item are leaves, wrap them all in a paragraph".
66
children.push({ children: [{ text: "" }], type: "paragraph" });
67
} else {
68
children.push({ text: "" });
69
}
70
}
71
const i = state.close_type.lastIndexOf("_");
72
const type = state.close_type.slice(0, i);
73
delete state.close_type;
74
delete state.contents;
75
76
const markdownToSlate = getMarkdownToSlate(type);
77
const node = markdownToSlate({
78
type,
79
token,
80
children,
81
state,
82
isEmpty,
83
cache,
84
});
85
if (type == "bullet_list" || type == "ordered_list") {
86
// tight-ness is ONLY used by lists and we only want it to propagate
87
// up to the enclosing list.
88
delete state.tight;
89
}
90
if (node == null) {
91
return [];
92
}
93
if (
94
cache != null &&
95
state.open_token?.level === 0 &&
96
state.open_token?.map != null
97
) {
98
const markdown = getSource({
99
start: state.open_token.map[0],
100
end: state.open_token.map[1],
101
lines: state.lines,
102
});
103
setCache({ cache, node, markdown });
104
}
105
return [node];
106
}
107
}
108
109
state.contents.push(token);
110
return [];
111
}
112
113
register(handleClose);
114
115