wikiparser-node 0.8.1 → 0.9.0-m

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/config/default.json +0 -1
  2. package/config/llwiki.json +0 -35
  3. package/config/moegirl.json +1 -44
  4. package/config/zhwiki.json +0 -466
  5. package/i18n/zh-hans.json +44 -0
  6. package/i18n/zh-hant.json +44 -0
  7. package/index.js +16 -256
  8. package/lib/element.js +29 -504
  9. package/lib/node.js +6 -542
  10. package/lib/text.js +10 -127
  11. package/lib/title.js +7 -32
  12. package/mixin/hidden.js +0 -3
  13. package/package.json +8 -8
  14. package/parser/brackets.js +8 -3
  15. package/parser/commentAndExt.js +1 -5
  16. package/parser/converter.js +0 -1
  17. package/parser/externalLinks.js +0 -1
  18. package/parser/hrAndDoubleUnderscore.js +0 -1
  19. package/parser/html.js +0 -1
  20. package/parser/links.js +5 -6
  21. package/parser/list.js +0 -1
  22. package/parser/magicLinks.js +0 -1
  23. package/parser/quotes.js +1 -2
  24. package/parser/table.js +0 -1
  25. package/src/arg.js +9 -119
  26. package/src/atom/hidden.js +0 -2
  27. package/src/atom/index.js +0 -17
  28. package/src/attribute.js +7 -181
  29. package/src/attributes.js +8 -312
  30. package/src/converter.js +2 -108
  31. package/src/converterFlags.js +3 -190
  32. package/src/converterRule.js +3 -187
  33. package/src/extLink.js +2 -121
  34. package/src/gallery.js +5 -62
  35. package/src/hasNowiki/index.js +0 -12
  36. package/src/hasNowiki/pre.js +0 -12
  37. package/src/heading.js +7 -58
  38. package/src/html.js +18 -127
  39. package/src/imageParameter.js +61 -200
  40. package/src/imagemap.js +7 -66
  41. package/src/imagemapLink.js +2 -14
  42. package/src/index.js +11 -534
  43. package/src/link/category.js +1 -37
  44. package/src/link/file.js +18 -168
  45. package/src/link/galleryImage.js +6 -64
  46. package/src/link/index.js +9 -277
  47. package/src/magicLink.js +2 -85
  48. package/src/nested/choose.js +0 -1
  49. package/src/nested/combobox.js +0 -1
  50. package/src/nested/index.js +3 -33
  51. package/src/nested/references.js +0 -1
  52. package/src/nowiki/comment.js +3 -27
  53. package/src/nowiki/dd.js +1 -47
  54. package/src/nowiki/doubleUnderscore.js +1 -31
  55. package/src/nowiki/hr.js +1 -20
  56. package/src/nowiki/index.js +3 -25
  57. package/src/nowiki/list.js +2 -5
  58. package/src/nowiki/noinclude.js +0 -14
  59. package/src/nowiki/quote.js +3 -17
  60. package/src/onlyinclude.js +1 -26
  61. package/src/paramTag/index.js +4 -27
  62. package/src/paramTag/inputbox.js +1 -4
  63. package/src/parameter.js +7 -149
  64. package/src/syntax.js +0 -68
  65. package/src/table/index.js +4 -942
  66. package/src/table/td.js +9 -230
  67. package/src/table/tr.js +4 -249
  68. package/src/tagPair/ext.js +13 -27
  69. package/src/tagPair/include.js +0 -24
  70. package/src/tagPair/index.js +2 -51
  71. package/src/transclude.js +38 -528
  72. package/util/lint.js +8 -7
  73. package/util/string.js +12 -44
  74. package/README.md +0 -39
  75. package/lib/ranges.js +0 -130
  76. package/mixin/attributeParent.js +0 -117
  77. package/mixin/fixedToken.js +0 -40
  78. package/mixin/singleLine.js +0 -31
  79. package/mixin/sol.js +0 -65
  80. package/parser/selector.js +0 -177
  81. package/src/charinsert.js +0 -97
  82. package/tool/index.js +0 -1202
  83. package/util/debug.js +0 -73
package/lib/text.js CHANGED
@@ -4,7 +4,7 @@ const Parser = require('..'),
4
4
  AstNode = require('./node'),
5
5
  AstElement = require('./element');
6
6
 
7
- const errorSyntax = /https?:|\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|<\s*\/?([a-z]\w*)(?=[\s/>])/giu,
7
+ const errorSyntax = /https?:\/\/|\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|<\s*\/?([a-z]\w*)(?=[\s/>])/giu,
8
8
  errorSyntaxUrl = /\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|<\s*\/?([a-z]\w*)(?=[\s/>])/giu,
9
9
  disallowedTags = [
10
10
  'html',
@@ -61,24 +61,13 @@ const errorSyntax = /https?:|\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|<
61
61
 
62
62
  /** 文本节点 */
63
63
  class AstText extends AstNode {
64
- #config;
65
64
  type = 'text';
66
65
  /** @type {string} */ data;
67
66
 
68
- /** 文本长度 */
69
- get length() {
70
- return this.data.length;
71
- }
72
-
73
67
  /** @param {string} text 包含文本 */
74
- constructor(text = '', config = Parser.getConfig()) {
68
+ constructor(text = '') {
75
69
  super();
76
- this.#config = config;
77
- Object.defineProperties(this, {
78
- data: {value: text, writable: false},
79
- childNodes: {enumerable: false, configurable: false},
80
- type: {enumerable: false, writable: false, configurable: false},
81
- });
70
+ this.data = text;
82
71
  }
83
72
 
84
73
  /** 输出字符串 */
@@ -97,20 +86,20 @@ class AstText extends AstNode {
97
86
  * @param {number} start 起始位置
98
87
  * @returns {LintError[]}
99
88
  */
100
- lint(start = 0) {
89
+ lint(start = this.getAbsoluteIndex()) {
101
90
  const {data, parentNode} = this,
102
91
  type = parentNode?.type,
103
92
  name = parentNode?.name,
104
- urlAttr = ['itemtype', 'src', 'srcset'].includes(parentNode?.parentNode?.name),
105
93
  errorRegex
106
94
  = type === 'free-ext-link' || type === 'ext-link-url' || type === 'image-parameter' && name === 'link'
107
95
  ? errorSyntaxUrl
108
96
  : errorSyntax,
109
- errors = [...data.matchAll(errorRegex)];
97
+ errors = [...data.matchAll(errorRegex)],
98
+ {ext, html} = this.getRootNode().getAttribute('config');
110
99
  if (errors.length > 0) {
111
100
  const root = this.getRootNode(),
112
101
  {top, left} = root.posFromIndex(start),
113
- tags = new Set([this.#config.ext, this.#config.html, disallowedTags].flat(2));
102
+ tags = new Set([ext, html, disallowedTags].flat(2));
114
103
  return errors.map(/** @returns {LintError} */ ({0: error, 1: prefix, 2: tag, index}) => {
115
104
  if (prefix) {
116
105
  index += prefix.length;
@@ -124,29 +113,9 @@ class AstText extends AstNode {
124
113
  {0: char, length} = error,
125
114
  endIndex = startIndex + length,
126
115
  end = char === '}' || char === ']' ? endIndex : startIndex + (char === 'h' ? 49 : 50);
127
- let severity = length > 1 ? 'error' : 'warning';
128
- if (char === 'h') {
129
- switch (type) {
130
- case 'ext-link-text':
131
- severity = 'warning';
132
- break;
133
- case 'attr-value':
134
- if (urlAttr) {
135
- return false;
136
- }
137
- break;
138
- case 'ext-inner':
139
- if (name === 'sm2' || name === 'flashmp3') {
140
- return false;
141
- }
142
- // no default
143
- }
144
- } else if (char === '<' && !tags.has(tag.toLowerCase())) {
145
- return false;
146
- }
147
- return {
148
- message: `孤立的"${char === 'h' ? error : char}"`,
149
- severity,
116
+ return (char !== 'h' || index > 0) && (char !== '<' || tags.has(tag.toLowerCase())) && {
117
+ message: Parser.msg('lonely "$1"', char === 'h' ? error : char),
118
+ severity: length > 1 ? 'error' : 'warning',
150
119
  startIndex,
151
120
  endIndex,
152
121
  startLine,
@@ -166,12 +135,7 @@ class AstText extends AstNode {
166
135
  */
167
136
  #setData(text) {
168
137
  text = String(text);
169
- const {data} = this,
170
- e = new Event('text', {bubbles: true});
171
138
  this.setAttribute('data', text);
172
- if (data !== text) {
173
- this.dispatchEvent(e, {oldText: data, newText: text});
174
- }
175
139
  }
176
140
 
177
141
  /**
@@ -181,87 +145,6 @@ class AstText extends AstNode {
181
145
  replaceData(text = '') {
182
146
  this.#setData(text);
183
147
  }
184
-
185
- /** 复制 */
186
- cloneNode() {
187
- return new AstText(this.data, this.#config);
188
- }
189
-
190
- /**
191
- * @override
192
- * @template {string} T
193
- * @param {T} key 属性键
194
- * @returns {TokenAttribute<T>}
195
- * @throws `Error` 文本节点没有子节点
196
- */
197
- getAttribute(key) {
198
- return key === 'verifyChild'
199
- ? () => {
200
- throw new Error('文本节点没有子节点!');
201
- }
202
- : super.getAttribute(key);
203
- }
204
-
205
- /**
206
- * 在后方添加字符串
207
- * @param {string} text 添加的字符串
208
- */
209
- appendData(text) {
210
- this.#setData(this.data + text);
211
- }
212
-
213
- /**
214
- * 删减字符串
215
- * @param {number} offset 起始位置
216
- * @param {number} count 删减字符数
217
- */
218
- deleteData(offset, count) {
219
- this.#setData(this.data.slice(0, offset) + this.data.slice(offset + count));
220
- }
221
-
222
- /**
223
- * 插入字符串
224
- * @param {number} offset 插入位置
225
- * @param {string} text 待插入的字符串
226
- */
227
- insertData(offset, text) {
228
- this.#setData(this.data.slice(0, offset) + text + this.data.slice(offset));
229
- }
230
-
231
- /**
232
- * 提取子串
233
- * @param {number} offset 起始位置
234
- * @param {number} count 字符数
235
- */
236
- substringData(offset, count) {
237
- return this.data.slice(offset, offset + count);
238
- }
239
-
240
- /**
241
- * 将文本子节点分裂为两部分
242
- * @param {number} offset 分裂位置
243
- * @throws `RangeError` 错误的断开位置
244
- * @throws `Error` 没有父节点
245
- */
246
- splitText(offset) {
247
- if (!Number.isInteger(offset)) {
248
- this.typeError('splitText', 'Number');
249
- } else if (offset > this.length || offset < -this.length) {
250
- throw new RangeError(`错误的断开位置!${offset}`);
251
- }
252
- const {parentNode, data} = this;
253
- if (!parentNode) {
254
- throw new Error('待分裂的文本节点没有父节点!');
255
- }
256
- const newText = new AstText(data.slice(offset), this.#config),
257
- childNodes = [...parentNode.childNodes];
258
- this.setAttribute('data', data.slice(0, offset));
259
- childNodes.splice(childNodes.indexOf(this) + 1, 0, newText);
260
- newText.setAttribute('parentNode', parentNode);
261
- parentNode.setAttribute('childNodes', childNodes);
262
- return newText;
263
- }
264
148
  }
265
149
 
266
- Parser.classes.AstText = __filename;
267
150
  module.exports = AstText;
package/lib/title.js CHANGED
@@ -1,17 +1,14 @@
1
1
  'use strict';
2
2
 
3
- const Parser = require('..');
3
+ const {decodeHtml} = require('../util/string'),
4
+ Parser = require('..');
4
5
 
5
6
  /** MediaWiki页面标题对象 */
6
7
  class Title {
7
8
  valid = true;
8
9
  ns = 0;
9
- fragment = '';
10
+ fragment;
10
11
  encoded = false;
11
- title = '';
12
- main = '';
13
- prefix = '';
14
- interwiki = '';
15
12
 
16
13
  /**
17
14
  * @param {string} title 标题(含或不含命名空间前缀)
@@ -22,9 +19,10 @@ class Title {
22
19
  constructor(title, defaultNs = 0, config = Parser.getConfig(), decode = false, selfLink = false) {
23
20
  const {namespaces, nsid} = config;
24
21
  let namespace = namespaces[defaultNs];
22
+ title = decodeHtml(title);
25
23
  if (decode && title.includes('%')) {
26
24
  try {
27
- const encoded = /%(?!5[bd]|7[b-d])[\da-f]{2}/iu.test(title);
25
+ const encoded = /%(?!21|3[ce]|5[bd]|7[b-d])[\da-f]{2}/iu.test(title);
28
26
  title = decodeURIComponent(title);
29
27
  this.encoded = encoded;
30
28
  } catch {}
@@ -34,11 +32,6 @@ class Title {
34
32
  namespace = '';
35
33
  title = title.slice(1).trim();
36
34
  }
37
- const iw = defaultNs ? undefined : Parser.isInterwiki(title, config);
38
- if (iw) {
39
- this.interwiki = iw[1].toLowerCase();
40
- title = title.slice(iw[0].length);
41
- }
42
35
  const m = title.split(':');
43
36
  if (m.length > 1) {
44
37
  const id = namespaces[nsid[m[0].trim().toLowerCase()]];
@@ -49,33 +42,15 @@ class Title {
49
42
  }
50
43
  this.ns = nsid[namespace.toLowerCase()];
51
44
  const i = title.indexOf('#');
52
- let fragment = '';
45
+ let fragment;
53
46
  if (i !== -1) {
54
47
  fragment = title.slice(i + 1).trimEnd();
55
- if (fragment.includes('%')) {
56
- try {
57
- fragment = decodeURIComponent(fragment);
58
- } catch {}
59
- } else if (fragment.includes('.')) {
60
- try {
61
- fragment = decodeURIComponent(fragment.replaceAll('.', '%'));
62
- } catch {}
63
- }
64
48
  title = title.slice(0, i).trim();
65
49
  }
66
- this.valid = Boolean(title || selfLink && fragment || this.interwiki)
50
+ this.valid = Boolean(title || selfLink && fragment !== undefined)
67
51
  && !/\0\d+[eh!+-]\x7F|[<>[\]{}|]|%[\da-f]{2}/iu.test(title);
68
52
  this.fragment = fragment;
69
- this.main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
70
- this.prefix = `${namespace}${namespace && ':'}`;
71
- this.title = `${iw ? `${this.interwiki}:` : ''}${this.prefix}${this.main.replaceAll(' ', '_')}`;
72
- }
73
-
74
- /** @override */
75
- toString() {
76
- return `${this.title}${this.fragment && '#'}${this.fragment}`;
77
53
  }
78
54
  }
79
55
 
80
- Parser.classes.Title = __filename;
81
56
  module.exports = Title;
package/mixin/hidden.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const Parser = require('..');
4
-
5
3
  /**
6
4
  * 解析后不可见的类
7
5
  * @template T
@@ -17,5 +15,4 @@ const hidden = Constructor => class extends Constructor {
17
15
  }
18
16
  };
19
17
 
20
- Parser.mixins.hidden = __filename;
21
18
  module.exports = hidden;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikiparser-node",
3
- "version": "0.8.1",
3
+ "version": "0.9.0-m",
4
4
  "description": "A Node.js parser for MediaWiki markup with AST",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -15,22 +15,22 @@
15
15
  "author": "Bhsd",
16
16
  "files": [
17
17
  "/index.js",
18
- "/parser/",
19
- "/util/",
20
- "/lib/",
21
- "/src/",
22
18
  "/config/",
19
+ "/i18n/",
20
+ "/lib/",
23
21
  "/mixin/",
24
- "/tool/"
22
+ "/parser/",
23
+ "/src/",
24
+ "/util/"
25
25
  ],
26
26
  "repository": {
27
27
  "type": "git",
28
28
  "url": "git+https://github.com/bhsd-harry/wikiparser-node.git"
29
29
  },
30
30
  "scripts": {
31
- "test": "eslint . && node test/test.js",
31
+ "test": "eslint .",
32
32
  "real": "node test/real.js",
33
- "single": "node --prof test/single.js && node --prof-process isolate-0x*-v8.log > test/processed.txt && rm isolate-0x*-v8.log"
33
+ "single": "node test/single.js"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^17.0.23",
@@ -14,6 +14,7 @@ const {removeComment} = require('../util/string'),
14
14
  */
15
15
  const parseBrackets = (text, config = Parser.getConfig(), accum = []) => {
16
16
  const source = `${config.excludes.includes('heading') ? '' : '^(\0\\d+c\x7F)*={1,6}|'}\\[\\[|\\{{2,}|-\\{(?!\\{)`,
17
+ {parserFunction: [,,, subst]} = config,
17
18
  /** @type {BracketExecArray[]} */ stack = [],
18
19
  closes = {'=': '\n', '{': '\\}{2,}|\\|', '-': '\\}-', '[': '\\]\\]'},
19
20
  /** @type {Record<string, string>} */ marks = {'!': '!', '!!': '+', '(!': '{', '!)': '}', '!-': '-', '=': '~'};
@@ -62,12 +63,17 @@ const parseBrackets = (text, config = Parser.getConfig(), accum = []) => {
62
63
  let skip = false,
63
64
  ch = 't';
64
65
  if (close.length === 3) {
65
- new ArgToken(parts.map(part => part.join('=')), config, accum);
66
+ const argParts = parts.map(part => part.join('=')),
67
+ str = argParts.length > 1 && removeComment(argParts[1]).trim();
68
+ new ArgToken(argParts, config, accum);
69
+ if (str && str.endsWith(':') && subst.includes(str.slice(0, -1).toLowerCase())) {
70
+ ch = 's';
71
+ }
66
72
  } else {
67
73
  const name = removeComment(parts[0][0]).trim();
68
74
  if (name in marks) {
69
75
  ch = marks[name]; // 标记{{!}}等
70
- } else if (/^(?:fullurl|canonicalurl|filepath):.|^server$/iu.test(name)) {
76
+ } else if (/^(?:filepath|(?:full|canonical)urle?):.|^server$/iu.test(name)) {
71
77
  ch = 'm';
72
78
  } else if (/^#vardefine:./iu.test(name)) {
73
79
  ch = 'c';
@@ -116,5 +122,4 @@ const parseBrackets = (text, config = Parser.getConfig(), accum = []) => {
116
122
  return text;
117
123
  };
118
124
 
119
- Parser.parsers.parseBrackets = __filename;
120
125
  module.exports = parseBrackets;
@@ -20,10 +20,7 @@ const parseCommentAndExt = (text, config = Parser.getConfig(), accum = [], inclu
20
20
  const str = `\0${accum.length}e\x7F`;
21
21
  new OnlyincludeToken(inner, config, accum);
22
22
  return str;
23
- }).replace(/(?<=^|\0\d+e\x7F).*?(?=$|\0\d+e\x7F)/gsu, substr => {
24
- if (substr === '') {
25
- return '';
26
- }
23
+ }).replace(/(?<=^|\0\d+e\x7F)[^\0]+(?=$|\0\d+e\x7F)/gu, substr => {
27
24
  new NoincludeToken(substr, config, accum);
28
25
  return `\0${accum.length - 1}c\x7F`;
29
26
  });
@@ -58,5 +55,4 @@ const parseCommentAndExt = (text, config = Parser.getConfig(), accum = [], inclu
58
55
  );
59
56
  };
60
57
 
61
- Parser.parsers.parseCommentAndExt = __filename;
62
58
  module.exports = parseCommentAndExt;
@@ -42,5 +42,4 @@ const parseConverter = (wikitext, config = Parser.getConfig(), accum = []) => {
42
42
  return wikitext;
43
43
  };
44
44
 
45
- Parser.parsers.parseConverter = __filename;
46
45
  module.exports = parseConverter;
@@ -29,5 +29,4 @@ const parseExternalLinks = (wikitext, config = Parser.getConfig(), accum = []) =
29
29
  });
30
30
  };
31
31
 
32
- Parser.parsers.parseExternalLinks = __filename;
33
32
  module.exports = parseExternalLinks;
@@ -34,5 +34,4 @@ const parseHrAndDoubleUnderscore = ({firstChild: {data}, type, name}, config = P
34
34
  return type === 'root' || type === 'ext-inner' && name === 'poem' ? data : data.slice(1);
35
35
  };
36
36
 
37
- Parser.parsers.parseHrAndDoubleUnderscore = __filename;
38
37
  module.exports = parseHrAndDoubleUnderscore;
package/parser/html.js CHANGED
@@ -38,5 +38,4 @@ const parseHtml = (wikitext, config = Parser.getConfig(), accum = []) => {
38
38
  return text;
39
39
  };
40
40
 
41
- Parser.parsers.parseHtml = __filename;
42
41
  module.exports = parseHtml;
package/parser/links.js CHANGED
@@ -44,12 +44,12 @@ const parseLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
44
44
  continue;
45
45
  }
46
46
  const title = Parser.normalizeTitle(link, 0, false, config, true, true, true),
47
- {ns, interwiki, valid} = title;
47
+ {ns, valid} = title;
48
48
  if (!valid) {
49
49
  s += `[[${x}`;
50
50
  continue;
51
51
  } else if (mightBeImg) {
52
- if (interwiki || ns !== 6) {
52
+ if (ns !== 6) {
53
53
  s += `[[${x}`;
54
54
  continue;
55
55
  }
@@ -79,16 +79,15 @@ const parseLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
79
79
  s += `\0${accum.length}l\x7F${after}`;
80
80
  let SomeLinkToken = LinkToken;
81
81
  if (!force) {
82
- if (!interwiki && ns === 6) {
82
+ if (ns === 6) {
83
83
  SomeLinkToken = FileToken;
84
- } else if (!interwiki && ns === 14) {
84
+ } else if (ns === 14) {
85
85
  SomeLinkToken = CategoryToken;
86
86
  }
87
87
  }
88
- new SomeLinkToken(link, text, title, config, accum, delimiter);
88
+ new SomeLinkToken(link, text, config, accum, delimiter);
89
89
  }
90
90
  return s;
91
91
  };
92
92
 
93
- Parser.parsers.parseLinks = __filename;
94
93
  module.exports = parseLinks;
package/parser/list.js CHANGED
@@ -55,5 +55,4 @@ const parseList = (text, config = Parser.getConfig(), accum = []) => {
55
55
  return text;
56
56
  };
57
57
 
58
- Parser.parsers.parseList = __filename;
59
58
  module.exports = parseList;
@@ -37,5 +37,4 @@ const parseMagicLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
37
37
  });
38
38
  };
39
39
 
40
- Parser.parsers.parseMagicLinks = __filename;
41
40
  module.exports = parseMagicLinks;
package/parser/quotes.js CHANGED
@@ -31,7 +31,7 @@ const parseQuotes = (text, config = Parser.getConfig(), accum = []) => {
31
31
  nBold++;
32
32
  if (firstSingle) {
33
33
  break;
34
- } else if (arr[i - 1].at(-1) === ' ') {
34
+ } else if (arr[i - 1].endsWith(' ')) {
35
35
  if (!firstMulti && !firstSpace) {
36
36
  firstSpace = i;
37
37
  }
@@ -60,5 +60,4 @@ const parseQuotes = (text, config = Parser.getConfig(), accum = []) => {
60
60
  return arr.join('');
61
61
  };
62
62
 
63
- Parser.parsers.parseQuotes = __filename;
64
63
  module.exports = parseQuotes;
package/parser/table.js CHANGED
@@ -110,5 +110,4 @@ const parseTable = ({firstChild: {data}, type, name}, config = Parser.getConfig(
110
110
  return out.slice(1);
111
111
  };
112
112
 
113
- Parser.parsers.parseTable = __filename;
114
113
  module.exports = parseTable;
package/src/arg.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const {text, noWrap} = require('../util/string'),
3
+ const {text} = require('../util/string'),
4
4
  {generateForSelf, generateForChild} = require('../util/lint'),
5
5
  Parser = require('..'),
6
6
  Token = require('.');
@@ -24,13 +24,11 @@ class ArgToken extends Token {
24
24
  */
25
25
  constructor(parts, config = Parser.getConfig(), accum = []) {
26
26
  super(undefined, config, true, accum, {
27
- AtomToken: 0, Token: 1, HiddenToken: '2:',
28
27
  });
29
28
  for (let i = 0; i < parts.length; i++) {
30
29
  if (i === 0 || i > 1) {
31
30
  const AtomToken = i === 0 ? require('./atom') : require('./atom/hidden');
32
31
  const token = new AtomToken(parts[i], i === 0 ? 'arg-name' : undefined, config, accum, {
33
- 'Stage-2': ':', '!HeadingToken': '',
34
32
  });
35
33
  super.insertAt(token);
36
34
  } else {
@@ -39,15 +37,13 @@ class ArgToken extends Token {
39
37
  super.insertAt(token.setAttribute('stage', 2));
40
38
  }
41
39
  }
42
- this.getAttribute('protectChildren')(0);
43
40
  }
44
41
 
45
42
  /**
46
43
  * @override
47
- * @param {string} selector
48
44
  */
49
45
  toString(selector) {
50
- return selector && this.matches(selector) ? '' : `{{{${super.toString(selector, '|')}}}}`;
46
+ return `{{{${super.toString(selector, '|')}}}}`;
51
47
  }
52
48
 
53
49
  /**
@@ -68,19 +64,14 @@ class ArgToken extends Token {
68
64
  return 1;
69
65
  }
70
66
 
71
- /** @override */
72
- print() {
73
- return super.print({pre: '{{{', post: '}}}', sep: '|'});
74
- }
75
-
76
67
  /**
77
68
  * @override
78
69
  * @param {number} start 起始位置
79
70
  * @returns {LintError[]}
80
71
  */
81
- lint(start = 0) {
72
+ lint(start = this.getAbsoluteIndex()) {
82
73
  if (!this.getAttribute('include')) {
83
- return [generateForSelf(this, {start}, '未预期的模板参数')];
74
+ return [generateForSelf(this, {start}, 'unexpected template argument')];
84
75
  }
85
76
  const {childNodes: [argName, argDefault, ...rest]} = this,
86
77
  errors = argName.lint(start + 3);
@@ -89,115 +80,14 @@ class ArgToken extends Token {
89
80
  }
90
81
  if (rest.length > 0) {
91
82
  const rect = {start, ...this.getRootNode().posFromIndex(start)};
92
- errors.push(...rest.map(child => generateForChild(child, rect, '三重括号内的不可见部分')));
83
+ errors.push(...rest.map(child => {
84
+ const error = generateForChild(child, rect, 'invisible content inside triple brackets'),
85
+ {startIndex, startCol, excerpt} = error;
86
+ return {...error, startIndex: startIndex - 1, startCol: startCol - 1, excerpt: `|${excerpt}`};
87
+ }));
93
88
  }
94
89
  return errors;
95
90
  }
96
-
97
- /** @override */
98
- cloneNode() {
99
- const [name, ...cloned] = this.cloneChildNodes();
100
- return Parser.run(() => {
101
- const token = new ArgToken([''], this.getAttribute('config'));
102
- token.firstChild.safeReplaceWith(name);
103
- token.append(...cloned);
104
- token.afterBuild();
105
- return token;
106
- });
107
- }
108
-
109
- /** @override */
110
- afterBuild() {
111
- this.setAttribute('name', this.firstChild.text().trim());
112
- const /** @type {AstListener} */ argListener = ({prevTarget}) => {
113
- if (prevTarget === this.firstChild) {
114
- this.setAttribute('name', prevTarget.text().trim());
115
- }
116
- };
117
- this.addEventListener(['remove', 'insert', 'replace', 'text'], argListener);
118
- }
119
-
120
- /**
121
- * 移除无效部分
122
- * @complexity `n`
123
- */
124
- removeRedundant() {
125
- Parser.run(() => {
126
- for (let i = this.length - 1; i > 1; i--) {
127
- super.removeAt(i);
128
- }
129
- });
130
- }
131
-
132
- /**
133
- * 移除子节点,且在移除`arg-default`子节点时自动移除全部多余子节点
134
- * @param {number} i 移除位置
135
- * @returns {Token}
136
- */
137
- removeAt(i) {
138
- if (i === 1) {
139
- this.removeRedundant();
140
- }
141
- return super.removeAt(i);
142
- }
143
-
144
- /**
145
- * @override
146
- * @param {Token} token 待插入的子节点
147
- * @param {number} i 插入位置
148
- * @throws `RangeError` 不可插入多余子节点
149
- */
150
- insertAt(token, i = this.length) {
151
- const j = i < 0 ? i + this.length : i;
152
- if (j > 1) {
153
- throw new RangeError(`${this.constructor.name} 不可插入多余的子节点!`);
154
- }
155
- super.insertAt(token, i);
156
- if (j === 1) {
157
- token.type = 'arg-default';
158
- }
159
- return token;
160
- }
161
-
162
- /**
163
- * 设置参数名
164
- * @param {string} name 新参数名
165
- * @throws `SyntaxError` 非法的参数名
166
- */
167
- setName(name) {
168
- name = String(name);
169
- const root = Parser.parse(`{{{${name}}}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
170
- {length, firstChild: arg} = root;
171
- if (length !== 1 || arg.type !== 'arg' || arg.length !== 1) {
172
- throw new SyntaxError(`非法的参数名称:${noWrap(name)}`);
173
- }
174
- const {firstChild} = arg;
175
- arg.destroy(true);
176
- this.firstChild.safeReplaceWith(firstChild);
177
- }
178
-
179
- /**
180
- * 设置预设值
181
- * @param {string} value 预设值
182
- * @throws `SyntaxError` 非法的参数预设值
183
- */
184
- setDefault(value) {
185
- value = String(value);
186
- const root = Parser.parse(`{{{|${value}}}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
187
- {length, firstChild: arg} = root;
188
- if (length !== 1 || arg.type !== 'arg' || arg.length !== 2) {
189
- throw new SyntaxError(`非法的参数预设值:${noWrap(value)}`);
190
- }
191
- const {childNodes: [, oldDefault]} = this,
192
- {lastChild} = arg;
193
- arg.destroy(true);
194
- if (oldDefault) {
195
- oldDefault.safeReplaceWith(lastChild);
196
- } else {
197
- this.insertAt(lastChild);
198
- }
199
- }
200
91
  }
201
92
 
202
- Parser.classes.ArgToken = __filename;
203
93
  module.exports = ArgToken;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const hidden = require('../../mixin/hidden'),
4
- Parser = require('../..'),
5
4
  AtomToken = require('.');
6
5
 
7
6
  /** 不可见的节点 */
@@ -9,5 +8,4 @@ class HiddenToken extends hidden(AtomToken) {
9
8
  type = 'hidden';
10
9
  }
11
10
 
12
- Parser.classes.HiddenToken = __filename;
13
11
  module.exports = HiddenToken;