ReformMarkdownTableInterceptor.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { BasicInterceptor } from 'crowi-pluginkit';
  2. import markdownTable from 'markdown-table';
  3. /**
  4. * The interceptor that reform markdown table
  5. */
  6. export default class ReformMarkdownTableInterceptor extends BasicInterceptor {
  7. constructor() {
  8. super();
  9. // https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
  10. // https://regex101.com/r/7BN2fR/7
  11. this.tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
  12. this.linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^\|\r\n]+\|[^\|\r\n]*)+/; // own idea
  13. this.getBot = this.getBot.bind(this);
  14. this.getEot = this.getEot.bind(this);
  15. this.getBol = this.getBol.bind(this);
  16. this.getStrFromBot = this.getStrFromBot.bind(this);
  17. this.getStrToEot = this.getStrToEot.bind(this);
  18. this.getStrFromBol = this.getStrFromBol.bind(this);
  19. this.parseFromTableStringToJSON = this.parseFromTableStringToJSON.bind(this);
  20. }
  21. /**
  22. * @inheritdoc
  23. */
  24. isInterceptWhen(contextName) {
  25. return (
  26. contextName === 'preHandleEnter'
  27. );
  28. }
  29. /**
  30. * return boolean value whether processable parallel
  31. */
  32. isProcessableParallel() {
  33. return false;
  34. }
  35. /**
  36. * @inheritdoc
  37. */
  38. process(contextName, ...args) {
  39. const context = Object.assign(args[0]); // clone
  40. const editor = context.editor;
  41. console.log('MarkdownTableHelper.process');
  42. // get strings from BOL(beginning of line) to current position
  43. const strFromBol = this.getStrFromBol(editor);
  44. if (this.linePartOfTableRE.test(strFromBol)) {
  45. // get lines all of table from current position to beginning of table
  46. const strTableLines = this.getStrFromBot(editor);
  47. console.log('strTableLines: ' + strTableLines);
  48. const table = this.parseFromTableStringToJSON(editor, this.getBot(editor), editor.getCursor());
  49. console.log('table: ' + JSON.stringify(table));
  50. const strTableLinesFormated = table;
  51. console.log('strTableLinesFormated: ' + strTableLinesFormated);
  52. // replace the lines to strFormatedTableLines
  53. editor.getDoc().replaceRange(strTableLinesFormated, this.getBot(editor), editor.getCursor());
  54. // report to manager that handling was done
  55. context.handlers.push(this.className);
  56. }
  57. // resolve
  58. return Promise.resolve(context);
  59. }
  60. /**
  61. * return the postion of the BOT(beginning of table)
  62. * (It is assumed that current line is a part of table)
  63. */
  64. getBot(editor) {
  65. const firstLine = editor.getDoc().firstLine();
  66. const curPos = editor.getCursor();
  67. let line = curPos.line - 1;
  68. for (; line >= firstLine; line--) {
  69. const strLine = editor.getDoc().getLine(line);
  70. if (!this.linePartOfTableRE.test(strLine)) {
  71. break;
  72. }
  73. }
  74. const botLine = Math.max(firstLine, line + 1);
  75. return { line: botLine, ch: 0 };
  76. }
  77. /**
  78. * return the postion of the EOT(end of table)
  79. * (It is assumed that current line is a part of table)
  80. */
  81. getEot(editor) {
  82. const lastLine = editor.getDoc().lastLine();
  83. const curPos = editor.getCursor();
  84. let line = curPos.line + 1;
  85. for (; line <= lastLine; line++) {
  86. const strLine = editor.getDoc().getLine(line);
  87. if (!this.linePartOfTableRE.test(strLine)) {
  88. break;
  89. }
  90. }
  91. const eotLine = Math.min(line - 1, lastLine);
  92. const lineLength = editor.getDoc().getLine(eotLine).length;
  93. return { line: eotLine, ch: lineLength };
  94. }
  95. /**
  96. * return the postion of the BOL(beginning of line)
  97. */
  98. getBol(editor) {
  99. const curPos = editor.getCursor();
  100. return { line: curPos.line, ch: 0 };
  101. }
  102. /**
  103. * return strings from BOT(beginning of table) to current position
  104. */
  105. getStrFromBot(editor) {
  106. const curPos = editor.getCursor();
  107. return editor.getDoc().getRange(this.getBot(editor), curPos);
  108. }
  109. /**
  110. * return strings from current position to EOT(end of table)
  111. */
  112. getStrToEot(editor) {
  113. const curPos = editor.getCursor();
  114. return editor.getDoc().getRange(curPos, this.getEot(editor));
  115. }
  116. /**
  117. * return strings from BOL(beginning of line) to current position
  118. */
  119. getStrFromBol(editor) {
  120. const curPos = editor.getCursor();
  121. return editor.getDoc().getRange(this.getBol(editor), curPos);
  122. }
  123. /**
  124. * returns object whose described by 'markdown-table' format
  125. * ref. https://github.com/wooorm/markdown-table
  126. * @param {string} lines all of table
  127. */
  128. parseFromTableStringToJSON(editor, posBeg, posEnd) {
  129. console.log("parseFromTableStringToJSON: posBeg.line: " + posBeg.line + ", posEnd.line: " + posEnd.line);
  130. let contents = [];
  131. let aligns = [];
  132. for (let pos = posBeg; pos.line <= posEnd.line; pos.line++) {
  133. const line = editor.getDoc().getLine(pos.line);
  134. console.log("line#" + pos.line + ": " + line);
  135. if (this.tableAlignmentLineRE.test(line)) {
  136. // parse line which described alignment
  137. const alignRuleRE = [
  138. { align: 'c', regex: /^:-+:$/ },
  139. { align: 'l', regex: /^:-+$/ },
  140. { align: 'r', regex: /^-+:$/ },
  141. ];
  142. let lineText = "";
  143. lineText = line.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
  144. lineText = lineText.replace(/\s*/g, '');
  145. aligns = lineText.split(/\|/).map(col => {
  146. const rule = alignRuleRE.find(rule => col.match(rule.regex));
  147. return (rule != undefined) ? rule.align : '';
  148. });
  149. } else {
  150. // parse line whether header or body
  151. let lineText = "";
  152. lineText = line.replace(/\s*\|\s*/g, '|');
  153. lineText = lineText.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
  154. const row = lineText.split(/\|/);
  155. console.log('row: ' + row);
  156. contents.push(row);
  157. }
  158. }
  159. console.log('contents: ' + JSON.stringify(contents));
  160. console.log('aligns: ' + JSON.stringify(aligns));
  161. return markdownTable(contents, { align: aligns } );
  162. }
  163. }