onchain-lexical-markdown 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OnchainLexicalMarkdown.js +11 -0
- package/README.md +96 -0
- package/flow/OnchainLexicalMarkdown.js.flow +130 -0
- package/package.json +45 -0
- package/src/MarkdownExport.ts +362 -0
- package/src/MarkdownImport.ts +343 -0
- package/src/MarkdownShortcuts.ts +529 -0
- package/src/MarkdownTransformers.ts +631 -0
- package/src/__tests__/unit/LexicalMarkdown.test.ts +891 -0
- package/src/fromMarkdownString.ts +39 -0
- package/src/importTextFormatTransformer.ts +137 -0
- package/src/importTextMatchTransformer.ts +108 -0
- package/src/importTextTransformers.ts +142 -0
- package/src/index.ts +81 -0
- package/src/toMarkdownString.ts +25 -0
- package/src/transformer/const.ts +12 -0
- package/src/transformer/hr.ts +37 -0
- package/src/transformer/index.ts +97 -0
- package/src/transformer/instance.ts +73 -0
- package/src/transformer/levelBasedControl.ts +95 -0
- package/src/transformer/table.ts +182 -0
- package/src/transformer/utils.ts +21 -0
- package/src/utils.ts +462 -0
package/src/utils.ts
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {ListNode} from '@lexical/list';
|
|
10
|
+
|
|
11
|
+
import {$isCodeNode} from '@lexical/code';
|
|
12
|
+
import {$isListItemNode, $isListNode} from '@lexical/list';
|
|
13
|
+
import {$isHeadingNode, $isQuoteNode} from '@lexical/rich-text';
|
|
14
|
+
import {
|
|
15
|
+
$isParagraphNode,
|
|
16
|
+
$isTextNode,
|
|
17
|
+
type ElementNode,
|
|
18
|
+
type LexicalNode,
|
|
19
|
+
type TextFormatType,
|
|
20
|
+
} from 'lexical';
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
ElementTransformer,
|
|
24
|
+
MultilineElementTransformer,
|
|
25
|
+
TextFormatTransformer,
|
|
26
|
+
TextMatchTransformer,
|
|
27
|
+
Transformer,
|
|
28
|
+
} from './MarkdownTransformers';
|
|
29
|
+
|
|
30
|
+
type MarkdownFormatKind =
|
|
31
|
+
| 'noTransformation'
|
|
32
|
+
| 'paragraphH1'
|
|
33
|
+
| 'paragraphH2'
|
|
34
|
+
| 'paragraphH3'
|
|
35
|
+
| 'paragraphH4'
|
|
36
|
+
| 'paragraphH5'
|
|
37
|
+
| 'paragraphH6'
|
|
38
|
+
| 'paragraphBlockQuote'
|
|
39
|
+
| 'paragraphUnorderedList'
|
|
40
|
+
| 'paragraphOrderedList'
|
|
41
|
+
| 'paragraphCodeBlock'
|
|
42
|
+
| 'horizontalRule'
|
|
43
|
+
| 'bold'
|
|
44
|
+
| 'code'
|
|
45
|
+
| 'italic'
|
|
46
|
+
| 'underline'
|
|
47
|
+
| 'strikethrough'
|
|
48
|
+
| 'italic_bold'
|
|
49
|
+
| 'strikethrough_italic'
|
|
50
|
+
| 'strikethrough_bold'
|
|
51
|
+
| 'strikethrough_italic_bold'
|
|
52
|
+
| 'link';
|
|
53
|
+
|
|
54
|
+
type MarkdownCriteria = Readonly<{
|
|
55
|
+
export?: (
|
|
56
|
+
node: LexicalNode,
|
|
57
|
+
traverseChildren: (elementNode: ElementNode) => string,
|
|
58
|
+
) => string | null;
|
|
59
|
+
exportFormat?: TextFormatType;
|
|
60
|
+
exportTag?: string;
|
|
61
|
+
exportTagClose?: string;
|
|
62
|
+
markdownFormatKind: MarkdownFormatKind | null | undefined;
|
|
63
|
+
regEx: RegExp;
|
|
64
|
+
regExForAutoFormatting: RegExp;
|
|
65
|
+
requiresParagraphStart: boolean | null | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
|
|
68
|
+
type MarkdownCriteriaArray = Array<MarkdownCriteria>;
|
|
69
|
+
|
|
70
|
+
const autoFormatBase: MarkdownCriteria = {
|
|
71
|
+
markdownFormatKind: null,
|
|
72
|
+
regEx: /(?:)/,
|
|
73
|
+
regExForAutoFormatting: /(?:)/,
|
|
74
|
+
requiresParagraphStart: false,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const paragraphStartBase: MarkdownCriteria = {
|
|
78
|
+
...autoFormatBase,
|
|
79
|
+
requiresParagraphStart: true,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const markdownHeader1: MarkdownCriteria = {
|
|
83
|
+
...paragraphStartBase,
|
|
84
|
+
export: createHeadingExport(1),
|
|
85
|
+
markdownFormatKind: 'paragraphH1',
|
|
86
|
+
regEx: /^(?:# )/,
|
|
87
|
+
regExForAutoFormatting: /^(?:# )/,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const markdownHeader2: MarkdownCriteria = {
|
|
91
|
+
...paragraphStartBase,
|
|
92
|
+
export: createHeadingExport(2),
|
|
93
|
+
markdownFormatKind: 'paragraphH2',
|
|
94
|
+
regEx: /^(?:## )/,
|
|
95
|
+
regExForAutoFormatting: /^(?:## )/,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const markdownHeader3: MarkdownCriteria = {
|
|
99
|
+
...paragraphStartBase,
|
|
100
|
+
export: createHeadingExport(3),
|
|
101
|
+
markdownFormatKind: 'paragraphH3',
|
|
102
|
+
regEx: /^(?:### )/,
|
|
103
|
+
regExForAutoFormatting: /^(?:### )/,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const markdownHeader4: MarkdownCriteria = {
|
|
107
|
+
...paragraphStartBase,
|
|
108
|
+
export: createHeadingExport(4),
|
|
109
|
+
markdownFormatKind: 'paragraphH4',
|
|
110
|
+
regEx: /^(?:#### )/,
|
|
111
|
+
regExForAutoFormatting: /^(?:#### )/,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const markdownHeader5: MarkdownCriteria = {
|
|
115
|
+
...paragraphStartBase,
|
|
116
|
+
export: createHeadingExport(5),
|
|
117
|
+
markdownFormatKind: 'paragraphH5',
|
|
118
|
+
regEx: /^(?:##### )/,
|
|
119
|
+
regExForAutoFormatting: /^(?:##### )/,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const markdownHeader6: MarkdownCriteria = {
|
|
123
|
+
...paragraphStartBase,
|
|
124
|
+
export: createHeadingExport(6),
|
|
125
|
+
markdownFormatKind: 'paragraphH6',
|
|
126
|
+
regEx: /^(?:###### )/,
|
|
127
|
+
regExForAutoFormatting: /^(?:###### )/,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const markdownBlockQuote: MarkdownCriteria = {
|
|
131
|
+
...paragraphStartBase,
|
|
132
|
+
export: blockQuoteExport,
|
|
133
|
+
markdownFormatKind: 'paragraphBlockQuote',
|
|
134
|
+
regEx: /^(?:> )/,
|
|
135
|
+
regExForAutoFormatting: /^(?:> )/,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const markdownUnorderedListDash: MarkdownCriteria = {
|
|
139
|
+
...paragraphStartBase,
|
|
140
|
+
export: listExport,
|
|
141
|
+
markdownFormatKind: 'paragraphUnorderedList',
|
|
142
|
+
regEx: /^(\s{0,10})(?:- )/,
|
|
143
|
+
regExForAutoFormatting: /^(\s{0,10})(?:- )/,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const markdownUnorderedListAsterisk: MarkdownCriteria = {
|
|
147
|
+
...paragraphStartBase,
|
|
148
|
+
export: listExport,
|
|
149
|
+
markdownFormatKind: 'paragraphUnorderedList',
|
|
150
|
+
regEx: /^(\s{0,10})(?:\* )/,
|
|
151
|
+
regExForAutoFormatting: /^(\s{0,10})(?:\* )/,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const markdownCodeBlock: MarkdownCriteria = {
|
|
155
|
+
...paragraphStartBase,
|
|
156
|
+
export: codeBlockExport,
|
|
157
|
+
markdownFormatKind: 'paragraphCodeBlock',
|
|
158
|
+
regEx: /^(```)$/,
|
|
159
|
+
regExForAutoFormatting: /^(```)([a-z]*)( )/,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const markdownOrderedList: MarkdownCriteria = {
|
|
163
|
+
...paragraphStartBase,
|
|
164
|
+
export: listExport,
|
|
165
|
+
markdownFormatKind: 'paragraphOrderedList',
|
|
166
|
+
regEx: /^(\s{0,10})(\d+)\.\s/,
|
|
167
|
+
regExForAutoFormatting: /^(\s{0,10})(\d+)\.\s/,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const markdownHorizontalRule: MarkdownCriteria = {
|
|
171
|
+
...paragraphStartBase,
|
|
172
|
+
markdownFormatKind: 'horizontalRule',
|
|
173
|
+
regEx: /^(?:\*\*\*)$/,
|
|
174
|
+
regExForAutoFormatting: /^(?:\*\*\* )/,
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const markdownHorizontalRuleUsingDashes: MarkdownCriteria = {
|
|
178
|
+
...paragraphStartBase,
|
|
179
|
+
markdownFormatKind: 'horizontalRule',
|
|
180
|
+
regEx: /^(?:---)$/,
|
|
181
|
+
regExForAutoFormatting: /^(?:--- )/,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const markdownInlineCode: MarkdownCriteria = {
|
|
185
|
+
...autoFormatBase,
|
|
186
|
+
exportFormat: 'code',
|
|
187
|
+
exportTag: '`',
|
|
188
|
+
markdownFormatKind: 'code',
|
|
189
|
+
regEx: /(`)(\s*)([^`]*)(\s*)(`)()/,
|
|
190
|
+
regExForAutoFormatting: /(`)(\s*\b)([^`]*)(\b\s*)(`)(\s)$/,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const markdownBold: MarkdownCriteria = {
|
|
194
|
+
...autoFormatBase,
|
|
195
|
+
exportFormat: 'bold',
|
|
196
|
+
exportTag: '**',
|
|
197
|
+
markdownFormatKind: 'bold',
|
|
198
|
+
regEx: /(\*\*)(\s*)([^**]*)(\s*)(\*\*)()/,
|
|
199
|
+
regExForAutoFormatting: /(\*\*)(\s*\b)([^**]*)(\b\s*)(\*\*)(\s)$/,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const markdownItalic: MarkdownCriteria = {
|
|
203
|
+
...autoFormatBase,
|
|
204
|
+
exportFormat: 'italic',
|
|
205
|
+
exportTag: '*',
|
|
206
|
+
markdownFormatKind: 'italic',
|
|
207
|
+
regEx: /(\*)(\s*)([^*]*)(\s*)(\*)()/,
|
|
208
|
+
regExForAutoFormatting: /(\*)(\s*\b)([^*]*)(\b\s*)(\*)(\s)$/,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const markdownBold2: MarkdownCriteria = {
|
|
212
|
+
...autoFormatBase,
|
|
213
|
+
exportFormat: 'bold',
|
|
214
|
+
exportTag: '_',
|
|
215
|
+
markdownFormatKind: 'bold',
|
|
216
|
+
regEx: /(__)(\s*)([^__]*)(\s*)(__)()/,
|
|
217
|
+
regExForAutoFormatting: /(__)(\s*)([^__]*)(\s*)(__)(\s)$/,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const markdownItalic2: MarkdownCriteria = {
|
|
221
|
+
...autoFormatBase,
|
|
222
|
+
exportFormat: 'italic',
|
|
223
|
+
exportTag: '_',
|
|
224
|
+
markdownFormatKind: 'italic',
|
|
225
|
+
regEx: /(_)()([^_]*)()(_)()/,
|
|
226
|
+
regExForAutoFormatting: /(_)()([^_]*)()(_)(\s)$/, // Maintain 7 groups.
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const fakeMarkdownUnderline: MarkdownCriteria = {
|
|
230
|
+
...autoFormatBase,
|
|
231
|
+
exportFormat: 'underline',
|
|
232
|
+
exportTag: '<u>',
|
|
233
|
+
exportTagClose: '</u>',
|
|
234
|
+
markdownFormatKind: 'underline',
|
|
235
|
+
regEx: /(<u>)(\s*)([^<]*)(\s*)(<\/u>)()/,
|
|
236
|
+
regExForAutoFormatting: /(<u>)(\s*\b)([^<]*)(\b\s*)(<\/u>)(\s)$/,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const markdownStrikethrough: MarkdownCriteria = {
|
|
240
|
+
...autoFormatBase,
|
|
241
|
+
exportFormat: 'strikethrough',
|
|
242
|
+
exportTag: '~~',
|
|
243
|
+
markdownFormatKind: 'strikethrough',
|
|
244
|
+
regEx: /(~~)(\s*)([^~~]*)(\s*)(~~)()/,
|
|
245
|
+
regExForAutoFormatting: /(~~)(\s*\b)([^~~]*)(\b\s*)(~~)(\s)$/,
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const markdownStrikethroughItalicBold: MarkdownCriteria = {
|
|
249
|
+
...autoFormatBase,
|
|
250
|
+
markdownFormatKind: 'strikethrough_italic_bold',
|
|
251
|
+
regEx: /(~~_\*\*)(\s*\b)([^~~_**][^**_~~]*)(\b\s*)(\*\*_~~)()/,
|
|
252
|
+
regExForAutoFormatting:
|
|
253
|
+
/(~~_\*\*)(\s*\b)([^~~_**][^**_~~]*)(\b\s*)(\*\*_~~)(\s)$/,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const markdownItalicbold: MarkdownCriteria = {
|
|
257
|
+
...autoFormatBase,
|
|
258
|
+
markdownFormatKind: 'italic_bold',
|
|
259
|
+
regEx: /(_\*\*)(\s*\b)([^_**][^**_]*)(\b\s*)(\*\*_)/,
|
|
260
|
+
regExForAutoFormatting: /(_\*\*)(\s*\b)([^_**][^**_]*)(\b\s*)(\*\*_)(\s)$/,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const markdownStrikethroughItalic: MarkdownCriteria = {
|
|
264
|
+
...autoFormatBase,
|
|
265
|
+
markdownFormatKind: 'strikethrough_italic',
|
|
266
|
+
regEx: /(~~_)(\s*)([^~~_][^_~~]*)(\s*)(_~~)/,
|
|
267
|
+
regExForAutoFormatting: /(~~_)(\s*)([^~~_][^_~~]*)(\s*)(_~~)(\s)$/,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const markdownStrikethroughBold: MarkdownCriteria = {
|
|
271
|
+
...autoFormatBase,
|
|
272
|
+
markdownFormatKind: 'strikethrough_bold',
|
|
273
|
+
regEx: /(~~\*\*)(\s*\b)([^~~**][^**~~]*)(\b\s*)(\*\*~~)/,
|
|
274
|
+
regExForAutoFormatting:
|
|
275
|
+
/(~~\*\*)(\s*\b)([^~~**][^**~~]*)(\b\s*)(\*\*~~)(\s)$/,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const markdownLink: MarkdownCriteria = {
|
|
279
|
+
...autoFormatBase,
|
|
280
|
+
markdownFormatKind: 'link',
|
|
281
|
+
regEx: /(\[)([^\]]*)(\]\()([^)]*)(\)*)()/,
|
|
282
|
+
regExForAutoFormatting: /(\[)([^\]]*)(\]\()([^)]*)(\)*)(\s)$/,
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const allMarkdownCriteriaForTextNodes: MarkdownCriteriaArray = [
|
|
286
|
+
// Place the combination formats ahead of the individual formats.
|
|
287
|
+
// Combos
|
|
288
|
+
markdownStrikethroughItalicBold,
|
|
289
|
+
markdownItalicbold,
|
|
290
|
+
markdownStrikethroughItalic,
|
|
291
|
+
markdownStrikethroughBold, // Individuals
|
|
292
|
+
markdownInlineCode,
|
|
293
|
+
markdownBold,
|
|
294
|
+
markdownItalic, // Must appear after markdownBold
|
|
295
|
+
markdownBold2,
|
|
296
|
+
markdownItalic2, // Must appear after markdownBold2.
|
|
297
|
+
fakeMarkdownUnderline,
|
|
298
|
+
markdownStrikethrough,
|
|
299
|
+
markdownLink,
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
const allMarkdownCriteriaForParagraphs: MarkdownCriteriaArray = [
|
|
303
|
+
markdownHeader1,
|
|
304
|
+
markdownHeader2,
|
|
305
|
+
markdownHeader3,
|
|
306
|
+
markdownHeader4,
|
|
307
|
+
markdownHeader5,
|
|
308
|
+
markdownHeader6,
|
|
309
|
+
markdownBlockQuote,
|
|
310
|
+
markdownUnorderedListDash,
|
|
311
|
+
markdownUnorderedListAsterisk,
|
|
312
|
+
markdownOrderedList,
|
|
313
|
+
markdownCodeBlock,
|
|
314
|
+
markdownHorizontalRule,
|
|
315
|
+
markdownHorizontalRuleUsingDashes,
|
|
316
|
+
];
|
|
317
|
+
|
|
318
|
+
export function getAllMarkdownCriteriaForParagraphs(): MarkdownCriteriaArray {
|
|
319
|
+
return allMarkdownCriteriaForParagraphs;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export function getAllMarkdownCriteriaForTextNodes(): MarkdownCriteriaArray {
|
|
323
|
+
return allMarkdownCriteriaForTextNodes;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
type Block = (
|
|
327
|
+
node: LexicalNode,
|
|
328
|
+
exportChildren: (elementNode: ElementNode) => string,
|
|
329
|
+
) => string | null;
|
|
330
|
+
|
|
331
|
+
function createHeadingExport(level: number): Block {
|
|
332
|
+
return (node, exportChildren) => {
|
|
333
|
+
return $isHeadingNode(node) && node.getTag() === 'h' + level
|
|
334
|
+
? '#'.repeat(level) + ' ' + exportChildren(node)
|
|
335
|
+
: null;
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function listExport(
|
|
340
|
+
node: LexicalNode,
|
|
341
|
+
exportChildren: (_node: ElementNode) => string,
|
|
342
|
+
) {
|
|
343
|
+
return $isListNode(node) ? processNestedLists(node, exportChildren, 0) : null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// TODO: should be param
|
|
347
|
+
const LIST_INDENT_SIZE = 4;
|
|
348
|
+
|
|
349
|
+
function processNestedLists(
|
|
350
|
+
listNode: ListNode,
|
|
351
|
+
exportChildren: (node: ElementNode) => string,
|
|
352
|
+
depth: number,
|
|
353
|
+
): string {
|
|
354
|
+
const output = [];
|
|
355
|
+
const children = listNode.getChildren();
|
|
356
|
+
let index = 0;
|
|
357
|
+
|
|
358
|
+
for (const listItemNode of children) {
|
|
359
|
+
if ($isListItemNode(listItemNode)) {
|
|
360
|
+
if (listItemNode.getChildrenSize() === 1) {
|
|
361
|
+
const firstChild = listItemNode.getFirstChild();
|
|
362
|
+
|
|
363
|
+
if ($isListNode(firstChild)) {
|
|
364
|
+
output.push(
|
|
365
|
+
processNestedLists(firstChild, exportChildren, depth + 1),
|
|
366
|
+
);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const indent = ' '.repeat(depth * LIST_INDENT_SIZE);
|
|
372
|
+
const prefix =
|
|
373
|
+
listNode.getListType() === 'bullet'
|
|
374
|
+
? '- '
|
|
375
|
+
: `${listNode.getStart() + index}. `;
|
|
376
|
+
output.push(indent + prefix + exportChildren(listItemNode));
|
|
377
|
+
index++;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return output.join('\n');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function blockQuoteExport(
|
|
385
|
+
node: LexicalNode,
|
|
386
|
+
exportChildren: (_node: ElementNode) => string,
|
|
387
|
+
) {
|
|
388
|
+
return $isQuoteNode(node) ? '> ' + exportChildren(node) : null;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function codeBlockExport(node: LexicalNode) {
|
|
392
|
+
if (!$isCodeNode(node)) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const textContent = node.getTextContent();
|
|
397
|
+
return (
|
|
398
|
+
'```' +
|
|
399
|
+
(node.getLanguage() || '') +
|
|
400
|
+
(textContent ? '\n' + textContent : '') +
|
|
401
|
+
'\n' +
|
|
402
|
+
'```'
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function indexBy<T>(
|
|
407
|
+
list: Array<T>,
|
|
408
|
+
callback: (arg0: T) => string | undefined,
|
|
409
|
+
): Readonly<Record<string, Array<T>>> {
|
|
410
|
+
const index: Record<string, Array<T>> = {};
|
|
411
|
+
|
|
412
|
+
for (const item of list) {
|
|
413
|
+
const key = callback(item);
|
|
414
|
+
|
|
415
|
+
if (!key) {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (index[key]) {
|
|
420
|
+
index[key].push(item);
|
|
421
|
+
} else {
|
|
422
|
+
index[key] = [item];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return index;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function transformersByType(transformers: Array<Transformer>): Readonly<{
|
|
430
|
+
element: Array<ElementTransformer>;
|
|
431
|
+
multilineElement: Array<MultilineElementTransformer>;
|
|
432
|
+
textFormat: Array<TextFormatTransformer>;
|
|
433
|
+
textMatch: Array<TextMatchTransformer>;
|
|
434
|
+
}> {
|
|
435
|
+
const byType = indexBy(transformers, (t) => t.type);
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
element: (byType.element || []) as Array<ElementTransformer>,
|
|
439
|
+
multilineElement: (byType['multiline-element'] ||
|
|
440
|
+
[]) as Array<MultilineElementTransformer>,
|
|
441
|
+
textFormat: (byType['text-format'] || []) as Array<TextFormatTransformer>,
|
|
442
|
+
textMatch: (byType['text-match'] || []) as Array<TextMatchTransformer>,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/;
|
|
447
|
+
|
|
448
|
+
const MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/;
|
|
449
|
+
|
|
450
|
+
export function isEmptyParagraph(node: LexicalNode): boolean {
|
|
451
|
+
if (!$isParagraphNode(node)) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const firstChild = node.getFirstChild();
|
|
456
|
+
return (
|
|
457
|
+
firstChild == null ||
|
|
458
|
+
(node.getChildrenSize() === 1 &&
|
|
459
|
+
$isTextNode(firstChild) &&
|
|
460
|
+
MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent()))
|
|
461
|
+
);
|
|
462
|
+
}
|