wikiparser-node 1.18.2 → 1.18.4

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 (76) hide show
  1. package/README.md +6 -1
  2. package/bundle/bundle-es7.min.js +29 -28
  3. package/bundle/bundle-lsp.min.js +31 -30
  4. package/bundle/bundle.min.js +30 -29
  5. package/config/minimum.json +7 -0
  6. package/dist/addon/token.js +37 -28
  7. package/dist/addon/transclude.js +1 -3
  8. package/dist/base.d.mts +4 -0
  9. package/dist/base.d.ts +4 -0
  10. package/dist/base.js +1 -0
  11. package/dist/base.mjs +2 -1
  12. package/dist/bin/config.js +3 -2
  13. package/dist/index.d.ts +14 -1
  14. package/dist/index.js +72 -72
  15. package/dist/lib/element.d.ts +6 -0
  16. package/dist/lib/element.js +543 -466
  17. package/dist/lib/lsp.d.ts +1 -0
  18. package/dist/lib/lsp.js +20 -15
  19. package/dist/lib/redirectMap.d.ts +7 -0
  20. package/dist/lib/redirectMap.js +31 -0
  21. package/dist/lib/text.d.ts +2 -2
  22. package/dist/lib/text.js +385 -325
  23. package/dist/lib/title.d.ts +23 -4
  24. package/dist/lib/title.js +17 -5
  25. package/dist/mixin/noEscape.d.ts +4 -0
  26. package/dist/mixin/noEscape.js +22 -0
  27. package/dist/mixin/readOnly.d.ts +4 -0
  28. package/dist/mixin/readOnly.js +26 -0
  29. package/dist/parser/braces.js +79 -37
  30. package/dist/parser/commentAndExt.js +5 -16
  31. package/dist/parser/links.js +1 -1
  32. package/dist/parser/quotes.js +1 -1
  33. package/dist/parser/redirect.js +1 -3
  34. package/dist/src/arg.js +253 -202
  35. package/dist/src/attribute.d.ts +0 -5
  36. package/dist/src/attribute.js +4 -8
  37. package/dist/src/converter.js +213 -162
  38. package/dist/src/gallery.js +1 -2
  39. package/dist/src/heading.js +5 -6
  40. package/dist/src/imageParameter.js +16 -16
  41. package/dist/src/imagemap.js +3 -2
  42. package/dist/src/index.d.ts +1 -1
  43. package/dist/src/index.js +722 -694
  44. package/dist/src/link/base.js +292 -241
  45. package/dist/src/link/file.js +13 -17
  46. package/dist/src/link/galleryImage.js +1 -1
  47. package/dist/src/link/redirectTarget.js +1 -2
  48. package/dist/src/magicLink.d.ts +0 -6
  49. package/dist/src/magicLink.js +5 -15
  50. package/dist/src/nested.js +7 -7
  51. package/dist/src/nowiki/base.js +2 -1
  52. package/dist/src/nowiki/index.js +4 -3
  53. package/dist/src/onlyinclude.js +95 -44
  54. package/dist/src/parameter.d.ts +0 -6
  55. package/dist/src/parameter.js +1 -13
  56. package/dist/src/redirect.js +6 -6
  57. package/dist/src/syntax.d.ts +4 -1
  58. package/dist/src/syntax.js +4 -1
  59. package/dist/src/table/base.d.ts +0 -5
  60. package/dist/src/table/base.js +2 -9
  61. package/dist/src/table/index.d.ts +1 -0
  62. package/dist/src/table/index.js +7 -4
  63. package/dist/src/table/td.d.ts +1 -0
  64. package/dist/src/table/td.js +2 -3
  65. package/dist/src/table/trBase.js +31 -14
  66. package/dist/src/tagPair/index.js +2 -1
  67. package/dist/src/transclude.js +713 -657
  68. package/dist/util/debug.js +10 -3
  69. package/dist/util/diff.js +1 -1
  70. package/dist/util/string.js +4 -5
  71. package/extensions/dist/base.js +8 -6
  72. package/extensions/dist/lint.js +1 -1
  73. package/extensions/es7/base.js +8 -6
  74. package/extensions/es7/lint.js +1 -1
  75. package/extensions/ui.css +1 -1
  76. package/package.json +3 -3
@@ -1,4 +1,10 @@
1
1
  import type { Config } from '../base';
2
+ export interface TitleOptions {
3
+ temporary?: boolean | undefined;
4
+ decode?: boolean | undefined;
5
+ selfLink?: boolean | undefined;
6
+ halfParsed?: boolean | undefined;
7
+ }
2
8
  /**
3
9
  * title object of a MediaWiki page
4
10
  *
@@ -19,7 +25,10 @@ export declare class Title {
19
25
  get prefix(): string;
20
26
  /** full title / 完整标题 */
21
27
  get title(): string;
22
- /** file extension / 扩展名 */
28
+ /**
29
+ * file extension / 扩展名
30
+ * @since v1.1.0
31
+ */
23
32
  get extension(): string | undefined;
24
33
  set extension(extension: string | undefined);
25
34
  /** @throws `RangeError` undefined namespace */
@@ -30,14 +39,18 @@ export declare class Title {
30
39
  *
31
40
  * @param title 标题(含或不含命名空间前缀)
32
41
  * @param defaultNs 命名空间
33
- * @param decode 是否需要解码
34
- * @param selfLink 是否允许selfLink
42
+ * @param config
43
+ * @param opt 选项
44
+ * @param opt.temporary 是否是临时标题
45
+ * @param opt.decode 是否需要解码
46
+ * @param opt.selfLink 是否允许selfLink
35
47
  */
36
- constructor(title: string, defaultNs: number, config: Config, temporary: boolean, decode: boolean, selfLink: boolean);
48
+ constructor(title: string, defaultNs: number, config: Config, { temporary, decode, selfLink }?: TitleOptions);
37
49
  /**
38
50
  * Check if the title is a redirect
39
51
  *
40
52
  * 检测是否是重定向
53
+ * @since v1.12.2
41
54
  */
42
55
  getRedirection(): [boolean, string];
43
56
  /**
@@ -45,6 +58,7 @@ export declare class Title {
45
58
  *
46
59
  * 生成URL
47
60
  * @param articlePath article path / 条目路径
61
+ * @since v1.10.0
48
62
  */
49
63
  getUrl(articlePath?: string): string;
50
64
  /**
@@ -57,30 +71,35 @@ export declare class Title {
57
71
  * Get the title of its subject page
58
72
  *
59
73
  * 转换为主页面
74
+ * @since v1.1.0
60
75
  */
61
76
  toSubjectPage(): void;
62
77
  /**
63
78
  * Get the title of its talk page
64
79
  *
65
80
  * 转换为讨论页面
81
+ * @since v1.1.0
66
82
  */
67
83
  toTalkPage(): void;
68
84
  /**
69
85
  * Check if the title is a talk page
70
86
  *
71
87
  * 是否是讨论页
88
+ * @since v1.1.0
72
89
  */
73
90
  isTalkPage(): boolean;
74
91
  /**
75
92
  * Get the title of its base page
76
93
  *
77
94
  * 转换为上一级页面
95
+ * @since v1.1.0
78
96
  */
79
97
  toBasePage(): void;
80
98
  /**
81
99
  * Get the title of its root page
82
100
  *
83
101
  * 转换为根页面
102
+ * @since v1.1.0
84
103
  */
85
104
  toRootPage(): void;
86
105
  }
package/dist/lib/title.js CHANGED
@@ -8,7 +8,6 @@ const string_1 = require("../util/string");
8
8
  /* NOT FOR BROWSER */
9
9
  const constants_1 = require("../util/constants");
10
10
  const index_1 = __importDefault(require("../index"));
11
- /* NOT FOR BROWSER END */
12
11
  /**
13
12
  * title object of a MediaWiki page
14
13
  *
@@ -56,7 +55,10 @@ class Title {
56
55
  get title() {
57
56
  return this.getRedirection()[1];
58
57
  }
59
- /** file extension / 扩展名 */
58
+ /**
59
+ * file extension / 扩展名
60
+ * @since v1.1.0
61
+ */
60
62
  get extension() {
61
63
  const { main } = this, i = main.lastIndexOf('.');
62
64
  return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
@@ -97,10 +99,13 @@ class Title {
97
99
  *
98
100
  * @param title 标题(含或不含命名空间前缀)
99
101
  * @param defaultNs 命名空间
100
- * @param decode 是否需要解码
101
- * @param selfLink 是否允许selfLink
102
+ * @param config
103
+ * @param opt 选项
104
+ * @param opt.temporary 是否是临时标题
105
+ * @param opt.decode 是否需要解码
106
+ * @param opt.selfLink 是否允许selfLink
102
107
  */
103
- constructor(title, defaultNs, config, temporary, decode, selfLink) {
108
+ constructor(title, defaultNs, config, { temporary, decode, selfLink } = {}) {
104
109
  const subpage = title.trim().startsWith('../');
105
110
  if (decode && title.includes('%')) {
106
111
  try {
@@ -174,6 +179,7 @@ class Title {
174
179
  * Check if the title is a redirect
175
180
  *
176
181
  * 检测是否是重定向
182
+ * @since v1.12.2
177
183
  */
178
184
  getRedirection() {
179
185
  const prefix = this.interwiki + (this.interwiki && ':') + // eslint-disable-line @stylistic/operator-linebreak
@@ -202,6 +208,7 @@ class Title {
202
208
  *
203
209
  * 生成URL
204
210
  * @param articlePath article path / 条目路径
211
+ * @since v1.10.0
205
212
  */
206
213
  getUrl(articlePath) {
207
214
  LSP: { // eslint-disable-line no-unused-labels
@@ -267,6 +274,7 @@ class Title {
267
274
  * Get the title of its subject page
268
275
  *
269
276
  * 转换为主页面
277
+ * @since v1.1.0
270
278
  */
271
279
  toSubjectPage() {
272
280
  if (this.isTalkPage()) {
@@ -277,6 +285,7 @@ class Title {
277
285
  * Get the title of its talk page
278
286
  *
279
287
  * 转换为讨论页面
288
+ * @since v1.1.0
280
289
  */
281
290
  toTalkPage() {
282
291
  if (!this.isTalkPage()) {
@@ -287,6 +296,7 @@ class Title {
287
296
  * Check if the title is a talk page
288
297
  *
289
298
  * 是否是讨论页
299
+ * @since v1.1.0
290
300
  */
291
301
  isTalkPage() {
292
302
  return this.ns % 2 === 1;
@@ -295,6 +305,7 @@ class Title {
295
305
  * Get the title of its base page
296
306
  *
297
307
  * 转换为上一级页面
308
+ * @since v1.1.0
298
309
  */
299
310
  toBasePage() {
300
311
  this.main = this.main.replace(/\/[^/]*$/u, '');
@@ -303,6 +314,7 @@ class Title {
303
314
  * Get the title of its root page
304
315
  *
305
316
  * 转换为根页面
317
+ * @since v1.1.0
306
318
  */
307
319
  toRootPage() {
308
320
  this.main = this.main.replace(/\/.*/u, '');
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 不需要转义的类
3
+ * @ignore
4
+ */
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noEscape = void 0;
4
+ const debug_1 = require("../util/debug");
5
+ const constants_1 = require("../util/constants");
6
+ /**
7
+ * 不需要转义的类
8
+ * @ignore
9
+ */
10
+ const noEscape = (constructor, _) => {
11
+ /** 不可包含换行符的类 */
12
+ class NoEscapeToken extends constructor {
13
+ /** @private */
14
+ escape() {
15
+ //
16
+ }
17
+ }
18
+ (0, debug_1.mixin)(NoEscapeToken, constructor);
19
+ return NoEscapeToken;
20
+ };
21
+ exports.noEscape = noEscape;
22
+ constants_1.mixins['noEscape'] = __filename;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 只读或可写的方法
3
+ * @param readonly 是否只读
4
+ */
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readOnly = void 0;
7
+ const debug_1 = require("../util/debug");
8
+ const constants_1 = require("../util/constants");
9
+ const index_1 = __importDefault(require("../index"));
10
+ /**
11
+ * 只读或可写的方法
12
+ * @param readonly 是否只读
13
+ */
14
+ const readOnly = (readonly = false) =>
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ (method) => function (...args) {
17
+ const { viewOnly } = index_1.default;
18
+ if (!debug_1.Shadow.running) {
19
+ index_1.default.viewOnly = readonly;
20
+ }
21
+ const result = method.apply(this, args);
22
+ index_1.default.viewOnly = viewOnly;
23
+ return result;
24
+ };
25
+ exports.readOnly = readOnly;
26
+ constants_1.mixins['readOnly'] = __filename;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseBraces = void 0;
4
+ const common_1 = require("@bhsd/common");
4
5
  const string_1 = require("../util/string");
5
6
  const heading_1 = require("../src/heading");
6
7
  const transclude_1 = require("../src/transclude");
@@ -8,12 +9,35 @@ const arg_1 = require("../src/arg");
8
9
  /* NOT FOR BROWSER */
9
10
  const constants_1 = require("../util/constants");
10
11
  /* NOT FOR BROWSER END */
12
+ /* NOT FOR BROWSER ONLY */
13
+ const v8_1 = require("v8");
14
+ const MAXHEAP = (0, v8_1.getHeapStatistics)().heap_size_limit * 0.9;
15
+ /* NOT FOR BROWSER ONLY END */
11
16
  const closes = {
12
17
  '=': String.raw `\n(?!(?:[^\S\n]|\0\d+[cn]\x7F)*\n)`,
13
18
  '{': String.raw `\}{2,}|\|`,
14
19
  '-': String.raw `\}-`,
15
20
  '[': String.raw `\]\]`,
16
- }, openBraces = String.raw `|\{{2,}`, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~'], ['server', 'm']]);
21
+ }, lbrack = String.raw `\[(?!\[)`, newline = String.raw `\n(?![=\0])`, openBraces = String.raw `|\{{2,}`, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~'], ['server', 'm']]), getExecRegex = (0, common_1.getRegex)(s => new RegExp(s, 'gmu'));
22
+ let reReplace;
23
+ /* NOT FOR BROWSER ONLY */
24
+ try {
25
+ reReplace = new RegExp(String.raw `(?<!\{)\{\{((?:[^\n{}[]|${lbrack}|${newline})*)\}\}` // eslint-disable-line prefer-template
26
+ + '|'
27
+ + String.raw `\{\{((?:[^\n{}[]|${lbrack}|${newline})*)\}\}(?!\})`
28
+ + '|'
29
+ + String.raw `\[\[(?:[^\n[\]{]|${newline})*\]\]`
30
+ + '|'
31
+ + String.raw `-\{(?:[^\n{}[]|${lbrack}|${newline})*\}-`, 'gu');
32
+ }
33
+ catch {
34
+ /* NOT FOR BROWSER ONLY END */
35
+ reReplace = new RegExp(String.raw `\{\{((?:[^\n{}[]|${lbrack}|${newline})*)\}\}(?!\})` // eslint-disable-line prefer-template
36
+ + '|'
37
+ + String.raw `\[\[(?:[^\n[\]{]|${newline})*\]\]`
38
+ + '|'
39
+ + String.raw `-\{(?:[^\n{}[]|${lbrack}|${newline})*\}-`, 'gu');
40
+ }
17
41
  /**
18
42
  * 获取模板或魔术字对应的字符
19
43
  * @param s 模板或魔术字名
@@ -36,7 +60,8 @@ const getSymbol = (s) => {
36
60
  * @param wikitext
37
61
  * @param config
38
62
  * @param accum
39
- * @throws TranscludeToken.constructor()
63
+ * @throws `RangeError` Maximum iteration exceeded
64
+ * @throws `TranscludeToken.constructor()`
40
65
  */
41
66
  const parseBraces = (wikitext, config, accum) => {
42
67
  const source = String.raw `${config.excludes?.includes('heading') ? '' : String.raw `^((?:\0\d+[cno]\x7F)*)={1,6}|`}\[\[|-\{(?!\{)`, { parserFunction: [, , , subst] } = config, stack = [], linkStack = [];
@@ -45,48 +70,63 @@ const parseBraces = (wikitext, config, accum) => {
45
70
  * @param s 不含内链的字符串
46
71
  */
47
72
  const restore = (s) => s.replace(/\0(\d+)\x7F/gu, (_, p1) => linkStack[p1]);
48
- wikitext = wikitext.replace(/\{\{([^\n{}[]*)\}\}(?!\})|\[\[[^\n[\]{]*\]\]/gu, (m, p1) => {
49
- if (p1 !== undefined) {
50
- try {
51
- const { length } = accum, parts = p1.split('|');
52
- // @ts-expect-error abstract class
53
- new transclude_1.TranscludeToken(parts[0], parts.slice(1).map(part => {
54
- const i = part.indexOf('=');
55
- return i === -1 ? [part] : [part.slice(0, i), part.slice(i + 1)];
56
- }), config, accum);
57
- return `\0${length}${getSymbol(parts[0])}\x7F`;
58
- }
59
- catch (e) {
60
- /* istanbul ignore if */
61
- if (!(e instanceof SyntaxError) || e.message !== 'Invalid template name') {
62
- throw e;
73
+ /**
74
+ * 填入模板内容
75
+ * @param text wikitext全文
76
+ * @param parts 模板参数
77
+ * @param lastIndex 匹配的起始位置
78
+ * @param index 匹配位置
79
+ */
80
+ const push = (text, parts, lastIndex, index) => {
81
+ parts[parts.length - 1].push(restore(text.slice(lastIndex, index)));
82
+ };
83
+ let replaced;
84
+ do {
85
+ if (replaced !== undefined) {
86
+ wikitext = replaced;
87
+ }
88
+ replaced = wikitext.replace(reReplace, (m, p1, p2) => {
89
+ if (p1 !== undefined || typeof p2 === 'string') {
90
+ try {
91
+ const { length } = accum, parts = (p1 ?? p2).split('|');
92
+ // @ts-expect-error abstract class
93
+ new transclude_1.TranscludeToken(restore(parts[0]), parts.slice(1).map(part => {
94
+ const i = part.indexOf('=');
95
+ return (i === -1 ? [part] : [part.slice(0, i), part.slice(i + 1)]).map(restore);
96
+ }), config, accum);
97
+ return `\0${length}${getSymbol(parts[0])}\x7F`;
98
+ }
99
+ catch (e) {
100
+ /* istanbul ignore if */
101
+ if (!(e instanceof SyntaxError) || e.message !== 'Invalid template name') {
102
+ throw e;
103
+ }
63
104
  }
64
105
  }
65
- }
66
- linkStack.push(m);
67
- return `\0${linkStack.length - 1}\x7F`;
68
- });
106
+ linkStack.push(restore(m));
107
+ return `\0${linkStack.length - 1}\x7F`;
108
+ });
109
+ } while (replaced !== wikitext);
110
+ wikitext = replaced;
69
111
  const lastBraces = wikitext.lastIndexOf('}}') - wikitext.length;
70
112
  let moreBraces = lastBraces + wikitext.length !== -1;
71
113
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
72
114
  /^((?:\0\d+[cno]\x7F)*)={1,6}|\[\[|-\{(?!\{)|\{{2,}|\n(?!(?:[^\S\n]|\0\d+[cn]\x7F)*\n)|[|=]|\}{2,}|\}-|\]\]/gmu;
73
- let regex = new RegExp(source + (moreBraces ? openBraces : ''), 'gmu'), mt = regex.exec(wikitext), lastIndex;
115
+ let regex = getExecRegex(source + (moreBraces ? openBraces : '')), mt = regex.exec(wikitext), lastIndex;
74
116
  while (mt
75
117
  || lastIndex !== undefined && lastIndex <= wikitext.length
76
118
  && stack[stack.length - 1]?.[0]?.startsWith('=')) {
119
+ /* NOT FOR BROWSER ONLY */
120
+ if (process.memoryUsage().heapUsed > MAXHEAP) {
121
+ throw new RangeError('Maximum heap size exceeded');
122
+ }
123
+ /* NOT FOR BROWSER ONLY END */
77
124
  if (mt?.[1]) {
78
125
  const [, { length }] = mt;
79
126
  mt[0] = mt[0].slice(length);
80
127
  mt.index += length;
81
128
  }
82
129
  const { 0: syntax, index: curIndex } = mt ?? { 0: '\n', index: wikitext.length }, top = stack.pop() ?? {}, { 0: open, index, parts, findEqual: topFindEqual, pos: topPos } = top, innerEqual = syntax === '=' && topFindEqual;
83
- /**
84
- * 填入模板内容
85
- * @param text wikitext全文
86
- */
87
- const push = (text) => {
88
- parts[parts.length - 1].push(restore(text.slice(topPos, curIndex)));
89
- };
90
130
  if (syntax === ']]' || syntax === '}-') { // 情形1:闭合内链或转换
91
131
  lastIndex = curIndex + 2;
92
132
  }
@@ -97,17 +137,19 @@ const parseBraces = (wikitext, config, accum) => {
97
137
  const rmt = /^(={1,6})(.+)\1((?:\s|\0\d+[cn]\x7F)*)$/u
98
138
  .exec(wikitext.slice(index, curIndex));
99
139
  if (rmt) {
100
- wikitext = `${wikitext.slice(0, index)}\0${accum.length}h\x7F${wikitext.slice(curIndex)}`;
101
- lastIndex = index + 4 + String(accum.length).length;
102
140
  rmt[2] = restore(rmt[2]);
103
- // @ts-expect-error abstract class
104
- new heading_1.HeadingToken(rmt[1].length, rmt.slice(2), config, accum);
141
+ if (!rmt[2].includes('\n')) {
142
+ wikitext = `${wikitext.slice(0, index)}\0${accum.length}h\x7F${wikitext.slice(curIndex)}`;
143
+ lastIndex = index + 4 + String(accum.length).length;
144
+ // @ts-expect-error abstract class
145
+ new heading_1.HeadingToken(rmt[1].length, rmt.slice(2), config, accum);
146
+ }
105
147
  }
106
148
  }
107
149
  }
108
150
  else if (syntax === '|' || innerEqual) { // 情形3:模板内部,含行首单个'='
109
151
  lastIndex = curIndex + 1;
110
- push(wikitext);
152
+ push(wikitext, parts, topPos, curIndex);
111
153
  if (syntax === '|') {
112
154
  parts.push([]);
113
155
  }
@@ -118,7 +160,7 @@ const parseBraces = (wikitext, config, accum) => {
118
160
  else if (syntax.startsWith('}}')) { // 情形4:闭合模板
119
161
  const close = syntax.slice(0, Math.min(open.length, 3)), rest = open.length - close.length, { length } = accum;
120
162
  lastIndex = curIndex + close.length; // 这不是最终的lastIndex
121
- push(wikitext);
163
+ push(wikitext, parts, topPos, curIndex);
122
164
  let skip = false, ch = 't';
123
165
  if (close.length === 3) {
124
166
  const argParts = parts.map(part => part.join('=')), str = argParts.length > 1 && (0, string_1.removeComment)(argParts[1]).trim();
@@ -173,9 +215,9 @@ const parseBraces = (wikitext, config, accum) => {
173
215
  }
174
216
  }
175
217
  /\{\{\s*([!=]|!!|\(!|!\)|!-)\s*\}\}(?!\})/gu; // eslint-disable-line @typescript-eslint/no-unused-expressions
176
- regex = new RegExp(source
218
+ regex = getExecRegex(source
177
219
  + (moreBraces ? openBraces : '')
178
- + (curTop ? `|${closes[curTop[0][0]]}${curTop.findEqual ? '|=' : ''}` : ''), 'gmu');
220
+ + (curTop ? `|${closes[curTop[0][0]]}${curTop.findEqual ? '|=' : ''}` : ''));
179
221
  regex.lastIndex = lastIndex;
180
222
  mt = regex.exec(wikitext);
181
223
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseCommentAndExt = void 0;
4
+ const common_1 = require("@bhsd/common");
4
5
  const onlyinclude_1 = require("../src/onlyinclude");
5
6
  const noinclude_1 = require("../src/nowiki/noinclude");
6
7
  const include_1 = require("../src/tagPair/include");
@@ -9,24 +10,12 @@ const comment_1 = require("../src/nowiki/comment");
9
10
  /* NOT FOR BROWSER */
10
11
  const constants_1 = require("../util/constants");
11
12
  /* NOT FOR BROWSER END */
12
- const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft, regexInclude = new WeakMap(), regexNoinclude = new WeakMap();
13
- /**
14
- * 获取正则表达式
15
- * @param ext 扩展标签
16
- * @param includeOnly 是否嵌入
17
- */
18
- const getRegex = (ext, includeOnly) => {
19
- const regex = includeOnly ? regexInclude : regexNoinclude;
20
- if (regex.has(ext)) {
21
- return regex.get(ext);
22
- }
13
+ const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft, getRegex = [false, true].map(includeOnly => {
23
14
  const noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly';
24
15
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
25
16
  /<!--[\s\S]*?(?:-->|$)|<foo(?:\s[^>]*)?\/?>|<\/foo\s*>|<(bar)(\s[^>]*?)?(?:\/>|>([\s\S]*?)<\/(\1\s*)>)|<(baz)(\s[^>]*?)?(?:\/>|>([\s\S]*?)(?:<\/(baz\s*)>|$))/giu;
26
- const re = new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${ext.join('|')})(\s[^>]*?)?(?:/>|>([\s\S]*?)</(\1\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>([\s\S]*?)(?:</(${includeRegex}\s*)>|$))`, 'giu');
27
- regex.set(ext, re);
28
- return re;
29
- };
17
+ return (0, common_1.getRegex)(ext => new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${ext.join('|')})(\s[^>]*?)?(?:/>|>([\s\S]*?)</(\1\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>([\s\S]*?)(?:</(${includeRegex}\s*)>|$))`, 'giu'));
18
+ });
30
19
  /**
31
20
  * 更新`<onlyinclude>`和`</onlyinclude>`的位置
32
21
  * @param wikitext
@@ -72,7 +61,7 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
72
61
  return str;
73
62
  }
74
63
  }
75
- return wikitext.replace(getRegex(config.ext, includeOnly), (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
64
+ return wikitext.replace(getRegex[includeOnly ? 1 : 0](config.ext), (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
76
65
  const l = accum.length;
77
66
  let ch = 'n';
78
67
  if (name) {
@@ -56,7 +56,7 @@ const parseLinks = (wikitext, config, accum, tidy) => {
56
56
  }
57
57
  const { ns, valid,
58
58
  /* NOT FOR BROWSER */
59
- interwiki, } = index_1.default.normalizeTitle(link, 0, false, config, true, true, true, true);
59
+ interwiki, } = index_1.default.normalizeTitle(link, 0, false, config, { halfParsed: true, temporary: true, decode: true, selfLink: true });
60
60
  if (!valid) {
61
61
  s += `[[${x}`;
62
62
  continue;
@@ -79,7 +79,7 @@ const parseQuotes = (wikitext, config, accum, tidy) => {
79
79
  /* NOT FOR BROWSER */
80
80
  if (tidy && (!bold || !italic)) {
81
81
  // @ts-expect-error abstract class
82
- new quote_1.QuoteToken((bold ? '' : "'''") + (italic ? '' : "''"), { bold: !bold, italic: !italic }, config, accum);
82
+ new quote_1.QuoteToken((bold ? '' : `'''`) + (italic ? '' : `''`), { bold: !bold, italic: !italic }, config, accum);
83
83
  arr.push(`\0${accum.length - 1}q\x7F`);
84
84
  }
85
85
  /* NOT FOR BROWSER END */
@@ -21,9 +21,7 @@ const parseRedirect = (text, config, accum) => {
21
21
  config.regexRedirect ??= new RegExp(String.raw `^(\s*)((?:${config.redirection.join('|')})\s*(?::\s*)?)\[\[([^\n|\]]+)(\|.*?)?\]\](\s*)`, 'iu');
22
22
  const mt = config.regexRedirect.exec(text);
23
23
  if (mt
24
- && index_1.default
25
- .normalizeTitle(mt[3], 0, false, config, true, true, true)
26
- .valid) {
24
+ && index_1.default.normalizeTitle(mt[3], 0, false, config, { halfParsed: true, temporary: true, decode: true }).valid) {
27
25
  text = `\0${accum.length}o\x7F${text.slice(mt[0].length)}`;
28
26
  // @ts-expect-error abstract class
29
27
  new redirect_1.RedirectToken(...mt.slice(1), config, accum);