oicontest
Version:
OI Contest Management Tool
181 lines (180 loc) • 7.75 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTemplate = getTemplate;
exports.writeFileWithDir = writeFileWithDir;
exports.readYaml = readYaml;
exports.writeYaml = writeYaml;
exports.checkFileExists = checkFileExists;
exports.countSubdirectories = countSubdirectories;
exports.loadJsonFile = loadJsonFile;
exports.verifyProblems = verifyProblems;
exports.contestInfoToMarkdown = contestInfoToMarkdown;
const js_yaml_1 = __importDefault(require("js-yaml"));
const mkdirp_1 = require("mkdirp");
const chalk_1 = __importDefault(require("chalk"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const handleMardown_1 = require("./handleMardown");
//@ts-ignore
const path = require("path");
// 获取模板内容
function getTemplate(templateDir, templateName) {
return fs_extra_1.default.readFileSync(path.join(templateDir, templateName), "utf-8");
}
// 写入文件,如果目录不存在则创建
function writeFileWithDir(filePath, content) {
const dir = path.dirname(filePath);
if (!fs_extra_1.default.existsSync(dir)) {
mkdirp_1.mkdirp.sync(dir);
}
fs_extra_1.default.writeFileSync(filePath, content);
}
// 读取 YAML 文件
function readYaml(filePath) {
try {
return js_yaml_1.default.load(fs_extra_1.default.readFileSync(filePath, "utf-8"));
}
catch (e) {
console.error(chalk_1.default.red(`Error reading YAML file ${filePath}: ${e.message}`));
return null;
}
}
// 写入 YAML 文件
function writeYaml(filePath, data) {
writeFileWithDir(filePath, js_yaml_1.default.dump(data));
}
// 检查文件是否存在
function checkFileExists(filePath) {
return fs_extra_1.default.existsSync(filePath);
}
function countSubdirectories(directoryPath) {
return __awaiter(this, void 0, void 0, function* () {
try {
const items = yield fs_extra_1.default.readdir(directoryPath);
let subdirCount = 0;
// 并行检查所有项目
const results = yield Promise.all(items.map((item) => __awaiter(this, void 0, void 0, function* () {
const fullPath = path.join(directoryPath, item);
const stats = yield fs_extra_1.default.stat(fullPath);
return stats.isDirectory();
})));
// 统计目录数量
results.forEach(isDirectory => {
if (isDirectory)
subdirCount++;
});
return subdirCount;
}
catch (error) {
console.error(`无法读取目录: ${directoryPath}`, error);
return -1;
}
});
}
function loadJsonFile(filePath) {
return __awaiter(this, void 0, void 0, function* () {
if (!fs_extra_1.default.existsSync(filePath)) {
throw new Error(`JSON file not found. Are you in a contest directory?`);
}
return fs_extra_1.default.readJSON(filePath);
});
}
function verifyProblems(problemDir) {
return __awaiter(this, void 0, void 0, function* () {
//验证题目
//1.读取各题目的status.json,返回已经验证的数量
const items = yield fs_extra_1.default.readdir(problemDir);
console.error(items);
let verifiedCount = 0;
// 并行检查所有项目
const results = yield Promise.all(items.map((item) => __awaiter(this, void 0, void 0, function* () {
const fullPath = path.join(problemDir, item, "status.json");
console.error(fullPath);
return fullPath;
})));
// 统计数量
// 由于 loadJsonFile 是异步函数,需要使用 await
// 因为 forEach 不支持 await,改用 for...of 循环
for (const fullPath of results) {
try {
const status = yield loadJsonFile(fullPath);
if (status.ischecked && status.ischecked.status)
verifiedCount++;
}
catch (err) {
// 可以选择忽略错误或记录日志
console.error(`Error loading ${fullPath}:`, err);
}
}
return verifiedCount;
});
}
function contestInfoToMarkdown(config) {
return __awaiter(this, void 0, void 0, function* () {
const contestDir = process.cwd();
//先将contest信息转换成markdown格式
if (config.problems.length === 0) {
console.error(chalk_1.default.red('Error: No problems added to contest'));
process.exit(1);
}
let mdContent = "";
//add title
let mdTitle = "# " + config.description + '\n\n' + `开始时间: ${config.startTime.padEnd(20)}` +
`时长: ${(config.duration.toString() + '分钟').padEnd(10)}` +
`题目数量: ${config.problems.length} 题`;
const headers = ['题目名称', '提交目录', "提交源程序名", '输入文件名', '输出文件名', '时间限制', '内存限制', '分值'];
let mdProblemsTable = "\n|";
for (const s of headers)
mdProblemsTable += s + "|";
mdProblemsTable += "\n|";
headers.forEach(() => {
mdProblemsTable += "---|";
});
for (const problem of config.problems) {
const values = [
problem.title,
problem.id,
problem.id + ".cpp",
problem.id + ".in",
problem.id + ".out",
problem.timeLimit.toString() + 'ms',
problem.memoryLimit.toString() + 'MB',
problem.maxScore.toString(),
];
mdProblemsTable += "\n|";
values.forEach((s) => {
mdProblemsTable += s + "|";
});
}
//加入注意事项
const notice = yield fs_extra_1.default.readFile(path.join(__dirname, "../templates", "notice.md"));
mdContent = "\n" + notice + "\n\n";
for (const p of config.problems) {
let mdfile = path.resolve(contestDir, "problem", p.id, "problem.md");
if (!fs_extra_1.default.existsSync(mdfile))
mdfile = path.resolve(contestDir, "problem", p.id, "problem_zh.md");
if (!fs_extra_1.default.existsSync(mdfile)) {
console.error(chalk_1.default.red(`题目文件${mdfile}未找到!`));
process.exit(1);
}
const problemConfig = yield fs_extra_1.default.readJSON(path.join(contestDir, "problem", p.id, "config.json"));
mdContent = mdContent + "\n-----------------\n\n# " + problemConfig.title + "\n\n";
//将里面的所有图片转换成绝对路径
mdContent += yield (0, handleMardown_1.convertMarkdownImagePaths)(mdfile);
}
const mdAll = mdTitle + "\n" + mdProblemsTable + mdContent;
//转换成html
return mdAll;
});
}