@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 +4 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +27 -4
- package/dist/index.mjs +27 -4
- package/dist/test.d.ts +38 -0
- package/dist/test.js +172 -0
- package/package.json +9 -10
- package/bin/dev.cjs +0 -15
package/README.md
ADDED
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
|
-
|
|
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
|
-
|
|
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.
|
|
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 --
|
|
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
|
-
"
|
|
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.
|
|
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`);
|