@bhsd/common 0.10.2 → 0.12.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 ADDED
@@ -0,0 +1,4 @@
1
+ # @bhsd/common
2
+
3
+ [![npm version](https://badge.fury.io/js/@bhsd%2Fcommon.svg)](https://www.npmjs.com/package/@bhsd/common)
4
+ [![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](LICENSE)
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
+ import type { ConfigData } from 'wikiparser-node';
1
2
  import type { LanguageServiceBase } from 'wikiparser-node/extensions/typings';
2
- export declare const CDN = "https://testingcf.jsdelivr.net";
3
3
  export type RegexGetter<T = string> = (s: T) => RegExp;
4
+ declare type ConfigGetter = () => Promise<ConfigData>;
4
5
  declare global {
5
6
  const define: unknown;
6
7
  }
8
+ export declare const CDN = "https://testingcf.jsdelivr.net";
7
9
  /**
8
10
  * 解码HTML实体
9
11
  * @param str 要解码的字符串
@@ -45,12 +47,20 @@ export declare const setObject: (key: string, value: unknown) => void;
45
47
  * @param baseVersion 基础版本号
46
48
  */
47
49
  export declare const compareVersion: (version: string, baseVersion: string) => boolean;
50
+ /**
51
+ * 加载 wikiparse
52
+ * @param getConfig 获取解析配置的函数
53
+ * @param langs 语言代码
54
+ */
55
+ export declare const getWikiparse: (getConfig?: ConfigGetter, langs?: string | string[]) => Promise<void>;
48
56
  /**
49
57
  * 获取LSP
50
58
  * @param obj 关联对象
51
59
  * @param include 是否嵌入
60
+ * @param getConfig 获取解析配置的函数
61
+ * @param lang 语言代码
52
62
  */
53
- export declare const getLSP: (obj: object, include?: boolean) => LanguageServiceBase | undefined;
63
+ export declare const getLSP: (obj: object, include?: boolean, getConfig?: ConfigGetter, lang?: string) => LanguageServiceBase | undefined;
54
64
  /**
55
65
  * 清理内联样式中的`{`和`}`
56
66
  * @param style 内联样式
@@ -72,3 +82,4 @@ export declare function getRegex<T extends object>(f: RegexGetter<T>): RegexGett
72
82
  * @param f 生成正则表达式的函数
73
83
  */
74
84
  export declare const getObjRegex: typeof getRegex;
85
+ export {};
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  getObjRegex: () => getObjRegex,
26
26
  getObject: () => getObject,
27
27
  getRegex: () => getRegex,
28
+ getWikiparse: () => getWikiparse,
28
29
  loadScript: () => loadScript,
29
30
  normalizeTitle: () => normalizeTitle,
30
31
  numToHex: () => numToHex,
@@ -113,11 +114,33 @@ const compareVersion = (version, baseVersion) => {
113
114
  const [major, minor] = parseVersion(version), [baseMajor, baseMinor] = parseVersion(baseVersion);
114
115
  return major > baseMajor || major === baseMajor && minor >= baseMinor;
115
116
  };
117
+ let configLoaded = false, i18nLoaded = false;
118
+ const getWikiparse = async (getConfig, langs) => {
119
+ const dir = "extensions/dist";
120
+ await loadScript(`npm/wikiparser-node/${dir}/base.min.js`, "wikiparse");
121
+ await loadScript(`${wikiparse.CDN}/${dir}/lsp.min.js`, "wikiparse.LanguageService");
122
+ if (!configLoaded && typeof getConfig === "function") {
123
+ configLoaded = true;
124
+ try {
125
+ wikiparse.setConfig(await getConfig());
126
+ } catch {
127
+ }
128
+ }
129
+ if (!i18nLoaded && langs) {
130
+ i18nLoaded = true;
131
+ for (const lang of Array.isArray(langs) ? langs : [langs]) {
132
+ try {
133
+ const i18n = await (await fetch(`${wikiparse.CDN}/i18n/${lang.toLowerCase()}.json`)).json();
134
+ wikiparse.setI18N(i18n);
135
+ break;
136
+ } catch {
137
+ }
138
+ }
139
+ }
140
+ };
116
141
  const lsps = /* @__PURE__ */ new WeakMap();
117
- const getLSP = (obj, include) => {
118
- const path = "npm/wikiparser-node/extensions/dist";
119
- void loadScript(`${path}/base.min.js`, "wikiparse");
120
- void loadScript(`${path}/lsp.min.js`, "wikiparse.LanguageService");
142
+ const getLSP = (obj, include, getConfig, lang) => {
143
+ void getWikiparse(getConfig, lang);
121
144
  if (typeof wikiparse !== "object" || !wikiparse.LanguageService || lsps.has(obj)) {
122
145
  return lsps.get(obj);
123
146
  }
package/dist/index.mjs CHANGED
@@ -76,11 +76,33 @@ const compareVersion = (version, baseVersion) => {
76
76
  const [major, minor] = parseVersion(version), [baseMajor, baseMinor] = parseVersion(baseVersion);
77
77
  return major > baseMajor || major === baseMajor && minor >= baseMinor;
78
78
  };
79
+ let configLoaded = false, i18nLoaded = false;
80
+ const getWikiparse = async (getConfig, langs) => {
81
+ const dir = "extensions/dist";
82
+ await loadScript(`npm/wikiparser-node/${dir}/base.min.js`, "wikiparse");
83
+ await loadScript(`${wikiparse.CDN}/${dir}/lsp.min.js`, "wikiparse.LanguageService");
84
+ if (!configLoaded && typeof getConfig === "function") {
85
+ configLoaded = true;
86
+ try {
87
+ wikiparse.setConfig(await getConfig());
88
+ } catch {
89
+ }
90
+ }
91
+ if (!i18nLoaded && langs) {
92
+ i18nLoaded = true;
93
+ for (const lang of Array.isArray(langs) ? langs : [langs]) {
94
+ try {
95
+ const i18n = await (await fetch(`${wikiparse.CDN}/i18n/${lang.toLowerCase()}.json`)).json();
96
+ wikiparse.setI18N(i18n);
97
+ break;
98
+ } catch {
99
+ }
100
+ }
101
+ }
102
+ };
79
103
  const lsps = /* @__PURE__ */ new WeakMap();
80
- const getLSP = (obj, include) => {
81
- const path = "npm/wikiparser-node/extensions/dist";
82
- void loadScript(`${path}/base.min.js`, "wikiparse");
83
- void loadScript(`${path}/lsp.min.js`, "wikiparse.LanguageService");
104
+ const getLSP = (obj, include, getConfig, lang) => {
105
+ void getWikiparse(getConfig, lang);
84
106
  if (typeof wikiparse !== "object" || !wikiparse.LanguageService || lsps.has(obj)) {
85
107
  return lsps.get(obj);
86
108
  }
@@ -114,6 +136,7 @@ export {
114
136
  getObjRegex,
115
137
  getObject,
116
138
  getRegex,
139
+ getWikiparse,
117
140
  loadScript,
118
141
  normalizeTitle,
119
142
  numToHex,
package/dist/test.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ declare interface MediaWikiPage {
2
+ readonly pageid: number;
3
+ readonly title: string;
4
+ readonly ns: number;
5
+ readonly revisions?: {
6
+ readonly content: string;
7
+ readonly contentmodel: string;
8
+ }[];
9
+ }
10
+ export interface SimplePage extends Pick<MediaWikiPage, 'pageid' | 'title' | 'ns'> {
11
+ readonly content: string;
12
+ }
13
+ export interface Test {
14
+ desc: string;
15
+ wikitext?: string;
16
+ parsed?: string;
17
+ html?: string;
18
+ print?: string;
19
+ render?: string;
20
+ }
21
+ /**
22
+ * 获取最近更改的页面源代码
23
+ * @param url api.php网址
24
+ * @param site 站点名称
25
+ * @param grclimit 页面数上限
26
+ */
27
+ export declare const getPages: (url: string, site?: string, grclimit?: string) => Promise<SimplePage[]>;
28
+ /** 重置请求 */
29
+ export declare const reset: () => void;
30
+ /**
31
+ * 执行解析测试
32
+ * @param parse 解析函数
33
+ * @param retry 重试次数
34
+ * @param grclimit 页面数上限
35
+ */
36
+ export declare const execute: (parse: (wikitext: string) => unknown, retry?: number, grclimit?: string) => Promise<void>;
37
+ export declare const mochaTest: (results: unknown, parse: (wikitext: string) => string, beforeFn?: Mocha.Func | Mocha.AsyncFunc) => void;
38
+ export {};
package/dist/test.js ADDED
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // test/test.ts
31
+ var test_exports = {};
32
+ __export(test_exports, {
33
+ execute: () => execute,
34
+ getPages: () => getPages,
35
+ mochaTest: () => mochaTest,
36
+ reset: () => reset
37
+ });
38
+ module.exports = __toCommonJS(test_exports);
39
+ var import_fs = __toESM(require("fs"));
40
+ var import_assert = __toESM(require("assert"));
41
+ var import_perf_hooks = require("perf_hooks");
42
+
43
+ // src/index.ts
44
+ var refreshStdout = (str) => {
45
+ process.stdout.write(`\x1B[K\x1B[?7l${str}\x1B[?7h\r`);
46
+ };
47
+
48
+ // test/test.ts
49
+ var apis = [
50
+ ["维基百科", "https://zh.wikipedia.org/w"],
51
+ ["Wikipedia", "https://en.wikipedia.org/w"],
52
+ ["ウィキペディア", "https://ja.wikipedia.org/w"]
53
+ ];
54
+ var c;
55
+ var getPages = async (url, site, grclimit = "max") => {
56
+ const qs = {
57
+ action: "query",
58
+ format: "json",
59
+ formatversion: "2",
60
+ errorformat: "plaintext",
61
+ generator: "recentchanges",
62
+ grcnamespace: site === "MediaWiki" ? "0|10|12|100|102|104|106" : "0|10",
63
+ grclimit,
64
+ grctype: "edit|new",
65
+ grctoponly: "1",
66
+ prop: "revisions",
67
+ rvprop: "contentmodel|content",
68
+ ...c
69
+ }, response = await (await fetch(`${url}?${String(new URLSearchParams(qs))}`)).json();
70
+ c = response.continue;
71
+ return response.query.pages.map(({ pageid, title, ns, revisions }) => ({
72
+ pageid,
73
+ title,
74
+ ns,
75
+ content: revisions?.[0]?.contentmodel === "wikitext" && revisions[0].content
76
+ })).filter((page) => page.content !== false);
77
+ };
78
+ var reset = () => {
79
+ c = void 0;
80
+ };
81
+ var execute = async (parse, retry = 10, grclimit) => {
82
+ const failures = /* @__PURE__ */ new Map();
83
+ for (const [site, url] of apis) {
84
+ console.log(`开始检查${site}:`);
85
+ let worst;
86
+ reset();
87
+ try {
88
+ let failed = 0, i = 0;
89
+ for (let j = 0; j < retry; j++) {
90
+ for (const { content, title } of await getPages(`${url}/api.php`, site, grclimit)) {
91
+ refreshStdout(`${i++} ${title}`);
92
+ try {
93
+ const start = import_perf_hooks.performance.now();
94
+ parse(content);
95
+ const duration = import_perf_hooks.performance.now() - start;
96
+ if (!worst || duration > worst.duration) {
97
+ worst = { title, duration };
98
+ }
99
+ } catch (e) {
100
+ console.error(`
101
+ 解析 ${title} 页面时出错!`, e);
102
+ failed++;
103
+ }
104
+ }
105
+ }
106
+ if (failed) {
107
+ failures.set(site, failed);
108
+ }
109
+ console.log(`
110
+ 最耗时页面:${worst.title} (${worst.duration.toFixed(3)}ms)`);
111
+ } catch (e) {
112
+ console.error(`访问${site}的API端口时出错!`, e);
113
+ }
114
+ }
115
+ if (failures.size > 0) {
116
+ let total = 0;
117
+ for (const [site, failed] of failures) {
118
+ console.error(`${site}:${failed} 个页面解析失败!`);
119
+ total += failed;
120
+ }
121
+ throw new Error(`共有 ${total} 个页面解析失败!`);
122
+ }
123
+ };
124
+ var tests = require("wikiparser-node/test/parserTests.json");
125
+ var split = (test) => test?.parsed?.split(/(?<=<\/>)(?!$)|(?<!^)(?=<\w)/u);
126
+ var mochaTest = (results, parse, beforeFn) => {
127
+ describe("Parser tests", () => {
128
+ for (let i = tests.length - 1; i >= 0; i--) {
129
+ const test = tests[i], { wikitext, desc } = test;
130
+ if (wikitext) {
131
+ it(desc, () => {
132
+ try {
133
+ delete test.html;
134
+ delete test.print;
135
+ delete test.render;
136
+ test.parsed = parse(wikitext);
137
+ import_assert.default.deepStrictEqual(
138
+ split(test),
139
+ split(results.find(({ desc: d }) => d === desc))
140
+ );
141
+ } catch (e) {
142
+ if (!(e instanceof import_assert.default.AssertionError)) {
143
+ tests.splice(i, 1);
144
+ }
145
+ if (e instanceof Error) {
146
+ Object.assign(e, { cause: { message: `
147
+ ${wikitext}` } });
148
+ }
149
+ throw e;
150
+ }
151
+ });
152
+ }
153
+ }
154
+ if (beforeFn) {
155
+ before(beforeFn);
156
+ }
157
+ after(() => {
158
+ import_fs.default.writeFileSync(
159
+ "test/parserTests.json",
160
+ `${JSON.stringify(tests, null, " ")}
161
+ `
162
+ );
163
+ });
164
+ });
165
+ };
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ execute,
169
+ getPages,
170
+ mochaTest,
171
+ reset
172
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhsd/common",
3
- "version": "0.10.2",
3
+ "version": "0.12.0",
4
4
  "license": "MIT",
5
5
  "author": "Bhsd",
6
6
  "files": [
@@ -24,17 +24,19 @@
24
24
  "import": "./dist/cm.mjs",
25
25
  "require": "./dist/cm.js"
26
26
  },
27
+ "./dist/test": {
28
+ "types": "./dist/test.d.ts",
29
+ "import": "./dist/test.js",
30
+ "require": "./dist/test.js"
31
+ },
27
32
  "./*.cjs": "./*.cjs",
28
33
  "./package.json": "./package.json"
29
34
  },
30
35
  "types": "./dist/index.d.ts",
31
36
  "sideEffects": false,
32
- "bin": {
33
- "copy-dev": "bin/dev.cjs"
34
- },
35
37
  "scripts": {
36
38
  "prepublishOnly": "npm run build",
37
- "build": "tsc --emitDeclarationOnly && esbuild src/* --charset=utf8 --target=es2024 --format=cjs --outdir=dist && esbuild src/* --charset=utf8 --target=es2024 --format=esm --outdir=dist --out-extension:.js=.mjs && rm dist/global.*",
39
+ "build": "tsc && esbuild src/* --charset=utf8 --target=es2024 --format=cjs --outdir=dist && esbuild test/* --charset=utf8 --target=es2024 --format=cjs --outdir=dist --bundle --platform=node --external:wikiparser-node && esbuild src/* --charset=utf8 --target=es2024 --format=esm --outdir=dist --out-extension:.js=.mjs && mv dist/*/*.d.ts dist/ && rm dist/global.*",
38
40
  "lint:ts": "tsc --noEmit && eslint --cache .",
39
41
  "lint": "npm run lint:ts"
40
42
  },
@@ -54,15 +56,12 @@
54
56
  "eslint-plugin-eslint-comments": "^3.2.0",
55
57
  "eslint-plugin-jsdoc": "^50.6.3",
56
58
  "eslint-plugin-json-es": "^1.6.0",
57
- "eslint-plugin-markdown": "4.0.1",
58
59
  "eslint-plugin-n": "^17.15.1",
59
60
  "eslint-plugin-promise": "^7.2.1",
60
61
  "eslint-plugin-regexp": "^2.7.0",
61
62
  "eslint-plugin-unicorn": "^56.0.1",
62
- "http-server": "^14.1.1",
63
- "mocha": "^11.1.0",
64
- "stylelint": "^16.19.1",
63
+ "stylelint": "^16.20.0",
65
64
  "typescript": "^5.8.2",
66
- "wikiparser-node": "^1.20.3"
65
+ "wikiparser-node": "^1.21.1"
67
66
  }
68
67
  }
package/bin/dev.cjs DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs'),
5
- {devDependencies, version} = require('@bhsd/common/package.json'),
6
- json = require(`${process.cwd()}/package.json`);
7
- const {name: n, dependencies, optionalDependencies} = json,
8
- others = {[n]: '', ...dependencies, ...optionalDependencies},
9
- dev = Object.fromEntries(
10
- Object.entries({...json.devDependencies, ...devDependencies}).filter(([k]) => !(k in others))
11
- .sort(([a], [b]) => a.localeCompare(b)),
12
- );
13
- (dependencies && '@bhsd/common' in dependencies ? dependencies : dev)['@bhsd/common'] = `^${version}`;
14
- json.devDependencies = dev;
15
- fs.writeFileSync('package.json', `${JSON.stringify(json, null, '\t')}\n`);