cherry-muse 1.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.
Files changed (226) hide show
  1. package/LICENSE +162 -0
  2. package/README.md +139 -0
  3. package/dist/addons/cherry-code-block-card-plugin.js +1 -0
  4. package/dist/addons/cherry-code-block-echarts-plugin.js +1 -0
  5. package/dist/addons/cherry-code-block-mermaid-plugin.js +1 -0
  6. package/dist/cherry-markdown.core.common.js +1 -0
  7. package/dist/cherry-markdown.core.js +1 -0
  8. package/dist/cherry-markdown.css +4089 -0
  9. package/dist/cherry-markdown.engine.core.common.js +1 -0
  10. package/dist/cherry-markdown.engine.core.esm.js +1 -0
  11. package/dist/cherry-markdown.engine.core.js +1 -0
  12. package/dist/cherry-markdown.esm.js +1 -0
  13. package/dist/cherry-markdown.js +70837 -0
  14. package/dist/cherry-markdown.js.map +1 -0
  15. package/dist/cherry-markdown.min.css +1 -0
  16. package/dist/cherry-markdown.min.js +1 -0
  17. package/dist/stats.html +4838 -0
  18. package/examples/scripts/pinyin/README.md +53 -0
  19. package/package.json +167 -0
  20. package/src/Cherry.config.js +411 -0
  21. package/src/Cherry.js +788 -0
  22. package/src/CherryStatic.js +70 -0
  23. package/src/Editor.js +746 -0
  24. package/src/Engine.js +334 -0
  25. package/src/Event.js +74 -0
  26. package/src/Factory.js +180 -0
  27. package/src/Logger.js +31 -0
  28. package/src/Previewer.js +1147 -0
  29. package/src/Sanitizer.js +4 -0
  30. package/src/Sanitizer.node.js +7 -0
  31. package/src/Stats.js +101 -0
  32. package/src/Theme.js +46 -0
  33. package/src/UrlCache.js +98 -0
  34. package/src/addons/cherry-code-block-card-plugin.js +213 -0
  35. package/src/addons/cherry-code-block-echarts-plugin.js +161 -0
  36. package/src/addons/cherry-code-block-mermaid-plugin.js +118 -0
  37. package/src/core/HookCenter.js +303 -0
  38. package/src/core/HooksConfig.js +106 -0
  39. package/src/core/ParagraphBase.js +314 -0
  40. package/src/core/SentenceBase.js +65 -0
  41. package/src/core/SyntaxBase.js +197 -0
  42. package/src/core/hooks/AutoLink.js +251 -0
  43. package/src/core/hooks/BackgroundColor.js +46 -0
  44. package/src/core/hooks/Badge.js +100 -0
  45. package/src/core/hooks/Blockquote.js +113 -0
  46. package/src/core/hooks/Br.js +85 -0
  47. package/src/core/hooks/CodeBlock.js +876 -0
  48. package/src/core/hooks/Color.js +78 -0
  49. package/src/core/hooks/CommentReference.js +96 -0
  50. package/src/core/hooks/Detail.js +138 -0
  51. package/src/core/hooks/Emoji.config.js +9388 -0
  52. package/src/core/hooks/Emoji.js +223 -0
  53. package/src/core/hooks/Emphasis.js +113 -0
  54. package/src/core/hooks/Footnote.js +125 -0
  55. package/src/core/hooks/FrontMatter.js +52 -0
  56. package/src/core/hooks/FrontMatterVars.js +82 -0
  57. package/src/core/hooks/Header.js +229 -0
  58. package/src/core/hooks/HighLight.js +37 -0
  59. package/src/core/hooks/Hr.js +52 -0
  60. package/src/core/hooks/HtmlBlock.js +159 -0
  61. package/src/core/hooks/Iframe.js +80 -0
  62. package/src/core/hooks/Image.js +276 -0
  63. package/src/core/hooks/InlineCode.js +45 -0
  64. package/src/core/hooks/InlineMath.js +142 -0
  65. package/src/core/hooks/Link.js +169 -0
  66. package/src/core/hooks/List.js +260 -0
  67. package/src/core/hooks/Mark.js +55 -0
  68. package/src/core/hooks/MathBlock.js +97 -0
  69. package/src/core/hooks/Panel.js +170 -0
  70. package/src/core/hooks/Paragraph.js +84 -0
  71. package/src/core/hooks/Ruby.js +34 -0
  72. package/src/core/hooks/Size.js +84 -0
  73. package/src/core/hooks/Strikethrough.js +54 -0
  74. package/src/core/hooks/Sub.js +47 -0
  75. package/src/core/hooks/SuggestList.js +317 -0
  76. package/src/core/hooks/Suggester.js +759 -0
  77. package/src/core/hooks/Sup.js +47 -0
  78. package/src/core/hooks/Table.js +315 -0
  79. package/src/core/hooks/Toc.js +290 -0
  80. package/src/core/hooks/Transfer.js +47 -0
  81. package/src/core/hooks/Underline.js +37 -0
  82. package/src/index.core.js +29 -0
  83. package/src/index.engine.core.js +62 -0
  84. package/src/index.engine.js +30 -0
  85. package/src/index.js +28 -0
  86. package/src/locales/index.js +21 -0
  87. package/src/locales/zh_CN.js +170 -0
  88. package/src/sass/cherry.scss +122 -0
  89. package/src/sass/components/bubble.scss +122 -0
  90. package/src/sass/components/codemirror.scss +628 -0
  91. package/src/sass/components/dropdown.scss +37 -0
  92. package/src/sass/components/editor.scss +78 -0
  93. package/src/sass/components/preview.scss +71 -0
  94. package/src/sass/components/prism.scss +142 -0
  95. package/src/sass/components/stats.scss +32 -0
  96. package/src/sass/components/toc.scss +184 -0
  97. package/src/sass/components/toolbar.scss +117 -0
  98. package/src/sass/core/AutoLink.scss +20 -0
  99. package/src/sass/core/BackgroundColor.scss +0 -0
  100. package/src/sass/core/Badge.scss +116 -0
  101. package/src/sass/core/Blockquote.scss +12 -0
  102. package/src/sass/core/Br.scss +0 -0
  103. package/src/sass/core/Card.scss +219 -0
  104. package/src/sass/core/CodeBlock.scss +205 -0
  105. package/src/sass/core/Color.scss +37 -0
  106. package/src/sass/core/CommentReference.scss +0 -0
  107. package/src/sass/core/Detail.scss +107 -0
  108. package/src/sass/core/Emoji.scss +127 -0
  109. package/src/sass/core/Emphasis.scss +9 -0
  110. package/src/sass/core/Footnote.scss +21 -0
  111. package/src/sass/core/FrontMatterVars.scss +19 -0
  112. package/src/sass/core/Header.scss +103 -0
  113. package/src/sass/core/HighLight.scss +0 -0
  114. package/src/sass/core/Hr.scss +10 -0
  115. package/src/sass/core/HtmlBlock.scss +0 -0
  116. package/src/sass/core/Iframe.scss +36 -0
  117. package/src/sass/core/Image.scss +59 -0
  118. package/src/sass/core/InlineCode.scss +10 -0
  119. package/src/sass/core/InlineMath.scss +11 -0
  120. package/src/sass/core/Link.scss +16 -0
  121. package/src/sass/core/List.scss +61 -0
  122. package/src/sass/core/Mark.scss +15 -0
  123. package/src/sass/core/MathBlock.scss +0 -0
  124. package/src/sass/core/Panel.scss +150 -0
  125. package/src/sass/core/Paragraph.scss +6 -0
  126. package/src/sass/core/Ruby.scss +0 -0
  127. package/src/sass/core/Size.scss +8 -0
  128. package/src/sass/core/Strikethrough.scss +0 -0
  129. package/src/sass/core/Sub.scss +5 -0
  130. package/src/sass/core/Suggester.scss +62 -0
  131. package/src/sass/core/Sup.scss +5 -0
  132. package/src/sass/core/Table.scss +127 -0
  133. package/src/sass/core/Toc.scss +28 -0
  134. package/src/sass/core/Transfer.scss +0 -0
  135. package/src/sass/core/Underline.scss +0 -0
  136. package/src/sass/google-fonts.scss +34 -0
  137. package/src/sass/index.scss +3 -0
  138. package/src/sass/prism/dark.scss +131 -0
  139. package/src/sass/prism/light.scss +143 -0
  140. package/src/sass/variables/colors.scss +96 -0
  141. package/src/toolbars/Bubble.js +232 -0
  142. package/src/toolbars/BubbleTable.js +147 -0
  143. package/src/toolbars/HookCenter.js +185 -0
  144. package/src/toolbars/MenuBase.js +357 -0
  145. package/src/toolbars/PreviewerBubble.js +558 -0
  146. package/src/toolbars/Toc.js +246 -0
  147. package/src/toolbars/Toolbar.js +401 -0
  148. package/src/toolbars/hooks/Audio.js +53 -0
  149. package/src/toolbars/hooks/Badge.js +80 -0
  150. package/src/toolbars/hooks/BarTable.js +41 -0
  151. package/src/toolbars/hooks/Bold.js +70 -0
  152. package/src/toolbars/hooks/Br.js +34 -0
  153. package/src/toolbars/hooks/Card.js +64 -0
  154. package/src/toolbars/hooks/CheckList.js +41 -0
  155. package/src/toolbars/hooks/Code.js +46 -0
  156. package/src/toolbars/hooks/Color.js +285 -0
  157. package/src/toolbars/hooks/Copy.js +139 -0
  158. package/src/toolbars/hooks/Detail.js +70 -0
  159. package/src/toolbars/hooks/ECharts.js +303 -0
  160. package/src/toolbars/hooks/Emoji.js +303 -0
  161. package/src/toolbars/hooks/Export.js +47 -0
  162. package/src/toolbars/hooks/File.js +54 -0
  163. package/src/toolbars/hooks/Formula.js +36 -0
  164. package/src/toolbars/hooks/FullScreen.js +55 -0
  165. package/src/toolbars/hooks/Graph.js +281 -0
  166. package/src/toolbars/hooks/H1.js +71 -0
  167. package/src/toolbars/hooks/H2.js +71 -0
  168. package/src/toolbars/hooks/H3.js +71 -0
  169. package/src/toolbars/hooks/Header.js +100 -0
  170. package/src/toolbars/hooks/Hr.js +35 -0
  171. package/src/toolbars/hooks/Iframe.js +35 -0
  172. package/src/toolbars/hooks/Image.js +60 -0
  173. package/src/toolbars/hooks/Insert.js +36 -0
  174. package/src/toolbars/hooks/Italic.js +70 -0
  175. package/src/toolbars/hooks/LineTable.js +41 -0
  176. package/src/toolbars/hooks/Link.js +46 -0
  177. package/src/toolbars/hooks/List.js +55 -0
  178. package/src/toolbars/hooks/Ol.js +41 -0
  179. package/src/toolbars/hooks/Panel.js +155 -0
  180. package/src/toolbars/hooks/Quote.js +45 -0
  181. package/src/toolbars/hooks/Redo.js +33 -0
  182. package/src/toolbars/hooks/Ruby.js +59 -0
  183. package/src/toolbars/hooks/Size.js +100 -0
  184. package/src/toolbars/hooks/Split.js +37 -0
  185. package/src/toolbars/hooks/Strikethrough.js +65 -0
  186. package/src/toolbars/hooks/Sub.js +58 -0
  187. package/src/toolbars/hooks/Sup.js +58 -0
  188. package/src/toolbars/hooks/SwitchModel.js +78 -0
  189. package/src/toolbars/hooks/Table.js +56 -0
  190. package/src/toolbars/hooks/Toc.js +35 -0
  191. package/src/toolbars/hooks/TogglePreview.js +79 -0
  192. package/src/toolbars/hooks/Ul.js +41 -0
  193. package/src/toolbars/hooks/Underline.js +65 -0
  194. package/src/toolbars/hooks/Undo.js +30 -0
  195. package/src/toolbars/hooks/Video.js +53 -0
  196. package/src/utils/LazyLoadImg.js +341 -0
  197. package/src/utils/autoindent.js +58 -0
  198. package/src/utils/codeBlockContentHandler.js +351 -0
  199. package/src/utils/config.js +98 -0
  200. package/src/utils/copy.js +55 -0
  201. package/src/utils/dialog.js +196 -0
  202. package/src/utils/dom.js +162 -0
  203. package/src/utils/downloadUtil.js +23 -0
  204. package/src/utils/env.js +22 -0
  205. package/src/utils/error.js +61 -0
  206. package/src/utils/event.js +38 -0
  207. package/src/utils/export.js +115 -0
  208. package/src/utils/file.js +121 -0
  209. package/src/utils/formulaUtilsHandler.js +230 -0
  210. package/src/utils/htmlparser.js +977 -0
  211. package/src/utils/image.js +99 -0
  212. package/src/utils/imgSizeHandler.js +279 -0
  213. package/src/utils/jsonUtils.js +17 -0
  214. package/src/utils/lineFeed.js +49 -0
  215. package/src/utils/listContentHandler.js +227 -0
  216. package/src/utils/lookbehind-replace.js +81 -0
  217. package/src/utils/mathjax.js +89 -0
  218. package/src/utils/myersDiff.js +211 -0
  219. package/src/utils/pasteHelper.js +253 -0
  220. package/src/utils/recount-pos.js +59 -0
  221. package/src/utils/regexp.js +295 -0
  222. package/src/utils/sanitize.js +477 -0
  223. package/src/utils/selection.js +50 -0
  224. package/src/utils/svgUtils.js +96 -0
  225. package/src/utils/tableContentHandler.js +592 -0
  226. package/tools/README.md +3 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import SyntaxBase from '@/core/SyntaxBase';
17
+ import { escapeHTMLSpecialCharOnce as _e } from '@/utils/sanitize';
18
+ import { compileRegExp } from '@/utils/regexp';
19
+ import { gfmUnicode } from './Emoji.config';
20
+
21
+ // ref: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint
22
+ export function convertToUnicode(code) {
23
+ if (!code) return '';
24
+ // 分割字符串为两部分
25
+ const parts = code.split('-').map((part) => parseInt(part, 16));
26
+
27
+ // 转换为 Unicode 字符
28
+ return fromCodePoint(...parts);
29
+ }
30
+
31
+ export function fuzzySearchKeysWithValues(query, options) {
32
+ const limit = 50;
33
+ const combinedValues = [];
34
+ let reachedLimit = false;
35
+
36
+ function addResult(emoji) {
37
+ combinedValues.push({
38
+ key: getEmoji(emoji.e, options, true),
39
+ value: `:${emoji.a[0]}:`,
40
+ });
41
+ }
42
+
43
+ for (const emojiCategoryKey in gfmUnicode.emojis) {
44
+ if (reachedLimit) break;
45
+
46
+ for (const emoji of gfmUnicode.emojis[emojiCategoryKey]) {
47
+ if (query === '') {
48
+ addResult(emoji);
49
+ } else {
50
+ if (emoji.a.some((alias) => alias.includes(query)) || emoji.t.some((tag) => tag.includes(query))) {
51
+ addResult(emoji);
52
+ }
53
+ }
54
+
55
+ if (combinedValues.length >= limit) {
56
+ reachedLimit = true;
57
+ break;
58
+ }
59
+ }
60
+ }
61
+
62
+ return combinedValues;
63
+ }
64
+
65
+ function getEmojiByName(name) {
66
+ for (const emojiCategoryKey in gfmUnicode.emojis) {
67
+ const emojiCategory = gfmUnicode.emojis[emojiCategoryKey];
68
+ const emoji = emojiCategory.find((emoji) => emoji.a.includes(name));
69
+ if (emoji) {
70
+ return emoji.e;
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ *
78
+ * @param nameOrUnicode
79
+ * @param options
80
+ * @param isUnicode
81
+ * @returns {string|*|null}
82
+ */
83
+ export function getEmoji(nameOrUnicode, options, isUnicode = false) {
84
+ let unicode = nameOrUnicode;
85
+ if (!isUnicode) {
86
+ unicode = getEmojiByName(nameOrUnicode);
87
+ if (unicode === null) {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ if (options.useUnicode) {
93
+ try {
94
+ return convertToUnicode(unicode);
95
+ } catch (e) {
96
+ console.error(e);
97
+ return null;
98
+ }
99
+ } else {
100
+ const src = options.resourceURL.replace(/\$\{code\}/g, unicode.toLowerCase());
101
+ return `<img class="emoji" src="${src}" alt="${_e(unicode)}" />`;
102
+ }
103
+ }
104
+
105
+ function fromCodePoint(...args) {
106
+ const codeUnits = [];
107
+ let codeLen = 0;
108
+ let result = '';
109
+ for (let index = 0, len = args.length; index !== len; ++index) {
110
+ let codePoint = +args[index];
111
+ // correctly handles all cases including `NaN`, `-Infinity`, `+Infinity`
112
+ // The surrounding `!(...)` is required to correctly handle `NaN` cases
113
+ // The (codePoint>>>0) === codePoint clause handles decimals and negatives
114
+ if (!(codePoint < 0x10ffff && codePoint >>> 0 === codePoint)) {
115
+ throw new RangeError(`Invalid code point: ${codePoint}`);
116
+ }
117
+ if (codePoint <= 0xffff) {
118
+ // BMP code point
119
+ codeLen = codeUnits.push(codePoint);
120
+ } else {
121
+ // Astral code point; split in surrogate halves
122
+ // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
123
+ codePoint -= 0x10000;
124
+ codeLen = codeUnits.push(
125
+ (codePoint >> 10) + 0xd800, // highSurrogate
126
+ (codePoint % 0x400) + 0xdc00, // lowSurrogate
127
+ );
128
+ }
129
+ if (codeLen >= 0x3fff) {
130
+ result += String.fromCharCode.apply(null, codeUnits);
131
+ codeUnits.length = 0;
132
+ }
133
+ }
134
+ return result + String.fromCharCode.apply(null, codeUnits);
135
+ }
136
+
137
+ export default class Emoji extends SyntaxBase {
138
+ static HOOK_NAME = 'emoji';
139
+
140
+ constructor({ config } = { config: undefined }) {
141
+ super({ config });
142
+ this.options = {
143
+ useUnicode: true,
144
+ upperCase: false,
145
+ customHandled: false,
146
+ resourceURL: 'https://github.githubassets.com/images/icons/emoji/unicode/${code}.png?v8',
147
+ emojis: { ...gfmUnicode.emojis },
148
+ };
149
+ if (typeof config !== 'object') {
150
+ return;
151
+ }
152
+ const { useUnicode, customResourceURL, customRenderer, upperCase } = config;
153
+ this.options.useUnicode = typeof useUnicode === 'boolean' ? useUnicode : this.options.useUnicode;
154
+ this.options.upperCase = typeof useUnicode === 'boolean' ? upperCase : this.options.upperCase;
155
+ if (useUnicode === false && typeof customResourceURL === 'string') {
156
+ this.options.resourceURL = customResourceURL;
157
+ }
158
+ if (typeof customRenderer === 'function') {
159
+ this.options.customHandled = true;
160
+ this.options.customRenderer = customRenderer;
161
+ }
162
+ // TODO: URL Validator
163
+ }
164
+
165
+ makeHtml(str, sentenceMakeFunc) {
166
+ if (!this.test(str)) {
167
+ return str;
168
+ }
169
+ return str.replace(this.RULE.reg, (match, emojiName) => {
170
+ // 先走自定义渲染逻辑
171
+ if (this.options.customHandled && typeof this.options.customRenderer === 'function') {
172
+ return this.options.customRenderer(emojiName);
173
+ }
174
+ const emoji = getEmoji(emojiName, this.options);
175
+ if (emoji === null) return str;
176
+ return `<span class="cherry-emoji">${emoji}</span>`;
177
+ });
178
+ }
179
+
180
+ rule() {
181
+ // (?<protocol>\\w+:)\\/\\/
182
+ const ret = {
183
+ // ?<left>
184
+ begin: ':',
185
+ content: '([\\w+_-]+)',
186
+ // ?<right>
187
+ end: ':',
188
+ };
189
+ ret.reg = compileRegExp(ret, 'g');
190
+ return ret;
191
+ }
192
+ overlayMode() {
193
+ return {
194
+ name: 'emoji',
195
+ inEmoji: false,
196
+ passLeftKey: false,
197
+ token(stream, state) {
198
+ // 检查是否是 emoji,但排除连续的三个冒号
199
+ if (!this.inEmoji && stream.match(/:[\w+_-]+:/)) {
200
+ this.inEmoji = true;
201
+ stream.backUp(stream.current().length);
202
+ }
203
+ if (this.inEmoji) {
204
+ if (stream.match(':')) {
205
+ if (!this.passLeftKey) {
206
+ this.passLeftKey = true;
207
+ } else {
208
+ this.inEmoji = false;
209
+ this.passLeftKey = false;
210
+ }
211
+ return 'emoji-container';
212
+ }
213
+ if (stream.match(/[\w+_-]+:/)) {
214
+ stream.backUp(1);
215
+ return 'emoji-text';
216
+ }
217
+ }
218
+ stream.next();
219
+ return null;
220
+ },
221
+ };
222
+ }
223
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import SyntaxBase from '@/core/SyntaxBase';
17
+ import { compileRegExp, ALLOW_WHITESPACE_MULTILINE, UNDERSCORE_EMPHASIS_BOUNDARY } from '@/utils/regexp';
18
+
19
+ export default class Emphasis extends SyntaxBase {
20
+ static HOOK_NAME = 'fontEmphasis';
21
+
22
+ constructor({ config } = { config: undefined }) {
23
+ super({ config });
24
+ if (!config) {
25
+ return;
26
+ }
27
+ this.allowWhitespace = !!config.allowWhitespace;
28
+ }
29
+
30
+ makeHtml(str, sentenceMakeFunc) {
31
+ const converAsterisk = function (match, leading, symbol, text) {
32
+ const tagType = symbol.length % 2 === 1 ? 'em' : 'strong';
33
+ const repeat = Math.floor(symbol.length / 2);
34
+ let prefix = '<strong>'.repeat(repeat);
35
+ let suffix = '</strong>'.repeat(repeat);
36
+ if (tagType === 'em') {
37
+ prefix += '<em>';
38
+ suffix = `</em>${suffix}`;
39
+ }
40
+ // 这里转义_是为了避免跨标签识别
41
+ const result = `${leading}${prefix}${sentenceMakeFunc(text).html.replace(/_/g, '~U')}${suffix}`;
42
+ return result;
43
+ };
44
+ let $str = str;
45
+ if (this.allowWhitespace) {
46
+ $str = $str.replace(/(^|\n[\s]*)(\*)([^\s*](?:.*?)(?:(?:\n.*?)*?))\*/g, converAsterisk);
47
+ $str = $str.replace(/(^|\n[\s]*)(\*{2,})((?:.*?)(?:(?:\n.*?)*?))\2/g, converAsterisk);
48
+ $str = $str.replace(/([^\n*\\\s][ ]*)(\*+)((?:.*?)(?:(?:\n.*?)*?))\2/g, converAsterisk);
49
+ } else {
50
+ // TODO: fix this error
51
+ // @ts-expect-error
52
+ $str = $str.replace(this.RULE.asterisk.reg, converAsterisk);
53
+ }
54
+
55
+ // TODO: fix this error
56
+ // @ts-expect-error
57
+ $str = $str.replace(this.RULE.underscore.reg, (match, leading, symbol, text, index, string) => {
58
+ if (text.trim() === '') {
59
+ return match;
60
+ }
61
+ const tagType = symbol.length % 2 === 1 ? 'em' : 'strong';
62
+ const repeat = Math.floor(symbol.length / 2);
63
+ let prefix = '<strong>'.repeat(repeat);
64
+ let suffix = '</strong>'.repeat(repeat);
65
+ const innerText = sentenceMakeFunc(text).html;
66
+ if (tagType === 'em') {
67
+ // if(/<em>.*?<\/em>/.test(innerText)) {
68
+ // prefix += symbol;
69
+ // suffix = symbol + suffix;
70
+ // } else {
71
+ prefix += '<em>';
72
+ suffix = `</em>${suffix}`;
73
+ // }
74
+ }
75
+ const result = `${leading}${prefix}${innerText}${suffix}`;
76
+ return result;
77
+ });
78
+
79
+ return $str.replace(/~U/g, '_');
80
+ }
81
+
82
+ test(str, flavor) {
83
+ return this.RULE[flavor].reg && this.RULE[flavor].reg.test(str);
84
+ }
85
+
86
+ /**
87
+ * TODO: fix type errors, prefer use `rules` for multiple spec instead
88
+ * @returns
89
+ */
90
+ rule({ config } = { config: undefined }) {
91
+ const allowWhitespace = config ? !!config.allowWhitespace : false;
92
+ const emRegexp = (allowWhitespace, symbol) => {
93
+ const char = `[^${symbol}\\s]`;
94
+ return allowWhitespace ? ALLOW_WHITESPACE_MULTILINE : `(${char}|${char}(.*?(\n${char}.*)*)${char})`;
95
+ };
96
+ const asterisk = {
97
+ begin: '(^|[^\\\\])([*]+)', // ?<leading>, ?<symbol>
98
+ content: `(${emRegexp(allowWhitespace, '*')})`, // ?<text>
99
+ end: '\\2',
100
+ };
101
+
102
+ // UNDERSCORE_EMPHASIS_BORDER:允许除下划线以外的「标点符号」和空格出现,使用[^\w\S \t]或[\W\s]会有性能问题
103
+ const underscore = {
104
+ begin: `(^|${UNDERSCORE_EMPHASIS_BOUNDARY})(_+)`, // ?<leading>, ?<symbol>
105
+ content: `(${emRegexp(allowWhitespace, '_')})`, // ?<text>
106
+ end: `\\2(?=${UNDERSCORE_EMPHASIS_BOUNDARY}|$)`,
107
+ };
108
+
109
+ asterisk.reg = compileRegExp(asterisk, 'g');
110
+ underscore.reg = compileRegExp(underscore, 'g');
111
+ return /** @type {any} */ ({ asterisk, underscore });
112
+ }
113
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import ParagraphBase from '@/core/ParagraphBase';
17
+ import { compileRegExp } from '@/utils/regexp';
18
+
19
+ export default class Footnote extends ParagraphBase {
20
+ static HOOK_NAME = 'footnote';
21
+
22
+ constructor({ externals, config }) {
23
+ super();
24
+ this.footnoteCache = {};
25
+ this.footnoteMap = {}; // 角标缓存索引
26
+ this.footnote = [];
27
+ }
28
+
29
+ $cleanCache() {
30
+ this.footnoteCache = {};
31
+ this.footnoteMap = {}; // 角标缓存索引
32
+ this.footnote = [];
33
+ }
34
+
35
+ pushFootnoteCache(key, cache) {
36
+ this.footnoteCache[key] = cache;
37
+ }
38
+
39
+ getFootnoteCache(key) {
40
+ return this.footnoteCache[key] || null;
41
+ }
42
+
43
+ pushFootNote(key, note) {
44
+ if (this.footnoteMap[key]) {
45
+ // 重复引用时返回已缓存下标
46
+ return this.footnoteMap[key];
47
+ }
48
+ const num = this.footnote.length + 1;
49
+ const fn = {};
50
+ fn.fn = `<sup><a href="#fn:${num}" id="fnref:${num}" title="${key}" class="footnote">[${num}]</a></sup>`;
51
+ fn.fnref = `<a href="#fnref:${num}" id="fn:${num}" title="${key}" class="footnote-ref">[${num}]</a>`;
52
+ fn.num = num;
53
+ fn.note = note.trim();
54
+ this.footnote.push(fn);
55
+ const replaceKey = `\0~fn#${num - 1}#\0`;
56
+ this.footnoteMap[key] = replaceKey;
57
+ return replaceKey;
58
+ }
59
+
60
+ getFootNote() {
61
+ return this.footnote;
62
+ }
63
+
64
+ formatFootNote() {
65
+ const footnote = this.getFootNote();
66
+ if (footnote.length <= 0) {
67
+ return '';
68
+ }
69
+ let html = footnote.map((note) => `<div class="one-footnote">\n${note.fnref}${note.note}\n</div>`).join('');
70
+ const sign = this.$engine.md5(html);
71
+ html = `<div class="footnote" data-sign="${sign}" data-lines="0"><div class="footnote-title">脚注</div>${html}</div>`;
72
+ return html;
73
+ }
74
+
75
+ // getParagraphHook() {
76
+ // return this.commentPAR;
77
+ // }
78
+
79
+ beforeMakeHtml(str) {
80
+ // 单行注释,TODO: 替换为引用
81
+ // str = str.replace(/(^|\n)\[([^^][^\]]*?)\]:([^\n]+?)(?=$|\n)/g, '$1');
82
+ let $str = str;
83
+ if (this.test($str)) {
84
+ $str = $str.replace(this.RULE.reg, (match, leading, key, content) => {
85
+ this.pushFootnoteCache(key, content);
86
+ const LF = match.match(/\n/g) || [];
87
+ return LF.join('');
88
+ });
89
+ // 替换实际引用
90
+ $str = $str.replace(/\[\^([^\]]+?)\](?!:)/g, (match, key) => {
91
+ const cache = this.getFootnoteCache(key);
92
+ if (cache) {
93
+ return this.pushFootNote(key, cache);
94
+ }
95
+ return match;
96
+ });
97
+ $str += this.formatFootNote();
98
+ }
99
+ return $str;
100
+ }
101
+
102
+ makeHtml(str, sentenceMakeFunc) {
103
+ return str;
104
+ }
105
+
106
+ afterMakeHtml(str) {
107
+ const footNotes = this.getFootNote();
108
+ const $str = str.replace(/\0~fn#([0-9]+)#\0/g, (match, num) => footNotes[num].fn);
109
+ this.$cleanCache();
110
+ return $str;
111
+ }
112
+
113
+ rule() {
114
+ const ret = {
115
+ begin: '(^|\\n)[ \t]*',
116
+ content: [
117
+ '\\[\\^([^\\]]+?)\\]:\\h*', // footnote key
118
+ '([\\s\\S]+?)', // footnote content
119
+ ].join(''),
120
+ end: '(?=\\s*$|\\n\\n)',
121
+ };
122
+ ret.reg = compileRegExp(ret, 'g', true);
123
+ return ret;
124
+ }
125
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import ParagraphBase from '@/core/ParagraphBase';
17
+ import { compileRegExp } from '@/utils/regexp';
18
+ import jsYaml from 'js-yaml';
19
+
20
+ export default class FrontMatter extends ParagraphBase {
21
+ static HOOK_NAME = 'frontMatter';
22
+
23
+ constructor(options) {
24
+ super({ needCache: true });
25
+ }
26
+
27
+ beforeMakeHtml(str) {
28
+ return str.replace(this.RULE.reg, (match, content) => {
29
+ try {
30
+ this.$engine.$cherry.frontMatter = jsYaml.load(content);
31
+ } catch (e) {
32
+ try {
33
+ this.$engine.$cherry.frontMatter = JSON.parse(e.toString());
34
+ } catch (e) {
35
+ this.$engine.$cherry.frontMatter = {};
36
+ }
37
+ }
38
+ return '';
39
+ });
40
+ }
41
+
42
+ makeHtml(str, sentenceMakeFunc) {
43
+ // fontMatter不渲染,作为全局属性出现。
44
+ return str;
45
+ }
46
+
47
+ rule() {
48
+ const ret = { begin: '^\\s*-{3,}[^\\n]*\\n', end: '\\n-{3,}[^\\n]*\\n', content: '([\\s\\S]+?)' };
49
+ ret.reg = compileRegExp(ret, 'g', true);
50
+ return ret;
51
+ }
52
+ }
@@ -0,0 +1,82 @@
1
+ import { compileRegExp } from '@/utils/regexp';
2
+ import ParagraphBase from '@/core/ParagraphBase';
3
+ import md5 from 'md5';
4
+
5
+ export default class FrontMatterVars extends ParagraphBase {
6
+ static HOOK_NAME = 'frontMatterVars';
7
+
8
+ constructor() {
9
+ super({ needCache: false });
10
+ }
11
+
12
+ makeHtml(str, sentenceMakeFunc) {
13
+ return str.replace(this.RULE.reg, (match, a, varName) => {
14
+ // Custom rendering logic
15
+ const value = this.resolveNestedVar(varName.trim());
16
+ if (typeof value === 'undefined') {
17
+ console.warn(`Variable ${varName} is not defined.`);
18
+ return match; // Return the original match if the variable is not defined
19
+ }
20
+ const lineCount = 1;
21
+ const sign = md5(`fontMatterVal:${varName}=${value}`);
22
+ return `<span data-sign="${sign}" data-type="frontMatter" data-lines="${lineCount}">${value}</span>`;
23
+ });
24
+ }
25
+
26
+ resolveNestedVar(varName) {
27
+ const vars = this.$engine.$cherry.frontMatter || {};
28
+ const levels = varName.split('.');
29
+ let current = vars;
30
+
31
+ for (const key of levels) {
32
+ if (current && typeof current === 'object' && key in current) {
33
+ current = current[key];
34
+ } else {
35
+ return undefined; // Return undefined if any level is not found
36
+ }
37
+ }
38
+ return current; // Return the final resolved value
39
+ }
40
+
41
+ rule() {
42
+ // (?<protocol>\\w+:)\\/\\/
43
+ const ret = {
44
+ // ?<left>
45
+ begin: '{{',
46
+ content: '(\\s+)?([\\w.]+)(\\s+)?',
47
+ // ?<right>
48
+ end: '}}',
49
+ };
50
+ ret.reg = compileRegExp(ret, 'g');
51
+ return ret;
52
+ }
53
+ overlayMode() {
54
+ return {
55
+ name: 'frontMatterVars',
56
+ inVars: false,
57
+ token(stream, state) {
58
+ // Check if the stream matches the variable pattern
59
+ if (!this.inVars && stream.match(/\{\{(\s+)?[\w.]+(\s+)?}}/)) {
60
+ this.inVars = true;
61
+ stream.backUp(stream.current().length);
62
+ }
63
+ if (this.inVars) {
64
+ if (stream.match('{{')) {
65
+ return 'vars-container';
66
+ }
67
+
68
+ if (stream.match('}}')) {
69
+ this.inVars = false;
70
+ return 'vars-container';
71
+ }
72
+ // Consume the next character if no specific match is found
73
+ stream.next();
74
+ return 'vars-text';
75
+ }
76
+ // Always advance the stream by one character if no match is found
77
+ stream.next();
78
+ return null;
79
+ },
80
+ };
81
+ }
82
+ }