wikiparser-node 1.5.1 → 1.5.2

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.
@@ -830,8 +830,7 @@
830
830
  "page=$1": "page",
831
831
  "page $1": "page",
832
832
  "页数=$1": "page",
833
- "$1页": "page",
834
- "lossy=$1": "lossy"
833
+ "$1页": "page"
835
834
  },
836
835
  "variants": [
837
836
  "zh",
@@ -1217,8 +1217,7 @@
1217
1217
  "text-bottom": "text-bottom",
1218
1218
  "lang=$1": "lang",
1219
1219
  "page=$1": "page",
1220
- "page $1": "page",
1221
- "lossy=$1": "lossy"
1220
+ "page $1": "page"
1222
1221
  },
1223
1222
  "variants": []
1224
1223
  }
@@ -285,10 +285,6 @@ class AstElement extends node_1.AstNode {
285
285
  return json;
286
286
  }
287
287
  /* NOT FOR BROWSER */
288
- /** @private */
289
- matchesTypes(types) {
290
- return types.has(this.type);
291
- }
292
288
  /** 销毁 */
293
289
  destroy() {
294
290
  this.parentNode?.destroy();
package/dist/lib/text.js CHANGED
@@ -121,8 +121,18 @@ class AstText extends node_1.AstNode {
121
121
  throw new Error('无法对孤立文本节点进行语法分析!');
122
122
  /* NOT FOR BROWSER END */
123
123
  }
124
+ const { type, name, parentNode: grandparent } = parentNode, nowiki = name === 'nowiki' || name === 'pre';
125
+ let isHtmlAttrVal = false;
126
+ if (type === 'attr-value') {
127
+ const { type: grandType, name: grandName, tag } = grandparent;
128
+ if (grandType !== 'ext-attr') {
129
+ isHtmlAttrVal = true;
130
+ }
131
+ else if (tag === 'choose' && (grandName === 'before' || grandName === 'after')) {
132
+ return [];
133
+ }
134
+ }
124
135
  const { NowikiToken } = require('../src/nowiki');
125
- const { type, name } = parentNode, nowiki = name === 'nowiki' || name === 'pre', isHtmlAttrVal = type === 'attr-value' && parentNode.parentNode.type !== 'ext-attr';
126
136
  let errorRegex;
127
137
  if (type === 'ext-inner' && (name === 'pre' || parentNode instanceof NowikiToken)) {
128
138
  errorRegex = new RegExp(`<\\s*(?:\\/\\s*)${nowiki ? '' : '?'}(${name})\\b`, 'giu');
@@ -9,13 +9,13 @@ export declare class Title {
9
9
  /** 不含命名空间的标题主体部分 */
10
10
  get main(): string;
11
11
  set main(title: string);
12
+ /** 扩展名 */
13
+ get extension(): string | undefined;
14
+ set extension(extension: string | undefined);
12
15
  /** 命名空间前缀 */
13
16
  get prefix(): string;
14
17
  /** 完整标题 */
15
18
  get title(): string;
16
- /** 扩展名 */
17
- get extension(): string | undefined;
18
- set extension(extension: string | undefined);
19
19
  /**
20
20
  * @param title 标题(含或不含命名空间前缀)
21
21
  * @param defaultNs 命名空间
package/dist/lib/title.js CHANGED
@@ -11,14 +11,15 @@ class Title {
11
11
  fragment;
12
12
  /** @private */
13
13
  encoded = false;
14
+ #main;
14
15
  /* NOT FOR BROWSER */
15
16
  #namespaces;
16
- #main;
17
17
  interwiki = '';
18
18
  /** @private */
19
19
  conversionTable = new Map();
20
20
  /** @private */
21
21
  redirects = new Map();
22
+ /* NOT FOR BROWSER END */
22
23
  /** 不含命名空间的标题主体部分 */
23
24
  get main() {
24
25
  return this.#main;
@@ -27,6 +28,16 @@ class Title {
27
28
  title = title.replace(/_/gu, ' ').trim();
28
29
  this.#main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
29
30
  }
31
+ /** 扩展名 */
32
+ get extension() {
33
+ const { main } = this, i = main.lastIndexOf('.');
34
+ return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
35
+ }
36
+ /* NOT FOR BROWSER */
37
+ set extension(extension) {
38
+ const { main } = this, i = main.lastIndexOf('.');
39
+ this.main = `${i === -1 ? main : main.slice(0, i)}.${extension}`;
40
+ }
30
41
  /** 命名空间前缀 */
31
42
  get prefix() {
32
43
  const namespace = this.#namespaces[this.ns];
@@ -44,15 +55,6 @@ class Title {
44
55
  title = `${prefix}${this.main}`.replace(/ /gu, '_');
45
56
  return this.redirects.get(title) ?? title;
46
57
  }
47
- /** 扩展名 */
48
- get extension() {
49
- const { main } = this, i = main.lastIndexOf('.');
50
- return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
51
- }
52
- set extension(extension) {
53
- const { main } = this, i = main.lastIndexOf('.');
54
- this.main = `${i === -1 ? main : main.slice(0, i)}.${extension}`;
55
- }
56
58
  /* NOT FOR BROWSER END */
57
59
  /**
58
60
  * @param title 标题(含或不含命名空间前缀)
@@ -112,9 +114,9 @@ class Title {
112
114
  }
113
115
  this.valid = Boolean(title || this.interwiki || selfLink && this.fragment !== undefined)
114
116
  && !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|]|%[\da-f]{2}/iu.test(title);
117
+ this.main = title;
115
118
  /* NOT FOR BROWSER */
116
119
  this.#namespaces = config.namespaces;
117
- this.main = title;
118
120
  Object.defineProperties(this, {
119
121
  valid: { writable: false },
120
122
  encoded: { enumerable: false, writable: false },
@@ -23,8 +23,8 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
23
23
  if (!dt) {
24
24
  return text;
25
25
  }
26
- const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+x\x7F/gu;
27
- let regex = fullRegex, ex = regex.exec(text), lt = 0, lc = 0;
26
+ const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
27
+ let regex = fullRegex, ex = regex.exec(text), lt = 0, lb = false, li = false, lc = 0;
28
28
  /**
29
29
  * 创建`DdToken`
30
30
  * @param syntax `:`
@@ -35,6 +35,18 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
35
35
  new dd_1.DdToken(syntax, config, accum);
36
36
  return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + syntax.length)}`;
37
37
  };
38
+ /**
39
+ * 更新 `lt`
40
+ * @param closing 是否是闭合标签
41
+ */
42
+ const update = (closing) => {
43
+ if (!closing) {
44
+ lt++;
45
+ }
46
+ else if (lt) {
47
+ lt--;
48
+ }
49
+ };
38
50
  while (ex && dt) {
39
51
  const { 0: syntax, index } = ex;
40
52
  if (syntax === '-{') {
@@ -53,15 +65,21 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
53
65
  regex.lastIndex = lastIndex;
54
66
  }
55
67
  }
56
- else if (syntax.startsWith('\0')) {
68
+ else if (syntax.endsWith('x\x7F')) {
57
69
  const { name, closing, selfClosing } = accum[Number(syntax.slice(1, -2))];
58
70
  if (!selfClosing || normalTags.includes(name)) {
59
- if (!closing) {
60
- lt++;
61
- }
62
- else if (lt) {
63
- lt--;
64
- }
71
+ update(closing);
72
+ }
73
+ }
74
+ else if (syntax.endsWith('q\x7F')) {
75
+ const { bold, italic } = accum[Number(syntax.slice(1, -2))];
76
+ if (bold) {
77
+ update(lb);
78
+ lb = !lb;
79
+ }
80
+ if (italic) {
81
+ update(li);
82
+ li = !li;
65
83
  }
66
84
  }
67
85
  else if (lt === 0) { // syntax === ':'
@@ -24,6 +24,8 @@ export declare abstract class AttributeToken extends Token {
24
24
  abstract get parentElement(): AttributesToken | undefined;
25
25
  abstract get nextElementSibling(): AtomToken | this | undefined;
26
26
  abstract get previousElementSibling(): AtomToken | this | undefined;
27
+ /** 标签名 */
28
+ get tag(): string;
27
29
  /** 引号是否匹配 */
28
30
  get balanced(): boolean;
29
31
  set balanced(value: boolean);
@@ -232,7 +232,7 @@ let AttributeToken = (() => {
232
232
  #equal;
233
233
  #quotes;
234
234
  /* NOT FOR BROWSER END */
235
- /** @private */
235
+ /** 标签名 */
236
236
  get tag() {
237
237
  return this.#tag;
238
238
  }
@@ -37,7 +37,7 @@ export declare abstract class ImageParameterToken extends Token {
37
37
  get height(): string | undefined;
38
38
  set height(height: string | undefined);
39
39
  /** @param str 图片参数 */
40
- constructor(str: string, config?: Parser.Config, accum?: Token[]);
40
+ constructor(str: string, extension: string | undefined, config?: Parser.Config, accum?: Token[]);
41
41
  /** @override */
42
42
  text(): string;
43
43
  /** @override */
@@ -8,7 +8,7 @@ const constants_1 = require("../util/constants");
8
8
  const index_1 = require("../index");
9
9
  const index_2 = require("./index");
10
10
  exports.galleryParams = new Set(['alt', 'link', 'lang', 'page', 'caption']);
11
- function validate(key, val, config = index_1.default.getConfig(), halfParsed = false) {
11
+ function validate(key, val, config, halfParsed = false, ext) {
12
12
  val = val.trim();
13
13
  let value = val.replace(/\0\d+t\x7F/gu, '').trim();
14
14
  switch (key) {
@@ -31,11 +31,13 @@ function validate(key, val, config = index_1.default.getConfig(), halfParsed = f
31
31
  return title.valid && title;
32
32
  }
33
33
  case 'lang':
34
- return !value || config.variants.includes(value);
34
+ return (ext === 'svg' || ext === 'svgz') && !/[^a-z\d-]/u.test(value);
35
35
  case 'alt':
36
36
  case 'class':
37
37
  case 'manualthumb':
38
38
  return true;
39
+ case 'page':
40
+ return (ext === 'djvu' || ext === 'djv') && Number(value) > 0;
39
41
  default:
40
42
  return !Number.isNaN(Number(value));
41
43
  }
@@ -44,6 +46,7 @@ function validate(key, val, config = index_1.default.getConfig(), halfParsed = f
44
46
  class ImageParameterToken extends index_2.Token {
45
47
  type = 'image-parameter';
46
48
  #syntax = '';
49
+ #extension;
47
50
  /* NOT FOR BROWSER END */
48
51
  /** 图片链接 */
49
52
  get link() {
@@ -106,7 +109,7 @@ class ImageParameterToken extends index_2.Token {
106
109
  }
107
110
  /* NOT FOR BROWSER END */
108
111
  /** @param str 图片参数 */
109
- constructor(str, config = index_1.default.getConfig(), accum = []) {
112
+ constructor(str, extension, config = index_1.default.getConfig(), accum = []) {
110
113
  let mt;
111
114
  const regexes = Object.entries(config.img).map(([syntax, param]) => [
112
115
  syntax,
@@ -115,7 +118,8 @@ class ImageParameterToken extends index_2.Token {
115
118
  ]), param = regexes.find(([, key, regex]) => {
116
119
  mt = regex.exec(str);
117
120
  return mt
118
- && (mt.length !== 4 || validate(key, mt[2], config, true) !== false);
121
+ && (mt.length !== 4
122
+ || validate(key, mt[2], config, true, extension) !== false);
119
123
  });
120
124
  // @ts-expect-error mt already assigned
121
125
  if (param && mt) {
@@ -135,6 +139,8 @@ class ImageParameterToken extends index_2.Token {
135
139
  super(str, { ...config, excludes: [...config.excludes ?? [], 'list'] }, accum);
136
140
  this.setAttribute('name', 'caption');
137
141
  this.setAttribute('stage', 7);
142
+ /* NOT FOR BROWSER */
143
+ this.#extension = extension;
138
144
  }
139
145
  /** @private */
140
146
  afterBuild() {
@@ -201,7 +207,7 @@ class ImageParameterToken extends index_2.Token {
201
207
  const cloned = this.cloneChildNodes(), config = this.getAttribute('config');
202
208
  return debug_1.Shadow.run(() => {
203
209
  // @ts-expect-error abstract class
204
- const token = new ImageParameterToken(this.#syntax.replace('$1', ''), config);
210
+ const token = new ImageParameterToken(this.#syntax.replace('$1', ''), this.#extension, config);
205
211
  token.replaceChildren(...cloned);
206
212
  token.setAttribute('name', this.name);
207
213
  token.setAttribute('syntax', this.#syntax);
@@ -15,6 +15,8 @@ export declare abstract class FileToken extends LinkBaseToken {
15
15
  abstract get lastChild(): AtomToken | ImageParameterToken;
16
16
  abstract get children(): [AtomToken, ...ImageParameterToken[]];
17
17
  abstract get lastElementChild(): AtomToken | ImageParameterToken;
18
+ /** 扩展名 */
19
+ get extension(): string | undefined;
18
20
  /** 图片链接 */
19
21
  get link(): string | Title;
20
22
  set link(value: string);
@@ -42,6 +42,12 @@ const explode = (start, end, separator, str) => {
42
42
  */
43
43
  class FileToken extends base_1.LinkBaseToken {
44
44
  type = 'file';
45
+ /* NOT FOR BROWSER END */
46
+ /** 扩展名 */
47
+ get extension() {
48
+ return this.getTitle().extension;
49
+ }
50
+ /* NOT FOR BROWSER */
45
51
  /** 图片链接 */
46
52
  get link() {
47
53
  return this.getArg('link')?.link ?? super.link;
@@ -93,9 +99,10 @@ class FileToken extends base_1.LinkBaseToken {
93
99
  /* NOT FOR BROWSER */
94
100
  this.setAttribute('acceptable', { AtomToken: 0, ImageParameterToken: '1:' });
95
101
  /* NOT FOR BROWSER END */
102
+ const { extension } = this;
96
103
  this.append(...explode('-{', '}-', '|', text).map(
97
104
  // @ts-expect-error abstract class
98
- part => new imageParameter_1.ImageParameterToken(part, config, accum)));
105
+ part => new imageParameter_1.ImageParameterToken(part, extension, config, accum)));
99
106
  }
100
107
  /** @override */
101
108
  lint(start = this.getAbsoluteIndex()) {
@@ -245,7 +252,7 @@ class FileToken extends base_1.LinkBaseToken {
245
252
  }
246
253
  const parameter = debug_1.Shadow.run(
247
254
  // @ts-expect-error abstract class
248
- () => new imageParameter_1.ImageParameterToken(syntax.replace('$1', ''), config));
255
+ () => new imageParameter_1.ImageParameterToken(syntax.replace('$1', ''), this.extension, config));
249
256
  if (free) {
250
257
  const { childNodes } = index_1.default.parse(value, this.getAttribute('include'), undefined, config);
251
258
  parameter.replaceChildren(...childNodes);
@@ -54,12 +54,6 @@ export declare abstract class TdToken extends TableBaseToken {
54
54
  isIndependent(): boolean;
55
55
  /** @override */
56
56
  cloneNode(): this;
57
- /**
58
- * @override
59
- * @param syntax 表格语法
60
- * @param esc 是否需要转义
61
- */
62
- setSyntax(syntax: string, esc?: boolean): void;
63
57
  /** 改为独占一行 */
64
58
  independence(): void;
65
59
  /**
@@ -251,11 +251,7 @@ let TdToken = (() => {
251
251
  super.setAttribute(key, value);
252
252
  }
253
253
  }
254
- /**
255
- * @override
256
- * @param syntax 表格语法
257
- * @param esc 是否需要转义
258
- */
254
+ /** @private */
259
255
  setSyntax(syntax, esc = false) {
260
256
  const aliases = { td: '\n|', th: '\n!', caption: '\n|+' };
261
257
  super.setSyntax(aliases[syntax] ?? syntax, esc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikiparser-node",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "A Node.js parser for MediaWiki markup with AST",
5
5
  "keywords": [
6
6
  "mediawiki",