wikiparser-node 0.11.0 → 1.0.0-beta.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 (252) hide show
  1. package/config/.schema.json +26 -0
  2. package/dist/index.d.ts +61 -113
  3. package/dist/index.js +314 -0
  4. package/dist/lib/element.d.ts +122 -108
  5. package/dist/lib/element.js +656 -0
  6. package/dist/lib/node.d.ts +115 -221
  7. package/dist/lib/node.js +473 -0
  8. package/dist/lib/ranges.d.ts +27 -26
  9. package/dist/lib/ranges.js +130 -0
  10. package/dist/lib/text.d.ts +36 -28
  11. package/dist/lib/text.js +215 -0
  12. package/dist/lib/title.d.ts +26 -12
  13. package/dist/lib/title.js +108 -0
  14. package/dist/mixin/attributesParent.js +90 -0
  15. package/dist/mixin/fixed.js +29 -0
  16. package/dist/mixin/hidden.js +19 -0
  17. package/dist/mixin/singleLine.js +23 -0
  18. package/dist/mixin/sol.js +41 -0
  19. package/dist/parser/brackets.js +118 -0
  20. package/dist/parser/commentAndExt.js +48 -0
  21. package/dist/parser/converter.js +31 -0
  22. package/dist/parser/externalLinks.js +22 -0
  23. package/dist/parser/hrAndDoubleUnderscore.js +35 -0
  24. package/dist/parser/html.js +29 -0
  25. package/dist/parser/links.js +86 -0
  26. package/dist/parser/list.js +51 -0
  27. package/dist/parser/magicLinks.js +32 -0
  28. package/dist/parser/quotes.js +57 -0
  29. package/dist/parser/selector.js +158 -0
  30. package/dist/parser/table.js +108 -0
  31. package/dist/src/arg.d.ts +47 -23
  32. package/dist/src/arg.js +196 -0
  33. package/dist/src/atom.d.ts +12 -0
  34. package/dist/src/atom.js +22 -0
  35. package/dist/src/attribute.d.ts +74 -33
  36. package/dist/src/attribute.js +433 -0
  37. package/dist/src/attributes.d.ts +61 -55
  38. package/dist/src/attributes.js +371 -0
  39. package/dist/src/converter.d.ts +45 -71
  40. package/dist/src/converter.js +135 -0
  41. package/dist/src/converterFlags.d.ts +64 -39
  42. package/dist/src/converterFlags.js +235 -0
  43. package/dist/src/converterRule.d.ts +49 -27
  44. package/dist/src/converterRule.js +255 -0
  45. package/dist/src/extLink.d.ts +41 -38
  46. package/dist/src/extLink.js +154 -0
  47. package/dist/src/gallery.d.ts +59 -18
  48. package/dist/src/gallery.js +132 -0
  49. package/dist/src/heading.d.ts +60 -22
  50. package/dist/src/heading.js +135 -0
  51. package/dist/src/hidden.d.ts +20 -0
  52. package/dist/src/hidden.js +24 -0
  53. package/dist/src/html.d.ts +83 -29
  54. package/dist/src/html.js +242 -0
  55. package/dist/src/imageParameter.d.ts +59 -40
  56. package/dist/src/imageParameter.js +251 -0
  57. package/dist/src/imagemap.d.ts +65 -21
  58. package/dist/src/imagemap.js +169 -0
  59. package/dist/src/imagemapLink.d.ts +46 -14
  60. package/dist/src/imagemapLink.js +38 -0
  61. package/dist/src/index.d.ts +71 -105
  62. package/dist/src/index.js +826 -0
  63. package/dist/src/link/base.d.ts +71 -0
  64. package/dist/src/link/base.js +225 -0
  65. package/dist/src/link/category.d.ts +10 -11
  66. package/dist/src/link/category.js +26 -0
  67. package/dist/src/link/file.d.ts +61 -39
  68. package/dist/src/link/file.js +242 -0
  69. package/dist/src/link/galleryImage.d.ts +34 -12
  70. package/dist/src/link/galleryImage.js +98 -0
  71. package/dist/src/link/index.d.ts +25 -63
  72. package/dist/src/link/index.js +136 -0
  73. package/dist/src/magicLink.d.ts +22 -15
  74. package/dist/src/magicLink.js +126 -0
  75. package/dist/src/nested.d.ts +47 -0
  76. package/dist/src/nested.js +84 -0
  77. package/dist/src/nowiki/base.d.ts +39 -0
  78. package/dist/src/nowiki/base.js +29 -0
  79. package/dist/src/nowiki/comment.d.ts +31 -20
  80. package/dist/src/nowiki/comment.js +61 -0
  81. package/dist/src/nowiki/dd.d.ts +17 -11
  82. package/dist/src/nowiki/dd.js +50 -0
  83. package/dist/src/nowiki/doubleUnderscore.d.ts +28 -13
  84. package/dist/src/nowiki/doubleUnderscore.js +45 -0
  85. package/dist/src/nowiki/hr.d.ts +28 -10
  86. package/dist/src/nowiki/hr.js +33 -0
  87. package/dist/src/nowiki/index.d.ts +17 -23
  88. package/dist/src/nowiki/index.js +21 -0
  89. package/dist/src/nowiki/list.d.ts +15 -7
  90. package/dist/src/nowiki/list.js +11 -0
  91. package/dist/src/nowiki/noinclude.d.ts +20 -7
  92. package/dist/src/nowiki/noinclude.js +22 -0
  93. package/dist/src/nowiki/quote.d.ts +25 -10
  94. package/dist/src/nowiki/quote.js +55 -0
  95. package/dist/src/onlyinclude.d.ts +28 -12
  96. package/dist/src/onlyinclude.js +64 -0
  97. package/dist/src/paramTag/index.d.ts +40 -17
  98. package/dist/src/paramTag/index.js +76 -0
  99. package/dist/src/paramTag/inputbox.d.ts +8 -7
  100. package/dist/src/paramTag/inputbox.js +19 -0
  101. package/dist/src/parameter.d.ts +62 -41
  102. package/dist/src/parameter.js +201 -0
  103. package/dist/src/pre.d.ts +32 -0
  104. package/dist/src/pre.js +39 -0
  105. package/dist/src/syntax.d.ts +17 -14
  106. package/dist/src/syntax.js +65 -0
  107. package/dist/src/table/base.d.ts +55 -0
  108. package/dist/src/table/base.js +77 -0
  109. package/dist/src/table/index.d.ts +123 -156
  110. package/dist/src/table/index.js +811 -0
  111. package/dist/src/table/td.d.ts +90 -67
  112. package/dist/src/table/td.js +276 -0
  113. package/dist/src/table/tr.d.ts +30 -85
  114. package/dist/src/table/tr.js +48 -0
  115. package/dist/src/table/trBase.d.ts +72 -0
  116. package/dist/src/table/trBase.js +153 -0
  117. package/dist/src/tagPair/ext.d.ts +47 -11
  118. package/dist/src/tagPair/ext.js +127 -0
  119. package/dist/src/tagPair/include.d.ts +32 -13
  120. package/dist/src/tagPair/include.js +40 -0
  121. package/dist/src/tagPair/index.d.ts +44 -29
  122. package/dist/src/tagPair/index.js +111 -0
  123. package/dist/src/transclude.d.ts +88 -85
  124. package/dist/src/transclude.js +739 -0
  125. package/dist/util/base.js +26 -0
  126. package/dist/util/debug.js +52 -0
  127. package/dist/util/diff.js +69 -0
  128. package/dist/util/lint.js +38 -0
  129. package/dist/util/string.js +103 -0
  130. package/errors/README +1 -0
  131. package/i18n/zh-hans.json +1 -0
  132. package/i18n/zh-hant.json +1 -0
  133. package/package.json +21 -24
  134. package/printed/README +1 -0
  135. package/dist/mixin/attributeParent.d.ts +0 -9
  136. package/dist/mixin/fixedToken.d.ts +0 -8
  137. package/dist/mixin/hidden.d.ts +0 -8
  138. package/dist/mixin/singleLine.d.ts +0 -8
  139. package/dist/mixin/sol.d.ts +0 -8
  140. package/dist/parser/brackets.d.ts +0 -12
  141. package/dist/parser/commentAndExt.d.ts +0 -8
  142. package/dist/parser/converter.d.ts +0 -7
  143. package/dist/parser/externalLinks.d.ts +0 -7
  144. package/dist/parser/hrAndDoubleUnderscore.d.ts +0 -11
  145. package/dist/parser/html.d.ts +0 -7
  146. package/dist/parser/links.d.ts +0 -7
  147. package/dist/parser/list.d.ts +0 -7
  148. package/dist/parser/magicLinks.d.ts +0 -7
  149. package/dist/parser/quotes.d.ts +0 -7
  150. package/dist/parser/selector.d.ts +0 -12
  151. package/dist/parser/table.d.ts +0 -11
  152. package/dist/src/atom/hidden.d.ts +0 -5
  153. package/dist/src/atom/index.d.ts +0 -15
  154. package/dist/src/charinsert.d.ts +0 -32
  155. package/dist/src/hasNowiki/index.d.ts +0 -14
  156. package/dist/src/hasNowiki/pre.d.ts +0 -13
  157. package/dist/src/nested/choose.d.ts +0 -13
  158. package/dist/src/nested/combobox.d.ts +0 -13
  159. package/dist/src/nested/index.d.ts +0 -18
  160. package/dist/src/nested/references.d.ts +0 -13
  161. package/dist/tool/index.d.ts +0 -420
  162. package/dist/util/base.d.ts +0 -10
  163. package/dist/util/debug.d.ts +0 -20
  164. package/dist/util/diff.d.ts +0 -8
  165. package/dist/util/lint.d.ts +0 -28
  166. package/dist/util/string.d.ts +0 -55
  167. package/index.js +0 -333
  168. package/lib/element.js +0 -618
  169. package/lib/node.js +0 -730
  170. package/lib/ranges.js +0 -130
  171. package/lib/text.js +0 -265
  172. package/lib/title.js +0 -83
  173. package/mixin/attributeParent.js +0 -117
  174. package/mixin/fixedToken.js +0 -40
  175. package/mixin/hidden.js +0 -21
  176. package/mixin/singleLine.js +0 -31
  177. package/mixin/sol.js +0 -54
  178. package/parser/brackets.js +0 -128
  179. package/parser/commentAndExt.js +0 -62
  180. package/parser/converter.js +0 -46
  181. package/parser/externalLinks.js +0 -33
  182. package/parser/hrAndDoubleUnderscore.js +0 -49
  183. package/parser/html.js +0 -42
  184. package/parser/links.js +0 -94
  185. package/parser/list.js +0 -59
  186. package/parser/magicLinks.js +0 -41
  187. package/parser/quotes.js +0 -64
  188. package/parser/selector.js +0 -180
  189. package/parser/table.js +0 -114
  190. package/src/arg.js +0 -207
  191. package/src/atom/hidden.js +0 -13
  192. package/src/atom/index.js +0 -43
  193. package/src/attribute.js +0 -472
  194. package/src/attributes.js +0 -453
  195. package/src/charinsert.js +0 -97
  196. package/src/converter.js +0 -176
  197. package/src/converterFlags.js +0 -284
  198. package/src/converterRule.js +0 -256
  199. package/src/extLink.js +0 -180
  200. package/src/gallery.js +0 -149
  201. package/src/hasNowiki/index.js +0 -44
  202. package/src/hasNowiki/pre.js +0 -40
  203. package/src/heading.js +0 -134
  204. package/src/html.js +0 -254
  205. package/src/imageParameter.js +0 -303
  206. package/src/imagemap.js +0 -199
  207. package/src/imagemapLink.js +0 -41
  208. package/src/index.js +0 -938
  209. package/src/link/category.js +0 -44
  210. package/src/link/file.js +0 -287
  211. package/src/link/galleryImage.js +0 -120
  212. package/src/link/index.js +0 -388
  213. package/src/magicLink.js +0 -151
  214. package/src/nested/choose.js +0 -24
  215. package/src/nested/combobox.js +0 -23
  216. package/src/nested/index.js +0 -96
  217. package/src/nested/references.js +0 -23
  218. package/src/nowiki/comment.js +0 -71
  219. package/src/nowiki/dd.js +0 -59
  220. package/src/nowiki/doubleUnderscore.js +0 -56
  221. package/src/nowiki/hr.js +0 -41
  222. package/src/nowiki/index.js +0 -56
  223. package/src/nowiki/list.js +0 -16
  224. package/src/nowiki/noinclude.js +0 -28
  225. package/src/nowiki/quote.js +0 -69
  226. package/src/onlyinclude.js +0 -64
  227. package/src/paramTag/index.js +0 -89
  228. package/src/paramTag/inputbox.js +0 -35
  229. package/src/parameter.js +0 -239
  230. package/src/syntax.js +0 -91
  231. package/src/table/index.js +0 -985
  232. package/src/table/td.js +0 -343
  233. package/src/table/tr.js +0 -319
  234. package/src/tagPair/ext.js +0 -146
  235. package/src/tagPair/include.js +0 -50
  236. package/src/tagPair/index.js +0 -131
  237. package/src/transclude.js +0 -843
  238. package/tool/index.js +0 -1209
  239. package/typings/api.d.ts +0 -9
  240. package/typings/array.d.ts +0 -29
  241. package/typings/event.d.ts +0 -22
  242. package/typings/index.d.ts +0 -118
  243. package/typings/node.d.ts +0 -35
  244. package/typings/parser.d.ts +0 -12
  245. package/typings/table.d.ts +0 -10
  246. package/typings/token.d.ts +0 -31
  247. package/typings/tool.d.ts +0 -6
  248. package/util/base.js +0 -17
  249. package/util/debug.js +0 -73
  250. package/util/diff.js +0 -76
  251. package/util/lint.js +0 -57
  252. package/util/string.js +0 -126
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ const string_1 = require("../util/string");
3
+ const Parser = require("../index");
4
+ const HeadingToken = require("../src/heading");
5
+ const TranscludeToken = require("../src/transclude");
6
+ const ArgToken = require("../src/arg");
7
+ /**
8
+ * 解析花括号
9
+ * @throws TranscludeToken.constructor()
10
+ */
11
+ const parseBrackets = (wikitext, config = Parser.getConfig(), accum = []) => {
12
+ const source = `${config.excludes?.includes('heading') ? '' : '^(\0\\d+c\x7F)*={1,6}|'}\\[\\[|\\{{2,}|-\\{(?!\\{)`, { parserFunction: [, , , subst] } = config, stack = [], closes = { '=': '\n', '{': '\\}{2,}|\\|', '-': '\\}-', '[': '\\]\\]' }, marks = { '!': '!', '!!': '+', '(!': '{', '!)': '}', '!-': '-', '=': '~' };
13
+ let text = wikitext, regex = new RegExp(source, 'gmu'), mt = regex.exec(text), moreBraces = text.includes('}}'), lastIndex;
14
+ while (mt || Number(lastIndex) <= text.length && stack.at(-1)?.[0]?.startsWith('=')) {
15
+ if (mt?.[1]) {
16
+ const [, { length }] = mt;
17
+ mt[0] = mt[0].slice(length);
18
+ mt.index += length;
19
+ }
20
+ const { 0: syntax, index: curIndex } = mt ?? { 0: '\n', index: text.length }, top = stack.pop() ?? {}, { 0: open, index, parts, findEqual: topFindEqual, pos: topPos } = top, innerEqual = syntax === '=' && topFindEqual;
21
+ if (syntax === ']]' || syntax === '}-') { // 情形1:闭合内链或转换
22
+ lastIndex = curIndex + 2;
23
+ }
24
+ else if (syntax === '\n') { // 情形2:闭合标题或文末
25
+ lastIndex = curIndex + 1;
26
+ const { pos, findEqual } = stack.at(-1) ?? {};
27
+ if (pos === undefined || findEqual || (0, string_1.removeComment)(text.slice(pos, index)) !== '') {
28
+ // eslint-disable-next-line regexp/no-misleading-capturing-group
29
+ const rmt = /^(={1,6})(.+)\1((?:\s|\0\d+c\x7F)*)$/u
30
+ .exec(text.slice(index, curIndex));
31
+ if (rmt) {
32
+ text = `${text.slice(0, index)}\0${accum.length}h\x7F${text.slice(curIndex)}`;
33
+ lastIndex = index + 4 + String(accum.length).length;
34
+ new HeadingToken(rmt[1].length, rmt.slice(2), config, accum);
35
+ }
36
+ }
37
+ }
38
+ else if (syntax === '|' || innerEqual) { // 情形3:模板内部,含行首单个'='
39
+ lastIndex = curIndex + 1;
40
+ parts.at(-1).push(text.slice(topPos, curIndex));
41
+ if (syntax === '|') {
42
+ parts.push([]);
43
+ }
44
+ top.pos = lastIndex;
45
+ top.findEqual = syntax === '|';
46
+ stack.push(top);
47
+ }
48
+ else if (syntax.startsWith('}}')) { // 情形4:闭合模板
49
+ const close = syntax.slice(0, Math.min(open.length, 3)), rest = open.length - close.length, { length } = accum;
50
+ lastIndex = curIndex + close.length; // 这不是最终的lastIndex
51
+ parts.at(-1).push(text.slice(topPos, curIndex));
52
+ let skip = false, ch = 't';
53
+ if (close.length === 3) {
54
+ const argParts = parts.map(part => part.join('=')), str = argParts.length > 1 && (0, string_1.removeComment)(argParts[1]).trim();
55
+ new ArgToken(argParts, config, accum);
56
+ if (str && str.endsWith(':') && subst.includes(str.slice(0, -1).toLowerCase())) {
57
+ ch = 's';
58
+ }
59
+ }
60
+ else {
61
+ try {
62
+ new TranscludeToken(parts[0][0], parts.slice(1), config, accum);
63
+ const name = (0, string_1.removeComment)(parts[0][0]).trim();
64
+ if (Object.hasOwn(marks, name)) {
65
+ ch = marks[name]; // 标记{{!}}等
66
+ }
67
+ else if (/^(?:filepath|(?:full|canonical)urle?):.|^server$/iu.test(name)) {
68
+ ch = 'm';
69
+ }
70
+ else if (/^#vardefine:./iu.test(name)) {
71
+ ch = 'c';
72
+ }
73
+ }
74
+ catch (e) {
75
+ if (e instanceof SyntaxError && e.message.startsWith('非法的模板名称:')) {
76
+ lastIndex = index + open.length;
77
+ skip = true;
78
+ }
79
+ else {
80
+ throw e;
81
+ }
82
+ }
83
+ }
84
+ if (!skip) {
85
+ text = `${text.slice(0, index + rest)}\0${length}${ch}\x7F${text.slice(lastIndex)}`;
86
+ lastIndex = index + rest + 3 + String(length).length;
87
+ if (rest > 1) {
88
+ stack.push({ 0: open.slice(0, rest), index: index, pos: index + rest, parts: [[]] });
89
+ }
90
+ else if (rest === 1 && text[index - 1] === '-') {
91
+ stack.push({ 0: '-{', index: index - 1, pos: index + 1, parts: [[]] });
92
+ }
93
+ }
94
+ }
95
+ else { // 情形5:开启
96
+ lastIndex = curIndex + syntax.length;
97
+ if (syntax.startsWith('{')) {
98
+ mt.pos = lastIndex;
99
+ mt.parts = [[]];
100
+ }
101
+ stack.push(...'0' in top ? [top] : [], mt);
102
+ }
103
+ moreBraces &&= text.slice(lastIndex).includes('}}');
104
+ let curTop = stack.at(-1);
105
+ if (!moreBraces && curTop?.[0]?.startsWith('{')) {
106
+ stack.pop();
107
+ curTop = stack.at(-1);
108
+ }
109
+ regex = new RegExp(source + (curTop
110
+ ? `|${closes[curTop[0][0]]}${curTop.findEqual ? '|=' : ''}`
111
+ : ''), 'gmu');
112
+ regex.lastIndex = lastIndex;
113
+ mt = regex.exec(text);
114
+ }
115
+ return text;
116
+ };
117
+ Parser.parsers['parseBrackets'] = __filename;
118
+ module.exports = parseBrackets;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const OnlyincludeToken = require("../src/onlyinclude");
4
+ const NoincludeToken = require("../src/nowiki/noinclude");
5
+ const IncludeToken = require("../src/tagPair/include");
6
+ const ExtToken = require("../src/tagPair/ext");
7
+ const CommentToken = require("../src/nowiki/comment");
8
+ /**
9
+ * 解析HTML注释和扩展标签
10
+ * @param includeOnly 是否嵌入
11
+ */
12
+ const parseCommentAndExt = (wikitext, config = Parser.getConfig(), accum = [], includeOnly = false) => {
13
+ const onlyinclude = /<onlyinclude>(.*?)<\/onlyinclude>/gsu;
14
+ if (includeOnly && wikitext.search(onlyinclude) !== -1) { // `<onlyinclude>`拥有最高优先级
15
+ return wikitext.replace(onlyinclude, (_, inner) => {
16
+ const str = `\0${accum.length}e\x7F`;
17
+ new OnlyincludeToken(inner, config, accum);
18
+ return str;
19
+ }).replace(/(?<=^|\0\d+e\x7F)[^\0]+(?=$|\0\d+e\x7F)/gu, substr => {
20
+ new NoincludeToken(substr, config, accum);
21
+ return `\0${accum.length - 1}c\x7F`;
22
+ });
23
+ }
24
+ const ext = config.ext.join('|'), includeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', noincludeRegex = includeOnly ? 'noinclude' : 'includeonly', regex = new RegExp('<!--.*?(?:-->|$)|' // comment
25
+ + `<${includeRegex}(?:\\s[^>]*?)?>|</${includeRegex}\\s*>|` // <includeonly>
26
+ + `<(${ext})(\\s[^>]*?)?(?:/>|>(.*?)</(\\1\\s*)>)|` // 扩展标签
27
+ + `<(${noincludeRegex})(\\s[^>]*?)?(?:/>|>(.*?)(?:</(\\5\\s*)>|$))`, // <noinclude>
28
+ 'gisu');
29
+ return wikitext.replace(regex, (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
30
+ const str = `\0${accum.length}${name ? 'e' : 'c'}\x7F`;
31
+ if (name) {
32
+ new ExtToken(name, attr, inner, closing, config, accum);
33
+ }
34
+ else if (substr.startsWith('<!--')) {
35
+ const closed = substr.endsWith('-->');
36
+ new CommentToken(substr.slice(4, closed ? -3 : undefined), closed, config, accum);
37
+ }
38
+ else if (include) {
39
+ new IncludeToken(include, includeAttr, includeInner, includeClosing, config, accum);
40
+ }
41
+ else {
42
+ new NoincludeToken(substr, config, accum);
43
+ }
44
+ return str;
45
+ });
46
+ };
47
+ Parser.parsers['parseCommentAndExt'] = __filename;
48
+ module.exports = parseCommentAndExt;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const ConverterToken = require("../src/converter");
4
+ /** 解析语言变体转换 */
5
+ const parseConverter = (wikitext, config = Parser.getConfig(), accum = []) => {
6
+ const regex1 = /-\{/gu, regex2 = /-\{|\}-/gu, stack = [];
7
+ let regex = regex1, text = wikitext, mt = regex.exec(text);
8
+ while (mt) {
9
+ const { 0: syntax, index } = mt;
10
+ if (syntax === '}-') {
11
+ const top = stack.pop(), { length } = accum, str = text.slice(top.index + 2, index), i = str.indexOf('|'), [flags, raw] = i === -1 ? [[], str] : [str.slice(0, i).split(';'), str.slice(i + 1)], temp = raw.replace(/(&[#a-z\d]+);/giu, '$1\x01'), // eslint-disable-line regexp/prefer-lookaround
12
+ variants = `(?:${config.variants.join('|')})`, rules = temp.split(new RegExp(`;(?=\\s*(?:${variants}|[^;]*?=>\\s*${variants})\\s*:)`, 'u'))
13
+ .map(rule => rule.replaceAll('\x01', ';'));
14
+ new ConverterToken(flags, rules, config, accum);
15
+ text = `${text.slice(0, top.index)}\0${length}v\x7F${text.slice(index + 2)}`;
16
+ if (stack.length === 0) {
17
+ regex = regex1;
18
+ }
19
+ regex.lastIndex = top.index + 3 + String(length).length;
20
+ }
21
+ else {
22
+ stack.push(mt);
23
+ regex = regex2;
24
+ regex.lastIndex = index + 2;
25
+ }
26
+ mt = regex.exec(text);
27
+ }
28
+ return text;
29
+ };
30
+ Parser.parsers['parseConverter'] = __filename;
31
+ module.exports = parseConverter;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ const string_1 = require("../util/string");
3
+ const Parser = require("../index");
4
+ const ExtLinkToken = require("../src/extLink");
5
+ /** 解析外部链接 */
6
+ const parseExternalLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
7
+ const regex = new RegExp(`\\[((?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar})(\\p{Zs}*)([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)\\]`, 'giu');
8
+ return wikitext.replace(regex, (_, url, space, text) => {
9
+ const { length } = accum, mt = /&[lg]t;/u.exec(url);
10
+ if (mt) {
11
+ /* eslint-disable no-param-reassign */
12
+ url = url.slice(0, mt.index);
13
+ space = '';
14
+ text = `${url.slice(mt.index)}${space}${text}`;
15
+ /* eslint-enable no-param-reassign */
16
+ }
17
+ new ExtLinkToken(url, space, text, config, accum);
18
+ return `\0${length}w\x7F`;
19
+ });
20
+ };
21
+ Parser.parsers['parseExternalLinks'] = __filename;
22
+ module.exports = parseExternalLinks;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const HrToken = require("../src/nowiki/hr");
4
+ const DoubleUnderscoreToken = require("../src/nowiki/doubleUnderscore");
5
+ const HeadingToken = require("../src/heading");
6
+ /**
7
+ * 解析`<hr>`和状态开关
8
+ * @param {Token} root 根节点
9
+ */
10
+ const parseHrAndDoubleUnderscore = ({ firstChild, type, name }, config = Parser.getConfig(), accum = []) => {
11
+ const { doubleUnderscore } = config, insensitive = new Set(doubleUnderscore[0]), sensitive = new Set(doubleUnderscore[1]);
12
+ let { data } = firstChild;
13
+ if (type !== 'root' && (type !== 'ext-inner' || name !== 'poem')) {
14
+ data = `\0${data}`;
15
+ }
16
+ data = data.replace(/^((?:\0\d+c\x7F)*)(-{4,})/gmu, (_, lead, m) => {
17
+ new HrToken(m.length, config, accum);
18
+ return `${lead}\0${accum.length - 1}r\x7F`;
19
+ }).replace(new RegExp(`__(${doubleUnderscore.flat().join('|')})__`, 'giu'), (m, p1) => {
20
+ if (insensitive.has(p1.toLowerCase()) || sensitive.has(p1)) {
21
+ new DoubleUnderscoreToken(p1, config, accum);
22
+ return `\0${accum.length - 1}u\x7F`;
23
+ }
24
+ return m;
25
+ }).replace(
26
+ // eslint-disable-next-line regexp/no-misleading-capturing-group
27
+ /^((?:\0\d+c\x7F)*)(={1,6})(.+)\2((?:[^\S\n]|\0\d+c\x7F)*)$/gmu, (_, lead, equals, heading, trail) => {
28
+ const text = `${lead}\0${accum.length}h\x7F`;
29
+ new HeadingToken(equals.length, [heading, trail], config, accum);
30
+ return text;
31
+ });
32
+ return type === 'root' || type === 'ext-inner' && name === 'poem' ? data : data.slice(1);
33
+ };
34
+ Parser.parsers['parseHrAndDoubleUnderscore'] = __filename;
35
+ module.exports = parseHrAndDoubleUnderscore;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const AttributesToken = require("../src/attributes");
4
+ const HtmlToken = require("../src/html");
5
+ /** 解析HTML标签 */
6
+ const parseHtml = (wikitext, config = Parser.getConfig(), accum = []) => {
7
+ const regex = /^(\/?)([a-z][^\s/>]*)((?:\s|\/(?!>))[^>]*?)?(\/?>)([^<]*)$/iu, elements = new Set(config.html.flat()), bits = wikitext.split('<');
8
+ let text = bits.shift();
9
+ for (const x of bits) {
10
+ const mt = regex.exec(x), t = mt?.[2], name = t?.toLowerCase();
11
+ if (!mt || !elements.has(name)) {
12
+ text += `<${x}`;
13
+ continue;
14
+ }
15
+ const [, slash, , params = '', brace, rest] = mt,
16
+ attr = new AttributesToken(params, 'html-attrs', name, config, accum), itemprop = attr.getAttr('itemprop');
17
+ if (name === 'meta' && (itemprop === undefined || attr.getAttr('content') === undefined)
18
+ || name === 'link' && (itemprop === undefined || attr.getAttr('href') === undefined)) {
19
+ text += `<${x}`;
20
+ accum.pop();
21
+ continue;
22
+ }
23
+ text += `\0${accum.length}x\x7F${rest}`;
24
+ new HtmlToken(t, attr, slash === '/', brace === '/>', config, accum);
25
+ }
26
+ return text;
27
+ };
28
+ Parser.parsers['parseHtml'] = __filename;
29
+ module.exports = parseHtml;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const LinkToken = require("../src/link");
4
+ const FileToken = require("../src/link/file");
5
+ const CategoryToken = require("../src/link/category");
6
+ /** 解析内部链接 */
7
+ const parseLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
8
+ const parseQuotes = require('./quotes.js');
9
+ const regex = /^((?:(?!\0\d+!\x7F)[^\n<>[\]{}|])+)(?:(\||\0\d+!\x7F)(.*?[^\]]))?\]\](.*)$/su, regexImg = /^((?:(?!\0\d+!\x7F)[^\n<>[\]{}|])+)(\||\0\d+!\x7F)(.*)$/su, regexExt = new RegExp(`^\\s*(?:${config.protocol})`, 'iu'), bits = wikitext.split('[[');
10
+ let s = bits.shift();
11
+ for (let i = 0; i < bits.length; i++) {
12
+ let mightBeImg = false, link, delimiter, text, after;
13
+ const x = bits[i], m = regex.exec(x);
14
+ if (m) {
15
+ [, link, delimiter, text, after] = m;
16
+ if (after.startsWith(']') && text?.includes('[')) {
17
+ text += ']';
18
+ after = after.slice(1);
19
+ }
20
+ }
21
+ else {
22
+ const m2 = regexImg.exec(x);
23
+ if (m2) {
24
+ mightBeImg = true;
25
+ [, link, delimiter, text] = m2;
26
+ }
27
+ }
28
+ if (link === undefined || regexExt.test(link) || /\0\d+[exhbru]\x7F/u.test(link)) {
29
+ s += `[[${x}`;
30
+ continue;
31
+ }
32
+ const force = link.trim().startsWith(':');
33
+ if (force && mightBeImg) {
34
+ s += `[[${x}`;
35
+ continue;
36
+ }
37
+ const title = Parser.normalizeTitle(link, 0, false, config, true, true, true), { ns, interwiki, valid } = title;
38
+ if (!valid) {
39
+ s += `[[${x}`;
40
+ continue;
41
+ }
42
+ else if (mightBeImg) {
43
+ if (interwiki || ns !== 6) {
44
+ s += `[[${x}`;
45
+ continue;
46
+ }
47
+ let found = false;
48
+ for (i++; i < bits.length; i++) {
49
+ const next = bits[i], p = next.split(']]');
50
+ if (p.length > 2) {
51
+ found = true;
52
+ text += `[[${p[0]}]]${p[1]}`;
53
+ after = p.slice(2).join(']]');
54
+ break;
55
+ }
56
+ else if (p.length === 2) {
57
+ text += `[[${p[0]}]]${p[1]}`;
58
+ }
59
+ else {
60
+ text += `[[${next}`;
61
+ break;
62
+ }
63
+ }
64
+ text = parseLinks(text, config, accum);
65
+ if (!found) {
66
+ s += `[[${link}${delimiter}${text}`;
67
+ continue;
68
+ }
69
+ }
70
+ text &&= parseQuotes(text, config, accum);
71
+ s += `\0${accum.length}l\x7F${after}`;
72
+ let SomeLinkToken = LinkToken;
73
+ if (!force) {
74
+ if (!interwiki && ns === 6) {
75
+ SomeLinkToken = FileToken;
76
+ }
77
+ else if (!interwiki && ns === 14) {
78
+ SomeLinkToken = CategoryToken;
79
+ }
80
+ }
81
+ new SomeLinkToken(link, text, config, accum, delimiter);
82
+ }
83
+ return s;
84
+ };
85
+ Parser.parsers['parseLinks'] = __filename;
86
+ module.exports = parseLinks;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const ListToken = require("../src/nowiki/list");
4
+ const DdToken = require("../src/nowiki/dd");
5
+ /** 解析列表 */
6
+ const parseList = (wikitext, config = Parser.getConfig(), accum = []) => {
7
+ const mt = /^((?:\0\d+c\x7F)*)([;:*#]+)/u.exec(wikitext);
8
+ if (!mt) {
9
+ return wikitext;
10
+ }
11
+ const [total, comment, prefix] = mt;
12
+ let text = `${comment}\0${accum.length}d\x7F${wikitext.slice(total.length)}`, dt = prefix.split(';').length - 1;
13
+ new ListToken(prefix, config, accum);
14
+ if (!dt) {
15
+ return text;
16
+ }
17
+ let regex = /:+|-\{/gu, ex = regex.exec(text), lc = 0;
18
+ while (ex && dt) {
19
+ const { 0: syntax, index } = ex;
20
+ if (syntax.startsWith(':')) {
21
+ if (syntax.length >= dt) {
22
+ new DdToken(':'.repeat(dt), config, accum);
23
+ return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + dt)}`;
24
+ }
25
+ text = `${text.slice(0, index)}\0${accum.length}d\x7F${text.slice(regex.lastIndex)}`;
26
+ dt -= syntax.length;
27
+ regex.lastIndex = index + 4 + String(accum.length).length;
28
+ new DdToken(syntax, config, accum);
29
+ }
30
+ else if (syntax === '-{') {
31
+ if (!lc) {
32
+ const { lastIndex } = regex;
33
+ regex = /-\{|\}-/gu;
34
+ regex.lastIndex = lastIndex;
35
+ }
36
+ lc++;
37
+ }
38
+ else {
39
+ lc--;
40
+ if (!lc) {
41
+ const { lastIndex } = regex;
42
+ regex = /:+|-\{/gu;
43
+ regex.lastIndex = lastIndex;
44
+ }
45
+ }
46
+ ex = regex.exec(text);
47
+ }
48
+ return text;
49
+ };
50
+ Parser.parsers['parseList'] = __filename;
51
+ module.exports = parseList;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ const string_1 = require("../util/string");
3
+ const Parser = require("../index");
4
+ const MagicLinkToken = require("../src/magicLink");
5
+ /** 解析自由外链 */
6
+ const parseMagicLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
7
+ const regex = new RegExp(`(?<![\\p{L}\\d_])(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})`, 'giu');
8
+ return wikitext.replace(regex, (m, p1) => {
9
+ let trail = '', url = m;
10
+ const m2 = /&(?:lt|gt|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
11
+ if (m2) {
12
+ trail = url.slice(m2.index);
13
+ url = url.slice(0, m2.index);
14
+ }
15
+ const sep = new RegExp(`[,;.:!?${url.includes('(') ? '' : ')'}]+$`, 'u'), sepChars = sep.exec(url);
16
+ if (sepChars) {
17
+ let correction = 0;
18
+ if (sepChars[0].startsWith(';') && /&(?:[a-z]+|#x[\da-f]+|#\d+)$/iu.test(url.slice(0, sepChars.index))) {
19
+ correction = 1;
20
+ }
21
+ trail = `${url.slice(sepChars.index + correction)}${trail}`;
22
+ url = url.slice(0, sepChars.index + correction);
23
+ }
24
+ if (trail.length >= p1.length) {
25
+ return m;
26
+ }
27
+ new MagicLinkToken(url, false, config, accum);
28
+ return `\0${accum.length - 1}w\x7F${trail}`;
29
+ });
30
+ };
31
+ Parser.parsers['parseMagicLinks'] = __filename;
32
+ module.exports = parseMagicLinks;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const QuoteToken = require("../src/nowiki/quote");
4
+ /** 解析单引号 */
5
+ const parseQuotes = (wikitext, config = Parser.getConfig(), accum = []) => {
6
+ const arr = wikitext.split(/('{2,})/u), { length } = arr;
7
+ if (length === 1) {
8
+ return wikitext;
9
+ }
10
+ let nBold = 0, nItalic = 0, firstSingle, firstMulti, firstSpace;
11
+ for (let i = 1; i < length; i += 2) {
12
+ const { length: len } = arr[i];
13
+ switch (len) {
14
+ case 2:
15
+ nItalic++;
16
+ break;
17
+ case 4:
18
+ arr[i - 1] += `'`;
19
+ arr[i] = `'''`;
20
+ // fall through
21
+ case 3:
22
+ nBold++;
23
+ if (firstSingle) {
24
+ break;
25
+ }
26
+ else if (arr[i - 1].endsWith(' ')) {
27
+ if (!firstMulti && !firstSpace) {
28
+ firstSpace = i;
29
+ }
30
+ }
31
+ else if (arr[i - 1].at(-2) === ' ') {
32
+ firstSingle = i;
33
+ }
34
+ else {
35
+ firstMulti ??= i;
36
+ }
37
+ break;
38
+ default:
39
+ arr[i - 1] += `'`.repeat(len - 5);
40
+ arr[i] = `'''''`;
41
+ nItalic++;
42
+ nBold++;
43
+ }
44
+ }
45
+ if (nItalic % 2 === 1 && nBold % 2 === 1) {
46
+ const i = firstSingle ?? firstMulti ?? firstSpace;
47
+ arr[i] = `''`;
48
+ arr[i - 1] += `'`;
49
+ }
50
+ for (let i = 1; i < length; i += 2) {
51
+ new QuoteToken(arr[i].length, config, accum);
52
+ arr[i] = `\0${accum.length - 1}q\x7F`;
53
+ }
54
+ return arr.join('');
55
+ };
56
+ Parser.parsers['parseQuotes'] = __filename;
57
+ module.exports = parseQuotes;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ const Parser = require("../index");
3
+ const simplePseudos = new Set([
4
+ 'root',
5
+ 'first-child',
6
+ 'first-of-type',
7
+ 'last-child',
8
+ 'last-of-type',
9
+ 'only-child',
10
+ 'only-of-type',
11
+ 'empty',
12
+ 'parent',
13
+ 'header',
14
+ 'hidden',
15
+ 'visible',
16
+ 'only-whitespace',
17
+ 'local-link',
18
+ 'read-only',
19
+ 'read-write',
20
+ 'invalid',
21
+ 'required',
22
+ 'optional',
23
+ ]);
24
+ const complexPseudos = [
25
+ 'is',
26
+ 'not',
27
+ 'nth-child',
28
+ 'nth-of-type',
29
+ 'nth-last-child',
30
+ 'nth-last-of-type',
31
+ 'contains',
32
+ 'has',
33
+ 'lang',
34
+ 'regex',
35
+ ];
36
+ const specialChars = [
37
+ ['[', '&lbrack;'],
38
+ [']', '&rbrack;'],
39
+ ['(', '&lpar;'],
40
+ [')', '&rpar;'],
41
+ ['"', '&quot;'],
42
+ [`'`, '&apos;'],
43
+ [':', '&colon;'],
44
+ ['\\', '&bsol;'],
45
+ ['&', '&amp;'],
46
+ ];
47
+ const pseudoRegex = new RegExp(`:(${complexPseudos.join('|')})$`, 'u'), regularRegex = /[[(,>+~]|\s+/u, attributeRegex = /^\s*(\w+)\s*(?:([~|^$*!]?=)\s*("[^"]*"|'[^']*'|[^\s[\]]+)(?:\s+(i))?\s*)?\]/u, functionRegex = /^(\s*"[^"]*"\s*|\s*'[^']*'\s*|[^()]*)\)/u, grouping = new Set([',', '>', '+', '~']), combinator = new Set(['>', '+', '~', '']);
48
+ /** 清理转义符号 */
49
+ const sanitize = (selector) => {
50
+ let s = selector;
51
+ for (const [c, escaped] of specialChars) {
52
+ s = s.replaceAll(`\\${c}`, escaped);
53
+ }
54
+ return s;
55
+ };
56
+ /** 还原转义符号 */
57
+ const desanitize = (selector) => {
58
+ let str = selector;
59
+ for (const [c, escaped] of specialChars) {
60
+ str = str.replaceAll(escaped, c);
61
+ }
62
+ return str.trim();
63
+ };
64
+ /**
65
+ * 去除首尾的引号
66
+ * @param val 属性值或伪选择器函数的参数
67
+ */
68
+ const deQuote = (val) => {
69
+ const quotes = /^(["']).*\1$/u.exec(val)?.[1];
70
+ return quotes ? val.slice(1, -1) : val.trim();
71
+ };
72
+ /**
73
+ * 解析简单伪选择器
74
+ * @param step 当前顶部
75
+ * @param str 不含属性和复杂伪选择器的语句
76
+ * @throws `SyntaxError` 非法的选择器
77
+ */
78
+ const pushSimple = (step, str) => {
79
+ const pieces = str.trim().split(':'),
80
+ // eslint-disable-next-line unicorn/explicit-length-check
81
+ i = pieces.slice(1).findIndex(pseudo => simplePseudos.has(pseudo)) + 1 || pieces.length;
82
+ if (pieces.slice(i).some(pseudo => !simplePseudos.has(pseudo))) {
83
+ throw new SyntaxError(`非法的选择器!\n${str}\n可能需要将':'转义为'\\:'。`);
84
+ }
85
+ step.push(desanitize(pieces.slice(0, i).join(':')), ...pieces.slice(i).map(piece => `:${piece}`));
86
+ };
87
+ /**
88
+ * 解析选择器
89
+ * @throws `SyntaxError` 非法的选择器
90
+ */
91
+ const parseSelector = (selector) => {
92
+ const s = selector.trim(), stack = [[[]]];
93
+ let sanitized = sanitize(s), regex = regularRegex, mt = regex.exec(sanitized), [condition] = stack, [step] = condition;
94
+ while (mt) {
95
+ let { 0: syntax, index } = mt;
96
+ if (syntax.trim() === '') {
97
+ index += syntax.length;
98
+ const char = sanitized[index];
99
+ syntax = grouping.has(char) ? char : '';
100
+ }
101
+ if (syntax === ',') { // 情形1:并列
102
+ pushSimple(step, sanitized.slice(0, index));
103
+ condition = [[]];
104
+ [step] = condition;
105
+ stack.push(condition);
106
+ }
107
+ else if (combinator.has(syntax)) { // 情形2:关系
108
+ pushSimple(step, sanitized.slice(0, index));
109
+ if (!step.some(Boolean)) {
110
+ throw new SyntaxError(`非法的选择器!\n${s}\n可能需要通用选择器'*'。`);
111
+ }
112
+ step.relation = syntax;
113
+ step = [];
114
+ condition.push(step);
115
+ }
116
+ else if (syntax === '[') { // 情形3:属性开启
117
+ pushSimple(step, sanitized.slice(0, index));
118
+ regex = attributeRegex;
119
+ }
120
+ else if (syntax.endsWith(']')) { // 情形4:属性闭合
121
+ mt[3] &&= desanitize(deQuote(mt[3]));
122
+ step.push(mt.slice(1));
123
+ regex = regularRegex;
124
+ }
125
+ else if (syntax === '(') { // 情形5:伪选择器开启
126
+ const pseudoExec = pseudoRegex.exec(sanitized.slice(0, index));
127
+ if (!pseudoExec) {
128
+ throw new SyntaxError(`非法的选择器!\n${desanitize(sanitized)}\n请检查伪选择器是否存在。`);
129
+ }
130
+ pushSimple(step, sanitized.slice(0, pseudoExec.index));
131
+ step.push(pseudoExec[1]); // 临时存放复杂伪选择器
132
+ regex = functionRegex;
133
+ }
134
+ else { // 情形6:伪选择器闭合
135
+ const pseudo = step.pop();
136
+ mt.push(pseudo);
137
+ mt[1] &&= deQuote(mt[1]);
138
+ step.push(mt.slice(1));
139
+ regex = regularRegex;
140
+ }
141
+ sanitized = sanitized.slice(index + syntax.length);
142
+ if (grouping.has(syntax)) {
143
+ sanitized = sanitized.trim();
144
+ }
145
+ mt = regex.exec(sanitized);
146
+ }
147
+ if (regex === regularRegex) {
148
+ pushSimple(step, sanitized);
149
+ const pseudos = new Set(stack.flat(2).filter(e => typeof e === 'string' && e.startsWith(':')));
150
+ if (pseudos.size > 0) {
151
+ Parser.warn('检测到伪选择器,请确认是否需要将":"转义成"\\:"。', pseudos);
152
+ }
153
+ return stack;
154
+ }
155
+ throw new SyntaxError(`非法的选择器!\n${s}\n检测到未闭合的'${regex === attributeRegex ? '[' : '('}'`);
156
+ };
157
+ Parser.parsers['parseSelector'] = __filename;
158
+ module.exports = parseSelector;