wikilint 2.3.7 → 2.3.8

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.
@@ -10,7 +10,6 @@ const hidden = (constructor) => {
10
10
  class AnyHiddenToken extends constructor {
11
11
  static hidden = true;
12
12
  /** 没有可见部分 */
13
- // eslint-disable-next-line class-methods-use-this
14
13
  text() {
15
14
  return '';
16
15
  }
@@ -49,9 +49,14 @@ const parseCommentAndExt = (wikitext, config = Parser.getConfig(), accum = [], i
49
49
  return str;
50
50
  }
51
51
  }
52
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
53
+ /<foo(?:\s[^>]*)?>|<\/foo\s*>/giu;
54
+ /<(bar)(\s[^>]*?)?(?:\/>|>(.*?)<\/(\1\s*)>)/gisu;
55
+ /<(baz)(\s[^>]*?)?(?:\/>|>(.*?)(?:<\/(baz\s*)>|$))/gisu;
56
+ /* eslint-enable @typescript-eslint/no-unused-expressions */
52
57
  const ext = config.ext.join('|'), noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly', regex = new RegExp('<!--.*?(?:-->|$)' // comment
53
58
  + '|'
54
- + `<${noincludeRegex}(?:\\s[^>]*?)?>|</${noincludeRegex}\\s*>` // <noinclude>
59
+ + `<${noincludeRegex}(?:\\s[^>]*)?>|</${noincludeRegex}\\s*>` // <noinclude>
55
60
  + '|'
56
61
  + `<(${ext})(\\s[^>]*?)?(?:/>|>(.*?)</(\\1\\s*)>)` // 扩展标签
57
62
  + '|'
@@ -15,10 +15,10 @@ const parseConverter = (text, config = Parser.getConfig(), accum = []) => {
15
15
  while (mt) {
16
16
  const { 0: syntax, index } = mt;
17
17
  if (syntax === '}-') {
18
- const top = stack.pop(), { length } = accum, str = text.slice(top.index + 2, index), i = str.indexOf('|'), [flags, raw] = i === -1 ? [[], str] : [str.slice(0, i).split(';'), str.slice(i + 1)], temp = raw.replace(/(&[#a-z\d]+);/giu, '$1\x01'), variants = `(?:${config.variants.join('|')})`, rules = temp.split(new RegExp(`;(?=\\s*(?:${`(?:${variants}|[^;]*?=>\\s*${variants})\\s*:`
19
- + '|'
20
- + '(?:\0\\d+c\x7f(?:\\s|\0\\d+c\x7f)*)?$' // 末尾的空白
21
- }))`, 'u')).map(rule => rule.replace(/\x01/gu, ';'));
18
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
19
+ /;(?=(?:[^;]*?=>)?\s*foo\s*:|(?:\s|\0\d+c\x7F)*$)/u;
20
+ const top = stack.pop(), { length } = accum, str = text.slice(top.index + 2, index), i = str.indexOf('|'), [flags, raw] = i === -1 ? [[], str] : [str.slice(0, i).split(';'), str.slice(i + 1)], temp = raw.replace(/(&[#a-z\d]+);/giu, '$1\x01'), variants = `(?:${config.variants.join('|')})`, rules = temp.split(new RegExp(`;(?=(?:[^;]*?=>)?\\s*${variants}\\s*:|(?:\\s|\0\\d+c\x7F)*$)`, 'u'))
21
+ .map(rule => rule.replace(/\x01/gu, ';'));
22
22
  new converter_1.ConverterToken(flags, rules, config, accum);
23
23
  text = `${text.slice(0, top.index)}\0${length}v\x7F${text.slice(index + 2)}`;
24
24
  if (stack.length === 0) {
@@ -11,7 +11,10 @@ const extLink_1 = require("../src/extLink");
11
11
  * @param accum
12
12
  */
13
13
  const parseExternalLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
14
- const regex = new RegExp(`\\[((?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar})(\\p{Zs}*)([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)\\]`, 'giu');
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
15
+ /\[((?:\[[\da-f:.]+\]|[^[\]\t\n\p{Zs}])[^[\]\t\n\p{Zs}]*(?=[[\]\t\p{Zs}]|\0\d))(\p{Zs}*(?=\P{Zs}))([^\]\n]*)\]/giu;
16
+ const regex = new RegExp(`\\[((?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar}(?=[[\\]<>"\\t\\p{Zs}]|\0\\d))`
17
+ + '(\\p{Zs}*(?=\\P{Zs}))([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)\\]', 'giu');
15
18
  return wikitext.replace(regex, (_, url, space, text) => {
16
19
  const { length } = accum, mt = /&[lg]t;/u.exec(url);
17
20
  if (mt) {
@@ -11,6 +11,8 @@ const magicLink_1 = require("../src/magicLink");
11
11
  * @param accum
12
12
  */
13
13
  const parseMagicLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
15
+ /(^|[^\p{L}\d_])((?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])(?:[^[\]<>"\0\t\n\p{Zs}]|\0\d+c\x7F)*)/giu;
14
16
  const regex = new RegExp(`(^|[^\\p{L}\\d_])(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})`, 'giu');
15
17
  return wikitext.replace(regex, (m, lead, p1) => {
16
18
  let trail = '', url = lead ? m.slice(1) : m;
@@ -124,6 +124,7 @@ const commonHtmlAttrs = new Set([
124
124
  * @classdesc `{childNodes: [AtomToken, Token|AtomToken]}`
125
125
  */
126
126
  class AttributeToken extends index_1.Token {
127
+ tag;
127
128
  #equal;
128
129
  #quotes;
129
130
  /** 引号是否匹配 */
@@ -32,10 +32,10 @@ class AttributesToken extends index_1.Token {
32
32
  this.type = type;
33
33
  this.setAttribute('name', name);
34
34
  if (attr) {
35
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
36
+ /([^\s/](?:(?!\0\d+~\x7F)[^\s/=])*)(?:(\s*(?:=|\0\d+~\x7F)\s*)(?:(["'])(.*?)(\3|$)|(\S*)))?/gsu;
35
37
  const regex = new RegExp('([^\\s/](?:(?!\0\\d+~\x7F)[^\\s/=])*)' // 属性名
36
- + `(?:${'((?:\\s|\0\\d+c\x7F)*' // `=`前的空白字符
37
- + '(?:=|\0\\d+~\x7F)' // `=`
38
- + '(?:\\s|\0\\d+c\x7F)*)' // `=`后的空白字符
38
+ + `(?:${'((?:\\s|\0\\d+c\x7F)*(?:=|\0\\d+~\x7F)(?:\\s|\0\\d+c\x7F)*)' // `=`和前后的空白字符
39
39
  + `(?:(["'])(.*?)(\\3|$)|(\\S*))` // 属性值
40
40
  })?`, 'gsu');
41
41
  let out = '', mt = regex.exec(attr), lastIndex = 0;
@@ -30,7 +30,7 @@ export declare class HtmlToken extends Token {
30
30
  * 搜索匹配的标签
31
31
  * @throws `SyntaxError` 同时闭合和自封闭的标签
32
32
  * @throws `SyntaxError` 无效自封闭标签
33
- * @throws `SyntaxError` 未闭合的标签
33
+ * @throws `SyntaxError` 未匹配的标签
34
34
  */
35
35
  findMatchingTag(): this | undefined;
36
36
  }
package/dist/src/html.js CHANGED
@@ -92,7 +92,7 @@ class HtmlToken extends index_1.Token {
92
92
  * 搜索匹配的标签
93
93
  * @throws `SyntaxError` 同时闭合和自封闭的标签
94
94
  * @throws `SyntaxError` 无效自封闭标签
95
- * @throws `SyntaxError` 未闭合的标签
95
+ * @throws `SyntaxError` 未匹配的标签
96
96
  */
97
97
  findMatchingTag() {
98
98
  const { html } = this.getAttribute('config'), { name: tagName, parentNode, closing } = this, string = (0, string_1.noWrap)(String(this));
@@ -16,6 +16,8 @@ function validate(key, val, config = Parser.getConfig(), halfParsed = false) {
16
16
  if (!value) {
17
17
  return val;
18
18
  }
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
20
+ /^(?:\/\/(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])|\0\d+m\x7F)(?:[^[\]<>"\0\t\n\p{Zs}]|\0\d+c\x7F)*$/iu;
19
21
  const regex = new RegExp(`^(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar}$`, 'iu');
20
22
  if (regex.test(value)) {
21
23
  return val;
@@ -59,7 +59,7 @@ class ImagemapToken extends index_1.Token {
59
59
  }
60
60
  else if (protocols.has(substr.slice(1, substr.indexOf(':') + 1))
61
61
  || protocols.has(substr.slice(1, substr.indexOf('//') + 2))) {
62
- const mtEx = /^\[([^\]\s]+)(?:(\s+)(\S[^\]]*)?)?\][\w\s]*$/u
62
+ const mtEx = /^\[([^\]\s]+)(?:(\s+(?=\S))([^\]]*))?\][\w\s]*$/u
63
63
  .exec(substr);
64
64
  if (mtEx) {
65
65
  super.insertAt(new imagemapLink_1.ImagemapLinkToken(line.slice(0, i), mtEx.slice(1), substr.slice(substr.indexOf(']') + 1), config, accum));
@@ -59,6 +59,8 @@ class ParameterToken extends index_1.Token {
59
59
  }
60
60
  /** @override */
61
61
  lint(start = this.getAbsoluteIndex()) {
62
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
63
+ /https?:\/\/(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])(?:[^[\]<>"\0\t\n\p{Zs}]|\0\d+c\x7F)*$/iu;
62
64
  const errors = super.lint(start), { firstChild } = this, link = new RegExp(`https?://${string_1.extUrlCharFirst}${string_1.extUrlChar}$`, 'iu')
63
65
  .exec(firstChild.toString(new Set(['comment', 'noinclude', 'include'])))?.[0];
64
66
  if (link && new URL(link).search) {
@@ -9,6 +9,7 @@ import type { LintError } from '../../base';
9
9
  */
10
10
  export declare class ExtToken extends TagPairToken {
11
11
  readonly type = "ext";
12
+ closed: true;
12
13
  readonly childNodes: [AttributesToken, Token];
13
14
  abstract get firstChild(): AttributesToken;
14
15
  abstract get lastChild(): Token;
@@ -6,11 +6,11 @@ export declare abstract class TagPairToken extends Token {
6
6
  #private;
7
7
  type: 'ext' | 'include';
8
8
  readonly name: string;
9
+ closed: boolean;
10
+ selfClosing: boolean;
9
11
  readonly childNodes: [AstNodes, AstNodes];
10
12
  abstract get firstChild(): AstNodes;
11
13
  abstract get lastChild(): AstNodes;
12
- /** 是否闭合 */
13
- get closed(): boolean;
14
14
  /**
15
15
  * @param name 标签名
16
16
  * @param attr 标签属性
@@ -5,13 +5,9 @@ const Parser = require("../../index");
5
5
  const index_1 = require("../index");
6
6
  /** 成对标签 */
7
7
  class TagPairToken extends index_1.Token {
8
- #selfClosing;
9
- #closed;
10
8
  #tags;
11
- /** 是否闭合 */
12
- get closed() {
13
- return this.#closed;
14
- }
9
+ closed;
10
+ selfClosing;
15
11
  /**
16
12
  * @param name 标签名
17
13
  * @param attr 标签属性
@@ -22,23 +18,23 @@ class TagPairToken extends index_1.Token {
22
18
  super(undefined, config);
23
19
  this.setAttribute('name', name.toLowerCase());
24
20
  this.#tags = [name, closed || name];
25
- this.#selfClosing = closed === undefined;
26
- this.#closed = closed !== '';
21
+ this.closed = closed !== '';
22
+ this.selfClosing = closed === undefined;
27
23
  this.append(attr, inner);
28
24
  const index = typeof attr === 'string' ? -1 : accum.indexOf(attr);
29
25
  accum.splice(index === -1 ? Infinity : index, 0, this);
30
26
  }
31
27
  /** @private */
32
28
  toString(omit) {
33
- const { firstChild, lastChild, } = this, [opening, closing] = this.#tags;
34
- return this.#selfClosing
29
+ const { selfClosing, firstChild, lastChild, } = this, [opening, closing] = this.#tags;
30
+ return selfClosing
35
31
  ? `<${opening}${firstChild.toString(omit)}/>`
36
32
  : `<${opening}${firstChild.toString(omit)}>${lastChild.toString(omit)}${this.closed ? `</${closing}>` : ''}`;
37
33
  }
38
34
  /** @override */
39
35
  text() {
40
36
  const [opening, closing] = this.#tags;
41
- return this.#selfClosing
37
+ return this.selfClosing
42
38
  ? `<${opening}${this.firstChild.text()}/>`
43
39
  : `<${opening}${super.text('>')}${this.closed ? `</${closing}>` : ''}`;
44
40
  }
@@ -11,7 +11,7 @@ import type { LintError } from '../base';
11
11
  export declare class TranscludeToken extends Token {
12
12
  #private;
13
13
  type: 'template' | 'magic-word';
14
- readonly modifier = "";
14
+ readonly modifier: string;
15
15
  readonly childNodes: [AtomToken | SyntaxToken, ...ParameterToken[]] | [SyntaxToken, AtomToken, AtomToken, ...ParameterToken[]];
16
16
  abstract get firstChild(): AtomToken | SyntaxToken;
17
17
  abstract get lastChild(): AtomToken | SyntaxToken | ParameterToken;
@@ -118,7 +118,7 @@ class TranscludeToken extends index_1.Token {
118
118
  /** 获取模板或模块名 */
119
119
  #getTitle() {
120
120
  const isTemplate = this.type === 'template', child = this.childNodes[isTemplate ? 0 : 1];
121
- return child && this.normalizeTitle(child.text(), isTemplate ? 10 : 828);
121
+ return this.normalizeTitle(child.text(), isTemplate ? 10 : 828);
122
122
  }
123
123
  /** @private */
124
124
  afterBuild() {
@@ -162,12 +162,7 @@ class TranscludeToken extends index_1.Token {
162
162
  return errors;
163
163
  }
164
164
  const title = this.#getTitle();
165
- if (!title) {
166
- rect = { start, ...this.getRootNode().posFromIndex(start) };
167
- errors.push((0, lint_1.generateForSelf)(this, rect, 'missing module name'));
168
- return errors;
169
- }
170
- else if (title.fragment !== undefined) {
165
+ if (title.fragment !== undefined) {
171
166
  rect = { start, ...this.getRootNode().posFromIndex(start) };
172
167
  errors.push((0, lint_1.generateForChild)(childNodes[type === 'template' ? 0 : 1], rect, 'useless fragment'));
173
168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.3.7",
3
+ "version": "2.3.8",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",