wikiparser-node 1.4.5 → 1.5.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.
- package/dist/base.d.ts +21 -11
- package/dist/index.js +3 -2
- package/dist/lib/element.d.ts +0 -5
- package/dist/lib/element.js +0 -38
- package/dist/lib/text.js +48 -11
- package/dist/src/arg.js +26 -8
- package/dist/src/attribute.js +32 -6
- package/dist/src/attributes.js +12 -2
- package/dist/src/converterFlags.js +17 -1
- package/dist/src/gallery.js +12 -0
- package/dist/src/html.js +19 -1
- package/dist/src/imageParameter.js +6 -1
- package/dist/src/index.js +11 -1
- package/dist/src/link/base.js +26 -6
- package/dist/src/magicLink.js +29 -5
- package/dist/src/nested.js +14 -1
- package/dist/src/nowiki/comment.js +9 -3
- package/dist/src/nowiki/index.js +9 -3
- package/dist/src/nowiki/quote.js +14 -0
- package/dist/src/paramTag/index.js +9 -1
- package/dist/src/parameter.js +10 -8
- package/dist/src/table/td.js +18 -1
- package/dist/src/table/trBase.js +5 -7
- package/dist/src/tagPair/include.js +9 -3
- package/dist/src/transclude.js +8 -1
- package/dist/util/diff.js +3 -2
- package/package.json +2 -1
package/dist/base.d.ts
CHANGED
|
@@ -13,18 +13,28 @@ export interface Config {
|
|
|
13
13
|
readonly conversionTable?: [string, string][];
|
|
14
14
|
readonly redirects?: [string, string][];
|
|
15
15
|
}
|
|
16
|
-
export
|
|
17
|
-
|
|
16
|
+
export declare namespace LintError {
|
|
17
|
+
type Severity = 'error' | 'warning';
|
|
18
|
+
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';
|
|
19
|
+
interface Fix {
|
|
20
|
+
readonly range: [number, number];
|
|
21
|
+
text: string;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
18
24
|
export interface LintError {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
rule: LintError.Rule;
|
|
26
|
+
message: string;
|
|
27
|
+
severity: LintError.Severity;
|
|
28
|
+
startIndex: number;
|
|
29
|
+
endIndex: number;
|
|
30
|
+
startLine: number;
|
|
31
|
+
startCol: number;
|
|
32
|
+
endLine: number;
|
|
33
|
+
endCol: number;
|
|
34
|
+
fix?: LintError.Fix;
|
|
35
|
+
suggestions?: (LintError.Fix & {
|
|
36
|
+
desc: string;
|
|
37
|
+
})[];
|
|
28
38
|
}
|
|
29
39
|
export type AST = Record<string, string | number | boolean> & {
|
|
30
40
|
range: [number, number];
|
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 chalk = require("chalk");
|
|
5
6
|
const debug_1 = require("./util/debug");
|
|
6
7
|
const constants_1 = require("./util/constants");
|
|
7
8
|
const string_1 = require("./util/string");
|
|
@@ -118,13 +119,13 @@ const Parser = {
|
|
|
118
119
|
/** @implements */
|
|
119
120
|
warn(msg, ...args) {
|
|
120
121
|
if (this.warning) {
|
|
121
|
-
console.warn(
|
|
122
|
+
console.warn(chalk.yellow(msg), ...args);
|
|
122
123
|
}
|
|
123
124
|
},
|
|
124
125
|
/** @implements */
|
|
125
126
|
debug(msg, ...args) {
|
|
126
127
|
if (this.debugging) {
|
|
127
|
-
console.debug(
|
|
128
|
+
console.debug(chalk.blue(msg), ...args);
|
|
128
129
|
}
|
|
129
130
|
},
|
|
130
131
|
error: diff_1.error,
|
package/dist/lib/element.d.ts
CHANGED
|
@@ -147,9 +147,4 @@ export declare abstract class AstElement extends AstNode {
|
|
|
147
147
|
*/
|
|
148
148
|
insertBefore(child: string, reference?: AstNodes): AstText;
|
|
149
149
|
insertBefore<T extends AstNodes>(child: T, reference?: AstNodes): T;
|
|
150
|
-
/**
|
|
151
|
-
* 输出AST
|
|
152
|
-
* @param depth 当前深度
|
|
153
|
-
*/
|
|
154
|
-
echo(depth?: number): void;
|
|
155
150
|
}
|
package/dist/lib/element.js
CHANGED
|
@@ -9,7 +9,6 @@ const constants_1 = require("../util/constants");
|
|
|
9
9
|
const selector_1 = require("../parser/selector");
|
|
10
10
|
const ranges_1 = require("./ranges");
|
|
11
11
|
const title_1 = require("./title");
|
|
12
|
-
const index_1 = require("../index");
|
|
13
12
|
const node_1 = require("./node");
|
|
14
13
|
/* NOT FOR BROWSER */
|
|
15
14
|
/**
|
|
@@ -613,43 +612,6 @@ class AstElement extends node_1.AstNode {
|
|
|
613
612
|
? this.insertAt(child)
|
|
614
613
|
: this.insertAt(child, this.#getChildIndex(reference));
|
|
615
614
|
}
|
|
616
|
-
/**
|
|
617
|
-
* 输出AST
|
|
618
|
-
* @param depth 当前深度
|
|
619
|
-
*/
|
|
620
|
-
echo(depth = 0) {
|
|
621
|
-
const indent = ' '.repeat(depth), str = String(this), { childNodes, type, length } = this;
|
|
622
|
-
if (childNodes.every(child => child.type === 'text' || !String(child))) {
|
|
623
|
-
console.log(`${indent}\x1B[32m<%s>\x1B[0m${(0, string_1.noWrap)(str)}\x1B[32m</%s>\x1B[0m`, type, type);
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
index_1.default.info(`${indent}<${type}>`);
|
|
627
|
-
let i = this.getAttribute('padding');
|
|
628
|
-
if (i) {
|
|
629
|
-
console.log(`${indent} ${(0, string_1.noWrap)(str.slice(0, i))}`);
|
|
630
|
-
}
|
|
631
|
-
for (let j = 0; j < length; j++) {
|
|
632
|
-
const child = childNodes[j], childStr = String(child), gap = j === length - 1 ? 0 : this.getGaps(j);
|
|
633
|
-
if (!childStr) {
|
|
634
|
-
//
|
|
635
|
-
}
|
|
636
|
-
else if (child.type === 'text') {
|
|
637
|
-
console.log(`${indent} ${(0, string_1.noWrap)(child.data)}`);
|
|
638
|
-
}
|
|
639
|
-
else {
|
|
640
|
-
child.echo(depth + 1);
|
|
641
|
-
}
|
|
642
|
-
i += childStr.length;
|
|
643
|
-
if (gap) {
|
|
644
|
-
console.log(`${indent} ${(0, string_1.noWrap)(str.slice(i, i + gap))}`);
|
|
645
|
-
i += gap;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
if (i < str.length) {
|
|
649
|
-
console.log(`${indent} ${(0, string_1.noWrap)(str.slice(i))}`);
|
|
650
|
-
}
|
|
651
|
-
index_1.default.info(`${indent}</${type}>`);
|
|
652
|
-
}
|
|
653
615
|
}
|
|
654
616
|
exports.AstElement = AstElement;
|
|
655
617
|
constants_1.classes['AstElement'] = __filename;
|
package/dist/lib/text.js
CHANGED
|
@@ -116,14 +116,13 @@ class AstText extends node_1.AstNode {
|
|
|
116
116
|
*/
|
|
117
117
|
lint(start = this.getAbsoluteIndex()) {
|
|
118
118
|
const { data, parentNode, nextSibling, previousSibling } = this;
|
|
119
|
-
/* NOT FOR BROWSER */
|
|
120
119
|
if (!parentNode) {
|
|
120
|
+
/* NOT FOR BROWSER */
|
|
121
121
|
throw new Error('无法对孤立文本节点进行语法分析!');
|
|
122
|
+
/* NOT FOR BROWSER END */
|
|
122
123
|
}
|
|
123
|
-
/* NOT FOR BROWSER END */
|
|
124
124
|
const { NowikiToken } = require('../src/nowiki');
|
|
125
|
-
|
|
126
|
-
const { type, name } = parentNode, nowiki = name === 'nowiki' || name === 'pre';
|
|
125
|
+
const { type, name } = parentNode, nowiki = name === 'nowiki' || name === 'pre', isHtmlAttrVal = type === 'attr-value' && parentNode.parentNode.type !== 'ext-attr';
|
|
127
126
|
let errorRegex;
|
|
128
127
|
if (type === 'ext-inner' && (name === 'pre' || parentNode instanceof NowikiToken)) {
|
|
129
128
|
errorRegex = new RegExp(`<\\s*(?:\\/\\s*)${nowiki ? '' : '?'}(${name})\\b`, 'giu');
|
|
@@ -131,7 +130,7 @@ class AstText extends node_1.AstNode {
|
|
|
131
130
|
else if (type === 'free-ext-link'
|
|
132
131
|
|| type === 'ext-link-url'
|
|
133
132
|
|| type === 'image-parameter' && name === 'link'
|
|
134
|
-
||
|
|
133
|
+
|| isHtmlAttrVal) {
|
|
135
134
|
errorRegex = errorSyntaxUrl;
|
|
136
135
|
}
|
|
137
136
|
else {
|
|
@@ -163,14 +162,15 @@ class AstText extends node_1.AstNode {
|
|
|
163
162
|
else if (char === ']' && (index || length > 1)) {
|
|
164
163
|
errorRegex.lastIndex--;
|
|
165
164
|
}
|
|
166
|
-
const startIndex = start + index, endIndex = startIndex + length, rootStr = String(root), nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && (char
|
|
165
|
+
const startIndex = start + index, endIndex = startIndex + length, rootStr = String(root), nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && !(char === '<' && (nowiki || !/[\s/>]/u.test(nextChar ?? ''))
|
|
166
|
+
|| isHtmlAttrVal && (char === '[' || char === ']'))
|
|
167
167
|
|| char === '{' && (nextChar === char || previousChar === '-')
|
|
168
168
|
|| char === '}' && (previousChar === char || nextChar === '-')
|
|
169
169
|
|| char === '[' && (nextChar === char
|
|
170
170
|
|| type === 'ext-link-text'
|
|
171
|
-
|| !data.slice(index + 1).trim()
|
|
171
|
+
|| nextType === 'free-ext-link' && !data.slice(index + 1).trim())
|
|
172
172
|
|| char === ']' && (previousChar === char
|
|
173
|
-
|| !data.slice(0, index).
|
|
173
|
+
|| previousType === 'free-ext-link' && !data.slice(0, index).includes(']'))
|
|
174
174
|
? 'error'
|
|
175
175
|
: 'warning';
|
|
176
176
|
const leftBracket = char === '{' || char === '[', rightBracket = char === ']' || char === '}';
|
|
@@ -191,8 +191,7 @@ class AstText extends node_1.AstNode {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
-
const lines = data.slice(0, index).split('\n'), startLine = lines.length + top - 1, line = lines[lines.length - 1], startCol = lines.length === 1 ? left + line.length : line.length
|
|
195
|
-
errors.push({
|
|
194
|
+
const lines = data.slice(0, index).split('\n'), startLine = lines.length + top - 1, line = lines[lines.length - 1], startCol = lines.length === 1 ? left + line.length : line.length, e = {
|
|
196
195
|
rule: ruleMap[char],
|
|
197
196
|
message: index_1.default.msg('lonely "$1"', char === 'h' ? error : char),
|
|
198
197
|
severity,
|
|
@@ -202,7 +201,45 @@ class AstText extends node_1.AstNode {
|
|
|
202
201
|
endLine: startLine,
|
|
203
202
|
startCol,
|
|
204
203
|
endCol: startCol + length,
|
|
205
|
-
}
|
|
204
|
+
};
|
|
205
|
+
if (char === '<') {
|
|
206
|
+
e.suggestions = [
|
|
207
|
+
{
|
|
208
|
+
desc: 'escape',
|
|
209
|
+
range: [startIndex, startIndex + 1],
|
|
210
|
+
text: '<',
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
else if (char === 'h'
|
|
215
|
+
&& !(type === 'ext-link-text' || type === 'link-text')
|
|
216
|
+
&& /[\p{L}\d_]/u.test(previousChar || '')) {
|
|
217
|
+
e.suggestions = [
|
|
218
|
+
{
|
|
219
|
+
desc: 'whitespace',
|
|
220
|
+
range: [startIndex, startIndex],
|
|
221
|
+
text: ' ',
|
|
222
|
+
},
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
else if (char === '[' && type === 'ext-link-text') {
|
|
226
|
+
const i = parentNode.getAbsoluteIndex() + String(parentNode).length;
|
|
227
|
+
e.suggestions = [
|
|
228
|
+
{
|
|
229
|
+
desc: 'escape',
|
|
230
|
+
range: [i, i + 1],
|
|
231
|
+
text: ']',
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
else if (char === ']' && previousType === 'free-ext-link' && severity === 'error') {
|
|
236
|
+
const i = start - String(previousSibling).length;
|
|
237
|
+
e.fix = {
|
|
238
|
+
range: [i, i],
|
|
239
|
+
text: '[',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
errors.push(e);
|
|
206
243
|
}
|
|
207
244
|
return errors;
|
|
208
245
|
}
|
package/dist/src/arg.js
CHANGED
|
@@ -71,22 +71,40 @@ class ArgToken extends index_2.Token {
|
|
|
71
71
|
}
|
|
72
72
|
/** @override */
|
|
73
73
|
lint(start = this.getAbsoluteIndex()) {
|
|
74
|
+
const { childNodes: [argName, argDefault, ...rest] } = this;
|
|
74
75
|
if (!this.getAttribute('include')) {
|
|
75
|
-
|
|
76
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'no-arg', 'unexpected template argument');
|
|
77
|
+
if (argDefault) {
|
|
78
|
+
e.fix = {
|
|
79
|
+
range: [start, e.endIndex],
|
|
80
|
+
text: argDefault.text(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return [e];
|
|
76
84
|
}
|
|
77
|
-
const
|
|
85
|
+
const errors = argName.lint(start + 3);
|
|
78
86
|
if (argDefault) {
|
|
79
87
|
errors.push(...argDefault.lint(start + 4 + String(argName).length));
|
|
80
88
|
}
|
|
81
89
|
if (rest.length > 0) {
|
|
82
90
|
const rect = { start, ...this.getRootNode().posFromIndex(start) };
|
|
83
91
|
errors.push(...rest.map(child => {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'invisible content inside triple braces');
|
|
93
|
+
e.startIndex--;
|
|
94
|
+
e.startCol--;
|
|
95
|
+
e.suggestions = [
|
|
96
|
+
{
|
|
97
|
+
desc: 'remove',
|
|
98
|
+
range: [e.startIndex, e.endIndex],
|
|
99
|
+
text: '',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
desc: 'escape',
|
|
103
|
+
range: [e.startIndex, e.startIndex + 1],
|
|
104
|
+
text: '{{!}}',
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
return e;
|
|
90
108
|
}));
|
|
91
109
|
}
|
|
92
110
|
return errors;
|
package/dist/src/attribute.js
CHANGED
|
@@ -347,11 +347,24 @@ let AttributeToken = (() => {
|
|
|
347
347
|
const root = this.getRootNode();
|
|
348
348
|
rect = { start, ...root.posFromIndex(start) };
|
|
349
349
|
const e = (0, lint_1.generateForChild)(lastChild, rect, 'unclosed-quote', index_1.default.msg('unclosed $1', 'quotes'), 'warning');
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
350
|
+
e.startIndex--;
|
|
351
|
+
e.startCol--;
|
|
352
|
+
const fix = {
|
|
353
|
+
range: [e.endIndex, e.endIndex],
|
|
354
|
+
text: this.#quotes[0],
|
|
355
|
+
};
|
|
356
|
+
if (lastChild.childNodes.some(child => child.type === 'text' && /\s/u.test(child.text()))) {
|
|
357
|
+
e.suggestions = [
|
|
358
|
+
{
|
|
359
|
+
desc: 'quote',
|
|
360
|
+
...fix,
|
|
361
|
+
},
|
|
362
|
+
];
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
e.fix = fix;
|
|
366
|
+
}
|
|
367
|
+
errors.push(e);
|
|
355
368
|
}
|
|
356
369
|
const attrs = extAttrs[tag];
|
|
357
370
|
if (attrs && !attrs.has(name)
|
|
@@ -372,7 +385,20 @@ let AttributeToken = (() => {
|
|
|
372
385
|
}
|
|
373
386
|
else if (name === 'tabindex' && typeof value === 'string' && value.trim() !== '0') {
|
|
374
387
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
375
|
-
|
|
388
|
+
const e = (0, lint_1.generateForChild)(lastChild, rect, 'illegal-attr', 'nonzero tabindex');
|
|
389
|
+
e.suggestions = [
|
|
390
|
+
{
|
|
391
|
+
desc: 'remove',
|
|
392
|
+
range: [start, e.endIndex],
|
|
393
|
+
text: '',
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
desc: '0 tabindex',
|
|
397
|
+
range: [e.startIndex, e.endIndex],
|
|
398
|
+
text: '0',
|
|
399
|
+
},
|
|
400
|
+
];
|
|
401
|
+
errors.push(e);
|
|
376
402
|
}
|
|
377
403
|
return errors;
|
|
378
404
|
}
|
package/dist/src/attributes.js
CHANGED
|
@@ -149,13 +149,23 @@ class AttributesToken extends index_2.Token {
|
|
|
149
149
|
let rect;
|
|
150
150
|
if (parentNode?.type === 'html' && parentNode.closing && this.text().trim()) {
|
|
151
151
|
rect = { start, ...this.getRootNode().posFromIndex(start) };
|
|
152
|
-
|
|
152
|
+
const e = (0, lint_1.generateForSelf)(this, rect, 'no-ignored', 'attributes of a closing tag');
|
|
153
|
+
e.fix = { range: [start, e.endIndex], text: '' };
|
|
154
|
+
errors.push(e);
|
|
153
155
|
}
|
|
154
156
|
for (let i = 0; i < length; i++) {
|
|
155
157
|
const attr = childNodes[i];
|
|
156
158
|
if (attr instanceof atom_1.AtomToken && attr.text().trim()) {
|
|
157
159
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
158
|
-
|
|
160
|
+
const e = (0, lint_1.generateForChild)(attr, rect, 'no-ignored', 'containing invalid attribute');
|
|
161
|
+
e.suggestions = [
|
|
162
|
+
{
|
|
163
|
+
desc: 'remove',
|
|
164
|
+
range: [e.startIndex, e.endIndex],
|
|
165
|
+
text: ' ',
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
errors.push(e);
|
|
159
169
|
}
|
|
160
170
|
else if (attr instanceof attribute_1.AttributeToken) {
|
|
161
171
|
const { name } = attr;
|
|
@@ -78,7 +78,23 @@ class ConverterFlagsToken extends index_2.Token {
|
|
|
78
78
|
&& !variantFlags.has(flag)
|
|
79
79
|
&& !unknownFlags.has(flag)
|
|
80
80
|
&& (variantFlags.size > 0 || !validFlags.has(flag))) {
|
|
81
|
-
|
|
81
|
+
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'invalid conversion flag');
|
|
82
|
+
if (variantFlags.size === 0 && definedFlags.has(flag.toUpperCase())) {
|
|
83
|
+
e.fix = {
|
|
84
|
+
range: [e.startIndex, e.endIndex],
|
|
85
|
+
text: flag.toUpperCase(),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
e.suggestions = [
|
|
90
|
+
{
|
|
91
|
+
desc: 'remove',
|
|
92
|
+
range: [e.startIndex, e.endIndex],
|
|
93
|
+
text: '',
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
errors.push(e);
|
|
82
98
|
}
|
|
83
99
|
}
|
|
84
100
|
return errors;
|
package/dist/src/gallery.js
CHANGED
|
@@ -76,6 +76,18 @@ class GalleryToken extends index_2.Token {
|
|
|
76
76
|
endLine: startLine,
|
|
77
77
|
startCol,
|
|
78
78
|
endCol: startCol + length,
|
|
79
|
+
suggestions: [
|
|
80
|
+
{
|
|
81
|
+
desc: 'remove',
|
|
82
|
+
range: [start, start + length],
|
|
83
|
+
text: '',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
desc: 'comment',
|
|
87
|
+
range: [start, start + length],
|
|
88
|
+
text: `<!--${str}-->`,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
79
91
|
});
|
|
80
92
|
}
|
|
81
93
|
else if (child.type !== 'noinclude' && child.type !== 'text') {
|
package/dist/src/html.js
CHANGED
|
@@ -216,6 +216,24 @@ let HtmlToken = (() => {
|
|
|
216
216
|
if (ancestor && magicWords.has(ancestor.name)) {
|
|
217
217
|
error.severity = 'warning';
|
|
218
218
|
}
|
|
219
|
+
else {
|
|
220
|
+
error.suggestions = [
|
|
221
|
+
{
|
|
222
|
+
desc: 'remove',
|
|
223
|
+
range: [start, error.endIndex],
|
|
224
|
+
text: '',
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else if (msg === 'tag that is both closing and self-closing') {
|
|
230
|
+
const { html: [, , voidTags] } = this.getAttribute('config');
|
|
231
|
+
if (voidTags.includes(this.name)) {
|
|
232
|
+
error.fix = {
|
|
233
|
+
range: [start + 1, start + 2],
|
|
234
|
+
text: '',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
219
237
|
}
|
|
220
238
|
errors.push(error);
|
|
221
239
|
}
|
|
@@ -233,7 +251,7 @@ let HtmlToken = (() => {
|
|
|
233
251
|
refError ??= (0, lint_1.generateForSelf)(this, { start }, 'h1', '');
|
|
234
252
|
errors.push({
|
|
235
253
|
...refError,
|
|
236
|
-
rule: '
|
|
254
|
+
rule: 'bold-header',
|
|
237
255
|
message: index_1.default.msg('bold in section header'),
|
|
238
256
|
severity: 'warning',
|
|
239
257
|
});
|
|
@@ -168,7 +168,12 @@ class ImageParameterToken extends index_2.Token {
|
|
|
168
168
|
lint(start = this.getAbsoluteIndex()) {
|
|
169
169
|
const errors = super.lint(start), { link, name } = this;
|
|
170
170
|
if (name === 'invalid') {
|
|
171
|
-
|
|
171
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'invalid-gallery', 'invalid gallery image parameter');
|
|
172
|
+
e.fix = {
|
|
173
|
+
range: [start, start + e.endIndex],
|
|
174
|
+
text: '',
|
|
175
|
+
};
|
|
176
|
+
errors.push(e);
|
|
172
177
|
}
|
|
173
178
|
else if (typeof link === 'object' && link.encoded) {
|
|
174
179
|
errors.push((0, lint_1.generateForSelf)(this, { start }, 'url-encoding', 'unnecessary URL encoding in an internal link'));
|
package/dist/src/index.js
CHANGED
|
@@ -414,7 +414,17 @@ class Token extends element_1.AstElement {
|
|
|
414
414
|
}
|
|
415
415
|
for (const value of Object.values(record)) {
|
|
416
416
|
if (value.size > 1) {
|
|
417
|
-
errors.push(...[...value].map(cat =>
|
|
417
|
+
errors.push(...[...value].map(cat => {
|
|
418
|
+
const e = (0, lint_1.generateForSelf)(cat, { start: cat.getAbsoluteIndex() }, 'no-duplicate', 'duplicated category');
|
|
419
|
+
e.suggestions = [
|
|
420
|
+
{
|
|
421
|
+
desc: 'remove',
|
|
422
|
+
range: [e.startIndex, e.endIndex],
|
|
423
|
+
text: '',
|
|
424
|
+
},
|
|
425
|
+
];
|
|
426
|
+
return e;
|
|
427
|
+
}));
|
|
418
428
|
}
|
|
419
429
|
}
|
|
420
430
|
}
|
package/dist/src/link/base.js
CHANGED
|
@@ -141,14 +141,34 @@ class LinkBaseToken extends index_2.Token {
|
|
|
141
141
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
142
142
|
errors.push((0, lint_1.generateForChild)(target, rect, 'url-encoding', 'unnecessary URL encoding in an internal link'));
|
|
143
143
|
}
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
if (linkType === 'link' || linkType === 'category') {
|
|
145
|
+
const textNode = linkText?.childNodes.find((c) => c.type === 'text' && c.data.includes('|'));
|
|
146
|
+
if (textNode) {
|
|
147
|
+
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
148
|
+
const e = (0, lint_1.generateForChild)(linkText, rect, 'pipe-like', 'additional "|" in the link text', 'warning');
|
|
149
|
+
e.suggestions = [
|
|
150
|
+
{
|
|
151
|
+
desc: 'escape',
|
|
152
|
+
range: [
|
|
153
|
+
e.startIndex + textNode.getRelativeIndex(),
|
|
154
|
+
e.startIndex + textNode.getRelativeIndex() + textNode.data.length,
|
|
155
|
+
],
|
|
156
|
+
text: textNode.data.replace(/\|/gu, '|'),
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
errors.push(e);
|
|
160
|
+
}
|
|
148
161
|
}
|
|
149
|
-
|
|
162
|
+
if (linkType !== 'link' && fragment !== undefined) {
|
|
150
163
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
151
|
-
|
|
164
|
+
const e = (0, lint_1.generateForChild)(target, rect, 'no-ignored', 'useless fragment'), textNode = target.childNodes.find((c) => c.type === 'text' && c.data.includes('#'));
|
|
165
|
+
if (textNode) {
|
|
166
|
+
e.fix = {
|
|
167
|
+
range: [e.startIndex + textNode.getRelativeIndex() + textNode.data.indexOf('#'), e.endIndex],
|
|
168
|
+
text: '',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
errors.push(e);
|
|
152
172
|
}
|
|
153
173
|
return errors;
|
|
154
174
|
}
|
package/dist/src/magicLink.js
CHANGED
|
@@ -114,17 +114,41 @@ let MagicLinkToken = (() => {
|
|
|
114
114
|
const refError = (0, lint_1.generateForChild)(child, rect, 'unterminated-url', '', 'warning');
|
|
115
115
|
regexGlobal.lastIndex = 0;
|
|
116
116
|
for (let mt = regexGlobal.exec(data); mt; mt = regexGlobal.exec(data)) {
|
|
117
|
-
const { index, 0: s } = mt, lines = data.slice(0, index).split('\n'), top = lines.length, left = lines[top - 1].length, startIndex = refError.startIndex + index, startLine = refError.startLine + top - 1, startCol = top === 1 ? refError.startCol + left : left;
|
|
118
|
-
|
|
117
|
+
const { index, 0: s } = mt, lines = data.slice(0, index).split('\n'), top = lines.length, left = lines[top - 1].length, startIndex = refError.startIndex + index, startLine = refError.startLine + top - 1, startCol = top === 1 ? refError.startCol + left : left, pipe = s.startsWith('|');
|
|
118
|
+
const e = {
|
|
119
119
|
...refError,
|
|
120
|
-
message: index_1.default.msg('$1 in URL',
|
|
120
|
+
message: index_1.default.msg('$1 in URL', pipe ? '"|"' : 'full-width punctuation'),
|
|
121
121
|
startIndex,
|
|
122
122
|
endIndex: startIndex + s.length,
|
|
123
123
|
startLine,
|
|
124
124
|
endLine: startLine,
|
|
125
125
|
startCol,
|
|
126
126
|
endCol: startCol + s.length,
|
|
127
|
-
}
|
|
127
|
+
};
|
|
128
|
+
if (!pipe) {
|
|
129
|
+
e.suggestions = [
|
|
130
|
+
{
|
|
131
|
+
desc: 'whitespace',
|
|
132
|
+
range: [startIndex, startIndex],
|
|
133
|
+
text: ' ',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
desc: 'escape',
|
|
137
|
+
range: [startIndex, e.endIndex],
|
|
138
|
+
text: encodeURI(s),
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
else if (s.length === 1) {
|
|
143
|
+
e.suggestions = [
|
|
144
|
+
{
|
|
145
|
+
desc: 'whitespace',
|
|
146
|
+
range: [startIndex, startIndex + 1],
|
|
147
|
+
text: ' ',
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
errors.push(e);
|
|
128
152
|
}
|
|
129
153
|
}
|
|
130
154
|
return errors;
|
|
@@ -148,7 +172,7 @@ let MagicLinkToken = (() => {
|
|
|
148
172
|
this.constructorError('不可插入模板');
|
|
149
173
|
}
|
|
150
174
|
else if (!debug_1.Shadow.running && type === 'magic-word' && name !== '!' && name !== '=') {
|
|
151
|
-
this.constructorError('不可插入
|
|
175
|
+
this.constructorError('不可插入 "{{!}}" 或 "{{=}}" 以外的魔术字');
|
|
152
176
|
}
|
|
153
177
|
}
|
|
154
178
|
return super.insertAt(token, i);
|
package/dist/src/nested.js
CHANGED
|
@@ -61,7 +61,20 @@ class NestedToken extends index_2.Token {
|
|
|
61
61
|
return str && !/^<!--.*-->$/su.test(str);
|
|
62
62
|
}).map(child => {
|
|
63
63
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
64
|
-
|
|
64
|
+
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', index_1.default.msg('invalid content in <$1>', this.name));
|
|
65
|
+
e.suggestions = [
|
|
66
|
+
{
|
|
67
|
+
desc: 'remove',
|
|
68
|
+
range: [e.startIndex, e.endIndex],
|
|
69
|
+
text: '',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
desc: 'comment',
|
|
73
|
+
range: [e.startIndex, e.startIndex],
|
|
74
|
+
text: `<!--${String(child)}-->`,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
return e;
|
|
65
78
|
}),
|
|
66
79
|
];
|
|
67
80
|
}
|
|
@@ -31,9 +31,15 @@ class CommentToken extends (0, hidden_1.hiddenToken)(base_1.NowikiBaseToken) {
|
|
|
31
31
|
}
|
|
32
32
|
/** @override */
|
|
33
33
|
lint(start = this.getAbsoluteIndex()) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (this.closed) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'unclosed-comment', index_1.default.msg('unclosed $1', 'HTML comment'));
|
|
38
|
+
e.fix = {
|
|
39
|
+
range: [e.endIndex, e.endIndex],
|
|
40
|
+
text: '-->',
|
|
41
|
+
};
|
|
42
|
+
return [e];
|
|
37
43
|
}
|
|
38
44
|
/** @private */
|
|
39
45
|
toString() {
|
package/dist/src/nowiki/index.js
CHANGED
|
@@ -12,9 +12,15 @@ class NowikiToken extends base_1.NowikiBaseToken {
|
|
|
12
12
|
/** @override */
|
|
13
13
|
lint(start = this.getAbsoluteIndex()) {
|
|
14
14
|
const { name, firstChild: { data } } = this;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if ((name === 'templatestyles' || name === 'section') && data) {
|
|
16
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'void-ext', index_1.default.msg('nothing should be in <$1>', name));
|
|
17
|
+
e.fix = {
|
|
18
|
+
range: [start - 1, e.endIndex + name.length + 3],
|
|
19
|
+
text: '/>',
|
|
20
|
+
};
|
|
21
|
+
return [e];
|
|
22
|
+
}
|
|
23
|
+
return super.lint(start);
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
exports.NowikiToken = NowikiToken;
|
package/dist/src/nowiki/quote.js
CHANGED
|
@@ -79,6 +79,13 @@ let QuoteToken = (() => {
|
|
|
79
79
|
startCol: endCol - length,
|
|
80
80
|
endLine,
|
|
81
81
|
endCol,
|
|
82
|
+
suggestions: [
|
|
83
|
+
{
|
|
84
|
+
desc: 'escape',
|
|
85
|
+
range: [startIndex, endIndex],
|
|
86
|
+
text: '''.repeat(length),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
82
89
|
});
|
|
83
90
|
}
|
|
84
91
|
if (nextSibling?.type === 'text' && nextSibling.data.startsWith(`'`)) {
|
|
@@ -91,6 +98,13 @@ let QuoteToken = (() => {
|
|
|
91
98
|
startLine,
|
|
92
99
|
startCol,
|
|
93
100
|
endCol: startCol + length,
|
|
101
|
+
suggestions: [
|
|
102
|
+
{
|
|
103
|
+
desc: 'escape',
|
|
104
|
+
range: [startIndex, endIndex],
|
|
105
|
+
text: '''.repeat(length),
|
|
106
|
+
},
|
|
107
|
+
],
|
|
94
108
|
});
|
|
95
109
|
}
|
|
96
110
|
if (bold && this.closest('heading-title')) {
|
|
@@ -47,7 +47,15 @@ class ParamTagToken extends index_2.Token {
|
|
|
47
47
|
return str && !(i >= 0 ? /^[a-z]+(?:\[\])?\s*(?:=|$)/iu : /^[a-z]+(?:\[\])?\s*=/iu).test(str);
|
|
48
48
|
}).map(child => {
|
|
49
49
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
|
50
|
-
|
|
50
|
+
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', index_1.default.msg('invalid parameter of <$1>', this.name));
|
|
51
|
+
e.suggestions = [
|
|
52
|
+
{
|
|
53
|
+
desc: 'remove',
|
|
54
|
+
range: [e.startIndex, e.endIndex],
|
|
55
|
+
text: '',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
return e;
|
|
51
59
|
});
|
|
52
60
|
}
|
|
53
61
|
/** @override */
|
package/dist/src/parameter.js
CHANGED
|
@@ -159,14 +159,16 @@ let ParameterToken = (() => {
|
|
|
159
159
|
const errors = super.lint(start), { firstChild } = this, link = new RegExp(`https?://${string_1.extUrlCharFirst}${string_1.extUrlChar}$`, 'iu').exec(firstChild.text())?.[0];
|
|
160
160
|
if (link && new URL(link).search) {
|
|
161
161
|
const e = (0, lint_1.generateForChild)(firstChild, { start }, 'unescaped', 'unescaped query string in an anonymous parameter');
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
e.startIndex = e.endIndex;
|
|
163
|
+
e.startLine = e.endLine;
|
|
164
|
+
e.startCol = e.endCol;
|
|
165
|
+
e.endIndex++;
|
|
166
|
+
e.endCol++;
|
|
167
|
+
e.fix = {
|
|
168
|
+
range: [e.startIndex, e.endIndex],
|
|
169
|
+
text: '{{=}}',
|
|
170
|
+
};
|
|
171
|
+
errors.push(e);
|
|
170
172
|
}
|
|
171
173
|
return errors;
|
|
172
174
|
}
|
package/dist/src/table/td.js
CHANGED
|
@@ -193,7 +193,24 @@ let TdToken = (() => {
|
|
|
193
193
|
if (child.type === 'text') {
|
|
194
194
|
const { data } = child;
|
|
195
195
|
if (data.includes('|')) {
|
|
196
|
-
|
|
196
|
+
const isError = data.includes('||'), e = (0, lint_1.generateForChild)(child, { start }, 'pipe-like', 'additional "|" in a table cell', isError ? 'error' : 'warning');
|
|
197
|
+
if (isError) {
|
|
198
|
+
const syntax = { caption: '|+', td: '|', th: '!' }[this.subtype];
|
|
199
|
+
e.fix = {
|
|
200
|
+
range: [e.startIndex, e.endIndex],
|
|
201
|
+
text: data.replace(/\|\|/gu, `\n${syntax}`),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
e.suggestions = [
|
|
206
|
+
{
|
|
207
|
+
desc: 'escape',
|
|
208
|
+
range: [e.startIndex, e.endIndex],
|
|
209
|
+
text: data.replace(/\|/gu, '|'),
|
|
210
|
+
},
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
errors.push(e);
|
|
197
214
|
}
|
|
198
215
|
}
|
|
199
216
|
}
|
package/dist/src/table/trBase.js
CHANGED
|
@@ -30,13 +30,11 @@ class TrBaseToken extends base_1.TableBaseToken {
|
|
|
30
30
|
catch { }
|
|
31
31
|
}
|
|
32
32
|
const error = (0, lint_1.generateForChild)(inter, { start }, 'fostered-content', 'content to be moved out from the table');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
startCol: 0,
|
|
39
|
-
});
|
|
33
|
+
error.severity = first.type === 'template' ? 'warning' : 'error';
|
|
34
|
+
error.startIndex++;
|
|
35
|
+
error.startLine++;
|
|
36
|
+
error.startCol = 0;
|
|
37
|
+
errors.push(error);
|
|
40
38
|
return errors;
|
|
41
39
|
}
|
|
42
40
|
/* NOT FOR BROWSER */
|
|
@@ -38,9 +38,15 @@ class IncludeToken extends (0, hidden_1.hiddenToken)(index_2.TagPairToken) {
|
|
|
38
38
|
}
|
|
39
39
|
/** @override */
|
|
40
40
|
lint(start = this.getAbsoluteIndex()) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (this.closed) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'unclosed-comment', index_1.default.msg('unclosed $1', `<${this.name}>`));
|
|
45
|
+
e.fix = {
|
|
46
|
+
range: [e.endIndex, e.endIndex],
|
|
47
|
+
text: `</${this.name}>`,
|
|
48
|
+
};
|
|
49
|
+
return [e];
|
|
44
50
|
}
|
|
45
51
|
/* NOT FOR BROWSER */
|
|
46
52
|
/** @override */
|
package/dist/src/transclude.js
CHANGED
|
@@ -232,7 +232,14 @@ class TranscludeToken extends index_2.Token {
|
|
|
232
232
|
const title = this.#getTitle();
|
|
233
233
|
if (title.fragment !== undefined) {
|
|
234
234
|
rect = { start, ...this.getRootNode().posFromIndex(start) };
|
|
235
|
-
|
|
235
|
+
const child = childNodes[type === 'template' ? 0 : 1], e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment'), textNode = child.childNodes.find((c) => c.type === 'text' && c.data.includes('#'));
|
|
236
|
+
if (textNode) {
|
|
237
|
+
e.fix = {
|
|
238
|
+
range: [e.startIndex + textNode.getRelativeIndex() + textNode.data.indexOf('#'), e.endIndex],
|
|
239
|
+
text: '',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
errors.push(e);
|
|
236
243
|
}
|
|
237
244
|
if (!title.valid) {
|
|
238
245
|
rect ??= { start, ...this.getRootNode().posFromIndex(start) };
|
package/dist/util/diff.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.info = exports.error = exports.diff = exports.cmd = void 0;
|
|
4
4
|
const fs = require("fs/promises");
|
|
5
5
|
const child_process_1 = require("child_process");
|
|
6
|
+
const chalk = require("chalk");
|
|
6
7
|
process.on('unhandledRejection', e => {
|
|
7
8
|
console.error(e);
|
|
8
9
|
});
|
|
@@ -72,11 +73,11 @@ const diff = async (oldStr, newStr, uid = -1) => {
|
|
|
72
73
|
exports.diff = diff;
|
|
73
74
|
/** @implements */
|
|
74
75
|
const error = (msg, ...args) => {
|
|
75
|
-
console.error(
|
|
76
|
+
console.error(chalk.red(msg), ...args);
|
|
76
77
|
};
|
|
77
78
|
exports.error = error;
|
|
78
79
|
/** @implements */
|
|
79
80
|
const info = (msg, ...args) => {
|
|
80
|
-
console.info(
|
|
81
|
+
console.info(chalk.green(msg), ...args);
|
|
81
82
|
};
|
|
82
83
|
exports.info = info;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikiparser-node",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A Node.js parser for MediaWiki markup with AST",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@typescript-eslint/eslint-plugin": "^6.19.1",
|
|
49
49
|
"@typescript-eslint/parser": "^6.19.1",
|
|
50
50
|
"ajv-cli": "^5.0.0",
|
|
51
|
+
"chalk": "^4.1.2",
|
|
51
52
|
"eslint": "^8.56.0",
|
|
52
53
|
"eslint-plugin-es-x": "^7.5.0",
|
|
53
54
|
"eslint-plugin-eslint-comments": "^3.2.0",
|