引入ESLint与Prettier

This commit is contained in:
ProjectXero 2023-10-21 10:32:35 +08:00
parent f7e29dc285
commit 040f0f3f5c
No known key found for this signature in database
GPG Key ID: 5B1AA72F4425593E
10 changed files with 2938 additions and 184 deletions

2741
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,19 @@
"license": "MIT",
"scripts": {
"build": "node ./script/build.js",
"update": "node ./script/update.js"
"update": "node ./script/update.js",
"lint-script": "eslint --fix script"
},
"dependencies": {
"ts-morph": "^20.0.0",
"typedoc": "^0.25.1",
"typedoc-plugin-mdn-links": "^3.1.0",
"typescript": "^5.2.2"
},
"devDependencies": {
"eslint": "^8.52.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"prettier": "^3.0.3"
}
}

16
script/.eslintrc.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
root: true,
plugins: ['prettier'],
extends: ['eslint:recommended', 'prettier'],
parserOptions: {
ecmaVersion: 'latest'
},
env: {
commonjs: true,
es2021: true,
node: true
},
rules: {
'prettier/prettier': 'error'
}
};

7
script/.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"printWidth": 120,
"tabWidth": 4,
"trailingComma": "none",
"singleQuote": true
}

View File

@ -1,33 +1,33 @@
const TypeDoc = require("typedoc");
const { Project } = require("ts-morph");
const { createRequire } = require("module");
const { resolve: resolvePath, relative: relativePath } = require("path");
const { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } = require("fs");
const { split } = require("./split");
const { execSync } = require("child_process");
const TypeDoc = require('typedoc');
const { Project } = require('ts-morph');
const { createRequire } = require('module');
const { resolve: resolvePath, relative: relativePath } = require('path');
const { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } = require('fs');
const { split } = require('./split');
const { execSync } = require('child_process');
const basePath = resolvePath(__dirname, "..");
const originalPath = resolvePath(basePath, "original");
const translatedPath = resolvePath(basePath, "translated");
const distPath = resolvePath(basePath, "dist");
const hookPath = resolvePath(__dirname, "hooks");
const basePath = resolvePath(__dirname, '..');
const originalPath = resolvePath(basePath, 'original');
const translatedPath = resolvePath(basePath, 'translated');
const distPath = resolvePath(basePath, 'dist');
const hookPath = resolvePath(__dirname, 'hooks');
const namespacePrefix = "@minecraft/";
const botModules = [
"@minecraft/vanilla-data"
];
const namespacePrefix = '@minecraft/';
const botModules = ['@minecraft/vanilla-data'];
function readPackageInfo(modulePath) {
const packageInfoPath = resolvePath(modulePath, "package.json");
const packageInfoPath = resolvePath(modulePath, 'package.json');
if (existsSync(packageInfoPath)) {
try {
return JSON.parse(readFileSync(packageInfoPath, "utf-8"));
} catch(e) { /* ignore */ }
return JSON.parse(readFileSync(packageInfoPath, 'utf-8'));
} catch (e) {
/* ignore */
}
}
}
function findModule(moduleName, root) {
const localRequire = createRequire(resolvePath(root, "node_modules"));
const localRequire = createRequire(resolvePath(root, 'node_modules'));
const searchPaths = localRequire.resolve.paths(moduleName);
for (const searchPath of searchPaths) {
const modulePath = resolvePath(searchPath, moduleName);
@ -57,14 +57,13 @@ function getCommonStringFromStart(a, b) {
return a.slice(0, len);
}
}
return "";
return '';
}
async function build(translated) {
// 加载钩子
mkdirSync(hookPath, { recursive: true });
const hookScripts = readdirSync(hookPath)
.filter((name) => /\.(cjs|js)$/i.test(name));
const hookScripts = readdirSync(hookPath).filter((name) => /\.(cjs|js)$/i.test(name));
hookScripts.sort();
const scriptRequire = createRequire(hookPath);
const scriptHooks = hookScripts.map((name) => scriptRequire(resolvePath(hookPath, name)));
@ -73,7 +72,7 @@ async function build(translated) {
const scriptHook = scriptHooks[i];
const logName = `[${event}] ${hookScripts[i]}`;
let hookFunc;
if (typeof scriptHooks === "function") {
if (typeof scriptHooks === 'function') {
hookFunc = scriptHook.bind(null, event);
} else {
hookFunc = scriptHook[event];
@ -85,28 +84,28 @@ async function build(translated) {
console.timeEnd(logName);
}
}
}
};
// 尝试加载翻译文件对应版本的 package.json
console.time('[restoreDependencies] Total');
const originalPackageJsonPath = resolvePath(originalPath, "package.json");
const cachedPackageJsonPath = resolvePath(translatedPath, "package.json");
const originalPackageJsonPath = resolvePath(originalPath, 'package.json');
const cachedPackageJsonPath = resolvePath(translatedPath, 'package.json');
const originalPackageJsonData = readFileSync(originalPackageJsonPath);
if (existsSync(cachedPackageJsonPath)) {
writeFileSync(originalPackageJsonPath, readFileSync(cachedPackageJsonPath));
}
// 使依赖与 package.json 同步
execSync("npm install", {
execSync('npm install', {
cwd: originalPath,
stdio: "inherit"
stdio: 'inherit'
});
console.timeEnd('[restoreDependencies] Total');
// 从依赖中构建用于生成文档的项目
console.time('[loadOriginal] Total');
await runHooks("beforeLoad", {});
const tsConfigFilePath = resolvePath(translatedPath, "tsconfig.json");
await runHooks('beforeLoad', {});
const tsConfigFilePath = resolvePath(translatedPath, 'tsconfig.json');
const project = new Project({
tsConfigFilePath,
skipAddingFilesFromTsConfig: true
@ -123,9 +122,9 @@ async function build(translated) {
console.log(`Loading d.ts for ${moduleName}@${version}`);
const dtsFiles = [];
walkFiles(modulePath, (dir, file, path) => {
if (file && file.endsWith(".d.ts")) {
if (file && file.endsWith('.d.ts')) {
const relPath = relativePath(modulePath, path);
if (!relPath.includes("node_modules")) {
if (!relPath.includes('node_modules')) {
dtsFiles.push(path);
}
}
@ -136,24 +135,25 @@ async function build(translated) {
if (dtsFiles.length === 1) {
const sourceFile = project.createSourceFile(
resolvePath(translatedPath, `${pureModuleName}.d.ts`),
readFileSync(dtsFiles[0], "utf-8").replace(/\r\n|\r/g, '\n'),
readFileSync(dtsFiles[0], 'utf-8').replace(/\r\n|\r/g, '\n'),
{ overwrite: true }
);
if (!botModules.includes(moduleName)) sourceFiles.push(sourceFile);
} else {
const typeEntry = resolvePath(modulePath, packageInfo.types).replace(/\.d\.ts$/i, "");
const commonParent = dtsFiles.map((path) => resolvePath(path, ".."))
const typeEntry = resolvePath(modulePath, packageInfo.types).replace(/\.d\.ts$/i, '');
const commonParent = dtsFiles
.map((path) => resolvePath(path, '..'))
.reduce((common, parent) => getCommonStringFromStart(common, parent));
const moduleRoot = resolvePath(translatedPath, pureModuleName);
const moduleEntry = resolvePath(moduleRoot, relativePath(commonParent, typeEntry));
const moduleEntryRelative = `./${relativePath(translatedPath, moduleEntry).replace(/\\/g, "/")}`;
const moduleEntryRelative = `./${relativePath(translatedPath, moduleEntry).replace(/\\/g, '/')}`;
const exportStatement = `export * from ${JSON.stringify(moduleEntryRelative)};`;
dtsFiles.forEach((file) => {
const target = resolvePath(moduleRoot, relativePath(commonParent, file));
mkdirSync(resolvePath(target, ".."), { recursive: true });
mkdirSync(resolvePath(target, '..'), { recursive: true });
const sourceFile = project.createSourceFile(
target,
readFileSync(file, "utf-8").replace(/\r\n|\r/g, '\n'),
readFileSync(file, 'utf-8').replace(/\r\n|\r/g, '\n'),
{ overwrite: true }
);
if (!botModules.includes(moduleName)) sourceFiles.push(sourceFile);
@ -169,9 +169,9 @@ async function build(translated) {
}
});
writeFileSync(originalPackageJsonPath, originalPackageJsonData);
await runHooks("afterLoad", { project, sourceFiles, dependencies });
await runHooks('afterLoad', { project, sourceFiles, dependencies });
console.timeEnd('[loadOriginal] Total');
if (translated) {
// 将顶层成员替换为带翻译的版本
console.time('[translate] Total');
@ -182,7 +182,7 @@ async function build(translated) {
pieces.sort((a, b) => b.start - a.start);
pieces.forEach((piece) => {
if (!existsSync(piece.path)) return;
const text = readFileSync(piece.path, "utf-8");
const text = readFileSync(piece.path, 'utf-8');
sourceFileText = `${sourceFileText.slice(0, piece.start)}${text}${sourceFileText.slice(piece.end)}`;
writtenCount++;
});
@ -190,29 +190,32 @@ async function build(translated) {
sourceFile.replaceWithText(sourceFileText);
}
});
await runHooks("afterTranslate", { project, sourceFiles, dependencies });
await runHooks('afterTranslate', { project, sourceFiles, dependencies });
console.timeEnd('[translate] Total');
}
// 生成 TypeDoc 页面
console.time('[analyze] Total');
project.saveSync();
const tsdocApplication = await TypeDoc.Application.bootstrapWithPlugins({
tsconfig: tsConfigFilePath,
githubPages: false
}, [new TypeDoc.TSConfigReader()]);
await runHooks("beforeConvert", { project, sourceFiles, dependencies, tsdocApplication });
const tsdocApplication = await TypeDoc.Application.bootstrapWithPlugins(
{
tsconfig: tsConfigFilePath,
githubPages: false
},
[new TypeDoc.TSConfigReader()]
);
await runHooks('beforeConvert', { project, sourceFiles, dependencies, tsdocApplication });
const tsdocProject = await tsdocApplication.convert();
console.timeEnd('[analyze] Total');
if (tsdocProject) {
console.time('[emit] Total');
await runHooks("afterConvert", { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
await runHooks('afterConvert', { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
await tsdocApplication.generateDocs(tsdocProject, distPath);
await tsdocApplication.generateJson(tsdocProject, resolvePath(distPath, 'index.json'));
await runHooks("afterEmit", { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
await runHooks('afterEmit', { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
console.timeEnd('[emit] Total');
} else {
throw new Error("Convert failed");
throw new Error('Convert failed');
}
return { project, sourceFiles, dependencies, tsdocProject };
}
@ -225,4 +228,4 @@ if (require.main === module) {
build(true).catch((err) => {
console.error(err);
});
}
}

View File

@ -1,16 +1,19 @@
const TypeDoc = require("typedoc");
const TypeDoc = require('typedoc');
/** @type {import('./hook').Hook} */
module.exports = {
afterConvert({ tsdocProject }) {
const reflectionEntries = Object.entries(tsdocProject.reflections)
.filter(([id, refl]) => !refl.kindOf([
TypeDoc.ReflectionKind.ConstructorSignature,
TypeDoc.ReflectionKind.CallSignature,
TypeDoc.ReflectionKind.GetSignature,
TypeDoc.ReflectionKind.SetSignature
]))
.map(([id, refl]) => [refl.getFriendlyFullName(), refl]);
const reflectionEntries = Object.values(tsdocProject.reflections)
.filter(
(refl) =>
!refl.kindOf([
TypeDoc.ReflectionKind.ConstructorSignature,
TypeDoc.ReflectionKind.CallSignature,
TypeDoc.ReflectionKind.GetSignature,
TypeDoc.ReflectionKind.SetSignature
])
)
.map((refl) => [refl.getFriendlyFullName(), refl]);
const visitCommentPart = (/** @type {TypeDoc.CommentDisplayPart} */ part) => {
if (part.kind === 'inline-tag' && part.tag === '@link') {
if (typeof part.target === 'string') {
@ -19,26 +22,30 @@ module.exports = {
if (typeof part.target === 'object' && part.target.name === part.text) {
return;
}
const segments = part.text.split(/[\./]/);
const segments = part.text.split(/[./]/);
const probablySymbolNames = segments.map((_, i) => segments.slice(i).join('.'));
const foundReflections = reflectionEntries.map(([friendlyFullName, refl]) => [
probablySymbolNames.findIndex((symbolName) => friendlyFullName === symbolName || friendlyFullName.endsWith(`.${symbolName}`)),
refl,
friendlyFullName
]).filter(([rank, refl]) => rank >= 0);
const foundReflections = reflectionEntries
.map(([friendlyFullName, refl]) => [
probablySymbolNames.findIndex(
(symbolName) =>
friendlyFullName === symbolName || friendlyFullName.endsWith(`.${symbolName}`)
),
refl,
friendlyFullName
])
.filter(([rank]) => rank >= 0);
if (foundReflections.length === 0) {
return;
}
const bestMatchReflection = foundReflections
.reduce((best, e) => e[0] < best[0] ? e : best);
const bestMatchReflection = foundReflections.reduce((best, e) => (e[0] < best[0] ? e : best));
const bestMatchReflections = foundReflections.filter((e) => e[0] <= bestMatchReflection[0]);
if (bestMatchReflections.length >= 2) {
console.warn(`Multiple resolutions of link: ${part.text}`);
}
part.target = bestMatchReflection[1];
}
}
Object.entries(tsdocProject.reflections).forEach(([id, reflection]) => {
};
Object.values(tsdocProject.reflections).forEach((reflection) => {
if (reflection.comment) {
reflection.comment.summary.forEach(visitCommentPart);
reflection.comment.blockTags.forEach((tag) => {

View File

@ -1,10 +1,10 @@
/** @type {import('./hook').Hook} */
module.exports = {
afterConvert({ tsdocProject }) {
Object.entries(tsdocProject.reflections).forEach(([id, reflection]) => {
Object.values(tsdocProject.reflections).forEach((reflection) => {
if (reflection.sources) {
reflection.sources.forEach((source) => {
source.fileName = source.fileName.replace("translated", tsdocProject.name);
source.fileName = source.fileName.replace('translated', tsdocProject.name);
});
}
});

View File

@ -1,5 +1,5 @@
import { Project, SourceFile } from "ts-morph";
import { Application, ProjectReflection } from "typedoc";
import { Project, SourceFile } from 'ts-morph';
import { Application, ProjectReflection } from 'typedoc';
declare type HookFunction<Context> = (context: Context) => void | Promise<void>;
@ -23,5 +23,5 @@ declare interface Hook {
afterTranslate?: HookFunction<TranslateHookContext>;
beforeConvert?: HookFunction<BeforeConvertHookContext>;
afterConvert?: HookFunction<AfterConvertHookContext>;
afterConvert?: HookFunction<AfterConvertHookContext>;
afterEmit?: HookFunction<AfterConvertHookContext>;
}

View File

@ -1,9 +1,9 @@
const { SyntaxKind, SourceFile } = require("ts-morph");
const { resolve: resolvePath, relative: relativePath } = require("path");
const { SyntaxKind } = require('ts-morph');
const { resolve: resolvePath, relative: relativePath } = require('path');
const basePath = resolvePath(__dirname, "..");
const translatingPath = resolvePath(basePath, "translate-pieces");
const translatedPath = resolvePath(basePath, "translated");
const basePath = resolvePath(__dirname, '..');
const translatingPath = resolvePath(basePath, 'translate-pieces');
const translatedPath = resolvePath(basePath, 'translated');
const SkippedTopLevelSyntaxKinds = [
SyntaxKind.EndOfFileToken,
@ -12,14 +12,14 @@ const SkippedTopLevelSyntaxKinds = [
];
const SyntaxKindToCategory = new Map([
[SyntaxKind.EnumDeclaration, "enums"],
[SyntaxKind.ClassDeclaration, "classes"],
[SyntaxKind.FunctionDeclaration, "functions"],
[SyntaxKind.InterfaceDeclaration, "interfaces"],
[SyntaxKind.ModuleDeclaration, "modules"],
[SyntaxKind.TypeAliasDeclaration, "types"],
[SyntaxKind.VariableStatement, "variables"],
[SyntaxKind.ExportDeclaration, "types"]
[SyntaxKind.EnumDeclaration, 'enums'],
[SyntaxKind.ClassDeclaration, 'classes'],
[SyntaxKind.FunctionDeclaration, 'functions'],
[SyntaxKind.InterfaceDeclaration, 'interfaces'],
[SyntaxKind.ModuleDeclaration, 'modules'],
[SyntaxKind.TypeAliasDeclaration, 'types'],
[SyntaxKind.VariableStatement, 'variables'],
[SyntaxKind.ExportDeclaration, 'types']
]);
/**
@ -33,7 +33,8 @@ function split(sourceFile) {
);
const piecePathList = [];
const pieces = [];
const packageDocumentationJSDoc = sourceFile.getDescendantsOfKind(SyntaxKind.JSDoc)
const packageDocumentationJSDoc = sourceFile
.getDescendantsOfKind(SyntaxKind.JSDoc)
.find((jsdoc) => jsdoc.getTags().some((tag) => tag.getTagName() === 'packageDocumentation'));
if (packageDocumentationJSDoc) {
pieces.push({
@ -44,7 +45,8 @@ function split(sourceFile) {
}
sourceFile.forEachChild((node) => {
if (SkippedTopLevelSyntaxKinds.includes(node.getKind())) return;
const includedSymbols = node.getDescendants()
const includedSymbols = node
.getDescendants()
.map((e) => e.getSymbol())
.filter((e) => e);
let symbol = node.getSymbol();
@ -67,7 +69,8 @@ function split(sourceFile) {
pieceIndex++;
}
piecePathList.push(piecePath.toLowerCase());
const jsdocList = node.getChildrenOfKind(SyntaxKind.JSDoc)
const jsdocList = node
.getChildrenOfKind(SyntaxKind.JSDoc)
.filter((jsdoc) => jsdoc.getStart() !== packageDocumentationJSDoc.getStart());
let pieceStart = node.getStart(false);
if (jsdocList.length > 0) {
@ -82,4 +85,4 @@ function split(sourceFile) {
return pieces;
}
module.exports = { split };
module.exports = { split };

View File

@ -1,20 +1,18 @@
const { execSync } = require("child_process");
const { readFileSync, writeFileSync, rmSync, mkdirSync, existsSync } = require("fs");
const { resolve: resolvePath } = require("path");
const { URL } = require("url");
const { build } = require("./build.js");
const { split } = require("./split.js");
const { execSync } = require('child_process');
const { readFileSync, writeFileSync, rmSync, mkdirSync, existsSync } = require('fs');
const { resolve: resolvePath } = require('path');
const { URL } = require('url');
const { build } = require('./build.js');
const { split } = require('./split.js');
const basePath = resolvePath(__dirname, "..");
const originalPath = resolvePath(basePath, "original");
const translatingPath = resolvePath(basePath, "translate-pieces");
const translatedPath = resolvePath(basePath, "translated");
const basePath = resolvePath(__dirname, '..');
const originalPath = resolvePath(basePath, 'original');
const translatingPath = resolvePath(basePath, 'translate-pieces');
const translatedPath = resolvePath(basePath, 'translated');
const namespacePrefix = "@minecraft/";
const baseURL = "https://projectxero.top/sapi/";
const botModules = [
"@minecraft/vanilla-data"
];
const namespacePrefix = '@minecraft/';
const baseURL = 'https://projectxero.top/sapi/';
const botModules = ['@minecraft/vanilla-data'];
function extractVersionInfo(versionString) {
const match = /^([\d.]+-\w+)\.([\d.]+)-(\w+)(\.\d+)?$/.exec(versionString);
@ -28,29 +26,29 @@ function extractVersionInfo(versionString) {
}
const KindString = [
"项目", // Project = 0x1,
"模块", // Module = 0x2,
"命名空间", // Namespace = 0x4,
"枚举", // Enum = 0x8,
"枚举成员", // EnumMember = 0x10,
"变量", // Variable = 0x20,
"函数", // Function = 0x40,
"类", // Class = 0x80,
"接口", // Interface = 0x100,
"构造器", // Constructor = 0x200,
"属性", // Property = 0x400,
"方法", // Method = 0x800,
"调用签名", // CallSignature = 0x1000,
"索引签名", // IndexSignature = 0x2000,
"构造器签名", // ConstructorSignature = 0x4000,
"参数", // Parameter = 0x8000,
"类型字面量", // TypeLiteral = 0x10000,
"类型参数", // TypeParameter = 0x20000,
"访问器", // Accessor = 0x40000,
"Getter 签名", // GetSignature = 0x80000,
"Setter 签名", // SetSignature = 0x100000,
"类型别名", // TypeAlias = 0x200000,
"引用" // Reference = 0x400000
'项目', // Project = 0x1,
'模块', // Module = 0x2,
'命名空间', // Namespace = 0x4,
'枚举', // Enum = 0x8,
'枚举成员', // EnumMember = 0x10,
'变量', // Variable = 0x20,
'函数', // Function = 0x40,
'类', // Class = 0x80,
'接口', // Interface = 0x100,
'构造器', // Constructor = 0x200,
'属性', // Property = 0x400,
'方法', // Method = 0x800,
'调用签名', // CallSignature = 0x1000,
'索引签名', // IndexSignature = 0x2000,
'构造器签名', // ConstructorSignature = 0x4000,
'参数', // Parameter = 0x8000,
'类型字面量', // TypeLiteral = 0x10000,
'类型参数', // TypeParameter = 0x20000,
'访问器', // Accessor = 0x40000,
'Getter 签名', // GetSignature = 0x80000,
'Setter 签名', // SetSignature = 0x100000,
'类型别名', // TypeAlias = 0x200000,
'引用' // Reference = 0x400000
];
function kindToString(kind) {
const result = [];
@ -59,28 +57,30 @@ function kindToString(kind) {
result.push(KindString[i]);
}
}
return result.join("/");
return result.join('/');
}
async function main() {
// 强制检出 original 分支
const head = execSync("git rev-parse --abbrev-ref HEAD", {
const head = execSync('git rev-parse --abbrev-ref HEAD', {
cwd: basePath
}).toString("utf-8").trim();
if (head !== "original" && head !== "HEAD") {
execSync("git checkout original", {
})
.toString('utf-8')
.trim();
if (head !== 'original' && head !== 'HEAD') {
execSync('git checkout original', {
cwd: basePath,
stdio: "inherit"
stdio: 'inherit'
});
}
// 清除 node_modules 与缓存的 package.json
const packageInfoPath = resolvePath(originalPath, "package.json");
const packageSnapshotPath = resolvePath(translatedPath, "package.json");
const packageInfoPath = resolvePath(originalPath, 'package.json');
const packageSnapshotPath = resolvePath(translatedPath, 'package.json');
if (existsSync(packageSnapshotPath)) {
rmSync(packageSnapshotPath);
}
const originalNodeModulesDir = resolvePath(originalPath, "node_modules");
const originalNodeModulesDir = resolvePath(originalPath, 'node_modules');
if (existsSync(originalNodeModulesDir)) {
rmSync(originalNodeModulesDir, { recursive: true, force: true });
}
@ -94,32 +94,21 @@ async function main() {
const pieces = split(sourceFile);
const sourceFileText = sourceFile.getFullText();
pieces.forEach((piece) => {
mkdirSync(resolvePath(piece.path, ".."), { recursive: true });
mkdirSync(resolvePath(piece.path, '..'), { recursive: true });
writeFileSync(piece.path, sourceFileText.slice(piece.start, piece.end));
});
});
// 生成 README.md
const readMePath = resolvePath(translatedPath, "README.md");
const readMe = readFileSync(readMePath, "utf-8");
const readMePath = resolvePath(translatedPath, 'README.md');
const readMe = readFileSync(readMePath, 'utf-8');
const summaryLines = [
"<!-- summary start -->",
"",
"模块:",
""
];
const summaryLines = ['<!-- summary start -->', '', '模块:', ''];
tsdocProject.children.forEach((moduleRef) => {
const docURL = new URL(moduleRef.url || '', baseURL);
summaryLines.push(`- [${namespacePrefix}${moduleRef.name}](${docURL})`);
});
summaryLines.push([
"",
"NPM 包:",
"",
"|包名|版本|",
"| - | - |"
]);
summaryLines.push(['', 'NPM 包:', '', '|包名|版本|', '| - | - |']);
let gameVersion;
Object.entries(dependencies).forEach(([moduleName, version]) => {
let versionString = version;
@ -131,32 +120,16 @@ async function main() {
const npmURL = `https://www.npmjs.com/package/${moduleName}`;
summaryLines.push(`|[${moduleName}](${npmURL})|\`${versionString}\`|`);
});
summaryLines.push([
"",
`游戏版本号:\`${gameVersion}\``,
"",
"<!-- summary end -->"
]);
summaryLines.push(['', `游戏版本号:\`${gameVersion}\``, '', '<!-- summary end -->']);
const statusHeadLines = [
"<!-- status start -->",
"",
"|模块|进度|",
"| - | - |"
];
const statusHeadLines = ['<!-- status start -->', '', '|模块|进度|', '| - | - |'];
const statusLines = [];
tsdocProject.children.forEach((moduleRef) => {
const moduleFullName = namespacePrefix + moduleRef.name;
if (botModules.includes(moduleFullName)) return;
const linkHref = moduleFullName.replace(/[@\/]/g, "");
const linkHref = moduleFullName.replace(/[@/]/g, '');
statusHeadLines.push(`|[${moduleFullName}](#${linkHref})|0/${moduleRef.children.length}|`);
statusLines.push([
"",
`### ${moduleFullName}`,
"",
"|名称|类型|状态|",
"| - | - | - |"
]);
statusLines.push(['', `### ${moduleFullName}`, '', '|名称|类型|状态|', '| - | - | - |']);
moduleRef.children.forEach((member) => {
const kindStr = kindToString(member.kind);
const url = new URL(member.url, baseURL);
@ -164,18 +137,15 @@ async function main() {
});
});
statusLines.unshift(statusHeadLines);
statusLines.push([
"",
"<!-- status end -->"
]);
statusLines.push(['', '<!-- status end -->']);
const newReadMe = readMe
.replace(/<!-- summary start -->\n\n[^]+\n\n<!-- summary end -->/, summaryLines.flat().join("\n"))
.replace(/<!-- status start -->\n\n[^]+\n\n<!-- status end -->/, statusLines.flat().join("\n"));
.replace(/<!-- summary start -->\n\n[^]+\n\n<!-- summary end -->/, summaryLines.flat().join('\n'))
.replace(/<!-- status start -->\n\n[^]+\n\n<!-- status end -->/, statusLines.flat().join('\n'));
writeFileSync(readMePath, newReadMe);
// 生成 package.json 快照
const packageInfo = JSON.parse(readFileSync(packageInfoPath, "utf-8"));
const packageInfo = JSON.parse(readFileSync(packageInfoPath, 'utf-8'));
writeFileSync(packageSnapshotPath, JSON.stringify({ ...packageInfo, dependencies }, null, 2));
}