wikilint 2.18.0 → 2.18.2

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.mts CHANGED
@@ -5,6 +5,7 @@ export interface Config {
5
5
  readonly namespaces: Record<string, string>;
6
6
  readonly nsid: Record<string, number>;
7
7
  readonly variable: string[];
8
+ readonly functionHook: string[];
8
9
  readonly parserFunction: [Record<string, string>, Record<string, string> | string[], string[], string[]];
9
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>?, Record<string, string>?];
10
11
  readonly protocol: string;
@@ -239,6 +240,13 @@ export interface LanguageService {
239
240
  * @param text source Wikitext / 源代码
240
241
  */
241
242
  provideDocumentSymbols(text: string): Promise<DocumentSymbol[]>;
243
+ /**
244
+ * Set the target Wikipedia
245
+ *
246
+ * 设置目标维基百科
247
+ * @param wiki Wikipedia URL / 维基百科网址
248
+ */
249
+ setTargetWikipedia(wiki: string): Promise<void>;
242
250
  }
243
251
  export interface Parser {
244
252
  config: Config | string;
@@ -247,8 +255,9 @@ export interface Parser {
247
255
  * Get the current parser configuration
248
256
  *
249
257
  * 获取当前的解析设置
258
+ * @param config unprocessed parser configuration / 未处理的解析设置
250
259
  */
251
- getConfig(): Config;
260
+ getConfig(config?: Config): Config;
252
261
  /**
253
262
  * Parse wikitext
254
263
  *
package/dist/base.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface Config {
5
5
  readonly namespaces: Record<string, string>;
6
6
  readonly nsid: Record<string, number>;
7
7
  readonly variable: string[];
8
+ readonly functionHook: string[];
8
9
  readonly parserFunction: [Record<string, string>, Record<string, string> | string[], string[], string[]];
9
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>?, Record<string, string>?];
10
11
  readonly protocol: string;
@@ -239,6 +240,13 @@ export interface LanguageService {
239
240
  * @param text source Wikitext / 源代码
240
241
  */
241
242
  provideDocumentSymbols(text: string): Promise<DocumentSymbol[]>;
243
+ /**
244
+ * Set the target Wikipedia
245
+ *
246
+ * 设置目标维基百科
247
+ * @param wiki Wikipedia URL / 维基百科网址
248
+ */
249
+ setTargetWikipedia(wiki: string): Promise<void>;
242
250
  }
243
251
  export interface Parser {
244
252
  config: Config | string;
@@ -247,8 +255,9 @@ export interface Parser {
247
255
  * Get the current parser configuration
248
256
  *
249
257
  * 获取当前的解析设置
258
+ * @param config unprocessed parser configuration / 未处理的解析设置
250
259
  */
251
- getConfig(): Config;
260
+ getConfig(config?: Config): Config;
252
261
  /**
253
262
  * Parse wikitext
254
263
  *
@@ -8,34 +8,6 @@ const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const assert_1 = __importDefault(require("assert"));
10
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
11
  /**
40
12
  * Converts an array to an object.
41
13
  * @param config parser configuration
@@ -65,14 +37,66 @@ const filterGadget = (id) => {
65
37
  const n = Number(id);
66
38
  return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
67
39
  };
68
- (async () => {
69
- const m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror${old ? '.data' : ''}`)).text(), params = {
40
+ /**
41
+ * Execute the data script.
42
+ * @param obj MediaWiki module implementation
43
+ */
44
+ const execute = (obj) => {
45
+ Object.entries(obj.files).find(([k]) => k.endsWith('.data.js'))[1]();
46
+ };
47
+ const mw = {
48
+ loader: {
49
+ done: false,
50
+ /** @ignore */
51
+ impl(callback) {
52
+ execute(callback()[1]);
53
+ },
54
+ /** @ignore */
55
+ implement(name, callback) {
56
+ if (typeof callback === 'object') {
57
+ execute(callback);
58
+ }
59
+ else if (!this.done) {
60
+ callback();
61
+ }
62
+ if (name.startsWith('ext.CodeMirror.data')) {
63
+ this.done = true;
64
+ }
65
+ },
66
+ /** @ignore */
67
+ state() {
68
+ //
69
+ },
70
+ },
71
+ config: {
72
+ /** @ignore */
73
+ set({ extCodeMirrorConfig }) {
74
+ mwConfig = extCodeMirrorConfig;
75
+ },
76
+ },
77
+ };
78
+ let mwConfig;
79
+ /**
80
+ * Get the parser configuration for a Wikimedia Foundation project.
81
+ * @param site site nickname
82
+ * @param url script path
83
+ * @param force whether to overwrite the existing configuration
84
+ */
85
+ exports.default = async (site, url, force) => {
86
+ if (!site || !url) {
87
+ console.error('Usage: npx getParserConfig <site> <script path> [force]');
88
+ process.exit(1);
89
+ }
90
+ else if (/(?:\.php|\/)$/u.test(url)) {
91
+ url = url.slice(0, url.lastIndexOf('/'));
92
+ }
93
+ const m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror.data|ext.CodeMirror`)).text(), params = {
70
94
  action: 'query',
71
95
  meta: 'siteinfo',
72
- siprop: `general|magicwords|namespaces|namespacealiases${old ? '|variables' : ''}`,
96
+ siprop: 'general|magicwords|functionhooks|namespaces|namespacealiases',
73
97
  format: 'json',
74
98
  formatversion: '2',
75
- }, { query: { general: { variants }, magicwords, namespaces, namespacealiases, variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`)).json();
99
+ }, { query: { general: { articlepath, variants }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`)).json(), { query: { variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`)).json();
76
100
  eval(m); // eslint-disable-line no-eval
77
101
  const dir = path_1.default.join('..', '..', 'config'), ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
78
102
  .flatMap(([id, { name, canonical = '' }]) => [
@@ -87,8 +111,8 @@ const filterGadget = (id) => {
87
111
  ...ns.map(([id, canonical]) => [canonical.toLowerCase(), Number(id)]),
88
112
  ...namespacealiases.filter(({ id }) => filterGadget(id)).map(({ id, alias }) => [alias.toLowerCase(), id]),
89
113
  ]),
90
- ...old && { variable: [...variables, '='] },
91
- articlePath: '/wiki/$1',
114
+ functionHook: [...functionhooks.map(s => s.toLowerCase()), 'msgnw'],
115
+ articlePath: articlepath,
92
116
  };
93
117
  config.doubleUnderscore[0] = [];
94
118
  config.doubleUnderscore[1] = [];
@@ -102,11 +126,15 @@ const filterGadget = (id) => {
102
126
  }
103
127
  config.parserFunction[2] = getAliases(magicwords, new Set(['msg', 'raw']));
104
128
  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));
129
+ if (!config.variable) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
130
+ Object.assign(config, { variable: [...new Set([...variables, '='])] });
108
131
  }
109
- if (force || !exists) {
132
+ const file = path_1.default.join(__dirname, dir, `${site}.json`);
133
+ if (force || !fs_1.default.existsSync(file)) {
110
134
  fs_1.default.writeFileSync(file, `${JSON.stringify(config, null, '\t')}\n`);
111
135
  }
112
- })();
136
+ else {
137
+ assert_1.default.deepStrictEqual(arrToObj(require(file)), arrToObj(config));
138
+ }
139
+ return config;
140
+ };
package/dist/index.js CHANGED
@@ -26,25 +26,27 @@ const Parser = {
26
26
  i18n: undefined,
27
27
  rules: base_1.rules,
28
28
  /** @implements */
29
- getConfig() {
29
+ getConfig(config) {
30
30
  /* NOT FOR BROWSER ONLY */
31
- if (typeof this.config === 'string') {
31
+ if (!config && typeof this.config === 'string') {
32
32
  this.config = rootRequire(this.config, 'config');
33
33
  /* istanbul ignore if */
34
- if (this.config.doubleUnderscore.length < 3 || Array.isArray(this.config.parserFunction[1])) {
34
+ if (this.config.doubleUnderscore.length < 3
35
+ || Array.isArray(this.config.parserFunction[1])
36
+ || !('functionHook' in this.config)) {
35
37
  (0, diff_1.error)(`The schema (${path_1.default.resolve(__dirname, '..', 'config', '.schema.json')}) of parser configuration is updated.`);
36
38
  }
37
39
  return this.getConfig();
38
40
  }
39
41
  /* NOT FOR BROWSER ONLY END */
40
- const { doubleUnderscore } = this.config;
42
+ const parserConfig = config ?? this.config, { doubleUnderscore } = parserConfig;
41
43
  for (let i = 0; i < 2; i++) {
42
44
  if (doubleUnderscore.length > i + 2 && doubleUnderscore[i].length === 0) {
43
45
  doubleUnderscore[i] = Object.keys(doubleUnderscore[i + 2]);
44
46
  }
45
47
  }
46
48
  return {
47
- ...this.config,
49
+ ...parserConfig,
48
50
  excludes: [],
49
51
  };
50
52
  },
@@ -1,13 +1,12 @@
1
1
  import type { Position } from 'vscode-languageserver-types';
2
2
  import type { TextDocument } from 'vscode-languageserver-textdocument';
3
- import type { LanguageService as JSONLanguageService, JSONDocument } from 'vscode-json-languageservice';
4
- import type { LanguageService as CSSLanguageService, Stylesheet } from 'vscode-css-languageservice';
5
- import type { PublicApi } from 'stylelint';
3
+ import type { JSONDocument } from 'vscode-json-languageservice';
4
+ import type { Stylesheet } from 'vscode-css-languageservice';
6
5
  import type { Token } from '../internal';
7
6
  export declare const jsonTags: string[];
8
- declare let jsonLSP: JSONLanguageService | undefined, cssLSP: CSSLanguageService | undefined;
9
- declare const stylelint: Promise<PublicApi | undefined>;
10
- export { jsonLSP, cssLSP, stylelint };
7
+ export declare const jsonLSP: import("vscode-json-languageservice").LanguageService | undefined;
8
+ export declare const cssLSP: import("vscode-css-languageservice").LanguageService | undefined;
9
+ export declare const stylelint: Promise<import("stylelint").PublicApi | undefined>;
11
10
  /** embedded document */
12
11
  declare class EmbeddedDocument implements TextDocument {
13
12
  #private;
@@ -52,3 +51,4 @@ export declare class EmbeddedCSSDocument extends EmbeddedDocument {
52
51
  constructor(root: Token, token: Token);
53
52
  getContent(): string;
54
53
  }
54
+ export {};
@@ -7,39 +7,47 @@ 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;
11
- try {
12
- exports.jsonLSP = jsonLSP = require('vscode-json-languageservice')
13
- .getLanguageService({
14
- /** @implements */
15
- async schemaRequestService(uri) {
16
- return (await fetch(uri)).text();
17
- },
18
- });
19
- jsonLSP.configure({
20
- schemas: exports.jsonTags.map((tag) => {
21
- const uri = path_1.default.join('..', '..', 'data', 'ext', tag);
22
- try {
23
- const schema = require(uri);
24
- return {
25
- uri,
26
- fileMatch: [tag],
27
- schema,
28
- };
29
- }
30
- catch {
31
- return false;
32
- }
33
- }).filter(Boolean),
34
- });
35
- }
36
- catch { }
37
- try {
38
- exports.cssLSP = cssLSP = require('vscode-css-languageservice')
39
- .getCSSLanguageService();
40
- }
41
- catch { }
42
- const stylelint = (async () => {
10
+ exports.jsonLSP = (() => {
11
+ try {
12
+ const lsp = require('vscode-json-languageservice')
13
+ .getLanguageService({
14
+ /** @implements */
15
+ async schemaRequestService(uri) {
16
+ return (await fetch(uri)).text();
17
+ },
18
+ });
19
+ lsp.configure({
20
+ schemas: exports.jsonTags.map((tag) => {
21
+ const uri = path_1.default.join('..', '..', 'data', 'ext', tag);
22
+ try {
23
+ const schema = require(uri);
24
+ return {
25
+ uri,
26
+ fileMatch: [tag],
27
+ schema,
28
+ };
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }).filter(Boolean),
34
+ });
35
+ return lsp;
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ })();
41
+ exports.cssLSP = (() => {
42
+ try {
43
+ return require('vscode-css-languageservice')
44
+ .getCSSLanguageService();
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ })();
50
+ exports.stylelint = (async () => {
43
51
  try {
44
52
  return (await import('stylelint')).default;
45
53
  }
@@ -47,7 +55,6 @@ const stylelint = (async () => {
47
55
  return undefined;
48
56
  }
49
57
  })();
50
- exports.stylelint = stylelint;
51
58
  /** embedded document */
52
59
  class EmbeddedDocument {
53
60
  uri = '';
@@ -100,7 +107,7 @@ class EmbeddedJSONDocument extends EmbeddedDocument {
100
107
  constructor(root, token) {
101
108
  super('json', root, token);
102
109
  this.uri = token.name;
103
- this.jsonDoc = jsonLSP.parseJSONDocument(this);
110
+ this.jsonDoc = exports.jsonLSP.parseJSONDocument(this);
104
111
  }
105
112
  }
106
113
  exports.EmbeddedJSONDocument = EmbeddedJSONDocument;
@@ -113,7 +120,7 @@ class EmbeddedCSSDocument extends EmbeddedDocument {
113
120
  constructor(root, token) {
114
121
  const { type, tag } = token.parentNode;
115
122
  super('css', root, token, `${type === 'ext-attr' ? 'div' : tag}{`, '}');
116
- this.styleSheet = cssLSP.parseStylesheet(this);
123
+ this.styleSheet = exports.cssLSP.parseStylesheet(this);
117
124
  }
118
125
  getContent() {
119
126
  return (0, common_1.sanitizeInlineStyle)(super.getContent());
package/dist/lib/lsp.d.ts CHANGED
@@ -1,18 +1,27 @@
1
1
  import Parser from '../index';
2
2
  import type { Range, Position, ColorInformation, ColorPresentation, FoldingRange, DocumentLink, Location, WorkspaceEdit, Diagnostic as DiagnosticBase, TextEdit, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
3
- import type { LanguageService as LanguageServiceBase, CompletionItem, SignatureData } from '../base';
4
- import type { AttributeToken } from '../internal';
3
+ import type { Config, LanguageService as LanguageServiceBase, CompletionItem, SignatureData } from '../base';
4
+ import type { Token, AttributeToken } from '../internal';
5
5
  export interface QuickFixData extends TextEdit {
6
6
  title: string;
7
7
  fix: boolean;
8
8
  }
9
9
  export declare const tasks: WeakMap<object, Parser.LanguageService>;
10
+ /**
11
+ * Check if a token is a plain attribute.
12
+ * @param token
13
+ * @param token.type
14
+ * @param token.parentNode
15
+ * @param token.length
16
+ * @param token.firstChild
17
+ * @param style whether it is a style attribute
18
+ */
19
+ export declare const isAttr: ({ type, parentNode, length, firstChild }: Token, style?: boolean) => boolean | undefined;
10
20
  /** VSCode-style language service */
11
21
  export declare class LanguageService implements LanguageServiceBase {
12
22
  #private;
13
23
  include: boolean;
14
24
  lilypond: string;
15
- lilypondData: string[];
16
25
  /** @param uri 任务标识 */
17
26
  constructor(uri: object);
18
27
  /** @implements */
@@ -133,4 +142,12 @@ export declare class LanguageService implements LanguageServiceBase {
133
142
  * @param text source Wikitext / 源代码
134
143
  */
135
144
  provideDocumentSymbols(text: string): Promise<DocumentSymbol[]>;
145
+ /**
146
+ * Set the target Wikipedia
147
+ *
148
+ * 设置目标维基百科
149
+ * @param wiki Wikipedia URL / 维基百科网址
150
+ * @throws `RangeError` 不是有效的维基百科网址
151
+ */
152
+ setTargetWikipedia(wiki: string): Promise<void>;
136
153
  }