@kerebron/extension-odt 0.5.2 → 0.5.4

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.
Files changed (61) hide show
  1. package/README.md +2 -2
  2. package/esm/ExtensionOdt.d.ts.map +1 -1
  3. package/esm/ExtensionOdt.js +28 -77
  4. package/esm/ExtensionOdt.js.map +1 -1
  5. package/esm/OdtParser.d.ts +41 -7
  6. package/esm/OdtParser.d.ts.map +1 -1
  7. package/esm/OdtParser.js +26 -19
  8. package/esm/OdtParser.js.map +1 -1
  9. package/esm/lists.d.ts +9 -9
  10. package/esm/lists.d.ts.map +1 -1
  11. package/esm/lists.js +21 -7
  12. package/esm/lists.js.map +1 -1
  13. package/esm/node_handlers/basic_node_handlers.d.ts +1 -0
  14. package/esm/node_handlers/basic_node_handlers.d.ts.map +1 -1
  15. package/esm/node_handlers/basic_node_handlers.js +77 -9
  16. package/esm/node_handlers/basic_node_handlers.js.map +1 -1
  17. package/esm/node_handlers/list_node_handlers.d.ts.map +1 -1
  18. package/esm/node_handlers/list_node_handlers.js +61 -65
  19. package/esm/node_handlers/list_node_handlers.js.map +1 -1
  20. package/esm/postprocess/convertCodeParagraphsToCodeBlocks.d.ts.map +1 -1
  21. package/esm/postprocess/convertCodeParagraphsToCodeBlocks.js +40 -66
  22. package/esm/postprocess/convertCodeParagraphsToCodeBlocks.js.map +1 -1
  23. package/esm/postprocess/convertMathMl.d.ts.map +1 -1
  24. package/esm/postprocess/convertMathMl.js +1 -1
  25. package/esm/postprocess/convertMathMl.js.map +1 -1
  26. package/esm/postprocess/fixContinuedLists.d.ts.map +1 -1
  27. package/esm/postprocess/fixContinuedLists.js +80 -67
  28. package/esm/postprocess/fixContinuedLists.js.map +1 -1
  29. package/esm/postprocess/fixListsLevels.d.ts +3 -0
  30. package/esm/postprocess/fixListsLevels.d.ts.map +1 -0
  31. package/esm/postprocess/fixListsLevels.js +62 -0
  32. package/esm/postprocess/fixListsLevels.js.map +1 -0
  33. package/esm/postprocess/mergeCodeBlocks.d.ts +3 -0
  34. package/esm/postprocess/mergeCodeBlocks.d.ts.map +1 -0
  35. package/esm/postprocess/mergeCodeBlocks.js +83 -0
  36. package/esm/postprocess/mergeCodeBlocks.js.map +1 -0
  37. package/esm/postprocess/postProcess.d.ts.map +1 -1
  38. package/esm/postprocess/postProcess.js +5 -2
  39. package/esm/postprocess/postProcess.js.map +1 -1
  40. package/esm/postprocess/removeUnusedBookmarks.d.ts +1 -1
  41. package/esm/postprocess/removeUnusedBookmarks.d.ts.map +1 -1
  42. package/esm/postprocess/removeUnusedBookmarks.js +16 -19
  43. package/esm/postprocess/removeUnusedBookmarks.js.map +1 -1
  44. package/esm/postprocess/urlRewrite.d.ts +4 -0
  45. package/esm/postprocess/urlRewrite.d.ts.map +1 -0
  46. package/esm/postprocess/urlRewrite.js +60 -0
  47. package/esm/postprocess/urlRewrite.js.map +1 -0
  48. package/package.json +3 -3
  49. package/src/ExtensionOdt.ts +30 -114
  50. package/src/OdtParser.ts +86 -31
  51. package/src/lists.ts +24 -10
  52. package/src/node_handlers/basic_node_handlers.ts +82 -10
  53. package/src/node_handlers/list_node_handlers.ts +91 -90
  54. package/src/postprocess/convertCodeParagraphsToCodeBlocks.ts +44 -86
  55. package/src/postprocess/convertMathMl.ts +1 -2
  56. package/src/postprocess/fixContinuedLists.ts +95 -78
  57. package/src/postprocess/fixListsLevels.ts +93 -0
  58. package/src/postprocess/mergeCodeBlocks.ts +114 -0
  59. package/src/postprocess/postProcess.ts +5 -1
  60. package/src/postprocess/removeUnusedBookmarks.ts +33 -21
  61. package/src/postprocess/urlRewrite.ts +95 -0
@@ -0,0 +1,114 @@
1
+ import { Command } from 'prosemirror-state';
2
+
3
+ const CODEBLOCK_START = ''; // gdocs
4
+ const CODEBLOCK_END = '';
5
+
6
+ // Related tests:
7
+ // test ./code-blocks.md
8
+ export const mergeCodeBlocks: Command = (state, dispatch): boolean => {
9
+ const schema = state.schema;
10
+ let tr = state.tr;
11
+
12
+ const codeBlockType = schema.nodes.code_block;
13
+ const paraBlockType = schema.nodes.paragraph;
14
+
15
+ const parent = state.doc;
16
+ let offset = 0;
17
+ for (let nodeNo = 0; nodeNo < parent.childCount; nodeNo++) {
18
+ const node = parent.nodeAt(offset);
19
+ if (!node) {
20
+ continue;
21
+ }
22
+
23
+ if (node.type !== codeBlockType) {
24
+ offset += node.nodeSize;
25
+ continue;
26
+ }
27
+
28
+ let codeTexts = [];
29
+ let codeSize = 0;
30
+ {
31
+ codeSize += node.nodeSize;
32
+ const text = node.text || node.textBetween(0, node.content.size);
33
+ codeTexts.push(text.endsWith('\n') ? text : text + '\n');
34
+ }
35
+
36
+ let nextPos = offset + node.nodeSize;
37
+ while (true) {
38
+ const next = state.doc.nodeAt(nextPos);
39
+ if (!next) {
40
+ break;
41
+ }
42
+
43
+ nextPos += next.nodeSize;
44
+
45
+ if (next.type === paraBlockType && next.childCount === 0) {
46
+ codeTexts.push('\n');
47
+ codeSize += next.nodeSize;
48
+ continue;
49
+ }
50
+
51
+ if (
52
+ next.type === codeBlockType && node.attrs.lang === next.attrs.lang &&
53
+ node.attrs.lang !== 'mathml'
54
+ ) {
55
+ const text = next.text || next.textBetween(0, next.content.size);
56
+ codeTexts.push(text.endsWith('\n') ? text : text + '\n');
57
+
58
+ codeSize += next.nodeSize;
59
+ continue;
60
+ }
61
+
62
+ break;
63
+ }
64
+
65
+ if (codeTexts.length > 1) {
66
+ const startPos = tr.mapping.map(offset);
67
+ const endPos = tr.mapping.map(offset + codeSize);
68
+
69
+ let codeText = codeTexts.join('').replace(/\n+$/gm, '\n');
70
+
71
+ const lines = codeText.split('\n');
72
+ let emptyCount = 0;
73
+ for (emptyCount = 0; emptyCount < lines.length; emptyCount++) {
74
+ if (lines[emptyCount].trim()) {
75
+ break;
76
+ }
77
+ }
78
+ lines.splice(0, emptyCount);
79
+
80
+ codeText = lines.join('\n');
81
+
82
+ const textNode = schema.text(codeText);
83
+ const codeBlock = schema.nodes.code_block.createAndFill({
84
+ lang: node.attrs.lang,
85
+ }, [textNode]);
86
+
87
+ if (codeBlock) {
88
+ tr = tr.replaceRangeWith(startPos, endPos, codeBlock);
89
+ }
90
+ }
91
+
92
+ offset += codeSize;
93
+ }
94
+
95
+ state.doc.descendants((node, pos) => {
96
+ if (
97
+ node.type === paraBlockType &&
98
+ [CODEBLOCK_START, CODEBLOCK_END].includes(
99
+ node.textBetween(0, node.content.size),
100
+ )
101
+ ) {
102
+ tr = tr.deleteRange(
103
+ tr.mapping.map(pos),
104
+ tr.mapping.map(pos + node.nodeSize),
105
+ );
106
+ }
107
+ });
108
+
109
+ if (dispatch) {
110
+ dispatch(tr);
111
+ }
112
+
113
+ return tr.docChanged;
114
+ };
@@ -5,6 +5,8 @@ import { convertCodeParagraphsToCodeBlocks } from './convertCodeParagraphsToCode
5
5
  import { removeUnusedBookmarks } from './removeUnusedBookmarks.js';
6
6
  import { fixContinuedLists } from './fixContinuedLists.js';
7
7
  import { convertMathMl } from './convertMathMl.js';
8
+ import { mergeCodeBlocks } from './mergeCodeBlocks.js';
9
+ import { fixListsLevels } from './fixListsLevels.js';
8
10
 
9
11
  export interface PostProcessConfig {
10
12
  doc: Node;
@@ -15,9 +17,11 @@ export function getDefaultsPostProcessFilters(
15
17
  { doc, filesMap }: PostProcessConfig,
16
18
  ): Array<Command> {
17
19
  return [
20
+ // removeUnusedBookmarks,
18
21
  convertCodeParagraphsToCodeBlocks,
19
- removeUnusedBookmarks,
22
+ fixListsLevels,
20
23
  fixContinuedLists,
21
24
  convertMathMl,
25
+ mergeCodeBlocks,
22
26
  ];
23
27
  }
@@ -1,36 +1,48 @@
1
- import { Fragment, MarkType, Node, Schema } from 'prosemirror-model';
2
- import { Command } from 'prosemirror-state';
1
+ import type { Node } from 'prosemirror-model';
2
+ import type { Command } from 'prosemirror-state';
3
3
 
4
4
  export const removeUnusedBookmarks: Command = (state, dispatch): boolean => {
5
- return false;
6
- function condition(mark) {
7
- console.log('rrrr', mark.type.name);
8
- return mark.type.name === 'bookmark';
9
- }
5
+ const schema = state.schema;
6
+ let tr = state.tr;
7
+
8
+ const bookmarkNodeType = schema.nodes.node_bookmark;
9
+ const bookmarkMarkType = schema.marks.bookmark;
10
10
 
11
- if (node.marks) {
12
- // For text nodes, filter out the marks that match the condition
13
- const newMarks = node.marks.filter((mark) => !condition(mark));
11
+ function walk(
12
+ node: Node,
13
+ pos = 0,
14
+ depth = 0,
15
+ ) {
16
+ if (node.type === bookmarkNodeType) {
17
+ tr = tr.delete(
18
+ tr.mapping.map(pos - 1),
19
+ tr.mapping.map(pos + node.nodeSize - 1),
20
+ );
21
+ return;
22
+ }
14
23
 
15
- // If marks were removed, return a new text node with the remaining marks
24
+ const newMarks = node.marks.filter((mark) =>
25
+ mark.type !== bookmarkMarkType
26
+ );
16
27
  if (newMarks.length !== node.marks.length) {
17
- return node.mark(newMarks);
28
+ tr = tr.setNodeMarkup(
29
+ tr.mapping.map(pos),
30
+ null,
31
+ null,
32
+ newMarks,
33
+ );
18
34
  }
19
35
 
20
- // Otherwise, return the original text node
21
- return node;
36
+ node.forEach((child, offset, index) => {
37
+ walk(child, pos + offset + 1, depth + 1);
38
+ });
22
39
  }
23
40
 
24
- // if (Array.isArray(node.content)) {
25
- // const content: Node[] = node.content.content.map(childNode => removeUnusedBookmarks(childNode));
26
- // return node.copy(content);
27
- // } else {
28
- // console.log('node.content', node.content);
29
- // }
41
+ walk(state.doc);
30
42
 
31
43
  if (dispatch) {
32
44
  dispatch(tr);
33
45
  }
34
46
 
35
- return tr.steps.length > 0;
47
+ return tr.docChanged;
36
48
  };
@@ -0,0 +1,95 @@
1
+ import { Node } from 'prosemirror-model';
2
+ import { EditorState, Transaction } from 'prosemirror-state';
3
+
4
+ import { UrlRewriter } from '@kerebron/editor';
5
+
6
+ export async function urlRewrite(
7
+ urlFromRewriter: UrlRewriter,
8
+ filesMap: Record<string, Uint8Array>,
9
+ state: EditorState,
10
+ dispatch: (tr: Transaction) => void,
11
+ ): Promise<boolean> {
12
+ const imageNodes: Array<{ node: Node; pos: number }> = [];
13
+ state.doc.descendants((node, pos) => {
14
+ if (node.type.name === 'image') {
15
+ imageNodes.push({ node, pos });
16
+ }
17
+ });
18
+
19
+ const linkNodes: Array<{ node: Node; pos: number }> = [];
20
+ state.doc.descendants((node, pos) => {
21
+ if (node.marks.find((mark) => mark.type.name === 'link')) {
22
+ linkNodes.push({ node, pos });
23
+ }
24
+ });
25
+
26
+ const tr = state.tr;
27
+
28
+ for (const { node, pos } of linkNodes) {
29
+ const linkMark = node.marks.find((mark) => mark.type.name === 'link');
30
+ if (!linkMark) {
31
+ continue;
32
+ }
33
+ let href = linkMark.attrs.href || '';
34
+ href = await urlFromRewriter(href, {
35
+ type: 'A',
36
+ dest: 'kerebron',
37
+ });
38
+ if (href !== linkMark.attrs.href) {
39
+ const newMarks = node.marks.map((mark) => {
40
+ if (mark.type.name === 'link') {
41
+ const markType = state.schema.marks['link'];
42
+ return markType.create({ ...mark.attrs, href });
43
+ }
44
+ return mark;
45
+ });
46
+
47
+ const nodeType = state.schema.nodes[node.type.name];
48
+ let replaceNode;
49
+ if (nodeType.isText) {
50
+ replaceNode = state.schema.text(
51
+ node.text || '',
52
+ newMarks,
53
+ );
54
+ } else {
55
+ replaceNode = nodeType.create(
56
+ node.attrs,
57
+ node.content,
58
+ newMarks,
59
+ );
60
+ }
61
+ tr.replaceWith(
62
+ tr.mapping.map(pos),
63
+ tr.mapping.map(pos + node.nodeSize),
64
+ replaceNode,
65
+ );
66
+ }
67
+ }
68
+
69
+ for (const { node, pos } of imageNodes) {
70
+ let src = node.attrs.src || '';
71
+
72
+ src = await urlFromRewriter(src, {
73
+ type: 'IMG',
74
+ dest: 'kerebron',
75
+ filesMap,
76
+ });
77
+
78
+ if (src !== node.attrs.src) {
79
+ const nodeType = state.schema.nodes[node.type.name];
80
+ const replaceNode = nodeType.create(
81
+ { ...node.attrs, src },
82
+ node.content,
83
+ node.marks,
84
+ );
85
+ tr.replaceWith(
86
+ tr.mapping.map(pos),
87
+ tr.mapping.map(pos + node.nodeSize),
88
+ replaceNode,
89
+ );
90
+ }
91
+ }
92
+ dispatch(tr);
93
+
94
+ return tr.docChanged;
95
+ }