-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate.js
136 lines (123 loc) · 3.95 KB
/
generate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// @ts-check
import 'zx/globals'
import { parse, stringify } from 'yaml'
import consola from 'consola'
/**
* @param {string} code
* @returns {{ template: string, ojMerge: boolean }}
*/
function extractTemplate(code) {
const lines = code.split('\n')
let parsing = false
let ojMerge = false
/** @type {string[]} */
const result = []
for (const line of lines) {
if (line === '#![cfg(not(oj_no_merge))]') {
ojMerge = true
}
if (!parsing && line === '/// ```no_run') {
parsing = true
continue
}
if (parsing && line === '/// ```') {
parsing = false
result.push('')
continue
}
if (parsing) {
result.push(line.slice(4).trimEnd())
}
}
if (result.length === 0) {
consola.fatal('No template found')
process.exit(1)
}
return {
template: result.join('\n').trimEnd() + '\n',
ojMerge
}
}
const mappings = parse(await fs.readFile(path.join(__dirname, 'mappings.yml'), 'utf8'))
/** @type {string} */
const name = argv.name
if (!name) {
consola.fatal('Name is required')
process.exit(1)
}
if (!mappings[name]) {
consola.fatal(`No mapping found for ${name}`)
process.exit(1)
}
const source = path.join(__dirname, 'src', 'bin', `${name}.rs`)
if (!(await fs.exists(source))) {
consola.fatal(`No source found for ${name}`)
process.exit(1)
}
const data = path.join(__dirname, 'fixtures', name)
if (!(await fs.exists(data))) {
consola.fatal(`No data found for ${name}`)
process.exit(1)
}
await $`rm -rf ${__dirname}/build/${name}`
await $`mkdir -p ${__dirname}/build/${name}`
await $`cp -r ${__dirname}/fixtures/common ${__dirname}/build/${name}/data`
await $`cp -r ${data}/* ${__dirname}/build/${name}/data`
await $`cp ${source} ${__dirname}/build/${name}/main.rs`
const problemConfig = parse(await fs.readFile(path.join(__dirname, 'problem.yml'), 'utf8'))
const code = await fs.readFile(source, 'utf8')
const { template, ojMerge: ojMergeInCode } = extractTemplate(code)
// Check if the .oj-merge file exists
const ojMergeFilePath = path.join(__dirname, 'fixtures', name, '.oj-merge')
const ojMergeInData = await fs.exists(ojMergeFilePath)
const ojMerge = ojMergeInCode || ojMergeInData
if (ojMerge) {
consola.info(`Merging enabled for ${name}`)
// Create the .oj-merge file in the data directory
await $`touch ${__dirname}/build/${name}/data/.oj-merge`
// Copy the source file to .source.rs in the data directory
const mergeSourcePath = path.join(__dirname, 'fixtures', name, '.source.rs')
if (!(await fs.exists(mergeSourcePath))) {
await $`cp ${source} ${__dirname}/build/${name}/data/.source.rs`
}
}
if (template) {
if (template.includes('// FIX ME')) {
await fs.writeFile(path.join(__dirname, 'build', name, 'data', 'template.rs'), template)
problemConfig.submit.form.files[0].description =
'注意:只允许修改标有 `// FIX ME` 的行,否则直接计0分。'
} else {
problemConfig.submit.form.files[0].description = '请基于如下Rust代码模板修改并提交。'
}
if (ojMerge) {
problemConfig.submit.form.files[0].description +=
'\n注意:本题另包含未公开的评测代码,且保留 `judge` 模块。你的作答将会被拼接在评测代码之后。'
}
problemConfig.submit.form.files[0].default = template
}
await fs.writeFile(path.join(__dirname, 'build', name, 'problem.yml'), stringify(problemConfig))
const statement = code
.split('\n')
.filter((line) => line.startsWith('///'))
.map((line) => line.slice(4))
.join('\n')
.replace(/```no_run/g, '```rust')
const title = name
.split('_')
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(' ')
const md = `---
title: ${title}
tags:
- Rust
---
# ${title}
${statement}`
await fs.writeFile(path.join(__dirname, 'build', name, 'statement.md'), md)
const aoiConfig = `
type: "problem"
server: hpcgame
problemId: ${mappings[name]}
`
await fs.writeFile(path.join(__dirname, 'build', name, 'aoi.config.yml'), aoiConfig)
consola.success(`Generated ${name}`)