@jutge.org/toolkit 4.4.27 → 4.4.28
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 +1 -0
- package/dist/index.js +354 -353
- package/docs/problem-anatomy.md +14 -4
- package/package.json +1 -1
- package/toolkit/lint.ts +40 -28
- package/docs/login.md +0 -0
package/docs/problem-anatomy.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Problem anatomy
|
|
1
|
+
# Problem anatomy
|
|
2
2
|
|
|
3
3
|
This document describes the anatomy of a common problem in [Jutge.org](https://jutge.org/). It explains the terminology used, the structure of a problem folder, and the purpose of each file that may be present in it.
|
|
4
4
|
|
|
@@ -87,6 +87,10 @@ The first method is preferred whenever possible, as it avoids duplication of fil
|
|
|
87
87
|
|
|
88
88
|
Problem statements are stored in LaTeX files named `problem.lang.tex`, where `lang` denotes the ISO 639-1 code of the language for which the statement is given (currently `ca`, `en`, `es`, `fr`, `de` for Catalan, English, Spanish, French, and German respectively). Problem statements make use of certain macros.
|
|
89
89
|
|
|
90
|
+
### Demo problem
|
|
91
|
+
|
|
92
|
+
The clonable `demo` problem contains an example of a problem statement with many features that can be used in your own problem statements; see [demo.tex](demo.tex) for examples and inspiration.
|
|
93
|
+
|
|
90
94
|
### Structure
|
|
91
95
|
|
|
92
96
|
The typical structure of a problem statement is the following:
|
|
@@ -293,8 +297,8 @@ If the arguments have not been specified, the default `time_factor` and `time_co
|
|
|
293
297
|
This is an example of how the arguments would look in `handler.yml`:
|
|
294
298
|
|
|
295
299
|
```yml
|
|
296
|
-
time_factor: [2, 10,
|
|
297
|
-
time_constant: [0.1, 0.
|
|
300
|
+
time_factor: [2, 10, 20]
|
|
301
|
+
time_constant: [0.1, 0.5, 1.0]
|
|
298
302
|
```
|
|
299
303
|
|
|
300
304
|
### Advanced: Checkers
|
|
@@ -371,7 +375,7 @@ Unfortunately, the distillation process requires some hand work and is not curre
|
|
|
371
375
|
|
|
372
376
|
### Test options
|
|
373
377
|
|
|
374
|
-
The `test.ops` file can be used to specify some advanced low-level limits for the correction of the corresponding test case. The options should be written as if they were arguments of a program, with a space between each other. The following options are available:
|
|
378
|
+
The `test.ops` file can be used to specify some advanced low-level limits for the correction of the corresponding test case. The options should be written in a line as if they were arguments of a program, with a space between each other. The following options are available:
|
|
375
379
|
|
|
376
380
|
- `--maxtime`: Sets maximum execution time. It has three values: `cputime`, `limtime`, and `clktime`. You can specify only the `cputime`, the `cputime` and the `limtime`, or all of them.
|
|
377
381
|
- `cputime` is the maximum time that the program has to use the CPU (processing instructions).
|
|
@@ -390,6 +394,12 @@ The `test.ops` file can be used to specify some advanced low-level limits for th
|
|
|
390
394
|
|
|
391
395
|
- `--maxcore`: Sets the maximum file size in MB of the core file (generated if the program crashes).
|
|
392
396
|
|
|
397
|
+
Here is an example of a `test.ops` file:
|
|
398
|
+
|
|
399
|
+
```
|
|
400
|
+
--maxtime=10 --maxoutput=5
|
|
401
|
+
```
|
|
402
|
+
|
|
393
403
|
## Solutions
|
|
394
404
|
|
|
395
405
|
Each problem must have one golden solution and may have several alternative solutions in different programming languages. By default, the golden solution is C++, but can be changed in the `handler.yml` file with the `solution` field (e.g., `solution: Python3`).
|
package/package.json
CHANGED
package/toolkit/lint.ts
CHANGED
|
@@ -1,33 +1,46 @@
|
|
|
1
1
|
import { Command } from '@commander-js/extra-typings'
|
|
2
2
|
import chalk from 'chalk'
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from 'path'
|
|
4
|
+
import { lintDirectories, type LintIssue, type LintPassed, type LintResult } from '../lib/lint'
|
|
4
5
|
import tui from '../lib/tui'
|
|
5
|
-
import { nothing } from '../lib/utils'
|
|
6
6
|
|
|
7
7
|
export function formatLintIssue(issue: LintIssue): string {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
8
|
+
// Pad path to 20 spaces, left-aligned file path before the code/info
|
|
9
|
+
const pathPart = issue.path ? chalk.gray(`${issue.path.padEnd(20, ' ')}`) : ' '.repeat(20);
|
|
10
|
+
const prefix = issue.severity === 'error' ? chalk.red('×') : chalk.yellow('⚠️');
|
|
11
|
+
return `${prefix} ${pathPart} ${issue.code}: ${issue.message}`;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
+
export function formatLintPassed(passed: LintPassed): string {
|
|
15
|
+
// Pad path to 20 spaces, left-aligned file path before the code/info
|
|
16
|
+
const pathPart = passed.path ? chalk.gray(`${passed.path.padEnd(20, ' ')}`) : ' '.repeat(20);
|
|
17
|
+
return `${chalk.green('✓')} ${pathPart} ${passed.code}: ${passed.message}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export function printLintResults(
|
|
22
|
+
results: LintResult[],
|
|
23
|
+
directories: string[],
|
|
24
|
+
options?: { verbose?: boolean },
|
|
25
|
+
): { hasError: boolean } {
|
|
26
|
+
const verbose = options?.verbose ?? false
|
|
14
27
|
let hasError = false
|
|
15
28
|
for (const result of results) {
|
|
16
29
|
const errors = result.issues.filter((i) => i.severity === 'error')
|
|
17
30
|
if (errors.length > 0) hasError = true
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
if (verbose && result.passed?.length) {
|
|
33
|
+
for (const p of result.passed) {
|
|
34
|
+
tui.print(formatLintPassed(p))
|
|
35
|
+
}
|
|
36
|
+
}
|
|
21
37
|
if (result.issues.length === 0) {
|
|
22
|
-
tui.
|
|
38
|
+
tui.success(`✅ No issues found in ${tui.hyperlink(resolve(result.directory))}`)
|
|
23
39
|
} else {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
tui.print(formatLintIssue(issue))
|
|
29
|
-
}
|
|
30
|
-
})
|
|
40
|
+
for (const issue of result.issues) {
|
|
41
|
+
tui.print(formatLintIssue(issue))
|
|
42
|
+
}
|
|
43
|
+
tui.error(`❌ ${result.issues.length} issue(s) found in ${tui.hyperlink(resolve(result.directory))}`)
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
46
|
|
|
@@ -46,18 +59,17 @@ export async function printLintResults(results: LintResult[], directories: strin
|
|
|
46
59
|
export const lintCmd = new Command('lint')
|
|
47
60
|
.summary('Lint a problem directory')
|
|
48
61
|
|
|
49
|
-
.
|
|
62
|
+
.option('-d, --directory <directory>', 'problem directory', '.')
|
|
63
|
+
.option('-v, --verbose', 'show all validations, including passed checks')
|
|
50
64
|
|
|
51
|
-
.action(async (directory
|
|
52
|
-
const results = await lintDirectories([directory])
|
|
65
|
+
.action(async ({ directory, verbose }) => {
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
67
|
+
await tui.section(`Linting ${tui.hyperlink(resolve(directory))}`, async () => {
|
|
68
|
+
const results = await lintDirectories([directory], { verbose })
|
|
69
|
+
if (results.length === 0) throw new Error('No problem directories found (looked for handler.yml in the given path(s)).')
|
|
70
|
+
const { hasError } = printLintResults(results, [directory], { verbose })
|
|
71
|
+
if (hasError) {
|
|
72
|
+
process.exitCode = 1
|
|
73
|
+
}
|
|
74
|
+
})
|
|
63
75
|
})
|
package/docs/login.md
DELETED
|
File without changes
|