wikiparser-node 1.28.0 → 1.29.0

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 (83) hide show
  1. package/README.md +0 -2
  2. package/bundle/bundle-es8.min.js +25 -25
  3. package/bundle/bundle-lsp.min.js +30 -30
  4. package/bundle/bundle.min.js +24 -24
  5. package/config/default.json +15 -16
  6. package/config/jawiki.json +15 -16
  7. package/data/ext/ThirdPartyNotices.txt +33 -0
  8. package/data/ext/mapframe.json +489 -2
  9. package/dist/addon/magicWords.js +132 -0
  10. package/dist/addon/table.js +4 -4
  11. package/dist/addon/token.js +37 -126
  12. package/dist/addon/transclude.js +24 -30
  13. package/dist/base.d.mts +4 -2
  14. package/dist/base.d.ts +4 -2
  15. package/dist/base.js +2 -0
  16. package/dist/base.mjs +3 -1
  17. package/dist/bin/config.js +11 -11
  18. package/dist/index.d.ts +2 -1
  19. package/dist/index.js +27 -5
  20. package/dist/lib/document.d.ts +23 -7
  21. package/dist/lib/document.js +7 -27
  22. package/dist/lib/element.js +1 -1
  23. package/dist/lib/lintConfig.js +4 -0
  24. package/dist/lib/lsp.d.ts +1 -12
  25. package/dist/lib/lsp.js +45 -79
  26. package/dist/lib/node.js +25 -25
  27. package/dist/lib/range.js +2 -2
  28. package/dist/lib/title.d.ts +3 -1
  29. package/dist/lib/title.js +54 -33
  30. package/dist/mixin/elementLike.js +14 -9
  31. package/dist/parser/commentAndExt.js +34 -27
  32. package/dist/parser/hrAndDoubleUnderscore.js +9 -8
  33. package/dist/parser/links.js +4 -3
  34. package/dist/parser/redirect.js +1 -1
  35. package/dist/parser/selector.js +7 -9
  36. package/dist/src/arg.js +6 -9
  37. package/dist/src/attribute.js +37 -8
  38. package/dist/src/attributes.js +1 -1
  39. package/dist/src/converter.js +6 -3
  40. package/dist/src/converterRule.js +4 -6
  41. package/dist/src/extLink.js +3 -4
  42. package/dist/src/heading.js +1 -2
  43. package/dist/src/imageParameter.d.ts +4 -1
  44. package/dist/src/imageParameter.js +79 -26
  45. package/dist/src/index.d.ts +8 -0
  46. package/dist/src/index.js +21 -29
  47. package/dist/src/link/base.js +6 -8
  48. package/dist/src/link/file.js +10 -14
  49. package/dist/src/link/galleryImage.js +1 -1
  50. package/dist/src/link/redirectTarget.js +1 -1
  51. package/dist/src/magicLink.js +13 -3
  52. package/dist/src/multiLine/gallery.js +2 -2
  53. package/dist/src/multiLine/imagemap.js +3 -4
  54. package/dist/src/multiLine/paramTag.js +2 -2
  55. package/dist/src/nowiki/doubleUnderscore.d.ts +2 -1
  56. package/dist/src/nowiki/doubleUnderscore.js +9 -5
  57. package/dist/src/nowiki/index.js +58 -4
  58. package/dist/src/onlyinclude.js +2 -1
  59. package/dist/src/parameter.js +4 -6
  60. package/dist/src/redirect.js +2 -2
  61. package/dist/src/table/base.js +1 -2
  62. package/dist/src/table/index.js +3 -6
  63. package/dist/src/table/td.d.ts +2 -3
  64. package/dist/src/table/td.js +6 -6
  65. package/dist/src/table/trBase.js +1 -1
  66. package/dist/src/tag/html.js +3 -4
  67. package/dist/src/tag/tvar.js +1 -2
  68. package/dist/src/tagPair/ext.js +12 -5
  69. package/dist/src/tagPair/include.js +2 -2
  70. package/dist/src/tagPair/translate.js +2 -2
  71. package/dist/src/transclude.js +5 -5
  72. package/dist/util/constants.js +4 -1
  73. package/dist/util/debug.js +1 -1
  74. package/dist/util/html.js +13 -10
  75. package/dist/util/search.js +16 -0
  76. package/dist/util/sharable.js +27 -3
  77. package/dist/util/sharable.mjs +28 -4
  78. package/extensions/dist/base.js +1 -1
  79. package/i18n/en.json +4 -0
  80. package/i18n/zh-hans.json +4 -0
  81. package/i18n/zh-hant.json +4 -0
  82. package/package.json +9 -7
  83. package/data/ext/maplink.json +0 -4
package/dist/lib/title.js CHANGED
@@ -9,6 +9,14 @@ const string_1 = require("../util/string");
9
9
  /* NOT FOR BROWSER */
10
10
  const constants_1 = require("../util/constants");
11
11
  const index_1 = __importDefault(require("../index"));
12
+ /**
13
+ * 解析标题的路径
14
+ * @param title 标题
15
+ */
16
+ const resolve = (title) => {
17
+ const [, { length }, sub] = /^((?:\.\.\/)*)([\s\S]*)/u.exec(title);
18
+ return [length / 3, sub];
19
+ };
12
20
  /**
13
21
  * title object of a MediaWiki page
14
22
  *
@@ -20,6 +28,8 @@ class Title {
20
28
  #path;
21
29
  #ns;
22
30
  #fragment;
31
+ /** @private */
32
+ page;
23
33
  valid;
24
34
  /** @private */
25
35
  encoded = false;
@@ -115,9 +125,11 @@ class Title {
115
125
  * @param opt.temporary 是否是临时标题
116
126
  * @param opt.decode 是否需要解码
117
127
  * @param opt.selfLink 是否允许selfLink
128
+ * @param opt.page 当前页面标题
118
129
  */
119
- constructor(title, defaultNs, config, { temporary, decode, selfLink } = {}) {
120
- const subpage = title.trim().startsWith('../');
130
+ constructor(title, defaultNs, config, { temporary, decode, selfLink, page } = {}) {
131
+ this.page = page;
132
+ const trimmed = title.trim(), subpage = trimmed.startsWith('../');
121
133
  if (decode && title.includes('%')) {
122
134
  try {
123
135
  const encoded = /%(?!21|3[ce]|5[bd]|7[b-d])[\da-f]{2}/iu.test(title);
@@ -127,7 +139,7 @@ class Title {
127
139
  catch { }
128
140
  }
129
141
  title = (0, string_1.decodeHtml)(title).replace(/[_ ]+/gu, ' ').trim();
130
- if (subpage) {
142
+ if (subpage || page && trimmed.startsWith('/')) {
131
143
  this.#ns = 0;
132
144
  }
133
145
  else {
@@ -165,11 +177,13 @@ class Title {
165
177
  this.#fragment = fragment.replace(/ /gu, '_');
166
178
  title = title.slice(0, i).trim();
167
179
  }
180
+ const [level, sub] = subpage ? resolve(title) : [0, title];
168
181
  this.valid = Boolean(title
169
182
  || this.interwiki
170
183
  || selfLink && this.ns === 0 && this.#fragment !== undefined)
171
184
  && (0, string_1.decodeHtml)(title) === title
172
- && !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|\n]|%[\da-f]{2}|(?:^|\/)\.{1,2}(?:$|\/)/iu.test(subpage ? /^(?:\.\.\/)+(.*)/u.exec(title)[1] : title);
185
+ && (level === 0 || page === undefined || page.split('/', level + 1).length > level)
186
+ && !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|\n]|%[\da-f]{2}|(?:^|\/)\.{1,2}(?:$|\/)/iu.test(sub);
173
187
  this.main = title;
174
188
  this.#namespaces = config.namespaces;
175
189
  this.#path = config.articlePath || '/wiki/$1';
@@ -187,6 +201,33 @@ class Title {
187
201
  });
188
202
  }
189
203
  }
204
+ /**
205
+ * 生成标题
206
+ * @param prefix 前缀
207
+ */
208
+ #getTitle(prefix) {
209
+ let title = (prefix + this.main).replace(/ /gu, '_');
210
+ if (title.startsWith('/')) {
211
+ title = (this.page ?? '') + title.replace(/(.)\/$/u, '$1');
212
+ }
213
+ else if (title.startsWith('../') && this.page?.includes('/')) {
214
+ const [level, sub] = resolve(title), dirs = this.page.split('/');
215
+ if (dirs.length > level) {
216
+ title = dirs.slice(0, -level).join('/') + (sub && '/') + sub;
217
+ }
218
+ }
219
+ /* NOT FOR BROWSER */
220
+ const media = title.startsWith('Media:');
221
+ let redirected = this.redirects.get(media ? `File:${title.slice(6)}` : title);
222
+ if (redirected) {
223
+ const hash = redirected.indexOf('#');
224
+ this.#redirectFragment = hash === -1 ? undefined : redirected.slice(hash + 1);
225
+ redirected = hash === -1 ? redirected : redirected.slice(0, hash);
226
+ return [true, media ? redirected.replace(/^File:/u, 'Media:') : redirected];
227
+ }
228
+ /* NOT FOR BROWSER */
229
+ return [false, title];
230
+ }
190
231
  /**
191
232
  * Check if the title is a redirect
192
233
  *
@@ -194,22 +235,20 @@ class Title {
194
235
  * @since v1.12.2
195
236
  */
196
237
  getRedirection() {
197
- const prefix = this.interwiki + (this.interwiki && ':') + // eslint-disable-line @stylistic/operator-linebreak
198
- this.prefix;
199
- let title = (prefix + this.main).replace(/ /gu, '_');
238
+ const { prefix,
200
239
  /* NOT FOR BROWSER */
201
- let redirected = this.#redirect(title);
202
- if (redirected) {
203
- return [true, redirected];
240
+ main, interwiki, } = this, pre = interwiki + (interwiki && ':') + // eslint-disable-line @stylistic/operator-linebreak
241
+ prefix, result = this.#getTitle(pre);
242
+ /* NOT FOR BROWSER */
243
+ if (result[0]) {
244
+ return result;
204
245
  }
205
246
  this.autoConvert();
206
- title = (prefix + this.main).replaceAll(' ', '_');
207
- redirected = this.#redirect(title);
208
- if (redirected) {
209
- return [true, redirected];
247
+ if (this.main !== main) {
248
+ return this.#getTitle(pre);
210
249
  }
211
250
  /* NOT FOR BROWSER END */
212
- return [false, title];
251
+ return result;
213
252
  }
214
253
  /** @private */
215
254
  setFragment(fragment) {
@@ -250,24 +289,6 @@ class Title {
250
289
  ? ''
251
290
  : `#${this.#fragment ?? this.#redirectFragment}`);
252
291
  }
253
- /**
254
- * 处理重定向
255
- * @param title 原标题
256
- */
257
- #redirect(title) {
258
- const media = title.startsWith('Media:');
259
- if (media) {
260
- title = `File:${title.slice(6)}`;
261
- }
262
- const redirected = this.redirects.get(title);
263
- if (redirected) {
264
- const hash = redirected.indexOf('#');
265
- title = hash === -1 ? redirected : redirected.slice(0, hash);
266
- this.#redirectFragment = hash === -1 ? undefined : redirected.slice(hash + 1);
267
- return media ? title.replace(/^File:/u, 'Media:') : title;
268
- }
269
- return '';
270
- }
271
292
  /**
272
293
  * Perform unidirectional language conversion
273
294
  *
@@ -33,16 +33,17 @@ const elementLike = (constructor) => {
33
33
  this);
34
34
  }
35
35
  getElementBy(condition) {
36
- for (const child of this.childNodes) {
37
- if (child.type === 'text') {
36
+ const stack = [...this.childNodes].reverse();
37
+ while (stack.length > 0) {
38
+ const child = stack.pop(), { type, childNodes } = child;
39
+ if (type === 'text') {
38
40
  continue;
39
41
  }
40
42
  else if (condition(child)) {
41
43
  return child;
42
44
  }
43
- const descendant = child.getElementBy(condition);
44
- if (descendant) {
45
- return descendant;
45
+ for (let i = childNodes.length - 1; i >= 0; i--) {
46
+ stack.push(childNodes[i]);
46
47
  }
47
48
  }
48
49
  return undefined;
@@ -50,15 +51,19 @@ const elementLike = (constructor) => {
50
51
  querySelector(selector) {
51
52
  return this.getElementBy(this.#getCondition(selector));
52
53
  }
53
- getElementsBy(condition, descendants = []) {
54
- for (const child of this.childNodes) {
55
- if (child.type === 'text') {
54
+ getElementsBy(condition) {
55
+ const stack = [...this.childNodes].reverse(), descendants = [];
56
+ while (stack.length > 0) {
57
+ const child = stack.pop(), { type, childNodes } = child;
58
+ if (type === 'text') {
56
59
  continue;
57
60
  }
58
61
  else if (condition(child)) {
59
62
  descendants.push(child);
60
63
  }
61
- child.getElementsBy(condition, descendants);
64
+ for (let i = childNodes.length - 1; i >= 0; i--) {
65
+ stack.push(childNodes[i]);
66
+ }
62
67
  }
63
68
  return descendants;
64
69
  }
@@ -12,11 +12,11 @@ const comment_1 = require("../src/nowiki/comment");
12
12
  /* NOT FOR BROWSER */
13
13
  const constants_1 = require("../util/constants");
14
14
  /* NOT FOR BROWSER END */
15
- const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft, getRegex = [false, true].map(includeOnly => {
15
+ const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft, getExtRegex = [false, true].map(includeOnly => {
16
16
  const noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly';
17
17
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
18
18
  /<!--[\s\S]*?(?:-->|$)|<foo(?:\s[^>]*)?\/?>|<\/foo\s*>|<(bar)(\s[^>]*?)?(?:\/>|>([\s\S]*?)<\/(\1\s*)>)|<(baz)(\s[^>]*?)?(?:\/>|>([\s\S]*?)(?:<\/(baz\s*)>|$))/giu;
19
- return (0, common_1.getObjRegex)(ext => new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${ext.join('|') // eslint-disable-next-line unicorn/prefer-string-raw
19
+ return (0, common_1.getRegex)(exts => new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${exts // eslint-disable-next-line unicorn/prefer-string-raw
20
20
  })(\s[^>]*?)?(?:/>|>([\s\S]*?)</(${'\\1'}\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>([\s\S]*?)(?:</(${includeRegex}\s*)>|$))`, 'giu'));
21
21
  });
22
22
  /**
@@ -64,8 +64,11 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
64
64
  return str;
65
65
  }
66
66
  }
67
- const { ext } = config, newExt = ext.filter(e => e !== 'translate' && e !== 'tvar'), newConfig = { ...config, ext: newExt };
67
+ const { ext } = config;
68
+ let newExt = ext, newConfig = config;
68
69
  if (ext.includes('translate')) {
70
+ newExt = ext.filter(e => e !== 'translate' && e !== 'tvar');
71
+ newConfig = { ...config, ext: newExt };
69
72
  const stack = [];
70
73
  wikitext = wikitext.replace(/<nowiki>[\s\S]*?<\/nowiki>/giu, m => {
71
74
  stack.push(m);
@@ -78,30 +81,34 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
78
81
  });
79
82
  wikitext = (0, string_1.restore)(wikitext, stack);
80
83
  }
81
- return wikitext.replace(getRegex[includeOnly ? 1 : 0](newExt), (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
82
- const l = accum.length;
83
- let ch = 'n';
84
- if (name) {
85
- ch = 'e';
86
- // @ts-expect-error abstract class
87
- new ext_1.ExtToken(name, attr, inner, closing, newConfig, include, accum);
88
- }
89
- else if (substr.startsWith('<!--')) {
90
- ch = 'c';
91
- const closed = substr.endsWith('-->');
92
- // @ts-expect-error abstract class
93
- new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1).slice(4, closed ? -3 : undefined), closed, config, accum);
94
- }
95
- else if (include) {
96
- // @ts-expect-error abstract class
97
- new include_1.IncludeToken(include, includeAttr && (0, string_1.restore)(includeAttr, accum, 1), includeInner && (0, string_1.restore)(includeInner, accum, 1), includeClosing, config, accum);
98
- }
99
- else {
100
- // @ts-expect-error abstract class
101
- new noinclude_1.NoincludeToken(substr, config, accum, true);
102
- }
103
- return `\0${l}${ch}\x7F`;
104
- });
84
+ const re = getExtRegex[includeOnly ? 1 : 0](newExt.join('|'));
85
+ re.lastIndex = 0;
86
+ return re.test(wikitext)
87
+ ? wikitext.replace(re, (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
88
+ const l = accum.length;
89
+ let ch = 'n';
90
+ if (name) {
91
+ ch = 'e';
92
+ // @ts-expect-error abstract class
93
+ new ext_1.ExtToken(name, attr, inner, closing, newConfig, include, accum);
94
+ }
95
+ else if (substr.startsWith('<!--')) {
96
+ ch = 'c';
97
+ const closed = substr.endsWith('-->');
98
+ // @ts-expect-error abstract class
99
+ new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1).slice(4, closed ? -3 : undefined), closed, config, accum);
100
+ }
101
+ else if (include) {
102
+ // @ts-expect-error abstract class
103
+ new include_1.IncludeToken(include, includeAttr && (0, string_1.restore)(includeAttr, accum, 1), includeInner && (0, string_1.restore)(includeInner, accum, 1), includeClosing, config, accum);
104
+ }
105
+ else {
106
+ // @ts-expect-error abstract class
107
+ new noinclude_1.NoincludeToken(substr, config, accum, true);
108
+ }
109
+ return `\0${l}${ch}\x7F`;
110
+ })
111
+ : wikitext;
105
112
  };
106
113
  exports.parseCommentAndExt = parseCommentAndExt;
107
114
  constants_1.parsers['parseCommentAndExt'] = __filename;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseHrAndDoubleUnderscore = void 0;
4
+ const cm_util_1 = require("@bhsd/cm-util");
4
5
  const hr_1 = require("../src/nowiki/hr");
5
6
  const doubleUnderscore_1 = require("../src/nowiki/doubleUnderscore");
6
7
  const heading_1 = require("../src/heading");
@@ -14,11 +15,11 @@ const constants_1 = require("../util/constants");
14
15
  * @param accum
15
16
  */
16
17
  const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config, accum) => {
17
- const { doubleUnderscore: [insensitive, sensitive, aliases] } = config;
18
- config.insensitiveDoubleUnderscore ??= new Set(insensitive);
19
- config.sensitiveDoubleUnderscore ??= new Set(sensitive);
20
- /__(toc|notoc)__/giu; // eslint-disable-line @typescript-eslint/no-unused-expressions
21
- config.regexHrAndDoubleUnderscore ??= new RegExp(`__(${[...insensitive, ...sensitive].join('|')})__`, 'giu');
18
+ const { doubleUnderscore: [insensitive, sensitive, aliases] } = config, all = [...insensitive, ...sensitive];
19
+ config.insensitiveDoubleUnderscore ??= new Set(insensitive.filter(cm_util_1.isUnderscore));
20
+ config.sensitiveDoubleUnderscore ??= new Set(sensitive.filter(cm_util_1.isUnderscore));
21
+ /__(toc|notoc)__|_{2}(目次)_{2}/giu; // eslint-disable-line @typescript-eslint/no-unused-expressions
22
+ config.regexHrAndDoubleUnderscore ??= new RegExp(`__(${all.filter(cm_util_1.isUnderscore).join('|')})__|_{2}(${all.filter(s => !(0, cm_util_1.isUnderscore)(s)).map(s => s.slice(2, -2)).join('|')})_{2}`, 'giu');
22
23
  if (type !== 'root' && (type !== 'ext-inner' || name !== 'poem')) {
23
24
  data = `\0${data}`;
24
25
  }
@@ -26,11 +27,11 @@ const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config
26
27
  // @ts-expect-error abstract class
27
28
  new hr_1.HrToken(m, config, accum);
28
29
  return `${lead}\0${accum.length - 1}r\x7F`;
29
- }).replace(config.regexHrAndDoubleUnderscore, (m, p1) => {
30
- const caseSensitive = config.sensitiveDoubleUnderscore.has(p1), lc = p1.toLowerCase(), caseInsensitive = config.insensitiveDoubleUnderscore.has(lc);
30
+ }).replace(config.regexHrAndDoubleUnderscore, (m, p1, p2) => {
31
+ const key = p1 ?? p2, caseSensitive = config.sensitiveDoubleUnderscore.has(key), lc = key.toLowerCase(), caseInsensitive = config.insensitiveDoubleUnderscore.has(lc);
31
32
  if (caseSensitive || caseInsensitive) {
32
33
  // @ts-expect-error abstract class
33
- new doubleUnderscore_1.DoubleUnderscoreToken(p1, caseSensitive, config, accum);
34
+ new doubleUnderscore_1.DoubleUnderscoreToken(key, caseSensitive, Boolean(p2), config, accum);
34
35
  return `\0${accum.length - 1}${caseInsensitive && (aliases?.[lc] ?? /* istanbul ignore next */ lc) === 'toc' ? 'u' : 'n'}\x7F`;
35
36
  }
36
37
  return m;
@@ -20,9 +20,10 @@ const regexImg = /^((?:(?!\0\d+!\x7F)[^\n[\]{}|])+)(\||\0\d+!\x7F)([\s\S]*)$/u;
20
20
  * @param wikitext
21
21
  * @param config
22
22
  * @param accum
23
+ * @param page 页面名称
23
24
  * @param tidy 是否整理链接
24
25
  */
25
- const parseLinks = (wikitext, config, accum, tidy) => {
26
+ const parseLinks = (wikitext, config, accum, page, tidy) => {
26
27
  /^\s*(?:ftp:\/\/|\/\/)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
27
28
  config.regexLinks ??= new RegExp(String.raw `^\s*(?:${config.protocol}|//)`, 'iu');
28
29
  const regex = config.inExt
@@ -59,7 +60,7 @@ const parseLinks = (wikitext, config, accum, tidy) => {
59
60
  }
60
61
  const { ns, valid,
61
62
  /* NOT FOR BROWSER */
62
- interwiki, } = index_1.default.normalizeTitle(trimmed, 0, false, config, { halfParsed: true, temporary: true, decode: true, selfLink: true });
63
+ interwiki, } = index_1.default.normalizeTitle(trimmed, 0, false, config, { halfParsed: true, temporary: true, decode: true, selfLink: true, page });
63
64
  if (!valid) {
64
65
  s += `[[${x}`;
65
66
  continue;
@@ -87,7 +88,7 @@ const parseLinks = (wikitext, config, accum, tidy) => {
87
88
  break;
88
89
  }
89
90
  }
90
- text = (0, exports.parseLinks)(text, config, accum, tidy);
91
+ text = (0, exports.parseLinks)(text, config, accum, page, tidy);
91
92
  if (!found) {
92
93
  s += `[[${link}${delimiter}${text}`;
93
94
  continue;
@@ -21,7 +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.normalizeTitle(mt[3], 0, false, config, { halfParsed: true, temporary: true, decode: true }).valid) {
24
+ && index_1.default.normalizeTitle(mt[3], 0, false, config, { halfParsed: true, temporary: true, decode: true, page: '' }).valid) {
25
25
  text = `\0${accum.length}o\x7F${text.slice(mt[0].length)}`;
26
26
  // @ts-expect-error abstract class
27
27
  new redirect_1.RedirectToken(...mt.slice(1), config, accum);
@@ -10,15 +10,13 @@ const attributes_1 = require("../lib/attributes");
10
10
  /**
11
11
  * type和name选择器
12
12
  * @param selector
13
- * @param type
14
- * @param name
15
13
  */
16
- const basic = (selector, type, name) => {
14
+ const basic = (selector) => {
17
15
  if (selector.includes('#')) {
18
- const i = selector.indexOf('#');
19
- return (i === 0 || selector.slice(0, i) === type) && selector.slice(i + 1) === name;
16
+ const i = selector.indexOf('#'), targetType = selector.slice(0, i), targetName = selector.slice(i + 1);
17
+ return (type, name) => (i === 0 || type === targetType) && name === targetName;
20
18
  }
21
- return !selector || selector === type;
19
+ return selector ? (type) => type === selector : () => true;
22
20
  };
23
21
  /* NOT FOR BROWSER */
24
22
  const simplePseudos = new Set([
@@ -174,7 +172,7 @@ const matches = (token, step, scope, has) => {
174
172
  }
175
173
  return token === scope;
176
174
  default:
177
- return basic(selector, type, name);
175
+ return basic(selector)(type, name);
178
176
  }
179
177
  }
180
178
  else if (selector.length === 4) { // 情形2:属性选择器
@@ -460,8 +458,8 @@ const getCondition = (selector, scope, has) => {
460
458
  return checkToken(selector, scope, has);
461
459
  }
462
460
  /* NOT FOR BROWSER END */
463
- const parts = selector.split(',');
464
- return (({ type, name }) => parts.some(str => basic(str.trim(), type, name)));
461
+ const parts = selector.split(',').map(str => basic(str.trim()));
462
+ return (({ type, name }) => parts.some(condition => condition(type, name)));
465
463
  };
466
464
  exports.getCondition = getCondition;
467
465
  constants_1.parsers['parseSelector'] = __filename;
package/dist/src/arg.js CHANGED
@@ -158,13 +158,12 @@ let ArgToken = (() => {
158
158
  argDefault.setAttribute('aIndex', index);
159
159
  const childErrors = argDefault.lint(index, re);
160
160
  if (childErrors.length > 0) {
161
- errors.push(...childErrors);
161
+ Array.prototype.push.apply(errors, childErrors);
162
162
  }
163
163
  }
164
- const rules = ['no-ignored', 'no-arg'], { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, s = rules.map(rule => lintConfig.getSeverity(rule, 'arg'));
164
+ const rules = ['no-ignored', 'no-arg'], { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, rect = new rect_1.BoundingRect(this, start), s = rules.map(rule => lintConfig.getSeverity(rule, 'arg'));
165
165
  if (s[0] && rest.length > 0) {
166
- const rect = new rect_1.BoundingRect(this, start);
167
- errors.push(...rest.map(child => {
166
+ Array.prototype.push.apply(errors, rest.map(child => {
168
167
  const e = (0, lint_1.generateForChild)(child, rect, rules[0], 'invisible-triple-braces', s[0]);
169
168
  e.startIndex--;
170
169
  e.startCol--;
@@ -178,7 +177,7 @@ let ArgToken = (() => {
178
177
  }));
179
178
  }
180
179
  if (s[1] && !this.getAttribute('include')) {
181
- const e = (0, lint_1.generateForSelf)(this, { start }, rules[1], 'unexpected-argument', s[1]);
180
+ const e = (0, lint_1.generateForSelf)(this, rect, rules[1], 'unexpected-argument', s[1]);
182
181
  if (computeEditInfo && argDefault) {
183
182
  e.suggestions = [(0, lint_1.fixBy)(e, 'expand', argDefault.text())];
184
183
  }
@@ -261,8 +260,7 @@ let ArgToken = (() => {
261
260
  * @param name new argument name / 新参数名
262
261
  */
263
262
  setName(name) {
264
- const { childNodes } = index_1.default
265
- .parse(name, this.getAttribute('include'), 2, this.getAttribute('config'));
263
+ const { childNodes } = index_1.default.parseWithRef(name, this, 2);
266
264
  this.firstChild.safeReplaceChildren(childNodes);
267
265
  }
268
266
  /**
@@ -276,8 +274,7 @@ let ArgToken = (() => {
276
274
  this.removeAt(1);
277
275
  return;
278
276
  }
279
- const root = index_1.default
280
- .parse(value, this.getAttribute('include'), undefined, this.getAttribute('config')), { childNodes: [, oldDefault] } = this;
277
+ const { childNodes: [, oldDefault] } = this, root = index_1.default.parseWithRef(value, this);
281
278
  if (oldDefault) {
282
279
  oldDefault.safeReplaceChildren(root.childNodes);
283
280
  }
@@ -46,9 +46,11 @@ const rect_1 = require("../lib/rect");
46
46
  const index_1 = __importDefault(require("../index"));
47
47
  const index_2 = require("./index");
48
48
  const atom_1 = require("./atom");
49
+ /* NOT FOR BROWSER ONLY */
50
+ const document_1 = require("../lib/document");
51
+ /* NOT FOR BROWSER ONLY END */
49
52
  /* NOT FOR BROWSER */
50
53
  const debug_1 = require("../util/debug");
51
- const document_1 = require("../lib/document");
52
54
  const fixed_1 = require("../mixin/fixed");
53
55
  const cached_1 = require("../mixin/cached");
54
56
  const stages = { 'ext-attr': 0, 'html-attr': 2, 'table-attr': 3 }, ariaAttrs = new Set(['aria-describedby', 'aria-flowto', 'aria-labelledby', 'aria-owns']);
@@ -138,6 +140,8 @@ let AttributeToken = (() => {
138
140
  valueToken.setAttribute('stage', constants_1.MAX_STAGE - 1);
139
141
  }
140
142
  else if (tag === 'gallery' && key === 'caption'
143
+ || tag === 'ref' && key === 'details'
144
+ || (tag === 'mapframe' || tag === 'maplink') && key === 'text'
141
145
  || tag === 'choose' && (key === 'before' || key === 'after')) {
142
146
  const newConfig = {
143
147
  ...config,
@@ -319,6 +323,30 @@ let AttributeToken = (() => {
319
323
  if (s[1] && sharable_1.obsoleteAttrs[tag]?.has(name)) {
320
324
  errors.push((0, lint_1.generateForChild)(firstChild, rect, rules[1], 'obsolete-attribute', s[1]));
321
325
  }
326
+ /* NOT FOR BROWSER ONLY */
327
+ const rule = 'invalid-css', sError = lintConfig.getSeverity(rule), sWarn = lintConfig.getSeverity(rule, 'warn');
328
+ if (document_1.cssLSP
329
+ && (sError || sWarn)
330
+ && name === 'style'
331
+ && lastChild.length === 1 && lastChild.firstChild.type === 'text') {
332
+ const root = this.getRootNode(), textDoc = new document_1.EmbeddedCSSDocument(root, lastChild);
333
+ Array.prototype.push.apply(errors, document_1.cssLSP.doValidation(textDoc, textDoc.styleSheet)
334
+ .filter(({ code, severity }) => code !== 'css-ruleorselectorexpected' && code !== 'emptyRules'
335
+ && (severity === 1 ? sError : sWarn))
336
+ .map(({ range: { start: { line, character }, end }, message, severity, code }) => ({
337
+ code: code,
338
+ rule,
339
+ message,
340
+ severity: (severity === 1 ? sError : sWarn),
341
+ startLine: line,
342
+ startCol: character,
343
+ startIndex: root.indexFromPos(line, character),
344
+ endLine: end.line,
345
+ endCol: end.character,
346
+ endIndex: root.indexFromPos(end.line, end.character),
347
+ })));
348
+ }
349
+ /* NOT FOR BROWSER ONLY END */
322
350
  return errors;
323
351
  }
324
352
  }
@@ -357,10 +385,10 @@ let AttributeToken = (() => {
357
385
  /* PRINT ONLY END */
358
386
  /* NOT FOR BROWSER */
359
387
  cloneNode() {
360
- const [key, value] = this.cloneChildNodes(), k = key.toString(), config = this.getAttribute('config');
388
+ const [key, value] = this.cloneChildNodes(), k = key.toString();
361
389
  return debug_1.Shadow.run(() => {
362
390
  // @ts-expect-error abstract class
363
- const token = new AttributeToken(this.type, this.tag, k, this.#equal, '', this.#quotes, config);
391
+ const token = new AttributeToken(this.type, this.tag, k, this.#equal, '', this.#quotes, this.getAttribute('config'));
364
392
  token.firstChild.safeReplaceWith(key);
365
393
  token.lastChild.safeReplaceWith(value);
366
394
  return token;
@@ -401,7 +429,7 @@ let AttributeToken = (() => {
401
429
  else if (value.includes('"') && value.includes(`'`)) {
402
430
  throw new RangeError('Attribute values cannot contain single and double quotes simultaneously!');
403
431
  }
404
- const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(value, this.getAttribute('include'), stages[type] + 1, config);
432
+ const { childNodes } = index_1.default.parseWithRef(value, this, stages[type] + 1);
405
433
  lastChild.safeReplaceChildren(childNodes);
406
434
  if (value.includes('"')) {
407
435
  this.#quotes = [`'`, `'`];
@@ -421,11 +449,12 @@ let AttributeToken = (() => {
421
449
  * @throws `Error` title和alt属性不能更名
422
450
  */
423
451
  rename(key) {
424
- if (this.name === 'title' || this.name === 'alt' && this.tag === 'img') {
425
- throw new Error(`${this.name} attribute cannot be renamed!`);
452
+ const { type, name, tag, firstChild } = this;
453
+ if (name === 'title' || name === 'alt' && tag === 'img') {
454
+ throw new Error(`${name} attribute cannot be renamed!`);
426
455
  }
427
- const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(key, this.getAttribute('include'), stages[this.type] + 1, config);
428
- this.firstChild.safeReplaceChildren(childNodes);
456
+ const { childNodes } = index_1.default.parseWithRef(key, this, stages[type] + 1);
457
+ firstChild.safeReplaceChildren(childNodes);
429
458
  }
430
459
  /** @private */
431
460
  toHtmlInternal() {
@@ -294,7 +294,7 @@ let AttributesToken = (() => {
294
294
  const value = attr.getValue();
295
295
  return [attr, value === true ? '' : value];
296
296
  });
297
- errors.push(...pairs.map(([attr, value], i) => {
297
+ Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
298
298
  const e = (0, lint_1.generateForChild)(attr, rect, rules[1], index_1.default.msg('duplicate-attribute', key), severity);
299
299
  if (computeEditInfo || fix) {
300
300
  const remove = (0, lint_1.fixByRemove)(e);
@@ -108,9 +108,12 @@ let ConverterToken = (() => {
108
108
  new converterRule_1.ConverterRuleToken(rules.join(';'), false, config, accum));
109
109
  }
110
110
  else {
111
- this.append(firstRuleToken, ...rules.slice(1)
112
- // @ts-expect-error abstract class
113
- .map((rule) => new converterRule_1.ConverterRuleToken(rule, true, config, accum)));
111
+ this.safeAppend([
112
+ firstRuleToken,
113
+ ...rules.slice(1)
114
+ // @ts-expect-error abstract class
115
+ .map((rule) => new converterRule_1.ConverterRuleToken(rule, true, config, accum)),
116
+ ]);
114
117
  }
115
118
  /* NOT FOR BROWSER */
116
119
  this.protectChildren(0);
@@ -232,8 +232,7 @@ let ConverterRuleToken = (() => {
232
232
  * @param to target of language conversion / 转换目标
233
233
  */
234
234
  setTo(to) {
235
- const { childNodes } = index_1.default
236
- .parse(to, this.getAttribute('include'), undefined, this.getAttribute('config'));
235
+ const { childNodes } = index_1.default.parseWithRef(to, this);
237
236
  this.lastChild.safeReplaceChildren(childNodes);
238
237
  }
239
238
  /**
@@ -243,9 +242,8 @@ let ConverterRuleToken = (() => {
243
242
  * @param variant language variant / 语言变体
244
243
  */
245
244
  setVariant(variant) {
246
- const config = this.getAttribute('config');
247
245
  if (this.length === 1) {
248
- super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(variant, 'converter-rule-variant', config)), 0);
246
+ super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(variant, 'converter-rule-variant', this.getAttribute('config'))), 0);
249
247
  }
250
248
  else {
251
249
  this.childNodes[this.length - 2].setText(variant);
@@ -263,9 +261,9 @@ let ConverterRuleToken = (() => {
263
261
  if (!variant) {
264
262
  throw new Error('Please specify the language variant first!');
265
263
  }
266
- const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(from, this.getAttribute('include'), undefined, config);
264
+ const { childNodes } = index_1.default.parseWithRef(from, this);
267
265
  if (!unidirectional) {
268
- super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'converter-rule-from', config)), 0);
266
+ super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'converter-rule-from', this.getAttribute('config'))), 0);
269
267
  }
270
268
  this.firstChild.safeReplaceChildren(childNodes);
271
269
  }
@@ -201,9 +201,8 @@ let ExtLinkToken = (() => {
201
201
  * @param str text of the link / 链接显示文字
202
202
  */
203
203
  setLinkText(str) {
204
- const root = index_1.default
205
- .parse(str, this.getAttribute('include'), 7, this.getAttribute('config'));
206
- if (this.length === 1) {
204
+ const { length, lastChild } = this, root = index_1.default.parseWithRef(str, this, 7);
205
+ if (length === 1) {
207
206
  root.type = 'ext-link-text';
208
207
  root.setAttribute('acceptable', {
209
208
  'Stage-7': ':', ConverterToken: ':',
@@ -211,7 +210,7 @@ let ExtLinkToken = (() => {
211
210
  this.insertAt(root);
212
211
  }
213
212
  else {
214
- this.lastChild.safeReplaceChildren(root.childNodes);
213
+ lastChild.safeReplaceChildren(root.childNodes);
215
214
  }
216
215
  this.#space ||= ' ';
217
216
  }
@@ -100,8 +100,7 @@ let HeadingToken = (() => {
100
100
  if (text.length > 1 && text.startsWith('=') && text.endsWith('=')) {
101
101
  throw new Error('Please use HeadingToken.setLevel method to change the level of the heading!');
102
102
  }
103
- const { childNodes } = index_1.default
104
- .parse(text, this.getAttribute('include'), undefined, this.getAttribute('config'));
103
+ const { childNodes } = index_1.default.parseWithRef(text, this);
105
104
  this.firstChild.safeReplaceChildren(childNodes);
106
105
  }
107
106
  /**