wikilint 2.5.0 → 2.5.1

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.
@@ -767,7 +767,7 @@
767
767
  "EXPECTED_UNCONNECTED_PAGE"
768
768
  ]
769
769
  ],
770
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
770
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
771
771
  "interwiki": [],
772
772
  "img": {
773
773
  "thumbnail": "thumbnail",
@@ -369,7 +369,7 @@
369
369
  "EXPECTED_UNCONNECTED_PAGE"
370
370
  ]
371
371
  ],
372
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
372
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
373
373
  "interwiki": [],
374
374
  "img": {
375
375
  "thumbnail": "thumbnail",
@@ -518,7 +518,7 @@
518
518
  "静态重定向"
519
519
  ]
520
520
  ],
521
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
521
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
522
522
  "interwiki": [],
523
523
  "img": {
524
524
  "thumbnail": "thumbnail",
@@ -66,8 +66,7 @@
66
66
  "wbr",
67
67
  "hr",
68
68
  "meta",
69
- "link",
70
- "img"
69
+ "link"
71
70
  ]
72
71
  ],
73
72
  "namespaces": {},
@@ -82,6 +81,7 @@
82
81
  "#speciale": "speciale",
83
82
  "#tag": "tag",
84
83
  "#formatdate": "formatdate",
84
+ "#dateformat": "formatdate",
85
85
  "#invoke": "invoke",
86
86
  "#while": "while",
87
87
  "#dowhile": "dowhile",
@@ -118,13 +118,10 @@
118
118
  ],
119
119
  [
120
120
  "msg",
121
- "原始",
122
121
  "raw"
123
122
  ],
124
123
  [
125
- "替代",
126
124
  "subst",
127
- "安全替代",
128
125
  "safesubst"
129
126
  ]
130
127
  ],
@@ -132,7 +129,7 @@
132
129
  [],
133
130
  []
134
131
  ],
135
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
132
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
136
133
  "interwiki": [],
137
134
  "img": {},
138
135
  "variants": []
@@ -707,7 +707,7 @@
707
707
  "EXPECTED_UNCONNECTED_PAGE"
708
708
  ]
709
709
  ],
710
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
710
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
711
711
  "interwiki": [],
712
712
  "img": {
713
713
  "thumbnail": "thumbnail",
package/dist/base.d.ts CHANGED
@@ -10,9 +10,10 @@ export interface Config {
10
10
  readonly variants: string[];
11
11
  readonly excludes?: string[];
12
12
  }
13
+ export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext"];
13
14
  export declare namespace LintError {
14
15
  type Severity = 'error' | 'warning';
15
- type Rule = 'bold-header' | 'format-leakage' | 'fostered-content' | 'h1' | 'illegal-attr' | 'insecure-style' | 'invalid-gallery' | 'invalid-imagemap' | 'invalid-invoke' | 'lonely-apos' | 'lonely-bracket' | 'lonely-http' | 'nested-link' | 'no-arg' | 'no-duplicate' | 'no-ignored' | 'obsolete-attr' | 'obsolete-tag' | 'parsing-order' | 'pipe-like' | 'table-layout' | 'tag-like' | 'unbalanced-header' | 'unclosed-comment' | 'unclosed-quote' | 'unclosed-table' | 'unescaped' | 'unknown-page' | 'unmatched-tag' | 'unterminated-url' | 'url-encoding' | 'var-anchor' | 'void-ext';
16
+ type Rule = typeof rules[number];
16
17
  interface Fix {
17
18
  readonly range: [number, number];
18
19
  text: string;
@@ -46,6 +47,7 @@ interface AstElement extends AstNode {
46
47
  export interface Parser {
47
48
  config: string | Config;
48
49
  i18n: string | Record<string, string> | undefined;
50
+ rules: readonly LintError.Rule[];
49
51
  /** 获取解析设置 */
50
52
  getConfig(): Config;
51
53
  /**
package/dist/base.js ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rules = void 0;
4
+ exports.rules = [
5
+ 'bold-header',
6
+ 'format-leakage',
7
+ 'fostered-content',
8
+ 'h1',
9
+ 'illegal-attr',
10
+ 'insecure-style',
11
+ 'invalid-gallery',
12
+ 'invalid-imagemap',
13
+ 'invalid-invoke',
14
+ 'lonely-apos',
15
+ 'lonely-bracket',
16
+ 'lonely-http',
17
+ 'nested-link',
18
+ 'no-arg',
19
+ 'no-duplicate',
20
+ 'no-ignored',
21
+ 'obsolete-attr',
22
+ 'obsolete-tag',
23
+ 'parsing-order',
24
+ 'pipe-like',
25
+ 'table-layout',
26
+ 'tag-like',
27
+ 'unbalanced-header',
28
+ 'unclosed-comment',
29
+ 'unclosed-quote',
30
+ 'unclosed-table',
31
+ 'unescaped',
32
+ 'unknown-page',
33
+ 'unmatched-tag',
34
+ 'unterminated-url',
35
+ 'url-encoding',
36
+ 'var-anchor',
37
+ 'void-ext',
38
+ ];
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  /* eslint n/exports-style: 0 */
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
+ const base_1 = require("./base");
5
6
  const debug_1 = require("./util/debug");
6
7
  const constants_1 = require("./util/constants");
7
8
  const string_1 = require("./util/string");
@@ -15,6 +16,7 @@ const rootRequire = (file, dir) => require(file.startsWith('/') ? file : `../${f
15
16
  const Parser = {
16
17
  config: 'default',
17
18
  i18n: undefined,
19
+ rules: base_1.rules,
18
20
  /** @implements */
19
21
  getConfig() {
20
22
  if (typeof this.config === 'string') {
@@ -22,7 +22,8 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
22
22
  if (!dt) {
23
23
  return text;
24
24
  }
25
- let regex = /:+|-\{/gu, ex = regex.exec(text), lc = 0;
25
+ const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+x\x7F/gu;
26
+ let regex = fullRegex, ex = regex.exec(text), lt = 0, lc = 0;
26
27
  /**
27
28
  * 创建`DdToken`
28
29
  * @param syntax `:`
@@ -35,15 +36,7 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
35
36
  };
36
37
  while (ex && dt) {
37
38
  const { 0: syntax, index } = ex;
38
- if (syntax.startsWith(':')) {
39
- if (syntax.length >= dt) {
40
- return dd(syntax.slice(0, dt), index);
41
- }
42
- dt -= syntax.length;
43
- regex.lastIndex = index + 4 + String(accum.length).length;
44
- text = dd(syntax, index);
45
- }
46
- else if (syntax === '-{') {
39
+ if (syntax === '-{') {
47
40
  if (!lc) {
48
41
  const { lastIndex } = regex;
49
42
  regex = /-\{|\}-/gu;
@@ -51,14 +44,33 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
51
44
  }
52
45
  lc++;
53
46
  }
54
- else {
47
+ else if (syntax === '}-') {
55
48
  lc--;
56
49
  if (!lc) {
57
50
  const { lastIndex } = regex;
58
- regex = /:+|-\{/gu;
51
+ regex = fullRegex;
59
52
  regex.lastIndex = lastIndex;
60
53
  }
61
54
  }
55
+ else if (syntax.startsWith('\0')) {
56
+ const { name, closing, selfClosing } = accum[Number(syntax.slice(1, -2))];
57
+ if (!selfClosing || normalTags.includes(name)) {
58
+ if (!closing) {
59
+ lt++;
60
+ }
61
+ else if (lt) {
62
+ lt--;
63
+ }
64
+ }
65
+ }
66
+ else if (lt === 0) { // syntax === ':'
67
+ if (syntax.length >= dt) {
68
+ return dd(syntax.slice(0, dt), index);
69
+ }
70
+ dt -= syntax.length;
71
+ regex.lastIndex = index + 4 + String(accum.length).length;
72
+ text = dd(syntax, index);
73
+ }
62
74
  ex = regex.exec(text);
63
75
  }
64
76
  return text;
@@ -20,6 +20,7 @@ const commonHtmlAttrs = new Set([
20
20
  'aria-hidden',
21
21
  'aria-label',
22
22
  'aria-labelledby',
23
+ 'aria-level',
23
24
  'aria-owns',
24
25
  'role',
25
26
  'about',
@@ -145,7 +146,7 @@ const commonHtmlAttrs = new Set([
145
146
  combobox: new Set(['placeholder', 'value', 'id', 'class', 'text', 'dropdown', 'style']),
146
147
  }, insecureStyle = new RegExp('expression'
147
148
  + '|'
148
- + '(?:filter|accelerator|-o-link(?:-source)?|-o-replace)\\s*:'
149
+ + '(?:accelerator|-o-link(?:-source)?|-o-replace)\\s*:'
149
150
  + '|'
150
151
  + '(?:url|image(?:-set)?)\\s*\\('
151
152
  + '|'
@@ -270,7 +271,7 @@ class AttributeToken extends index_2.Token {
270
271
  if (lastChild.childNodes.some(child => child.type === 'text' && /\s/u.test(child.text()))) {
271
272
  e.suggestions = [
272
273
  {
273
- desc: 'quote',
274
+ desc: 'close',
274
275
  ...fix,
275
276
  },
276
277
  ];
@@ -13,6 +13,8 @@ export declare abstract class HtmlToken extends Token {
13
13
  readonly childNodes: readonly [AttributesToken];
14
14
  abstract get firstChild(): AttributesToken;
15
15
  abstract get lastChild(): AttributesToken;
16
+ /** 是否自封闭 */
17
+ get selfClosing(): boolean;
16
18
  /** 是否是闭合标签 */
17
19
  get closing(): boolean;
18
20
  /**
package/dist/src/html.js CHANGED
@@ -41,6 +41,10 @@ class HtmlToken extends index_2.Token {
41
41
  #closing;
42
42
  #selfClosing;
43
43
  #tag;
44
+ /** 是否自封闭 */
45
+ get selfClosing() {
46
+ return this.#selfClosing;
47
+ }
44
48
  /** 是否是闭合标签 */
45
49
  get closing() {
46
50
  return this.#closing;
@@ -163,14 +167,14 @@ class HtmlToken extends index_2.Token {
163
167
  * @throws `SyntaxError` 未匹配的标签
164
168
  */
165
169
  findMatchingTag() {
166
- const { html } = this.getAttribute('config'), { name: tagName, parentNode, closing } = this, string = (0, string_1.noWrap)(String(this));
167
- if (closing && (this.#selfClosing || html[2].includes(tagName))) {
170
+ const { html: [normalTags, flexibleTags, voidTags] } = this.getAttribute('config'), { name: tagName, parentNode, closing } = this, string = (0, string_1.noWrap)(String(this));
171
+ if (closing && (this.#selfClosing || voidTags.includes(tagName))) {
168
172
  throw new SyntaxError(`tag that is both closing and self-closing: ${string}`);
169
173
  }
170
- else if (html[2].includes(tagName) || this.#selfClosing && html[1].includes(tagName)) { // 自封闭标签
174
+ else if (voidTags.includes(tagName) || this.#selfClosing && flexibleTags.includes(tagName)) { // 自封闭标签
171
175
  return this;
172
176
  }
173
- else if (this.#selfClosing && html[0].includes(tagName)) {
177
+ else if (this.#selfClosing && normalTags.includes(tagName)) {
174
178
  throw new SyntaxError(`invalid self-closing tag: ${string}`);
175
179
  }
176
180
  else if (!parentNode) {
@@ -26,10 +26,13 @@ class IncludeToken extends (0, hidden_1.hiddenToken)(index_2.TagPairToken) {
26
26
  return [];
27
27
  }
28
28
  const e = (0, lint_1.generateForSelf)(this, { start }, 'unclosed-comment', index_1.default.msg('unclosed $1', `<${this.name}>`));
29
- e.fix = {
30
- range: [e.endIndex, e.endIndex],
31
- text: `</${this.name}>`,
32
- };
29
+ e.suggestions = [
30
+ {
31
+ desc: 'close',
32
+ range: [e.endIndex, e.endIndex],
33
+ text: `</${this.name}>`,
34
+ },
35
+ ];
33
36
  return [e];
34
37
  }
35
38
  }
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noWrap = exports.decodeHtml = exports.text = exports.escapeRegExp = exports.removeComment = exports.tidy = exports.extUrlChar = exports.extUrlCharFirst = void 0;
4
- exports.extUrlCharFirst = '(?:\\[[\\da-f:.]+\\]|[^[\\]<>"\0-\x1F\x7F\\p{Zs}\uFFFD])';
5
- exports.extUrlChar = '(?:[^[\\]<>"\0-\x1F\x7F\\p{Zs}\uFFFD]|\0\\d+[c!~]\x7F)*';
4
+ const commonExtUrlChar = '[^[\\]<>"\0-\x1F\x7F\\p{Zs}\uFFFD]';
5
+ exports.extUrlCharFirst = `(?:\\[[\\da-f:.]+\\]|${commonExtUrlChar})`;
6
+ exports.extUrlChar = `(?:${commonExtUrlChar}|\0\\d+[c!~]\x7F)*`;
6
7
  /**
7
8
  * 生成正则替换函数
8
9
  * @param regex 正则表达式
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "scripts": {
35
35
  "declaration": "grep -rl --include='*.d.ts' '@private' dist/ | xargs bash sed.sh -i -E '/^\\s+\\/\\*\\* @private/,+1d'; node ./dist/bin/declaration.js",
36
- "prepublishOnly": "npm run build && rm dist/internal.js dist/base.js dist/[bmpu]*/*.d.ts",
36
+ "prepublishOnly": "npm run build && rm dist/internal.js dist/[bmpu]*/*.d.ts",
37
37
  "build": "bash build.sh",
38
38
  "diff": "bash diff.sh",
39
39
  "diff:stat": "f() { git diff --stat --ignore-all-space --color=always $1 $2 -- . ':!extensions/' ':!bin/' | grep '\\.ts'; }; f",