mirror of
https://github.com/XeroAlpha/sapi-typedoc.git
synced 2024-11-22 17:48:50 +00:00
优化钩子调用方式
This commit is contained in:
parent
6f82e2a69e
commit
2d0734efa8
@ -3,14 +3,10 @@ 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, replacePieces } = require('./split');
|
||||
const { split, replacePieces } = require('./split.js');
|
||||
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 { loadHooks } = require('./hooks.js');
|
||||
const { basePath, originalPath, translatedPath, distPath } = require('./utils.js');
|
||||
|
||||
const namespacePrefix = '@minecraft/';
|
||||
const botModules = ['@minecraft/vanilla-data'];
|
||||
@ -82,30 +78,8 @@ function getCommonStringFromStart(a, b) {
|
||||
}
|
||||
|
||||
async function build(translated) {
|
||||
// 加载钩子
|
||||
mkdirSync(hookPath, { recursive: true });
|
||||
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)));
|
||||
const runHooks = async (event, arg) => {
|
||||
for (let i = 0; i < scriptHooks.length; i++) {
|
||||
const scriptHook = scriptHooks[i];
|
||||
const logName = `[${event}] ${hookScripts[i]}`;
|
||||
let hookFunc;
|
||||
if (typeof scriptHooks === 'function') {
|
||||
hookFunc = scriptHook.bind(null, event);
|
||||
} else {
|
||||
hookFunc = scriptHook[event];
|
||||
}
|
||||
if (hookFunc) {
|
||||
console.time(logName);
|
||||
const result = hookFunc(arg);
|
||||
if (result && result.then) await result;
|
||||
console.timeEnd(logName);
|
||||
}
|
||||
}
|
||||
};
|
||||
const runHooks = loadHooks();
|
||||
const hookEventContext = {};
|
||||
|
||||
// 尝试加载翻译文件对应版本的 package.json
|
||||
console.time('[restoreDependencies] Total');
|
||||
@ -129,7 +103,8 @@ async function build(translated) {
|
||||
|
||||
// 从依赖中构建用于生成文档的项目
|
||||
console.time('[loadOriginal] Total');
|
||||
await runHooks('beforeLoad', {});
|
||||
Object.assign(hookEventContext, { basePath });
|
||||
await runHooks('beforeLoad', hookEventContext);
|
||||
const tsConfigFilePath = resolvePath(translatedPath, 'tsconfig.json');
|
||||
const project = new Project({
|
||||
tsConfigFilePath,
|
||||
@ -197,7 +172,8 @@ async function build(translated) {
|
||||
dependencies[moduleName] = version;
|
||||
}
|
||||
});
|
||||
await runHooks('afterLoad', { project, sourceFiles, dependencies });
|
||||
Object.assign(hookEventContext, { basePath, project, sourceFiles, dependencies });
|
||||
await runHooks('afterLoad', hookEventContext);
|
||||
console.timeEnd('[loadOriginal] Total');
|
||||
|
||||
if (translated) {
|
||||
@ -207,7 +183,7 @@ async function build(translated) {
|
||||
const pieces = split(sourceFile);
|
||||
replacePieces(sourceFile, pieces);
|
||||
});
|
||||
await runHooks('afterTranslate', { project, sourceFiles, dependencies });
|
||||
await runHooks('afterTranslate', hookEventContext);
|
||||
console.timeEnd('[translate] Total');
|
||||
}
|
||||
|
||||
@ -223,20 +199,22 @@ async function build(translated) {
|
||||
},
|
||||
[new TypeDoc.TSConfigReader()]
|
||||
);
|
||||
await runHooks('beforeConvert', { project, sourceFiles, dependencies, tsdocApplication });
|
||||
Object.assign(hookEventContext, { tsdocApplication });
|
||||
await runHooks('beforeConvert', hookEventContext);
|
||||
const tsdocProject = await tsdocApplication.convert();
|
||||
console.timeEnd('[analyze] Total');
|
||||
if (tsdocProject) {
|
||||
console.time('[emit] Total');
|
||||
await runHooks('afterConvert', { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
|
||||
Object.assign(hookEventContext, { tsdocProject });
|
||||
await runHooks('afterConvert', hookEventContext);
|
||||
await tsdocApplication.generateDocs(tsdocProject, distPath);
|
||||
await tsdocApplication.generateJson(tsdocProject, resolvePath(distPath, 'index.json'));
|
||||
await runHooks('afterEmit', { project, sourceFiles, dependencies, tsdocApplication, tsdocProject });
|
||||
await runHooks('afterEmit', hookEventContext);
|
||||
console.timeEnd('[emit] Total');
|
||||
} else {
|
||||
throw new Error('Convert failed');
|
||||
}
|
||||
return { project, sourceFiles, dependencies, tsdocProject };
|
||||
return hookEventContext;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
34
script/hooks.js
Normal file
34
script/hooks.js
Normal file
@ -0,0 +1,34 @@
|
||||
const { createRequire } = require('module');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const { readdirSync, mkdirSync } = require('fs');
|
||||
|
||||
const hookPath = resolvePath(__dirname, 'hooks');
|
||||
|
||||
function loadHooks() {
|
||||
mkdirSync(hookPath, { recursive: true });
|
||||
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)));
|
||||
const runHooks = async (event, arg) => {
|
||||
for (let i = 0; i < scriptHooks.length; i++) {
|
||||
const scriptHook = scriptHooks[i];
|
||||
const logName = `[${event}] ${hookScripts[i]}`;
|
||||
let hookFunc;
|
||||
if (typeof scriptHooks === 'function') {
|
||||
hookFunc = scriptHook.bind(null, event);
|
||||
} else {
|
||||
hookFunc = scriptHook[event];
|
||||
}
|
||||
if (hookFunc) {
|
||||
console.time(logName);
|
||||
const result = hookFunc(arg);
|
||||
if (result && result.then) await result;
|
||||
console.timeEnd(logName);
|
||||
}
|
||||
}
|
||||
};
|
||||
return runHooks;
|
||||
}
|
||||
|
||||
module.exports = { loadHooks };
|
@ -1,8 +1,7 @@
|
||||
const { execSync } = require('child_process');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const { ReflectionKind } = require('typedoc');
|
||||
|
||||
const basePath = resolvePath(__dirname, '..', '..');
|
||||
const { git, translatedPath } = require('../utils.js');
|
||||
const { readFileSync, writeFileSync } = require('fs');
|
||||
|
||||
const kindMap = [
|
||||
[ReflectionKind.Enum, 'enums', '枚举', 'enums'],
|
||||
@ -35,10 +34,6 @@ function getReflectionUrl(refl) {
|
||||
return `./${kindInfo.docMapping}/${parts.join('.')}.html`;
|
||||
}
|
||||
|
||||
function git(args) {
|
||||
return execSync(`git ${args}`, { cwd: basePath });
|
||||
}
|
||||
|
||||
function getCurrentHead() {
|
||||
return git('rev-parse --abbrev-ref HEAD').toString('utf-8').trim();
|
||||
}
|
||||
@ -195,6 +190,17 @@ function analyzeTranslateState() {
|
||||
return statusMap;
|
||||
}
|
||||
|
||||
function extractVersionInfo(versionString) {
|
||||
const match = /^([\d.]+-\w+)\.([\d.]+)-(\w+)(\.\d+)?$/.exec(versionString);
|
||||
if (match) {
|
||||
const [, version, gameVersion, gamePreRelease, gameBuild] = match;
|
||||
if (gameBuild) {
|
||||
return { version, gamePreRelease, gameVersion: gameVersion + gameBuild };
|
||||
}
|
||||
return { version, gamePreRelease, gameVersion };
|
||||
}
|
||||
}
|
||||
|
||||
const namespacePrefix = '@minecraft/';
|
||||
const stateDescMap = {
|
||||
untranslated: '未翻译',
|
||||
@ -291,5 +297,29 @@ module.exports = {
|
||||
if (reviewPieces.length > 0) {
|
||||
reviewPieces.forEach((piecePath) => console.log(`[review] Review required: ${piecePath}`));
|
||||
}
|
||||
},
|
||||
afterUpdate({ dependencies }) {
|
||||
const readMePath = resolvePath(translatedPath, 'README.md');
|
||||
const readMe = readFileSync(readMePath, 'utf-8');
|
||||
|
||||
const summaryLines = ['<!-- summary start -->', '', 'NPM 包:', '', '|包名|版本|', '| - | - |'];
|
||||
let gameVersion;
|
||||
Object.entries(dependencies).forEach(([moduleName, version]) => {
|
||||
let versionString = version;
|
||||
const versionInfo = extractVersionInfo(version);
|
||||
if (versionInfo) {
|
||||
if (!gameVersion) gameVersion = versionInfo.gameVersion;
|
||||
versionString = versionInfo.version;
|
||||
}
|
||||
const npmURL = `https://www.npmjs.com/package/${moduleName}`;
|
||||
summaryLines.push(`|[${moduleName}](${npmURL})|\`${versionString}\`|`);
|
||||
});
|
||||
summaryLines.push(['', `游戏版本号:\`${gameVersion}\``, '', '<!-- summary end -->']);
|
||||
|
||||
const newReadMe = readMe.replace(
|
||||
/<!-- summary start -->\n\n[^]+\n\n<!-- summary end -->/,
|
||||
summaryLines.flat().join('\n')
|
||||
);
|
||||
writeFileSync(readMePath, newReadMe);
|
||||
}
|
||||
};
|
||||
|
13
script/hooks/hook.d.ts
vendored
13
script/hooks/hook.d.ts
vendored
@ -3,7 +3,15 @@ import { Application, ProjectReflection } from 'typedoc';
|
||||
|
||||
declare type HookFunction<Context> = (context: Context) => void | Promise<void>;
|
||||
|
||||
declare interface TranslateHookContext {
|
||||
declare interface HookContext {
|
||||
basePath: string;
|
||||
originalPath: string;
|
||||
translatingPath: string;
|
||||
translatedPath: string;
|
||||
distPath: string;
|
||||
}
|
||||
|
||||
declare interface TranslateHookContext extends HookContext {
|
||||
project: Project;
|
||||
sourceFiles: SourceFile[];
|
||||
dependencies: Record<string, string>;
|
||||
@ -18,10 +26,11 @@ declare interface AfterConvertHookContext extends BeforeConvertHookContext {
|
||||
}
|
||||
|
||||
declare interface Hook {
|
||||
beforeLoad?: HookFunction<void>;
|
||||
beforeLoad?: HookFunction<HookContext>;
|
||||
afterLoad?: HookFunction<TranslateHookContext>;
|
||||
afterTranslate?: HookFunction<TranslateHookContext>;
|
||||
beforeConvert?: HookFunction<BeforeConvertHookContext>;
|
||||
afterConvert?: HookFunction<AfterConvertHookContext>;
|
||||
afterEmit?: HookFunction<AfterConvertHookContext>;
|
||||
afterUpdate?: HookFunction<AfterConvertHookContext>;
|
||||
}
|
||||
|
@ -1,11 +1,4 @@
|
||||
const { execSync } = require('child_process');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
|
||||
const basePath = resolvePath(__dirname, '..');
|
||||
|
||||
function git(args) {
|
||||
return execSync(`git ${args}`, { cwd: basePath });
|
||||
}
|
||||
const { git } = require('./utils.js');
|
||||
|
||||
function listTrackingFiles(branch) {
|
||||
const files = {};
|
||||
|
@ -2,10 +2,7 @@ const { SyntaxKind, ts } = require('ts-morph');
|
||||
const { resolve: resolvePath, relative: relativePath, sep: pathSep } = require('path');
|
||||
const { sep: pathSepPosix } = require('path/posix');
|
||||
const { mkdirSync, writeFileSync, existsSync, readFileSync } = require('fs');
|
||||
|
||||
const basePath = resolvePath(__dirname, '..');
|
||||
const translatingPath = resolvePath(basePath, 'translate-pieces');
|
||||
const translatedPath = resolvePath(basePath, 'translated');
|
||||
const { translatingPath, translatedPath } = require('./utils');
|
||||
|
||||
const SkippedTopLevelSyntaxKinds = [
|
||||
SyntaxKind.EndOfFileToken,
|
||||
|
@ -3,26 +3,14 @@ const { readFileSync, writeFileSync, rmSync, existsSync } = require('fs');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const { build } = require('./build.js');
|
||||
const { split, writePiece } = require('./split.js');
|
||||
|
||||
const basePath = resolvePath(__dirname, '..');
|
||||
const originalPath = resolvePath(basePath, 'original');
|
||||
const translatingPath = resolvePath(basePath, 'translate-pieces');
|
||||
const translatedPath = resolvePath(basePath, 'translated');
|
||||
|
||||
function extractVersionInfo(versionString) {
|
||||
const match = /^([\d.]+-\w+)\.([\d.]+)-(\w+)(\.\d+)?$/.exec(versionString);
|
||||
if (match) {
|
||||
const [, version, gameVersion, gamePreRelease, gameBuild] = match;
|
||||
if (gameBuild) {
|
||||
return { version, gamePreRelease, gameVersion: gameVersion + gameBuild };
|
||||
}
|
||||
return { version, gamePreRelease, gameVersion };
|
||||
}
|
||||
}
|
||||
const { loadHooks } = require('./hooks.js');
|
||||
const { basePath, originalPath, translatingPath, translatedPath } = require('./utils');
|
||||
|
||||
const excludedPackages = ['@minecraft/dummy-package', '@minecraft/core-build-tasks', '@minecraft/creator-tools'];
|
||||
|
||||
async function main() {
|
||||
const runHooks = loadHooks();
|
||||
|
||||
// 强制检出 original 分支
|
||||
const head = execSync('git rev-parse --abbrev-ref HEAD', {
|
||||
cwd: basePath
|
||||
@ -61,7 +49,8 @@ async function main() {
|
||||
}
|
||||
|
||||
// 不使用翻译构建项目
|
||||
const { sourceFiles, dependencies } = await build(false);
|
||||
const buildResult = await build(false);
|
||||
const { sourceFiles, dependencies } = buildResult;
|
||||
|
||||
// 检查是否所有包都在依赖中
|
||||
const missingDependencies = onlinePackageNames.filter((packageName) => !(packageName in dependencies));
|
||||
@ -75,30 +64,7 @@ async function main() {
|
||||
const pieces = split(sourceFile);
|
||||
pieces.forEach((piece) => writePiece(sourceFile, piece));
|
||||
});
|
||||
|
||||
// 生成 README.md
|
||||
const readMePath = resolvePath(translatedPath, 'README.md');
|
||||
const readMe = readFileSync(readMePath, 'utf-8');
|
||||
|
||||
const summaryLines = ['<!-- summary start -->', '', 'NPM 包:', '', '|包名|版本|', '| - | - |'];
|
||||
let gameVersion;
|
||||
Object.entries(dependencies).forEach(([moduleName, version]) => {
|
||||
let versionString = version;
|
||||
const versionInfo = extractVersionInfo(version);
|
||||
if (versionInfo) {
|
||||
if (!gameVersion) gameVersion = versionInfo.gameVersion;
|
||||
versionString = versionInfo.version;
|
||||
}
|
||||
const npmURL = `https://www.npmjs.com/package/${moduleName}`;
|
||||
summaryLines.push(`|[${moduleName}](${npmURL})|\`${versionString}\`|`);
|
||||
});
|
||||
summaryLines.push(['', `游戏版本号:\`${gameVersion}\``, '', '<!-- summary end -->']);
|
||||
|
||||
const newReadMe = readMe.replace(
|
||||
/<!-- summary start -->\n\n[^]+\n\n<!-- summary end -->/,
|
||||
summaryLines.flat().join('\n')
|
||||
);
|
||||
writeFileSync(readMePath, newReadMe);
|
||||
await runHooks('afterUpdate', buildResult);
|
||||
|
||||
// 生成 package.json 快照
|
||||
const packageInfo = JSON.parse(readFileSync(packageInfoPath, 'utf-8'));
|
||||
|
21
script/utils.js
Normal file
21
script/utils.js
Normal file
@ -0,0 +1,21 @@
|
||||
const { execSync } = require('child_process');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
|
||||
const basePath = resolvePath(__dirname, '..');
|
||||
const originalPath = resolvePath(basePath, 'original');
|
||||
const translatingPath = resolvePath(basePath, 'translate-pieces');
|
||||
const translatedPath = resolvePath(basePath, 'translated');
|
||||
const distPath = resolvePath(basePath, 'dist');
|
||||
|
||||
function git(args) {
|
||||
return execSync(`git ${args}`, { cwd: basePath });
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
basePath,
|
||||
originalPath,
|
||||
translatingPath,
|
||||
translatedPath,
|
||||
distPath,
|
||||
git
|
||||
};
|
Loading…
Reference in New Issue
Block a user