@jutge.org/toolkit 4.4.27 → 4.4.29

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.
@@ -1,4 +1,4 @@
1
- # Problem anatomy (WORK IN PROGRESS)
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](../assets/problems/demo/demo.pbm/problem.en.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, 2]
297
- time_constant: [0.1, 0.01, 0.05]
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jutge.org/toolkit",
3
3
  "description": "Toolkit to prepare problems for Jutge.org",
4
- "version": "4.4.27",
4
+ "version": "4.4.29",
5
5
  "homepage": "https://jutge.org",
6
6
  "author": {
7
7
  "name": "Jutge.org",
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 { lintDirectories, type LintIssue, type LintResult } from '../lib/lint'
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
- const prefix = issue.severity === 'error' ? chalk.red('error') : chalk.yellow('warning')
9
- const path = issue.path ? chalk.gray(` (${issue.path})`) : ''
10
- return ` ${prefix} ${issue.code}: ${issue.message}${path}`
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 async function printLintResults(results: LintResult[], directories: string[]): Promise<{ hasError: boolean }> {
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
- const dirLabel =
20
- result.directory === directories[0] && results.length === 1 ? result.directory : result.directory
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.print(chalk.green('✓') + ' ' + dirLabel + ' ' + chalk.gray('— no issues'))
38
+ tui.success(`✅ No issues found in ${tui.hyperlink(resolve(result.directory))}`)
23
39
  } else {
24
- tui.print()
25
- await tui.section(`Linting ${dirLabel}`, async () => {
26
- await nothing()
27
- for (const issue of result.issues) {
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
- .argument('[directory]', 'problem directory to lint', '.')
62
+ .option('-d, --directory <directory>', 'problem directory', '.')
63
+ .option('-v, --verbose', 'show all validations, including passed checks')
50
64
 
51
- .action(async (directory: string) => {
52
- const results = await lintDirectories([directory])
65
+ .action(async ({ directory, verbose }) => {
53
66
 
54
- if (results.length === 0) {
55
- tui.warning('No problem directories found (looked for handler.yml in the given path(s)).')
56
- return
57
- }
58
-
59
- const { hasError } = await printLintResults(results, [directory])
60
- if (hasError) {
61
- process.exitCode = 1
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