Linker.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import path from 'path';
  2. export default class Linker {
  3. constructor(type = this.type.markdownLink, label = '', link = '', isUseRelativePath = false, rootPath = '') {
  4. this.type = type;
  5. this.label = label;
  6. this.link = link;
  7. this.isUseRelativePath = isUseRelativePath;
  8. this.rootPath = rootPath;
  9. this.generateMarkdownText = this.generateMarkdownText.bind(this);
  10. }
  11. static types = {
  12. markdownLink: 'mdLink',
  13. growiLink: 'growiLink',
  14. pukiwikiLink: 'pukiwikiLink',
  15. }
  16. generateMarkdownText() {
  17. let reshapedLink = this.link;
  18. if (this.isUseRelativePath && this.link.match(/^\//)) {
  19. reshapedLink = path.relative(this.rootPath, this.link);
  20. }
  21. if (this.type === Linker.types.pukiwikiLink) {
  22. if (this.label === reshapedLink) return `[[${reshapedLink}]]`;
  23. return `[[${this.label}>${reshapedLink}]]`;
  24. }
  25. if (this.type === Linker.types.growiLink) {
  26. return `[${reshapedLink}]`;
  27. }
  28. if (this.type === Linker.types.markdownLink) {
  29. return `[${this.label}](${reshapedLink})`;
  30. }
  31. }
  32. // create an instance of Linker from string
  33. static fromMarkdownString(str) {
  34. // if str doesn't mean a linker, create a link whose label is str
  35. let label = str;
  36. let link = '';
  37. let type = this.types.markdownLink;
  38. // pukiwiki
  39. // https://regex101.com/r/2fNmUN/1
  40. if (str.match(/^\[\[.*\]\]$/)) {
  41. type = this.types.pukiwikiLink;
  42. const value = str.slice(2, -2);
  43. const indexOfSplit = value.lastIndexOf('>');
  44. if (indexOfSplit < 0) {
  45. label = value;
  46. link = value;
  47. }
  48. else {
  49. label = value.slice(0, indexOfSplit);
  50. link = value.slice(indexOfSplit + 1);
  51. }
  52. }
  53. // growi
  54. // https://regex101.com/r/DJfkYf/1
  55. else if (str.match(/^\[\/.*\]$/)) {
  56. type = this.types.growiLink;
  57. const value = str.slice(1, -1);
  58. label = value;
  59. link = value;
  60. }
  61. // markdown
  62. // https://regex101.com/r/DZCKP3/1
  63. else if (str.match(/^\[.*\]\(.*\)$/)) {
  64. type = this.types.markdownLink;
  65. const value = str.slice(1, -1);
  66. const indexOfSplit = value.lastIndexOf('](');
  67. label = value.slice(0, indexOfSplit);
  68. link = value.slice(indexOfSplit + 2);
  69. }
  70. return new Linker(type, label, link);
  71. }
  72. // create an instance of Linker from text with index
  73. static fromLineWithIndex(line, index) {
  74. const { beginningOfLink, endOfLink } = this.getBeginningAndEndIndexOfLink(line, index);
  75. // if index is in a link, extract it from line
  76. let linkStr = '';
  77. if (beginningOfLink >= 0 && endOfLink >= 0) {
  78. linkStr = line.substring(beginningOfLink, endOfLink);
  79. }
  80. return this.fromMarkdownString(linkStr);
  81. }
  82. // return beginning and end indexies of link
  83. // if index is not in a link, return { beginningOfLink: -1, endOfLink: -1 }
  84. static getBeginningAndEndIndexOfLink(line, index) {
  85. let beginningOfLink;
  86. let endOfLink;
  87. // pukiwiki link ('[[link]]')
  88. [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[[', ']]');
  89. // if index is not in a pukiwiki link
  90. // growi link ('[/link]')
  91. if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
  92. [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[/', ']');
  93. }
  94. // and if index is not in a growi link
  95. // markdown link ('[label](link)')
  96. if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
  97. [beginningOfLink, endOfLink] = this.getBeginningAndEndIndexWithPrefixAndSuffix(line, index, '[', ')', '](');
  98. }
  99. // and if index is not in a markdown link
  100. // return { beginningOfLink: -1, endOfLink: -1 }
  101. if (beginningOfLink < 0 || endOfLink < 0 || beginningOfLink > index || endOfLink < index) {
  102. [beginningOfLink, endOfLink] = [-1, -1];
  103. }
  104. return { beginningOfLink, endOfLink };
  105. }
  106. // return begin and end indexies as array only when index is between prefix and suffix and link contains containText.
  107. static getBeginningAndEndIndexWithPrefixAndSuffix(line, index, prefix, suffix, containText = '') {
  108. const beginningIndex = line.lastIndexOf(prefix, index);
  109. const IndexOfContainText = line.indexOf(containText, beginningIndex + prefix.length);
  110. const endIndex = line.indexOf(suffix, IndexOfContainText + containText.length);
  111. if (beginningIndex < 0 || IndexOfContainText < 0 || endIndex < 0) {
  112. return [-1, -1];
  113. }
  114. return [beginningIndex, endIndex + suffix.length];
  115. }
  116. }