@bhsd/codemirror-mediawiki 2.20.2 → 2.21.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 +13 -0
- package/dist/escape.d.ts +2 -1
- package/dist/hover.d.ts +19 -0
- package/dist/main.min.js +17 -17
- package/dist/matchTag.d.ts +2 -2
- package/dist/mw.min.js +20 -20
- package/dist/mwConfig.mjs +0 -4
- package/dist/openLinks.d.ts +2 -1
- package/dist/ref.d.ts +4 -6
- package/dist/signature.d.ts +3 -0
- package/dist/tree.d.ts +16 -0
- package/dist/wiki.min.js +20 -20
- package/i18n/en.json +4 -2
- package/i18n/zh-hans.json +4 -2
- package/i18n/zh-hant.json +4 -2
- package/mediawiki.css +18 -3
- package/package.json +29 -34
- package/mw/config.ts +0 -185
- package/src/linter.ts +0 -149
- package/src/static.ts +0 -62
package/i18n/en.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.21.0",
|
|
3
3
|
"lang": "en",
|
|
4
4
|
"i18n-failed": "Failed to fetch the translation file in $1.",
|
|
5
5
|
"title": "CodeMirror Addons",
|
|
@@ -20,14 +20,16 @@
|
|
|
20
20
|
"addon-highlightSpecialChars": "Show special characters",
|
|
21
21
|
"addon-highlightTrailingWhitespace": "Show trailing spaces",
|
|
22
22
|
"addon-highlightWhitespace": "Show whitespace characters",
|
|
23
|
+
"addon-hover": "Hover over a magic word to see the help information",
|
|
23
24
|
"addon-indent": "Indent",
|
|
24
25
|
"addon-lint": "Linter",
|
|
25
26
|
"addon-openLinks": "Open the link or transcluded page with CTRL-click",
|
|
26
27
|
"addon-openLinks-mac": "Open the link or transcluded page with CMD-click",
|
|
28
|
+
"addon-refHover": "Hover over a predefined reference to see its content (CodeMirror)",
|
|
27
29
|
"addon-save": "Save your preferences on a [[special:mypage/codemirror-mediawiki.json|user subpage]]",
|
|
28
30
|
"addon-scrollPastEnd": "Scroll down past the end of the document",
|
|
31
|
+
"addon-signatureHelp": "Show parser function signatures",
|
|
29
32
|
"addon-tagMatching": "Highlight matching/non-matching tags",
|
|
30
|
-
"addon-refHover": "Hover over a predefined reference to see its content (CodeMirror) or go to its difinition (Monaco)",
|
|
31
33
|
"addon-useMonaco": "Use Monaco Editor for new editors",
|
|
32
34
|
"addon-wikiEditor": "Load WikiEditor toolbar",
|
|
33
35
|
"no-wikiEditor": "WikiEditor is not available.",
|
package/i18n/zh-hans.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.21.0",
|
|
3
3
|
"lang": "zh-hans",
|
|
4
4
|
"i18n-failed": "获取 $1 的语言文件失败。",
|
|
5
5
|
"title": "CodeMirror插件",
|
|
@@ -20,14 +20,16 @@
|
|
|
20
20
|
"addon-highlightSpecialChars": "显示特殊字符",
|
|
21
21
|
"addon-highlightTrailingWhitespace": "显示尾随空格",
|
|
22
22
|
"addon-highlightWhitespace": "显示空白字符",
|
|
23
|
+
"addon-hover": "悬停在魔术字上可查看帮助",
|
|
23
24
|
"addon-indent": "缩进",
|
|
24
25
|
"addon-lint": "语法检查",
|
|
25
26
|
"addon-openLinks": "CTRL+点击可打开链接或嵌入的页面",
|
|
26
27
|
"addon-openLinks-mac": "CMD+点击可打开链接或嵌入的页面",
|
|
28
|
+
"addon-refHover": "悬停在预定义的引用上可查看其内容(CodeMirror)",
|
|
27
29
|
"addon-save": "将设置保存至[[special:mypage/codemirror-mediawiki.json|用户子页面]]",
|
|
28
30
|
"addon-scrollPastEnd": "允许向下滚动超过文档末尾",
|
|
31
|
+
"addon-signatureHelp": "显示解析器函数的签名",
|
|
29
32
|
"addon-tagMatching": "高亮显示匹配和未匹配的标签",
|
|
30
|
-
"addon-refHover": "悬停在预定义的引用上可查看其内容(CodeMirror)或转到其定义(Monaco)",
|
|
31
33
|
"addon-useMonaco": "新增的编辑区使用Monaco编辑器",
|
|
32
34
|
"addon-wikiEditor": "加载WikiEditor工具栏",
|
|
33
35
|
"no-wikiEditor": "未找到WikiEditor扩展。",
|
package/i18n/zh-hant.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.21.0",
|
|
3
3
|
"lang": "zh-hant",
|
|
4
4
|
"i18n-failed": "取得 $1 的語言檔案失敗。",
|
|
5
5
|
"title": "CodeMirror外掛程式",
|
|
@@ -20,14 +20,16 @@
|
|
|
20
20
|
"addon-highlightSpecialChars": "顯示特殊字符",
|
|
21
21
|
"addon-highlightTrailingWhitespace": "顯示尾隨空格",
|
|
22
22
|
"addon-highlightWhitespace": "顯示空白字符",
|
|
23
|
+
"addon-hover": "懸停在魔術字上可查看使用說明",
|
|
23
24
|
"addon-indent": "縮排",
|
|
24
25
|
"addon-lint": "語法檢查",
|
|
25
26
|
"addon-openLinks": "CTRL+點擊可打開連結或嵌入包含的頁面",
|
|
26
27
|
"addon-openLinks-mac": "CMD+點擊可打開連結或嵌入包含的頁面",
|
|
28
|
+
"addon-refHover": "懸停在預定義的參考上可查看其內容(CodeMirror)",
|
|
27
29
|
"addon-save": "將設定儲存至[[special:mypage/codemirror-mediawiki.json|使用者子頁面]]",
|
|
28
30
|
"addon-scrollPastEnd": "允許向下滾動超過文件末尾",
|
|
31
|
+
"addon-signatureHelp": "顯示解析器函數的簽名",
|
|
29
32
|
"addon-tagMatching": "突出顯示匹配和未匹配的標籤",
|
|
30
|
-
"addon-refHover": "懸停在預定義的參考上可查看其內容(CodeMirror)或轉到其定義(Monaco)",
|
|
31
33
|
"addon-useMonaco": "新增的編輯區使用Monaco編輯器",
|
|
32
34
|
"addon-wikiEditor": "載入WikiEditor工具列",
|
|
33
35
|
"no-wikiEditor": "未找到WikiEditor擴展。",
|
package/mediawiki.css
CHANGED
|
@@ -19,13 +19,28 @@
|
|
|
19
19
|
.cm-tooltip-fold:hover {
|
|
20
20
|
opacity: 1;
|
|
21
21
|
}
|
|
22
|
-
.cm-tooltip-ref {
|
|
23
|
-
cursor: pointer;
|
|
22
|
+
.cm-tooltip-ref, .cm-tooltip-hover {
|
|
24
23
|
padding: 2px 5px;
|
|
25
|
-
white-space: pre-wrap;
|
|
26
24
|
width: max-content;
|
|
27
25
|
max-width: 60vw;
|
|
28
26
|
}
|
|
27
|
+
.cm-tooltip-ref {
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
white-space: pre-wrap;
|
|
30
|
+
}
|
|
31
|
+
.cm-tooltip-hover * {
|
|
32
|
+
margin-top: 0 !important;
|
|
33
|
+
margin-bottom: 0 !important;
|
|
34
|
+
}
|
|
35
|
+
.cm-tooltip-hover > div {
|
|
36
|
+
font-size: 90%;
|
|
37
|
+
line-height: 1.4;
|
|
38
|
+
}
|
|
39
|
+
.cm-tooltip-hover code {
|
|
40
|
+
background-color: #e0e6eb;
|
|
41
|
+
padding: .1em .4em;
|
|
42
|
+
border-radius: .4em;
|
|
43
|
+
}
|
|
29
44
|
.cm-focused .cm-matchingTag {
|
|
30
45
|
background-color: rgba(50, 140, 130, .32);
|
|
31
46
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bhsd/codemirror-mediawiki",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.0",
|
|
4
4
|
"description": "Modified CodeMirror mode based on wikimedia/mediawiki-extensions-CodeMirror",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -19,14 +19,12 @@
|
|
|
19
19
|
"/dist/*.mjs",
|
|
20
20
|
"!/dist/*-page.d.ts",
|
|
21
21
|
"!/dist/parser.*",
|
|
22
|
-
"/src/linter.ts",
|
|
23
|
-
"/src/static.ts",
|
|
24
|
-
"/mw/config.ts",
|
|
25
22
|
"/mediawiki.css"
|
|
26
23
|
],
|
|
27
24
|
"browser": "dist/main.min.js",
|
|
28
25
|
"main": "./dist/main.min.js",
|
|
29
26
|
"types": "./dist/codemirror.d.ts",
|
|
27
|
+
"sideEffects": false,
|
|
30
28
|
"repository": {
|
|
31
29
|
"type": "git",
|
|
32
30
|
"url": "git+https://github.com/bhsd-harry/codemirror-mediawiki.git"
|
|
@@ -44,58 +42,55 @@
|
|
|
44
42
|
"lint": "npm run lint:ts && npm run lint:css",
|
|
45
43
|
"prof": "node --prof test/dist/test/prof.js && node --prof-process isolate-0x*-v8.log > test/prof.txt && gsed -i '0,/Bottom up/d' test/prof.txt && rm isolate-0x*-v8.log",
|
|
46
44
|
"server": "npm run test:end; http-server .. -c-1 --cors -s &",
|
|
47
|
-
"test": "npm run build:core && npm run build:wiki && npm run build:gh-page && npm run server",
|
|
48
45
|
"test:end": "pkill -x http-server",
|
|
49
46
|
"test:real": "node test/dist/test/real.js"
|
|
50
47
|
},
|
|
51
48
|
"dependencies": {
|
|
52
|
-
"@bhsd/common": "^0.6.
|
|
53
|
-
"@codemirror/language": "^6.10.
|
|
49
|
+
"@bhsd/common": "^0.6.4",
|
|
50
|
+
"@codemirror/language": "^6.10.8",
|
|
54
51
|
"@codemirror/lint": "^6.8.4",
|
|
55
|
-
"@codemirror/state": "^6.
|
|
56
|
-
"@codemirror/view": "^6.
|
|
57
|
-
"@lezer/
|
|
58
|
-
"
|
|
59
|
-
"wikiparser-node": "^1.15.1"
|
|
52
|
+
"@codemirror/state": "^6.5.1",
|
|
53
|
+
"@codemirror/view": "^6.36.2",
|
|
54
|
+
"@lezer/highlight": "^1.2.1",
|
|
55
|
+
"wikiparser-node": "^1.16.2"
|
|
60
56
|
},
|
|
61
57
|
"devDependencies": {
|
|
62
|
-
"@codemirror
|
|
63
|
-
"@codemirror/
|
|
58
|
+
"@bhsd/codemirror-css-color-picker": "^6.3.0",
|
|
59
|
+
"@codemirror/autocomplete": "^6.18.4",
|
|
60
|
+
"@codemirror/commands": "^6.8.0",
|
|
64
61
|
"@codemirror/lang-css": "^6.3.1",
|
|
65
62
|
"@codemirror/lang-javascript": "^6.2.2",
|
|
66
63
|
"@codemirror/lang-json": "^6.0.1",
|
|
67
64
|
"@codemirror/legacy-modes": "^6.4.2",
|
|
68
65
|
"@codemirror/search": "^6.5.8",
|
|
69
|
-
"@
|
|
70
|
-
"@
|
|
71
|
-
"@stylistic/eslint-plugin": "^2.11.0",
|
|
72
|
-
"@stylistic/stylelint-plugin": "^3.1.1",
|
|
66
|
+
"@stylistic/eslint-plugin": "^3.1.0",
|
|
67
|
+
"@stylistic/stylelint-plugin": "^3.1.2",
|
|
73
68
|
"@types/eslint": "^8.56.10",
|
|
74
69
|
"@types/jquery": "^3.5.32",
|
|
70
|
+
"@types/markdown-it": "^14.1.2",
|
|
75
71
|
"@types/mocha": "^10.0.10",
|
|
76
|
-
"@types/node": "^22.
|
|
77
|
-
"@types/oojs-ui": "^0.49.
|
|
78
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
79
|
-
"@typescript-eslint/parser": "^8.
|
|
80
|
-
"esbuild": "^0.
|
|
72
|
+
"@types/node": "^22.13.1",
|
|
73
|
+
"@types/oojs-ui": "^0.49.4",
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
|
75
|
+
"@typescript-eslint/parser": "^8.23.0",
|
|
76
|
+
"esbuild": "^0.25.0",
|
|
81
77
|
"eslint": "^8.57.1",
|
|
82
78
|
"eslint-plugin-es-x": "^8.4.1",
|
|
83
79
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
84
|
-
"eslint-plugin-jsdoc": "^50.6.
|
|
80
|
+
"eslint-plugin-jsdoc": "^50.6.3",
|
|
85
81
|
"eslint-plugin-json-es": "^1.6.0",
|
|
86
82
|
"eslint-plugin-markdown": "4.0.1",
|
|
87
|
-
"eslint-plugin-n": "^17.
|
|
83
|
+
"eslint-plugin-n": "^17.15.1",
|
|
88
84
|
"eslint-plugin-promise": "^7.2.1",
|
|
89
|
-
"eslint-plugin-regexp": "^2.
|
|
85
|
+
"eslint-plugin-regexp": "^2.7.0",
|
|
90
86
|
"eslint-plugin-unicorn": "^56.0.1",
|
|
91
|
-
"http-server": "^14.1.
|
|
87
|
+
"http-server": "^14.1.1",
|
|
92
88
|
"luacheck-browserify": "^0.2.2",
|
|
93
|
-
"mocha": "^
|
|
94
|
-
"monaco-editor": "^0.52.
|
|
95
|
-
"
|
|
96
|
-
"stylelint": "^
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"typescript": "^5.7.2"
|
|
89
|
+
"mocha": "^11.1.0",
|
|
90
|
+
"monaco-editor": "^0.52.2",
|
|
91
|
+
"stylelint": "^16.14.1",
|
|
92
|
+
"stylelint-config-recommended": "^15.0.0",
|
|
93
|
+
"types-mediawiki": "^1.9.1",
|
|
94
|
+
"typescript": "^5.7.3"
|
|
100
95
|
}
|
|
101
96
|
}
|
package/mw/config.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import {CDN, setObject, getObject, compareVersion} from '@bhsd/common';
|
|
2
|
-
import {getStaticMwConfig} from '../src/static';
|
|
3
|
-
import type {Config} from 'wikiparser-node';
|
|
4
|
-
import type {MwConfig} from '../src/token';
|
|
5
|
-
|
|
6
|
-
declare interface MagicWord {
|
|
7
|
-
name: string;
|
|
8
|
-
aliases: string[];
|
|
9
|
-
'case-sensitive': boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
declare type MagicRule = (word: MagicWord) => boolean;
|
|
13
|
-
|
|
14
|
-
// 和本地缓存有关的常数
|
|
15
|
-
const ALL_SETTINGS_CACHE: Record<string, {time: number, config: MwConfig}> =
|
|
16
|
-
getObject('InPageEditMwConfig') ?? {},
|
|
17
|
-
SITE_ID = typeof mw === 'object' ? mw.config.get('wgServerName') + mw.config.get('wgScriptPath') : location.origin,
|
|
18
|
-
SITE_SETTINGS = ALL_SETTINGS_CACHE[SITE_ID],
|
|
19
|
-
VALID = Number(SITE_SETTINGS?.time) > Date.now() - 86_400 * 1000 * 30;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 将魔术字信息转换为CodeMirror接受的设置
|
|
23
|
-
* @param magicWords 完整魔术字列表
|
|
24
|
-
* @param rule 过滤函数
|
|
25
|
-
* @param flip 是否反向筛选对大小写敏感的魔术字
|
|
26
|
-
*/
|
|
27
|
-
const getConfig = (magicWords: MagicWord[], rule: MagicRule, flip?: boolean): Record<string, string> =>
|
|
28
|
-
Object.fromEntries(
|
|
29
|
-
magicWords.filter(rule).filter(({'case-sensitive': i}) => i !== flip)
|
|
30
|
-
.flatMap(({aliases, name, 'case-sensitive': i}) => aliases.map(alias => ({
|
|
31
|
-
alias: (i ? alias : alias.toLowerCase()).replace(/:$/u, ''),
|
|
32
|
-
name,
|
|
33
|
-
})))
|
|
34
|
-
.map(({alias, name}) => [alias, name]),
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 将魔术字信息转换为CodeMirror接受的设置
|
|
39
|
-
* @param magicWords 完整魔术字列表
|
|
40
|
-
* @param rule 过滤函数
|
|
41
|
-
*/
|
|
42
|
-
const getConfigPair = (magicWords: MagicWord[], rule: MagicRule): [Record<string, string>, Record<string, string>] =>
|
|
43
|
-
[true, false].map(bool => getConfig(magicWords, rule, bool)) as [Record<string, string>, Record<string, string>];
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* 将设置保存到mw.config
|
|
47
|
-
* @param config 设置
|
|
48
|
-
*/
|
|
49
|
-
const setConfig = (config: MwConfig): void => {
|
|
50
|
-
mw.config.set('extCodeMirrorConfig', config);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 加载CodeMirror的mediawiki模块需要的设置
|
|
55
|
-
* @param modes tagModes
|
|
56
|
-
*/
|
|
57
|
-
export const getMwConfig = async (modes: Record<string, string>): Promise<MwConfig> => {
|
|
58
|
-
if (mw.loader.getState('ext.CodeMirror') !== null && !VALID) { // 只在localStorage过期时才会重新加载ext.CodeMirror.data
|
|
59
|
-
await mw.loader.using(mw.loader.getState('ext.CodeMirror.data') ? 'ext.CodeMirror.data' : 'ext.CodeMirror');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let config = mw.config.get('extCodeMirrorConfig') as MwConfig | null;
|
|
63
|
-
if (!config && VALID) {
|
|
64
|
-
({config} = SITE_SETTINGS!);
|
|
65
|
-
setConfig(config);
|
|
66
|
-
}
|
|
67
|
-
const isIPE = config && Object.values(config.functionSynonyms[0]).includes(true as unknown as string),
|
|
68
|
-
nsid = mw.config.get('wgNamespaceIds');
|
|
69
|
-
// 情形1:config已更新,可能来自localStorage
|
|
70
|
-
if (config?.img && config.redirection && config.variants && config.variableIDs && !isIPE) {
|
|
71
|
-
config.urlProtocols = config.urlProtocols.replace(/\\:/gu, ':');
|
|
72
|
-
config.tagModes = modes;
|
|
73
|
-
return {...config, nsid};
|
|
74
|
-
} else if (location.hostname.endsWith('.moegirl.org.cn')) {
|
|
75
|
-
const parserConfig: Config = await (await fetch(
|
|
76
|
-
`${CDN}/npm/wikiparser-node/config/moegirl.json`,
|
|
77
|
-
)).json();
|
|
78
|
-
setObject('wikilintConfig', parserConfig);
|
|
79
|
-
config = getStaticMwConfig(parserConfig, modes);
|
|
80
|
-
} else {
|
|
81
|
-
// 以下情形均需要发送API请求
|
|
82
|
-
// 情形2:localStorage未过期但不包含新设置
|
|
83
|
-
// 情形3:新加载的 ext.CodeMirror.data
|
|
84
|
-
// 情形4:`config === null`
|
|
85
|
-
await mw.loader.using('mediawiki.api');
|
|
86
|
-
const {query: {general: {variants}, magicwords, extensiontags, functionhooks, variables}}: {
|
|
87
|
-
query: {
|
|
88
|
-
general: {variants?: {code: string}[]};
|
|
89
|
-
magicwords: MagicWord[];
|
|
90
|
-
extensiontags: string[];
|
|
91
|
-
functionhooks: string[];
|
|
92
|
-
variables: string[];
|
|
93
|
-
};
|
|
94
|
-
} = await new mw.Api().get({
|
|
95
|
-
meta: 'siteinfo',
|
|
96
|
-
siprop: [
|
|
97
|
-
'general',
|
|
98
|
-
'magicwords',
|
|
99
|
-
...config && !isIPE ? [] : ['extensiontags', 'functionhooks'],
|
|
100
|
-
...config?.variableIDs && !isIPE ? [] : ['variables'],
|
|
101
|
-
],
|
|
102
|
-
formatversion: '2',
|
|
103
|
-
}) as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
104
|
-
const others = new Set(['msg', 'raw', 'msgnw', 'subst', 'safesubst']);
|
|
105
|
-
|
|
106
|
-
// 先处理魔术字和状态开关
|
|
107
|
-
if (config && !isIPE) { // 情形2或3
|
|
108
|
-
const {functionSynonyms: [insensitive]} = config;
|
|
109
|
-
if (!('subst' in insensitive)) {
|
|
110
|
-
Object.assign(insensitive, getConfig(magicwords, ({name}) => others.has(name)));
|
|
111
|
-
}
|
|
112
|
-
} else { // 情形4:`config === null`
|
|
113
|
-
const functions = new Set([
|
|
114
|
-
...functionhooks,
|
|
115
|
-
...variables,
|
|
116
|
-
...others,
|
|
117
|
-
]);
|
|
118
|
-
// @ts-expect-error incomplete properties
|
|
119
|
-
config = {
|
|
120
|
-
tags: Object.fromEntries(extensiontags.map(tag => [tag.slice(1, -1), true])),
|
|
121
|
-
functionSynonyms: getConfigPair(magicwords, ({name}) => functions.has(name)),
|
|
122
|
-
doubleUnderscore: getConfigPair(
|
|
123
|
-
magicwords,
|
|
124
|
-
({aliases}) => aliases.some(alias => /^__.+__$/u.test(alias)),
|
|
125
|
-
),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
config!.tagModes = modes;
|
|
129
|
-
config!.img = getConfig(magicwords, ({name}) => name.startsWith('img_'));
|
|
130
|
-
config!.variants = variants ? variants.map(({code}) => code) : [];
|
|
131
|
-
config!.redirection = magicwords.find(({name}) => name === 'redirect')!.aliases;
|
|
132
|
-
config!.urlProtocols = mw.config.get('wgUrlProtocols').replace(/\\:/gu, ':');
|
|
133
|
-
config!.variableIDs ??= variables;
|
|
134
|
-
}
|
|
135
|
-
setConfig(config!);
|
|
136
|
-
ALL_SETTINGS_CACHE[SITE_ID] = {config: config!, time: Date.now()};
|
|
137
|
-
setObject('InPageEditMwConfig', ALL_SETTINGS_CACHE);
|
|
138
|
-
return {...config!, nsid};
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 将MwConfig转换为Config
|
|
143
|
-
* @param minConfig 基础Config
|
|
144
|
-
* @param mwConfig
|
|
145
|
-
*/
|
|
146
|
-
export const getParserConfig = (minConfig: Config, mwConfig: MwConfig): Config => {
|
|
147
|
-
let config: Config | null = getObject('wikilintConfig');
|
|
148
|
-
if (config) {
|
|
149
|
-
return config;
|
|
150
|
-
}
|
|
151
|
-
const {tags, nsid, doubleUnderscore, variants, urlProtocols, redirection, functionSynonyms, img} = mwConfig,
|
|
152
|
-
[insensitive, sensitive] = functionSynonyms;
|
|
153
|
-
config = {
|
|
154
|
-
...minConfig,
|
|
155
|
-
ext: Object.keys(tags),
|
|
156
|
-
namespaces: mw.config.get('wgFormattedNamespaces'),
|
|
157
|
-
nsid,
|
|
158
|
-
doubleUnderscore: doubleUnderscore.map(
|
|
159
|
-
obj => Object.keys(obj).map(s => s.slice(2, -2)),
|
|
160
|
-
) as [string[], string[]],
|
|
161
|
-
variants: variants!,
|
|
162
|
-
protocol: urlProtocols.replace(/\|\\?\/\\?\//u, ''),
|
|
163
|
-
redirection: redirection ?? minConfig.redirection,
|
|
164
|
-
};
|
|
165
|
-
if (location.hostname.endsWith('.moegirl.org.cn')) {
|
|
166
|
-
config.html[2].push('img');
|
|
167
|
-
}
|
|
168
|
-
config.parserFunction[0] = insensitive;
|
|
169
|
-
if (mw.loader.getState('ext.CodeMirror') === null) {
|
|
170
|
-
for (const [key, val] of Object.entries(insensitive)) {
|
|
171
|
-
if (!key.startsWith('#')) {
|
|
172
|
-
config.parserFunction[0][`#${key}`] = val;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
config.parserFunction[1] = 'wikiparser' in globalThis
|
|
177
|
-
&& compareVersion(wikiparse.version, '1.15')
|
|
178
|
-
&& !Object.values(sensitive as Record<string, unknown>).includes(true)
|
|
179
|
-
? {...sensitive, '=': '='}
|
|
180
|
-
: [...Object.keys(sensitive), '='];
|
|
181
|
-
for (const [key, val] of Object.entries(img!)) {
|
|
182
|
-
config.img[key] = val.slice(4);
|
|
183
|
-
}
|
|
184
|
-
return config;
|
|
185
|
-
};
|
package/src/linter.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import {CDN, loadScript} from '@bhsd/common';
|
|
2
|
-
import type {LinterBase} from 'wikiparser-node/extensions/typings';
|
|
3
|
-
import type {Linter} from 'eslint';
|
|
4
|
-
import type {Warning} from 'stylelint';
|
|
5
|
-
import type {Diagnostic} from 'luacheck-browserify';
|
|
6
|
-
|
|
7
|
-
declare type getLinter<T> = (opt?: Record<string, unknown>) => T;
|
|
8
|
-
declare type getAsyncLinter<T> = (opt?: Record<string, unknown>) => Promise<T>;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 获取 WikiLint
|
|
12
|
-
* @param opt 选项
|
|
13
|
-
*/
|
|
14
|
-
export const getWikiLinter: getAsyncLinter<LinterBase> = async opt => {
|
|
15
|
-
const REPO = 'npm/wikiparser-node',
|
|
16
|
-
DIR = `${REPO}/extensions/dist`,
|
|
17
|
-
lang = opt?.['i18n'];
|
|
18
|
-
await loadScript(`${DIR}/base.min.js`, 'wikiparse');
|
|
19
|
-
await loadScript(`${DIR}/lint.min.js`, 'wikiparse.Linter');
|
|
20
|
-
if (typeof lang === 'string') {
|
|
21
|
-
try {
|
|
22
|
-
const i18n: Record<string, string> =
|
|
23
|
-
await (await fetch(`${CDN}/${REPO}/i18n/${lang.toLowerCase()}.json`)).json();
|
|
24
|
-
wikiparse.setI18N(i18n);
|
|
25
|
-
} catch {}
|
|
26
|
-
}
|
|
27
|
-
return new wikiparse.Linter!(opt?.['include'] as boolean | undefined);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 获取 ESLint
|
|
32
|
-
* @param opt 选项
|
|
33
|
-
*/
|
|
34
|
-
export const getJsLinter: getAsyncLinter<(text: string) => Linter.LintMessage[]> = async opt => {
|
|
35
|
-
await loadScript('npm/eslint-linter-browserify@8.57.0/linter.min.js', 'eslint', true);
|
|
36
|
-
/** @see https://www.npmjs.com/package/@codemirror/lang-javascript */
|
|
37
|
-
const esLinter = new eslint.Linter(),
|
|
38
|
-
conf: Linter.Config = {
|
|
39
|
-
env: {browser: true, es2024: true},
|
|
40
|
-
parserOptions: {ecmaVersion: 15, sourceType: 'module'},
|
|
41
|
-
rules: {},
|
|
42
|
-
...opt,
|
|
43
|
-
};
|
|
44
|
-
for (const [name, {meta}] of esLinter.getRules()) {
|
|
45
|
-
if (meta?.docs?.recommended) {
|
|
46
|
-
conf.rules![name] ??= 2;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return text => esLinter.verify(text, conf);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 获取 Stylelint
|
|
54
|
-
* @param opt 选项
|
|
55
|
-
*/
|
|
56
|
-
export const getCssLinter: getAsyncLinter<(text: string) => Promise<Warning[]>> = async opt => {
|
|
57
|
-
await loadScript('npm/stylelint-bundle', 'stylelint');
|
|
58
|
-
/** @see https://www.npmjs.com/package/stylelint-config-recommended */
|
|
59
|
-
const config = {
|
|
60
|
-
rules: {
|
|
61
|
-
'annotation-no-unknown': true,
|
|
62
|
-
'at-rule-no-unknown': true,
|
|
63
|
-
'block-no-empty': true,
|
|
64
|
-
'color-no-invalid-hex': true,
|
|
65
|
-
'comment-no-empty': true,
|
|
66
|
-
'custom-property-no-missing-var-function': true,
|
|
67
|
-
'declaration-block-no-duplicate-custom-properties': true,
|
|
68
|
-
'declaration-block-no-duplicate-properties': [
|
|
69
|
-
true,
|
|
70
|
-
{
|
|
71
|
-
ignore: ['consecutive-duplicates-with-different-syntaxes'],
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
'declaration-block-no-shorthand-property-overrides': true,
|
|
75
|
-
'font-family-no-duplicate-names': true,
|
|
76
|
-
'font-family-no-missing-generic-family-keyword': true,
|
|
77
|
-
'function-calc-no-unspaced-operator': true,
|
|
78
|
-
'function-linear-gradient-no-nonstandard-direction': true,
|
|
79
|
-
'function-no-unknown': true,
|
|
80
|
-
'keyframe-block-no-duplicate-selectors': true,
|
|
81
|
-
'keyframe-declaration-no-important': true,
|
|
82
|
-
'media-feature-name-no-unknown': true,
|
|
83
|
-
'media-query-no-invalid': true,
|
|
84
|
-
'named-grid-areas-no-invalid': true,
|
|
85
|
-
'no-descending-specificity': true,
|
|
86
|
-
'no-duplicate-at-import-rules': true,
|
|
87
|
-
'no-duplicate-selectors': true,
|
|
88
|
-
'no-empty-source': true,
|
|
89
|
-
'no-invalid-double-slash-comments': true,
|
|
90
|
-
'no-invalid-position-at-import-rule': true,
|
|
91
|
-
'no-irregular-whitespace': true,
|
|
92
|
-
'property-no-unknown': true,
|
|
93
|
-
'selector-anb-no-unmatchable': true,
|
|
94
|
-
'selector-pseudo-class-no-unknown': true,
|
|
95
|
-
'selector-pseudo-element-no-unknown': true,
|
|
96
|
-
'selector-type-no-unknown': [
|
|
97
|
-
true,
|
|
98
|
-
{
|
|
99
|
-
ignore: ['custom-elements'],
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
'string-no-newline': true,
|
|
103
|
-
'unit-no-unknown': true,
|
|
104
|
-
...opt?.['rules'] as Record<string, unknown>,
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
return async code => (await stylelint.lint({code, config})).results.flatMap(({warnings}) => warnings);
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
/** 获取 Luacheck */
|
|
111
|
-
export const getLuaLinter: getAsyncLinter<(text: string) => Promise<Diagnostic[]>> = async () => {
|
|
112
|
-
await loadScript('npm/luacheck-browserify/dist/index.min.js', 'luacheck');
|
|
113
|
-
const luachecker = await luacheck(undefined as unknown as string);
|
|
114
|
-
return async text => (await luachecker.queue(text)).filter(({severity}) => severity);
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
declare interface JsonError {
|
|
118
|
-
message: string;
|
|
119
|
-
severity: 'error';
|
|
120
|
-
line: string | undefined;
|
|
121
|
-
column: string | undefined;
|
|
122
|
-
position: string | undefined;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** JSON.parse */
|
|
126
|
-
export const getJsonLinter: getLinter<(text: string) => JsonError[]> = () => str => {
|
|
127
|
-
try {
|
|
128
|
-
if (str.trim()) {
|
|
129
|
-
JSON.parse(str);
|
|
130
|
-
}
|
|
131
|
-
} catch (e) {
|
|
132
|
-
if (e instanceof SyntaxError) {
|
|
133
|
-
const {message} = e,
|
|
134
|
-
line = /\bline (\d+)/u.exec(message)?.[1],
|
|
135
|
-
column = /\bcolumn (\d+)/u.exec(message)?.[1],
|
|
136
|
-
position = /\bposition (\d+)/u.exec(message)?.[1];
|
|
137
|
-
return [
|
|
138
|
-
{
|
|
139
|
-
message,
|
|
140
|
-
severity: 'error',
|
|
141
|
-
line,
|
|
142
|
-
column,
|
|
143
|
-
position,
|
|
144
|
-
},
|
|
145
|
-
];
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return [];
|
|
149
|
-
};
|
package/src/static.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type {Config} from 'wikiparser-node';
|
|
2
|
-
import type {MwConfig} from './token';
|
|
3
|
-
|
|
4
|
-
export const tagModes = {
|
|
5
|
-
onlyinclude: 'mediawiki',
|
|
6
|
-
includeonly: 'mediawiki',
|
|
7
|
-
noinclude: 'mediawiki',
|
|
8
|
-
pre: 'text/pre',
|
|
9
|
-
nowiki: 'text/nowiki',
|
|
10
|
-
indicator: 'mediawiki',
|
|
11
|
-
poem: 'mediawiki',
|
|
12
|
-
ref: 'mediawiki',
|
|
13
|
-
references: 'text/references',
|
|
14
|
-
gallery: 'text/gallery',
|
|
15
|
-
poll: 'mediawiki',
|
|
16
|
-
tabs: 'mediawiki',
|
|
17
|
-
tab: 'mediawiki',
|
|
18
|
-
choose: 'text/choose',
|
|
19
|
-
option: 'mediawiki',
|
|
20
|
-
combobox: 'text/combobox',
|
|
21
|
-
combooption: 'mediawiki',
|
|
22
|
-
inputbox: 'text/inputbox',
|
|
23
|
-
templatedata: 'json',
|
|
24
|
-
mapframe: 'json',
|
|
25
|
-
maplink: 'json',
|
|
26
|
-
graph: 'json',
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const getStaticMwConfig = (
|
|
30
|
-
{
|
|
31
|
-
variable,
|
|
32
|
-
parserFunction: [p0, p1, ...p2],
|
|
33
|
-
protocol,
|
|
34
|
-
nsid,
|
|
35
|
-
variants,
|
|
36
|
-
redirection,
|
|
37
|
-
ext,
|
|
38
|
-
doubleUnderscore: [d0, d1, d2, d3],
|
|
39
|
-
img,
|
|
40
|
-
}: Config,
|
|
41
|
-
modes: Record<string, string>,
|
|
42
|
-
): MwConfig => ({
|
|
43
|
-
tags: Object.fromEntries(ext.map(s => [s, true])),
|
|
44
|
-
tagModes: modes,
|
|
45
|
-
doubleUnderscore: [
|
|
46
|
-
Object.fromEntries((d2 && d0.length === 0 ? Object.keys(d2) : d0).map(s => [`__${s}__`, true])),
|
|
47
|
-
Object.fromEntries((d3 && d1.length === 0 ? Object.keys(d3) : d1).map(s => [`__${s}__`, true])),
|
|
48
|
-
],
|
|
49
|
-
variableIDs: variable,
|
|
50
|
-
functionSynonyms: [
|
|
51
|
-
{
|
|
52
|
-
...p0,
|
|
53
|
-
...Object.fromEntries(p2.flat().map(s => [s, s])),
|
|
54
|
-
},
|
|
55
|
-
Array.isArray(p1) ? Object.fromEntries(p1.map(s => [s, s.toLowerCase()])) : {...p1},
|
|
56
|
-
],
|
|
57
|
-
urlProtocols: `${protocol}|//`,
|
|
58
|
-
nsid,
|
|
59
|
-
img: Object.fromEntries(Object.entries(img).map(([k, v]) => [k, `img_${v}`])),
|
|
60
|
-
variants,
|
|
61
|
-
redirection,
|
|
62
|
-
});
|