wikiparser-node 1.12.5-b → 1.12.5

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 (174) hide show
  1. package/config/.schema.json +203 -0
  2. package/config/default.json +30 -29
  3. package/config/enwiki.json +829 -15
  4. package/config/llwiki.json +56 -21
  5. package/config/moegirl.json +65 -21
  6. package/config/zhwiki.json +494 -28
  7. package/dist/addon/table.js +494 -0
  8. package/dist/addon/token.js +392 -0
  9. package/dist/addon/transclude.js +184 -0
  10. package/dist/base.d.ts +81 -0
  11. package/dist/base.js +40 -0
  12. package/dist/index.d.ts +33 -0
  13. package/dist/index.js +275 -0
  14. package/dist/internal.d.ts +47 -0
  15. package/dist/lib/element.d.ts +125 -0
  16. package/dist/lib/element.js +377 -0
  17. package/dist/lib/node.d.ts +173 -0
  18. package/dist/lib/node.js +478 -0
  19. package/dist/lib/range.d.ts +105 -0
  20. package/dist/lib/range.js +406 -0
  21. package/dist/lib/ranges.d.ts +28 -0
  22. package/dist/lib/ranges.js +126 -0
  23. package/dist/lib/rect.d.ts +18 -0
  24. package/dist/lib/rect.js +36 -0
  25. package/dist/lib/text.d.ts +58 -0
  26. package/dist/lib/text.js +414 -0
  27. package/dist/lib/title.d.ts +49 -0
  28. package/dist/lib/title.js +253 -0
  29. package/dist/mixin/attributesParent.d.ts +49 -0
  30. package/dist/mixin/attributesParent.js +80 -0
  31. package/dist/mixin/fixed.d.ts +5 -0
  32. package/dist/mixin/fixed.js +32 -0
  33. package/dist/mixin/flagsParent.d.ts +43 -0
  34. package/dist/mixin/flagsParent.js +64 -0
  35. package/dist/mixin/hidden.d.ts +7 -0
  36. package/dist/mixin/hidden.js +39 -0
  37. package/dist/mixin/magicLinkParent.d.ts +19 -0
  38. package/dist/mixin/magicLinkParent.js +43 -0
  39. package/dist/mixin/singleLine.d.ts +5 -0
  40. package/dist/mixin/singleLine.js +25 -0
  41. package/dist/mixin/sol.d.ts +6 -0
  42. package/dist/mixin/sol.js +45 -0
  43. package/dist/mixin/syntax.d.ts +8 -0
  44. package/dist/mixin/syntax.js +46 -0
  45. package/dist/parser/braces.js +152 -0
  46. package/dist/parser/commentAndExt.js +84 -0
  47. package/dist/parser/converter.js +41 -0
  48. package/dist/parser/externalLinks.js +39 -0
  49. package/dist/parser/hrAndDoubleUnderscore.js +44 -0
  50. package/dist/parser/html.js +40 -0
  51. package/dist/parser/links.js +103 -0
  52. package/dist/parser/list.js +116 -0
  53. package/dist/parser/magicLinks.js +55 -0
  54. package/dist/parser/quotes.js +69 -0
  55. package/dist/parser/redirect.js +28 -0
  56. package/dist/parser/selector.js +393 -0
  57. package/dist/parser/table.js +125 -0
  58. package/dist/src/arg.d.ts +49 -0
  59. package/dist/src/arg.js +220 -0
  60. package/dist/src/atom.d.ts +14 -0
  61. package/dist/src/atom.js +54 -0
  62. package/dist/src/attribute.d.ts +64 -0
  63. package/dist/src/attribute.js +482 -0
  64. package/dist/src/attributes.d.ts +103 -0
  65. package/dist/src/attributes.js +380 -0
  66. package/dist/src/converter.d.ts +28 -0
  67. package/dist/src/converter.js +153 -0
  68. package/dist/src/converterFlags.d.ts +80 -0
  69. package/dist/src/converterFlags.js +241 -0
  70. package/dist/src/converterRule.d.ts +71 -0
  71. package/dist/src/converterRule.js +218 -0
  72. package/dist/src/extLink.d.ts +36 -0
  73. package/dist/src/extLink.js +223 -0
  74. package/dist/src/gallery.d.ts +51 -0
  75. package/dist/src/gallery.js +166 -0
  76. package/dist/src/heading.d.ts +44 -0
  77. package/dist/src/heading.js +222 -0
  78. package/dist/src/hidden.d.ts +9 -0
  79. package/dist/src/hidden.js +82 -0
  80. package/dist/src/html.d.ts +61 -0
  81. package/dist/src/html.js +344 -0
  82. package/dist/src/imageParameter.d.ts +60 -0
  83. package/dist/src/imageParameter.js +262 -0
  84. package/dist/src/imagemap.d.ts +47 -0
  85. package/dist/src/imagemap.js +148 -0
  86. package/dist/src/imagemapLink.d.ts +35 -0
  87. package/dist/src/imagemapLink.js +99 -0
  88. package/dist/src/index.d.ts +136 -0
  89. package/dist/src/index.js +790 -0
  90. package/dist/src/link/base.d.ts +52 -0
  91. package/dist/src/link/base.js +258 -0
  92. package/dist/src/link/category.d.ts +22 -0
  93. package/dist/src/link/category.js +36 -0
  94. package/dist/src/link/file.d.ts +102 -0
  95. package/dist/src/link/file.js +345 -0
  96. package/dist/src/link/galleryImage.d.ts +29 -0
  97. package/dist/src/link/galleryImage.js +133 -0
  98. package/dist/src/link/index.d.ts +39 -0
  99. package/dist/src/link/index.js +100 -0
  100. package/dist/src/link/redirectTarget.d.ts +27 -0
  101. package/dist/src/link/redirectTarget.js +71 -0
  102. package/dist/src/magicLink.d.ts +57 -0
  103. package/dist/src/magicLink.js +261 -0
  104. package/dist/src/nested.d.ts +40 -0
  105. package/dist/src/nested.js +108 -0
  106. package/dist/src/nowiki/base.d.ts +28 -0
  107. package/dist/src/nowiki/base.js +90 -0
  108. package/dist/src/nowiki/comment.d.ts +14 -0
  109. package/dist/src/nowiki/comment.js +123 -0
  110. package/dist/src/nowiki/dd.d.ts +8 -0
  111. package/dist/src/nowiki/dd.js +74 -0
  112. package/dist/src/nowiki/doubleUnderscore.d.ts +15 -0
  113. package/dist/src/nowiki/doubleUnderscore.js +101 -0
  114. package/dist/src/nowiki/hr.d.ts +5 -0
  115. package/dist/src/nowiki/hr.js +72 -0
  116. package/dist/src/nowiki/index.d.ts +14 -0
  117. package/dist/src/nowiki/index.js +30 -0
  118. package/dist/src/nowiki/list.d.ts +5 -0
  119. package/dist/src/nowiki/list.js +67 -0
  120. package/dist/src/nowiki/listBase.d.ts +23 -0
  121. package/dist/src/nowiki/listBase.js +100 -0
  122. package/dist/src/nowiki/noinclude.d.ts +6 -0
  123. package/dist/src/nowiki/noinclude.js +77 -0
  124. package/dist/src/nowiki/quote.d.ts +14 -0
  125. package/dist/src/nowiki/quote.js +149 -0
  126. package/dist/src/onlyinclude.d.ts +13 -0
  127. package/dist/src/onlyinclude.js +60 -0
  128. package/dist/src/paramTag/index.d.ts +28 -0
  129. package/dist/src/paramTag/index.js +80 -0
  130. package/dist/src/paramTag/inputbox.d.ts +8 -0
  131. package/dist/src/paramTag/inputbox.js +24 -0
  132. package/dist/src/parameter.d.ts +60 -0
  133. package/dist/src/parameter.js +267 -0
  134. package/dist/src/pre.d.ts +28 -0
  135. package/dist/src/pre.js +62 -0
  136. package/dist/src/redirect.d.ts +30 -0
  137. package/dist/src/redirect.js +128 -0
  138. package/dist/src/syntax.d.ts +15 -0
  139. package/dist/src/syntax.js +87 -0
  140. package/dist/src/table/base.d.ts +28 -0
  141. package/dist/src/table/base.js +81 -0
  142. package/dist/src/table/index.d.ts +230 -0
  143. package/dist/src/table/index.js +506 -0
  144. package/dist/src/table/td.d.ts +72 -0
  145. package/dist/src/table/td.js +375 -0
  146. package/dist/src/table/tr.d.ts +30 -0
  147. package/dist/src/table/tr.js +61 -0
  148. package/dist/src/table/trBase.d.ts +49 -0
  149. package/dist/src/table/trBase.js +165 -0
  150. package/dist/src/tagPair/ext.d.ts +29 -0
  151. package/dist/src/tagPair/ext.js +229 -0
  152. package/dist/src/tagPair/include.d.ts +33 -0
  153. package/dist/src/tagPair/include.js +132 -0
  154. package/dist/src/tagPair/index.d.ts +23 -0
  155. package/dist/src/tagPair/index.js +130 -0
  156. package/dist/src/transclude.d.ts +159 -0
  157. package/dist/src/transclude.js +598 -0
  158. package/dist/util/constants.js +26 -0
  159. package/dist/util/debug.js +95 -0
  160. package/dist/util/diff.js +83 -0
  161. package/dist/util/html.js +146 -0
  162. package/dist/util/lint.js +32 -0
  163. package/dist/util/string.js +107 -0
  164. package/errors/README +3 -0
  165. package/package.json +21 -28
  166. package/printed/README +3 -0
  167. package/bundle/bundle.min.js +0 -37
  168. package/extensions/dist/base.js +0 -163
  169. package/extensions/dist/codejar.js +0 -52
  170. package/extensions/dist/editor.js +0 -159
  171. package/extensions/dist/highlight.js +0 -30
  172. package/extensions/dist/lint.js +0 -72
  173. package/extensions/editor.css +0 -59
  174. package/extensions/ui.css +0 -162
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseList = void 0;
4
+ const html_1 = require("../util/html");
5
+ const list_1 = require("../src/nowiki/list");
6
+ const dd_1 = require("../src/nowiki/dd");
7
+ /* NOT FOR BROWSER */
8
+ const constants_1 = require("../util/constants");
9
+ /* NOT FOR BROWSER END */
10
+ /**
11
+ * 解析列表
12
+ * @param wikitext
13
+ * @param state
14
+ * @param state.lastPrefix 上一个列表的前缀
15
+ * @param config
16
+ * @param accum
17
+ */
18
+ const parseList = (wikitext, state, config, accum) => {
19
+ const mt = /^((?:\0\d+[cno]\x7F)*)([;:*#]+\s*)/u.exec(wikitext);
20
+ if (!mt) {
21
+ state.lastPrefix = '';
22
+ return wikitext;
23
+ }
24
+ const [total, comment, prefix] = mt, prefix2 = prefix.replace(/;/gu, ':'), commonPrefixLength = (0, html_1.getCommon)(prefix2, state.lastPrefix), parts = (commonPrefixLength > 1 ? prefix.slice(commonPrefixLength - 1) : prefix).split(/(?=;)/u), isDt = parts[0].startsWith(';');
25
+ let dt = parts.length - (isDt ? 0 : 1);
26
+ if (commonPrefixLength > 1) {
27
+ const commonPrefix = prefix.slice(0, commonPrefixLength - 1);
28
+ if (isDt) {
29
+ parts.unshift(commonPrefix);
30
+ }
31
+ else {
32
+ parts[0] = commonPrefix + parts[0];
33
+ }
34
+ }
35
+ state.lastPrefix = prefix2;
36
+ let text = comment + parts.map((_, i) => `\0${accum.length + i}d\x7F`).join('') + wikitext.slice(total.length);
37
+ for (const part of parts) {
38
+ // @ts-expect-error abstract class
39
+ new list_1.ListToken(part, config, accum);
40
+ }
41
+ if (!dt) {
42
+ return text;
43
+ }
44
+ const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
45
+ let regex = fullRegex, ex = regex.exec(text), lt = 0, lb = false, li = false, lc = 0;
46
+ /**
47
+ * 创建`DdToken`
48
+ * @param syntax `:`
49
+ * @param index 起点
50
+ */
51
+ const dd = (syntax, index) => {
52
+ // @ts-expect-error abstract class
53
+ new dd_1.DdToken(syntax, config, accum);
54
+ return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + syntax.length)}`;
55
+ };
56
+ /**
57
+ * 更新 `lt`
58
+ * @param closing 是否是闭合标签
59
+ */
60
+ const update = (closing) => {
61
+ if (!closing) {
62
+ lt++;
63
+ }
64
+ else if (lt) {
65
+ lt--;
66
+ }
67
+ };
68
+ while (ex && dt) {
69
+ const { 0: syntax, index } = ex;
70
+ if (syntax === '-{') {
71
+ if (!lc) {
72
+ const { lastIndex } = regex;
73
+ regex = /-\{|\}-/gu;
74
+ regex.lastIndex = lastIndex;
75
+ }
76
+ lc++;
77
+ }
78
+ else if (syntax === '}-') {
79
+ lc--;
80
+ if (!lc) {
81
+ const { lastIndex } = regex;
82
+ regex = fullRegex;
83
+ regex.lastIndex = lastIndex;
84
+ }
85
+ }
86
+ else if (syntax.endsWith('x\x7F')) {
87
+ const { name, closing, selfClosing } = accum[Number(syntax.slice(1, -2))];
88
+ if (!selfClosing || normalTags.includes(name)) {
89
+ update(closing);
90
+ }
91
+ }
92
+ else if (syntax.endsWith('q\x7F')) {
93
+ const { bold, italic } = accum[Number(syntax.slice(1, -2))];
94
+ if (bold) {
95
+ update(lb);
96
+ lb = !lb;
97
+ }
98
+ if (italic) {
99
+ update(li);
100
+ li = !li;
101
+ }
102
+ }
103
+ else if (lt === 0) { // syntax === ':'
104
+ if (syntax.length >= dt) {
105
+ return dd(syntax.slice(0, dt), index);
106
+ }
107
+ dt -= syntax.length;
108
+ regex.lastIndex = index + 4 + String(accum.length).length;
109
+ text = dd(syntax, index);
110
+ }
111
+ ex = regex.exec(text);
112
+ }
113
+ return text;
114
+ };
115
+ exports.parseList = parseList;
116
+ constants_1.parsers['parseList'] = __filename;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMagicLinks = void 0;
4
+ const string_1 = require("../util/string");
5
+ const magicLink_1 = require("../src/magicLink");
6
+ /* NOT FOR BROWSER */
7
+ const constants_1 = require("../util/constants");
8
+ /* NOT FOR BROWSER END */
9
+ const space = String.raw `[\p{Zs}\t]| |&#0*160;|&#x0*a0;`, sp = `(?:${space})+`, spdash = `(?:${space}|-)`, magicLinkPattern = String.raw `(?:RFC|PMID)${sp}\d+\b|ISBN${sp}(?:97[89]${spdash}?)?(?:\d${spdash}?){9}[\dx]\b`;
10
+ /**
11
+ * 解析自由外链
12
+ * @param wikitext
13
+ * @param config
14
+ * @param accum
15
+ */
16
+ const parseMagicLinks = (wikitext, config, accum) => {
17
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
18
+ /(^|[^\p{L}\d_])(?:(?:ftp:\/\/|http:\/\/)((?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])[^[\]<>"\0\t\n\p{Zs}]*)|(?:rfc|pmid)[\p{Zs}\t]+\d+\b|isbn[\p{Zs}\t]+(?:97[89][\p{Zs}\t-]?)?(?:\d[\p{Zs}\t-]?){9}[\dx]\b)/giu;
19
+ const regex = new RegExp(String.raw `(^|[^\p{L}\d_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
20
+ return wikitext.replace(regex, (m, lead, p1) => {
21
+ let url = lead ? m.slice(lead.length) : m;
22
+ if (p1) {
23
+ let trail = '';
24
+ const m2 = /&(?:lt|gt|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
25
+ if (m2) {
26
+ trail = url.slice(m2.index);
27
+ url = url.slice(0, m2.index);
28
+ }
29
+ const sep = url.includes('(') ? /[^,;\\.:!?][,;\\.:!?]+$/u : /[^,;\\.:!?)][,;\\.:!?)]+$/u, sepChars = sep.exec(url);
30
+ if (sepChars) {
31
+ let correction = 1;
32
+ if (sepChars[0][1] === ';'
33
+ && /&(?:[a-z]+|#x[\da-f]+|#\d+)$/iu.test(url.slice(0, sepChars.index))) {
34
+ correction = 2;
35
+ }
36
+ trail = url.slice(sepChars.index + correction) + trail;
37
+ url = url.slice(0, sepChars.index + correction);
38
+ }
39
+ if (trail.length >= p1.length) {
40
+ return m;
41
+ }
42
+ // @ts-expect-error abstract class
43
+ new magicLink_1.MagicLinkToken(url, undefined, config, accum);
44
+ return `${lead}\0${accum.length - 1}w\x7F${trail}`;
45
+ }
46
+ else if (!/^(?:RFC|PMID|ISBN)/u.test(url)) {
47
+ return m;
48
+ }
49
+ // @ts-expect-error abstract class
50
+ new magicLink_1.MagicLinkToken(url, 'magic-link', config, accum);
51
+ return `${lead}\0${accum.length - 1}i\x7F`;
52
+ });
53
+ };
54
+ exports.parseMagicLinks = parseMagicLinks;
55
+ constants_1.parsers['parseMagicLinks'] = __filename;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseQuotes = void 0;
4
+ const quote_1 = require("../src/nowiki/quote");
5
+ /* NOT FOR BROWSER */
6
+ const constants_1 = require("../util/constants");
7
+ /* NOT FOR BROWSER END */
8
+ /**
9
+ * 解析单引号
10
+ * @param wikitext
11
+ * @param config
12
+ * @param accum
13
+ */
14
+ const parseQuotes = (wikitext, config, accum) => {
15
+ const arr = wikitext.split(/('{2,})/u), { length } = arr;
16
+ if (length === 1) {
17
+ return wikitext;
18
+ }
19
+ let nBold = 0, nItalic = 0, firstSingle, firstMulti, firstSpace;
20
+ for (let i = 1; i < length; i += 2) {
21
+ const len = arr[i].length;
22
+ switch (len) {
23
+ case 2:
24
+ nItalic++;
25
+ break;
26
+ case 4:
27
+ arr[i - 1] += `'`;
28
+ arr[i] = `'''`;
29
+ // fall through
30
+ case 3:
31
+ nBold++;
32
+ if (firstSingle !== undefined) {
33
+ break;
34
+ }
35
+ else if (arr[i - 1].endsWith(' ')) {
36
+ if (firstMulti === undefined && firstSpace === undefined) {
37
+ firstSpace = i;
38
+ }
39
+ }
40
+ else if (arr[i - 1].slice(-2, -1) === ' ') {
41
+ firstSingle = i;
42
+ }
43
+ else {
44
+ firstMulti ??= i;
45
+ }
46
+ break;
47
+ default:
48
+ arr[i - 1] += `'`.repeat(len - 5);
49
+ arr[i] = `'''''`;
50
+ nItalic++;
51
+ nBold++;
52
+ }
53
+ }
54
+ if (nItalic % 2 === 1 && nBold % 2 === 1) {
55
+ const i = firstSingle ?? firstMulti ?? firstSpace;
56
+ if (i !== undefined) {
57
+ arr[i] = `''`;
58
+ arr[i - 1] += `'`;
59
+ }
60
+ }
61
+ for (let i = 1; i < length; i += 2) {
62
+ // @ts-expect-error abstract class
63
+ new quote_1.QuoteToken(arr[i], config, accum);
64
+ arr[i] = `\0${accum.length - 1}q\x7F`;
65
+ }
66
+ return arr.join('');
67
+ };
68
+ exports.parseQuotes = parseQuotes;
69
+ constants_1.parsers['parseQuotes'] = __filename;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRedirect = void 0;
4
+ const index_1 = require("../index");
5
+ const redirect_1 = require("../src/redirect");
6
+ /* NOT FOR BROWSER */
7
+ const constants_1 = require("../util/constants");
8
+ /* NOT FOR BROWSER END */
9
+ /**
10
+ * 解析重定向
11
+ * @param text
12
+ * @param config
13
+ * @param accum
14
+ */
15
+ const parseRedirect = (text, config, accum) => {
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
17
+ /^(\s*)((?:#redirect|#重定向)\s*(?::\s*)?)\[\[([^\n|\]]+)(\|.*?)?\]\](\s*)/iu;
18
+ const re = new RegExp(String.raw `^(\s*)((?:${config.redirection.join('|')})\s*(?::\s*)?)\[\[([^\n|\]]+)(\|.*?)?\]\](\s*)`, 'iu'), mt = re.exec(text);
19
+ if (mt && index_1.default.normalizeTitle(mt[3], 0, false, config, true, true).valid) {
20
+ text = `\0${accum.length}o\x7F${text.slice(mt[0].length)}`;
21
+ // @ts-expect-error abstract class
22
+ new redirect_1.RedirectToken(...mt.slice(1), config, accum);
23
+ return text;
24
+ }
25
+ return false;
26
+ };
27
+ exports.parseRedirect = parseRedirect;
28
+ constants_1.parsers['parseRedirect'] = __filename;
@@ -0,0 +1,393 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkToken = void 0;
4
+ const constants_1 = require("../util/constants");
5
+ const ranges_1 = require("../lib/ranges");
6
+ const title_1 = require("../lib/title");
7
+ const simplePseudos = new Set([
8
+ 'root',
9
+ 'first-child',
10
+ 'first-of-type',
11
+ 'last-child',
12
+ 'last-of-type',
13
+ 'only-child',
14
+ 'only-of-type',
15
+ 'empty',
16
+ 'parent',
17
+ 'header',
18
+ 'hidden',
19
+ 'visible',
20
+ 'only-whitespace',
21
+ 'any-link',
22
+ 'local-link',
23
+ 'invalid',
24
+ 'required',
25
+ 'optional',
26
+ ]), complexPseudos = new Set([
27
+ 'is',
28
+ 'not',
29
+ 'nth-child',
30
+ 'nth-of-type',
31
+ 'nth-last-child',
32
+ 'nth-last-of-type',
33
+ 'contains',
34
+ 'has',
35
+ 'lang',
36
+ 'regex',
37
+ ]), specialChars = [
38
+ ['[', '&lbrack;'],
39
+ [']', '&rbrack;'],
40
+ ['(', '&lpar;'],
41
+ [')', '&rpar;'],
42
+ ['"', '&quot;'],
43
+ [`'`, '&apos;'],
44
+ [':', '&colon;'],
45
+ ['\\', '&bsol;'],
46
+ ['&', '&amp;'],
47
+ ], 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(['>', '+', '~', '']), primitives = new Set(['string', 'number', 'boolean', 'undefined']);
48
+ /**
49
+ * optionally convert to lower cases
50
+ * @param val 属性值
51
+ * @param i 是否对大小写不敏感
52
+ */
53
+ const toCase = (val, i) => i ? val.toLowerCase() : val;
54
+ /**
55
+ * 检查某个下标是否符合表达式
56
+ * @param str 表达式
57
+ * @param i 待检查的下标
58
+ */
59
+ const nth = (str, i) => new ranges_1.Ranges(str).applyTo(i + 1).includes(i);
60
+ /**
61
+ * 是否受保护。保护条件来自Token,这里仅提前用于:required和:optional伪选择器。
62
+ * @param token 节点
63
+ */
64
+ const isProtected = (token) => {
65
+ const { parentNode } = token;
66
+ if (!parentNode) {
67
+ return undefined;
68
+ }
69
+ const { childNodes, fixed } = parentNode;
70
+ return fixed
71
+ || parentNode.getAttribute('protectedChildren').applyTo(childNodes).includes(childNodes.indexOf(token));
72
+ };
73
+ /**
74
+ * 获取属性
75
+ * @param token 节点
76
+ * @param key 属性键
77
+ */
78
+ const getAttr = (token, key) => {
79
+ if (typeof token.getAttr === 'function') {
80
+ const attr = token.getAttr(key);
81
+ if (attr !== undefined) {
82
+ return attr;
83
+ }
84
+ }
85
+ const val = token[key];
86
+ return val instanceof RegExp ? val.source : val;
87
+ };
88
+ /**
89
+ * 检查是否符合解析后的选择器,不含节点关系
90
+ * @param token 节点
91
+ * @param step 解析后的选择器
92
+ * @throws `SyntaxError` 错误的正则伪选择器
93
+ * @throws `SyntaxError` 未定义的伪选择器
94
+ */
95
+ const matches = (token, step) => {
96
+ const { parentNode, type, name, childNodes, link } = token, children = parentNode?.children, childrenOfType = children?.filter(({ type: t }) => t === type), siblingsCount = children?.length ?? 1, siblingsCountOfType = childrenOfType?.length ?? 1, index = (children?.indexOf(token) ?? 0) + 1, indexOfType = (childrenOfType?.indexOf(token) ?? 0) + 1, lastIndex = siblingsCount - index + 1, lastIndexOfType = siblingsCountOfType - indexOfType + 1;
97
+ return step.every(selector => {
98
+ if (typeof selector === 'string') {
99
+ switch (selector) { // 情形1:简单伪选择器、type和name
100
+ case '*':
101
+ return true;
102
+ case ':root':
103
+ return !parentNode;
104
+ case ':first-child':
105
+ return index === 1;
106
+ case ':first-of-type':
107
+ return indexOfType === 1;
108
+ case ':last-child':
109
+ return lastIndex === 1;
110
+ case ':last-of-type':
111
+ return lastIndexOfType === 1;
112
+ case ':only-child':
113
+ return siblingsCount === 1;
114
+ case ':only-of-type':
115
+ return siblingsCountOfType === 1;
116
+ case ':empty':
117
+ return !childNodes.some(({ type: t, data }) => t !== 'text' || data);
118
+ case ':parent':
119
+ return childNodes.some(({ type: t, data }) => t !== 'text' || data);
120
+ case ':header':
121
+ return type === 'heading';
122
+ case ':hidden':
123
+ return token.text() === '';
124
+ case ':visible':
125
+ return token.text() !== '';
126
+ case ':only-whitespace':
127
+ return token.text().trim() === '';
128
+ case ':any-link':
129
+ return type === 'link'
130
+ || type === 'redirect-target'
131
+ || type === 'free-ext-link'
132
+ || type === 'magic-link'
133
+ || type === 'ext-link'
134
+ || (type === 'file' || type === 'gallery-image') && link;
135
+ case ':local-link':
136
+ return (type === 'link' || type === 'file' || type === 'gallery-image')
137
+ && link instanceof title_1.Title
138
+ && link.title === '';
139
+ case ':invalid':
140
+ return type === 'table-inter' || type === 'image-parameter' && name === 'invalid';
141
+ case ':required':
142
+ return isProtected(token) === true;
143
+ case ':optional':
144
+ return isProtected(token) === false;
145
+ default: {
146
+ const [t, n] = selector.split('#');
147
+ return (!t || t === type) && (!n || n === name);
148
+ }
149
+ }
150
+ }
151
+ else if (selector.length === 4) { // 情形2:属性选择器
152
+ const [key, equal, val = '', i] = selector, isAttr = typeof token.hasAttr === 'function' && typeof token.getAttr === 'function';
153
+ if (!(key in token) && (!isAttr || !token.hasAttr(key))) {
154
+ return equal === '!=';
155
+ }
156
+ const v = toCase(val, i), thisVal = getAttr(token, key);
157
+ if (!equal) {
158
+ return thisVal !== undefined && thisVal !== false;
159
+ }
160
+ if (equal === '~=') {
161
+ const thisVals = typeof thisVal === 'string' ? thisVal.split(/\s/u) : thisVal;
162
+ return Boolean(thisVals?.[Symbol.iterator])
163
+ && [...thisVals].some(w => typeof w === 'string' && toCase(w, i) === v);
164
+ }
165
+ else if (!primitives.has(typeof thisVal) && !(thisVal instanceof title_1.Title)) {
166
+ throw new RangeError(`The complex attribute ${key} cannot be used in a selector!`);
167
+ }
168
+ const stringVal = toCase(String(thisVal), i);
169
+ switch (equal) {
170
+ case '|=':
171
+ return stringVal === v || stringVal.startsWith(`${v}-`);
172
+ case '^=':
173
+ return stringVal.startsWith(v);
174
+ case '$=':
175
+ return stringVal.endsWith(v);
176
+ case '*=':
177
+ return stringVal.includes(v);
178
+ case '!=':
179
+ return stringVal !== v;
180
+ default: // `=`
181
+ return stringVal === v;
182
+ }
183
+ }
184
+ const [s, pseudo] = selector; // 情形3:复杂伪选择器
185
+ switch (pseudo) {
186
+ case 'is':
187
+ return token.matches(s);
188
+ case 'not':
189
+ return !token.matches(s);
190
+ case 'nth-child':
191
+ return nth(s, index);
192
+ case 'nth-of-type':
193
+ return nth(s, indexOfType);
194
+ case 'nth-last-child':
195
+ return nth(s, lastIndex);
196
+ case 'nth-last-of-type':
197
+ return nth(s, lastIndexOfType);
198
+ case 'contains':
199
+ return token.text().includes(s);
200
+ case 'has':
201
+ return Boolean(token.querySelector(s));
202
+ case 'lang': {
203
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
204
+ /^zh(?:-|$)/iu;
205
+ const regex = new RegExp(`^${s}(?:-|$)`, 'iu');
206
+ let node = token;
207
+ for (; node; node = node.parentNode) {
208
+ const lang = node.attributes?.['lang'];
209
+ if (lang !== undefined) {
210
+ return typeof lang === 'string' && regex.test(lang);
211
+ }
212
+ }
213
+ return false;
214
+ }
215
+ case 'regex': {
216
+ const mt = /^([^,]+),\s*\/(.+)\/([a-z]*)$/u.exec(s);
217
+ if (!mt) {
218
+ throw new SyntaxError(`Wrong usage of the regex pseudo-selector. Use ":regex('attr, /re/i')" format.`);
219
+ }
220
+ try {
221
+ return new RegExp(mt[2], mt[3]).test(String(getAttr(token, mt[1].trim())));
222
+ }
223
+ catch {
224
+ throw new SyntaxError(`Invalid regular expression: /${mt[2]}/${mt[3]}`);
225
+ }
226
+ }
227
+ default:
228
+ throw new SyntaxError(`Undefined pseudo-selector: ${pseudo}`);
229
+ }
230
+ });
231
+ };
232
+ /**
233
+ * 检查是否符合解析后的选择器
234
+ * @param token 节点
235
+ * @param copy 解析后的选择器
236
+ */
237
+ const matchesArray = (token, copy) => {
238
+ const condition = [...copy];
239
+ if (matches(token, condition.pop())) {
240
+ const { parentNode, previousElementSibling } = token;
241
+ switch (condition.at(-1)?.relation) {
242
+ case undefined:
243
+ return true;
244
+ case '>':
245
+ return Boolean(parentNode && matchesArray(parentNode, condition));
246
+ case '+':
247
+ return Boolean(previousElementSibling && matchesArray(previousElementSibling, condition));
248
+ case '~': {
249
+ if (!parentNode) {
250
+ return false;
251
+ }
252
+ const { children } = parentNode;
253
+ return children.slice(0, children.indexOf(token)).some(child => matchesArray(child, condition));
254
+ }
255
+ default: // ' '
256
+ return token.getAncestors().some(ancestor => matchesArray(ancestor, condition));
257
+ }
258
+ }
259
+ return false;
260
+ };
261
+ /**
262
+ * 还原转义符号
263
+ * @param selector
264
+ */
265
+ const desanitize = (selector) => {
266
+ for (const [c, entity] of specialChars) {
267
+ selector = selector.replaceAll(entity, c);
268
+ }
269
+ return selector.trim();
270
+ };
271
+ /**
272
+ * 去除首尾的引号
273
+ * @param val 属性值或伪选择器函数的参数
274
+ */
275
+ const deQuote = (val) => /^(["']).*\1$/u.test(val) ? val.slice(1, -1) : val.trim();
276
+ /**
277
+ * 检查节点是否符合选择器
278
+ * @param selector
279
+ */
280
+ const checkToken = (selector) => (token) => {
281
+ let sanitized = selector.trim();
282
+ for (const [c, entity] of specialChars) {
283
+ sanitized = sanitized.replaceAll(`\\${c}`, entity);
284
+ }
285
+ const stack = [[[]]];
286
+ let regex = regularRegex, mt = regex.exec(sanitized), [condition] = stack, [step] = condition;
287
+ /**
288
+ * 解析简单伪选择器
289
+ * @param index 伪选择器的终点位置
290
+ * @throws `SyntaxError` 选择器排序
291
+ * @throws `SyntaxError` 非法的选择器
292
+ */
293
+ const pushSimple = (index) => {
294
+ const str = sanitized.slice(0, index).trim();
295
+ if (!str) {
296
+ return;
297
+ }
298
+ const pieces = str.split(/(?=[:#])/u);
299
+ for (let i = 0; i < pieces.length; i++) {
300
+ const piece = pieces[i];
301
+ if (!/^[:#]/u.test(piece)) {
302
+ if (step.length > 0) {
303
+ throw new SyntaxError(`Invalid selector!\n${selector}\nType selectors must come first.`);
304
+ }
305
+ else {
306
+ step.push(piece);
307
+ }
308
+ }
309
+ else if (piece.startsWith(':')) {
310
+ if (simplePseudos.has(piece.slice(1))) {
311
+ step.push(piece);
312
+ }
313
+ else if (pieces[i - 1]?.startsWith('#')) {
314
+ pieces[i - 1] += piece;
315
+ pieces.splice(i, 1);
316
+ i--;
317
+ }
318
+ else {
319
+ throw new SyntaxError(`Undefined pseudo selector!\n${desanitize(piece)}`);
320
+ }
321
+ }
322
+ }
323
+ step.push(...pieces.filter(piece => piece.startsWith('#')).map(desanitize));
324
+ };
325
+ /**
326
+ * 检查是否需要通用选择器
327
+ * @throws `SyntaxError` 非法的选择器
328
+ */
329
+ const needUniversal = () => {
330
+ if (step.length === 0) {
331
+ throw new SyntaxError(`Invalid selector!\n${selector}\nYou may need the universal selector '*'.`);
332
+ }
333
+ };
334
+ while (mt) {
335
+ let { 0: syntax, index } = mt;
336
+ if (syntax.trim() === '') {
337
+ index += syntax.length;
338
+ const char = sanitized[index];
339
+ syntax = grouping.has(char) ? char : '';
340
+ }
341
+ if (syntax === ',') { // 情形1:并列
342
+ pushSimple(index);
343
+ needUniversal();
344
+ condition = [[]];
345
+ [step] = condition;
346
+ stack.push(condition);
347
+ }
348
+ else if (combinator.has(syntax)) { // 情形2:关系
349
+ pushSimple(index);
350
+ needUniversal();
351
+ step.relation = syntax;
352
+ step = [];
353
+ condition.push(step);
354
+ }
355
+ else if (syntax === '[') { // 情形3:属性开启
356
+ pushSimple(index);
357
+ regex = attributeRegex;
358
+ }
359
+ else if (syntax.endsWith(']')) { // 情形4:属性闭合
360
+ mt[3] &&= desanitize(deQuote(mt[3]));
361
+ step.push(mt.slice(1));
362
+ regex = regularRegex;
363
+ }
364
+ else if (syntax === '(') { // 情形5:伪选择器开启
365
+ const i = sanitized.lastIndexOf(':', index), pseudo = sanitized.slice(i + 1, index);
366
+ if (i === -1 || !complexPseudos.has(pseudo)) {
367
+ throw new SyntaxError(`Undefined pseudo selector!\n${desanitize(sanitized)}`);
368
+ }
369
+ pushSimple(i);
370
+ step.push(pseudo); // 临时存放复杂伪选择器
371
+ regex = functionRegex;
372
+ }
373
+ else { // 情形6:伪选择器闭合
374
+ mt.push(step.pop());
375
+ mt[1] &&= deQuote(mt[1]);
376
+ step.push(mt.slice(1));
377
+ regex = regularRegex;
378
+ }
379
+ sanitized = sanitized.slice(index + syntax.length);
380
+ if (grouping.has(syntax)) {
381
+ sanitized = sanitized.trim();
382
+ }
383
+ mt = regex.exec(sanitized);
384
+ }
385
+ if (regex === regularRegex) {
386
+ pushSimple();
387
+ needUniversal();
388
+ return stack.some(copy => matchesArray(token, copy));
389
+ }
390
+ throw new SyntaxError(`Unclosed '${regex === attributeRegex ? '[' : '('}' in the selector!\n${desanitize(sanitized)}`);
391
+ };
392
+ exports.checkToken = checkToken;
393
+ constants_1.parsers['parseSelector'] = __filename;