wikilint 2.17.1 → 2.18.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/README.md +17 -0
- package/bin/config.js +3 -0
- package/config/.schema.json +1 -1
- package/config/default.json +86 -23
- package/config/enwiki.json +20 -13
- package/config/llwiki.json +99 -7
- package/config/minimum.json +6 -3
- package/config/moegirl.json +12 -12
- package/config/zhwiki.json +52 -21
- package/data/ext/score.json +1033 -0
- package/dist/bin/config.js +112 -0
- package/dist/lib/document.d.ts +2 -1
- package/dist/lib/document.js +10 -5
- package/dist/lib/lsp.d.ts +2 -0
- package/dist/lib/lsp.js +174 -33
- package/package.json +12 -12
- package/dist/util/sharable.d.ts +0 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable n/no-process-exit */
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const assert_1 = __importDefault(require("assert"));
|
|
10
|
+
const cm_1 = require("@bhsd/common/dist/cm");
|
|
11
|
+
const { argv } = process, [, , site, , force, old] = argv;
|
|
12
|
+
let [, , , url] = argv;
|
|
13
|
+
if (!site || !url) {
|
|
14
|
+
console.error('Usage: npx getParserConfig <site> <script path> [force]');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
else if (/(?:\.php|\/)$/u.test(url)) {
|
|
18
|
+
url = url.slice(0, url.lastIndexOf('/'));
|
|
19
|
+
}
|
|
20
|
+
let mwConfig;
|
|
21
|
+
const mw = {
|
|
22
|
+
loader: {
|
|
23
|
+
/** @ignore */
|
|
24
|
+
impl(callback) {
|
|
25
|
+
Object.entries(callback()[1].files).find(([k]) => k.endsWith('.data.js'))[1]();
|
|
26
|
+
},
|
|
27
|
+
/** @ignore */
|
|
28
|
+
implement(_, callback) {
|
|
29
|
+
callback();
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
config: {
|
|
33
|
+
/** @ignore */
|
|
34
|
+
set({ extCodeMirrorConfig }) {
|
|
35
|
+
mwConfig = extCodeMirrorConfig;
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Converts an array to an object.
|
|
41
|
+
* @param config parser configuration
|
|
42
|
+
* @param config.articlePath article path
|
|
43
|
+
*/
|
|
44
|
+
const arrToObj = ({ articlePath, ...obj }) => {
|
|
45
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
46
|
+
if (Array.isArray(v) && v.every(x => typeof x === 'string')) {
|
|
47
|
+
Object.assign(obj, { [k]: Object.fromEntries(v.map(x => [x, true])) });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return obj;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Gets the aliases of magic words.
|
|
54
|
+
* @param magicwords magic words
|
|
55
|
+
* @param targets magic word names
|
|
56
|
+
*/
|
|
57
|
+
const getAliases = (magicwords, targets) => magicwords
|
|
58
|
+
.filter(({ name }) => targets.has(name))
|
|
59
|
+
.flatMap(({ aliases }) => aliases.map(s => s.replace(/:$/u, '').toLowerCase()));
|
|
60
|
+
/**
|
|
61
|
+
* Filters out gadget-related namespaces.
|
|
62
|
+
* @param id namespace ID
|
|
63
|
+
*/
|
|
64
|
+
const filterGadget = (id) => {
|
|
65
|
+
const n = Number(id);
|
|
66
|
+
return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
|
|
67
|
+
};
|
|
68
|
+
(async () => {
|
|
69
|
+
const m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror${old ? '.data' : ''}`)).text(), params = {
|
|
70
|
+
action: 'query',
|
|
71
|
+
meta: 'siteinfo',
|
|
72
|
+
siprop: `general|magicwords|namespaces|namespacealiases${old ? '|variables' : ''}`,
|
|
73
|
+
format: 'json',
|
|
74
|
+
formatversion: '2',
|
|
75
|
+
}, { query: { general: { variants }, magicwords, namespaces, namespacealiases, variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`)).json();
|
|
76
|
+
eval(m); // eslint-disable-line no-eval
|
|
77
|
+
const dir = path_1.default.join('..', '..', 'config'), ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
|
|
78
|
+
.flatMap(([id, { name, canonical = '' }]) => [
|
|
79
|
+
[id, name],
|
|
80
|
+
...name === canonical ? [] : [[id, canonical]],
|
|
81
|
+
]), config = {
|
|
82
|
+
...(0, cm_1.getParserConfig)(require(path_1.default.join(dir, 'minimum')), mwConfig),
|
|
83
|
+
...(0, cm_1.getKeywords)(magicwords),
|
|
84
|
+
variants: (0, cm_1.getVariants)(variants),
|
|
85
|
+
namespaces: Object.fromEntries(ns),
|
|
86
|
+
nsid: Object.fromEntries([
|
|
87
|
+
...ns.map(([id, canonical]) => [canonical.toLowerCase(), Number(id)]),
|
|
88
|
+
...namespacealiases.filter(({ id }) => filterGadget(id)).map(({ id, alias }) => [alias.toLowerCase(), id]),
|
|
89
|
+
]),
|
|
90
|
+
...old && { variable: [...variables, '='] },
|
|
91
|
+
articlePath: '/wiki/$1',
|
|
92
|
+
};
|
|
93
|
+
config.doubleUnderscore[0] = [];
|
|
94
|
+
config.doubleUnderscore[1] = [];
|
|
95
|
+
Object.assign(config.parserFunction[0], (0, cm_1.getConfig)(magicwords, ({ name }) => name === 'msgnw'));
|
|
96
|
+
if ('#choose' in config.parserFunction[0]) {
|
|
97
|
+
delete config.parserFunction[0]['choose'];
|
|
98
|
+
const i = config.variable.indexOf('choose');
|
|
99
|
+
if (i !== -1) {
|
|
100
|
+
config.variable.splice(i, 1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
config.parserFunction[2] = getAliases(magicwords, new Set(['msg', 'raw']));
|
|
104
|
+
config.parserFunction[3] = getAliases(magicwords, new Set(['subst', 'safesubst']));
|
|
105
|
+
const file = path_1.default.join(__dirname, dir, `${site}.json`), exists = fs_1.default.existsSync(file);
|
|
106
|
+
if (exists) {
|
|
107
|
+
assert_1.default.deepStrictEqual(arrToObj(require(file)), arrToObj(config));
|
|
108
|
+
}
|
|
109
|
+
if (force || !exists) {
|
|
110
|
+
fs_1.default.writeFileSync(file, `${JSON.stringify(config, null, '\t')}\n`);
|
|
111
|
+
}
|
|
112
|
+
})();
|
package/dist/lib/document.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import type { LanguageService as CSSLanguageService, Stylesheet } from 'vscode-c
|
|
|
5
5
|
import type { PublicApi } from 'stylelint';
|
|
6
6
|
import type { Token } from '../internal';
|
|
7
7
|
export declare const jsonTags: string[];
|
|
8
|
-
declare let jsonLSP: JSONLanguageService | undefined, cssLSP: CSSLanguageService | undefined
|
|
8
|
+
declare let jsonLSP: JSONLanguageService | undefined, cssLSP: CSSLanguageService | undefined;
|
|
9
|
+
declare const stylelint: Promise<PublicApi | undefined>;
|
|
9
10
|
export { jsonLSP, cssLSP, stylelint };
|
|
10
11
|
/** embedded document */
|
|
11
12
|
declare class EmbeddedDocument implements TextDocument {
|
package/dist/lib/document.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.EmbeddedCSSDocument = exports.EmbeddedJSONDocument = exports.stylelint =
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const common_1 = require("@bhsd/common");
|
|
9
9
|
exports.jsonTags = ['templatedata', 'mapframe', 'maplink'];
|
|
10
|
-
let jsonLSP, cssLSP
|
|
10
|
+
let jsonLSP, cssLSP;
|
|
11
11
|
try {
|
|
12
12
|
exports.jsonLSP = jsonLSP = require('vscode-json-languageservice')
|
|
13
13
|
.getLanguageService({
|
|
@@ -39,10 +39,15 @@ try {
|
|
|
39
39
|
.getCSSLanguageService();
|
|
40
40
|
}
|
|
41
41
|
catch { }
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const stylelint = (async () => {
|
|
43
|
+
try {
|
|
44
|
+
return (await import('stylelint')).default;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
})();
|
|
50
|
+
exports.stylelint = stylelint;
|
|
46
51
|
/** embedded document */
|
|
47
52
|
class EmbeddedDocument {
|
|
48
53
|
uri = '';
|
package/dist/lib/lsp.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare const tasks: WeakMap<object, Parser.LanguageService>;
|
|
|
11
11
|
export declare class LanguageService implements LanguageServiceBase {
|
|
12
12
|
#private;
|
|
13
13
|
include: boolean;
|
|
14
|
+
lilypond: string;
|
|
15
|
+
lilypondData: string[];
|
|
14
16
|
/** @param uri 任务标识 */
|
|
15
17
|
constructor(uri: object);
|
|
16
18
|
/** @implements */
|
package/dist/lib/lsp.js
CHANGED
|
@@ -10,15 +10,18 @@ const lint_1 = require("../util/lint");
|
|
|
10
10
|
const string_1 = require("../util/string");
|
|
11
11
|
const index_1 = __importDefault(require("../index"));
|
|
12
12
|
/* NOT FOR BROWSER ONLY */
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
14
|
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const util_1 = __importDefault(require("util"));
|
|
16
|
+
const child_process_1 = require("child_process");
|
|
17
|
+
const crypto_1 = require("crypto");
|
|
14
18
|
const stylelint_1 = require("@bhsd/common/dist/stylelint");
|
|
15
19
|
const document_1 = require("./document");
|
|
16
|
-
/* NOT FOR BROWSER ONLY */
|
|
17
20
|
/** @see https://www.npmjs.com/package/stylelint-config-recommended */
|
|
18
21
|
const cssRules = {
|
|
19
22
|
'block-no-empty': null,
|
|
20
23
|
'property-no-unknown': null,
|
|
21
|
-
}, jsonSelector = document_1.jsonTags.map(s => `ext-inner#${s}`).join();
|
|
24
|
+
}, jsonSelector = document_1.jsonTags.map(s => `ext-inner#${s}`).join(), scores = new Map();
|
|
22
25
|
/* NOT FOR BROWSER ONLY END */
|
|
23
26
|
exports.tasks = new WeakMap();
|
|
24
27
|
const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']), nameAttrs = new Set(['name', 'extends', 'follow']), groupAttrs = new Set(['group']), renameTypes = new Set([
|
|
@@ -80,28 +83,39 @@ const createNodeRange = (token) => {
|
|
|
80
83
|
* @param pos.line line number
|
|
81
84
|
* @param pos.character character number
|
|
82
85
|
* @param extra extra text
|
|
86
|
+
* @param getDoc documentation method
|
|
83
87
|
*/
|
|
84
|
-
const getCompletion = (words, kind, mt, { line, character }, extra) => [...new Set(words)].map((w) =>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const getCompletion = (words, kind, mt, { line, character }, extra, getDoc) => [...new Set(words)].map((w) => {
|
|
89
|
+
const doc = getDoc?.(w)?.description;
|
|
90
|
+
return {
|
|
91
|
+
label: w,
|
|
92
|
+
kind,
|
|
93
|
+
textEdit: {
|
|
94
|
+
range: {
|
|
95
|
+
start: { line, character: character - mt.length },
|
|
96
|
+
end: { line, character },
|
|
97
|
+
},
|
|
98
|
+
newText: w + (extra ?? ''),
|
|
91
99
|
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
...doc && {
|
|
101
|
+
documentation: {
|
|
102
|
+
kind: 'markdown',
|
|
103
|
+
value: doc,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
});
|
|
95
108
|
/**
|
|
96
109
|
* Get the caret position at the position from a word.
|
|
97
110
|
* @param root root token
|
|
111
|
+
* @param text source code
|
|
98
112
|
* @param pos position
|
|
99
113
|
* @param pos.line line number
|
|
100
114
|
* @param pos.character character number
|
|
101
115
|
*/
|
|
102
|
-
const caretPositionFromWord = (root, { line, character }) => {
|
|
116
|
+
const caretPositionFromWord = (root, text, { line, character }) => {
|
|
103
117
|
const index = root.indexFromPos(line, character);
|
|
104
|
-
return root.caretPositionFromIndex(index + Number(/\w/u.test(
|
|
118
|
+
return root.caretPositionFromIndex(index + Number(/\w/u.test(text.charAt(index))));
|
|
105
119
|
};
|
|
106
120
|
/**
|
|
107
121
|
* Get the attribute of a `<ref>` tag.
|
|
@@ -167,15 +181,13 @@ const getQuickFix = (root, fix, preferred = false) => ({
|
|
|
167
181
|
});
|
|
168
182
|
/* NOT FOR BROWSER ONLY */
|
|
169
183
|
/**
|
|
170
|
-
*
|
|
171
|
-
* @param
|
|
172
|
-
* @param
|
|
173
|
-
* @param line line number
|
|
174
|
-
* @param column column number
|
|
184
|
+
* Correct the position of an error.
|
|
185
|
+
* @param height
|
|
186
|
+
* @param width
|
|
187
|
+
* @param line 0-based line number
|
|
188
|
+
* @param column 0-based column number
|
|
175
189
|
*/
|
|
176
|
-
const
|
|
177
|
-
const { top, left, height, width } = rect, start = bottom - height - 1;
|
|
178
|
-
line -= start;
|
|
190
|
+
const adjustPos = (height, width, line, column) => {
|
|
179
191
|
if (line === 0) {
|
|
180
192
|
line = 1;
|
|
181
193
|
column = 0;
|
|
@@ -184,8 +196,38 @@ const getStylelintPos = (rect, bottom, line, column) => {
|
|
|
184
196
|
line = height;
|
|
185
197
|
column = width;
|
|
186
198
|
}
|
|
199
|
+
return [line, column];
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Get the position of a Stylelint error.
|
|
203
|
+
* @param rect bounding client rect of the token
|
|
204
|
+
* @param bottom bottom of the style block
|
|
205
|
+
* @param line line number
|
|
206
|
+
* @param column column number
|
|
207
|
+
*/
|
|
208
|
+
const getStylelintPos = (rect, bottom, line, column) => {
|
|
209
|
+
const { top, left, height, width } = rect, start = bottom - height - 1;
|
|
210
|
+
line -= start;
|
|
211
|
+
[line, column] = adjustPos(height, width, line, column);
|
|
187
212
|
return (0, lint_1.getEndPos)(top, left, line, column);
|
|
188
213
|
};
|
|
214
|
+
/**
|
|
215
|
+
* Convert LilyPond errors to VSCode diagnostics.
|
|
216
|
+
* @param token `<score>` extension token
|
|
217
|
+
* @param errors LilyPond errors
|
|
218
|
+
*/
|
|
219
|
+
const getLilyPondDiagnostics = (token, errors) => {
|
|
220
|
+
const { top, left } = token.lastChild.getBoundingClientRect();
|
|
221
|
+
return errors.map(({ line, col, message }) => {
|
|
222
|
+
const pos = (0, lint_1.getEndPos)(top, left, line, col);
|
|
223
|
+
return {
|
|
224
|
+
range: { start: pos, end: pos },
|
|
225
|
+
severity: 1,
|
|
226
|
+
source: 'LilyPond',
|
|
227
|
+
message,
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
};
|
|
189
231
|
/**
|
|
190
232
|
* Get the end position of a section.
|
|
191
233
|
* @param section section
|
|
@@ -213,18 +255,38 @@ class LanguageService {
|
|
|
213
255
|
include = true;
|
|
214
256
|
/** @private */
|
|
215
257
|
data;
|
|
258
|
+
/* NOT FOR BROWSER ONLY */
|
|
259
|
+
lilypond;
|
|
260
|
+
lilypondData;
|
|
261
|
+
/* NOT FOR BROWSER ONLY END */
|
|
216
262
|
/** @param uri 任务标识 */
|
|
217
263
|
constructor(uri) {
|
|
218
264
|
exports.tasks.set(uri, this);
|
|
219
265
|
/* NOT FOR BROWSER ONLY */
|
|
220
|
-
Object.
|
|
221
|
-
|
|
222
|
-
|
|
266
|
+
Object.defineProperties(this, {
|
|
267
|
+
data: {
|
|
268
|
+
value: require(path_1.default.join('..', '..', 'data', 'signatures')),
|
|
269
|
+
enumerable: false,
|
|
270
|
+
},
|
|
271
|
+
lilypondData: {
|
|
272
|
+
value: require(path_1.default.join('..', '..', 'data', 'ext', 'score')),
|
|
273
|
+
enumerable: false,
|
|
274
|
+
},
|
|
223
275
|
});
|
|
224
276
|
}
|
|
225
277
|
/** @implements */
|
|
226
278
|
destroy() {
|
|
227
279
|
Object.setPrototypeOf(this, null);
|
|
280
|
+
/* NOT FOR BROWSER ONLY */
|
|
281
|
+
const dir = path_1.default.join(__dirname, 'lilypond');
|
|
282
|
+
if (fs_1.default.existsSync(dir)) {
|
|
283
|
+
for (const file of fs_1.default.readdirSync(dir)) {
|
|
284
|
+
try {
|
|
285
|
+
void fs_1.default.promises.unlink(path_1.default.join(dir, file));
|
|
286
|
+
}
|
|
287
|
+
catch { }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
228
290
|
}
|
|
229
291
|
/** 检查解析设置有无更新 */
|
|
230
292
|
#checkConfig() {
|
|
@@ -409,7 +471,7 @@ class LanguageService {
|
|
|
409
471
|
return getCompletion(allTags, 'Class', mt[1].slice(closing ? 1 : 0), position, closing && !curLine?.slice(character).trim().startsWith('>') ? '>' : '');
|
|
410
472
|
}
|
|
411
473
|
else if (mt?.[4]) { // behavior switch
|
|
412
|
-
return getCompletion(switches, 'Constant', mt[4], position);
|
|
474
|
+
return getCompletion(switches, 'Constant', mt[4], position, '', name => this.data && this.#getBehaviorSwitch(name.slice(2, -2)));
|
|
413
475
|
}
|
|
414
476
|
else if (mt?.[5] !== undefined) { // protocol
|
|
415
477
|
return getCompletion(protocols, 'Reference', mt[5], position);
|
|
@@ -428,7 +490,7 @@ class LanguageService {
|
|
|
428
490
|
? getCompletion(// link
|
|
429
491
|
root.querySelectorAll('link,file,category,redirect-target').filter(token => token !== cur).map(({ name }) => name), 'Folder', str, position)
|
|
430
492
|
: [
|
|
431
|
-
...getCompletion(functions, 'Function', match, position),
|
|
493
|
+
...getCompletion(functions, 'Function', match, position, '', name => this.data && this.#getParserFunction(name.replace(/^#/u, '').toLowerCase())),
|
|
432
494
|
...match.startsWith('#')
|
|
433
495
|
? []
|
|
434
496
|
: getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
|
|
@@ -519,6 +581,27 @@ class LanguageService {
|
|
|
519
581
|
else if (document_1.jsonLSP && type === 'ext-inner' && document_1.jsonTags.includes(cur.name)) {
|
|
520
582
|
const textDoc = new document_1.EmbeddedJSONDocument(root, cur);
|
|
521
583
|
return (await document_1.jsonLSP.doComplete(textDoc, position, textDoc.jsonDoc))?.items;
|
|
584
|
+
}
|
|
585
|
+
else if (type === 'ext-inner' && cur.name === 'score') {
|
|
586
|
+
const lang = parentNode.getAttr('lang');
|
|
587
|
+
if (lang !== undefined && lang !== 'lilypond') {
|
|
588
|
+
return undefined;
|
|
589
|
+
}
|
|
590
|
+
const j = root.indexFromPos(line, character), i = cur.getAbsoluteIndex(), before = this.#text.slice(i, j), comment = before.lastIndexOf('%');
|
|
591
|
+
if (comment !== -1
|
|
592
|
+
&& (before.charAt(comment + 1) === '{' || !before.slice(comment).includes('\n'))) {
|
|
593
|
+
return undefined;
|
|
594
|
+
}
|
|
595
|
+
const word = /\\?\b(?:\w|\b(?:->?|\.)|\bly:)+$/u.exec(curLine.slice(0, character))?.[0];
|
|
596
|
+
if (word) {
|
|
597
|
+
const { lilypondData } = this;
|
|
598
|
+
return word.startsWith('\\')
|
|
599
|
+
? getCompletion(lilypondData.filter(w => w.startsWith('\\')), 'Function', word, position)
|
|
600
|
+
: [
|
|
601
|
+
...getCompletion(lilypondData.filter(w => /^[a-z]/u.test(w)), 'Variable', word, position),
|
|
602
|
+
...getCompletion(lilypondData.filter(w => /^[A-Z]/u.test(w)), 'Class', word, position),
|
|
603
|
+
];
|
|
604
|
+
}
|
|
522
605
|
/* NOT FOR BROWSER ONLY END */
|
|
523
606
|
}
|
|
524
607
|
return undefined;
|
|
@@ -554,13 +637,13 @@ class LanguageService {
|
|
|
554
637
|
],
|
|
555
638
|
})),
|
|
556
639
|
/* eslint-disable @stylistic/operator-linebreak */
|
|
557
|
-
cssDiagnostics = document_1.stylelint ?
|
|
640
|
+
cssDiagnostics = await document_1.stylelint ?
|
|
558
641
|
await (async () => {
|
|
559
642
|
const tokens = this.findStyleTokens();
|
|
560
643
|
if (tokens.length === 0) {
|
|
561
644
|
return [];
|
|
562
645
|
}
|
|
563
|
-
const cssErrors = await (0, stylelint_1.styleLint)(await document_1.stylelint, tokens.map(({ type, tag, lastChild }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n${(0, common_1.sanitizeInlineStyle)(lastChild.toString())}\n}`).join('\n'), cssRules);
|
|
646
|
+
const cssErrors = await (0, stylelint_1.styleLint)((await document_1.stylelint), tokens.map(({ type, tag, lastChild }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n${(0, common_1.sanitizeInlineStyle)(lastChild.toString())}\n}`).join('\n'), cssRules);
|
|
564
647
|
if (cssErrors.length === 0) {
|
|
565
648
|
return [];
|
|
566
649
|
}
|
|
@@ -597,7 +680,58 @@ class LanguageService {
|
|
|
597
680
|
})) :
|
|
598
681
|
[];
|
|
599
682
|
/* eslint-enable @stylistic/operator-linebreak */
|
|
600
|
-
|
|
683
|
+
/* NOT FOR BROWSER ONLY */
|
|
684
|
+
let lilypondDiagnostics = [];
|
|
685
|
+
if (this.lilypond) {
|
|
686
|
+
const tokens = root.querySelectorAll('ext#score').filter(token => {
|
|
687
|
+
const lang = token.getAttr('lang');
|
|
688
|
+
return (lang === undefined || lang === 'lilypond') && token.innerText;
|
|
689
|
+
});
|
|
690
|
+
if (tokens.length > 0) {
|
|
691
|
+
const dir = path_1.default.join(__dirname, 'lilypond');
|
|
692
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
693
|
+
fs_1.default.mkdirSync(dir);
|
|
694
|
+
}
|
|
695
|
+
lilypondDiagnostics = await Promise.all(tokens.map(async (token) => {
|
|
696
|
+
const { innerText } = token, score = `showLastLength = R1${token.getAttr('raw') === undefined ? ` \\score {\n${innerText}\n}` : `\n${innerText}`}`;
|
|
697
|
+
if (scores.has(score)) {
|
|
698
|
+
return getLilyPondDiagnostics(token, scores.get(score));
|
|
699
|
+
}
|
|
700
|
+
const hash = (0, crypto_1.createHash)('sha256');
|
|
701
|
+
hash.update(score);
|
|
702
|
+
const file = path_1.default.join(dir, `${hash.digest('hex')}.ly`);
|
|
703
|
+
fs_1.default.writeFileSync(file, score);
|
|
704
|
+
try {
|
|
705
|
+
await util_1.default.promisify(child_process_1.execFile)(this.lilypond, ['-s', '-o', dir, file]);
|
|
706
|
+
scores.set(score, []);
|
|
707
|
+
}
|
|
708
|
+
catch (e) {
|
|
709
|
+
const { stderr } = e;
|
|
710
|
+
if (stderr) {
|
|
711
|
+
const re = new RegExp(String.raw `^${file}:(\d+):(\d+): error: (.+)$`, 'gmu'), lilypondErrors = [...stderr.matchAll(re)].map(([, line, col, msg]) => {
|
|
712
|
+
const { offsetHeight, offsetWidth } = token.lastChild, pos = adjustPos(offsetHeight, offsetWidth, Number(line) - 1, Number(col) - 1);
|
|
713
|
+
return {
|
|
714
|
+
line: pos[0],
|
|
715
|
+
col: pos[1],
|
|
716
|
+
message: msg,
|
|
717
|
+
};
|
|
718
|
+
});
|
|
719
|
+
scores.set(score, lilypondErrors);
|
|
720
|
+
return getLilyPondDiagnostics(token, lilypondErrors);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return [];
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
/* NOT FOR BROWSER ONLY END */
|
|
728
|
+
return [
|
|
729
|
+
diagnostics,
|
|
730
|
+
cssDiagnostics,
|
|
731
|
+
jsonDiagnostics,
|
|
732
|
+
/* NOT FOR BROWSER ONLY */
|
|
733
|
+
lilypondDiagnostics,
|
|
734
|
+
].flat(2);
|
|
601
735
|
}
|
|
602
736
|
/**
|
|
603
737
|
* Provide folding ranges
|
|
@@ -750,7 +884,7 @@ class LanguageService {
|
|
|
750
884
|
* @param position 位置
|
|
751
885
|
*/
|
|
752
886
|
async provideReferences(text, position) {
|
|
753
|
-
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.type === 'ext-attr-dirty' || element.type === 'html-attr-dirty')
|
|
887
|
+
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.type === 'ext-attr-dirty' || element.type === 'html-attr-dirty')
|
|
754
888
|
? element.parentNode.parentNode
|
|
755
889
|
: element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
756
890
|
if (!refName && !refGroup && !referenceTypes.has(type)) {
|
|
@@ -830,6 +964,13 @@ class LanguageService {
|
|
|
830
964
|
},
|
|
831
965
|
};
|
|
832
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* 检索状态开关
|
|
969
|
+
* @param name 魔术字名
|
|
970
|
+
*/
|
|
971
|
+
#getBehaviorSwitch(name) {
|
|
972
|
+
return this.data.behaviorSwitches.find(({ aliases }) => aliases.includes(name));
|
|
973
|
+
}
|
|
833
974
|
/**
|
|
834
975
|
* 检索解析器函数
|
|
835
976
|
* @param name 函数名
|
|
@@ -850,10 +991,10 @@ class LanguageService {
|
|
|
850
991
|
if (!this.data) {
|
|
851
992
|
return undefined;
|
|
852
993
|
}
|
|
853
|
-
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), token = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, { type, parentNode, length, name } = token;
|
|
994
|
+
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), token = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, { type, parentNode, length, name } = token;
|
|
854
995
|
let info, f, range;
|
|
855
996
|
if (token.is('double-underscore') && offset > 0) {
|
|
856
|
-
info = this
|
|
997
|
+
info = this.#getBehaviorSwitch(token.innerText.toLowerCase());
|
|
857
998
|
}
|
|
858
999
|
else if (type === 'magic-word-name') {
|
|
859
1000
|
info = this.#getParserFunction(parentNode.name);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"/data/",
|
|
21
21
|
"/i18n/",
|
|
22
22
|
"/coverage/badge.svg",
|
|
23
|
-
"/bin
|
|
23
|
+
"/bin/*.js",
|
|
24
24
|
"/dist/",
|
|
25
|
-
"!/dist/
|
|
26
|
-
"!/dist/
|
|
27
|
-
"!/dist/bin/declaration.js"
|
|
25
|
+
"!/dist/script/",
|
|
26
|
+
"!/dist/test/"
|
|
28
27
|
],
|
|
29
28
|
"bin": {
|
|
30
|
-
"wikilint": "bin/cli.js"
|
|
29
|
+
"wikilint": "bin/cli.js",
|
|
30
|
+
"getParserConfig": "bin/config.js"
|
|
31
31
|
},
|
|
32
32
|
"main": "./dist/index.js",
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"url": "git+https://github.com/bhsd-harry/wikiparser-node.git"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
|
-
"declaration": "grep -rl --include='*.d.ts' '@private' dist/ | xargs bash sed.sh -i -E '/^\\s+\\/\\*\\* @private/,+1d'; grep -rl --include='*.d.ts' '/util/' dist/ | xargs bash sed.sh -i -E '/^import .+\\/util\\//d'; bash sed.sh -i -E 's/abstract (lint|print|text)\\b/\\1/' dist/lib/node.d.ts; node dist/
|
|
40
|
+
"declaration": "grep -rl --include='*.d.ts' '@private' dist/ | xargs bash sed.sh -i -E '/^\\s+\\/\\*\\* @private/,+1d'; grep -rl --include='*.d.ts' '/util/' dist/ | xargs bash sed.sh -i -E '/^import .+\\/util\\//d'; bash sed.sh -i -E 's/abstract (lint|print|text)\\b/\\1/' dist/lib/node.d.ts; node dist/script/declaration.js",
|
|
41
41
|
"prepublishOnly": "npm run build:core",
|
|
42
42
|
"build:core": "bash build.sh",
|
|
43
43
|
"build": "npm run build:core",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"lint:json": "v8r -s config/.schema.json config/*.json && v8r -s data/.schema.json data/*.json && node dist/test/json.js",
|
|
48
48
|
"lint": "npm run lint:ts && npm run lint:json",
|
|
49
49
|
"prof": "node dist/test/prof.js",
|
|
50
|
-
"coverage": "nyc --cache-dir=./.cache/nyc npm test && node dist/
|
|
50
|
+
"coverage": "nyc --cache-dir=./.cache/nyc npm test && node dist/script/coverage.js && open coverage/index.html",
|
|
51
51
|
"test:unit": "mocha dist/test/test.js",
|
|
52
52
|
"test:parser": "mocha dist/test/parserTests.js",
|
|
53
53
|
"test": "npm run test:unit && npm run test:parser",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@bhsd/common": "^0.
|
|
68
|
+
"@bhsd/common": "^0.8.0",
|
|
69
69
|
"vscode-languageserver-types": "^3.17.5"
|
|
70
70
|
},
|
|
71
71
|
"optionalDependencies": {
|
|
@@ -74,8 +74,7 @@
|
|
|
74
74
|
"minimatch": "^10.0.1",
|
|
75
75
|
"stylelint": "^16.14.1",
|
|
76
76
|
"vscode-css-languageservice": "^6.3.2",
|
|
77
|
-
"vscode-json-languageservice": "^5.4.3"
|
|
78
|
-
"vscode-languageserver-textdocument": "^1.0.12"
|
|
77
|
+
"vscode-json-languageservice": "^5.4.3"
|
|
79
78
|
},
|
|
80
79
|
"devDependencies": {
|
|
81
80
|
"@stylistic/eslint-plugin": "^3.1.0",
|
|
@@ -102,7 +101,8 @@
|
|
|
102
101
|
"nyc": "^17.1.0",
|
|
103
102
|
"stylelint-config-recommended": "^15.0.0",
|
|
104
103
|
"typescript": "^5.7.3",
|
|
105
|
-
"v8r": "^4.2.1"
|
|
104
|
+
"v8r": "^4.2.1",
|
|
105
|
+
"vscode-languageserver-textdocument": "^1.0.12"
|
|
106
106
|
},
|
|
107
107
|
"engines": {
|
|
108
108
|
"node": ">=18.17.0"
|
package/dist/util/sharable.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const commonHtmlAttrs: Set<string>, htmlAttrs: Record<string, Set<string>>, extAttrs: Record<string, Set<string>>, obsoleteAttrs: Record<string, Set<string>>;
|