@exercode/problem-utils 1.19.0 → 2.0.0
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 +8 -8
- package/bin/exercode-problem.mjs +2 -0
- package/dist/cli/exercodeProblem.cjs +9 -0
- package/dist/cli/exercodeProblem.cjs.map +1 -0
- package/dist/cli/exercodeProblem.js +9 -0
- package/dist/cli/exercodeProblem.js.map +1 -0
- package/dist/cli/runSingleHarness.cjs +1 -1
- package/dist/cli/runSingleHarness.cjs.map +1 -1
- package/dist/cli/runSingleHarness.js +1 -1
- package/dist/cli/runSingleHarness.js.map +1 -1
- package/dist/helpers/removeCommentsInSourceCode.cjs +6 -5
- package/dist/helpers/removeCommentsInSourceCode.cjs.map +1 -1
- package/dist/helpers/removeCommentsInSourceCode.js +6 -5
- package/dist/helpers/removeCommentsInSourceCode.js.map +1 -1
- package/dist/presets/stdio.cjs.map +1 -1
- package/dist/presets/stdio.d.ts +3 -3
- package/dist/presets/stdio.js.map +1 -1
- package/dist/types/language.cjs +1 -1
- package/dist/types/language.cjs.map +1 -1
- package/dist/types/language.d.ts +1 -0
- package/dist/types/language.js +1 -1
- package/dist/types/language.js.map +1 -1
- package/package.json +2 -2
- package/bin/exercode.mjs +0 -2
- package/dist/cli/exercode.cjs +0 -9
- package/dist/cli/exercode.cjs.map +0 -1
- package/dist/cli/exercode.js +0 -9
- package/dist/cli/exercode.js.map +0 -1
- /package/dist/cli/{exercode.d.ts → exercodeProblem.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -8,24 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
## CLI
|
|
10
10
|
|
|
11
|
-
The package ships an `exercode` command for problem authors (run it with `bun x` in a repository that depends on `@exercode/problem-utils`):
|
|
11
|
+
The package ships an `exercode-problem` command for problem authors (run it with `bun x` in a repository that depends on `@exercode/problem-utils`):
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
# Judge all model answers of all problems (directories containing problem.md or <id>.problem.md) under a directory.
|
|
15
15
|
# model_answers/* must be fully accepted; model_answers.fails/* must fail at least one test case.
|
|
16
|
-
bun x exercode # everything under the current directory
|
|
17
|
-
bun x exercode courses/foo # everything under courses/foo
|
|
18
|
-
bun x exercode --only a_plus --skip gui_ --concurrency 2
|
|
16
|
+
bun x exercode-problem # everything under the current directory
|
|
17
|
+
bun x exercode-problem courses/foo # everything under courses/foo
|
|
18
|
+
bun x exercode-problem --only a_plus --skip gui_ --concurrency 2
|
|
19
19
|
|
|
20
20
|
# Judge one answer directory of the problem in the current directory.
|
|
21
|
-
bun x exercode judge model_answers/python
|
|
22
|
-
bun x exercode judge model_answers/python '{ "language": "python" }'
|
|
21
|
+
bun x exercode-problem judge model_answers/python
|
|
22
|
+
bun x exercode-problem judge model_answers/python '{ "language": "python" }'
|
|
23
23
|
|
|
24
24
|
# Debug one answer directory of the problem in the current directory.
|
|
25
|
-
bun x exercode debug model_answers/python '{ "stdin": "1 2" }'
|
|
25
|
+
bun x exercode-problem debug model_answers/python '{ "stdin": "1 2" }'
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
`judge` and `debug` run a custom `judge.ts` / `debug.ts` when the problem has one, and apply `stdioJudgePreset` / `stdioDebugPreset` otherwise, mirroring the Exercode server. The debug fallback applies only to standard problems: a problem with a custom `judge.ts` needs its own `debug.ts`, and `exercode debug` fails with a message otherwise (the server likewise reports debug as unsupported there).
|
|
28
|
+
`judge` and `debug` run a custom `judge.ts` / `debug.ts` when the problem has one, and apply `stdioJudgePreset` / `stdioDebugPreset` otherwise, mirroring the Exercode server. The debug fallback applies only to standard problems: a problem with a custom `judge.ts` needs its own `debug.ts`, and `exercode-problem debug` fails with a message otherwise (the server likewise reports debug as unsupported there).
|
|
29
29
|
|
|
30
30
|
The all-problem check judges serially by default because time limits are measured in wall-clock time; pass `--concurrency <n>` to parallelize when the checked problems are not timing-sensitive.
|
|
31
31
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";const e=require("./runSingleHarness.cjs"),t=require("./checkAllProblems.cjs"),n=`Usage: exercode-problem [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]
|
|
2
|
+
exercode-problem judge <answerDir> [paramsJson]
|
|
3
|
+
exercode-problem debug <answerDir> [paramsJson]
|
|
4
|
+
|
|
5
|
+
Without a subcommand, judge all model answers of all problems under rootDir
|
|
6
|
+
(default: the current directory). Use \`judge\` or \`debug\` in a problem
|
|
7
|
+
directory to run one answer directory, e.g.:
|
|
8
|
+
exercode-problem debug model_answers/python '{ "stdin": "1 2" }'`;r();async function r(){let r=process.argv.slice(2);if(r[0]===`--help`||r[0]===`-h`){console.info(n);return}try{if(r[0]===`judge`||r[0]===`debug`){if(r.length<2){console.error(n),process.exitCode=1;return}process.argv.splice(2,1),process.exitCode=await e.runSingleHarness(r[0])}else process.exitCode=await t.checkAllProblems(r)}catch(e){console.error(e),process.exitCode=1}}
|
|
9
|
+
//# sourceMappingURL=exercodeProblem.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exercodeProblem.cjs","names":["runSingleHarness","checkAllProblems"],"sources":["../../src/cli/exercodeProblem.ts"],"sourcesContent":["import { checkAllProblems } from './checkAllProblems.js';\nimport { runSingleHarness } from './runSingleHarness.js';\n\nconst usage = `Usage: exercode-problem [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]\n exercode-problem judge <answerDir> [paramsJson]\n exercode-problem debug <answerDir> [paramsJson]\n\nWithout a subcommand, judge all model answers of all problems under rootDir\n(default: the current directory). Use \\`judge\\` or \\`debug\\` in a problem\ndirectory to run one answer directory, e.g.:\n exercode-problem debug model_answers/python '{ \"stdin\": \"1 2\" }'`;\n\n// oxlint-disable-next-line unicorn/prefer-top-level-await -- the CJS build output does not support top-level await\nvoid main();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n if (args[0] === '--help' || args[0] === '-h') {\n // console.log would be stripped from the built CLI, so print the usage with console.info.\n console.info(usage);\n return;\n }\n try {\n if (args[0] === 'judge' || args[0] === 'debug') {\n if (args.length < 2) {\n console.error(usage);\n process.exitCode = 1;\n return;\n }\n // Harness scripts and presets read the answer directory and params from fixed positions in\n // `process.argv`, so drop the subcommand to restore those positions.\n process.argv.splice(2, 1);\n process.exitCode = await runSingleHarness(args[0]);\n } else {\n process.exitCode = await checkAllProblems(args);\n }\n } catch (error) {\n // Print the whole error: harness failures need their stack and `cause`, not just the message.\n console.error(error);\n process.exitCode = 1;\n }\n}\n"],"mappings":"2FAGM,EAAQ;;;;;;;oEAUT,EAAK,EAEV,eAAe,GAAsB,CACnC,IAAM,EAAO,QAAQ,KAAK,MAAM,CAAC,EACjC,GAAI,EAAK,KAAO,UAAY,EAAK,KAAO,KAAM,CAE5C,QAAQ,KAAK,CAAK,EAClB,MACF,CACA,GAAI,CACF,GAAI,EAAK,KAAO,SAAW,EAAK,KAAO,QAAS,CAC9C,GAAI,EAAK,OAAS,EAAG,CACnB,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,EACnB,MACF,CAGA,QAAQ,KAAK,OAAO,EAAG,CAAC,EACxB,QAAQ,SAAW,MAAMA,EAAAA,iBAAiB,EAAK,EAAE,CACnD,KACE,SAAQ,SAAW,MAAMC,EAAAA,iBAAiB,CAAI,CAElD,OAAS,EAAO,CAEd,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,CACrB,CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{runSingleHarness as e}from"./runSingleHarness.js";import{checkAllProblems as t}from"./checkAllProblems.js";const n=`Usage: exercode-problem [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]
|
|
2
|
+
exercode-problem judge <answerDir> [paramsJson]
|
|
3
|
+
exercode-problem debug <answerDir> [paramsJson]
|
|
4
|
+
|
|
5
|
+
Without a subcommand, judge all model answers of all problems under rootDir
|
|
6
|
+
(default: the current directory). Use \`judge\` or \`debug\` in a problem
|
|
7
|
+
directory to run one answer directory, e.g.:
|
|
8
|
+
exercode-problem debug model_answers/python '{ "stdin": "1 2" }'`;r();async function r(){let r=process.argv.slice(2);if(r[0]===`--help`||r[0]===`-h`){console.info(n);return}try{if(r[0]===`judge`||r[0]===`debug`){if(r.length<2){console.error(n),process.exitCode=1;return}process.argv.splice(2,1),process.exitCode=await e(r[0])}else process.exitCode=await t(r)}catch(e){console.error(e),process.exitCode=1}}
|
|
9
|
+
//# sourceMappingURL=exercodeProblem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exercodeProblem.js","names":[],"sources":["../../src/cli/exercodeProblem.ts"],"sourcesContent":["import { checkAllProblems } from './checkAllProblems.js';\nimport { runSingleHarness } from './runSingleHarness.js';\n\nconst usage = `Usage: exercode-problem [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]\n exercode-problem judge <answerDir> [paramsJson]\n exercode-problem debug <answerDir> [paramsJson]\n\nWithout a subcommand, judge all model answers of all problems under rootDir\n(default: the current directory). Use \\`judge\\` or \\`debug\\` in a problem\ndirectory to run one answer directory, e.g.:\n exercode-problem debug model_answers/python '{ \"stdin\": \"1 2\" }'`;\n\n// oxlint-disable-next-line unicorn/prefer-top-level-await -- the CJS build output does not support top-level await\nvoid main();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n if (args[0] === '--help' || args[0] === '-h') {\n // console.log would be stripped from the built CLI, so print the usage with console.info.\n console.info(usage);\n return;\n }\n try {\n if (args[0] === 'judge' || args[0] === 'debug') {\n if (args.length < 2) {\n console.error(usage);\n process.exitCode = 1;\n return;\n }\n // Harness scripts and presets read the answer directory and params from fixed positions in\n // `process.argv`, so drop the subcommand to restore those positions.\n process.argv.splice(2, 1);\n process.exitCode = await runSingleHarness(args[0]);\n } else {\n process.exitCode = await checkAllProblems(args);\n }\n } catch (error) {\n // Print the whole error: harness failures need their stack and `cause`, not just the message.\n console.error(error);\n process.exitCode = 1;\n }\n}\n"],"mappings":"kHAGA,MAAM,EAAQ;;;;;;;oEAUT,EAAK,EAEV,eAAe,GAAsB,CACnC,IAAM,EAAO,QAAQ,KAAK,MAAM,CAAC,EACjC,GAAI,EAAK,KAAO,UAAY,EAAK,KAAO,KAAM,CAE5C,QAAQ,KAAK,CAAK,EAClB,MACF,CACA,GAAI,CACF,GAAI,EAAK,KAAO,SAAW,EAAK,KAAO,QAAS,CAC9C,GAAI,EAAK,OAAS,EAAG,CACnB,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,EACnB,MACF,CAGA,QAAQ,KAAK,OAAO,EAAG,CAAC,EACxB,QAAQ,SAAW,MAAM,EAAiB,EAAK,EAAE,CACnD,KACE,SAAQ,SAAW,MAAM,EAAiB,CAAI,CAElD,OAAS,EAAO,CAEd,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,CACrB,CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../helpers/defaultStdioHarness.cjs"),n=require("../helpers/readProblemMarkdownFrontMatter.cjs"),r=require("../helpers/readTestCases.cjs"),i=require("../presets/stdio.cjs");let a=require("node:path");a=e.__toESM(a,1);let o=require("node:child_process");o=e.__toESM(o,1);let s=require("node:fs");s=e.__toESM(s,1);const c=`a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired`;async function l(e){let l=process.cwd(),d=await t.findDefaultStdioHarnessFiles(l);if(d.length>0)return console.error(u(d)),1;let f=e===`judge`?`judge.ts`:`debug.ts`;if(s.default.existsSync(a.default.join(l,f))){let e=o.default.spawnSync(process.execPath,[`run`,f,...process.argv.slice(2)],{cwd:l,stdio:`inherit`});return e.error?(console.error(`failed to run ${f}: ${e.error.message}`),1):e.status??1}return e===`debug`&&s.default.existsSync(a.default.join(l,`judge.ts`))?(console.error(`This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.`),1):e===`judge`&&(await r.readTestCases(a.default.join(l,`test_cases`))).length===0&&!n.judgesWithoutTestCases(await n.readProblemMarkdownFrontMatter(l))?(console.error(c),1):(await(e===`judge`?i.stdioJudgePreset(l):i.stdioDebugPreset(l)),0)}function u(e){let t=e.join(` and `);return`${t} must not be committed because the content is identical to the default stdio harness.
|
|
2
2
|
A problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,
|
|
3
|
-
so delete ${t} and run the problem with \`bun x exercode judge <answerDir>\` or \`bun x exercode debug <answerDir>\`.
|
|
3
|
+
so delete ${t} and run the problem with \`bun x exercode-problem judge <answerDir>\` or \`bun x exercode-problem debug <answerDir>\`.
|
|
4
4
|
If the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`}exports.MISSING_TEST_CASES_ERROR=c,exports.formatDefaultHarnessError=u,exports.runSingleHarness=l;
|
|
5
5
|
//# sourceMappingURL=runSingleHarness.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runSingleHarness.cjs","names":["findDefaultStdioHarnessFiles","fs","path","child_process","readTestCases","judgesWithoutTestCases","readProblemMarkdownFrontMatter","stdioJudgePreset","stdioDebugPreset"],"sources":["../../src/cli/runSingleHarness.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { stdioDebugPreset, stdioJudgePreset } from '../presets/stdio.js';\n\nexport const MISSING_TEST_CASES_ERROR =\n 'a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired';\n\n/**\n * Run the judge or debug harness of the problem in the current working directory: a custom\n * `judge.ts` / `debug.ts` when present, or the default stdio preset otherwise (mirroring the\n * Exercode server, which applies the stdio presets to problems without these files).\n */\nexport async function runSingleHarness(kind: 'judge' | 'debug'): Promise<number> {\n const problemDir = process.cwd();\n\n const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n if (defaultHarnessFileNames.length > 0) {\n console.error(formatDefaultHarnessError(defaultHarnessFileNames));\n return 1;\n }\n\n const harnessFileName = kind === 'judge' ? 'judge.ts' : 'debug.ts';\n if (fs.existsSync(path.join(problemDir, harnessFileName))) {\n // process.execPath keeps the harness on the same bun executable regardless of PATH.\n const spawnResult = child_process.spawnSync(process.execPath, ['run', harnessFileName, ...process.argv.slice(2)], {\n cwd: problemDir,\n stdio: 'inherit',\n });\n if (spawnResult.error) {\n console.error(`failed to run ${harnessFileName}: ${spawnResult.error.message}`);\n return 1;\n }\n return spawnResult.status ?? 1;\n }\n\n // A custom judge.ts marks the problem as non-standard, so the stdio debug preset would judge the\n // answer against a contract the problem does not have (mirroring the server, which reports debug\n // as unsupported in this case).\n if (kind === 'debug' && fs.existsSync(path.join(problemDir, 'judge.ts'))) {\n console.error('This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.');\n return 1;\n }\n\n // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n // unless static-analysis rules or manual scoring make the problem judgeable without them.\n if (kind === 'judge') {\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n if (testCases.length === 0 && !judgesWithoutTestCases(await readProblemMarkdownFrontMatter(problemDir))) {\n console.error(MISSING_TEST_CASES_ERROR);\n return 1;\n }\n }\n\n // The presets read the answer directory and params from `process.argv`, which holds them at the\n // same positions as when a harness script is invoked directly.\n await (kind === 'judge' ? stdioJudgePreset(problemDir) : stdioDebugPreset(problemDir));\n return 0;\n}\n\nexport function formatDefaultHarnessError(defaultHarnessFileNames: readonly string[]): string {\n const fileNames = defaultHarnessFileNames.join(' and ');\n return `${fileNames} must not be committed because the content is identical to the default stdio harness.\nA problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,\nso delete ${fileNames} and run the problem with \\`bun x exercode judge <answerDir>\\` or \\`bun x exercode debug <answerDir>\\`.\nIf the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`;\n}\n"],"mappings":"ucASA,MAAa,EACX,6KAOF,eAAsB,EAAiB,EAA0C,CAC/E,IAAM,EAAa,QAAQ,IAAI,EAEzB,EAA0B,MAAMA,EAAAA,6BAA6B,CAAU,EAC7E,GAAI,EAAwB,OAAS,EAEnC,OADA,QAAQ,MAAM,EAA0B,CAAuB,CAAC,EACzD,EAGT,IAAM,EAAkB,IAAS,QAAU,WAAa,WACxD,GAAIC,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,CAAe,CAAC,EAAG,CAEzD,IAAM,EAAcC,EAAAA,QAAc,UAAU,QAAQ,SAAU,CAAC,MAAO,EAAiB,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAG,CAChH,IAAK,EACL,MAAO,SACT,CAAC,EAKD,OAJI,EAAY,OACd,QAAQ,MAAM,iBAAiB,EAAgB,IAAI,EAAY,MAAM,SAAS,EACvE,GAEF,EAAY,QAAU,CAC/B,CAwBA,OAnBI,IAAS,SAAWF,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,UAAU,CAAC,GACrE,QAAQ,MAAM,0FAA0F,EACjG,GAML,IAAS,UAEP,MADoBE,EAAAA,cAAcF,EAAAA,QAAK,KAAK,EAAY,YAAY,CAAC,EAAA,CAC3D,SAAW,GAAK,CAACG,EAAAA,uBAAuB,MAAMC,EAAAA,+BAA+B,CAAU,CAAC,GACpG,QAAQ,MAAM,CAAwB,EAC/B,IAMX,MAAO,IAAS,QAAUC,EAAAA,iBAAiB,CAAU,EAAIC,EAAAA,iBAAiB,CAAU,GAC7E,EACT,CAEA,SAAgB,EAA0B,EAAoD,CAC5F,IAAM,EAAY,EAAwB,KAAK,OAAO,EACtD,MAAO,GAAG,EAAU;;YAEV,EAAU;6GAEtB"}
|
|
1
|
+
{"version":3,"file":"runSingleHarness.cjs","names":["findDefaultStdioHarnessFiles","fs","path","child_process","readTestCases","judgesWithoutTestCases","readProblemMarkdownFrontMatter","stdioJudgePreset","stdioDebugPreset"],"sources":["../../src/cli/runSingleHarness.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { stdioDebugPreset, stdioJudgePreset } from '../presets/stdio.js';\n\nexport const MISSING_TEST_CASES_ERROR =\n 'a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired';\n\n/**\n * Run the judge or debug harness of the problem in the current working directory: a custom\n * `judge.ts` / `debug.ts` when present, or the default stdio preset otherwise (mirroring the\n * Exercode server, which applies the stdio presets to problems without these files).\n */\nexport async function runSingleHarness(kind: 'judge' | 'debug'): Promise<number> {\n const problemDir = process.cwd();\n\n const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n if (defaultHarnessFileNames.length > 0) {\n console.error(formatDefaultHarnessError(defaultHarnessFileNames));\n return 1;\n }\n\n const harnessFileName = kind === 'judge' ? 'judge.ts' : 'debug.ts';\n if (fs.existsSync(path.join(problemDir, harnessFileName))) {\n // process.execPath keeps the harness on the same bun executable regardless of PATH.\n const spawnResult = child_process.spawnSync(process.execPath, ['run', harnessFileName, ...process.argv.slice(2)], {\n cwd: problemDir,\n stdio: 'inherit',\n });\n if (spawnResult.error) {\n console.error(`failed to run ${harnessFileName}: ${spawnResult.error.message}`);\n return 1;\n }\n return spawnResult.status ?? 1;\n }\n\n // A custom judge.ts marks the problem as non-standard, so the stdio debug preset would judge the\n // answer against a contract the problem does not have (mirroring the server, which reports debug\n // as unsupported in this case).\n if (kind === 'debug' && fs.existsSync(path.join(problemDir, 'judge.ts'))) {\n console.error('This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.');\n return 1;\n }\n\n // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n // unless static-analysis rules or manual scoring make the problem judgeable without them.\n if (kind === 'judge') {\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n if (testCases.length === 0 && !judgesWithoutTestCases(await readProblemMarkdownFrontMatter(problemDir))) {\n console.error(MISSING_TEST_CASES_ERROR);\n return 1;\n }\n }\n\n // The presets read the answer directory and params from `process.argv`, which holds them at the\n // same positions as when a harness script is invoked directly.\n await (kind === 'judge' ? stdioJudgePreset(problemDir) : stdioDebugPreset(problemDir));\n return 0;\n}\n\nexport function formatDefaultHarnessError(defaultHarnessFileNames: readonly string[]): string {\n const fileNames = defaultHarnessFileNames.join(' and ');\n return `${fileNames} must not be committed because the content is identical to the default stdio harness.\nA problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,\nso delete ${fileNames} and run the problem with \\`bun x exercode-problem judge <answerDir>\\` or \\`bun x exercode-problem debug <answerDir>\\`.\nIf the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`;\n}\n"],"mappings":"ucASA,MAAa,EACX,6KAOF,eAAsB,EAAiB,EAA0C,CAC/E,IAAM,EAAa,QAAQ,IAAI,EAEzB,EAA0B,MAAMA,EAAAA,6BAA6B,CAAU,EAC7E,GAAI,EAAwB,OAAS,EAEnC,OADA,QAAQ,MAAM,EAA0B,CAAuB,CAAC,EACzD,EAGT,IAAM,EAAkB,IAAS,QAAU,WAAa,WACxD,GAAIC,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,CAAe,CAAC,EAAG,CAEzD,IAAM,EAAcC,EAAAA,QAAc,UAAU,QAAQ,SAAU,CAAC,MAAO,EAAiB,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAG,CAChH,IAAK,EACL,MAAO,SACT,CAAC,EAKD,OAJI,EAAY,OACd,QAAQ,MAAM,iBAAiB,EAAgB,IAAI,EAAY,MAAM,SAAS,EACvE,GAEF,EAAY,QAAU,CAC/B,CAwBA,OAnBI,IAAS,SAAWF,EAAAA,QAAG,WAAWC,EAAAA,QAAK,KAAK,EAAY,UAAU,CAAC,GACrE,QAAQ,MAAM,0FAA0F,EACjG,GAML,IAAS,UAEP,MADoBE,EAAAA,cAAcF,EAAAA,QAAK,KAAK,EAAY,YAAY,CAAC,EAAA,CAC3D,SAAW,GAAK,CAACG,EAAAA,uBAAuB,MAAMC,EAAAA,+BAA+B,CAAU,CAAC,GACpG,QAAQ,MAAM,CAAwB,EAC/B,IAMX,MAAO,IAAS,QAAUC,EAAAA,iBAAiB,CAAU,EAAIC,EAAAA,iBAAiB,CAAU,GAC7E,EACT,CAEA,SAAgB,EAA0B,EAAoD,CAC5F,IAAM,EAAY,EAAwB,KAAK,OAAO,EACtD,MAAO,GAAG,EAAU;;YAEV,EAAU;6GAEtB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{findDefaultStdioHarnessFiles as e}from"../helpers/defaultStdioHarness.js";import{judgesWithoutTestCases as t,readProblemMarkdownFrontMatter as n}from"../helpers/readProblemMarkdownFrontMatter.js";import{readTestCases as r}from"../helpers/readTestCases.js";import{stdioDebugPreset as i,stdioJudgePreset as a}from"../presets/stdio.js";import o from"node:path";import s from"node:child_process";import c from"node:fs";const l=`a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired`;async function u(u){let f=process.cwd(),p=await e(f);if(p.length>0)return console.error(d(p)),1;let m=u===`judge`?`judge.ts`:`debug.ts`;if(c.existsSync(o.join(f,m))){let e=s.spawnSync(process.execPath,[`run`,m,...process.argv.slice(2)],{cwd:f,stdio:`inherit`});return e.error?(console.error(`failed to run ${m}: ${e.error.message}`),1):e.status??1}return u===`debug`&&c.existsSync(o.join(f,`judge.ts`))?(console.error(`This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.`),1):u===`judge`&&(await r(o.join(f,`test_cases`))).length===0&&!t(await n(f))?(console.error(l),1):(await(u===`judge`?a(f):i(f)),0)}function d(e){let t=e.join(` and `);return`${t} must not be committed because the content is identical to the default stdio harness.
|
|
2
2
|
A problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,
|
|
3
|
-
so delete ${t} and run the problem with \`bun x exercode judge <answerDir>\` or \`bun x exercode debug <answerDir>\`.
|
|
3
|
+
so delete ${t} and run the problem with \`bun x exercode-problem judge <answerDir>\` or \`bun x exercode-problem debug <answerDir>\`.
|
|
4
4
|
If the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`}export{l as MISSING_TEST_CASES_ERROR,d as formatDefaultHarnessError,u as runSingleHarness};
|
|
5
5
|
//# sourceMappingURL=runSingleHarness.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runSingleHarness.js","names":[],"sources":["../../src/cli/runSingleHarness.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { stdioDebugPreset, stdioJudgePreset } from '../presets/stdio.js';\n\nexport const MISSING_TEST_CASES_ERROR =\n 'a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired';\n\n/**\n * Run the judge or debug harness of the problem in the current working directory: a custom\n * `judge.ts` / `debug.ts` when present, or the default stdio preset otherwise (mirroring the\n * Exercode server, which applies the stdio presets to problems without these files).\n */\nexport async function runSingleHarness(kind: 'judge' | 'debug'): Promise<number> {\n const problemDir = process.cwd();\n\n const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n if (defaultHarnessFileNames.length > 0) {\n console.error(formatDefaultHarnessError(defaultHarnessFileNames));\n return 1;\n }\n\n const harnessFileName = kind === 'judge' ? 'judge.ts' : 'debug.ts';\n if (fs.existsSync(path.join(problemDir, harnessFileName))) {\n // process.execPath keeps the harness on the same bun executable regardless of PATH.\n const spawnResult = child_process.spawnSync(process.execPath, ['run', harnessFileName, ...process.argv.slice(2)], {\n cwd: problemDir,\n stdio: 'inherit',\n });\n if (spawnResult.error) {\n console.error(`failed to run ${harnessFileName}: ${spawnResult.error.message}`);\n return 1;\n }\n return spawnResult.status ?? 1;\n }\n\n // A custom judge.ts marks the problem as non-standard, so the stdio debug preset would judge the\n // answer against a contract the problem does not have (mirroring the server, which reports debug\n // as unsupported in this case).\n if (kind === 'debug' && fs.existsSync(path.join(problemDir, 'judge.ts'))) {\n console.error('This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.');\n return 1;\n }\n\n // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n // unless static-analysis rules or manual scoring make the problem judgeable without them.\n if (kind === 'judge') {\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n if (testCases.length === 0 && !judgesWithoutTestCases(await readProblemMarkdownFrontMatter(problemDir))) {\n console.error(MISSING_TEST_CASES_ERROR);\n return 1;\n }\n }\n\n // The presets read the answer directory and params from `process.argv`, which holds them at the\n // same positions as when a harness script is invoked directly.\n await (kind === 'judge' ? stdioJudgePreset(problemDir) : stdioDebugPreset(problemDir));\n return 0;\n}\n\nexport function formatDefaultHarnessError(defaultHarnessFileNames: readonly string[]): string {\n const fileNames = defaultHarnessFileNames.join(' and ');\n return `${fileNames} must not be committed because the content is identical to the default stdio harness.\nA problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,\nso delete ${fileNames} and run the problem with \\`bun x exercode judge <answerDir>\\` or \\`bun x exercode debug <answerDir>\\`.\nIf the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`;\n}\n"],"mappings":"saASA,MAAa,EACX,6KAOF,eAAsB,EAAiB,EAA0C,CAC/E,IAAM,EAAa,QAAQ,IAAI,EAEzB,EAA0B,MAAM,EAA6B,CAAU,EAC7E,GAAI,EAAwB,OAAS,EAEnC,OADA,QAAQ,MAAM,EAA0B,CAAuB,CAAC,EACzD,EAGT,IAAM,EAAkB,IAAS,QAAU,WAAa,WACxD,GAAI,EAAG,WAAW,EAAK,KAAK,EAAY,CAAe,CAAC,EAAG,CAEzD,IAAM,EAAc,EAAc,UAAU,QAAQ,SAAU,CAAC,MAAO,EAAiB,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAG,CAChH,IAAK,EACL,MAAO,SACT,CAAC,EAKD,OAJI,EAAY,OACd,QAAQ,MAAM,iBAAiB,EAAgB,IAAI,EAAY,MAAM,SAAS,EACvE,GAEF,EAAY,QAAU,CAC/B,CAwBA,OAnBI,IAAS,SAAW,EAAG,WAAW,EAAK,KAAK,EAAY,UAAU,CAAC,GACrE,QAAQ,MAAM,0FAA0F,EACjG,GAML,IAAS,UAEP,MADoB,EAAc,EAAK,KAAK,EAAY,YAAY,CAAC,EAAA,CAC3D,SAAW,GAAK,CAAC,EAAuB,MAAM,EAA+B,CAAU,CAAC,GACpG,QAAQ,MAAM,CAAwB,EAC/B,IAMX,MAAO,IAAS,QAAU,EAAiB,CAAU,EAAI,EAAiB,CAAU,GAC7E,EACT,CAEA,SAAgB,EAA0B,EAAoD,CAC5F,IAAM,EAAY,EAAwB,KAAK,OAAO,EACtD,MAAO,GAAG,EAAU;;YAEV,EAAU;6GAEtB"}
|
|
1
|
+
{"version":3,"file":"runSingleHarness.js","names":[],"sources":["../../src/cli/runSingleHarness.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { stdioDebugPreset, stdioJudgePreset } from '../presets/stdio.js';\n\nexport const MISSING_TEST_CASES_ERROR =\n 'a standard stdio problem (without judge.ts) needs at least one test case under test_cases/, static-analysis rules (e.g. requiredRegExpsInCode), or isManualScoringRequired';\n\n/**\n * Run the judge or debug harness of the problem in the current working directory: a custom\n * `judge.ts` / `debug.ts` when present, or the default stdio preset otherwise (mirroring the\n * Exercode server, which applies the stdio presets to problems without these files).\n */\nexport async function runSingleHarness(kind: 'judge' | 'debug'): Promise<number> {\n const problemDir = process.cwd();\n\n const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n if (defaultHarnessFileNames.length > 0) {\n console.error(formatDefaultHarnessError(defaultHarnessFileNames));\n return 1;\n }\n\n const harnessFileName = kind === 'judge' ? 'judge.ts' : 'debug.ts';\n if (fs.existsSync(path.join(problemDir, harnessFileName))) {\n // process.execPath keeps the harness on the same bun executable regardless of PATH.\n const spawnResult = child_process.spawnSync(process.execPath, ['run', harnessFileName, ...process.argv.slice(2)], {\n cwd: problemDir,\n stdio: 'inherit',\n });\n if (spawnResult.error) {\n console.error(`failed to run ${harnessFileName}: ${spawnResult.error.message}`);\n return 1;\n }\n return spawnResult.status ?? 1;\n }\n\n // A custom judge.ts marks the problem as non-standard, so the stdio debug preset would judge the\n // answer against a contract the problem does not have (mirroring the server, which reports debug\n // as unsupported in this case).\n if (kind === 'debug' && fs.existsSync(path.join(problemDir, 'judge.ts'))) {\n console.error('This problem has a custom judge.ts but no debug.ts; add a debug.ts to support debugging.');\n return 1;\n }\n\n // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n // unless static-analysis rules or manual scoring make the problem judgeable without them.\n if (kind === 'judge') {\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n if (testCases.length === 0 && !judgesWithoutTestCases(await readProblemMarkdownFrontMatter(problemDir))) {\n console.error(MISSING_TEST_CASES_ERROR);\n return 1;\n }\n }\n\n // The presets read the answer directory and params from `process.argv`, which holds them at the\n // same positions as when a harness script is invoked directly.\n await (kind === 'judge' ? stdioJudgePreset(problemDir) : stdioDebugPreset(problemDir));\n return 0;\n}\n\nexport function formatDefaultHarnessError(defaultHarnessFileNames: readonly string[]): string {\n const fileNames = defaultHarnessFileNames.join(' and ');\n return `${fileNames} must not be committed because the content is identical to the default stdio harness.\nA problem without judge.ts is automatically judged with stdioJudgePreset and debugged with stdioDebugPreset,\nso delete ${fileNames} and run the problem with \\`bun x exercode-problem judge <answerDir>\\` or \\`bun x exercode-problem debug <answerDir>\\`.\nIf the file intentionally demonstrates the default harness, add an explanatory comment to mark it as custom.`;\n}\n"],"mappings":"saASA,MAAa,EACX,6KAOF,eAAsB,EAAiB,EAA0C,CAC/E,IAAM,EAAa,QAAQ,IAAI,EAEzB,EAA0B,MAAM,EAA6B,CAAU,EAC7E,GAAI,EAAwB,OAAS,EAEnC,OADA,QAAQ,MAAM,EAA0B,CAAuB,CAAC,EACzD,EAGT,IAAM,EAAkB,IAAS,QAAU,WAAa,WACxD,GAAI,EAAG,WAAW,EAAK,KAAK,EAAY,CAAe,CAAC,EAAG,CAEzD,IAAM,EAAc,EAAc,UAAU,QAAQ,SAAU,CAAC,MAAO,EAAiB,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAG,CAChH,IAAK,EACL,MAAO,SACT,CAAC,EAKD,OAJI,EAAY,OACd,QAAQ,MAAM,iBAAiB,EAAgB,IAAI,EAAY,MAAM,SAAS,EACvE,GAEF,EAAY,QAAU,CAC/B,CAwBA,OAnBI,IAAS,SAAW,EAAG,WAAW,EAAK,KAAK,EAAY,UAAU,CAAC,GACrE,QAAQ,MAAM,0FAA0F,EACjG,GAML,IAAS,UAEP,MADoB,EAAc,EAAK,KAAK,EAAY,YAAY,CAAC,EAAA,CAC3D,SAAW,GAAK,CAAC,EAAuB,MAAM,EAA+B,CAAU,CAAC,GACpG,QAAQ,MAAM,CAAwB,EAC/B,IAMX,MAAO,IAAS,QAAU,EAAiB,CAAU,EAAI,EAAiB,CAAU,GAC7E,EACT,CAEA,SAAgB,EAA0B,EAAoD,CAC5F,IAAM,EAAY,EAAwB,KAAK,OAAO,EACtD,MAAO,GAAG,EAAU;;YAEV,EAAU;6GAEtB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
"use strict";function e(e,t){return n(e,t,{removeStrings:!1})}function t(e,t){return n(e,t,{removeStrings:!0})}function n(e,t,n,a=r(e)){if(!e.comments?.length&&(!n.removeStrings||!e.strings?.length))return t;let s=[],c=0;for(;c<t.length;){let r;for(let e of a){let a=e.openRegExp;a.lastIndex=c;let o=a.exec(t);o&&i(o,e,r,n)&&(r={grammar:e,match:o})}if(r){let i=r.match.index;if(!r.grammar.isComment&&n.removeStrings&&(i=
|
|
2
|
-
`)}function h(e,t
|
|
3
|
-
`)}function
|
|
4
|
-
`)
|
|
5
|
-
|
|
1
|
+
"use strict";function e(e,t){return n(e,t,{removeStrings:!1})}function t(e,t){return n(e,t,{removeStrings:!0})}function n(e,t,n,a=r(e)){if(!e.comments?.length&&(!n.removeStrings||!e.strings?.length))return t;let s=[],c=0;for(;c<t.length;){let r;for(let e of a){let a=e.openRegExp;a.lastIndex=c;let o=a.exec(t);o&&i(o,e,r,n)&&(r={grammar:e,match:o})}if(r){let i=r.match.index;if(!r.grammar.isComment&&n.removeStrings&&(i=d(t,r.match.index)),s.push(t.slice(c,i)),r.grammar.isComment){let e=r.grammar.closeRegExp;e.lastIndex=r.match.index+r.match[0].length;let n=e.exec(t);c=n?n.index+n[0].length:t.length}else{c=o(t,r.match.index,r.grammar);let i=t.slice(r.match.index,c);n.removeStrings?s.push(p(e,a,r.grammar,t,r.match.index,i)):s.push(i)}}else s.push(t.slice(c)),c=t.length}return s.join(``)}function r(e){return[...e.comments?.map(e=>({closeRegExp:a(e.close??/(?=\n)/g),isComment:!0,openRegExp:a(e.open)}))??[],...e.strings?.map(e=>({closeRegExp:a(e.close),isComment:!1,openRegExp:a(e.open),templateSyntax:e.templateSyntax}))??[]]}function i(e,t,n,r){return!n||e.index<n.match.index?!0:e.index>n.match.index?!1:r.removeStrings&&n.grammar.isComment&&!t.isComment}function a(e){return new RegExp(e,e.flags.includes(`g`)?e.flags:`${e.flags}g`)}function o(e,t,n){if(n.templateSyntax===`kotlin`)return s(e,t);if(e[t]==="`")return c(e,t);if(_(e,t))return l(e,t);let r=n.closeRegExp;r.lastIndex=t+1;let i=r.exec(e);return i?i.index+i[0].length:e.length}function s(e,t){let n=u(e,t),r=n.length===3,i=t+n.length;for(;i<e.length;){if(e.startsWith(n,i))return i+n.length;if(!r&&e[i]===`\\`){i+=2;continue}if(e[i]===`$`&&e[i+1]===`{`){i=b(e,i+2,`}`,{slashStartsComments:!0,slashStartsRegExp:!1,supportsKotlinStrings:!0}).endIndex+1;continue}i+=1}return e.length}function c(e,t){let n=t+1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]==="`")return n+1;if(e[n]===`$`&&e[n+1]===`{`){n=b(e,n+2,`}`,{slashStartsRegExp:!0}).endIndex+1;continue}n+=1}return e.length}function l(e,t){let n=u(e,t),r=t+n.length;for(;r<e.length;){if(e.startsWith(n,r))return r+n.length;if(e[r]===`{`&&e[r+1]===`{`){r+=2;continue}if(e[r]===`{`){r=b(e,r+1,`}`,{slashStartsRegExp:!1}).endIndex+1;continue}r+=e[r]===`\\`?2:1}return e.length}function u(e,t){let n=e.slice(t,t+3);return n===`'''`||n===`"""`?n:e[t]??``}function d(e,t){let n=f(e,t);return n?t-n.length:t}function f(e,t){if(e[t]!==`"`&&e[t]!==`'`)return;let n=t-1;for(;n>=0&&/[A-Za-z]/.test(e[n]??``);)--n;let r=e.slice(n+1,t);if(!(!r||!/^[bfru]+$/i.test(r))&&!(n>=0&&/[\dA-Za-z_]/.test(e[n]??``)))return r}function p(e,t,n,r,i,a){return n.templateSyntax===`kotlin`?m(e,t,a):a.startsWith("`")?v(e,t,a):_(r,i)?y(e,t,a):``}function m(e,t,r){let i=u(r,0).length,a=i===3,o=[],s=i;for(;s<r.length-i;){if(!a&&r[s]===`\\`){s+=2;continue}if(r[s]!==`$`){s+=1;continue}if(r[s+1]===`{`){let i=b(r,s+2,`}`,{slashStartsComments:!0,slashStartsRegExp:!1,supportsKotlinStrings:!0});o.push(n(e,i.content,{removeStrings:!0},t)),s=i.endIndex+1;continue}if(h(r[s+1])){let e=s+2;for(;g(r[e]);)e+=1;o.push(r.slice(s+1,e)),s=e;continue}s+=1}return o.join(`
|
|
2
|
+
`)}function h(e){return e!==void 0&&/[\p{L}_]/u.test(e)}function g(e){return e!==void 0&&/[\p{L}\p{N}_]/u.test(e)}function _(e,t){return f(e,t)?.toLowerCase().includes(`f`)??!1}function v(e,t,r){let i=[],a=1;for(;a<r.length-1;){if(r[a]===`\\`){a+=2;continue}if(r[a]===`$`&&r[a+1]===`{`){let o=b(r,a+2,`}`,{slashStartsRegExp:!0});i.push(n(e,o.content,{removeStrings:!0},t)),a=o.endIndex+1;continue}a+=1}return i.join(`
|
|
3
|
+
`)}function y(e,t,r){let i=u(r,0).length,a=[],o=i;for(;o<r.length-i;){if(r[o]===`{`&&r[o+1]===`{`){o+=2;continue}if(r[o]===`{`){let i=b(r,o+1,`}`,{slashStartsRegExp:!1});a.push(n(e,i.content,{removeStrings:!0},t)),o=i.endIndex+1;continue}o+=r[o]===`\\`?2:1}return a.join(`
|
|
4
|
+
`)}function b(e,t,n,r){let i=1,a=t;for(;a<e.length;){let o=e[a];if(o===`"`&&r.supportsKotlinStrings){a=s(e,a);continue}if(o===`"`||o===`'`||o==="`"){a=x(e,a);continue}if((r.slashStartsComments||r.slashStartsRegExp)&&e[a]===`/`&&e[a+1]===`/`){a=C(e,a);continue}if((r.slashStartsComments||r.slashStartsRegExp)&&e[a]===`/`&&e[a+1]===`*`){a=w(e,a);continue}if(r.slashStartsRegExp&&o===`/`){a=S(e,a);continue}if(o===`{`&&(i+=1),o===n&&(--i,i===0))return{content:e.slice(t,a),endIndex:a};a+=1}return{content:e.slice(t),endIndex:e.length}}function x(e,t){let n=u(e,t),r=t+n.length;for(;r<e.length;){if(e[r]===`\\`){r+=2;continue}if(e.startsWith(n,r))return r+n.length;r+=1}return r}function S(e,t){let n=t+1,r=!1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]===`[`&&(r=!0),e[n]===`]`&&(r=!1),e[n]===`/`&&!r){for(n+=1;/[A-Za-z]/.test(e[n]??``);)n+=1;return n}if(e[n]===`
|
|
5
|
+
`)return t+1;n+=1}return t+1}function C(e,t){let n=e.indexOf(`
|
|
6
|
+
`,t+2);return n===-1?e.length:n}function w(e,t){let n=e.indexOf(`*/`,t+2);return n===-1?e.length:n+2}exports.removeCommentsAndStringsInSourceCode=t,exports.removeCommentsInSourceCode=e;
|
|
6
7
|
//# sourceMappingURL=removeCommentsInSourceCode.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"removeCommentsInSourceCode.cjs","names":[],"sources":["../../src/helpers/removeCommentsInSourceCode.ts"],"sourcesContent":["import type { LanguageDefinition } from '../types/language.js';\n\nexport type SourceCodeGrammar = NonNullable<LanguageDefinition['grammer']>;\n\n/** Removes comments from source code according to the provided language grammar. */\nexport function removeCommentsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: false });\n}\n\n/** Removes comments and string literal contents while preserving executable interpolation expressions. */\nexport function removeCommentsAndStringsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: true });\n}\n\ninterface CommentOrStringGrammar {\n closeRegExp: RegExp;\n isComment: boolean;\n openRegExp: RegExp;\n}\n\nfunction removeCommentsAndMaybeStringsInSourceCode(\n grammar: SourceCodeGrammar,\n sourceCode: string,\n options: { removeStrings: boolean },\n commentOrStringGrammars = compileCommentOrStringGrammars(grammar)\n): string {\n if (!grammar.comments?.length && (!options.removeStrings || !grammar.strings?.length)) return sourceCode;\n\n const newSourceCodeSlices: string[] = [];\n\n let lastIndex = 0;\n\n while (lastIndex < sourceCode.length) {\n let first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined;\n\n for (const commentOrStringGrammer of commentOrStringGrammars) {\n const startRegExp = commentOrStringGrammer.openRegExp;\n startRegExp.lastIndex = lastIndex;\n\n const match = startRegExp.exec(sourceCode);\n\n if (match && shouldPreferMatch(match, commentOrStringGrammer, first, options)) {\n first = { grammar: commentOrStringGrammer, match };\n }\n }\n\n if (first) {\n let stringPrefixStartIndex = first.match.index;\n if (!first.grammar.isComment && options.removeStrings) {\n stringPrefixStartIndex = getPythonStringPrefixStartIndex(sourceCode, first.match.index);\n }\n newSourceCodeSlices.push(sourceCode.slice(lastIndex, stringPrefixStartIndex));\n\n if (!first.grammar.isComment) {\n lastIndex = findStringEndIndex(sourceCode, first.match.index, first.grammar);\n const stringLiteral = sourceCode.slice(first.match.index, lastIndex);\n if (options.removeStrings) {\n newSourceCodeSlices.push(\n preserveStringInterpolationExpressions(\n grammar,\n commentOrStringGrammars,\n sourceCode,\n first.match.index,\n stringLiteral\n )\n );\n } else {\n newSourceCodeSlices.push(stringLiteral);\n }\n } else {\n const closeRegExp = first.grammar.closeRegExp;\n closeRegExp.lastIndex = first.match.index + first.match[0].length;\n\n const match = closeRegExp.exec(sourceCode);\n\n lastIndex = match ? match.index + match[0].length : sourceCode.length;\n }\n } else {\n newSourceCodeSlices.push(sourceCode.slice(lastIndex));\n lastIndex = sourceCode.length;\n }\n }\n\n return newSourceCodeSlices.join('');\n}\n\nfunction compileCommentOrStringGrammars(grammar: SourceCodeGrammar): readonly CommentOrStringGrammar[] {\n return [\n ...(grammar.comments?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close ?? /(?=\\n)/g),\n isComment: true,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ...(grammar.strings?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close),\n isComment: false,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ] satisfies CommentOrStringGrammar[];\n}\n\nfunction shouldPreferMatch(\n match: RegExpExecArray,\n grammar: CommentOrStringGrammar,\n first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined,\n options: { removeStrings: boolean }\n): boolean {\n if (!first) return true;\n if (match.index < first.match.index) return true;\n if (match.index > first.match.index) return false;\n return options.removeStrings && first.grammar.isComment && !grammar.isComment;\n}\n\nfunction makeGlobalRegExp(regExp: RegExp): RegExp {\n return new RegExp(regExp, regExp.flags.includes('g') ? regExp.flags : `${regExp.flags}g`);\n}\n\nfunction findStringEndIndex(sourceCode: string, stringStartIndex: number, grammar: CommentOrStringGrammar): number {\n if (sourceCode[stringStartIndex] === '`') return findJavaScriptTemplateEndIndex(sourceCode, stringStartIndex);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return findPythonFStringEndIndex(sourceCode, stringStartIndex);\n\n const closeRegExp = grammar.closeRegExp;\n closeRegExp.lastIndex = stringStartIndex + 1;\n const match = closeRegExp.exec(sourceCode);\n return match ? match.index + match[0].length : sourceCode.length;\n}\n\nfunction findJavaScriptTemplateEndIndex(sourceCode: string, stringStartIndex: number): number {\n let index = stringStartIndex + 1;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '`') return index + 1;\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index = readBalancedExpression(sourceCode, index + 2, '}', { slashStartsRegExp: true }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findPythonFStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (sourceCode[index] === '{' && sourceCode[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '{') {\n index = readBalancedExpression(sourceCode, index + 1, '}', { slashStartsRegExp: false }).endIndex + 1;\n continue;\n }\n index += sourceCode[index] === '\\\\' ? 2 : 1;\n }\n\n return sourceCode.length;\n}\n\nfunction getStringQuote(sourceCode: string, stringStartIndex: number): string {\n const threeCharacterQuote = sourceCode.slice(stringStartIndex, stringStartIndex + 3);\n if (threeCharacterQuote === \"'''\" || threeCharacterQuote === '\"\"\"') return threeCharacterQuote;\n return sourceCode[stringStartIndex] ?? '';\n}\n\nfunction getPythonStringPrefixStartIndex(sourceCode: string, stringStartIndex: number): number {\n const prefix = getPythonStringPrefix(sourceCode, stringStartIndex);\n return prefix ? stringStartIndex - prefix.length : stringStartIndex;\n}\n\nfunction getPythonStringPrefix(sourceCode: string, stringStartIndex: number): string | undefined {\n if (sourceCode[stringStartIndex] !== '\"' && sourceCode[stringStartIndex] !== \"'\") return undefined;\n let index = stringStartIndex - 1;\n while (index >= 0 && /[A-Za-z]/.test(sourceCode[index] ?? '')) index -= 1;\n\n const prefix = sourceCode.slice(index + 1, stringStartIndex);\n if (!prefix || !/^[bfru]+$/i.test(prefix)) return undefined;\n if (index >= 0 && /[\\dA-Za-z_]/.test(sourceCode[index] ?? '')) return undefined;\n\n return prefix;\n}\n\nfunction preserveStringInterpolationExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n sourceCode: string,\n stringStartIndex: number,\n stringLiteral: string\n): string {\n if (stringLiteral.startsWith('`'))\n return preserveJavaScriptTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return preservePythonFStringExpressions(grammar, commentOrStringGrammars, stringLiteral);\n return '';\n}\n\nfunction hasPythonFStringPrefix(sourceCode: string, stringStartIndex: number): boolean {\n return getPythonStringPrefix(sourceCode, stringStartIndex)?.toLowerCase().includes('f') ?? false;\n}\n\nfunction preserveJavaScriptTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const expressions: string[] = [];\n let index = 1;\n\n while (index < stringLiteral.length - 1) {\n if (stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '$' && stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', { slashStartsRegExp: true });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction preservePythonFStringExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (stringLiteral[index] === '{' && stringLiteral[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 1, '}', { slashStartsRegExp: false });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += stringLiteral[index] === '\\\\' ? 2 : 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction readBalancedExpression(\n sourceCode: string,\n startIndex: number,\n closeChar: string,\n options: { slashStartsRegExp: boolean }\n): { content: string; endIndex: number } {\n let depth = 1;\n let index = startIndex;\n\n while (index < sourceCode.length) {\n const char = sourceCode[index];\n if (char === '\"' || char === \"'\" || char === '`') {\n index = skipQuotedSpan(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && sourceCode[index] === '/' && sourceCode[index + 1] === '/') {\n index = skipJavaScriptSingleLineComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && sourceCode[index] === '/' && sourceCode[index + 1] === '*') {\n index = skipJavaScriptBlockComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && char === '/') {\n index = skipJavaScriptRegExpLiteral(sourceCode, index);\n continue;\n }\n if (char === '{') depth += 1;\n if (char === closeChar) {\n depth -= 1;\n if (depth === 0) return { content: sourceCode.slice(startIndex, index), endIndex: index };\n }\n index += 1;\n }\n\n return { content: sourceCode.slice(startIndex), endIndex: sourceCode.length };\n}\n\nfunction skipQuotedSpan(sourceCode: string, startIndex: number): number {\n const quote = getStringQuote(sourceCode, startIndex);\n let index = startIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n index += 1;\n }\n\n return index;\n}\n\nfunction skipJavaScriptRegExpLiteral(sourceCode: string, startIndex: number): number {\n let index = startIndex + 1;\n let inCharacterClass = false;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '[') inCharacterClass = true;\n if (sourceCode[index] === ']') inCharacterClass = false;\n if (sourceCode[index] === '/' && !inCharacterClass) {\n index += 1;\n while (/[A-Za-z]/.test(sourceCode[index] ?? '')) index += 1;\n return index;\n }\n if (sourceCode[index] === '\\n') return startIndex + 1;\n index += 1;\n }\n\n return startIndex + 1;\n}\n\nfunction skipJavaScriptSingleLineComment(sourceCode: string, startIndex: number): number {\n const newLineIndex = sourceCode.indexOf('\\n', startIndex + 2);\n return newLineIndex === -1 ? sourceCode.length : newLineIndex;\n}\n\nfunction skipJavaScriptBlockComment(sourceCode: string, startIndex: number): number {\n const endIndex = sourceCode.indexOf('*/', startIndex + 2);\n return endIndex === -1 ? sourceCode.length : endIndex + 2;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"removeCommentsInSourceCode.cjs","names":[],"sources":["../../src/helpers/removeCommentsInSourceCode.ts"],"sourcesContent":["import type { LanguageDefinition } from '../types/language.js';\n\nexport type SourceCodeGrammar = NonNullable<LanguageDefinition['grammer']>;\n\n/** Removes comments from source code according to the provided language grammar. */\nexport function removeCommentsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: false });\n}\n\n/** Removes comments and string literal contents while preserving executable interpolation expressions. */\nexport function removeCommentsAndStringsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: true });\n}\n\ninterface CommentOrStringGrammar {\n closeRegExp: RegExp;\n isComment: boolean;\n openRegExp: RegExp;\n templateSyntax?: 'kotlin';\n}\n\ninterface BalancedExpressionOptions {\n slashStartsComments?: boolean;\n slashStartsRegExp: boolean;\n supportsKotlinStrings?: boolean;\n}\n\nfunction removeCommentsAndMaybeStringsInSourceCode(\n grammar: SourceCodeGrammar,\n sourceCode: string,\n options: { removeStrings: boolean },\n commentOrStringGrammars = compileCommentOrStringGrammars(grammar)\n): string {\n if (!grammar.comments?.length && (!options.removeStrings || !grammar.strings?.length)) return sourceCode;\n\n const newSourceCodeSlices: string[] = [];\n\n let lastIndex = 0;\n\n while (lastIndex < sourceCode.length) {\n let first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined;\n\n for (const commentOrStringGrammer of commentOrStringGrammars) {\n const startRegExp = commentOrStringGrammer.openRegExp;\n startRegExp.lastIndex = lastIndex;\n\n const match = startRegExp.exec(sourceCode);\n\n if (match && shouldPreferMatch(match, commentOrStringGrammer, first, options)) {\n first = { grammar: commentOrStringGrammer, match };\n }\n }\n\n if (first) {\n let stringPrefixStartIndex = first.match.index;\n if (!first.grammar.isComment && options.removeStrings) {\n stringPrefixStartIndex = getPythonStringPrefixStartIndex(sourceCode, first.match.index);\n }\n newSourceCodeSlices.push(sourceCode.slice(lastIndex, stringPrefixStartIndex));\n\n if (!first.grammar.isComment) {\n lastIndex = findStringEndIndex(sourceCode, first.match.index, first.grammar);\n const stringLiteral = sourceCode.slice(first.match.index, lastIndex);\n if (options.removeStrings) {\n newSourceCodeSlices.push(\n preserveStringInterpolationExpressions(\n grammar,\n commentOrStringGrammars,\n first.grammar,\n sourceCode,\n first.match.index,\n stringLiteral\n )\n );\n } else {\n newSourceCodeSlices.push(stringLiteral);\n }\n } else {\n const closeRegExp = first.grammar.closeRegExp;\n closeRegExp.lastIndex = first.match.index + first.match[0].length;\n\n const match = closeRegExp.exec(sourceCode);\n\n lastIndex = match ? match.index + match[0].length : sourceCode.length;\n }\n } else {\n newSourceCodeSlices.push(sourceCode.slice(lastIndex));\n lastIndex = sourceCode.length;\n }\n }\n\n return newSourceCodeSlices.join('');\n}\n\nfunction compileCommentOrStringGrammars(grammar: SourceCodeGrammar): readonly CommentOrStringGrammar[] {\n return [\n ...(grammar.comments?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close ?? /(?=\\n)/g),\n isComment: true,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ...(grammar.strings?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close),\n isComment: false,\n openRegExp: makeGlobalRegExp(v.open),\n templateSyntax: v.templateSyntax,\n })) ?? []),\n ] satisfies CommentOrStringGrammar[];\n}\n\nfunction shouldPreferMatch(\n match: RegExpExecArray,\n grammar: CommentOrStringGrammar,\n first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined,\n options: { removeStrings: boolean }\n): boolean {\n if (!first) return true;\n if (match.index < first.match.index) return true;\n if (match.index > first.match.index) return false;\n return options.removeStrings && first.grammar.isComment && !grammar.isComment;\n}\n\nfunction makeGlobalRegExp(regExp: RegExp): RegExp {\n return new RegExp(regExp, regExp.flags.includes('g') ? regExp.flags : `${regExp.flags}g`);\n}\n\nfunction findStringEndIndex(sourceCode: string, stringStartIndex: number, grammar: CommentOrStringGrammar): number {\n if (grammar.templateSyntax === 'kotlin') return findKotlinStringEndIndex(sourceCode, stringStartIndex);\n if (sourceCode[stringStartIndex] === '`') return findJavaScriptTemplateEndIndex(sourceCode, stringStartIndex);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return findPythonFStringEndIndex(sourceCode, stringStartIndex);\n\n const closeRegExp = grammar.closeRegExp;\n closeRegExp.lastIndex = stringStartIndex + 1;\n const match = closeRegExp.exec(sourceCode);\n return match ? match.index + match[0].length : sourceCode.length;\n}\n\nfunction findKotlinStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n const isRawString = quote.length === 3;\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (!isRawString && sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index =\n readBalancedExpression(sourceCode, index + 2, '}', {\n slashStartsComments: true,\n slashStartsRegExp: false,\n supportsKotlinStrings: true,\n }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findJavaScriptTemplateEndIndex(sourceCode: string, stringStartIndex: number): number {\n let index = stringStartIndex + 1;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '`') return index + 1;\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index = readBalancedExpression(sourceCode, index + 2, '}', { slashStartsRegExp: true }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findPythonFStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (sourceCode[index] === '{' && sourceCode[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '{') {\n index = readBalancedExpression(sourceCode, index + 1, '}', { slashStartsRegExp: false }).endIndex + 1;\n continue;\n }\n index += sourceCode[index] === '\\\\' ? 2 : 1;\n }\n\n return sourceCode.length;\n}\n\nfunction getStringQuote(sourceCode: string, stringStartIndex: number): string {\n const threeCharacterQuote = sourceCode.slice(stringStartIndex, stringStartIndex + 3);\n if (threeCharacterQuote === \"'''\" || threeCharacterQuote === '\"\"\"') return threeCharacterQuote;\n return sourceCode[stringStartIndex] ?? '';\n}\n\nfunction getPythonStringPrefixStartIndex(sourceCode: string, stringStartIndex: number): number {\n const prefix = getPythonStringPrefix(sourceCode, stringStartIndex);\n return prefix ? stringStartIndex - prefix.length : stringStartIndex;\n}\n\nfunction getPythonStringPrefix(sourceCode: string, stringStartIndex: number): string | undefined {\n if (sourceCode[stringStartIndex] !== '\"' && sourceCode[stringStartIndex] !== \"'\") return undefined;\n let index = stringStartIndex - 1;\n while (index >= 0 && /[A-Za-z]/.test(sourceCode[index] ?? '')) index -= 1;\n\n const prefix = sourceCode.slice(index + 1, stringStartIndex);\n if (!prefix || !/^[bfru]+$/i.test(prefix)) return undefined;\n if (index >= 0 && /[\\dA-Za-z_]/.test(sourceCode[index] ?? '')) return undefined;\n\n return prefix;\n}\n\nfunction preserveStringInterpolationExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringGrammar: CommentOrStringGrammar,\n sourceCode: string,\n stringStartIndex: number,\n stringLiteral: string\n): string {\n if (stringGrammar.templateSyntax === 'kotlin')\n return preserveKotlinStringTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (stringLiteral.startsWith('`'))\n return preserveJavaScriptTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return preservePythonFStringExpressions(grammar, commentOrStringGrammars, stringLiteral);\n return '';\n}\n\nfunction preserveKotlinStringTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const isRawString = quoteLength === 3;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (!isRawString && stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] !== '$') {\n index += 1;\n continue;\n }\n if (stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', {\n slashStartsComments: true,\n slashStartsRegExp: false,\n supportsKotlinStrings: true,\n });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n if (isKotlinIdentifierStart(stringLiteral[index + 1])) {\n let endIndex = index + 2;\n while (isKotlinIdentifierPart(stringLiteral[endIndex])) endIndex += 1;\n expressions.push(stringLiteral.slice(index + 1, endIndex));\n index = endIndex;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction isKotlinIdentifierStart(character: string | undefined): boolean {\n return character !== undefined && /[\\p{L}_]/u.test(character);\n}\n\nfunction isKotlinIdentifierPart(character: string | undefined): boolean {\n return character !== undefined && /[\\p{L}\\p{N}_]/u.test(character);\n}\n\nfunction hasPythonFStringPrefix(sourceCode: string, stringStartIndex: number): boolean {\n return getPythonStringPrefix(sourceCode, stringStartIndex)?.toLowerCase().includes('f') ?? false;\n}\n\nfunction preserveJavaScriptTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const expressions: string[] = [];\n let index = 1;\n\n while (index < stringLiteral.length - 1) {\n if (stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '$' && stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', { slashStartsRegExp: true });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction preservePythonFStringExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (stringLiteral[index] === '{' && stringLiteral[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 1, '}', { slashStartsRegExp: false });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += stringLiteral[index] === '\\\\' ? 2 : 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction readBalancedExpression(\n sourceCode: string,\n startIndex: number,\n closeChar: string,\n options: BalancedExpressionOptions\n): { content: string; endIndex: number } {\n let depth = 1;\n let index = startIndex;\n\n while (index < sourceCode.length) {\n const char = sourceCode[index];\n if (char === '\"' && options.supportsKotlinStrings) {\n index = findKotlinStringEndIndex(sourceCode, index);\n continue;\n }\n if (char === '\"' || char === \"'\" || char === '`') {\n index = skipQuotedSpan(sourceCode, index);\n continue;\n }\n if (\n (options.slashStartsComments || options.slashStartsRegExp) &&\n sourceCode[index] === '/' &&\n sourceCode[index + 1] === '/'\n ) {\n index = skipJavaScriptSingleLineComment(sourceCode, index);\n continue;\n }\n if (\n (options.slashStartsComments || options.slashStartsRegExp) &&\n sourceCode[index] === '/' &&\n sourceCode[index + 1] === '*'\n ) {\n index = skipJavaScriptBlockComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && char === '/') {\n index = skipJavaScriptRegExpLiteral(sourceCode, index);\n continue;\n }\n if (char === '{') depth += 1;\n if (char === closeChar) {\n depth -= 1;\n if (depth === 0) return { content: sourceCode.slice(startIndex, index), endIndex: index };\n }\n index += 1;\n }\n\n return { content: sourceCode.slice(startIndex), endIndex: sourceCode.length };\n}\n\nfunction skipQuotedSpan(sourceCode: string, startIndex: number): number {\n const quote = getStringQuote(sourceCode, startIndex);\n let index = startIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n index += 1;\n }\n\n return index;\n}\n\nfunction skipJavaScriptRegExpLiteral(sourceCode: string, startIndex: number): number {\n let index = startIndex + 1;\n let inCharacterClass = false;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '[') inCharacterClass = true;\n if (sourceCode[index] === ']') inCharacterClass = false;\n if (sourceCode[index] === '/' && !inCharacterClass) {\n index += 1;\n while (/[A-Za-z]/.test(sourceCode[index] ?? '')) index += 1;\n return index;\n }\n if (sourceCode[index] === '\\n') return startIndex + 1;\n index += 1;\n }\n\n return startIndex + 1;\n}\n\nfunction skipJavaScriptSingleLineComment(sourceCode: string, startIndex: number): number {\n const newLineIndex = sourceCode.indexOf('\\n', startIndex + 2);\n return newLineIndex === -1 ? sourceCode.length : newLineIndex;\n}\n\nfunction skipJavaScriptBlockComment(sourceCode: string, startIndex: number): number {\n const endIndex = sourceCode.indexOf('*/', startIndex + 2);\n return endIndex === -1 ? sourceCode.length : endIndex + 2;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
function e(e,t){return n(e,t,{removeStrings:!1})}function t(e,t){return n(e,t,{removeStrings:!0})}function n(e,t,n,a=r(e)){if(!e.comments?.length&&(!n.removeStrings||!e.strings?.length))return t;let s=[],c=0;for(;c<t.length;){let r;for(let e of a){let a=e.openRegExp;a.lastIndex=c;let o=a.exec(t);o&&i(o,e,r,n)&&(r={grammar:e,match:o})}if(r){let i=r.match.index;if(!r.grammar.isComment&&n.removeStrings&&(i=
|
|
2
|
-
`)}function h(e,t
|
|
3
|
-
`)}function
|
|
4
|
-
`)
|
|
5
|
-
|
|
1
|
+
function e(e,t){return n(e,t,{removeStrings:!1})}function t(e,t){return n(e,t,{removeStrings:!0})}function n(e,t,n,a=r(e)){if(!e.comments?.length&&(!n.removeStrings||!e.strings?.length))return t;let s=[],c=0;for(;c<t.length;){let r;for(let e of a){let a=e.openRegExp;a.lastIndex=c;let o=a.exec(t);o&&i(o,e,r,n)&&(r={grammar:e,match:o})}if(r){let i=r.match.index;if(!r.grammar.isComment&&n.removeStrings&&(i=d(t,r.match.index)),s.push(t.slice(c,i)),r.grammar.isComment){let e=r.grammar.closeRegExp;e.lastIndex=r.match.index+r.match[0].length;let n=e.exec(t);c=n?n.index+n[0].length:t.length}else{c=o(t,r.match.index,r.grammar);let i=t.slice(r.match.index,c);n.removeStrings?s.push(p(e,a,r.grammar,t,r.match.index,i)):s.push(i)}}else s.push(t.slice(c)),c=t.length}return s.join(``)}function r(e){return[...e.comments?.map(e=>({closeRegExp:a(e.close??/(?=\n)/g),isComment:!0,openRegExp:a(e.open)}))??[],...e.strings?.map(e=>({closeRegExp:a(e.close),isComment:!1,openRegExp:a(e.open),templateSyntax:e.templateSyntax}))??[]]}function i(e,t,n,r){return!n||e.index<n.match.index?!0:e.index>n.match.index?!1:r.removeStrings&&n.grammar.isComment&&!t.isComment}function a(e){return new RegExp(e,e.flags.includes(`g`)?e.flags:`${e.flags}g`)}function o(e,t,n){if(n.templateSyntax===`kotlin`)return s(e,t);if(e[t]==="`")return c(e,t);if(_(e,t))return l(e,t);let r=n.closeRegExp;r.lastIndex=t+1;let i=r.exec(e);return i?i.index+i[0].length:e.length}function s(e,t){let n=u(e,t),r=n.length===3,i=t+n.length;for(;i<e.length;){if(e.startsWith(n,i))return i+n.length;if(!r&&e[i]===`\\`){i+=2;continue}if(e[i]===`$`&&e[i+1]===`{`){i=b(e,i+2,`}`,{slashStartsComments:!0,slashStartsRegExp:!1,supportsKotlinStrings:!0}).endIndex+1;continue}i+=1}return e.length}function c(e,t){let n=t+1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]==="`")return n+1;if(e[n]===`$`&&e[n+1]===`{`){n=b(e,n+2,`}`,{slashStartsRegExp:!0}).endIndex+1;continue}n+=1}return e.length}function l(e,t){let n=u(e,t),r=t+n.length;for(;r<e.length;){if(e.startsWith(n,r))return r+n.length;if(e[r]===`{`&&e[r+1]===`{`){r+=2;continue}if(e[r]===`{`){r=b(e,r+1,`}`,{slashStartsRegExp:!1}).endIndex+1;continue}r+=e[r]===`\\`?2:1}return e.length}function u(e,t){let n=e.slice(t,t+3);return n===`'''`||n===`"""`?n:e[t]??``}function d(e,t){let n=f(e,t);return n?t-n.length:t}function f(e,t){if(e[t]!==`"`&&e[t]!==`'`)return;let n=t-1;for(;n>=0&&/[A-Za-z]/.test(e[n]??``);)--n;let r=e.slice(n+1,t);if(!(!r||!/^[bfru]+$/i.test(r))&&!(n>=0&&/[\dA-Za-z_]/.test(e[n]??``)))return r}function p(e,t,n,r,i,a){return n.templateSyntax===`kotlin`?m(e,t,a):a.startsWith("`")?v(e,t,a):_(r,i)?y(e,t,a):``}function m(e,t,r){let i=u(r,0).length,a=i===3,o=[],s=i;for(;s<r.length-i;){if(!a&&r[s]===`\\`){s+=2;continue}if(r[s]!==`$`){s+=1;continue}if(r[s+1]===`{`){let i=b(r,s+2,`}`,{slashStartsComments:!0,slashStartsRegExp:!1,supportsKotlinStrings:!0});o.push(n(e,i.content,{removeStrings:!0},t)),s=i.endIndex+1;continue}if(h(r[s+1])){let e=s+2;for(;g(r[e]);)e+=1;o.push(r.slice(s+1,e)),s=e;continue}s+=1}return o.join(`
|
|
2
|
+
`)}function h(e){return e!==void 0&&/[\p{L}_]/u.test(e)}function g(e){return e!==void 0&&/[\p{L}\p{N}_]/u.test(e)}function _(e,t){return f(e,t)?.toLowerCase().includes(`f`)??!1}function v(e,t,r){let i=[],a=1;for(;a<r.length-1;){if(r[a]===`\\`){a+=2;continue}if(r[a]===`$`&&r[a+1]===`{`){let o=b(r,a+2,`}`,{slashStartsRegExp:!0});i.push(n(e,o.content,{removeStrings:!0},t)),a=o.endIndex+1;continue}a+=1}return i.join(`
|
|
3
|
+
`)}function y(e,t,r){let i=u(r,0).length,a=[],o=i;for(;o<r.length-i;){if(r[o]===`{`&&r[o+1]===`{`){o+=2;continue}if(r[o]===`{`){let i=b(r,o+1,`}`,{slashStartsRegExp:!1});a.push(n(e,i.content,{removeStrings:!0},t)),o=i.endIndex+1;continue}o+=r[o]===`\\`?2:1}return a.join(`
|
|
4
|
+
`)}function b(e,t,n,r){let i=1,a=t;for(;a<e.length;){let o=e[a];if(o===`"`&&r.supportsKotlinStrings){a=s(e,a);continue}if(o===`"`||o===`'`||o==="`"){a=x(e,a);continue}if((r.slashStartsComments||r.slashStartsRegExp)&&e[a]===`/`&&e[a+1]===`/`){a=C(e,a);continue}if((r.slashStartsComments||r.slashStartsRegExp)&&e[a]===`/`&&e[a+1]===`*`){a=w(e,a);continue}if(r.slashStartsRegExp&&o===`/`){a=S(e,a);continue}if(o===`{`&&(i+=1),o===n&&(--i,i===0))return{content:e.slice(t,a),endIndex:a};a+=1}return{content:e.slice(t),endIndex:e.length}}function x(e,t){let n=u(e,t),r=t+n.length;for(;r<e.length;){if(e[r]===`\\`){r+=2;continue}if(e.startsWith(n,r))return r+n.length;r+=1}return r}function S(e,t){let n=t+1,r=!1;for(;n<e.length;){if(e[n]===`\\`){n+=2;continue}if(e[n]===`[`&&(r=!0),e[n]===`]`&&(r=!1),e[n]===`/`&&!r){for(n+=1;/[A-Za-z]/.test(e[n]??``);)n+=1;return n}if(e[n]===`
|
|
5
|
+
`)return t+1;n+=1}return t+1}function C(e,t){let n=e.indexOf(`
|
|
6
|
+
`,t+2);return n===-1?e.length:n}function w(e,t){let n=e.indexOf(`*/`,t+2);return n===-1?e.length:n+2}export{t as removeCommentsAndStringsInSourceCode,e as removeCommentsInSourceCode};
|
|
6
7
|
//# sourceMappingURL=removeCommentsInSourceCode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"removeCommentsInSourceCode.js","names":[],"sources":["../../src/helpers/removeCommentsInSourceCode.ts"],"sourcesContent":["import type { LanguageDefinition } from '../types/language.js';\n\nexport type SourceCodeGrammar = NonNullable<LanguageDefinition['grammer']>;\n\n/** Removes comments from source code according to the provided language grammar. */\nexport function removeCommentsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: false });\n}\n\n/** Removes comments and string literal contents while preserving executable interpolation expressions. */\nexport function removeCommentsAndStringsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: true });\n}\n\ninterface CommentOrStringGrammar {\n closeRegExp: RegExp;\n isComment: boolean;\n openRegExp: RegExp;\n}\n\nfunction removeCommentsAndMaybeStringsInSourceCode(\n grammar: SourceCodeGrammar,\n sourceCode: string,\n options: { removeStrings: boolean },\n commentOrStringGrammars = compileCommentOrStringGrammars(grammar)\n): string {\n if (!grammar.comments?.length && (!options.removeStrings || !grammar.strings?.length)) return sourceCode;\n\n const newSourceCodeSlices: string[] = [];\n\n let lastIndex = 0;\n\n while (lastIndex < sourceCode.length) {\n let first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined;\n\n for (const commentOrStringGrammer of commentOrStringGrammars) {\n const startRegExp = commentOrStringGrammer.openRegExp;\n startRegExp.lastIndex = lastIndex;\n\n const match = startRegExp.exec(sourceCode);\n\n if (match && shouldPreferMatch(match, commentOrStringGrammer, first, options)) {\n first = { grammar: commentOrStringGrammer, match };\n }\n }\n\n if (first) {\n let stringPrefixStartIndex = first.match.index;\n if (!first.grammar.isComment && options.removeStrings) {\n stringPrefixStartIndex = getPythonStringPrefixStartIndex(sourceCode, first.match.index);\n }\n newSourceCodeSlices.push(sourceCode.slice(lastIndex, stringPrefixStartIndex));\n\n if (!first.grammar.isComment) {\n lastIndex = findStringEndIndex(sourceCode, first.match.index, first.grammar);\n const stringLiteral = sourceCode.slice(first.match.index, lastIndex);\n if (options.removeStrings) {\n newSourceCodeSlices.push(\n preserveStringInterpolationExpressions(\n grammar,\n commentOrStringGrammars,\n sourceCode,\n first.match.index,\n stringLiteral\n )\n );\n } else {\n newSourceCodeSlices.push(stringLiteral);\n }\n } else {\n const closeRegExp = first.grammar.closeRegExp;\n closeRegExp.lastIndex = first.match.index + first.match[0].length;\n\n const match = closeRegExp.exec(sourceCode);\n\n lastIndex = match ? match.index + match[0].length : sourceCode.length;\n }\n } else {\n newSourceCodeSlices.push(sourceCode.slice(lastIndex));\n lastIndex = sourceCode.length;\n }\n }\n\n return newSourceCodeSlices.join('');\n}\n\nfunction compileCommentOrStringGrammars(grammar: SourceCodeGrammar): readonly CommentOrStringGrammar[] {\n return [\n ...(grammar.comments?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close ?? /(?=\\n)/g),\n isComment: true,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ...(grammar.strings?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close),\n isComment: false,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ] satisfies CommentOrStringGrammar[];\n}\n\nfunction shouldPreferMatch(\n match: RegExpExecArray,\n grammar: CommentOrStringGrammar,\n first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined,\n options: { removeStrings: boolean }\n): boolean {\n if (!first) return true;\n if (match.index < first.match.index) return true;\n if (match.index > first.match.index) return false;\n return options.removeStrings && first.grammar.isComment && !grammar.isComment;\n}\n\nfunction makeGlobalRegExp(regExp: RegExp): RegExp {\n return new RegExp(regExp, regExp.flags.includes('g') ? regExp.flags : `${regExp.flags}g`);\n}\n\nfunction findStringEndIndex(sourceCode: string, stringStartIndex: number, grammar: CommentOrStringGrammar): number {\n if (sourceCode[stringStartIndex] === '`') return findJavaScriptTemplateEndIndex(sourceCode, stringStartIndex);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return findPythonFStringEndIndex(sourceCode, stringStartIndex);\n\n const closeRegExp = grammar.closeRegExp;\n closeRegExp.lastIndex = stringStartIndex + 1;\n const match = closeRegExp.exec(sourceCode);\n return match ? match.index + match[0].length : sourceCode.length;\n}\n\nfunction findJavaScriptTemplateEndIndex(sourceCode: string, stringStartIndex: number): number {\n let index = stringStartIndex + 1;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '`') return index + 1;\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index = readBalancedExpression(sourceCode, index + 2, '}', { slashStartsRegExp: true }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findPythonFStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (sourceCode[index] === '{' && sourceCode[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '{') {\n index = readBalancedExpression(sourceCode, index + 1, '}', { slashStartsRegExp: false }).endIndex + 1;\n continue;\n }\n index += sourceCode[index] === '\\\\' ? 2 : 1;\n }\n\n return sourceCode.length;\n}\n\nfunction getStringQuote(sourceCode: string, stringStartIndex: number): string {\n const threeCharacterQuote = sourceCode.slice(stringStartIndex, stringStartIndex + 3);\n if (threeCharacterQuote === \"'''\" || threeCharacterQuote === '\"\"\"') return threeCharacterQuote;\n return sourceCode[stringStartIndex] ?? '';\n}\n\nfunction getPythonStringPrefixStartIndex(sourceCode: string, stringStartIndex: number): number {\n const prefix = getPythonStringPrefix(sourceCode, stringStartIndex);\n return prefix ? stringStartIndex - prefix.length : stringStartIndex;\n}\n\nfunction getPythonStringPrefix(sourceCode: string, stringStartIndex: number): string | undefined {\n if (sourceCode[stringStartIndex] !== '\"' && sourceCode[stringStartIndex] !== \"'\") return undefined;\n let index = stringStartIndex - 1;\n while (index >= 0 && /[A-Za-z]/.test(sourceCode[index] ?? '')) index -= 1;\n\n const prefix = sourceCode.slice(index + 1, stringStartIndex);\n if (!prefix || !/^[bfru]+$/i.test(prefix)) return undefined;\n if (index >= 0 && /[\\dA-Za-z_]/.test(sourceCode[index] ?? '')) return undefined;\n\n return prefix;\n}\n\nfunction preserveStringInterpolationExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n sourceCode: string,\n stringStartIndex: number,\n stringLiteral: string\n): string {\n if (stringLiteral.startsWith('`'))\n return preserveJavaScriptTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return preservePythonFStringExpressions(grammar, commentOrStringGrammars, stringLiteral);\n return '';\n}\n\nfunction hasPythonFStringPrefix(sourceCode: string, stringStartIndex: number): boolean {\n return getPythonStringPrefix(sourceCode, stringStartIndex)?.toLowerCase().includes('f') ?? false;\n}\n\nfunction preserveJavaScriptTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const expressions: string[] = [];\n let index = 1;\n\n while (index < stringLiteral.length - 1) {\n if (stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '$' && stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', { slashStartsRegExp: true });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction preservePythonFStringExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (stringLiteral[index] === '{' && stringLiteral[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 1, '}', { slashStartsRegExp: false });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += stringLiteral[index] === '\\\\' ? 2 : 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction readBalancedExpression(\n sourceCode: string,\n startIndex: number,\n closeChar: string,\n options: { slashStartsRegExp: boolean }\n): { content: string; endIndex: number } {\n let depth = 1;\n let index = startIndex;\n\n while (index < sourceCode.length) {\n const char = sourceCode[index];\n if (char === '\"' || char === \"'\" || char === '`') {\n index = skipQuotedSpan(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && sourceCode[index] === '/' && sourceCode[index + 1] === '/') {\n index = skipJavaScriptSingleLineComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && sourceCode[index] === '/' && sourceCode[index + 1] === '*') {\n index = skipJavaScriptBlockComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && char === '/') {\n index = skipJavaScriptRegExpLiteral(sourceCode, index);\n continue;\n }\n if (char === '{') depth += 1;\n if (char === closeChar) {\n depth -= 1;\n if (depth === 0) return { content: sourceCode.slice(startIndex, index), endIndex: index };\n }\n index += 1;\n }\n\n return { content: sourceCode.slice(startIndex), endIndex: sourceCode.length };\n}\n\nfunction skipQuotedSpan(sourceCode: string, startIndex: number): number {\n const quote = getStringQuote(sourceCode, startIndex);\n let index = startIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n index += 1;\n }\n\n return index;\n}\n\nfunction skipJavaScriptRegExpLiteral(sourceCode: string, startIndex: number): number {\n let index = startIndex + 1;\n let inCharacterClass = false;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '[') inCharacterClass = true;\n if (sourceCode[index] === ']') inCharacterClass = false;\n if (sourceCode[index] === '/' && !inCharacterClass) {\n index += 1;\n while (/[A-Za-z]/.test(sourceCode[index] ?? '')) index += 1;\n return index;\n }\n if (sourceCode[index] === '\\n') return startIndex + 1;\n index += 1;\n }\n\n return startIndex + 1;\n}\n\nfunction skipJavaScriptSingleLineComment(sourceCode: string, startIndex: number): number {\n const newLineIndex = sourceCode.indexOf('\\n', startIndex + 2);\n return newLineIndex === -1 ? sourceCode.length : newLineIndex;\n}\n\nfunction skipJavaScriptBlockComment(sourceCode: string, startIndex: number): number {\n const endIndex = sourceCode.indexOf('*/', startIndex + 2);\n return endIndex === -1 ? sourceCode.length : endIndex + 2;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"removeCommentsInSourceCode.js","names":[],"sources":["../../src/helpers/removeCommentsInSourceCode.ts"],"sourcesContent":["import type { LanguageDefinition } from '../types/language.js';\n\nexport type SourceCodeGrammar = NonNullable<LanguageDefinition['grammer']>;\n\n/** Removes comments from source code according to the provided language grammar. */\nexport function removeCommentsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: false });\n}\n\n/** Removes comments and string literal contents while preserving executable interpolation expressions. */\nexport function removeCommentsAndStringsInSourceCode(grammar: SourceCodeGrammar, sourceCode: string): string {\n return removeCommentsAndMaybeStringsInSourceCode(grammar, sourceCode, { removeStrings: true });\n}\n\ninterface CommentOrStringGrammar {\n closeRegExp: RegExp;\n isComment: boolean;\n openRegExp: RegExp;\n templateSyntax?: 'kotlin';\n}\n\ninterface BalancedExpressionOptions {\n slashStartsComments?: boolean;\n slashStartsRegExp: boolean;\n supportsKotlinStrings?: boolean;\n}\n\nfunction removeCommentsAndMaybeStringsInSourceCode(\n grammar: SourceCodeGrammar,\n sourceCode: string,\n options: { removeStrings: boolean },\n commentOrStringGrammars = compileCommentOrStringGrammars(grammar)\n): string {\n if (!grammar.comments?.length && (!options.removeStrings || !grammar.strings?.length)) return sourceCode;\n\n const newSourceCodeSlices: string[] = [];\n\n let lastIndex = 0;\n\n while (lastIndex < sourceCode.length) {\n let first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined;\n\n for (const commentOrStringGrammer of commentOrStringGrammars) {\n const startRegExp = commentOrStringGrammer.openRegExp;\n startRegExp.lastIndex = lastIndex;\n\n const match = startRegExp.exec(sourceCode);\n\n if (match && shouldPreferMatch(match, commentOrStringGrammer, first, options)) {\n first = { grammar: commentOrStringGrammer, match };\n }\n }\n\n if (first) {\n let stringPrefixStartIndex = first.match.index;\n if (!first.grammar.isComment && options.removeStrings) {\n stringPrefixStartIndex = getPythonStringPrefixStartIndex(sourceCode, first.match.index);\n }\n newSourceCodeSlices.push(sourceCode.slice(lastIndex, stringPrefixStartIndex));\n\n if (!first.grammar.isComment) {\n lastIndex = findStringEndIndex(sourceCode, first.match.index, first.grammar);\n const stringLiteral = sourceCode.slice(first.match.index, lastIndex);\n if (options.removeStrings) {\n newSourceCodeSlices.push(\n preserveStringInterpolationExpressions(\n grammar,\n commentOrStringGrammars,\n first.grammar,\n sourceCode,\n first.match.index,\n stringLiteral\n )\n );\n } else {\n newSourceCodeSlices.push(stringLiteral);\n }\n } else {\n const closeRegExp = first.grammar.closeRegExp;\n closeRegExp.lastIndex = first.match.index + first.match[0].length;\n\n const match = closeRegExp.exec(sourceCode);\n\n lastIndex = match ? match.index + match[0].length : sourceCode.length;\n }\n } else {\n newSourceCodeSlices.push(sourceCode.slice(lastIndex));\n lastIndex = sourceCode.length;\n }\n }\n\n return newSourceCodeSlices.join('');\n}\n\nfunction compileCommentOrStringGrammars(grammar: SourceCodeGrammar): readonly CommentOrStringGrammar[] {\n return [\n ...(grammar.comments?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close ?? /(?=\\n)/g),\n isComment: true,\n openRegExp: makeGlobalRegExp(v.open),\n })) ?? []),\n ...(grammar.strings?.map((v) => ({\n closeRegExp: makeGlobalRegExp(v.close),\n isComment: false,\n openRegExp: makeGlobalRegExp(v.open),\n templateSyntax: v.templateSyntax,\n })) ?? []),\n ] satisfies CommentOrStringGrammar[];\n}\n\nfunction shouldPreferMatch(\n match: RegExpExecArray,\n grammar: CommentOrStringGrammar,\n first: { grammar: CommentOrStringGrammar; match: RegExpExecArray } | undefined,\n options: { removeStrings: boolean }\n): boolean {\n if (!first) return true;\n if (match.index < first.match.index) return true;\n if (match.index > first.match.index) return false;\n return options.removeStrings && first.grammar.isComment && !grammar.isComment;\n}\n\nfunction makeGlobalRegExp(regExp: RegExp): RegExp {\n return new RegExp(regExp, regExp.flags.includes('g') ? regExp.flags : `${regExp.flags}g`);\n}\n\nfunction findStringEndIndex(sourceCode: string, stringStartIndex: number, grammar: CommentOrStringGrammar): number {\n if (grammar.templateSyntax === 'kotlin') return findKotlinStringEndIndex(sourceCode, stringStartIndex);\n if (sourceCode[stringStartIndex] === '`') return findJavaScriptTemplateEndIndex(sourceCode, stringStartIndex);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return findPythonFStringEndIndex(sourceCode, stringStartIndex);\n\n const closeRegExp = grammar.closeRegExp;\n closeRegExp.lastIndex = stringStartIndex + 1;\n const match = closeRegExp.exec(sourceCode);\n return match ? match.index + match[0].length : sourceCode.length;\n}\n\nfunction findKotlinStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n const isRawString = quote.length === 3;\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (!isRawString && sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index =\n readBalancedExpression(sourceCode, index + 2, '}', {\n slashStartsComments: true,\n slashStartsRegExp: false,\n supportsKotlinStrings: true,\n }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findJavaScriptTemplateEndIndex(sourceCode: string, stringStartIndex: number): number {\n let index = stringStartIndex + 1;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '`') return index + 1;\n if (sourceCode[index] === '$' && sourceCode[index + 1] === '{') {\n index = readBalancedExpression(sourceCode, index + 2, '}', { slashStartsRegExp: true }).endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return sourceCode.length;\n}\n\nfunction findPythonFStringEndIndex(sourceCode: string, stringStartIndex: number): number {\n const quote = getStringQuote(sourceCode, stringStartIndex);\n let index = stringStartIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n if (sourceCode[index] === '{' && sourceCode[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '{') {\n index = readBalancedExpression(sourceCode, index + 1, '}', { slashStartsRegExp: false }).endIndex + 1;\n continue;\n }\n index += sourceCode[index] === '\\\\' ? 2 : 1;\n }\n\n return sourceCode.length;\n}\n\nfunction getStringQuote(sourceCode: string, stringStartIndex: number): string {\n const threeCharacterQuote = sourceCode.slice(stringStartIndex, stringStartIndex + 3);\n if (threeCharacterQuote === \"'''\" || threeCharacterQuote === '\"\"\"') return threeCharacterQuote;\n return sourceCode[stringStartIndex] ?? '';\n}\n\nfunction getPythonStringPrefixStartIndex(sourceCode: string, stringStartIndex: number): number {\n const prefix = getPythonStringPrefix(sourceCode, stringStartIndex);\n return prefix ? stringStartIndex - prefix.length : stringStartIndex;\n}\n\nfunction getPythonStringPrefix(sourceCode: string, stringStartIndex: number): string | undefined {\n if (sourceCode[stringStartIndex] !== '\"' && sourceCode[stringStartIndex] !== \"'\") return undefined;\n let index = stringStartIndex - 1;\n while (index >= 0 && /[A-Za-z]/.test(sourceCode[index] ?? '')) index -= 1;\n\n const prefix = sourceCode.slice(index + 1, stringStartIndex);\n if (!prefix || !/^[bfru]+$/i.test(prefix)) return undefined;\n if (index >= 0 && /[\\dA-Za-z_]/.test(sourceCode[index] ?? '')) return undefined;\n\n return prefix;\n}\n\nfunction preserveStringInterpolationExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringGrammar: CommentOrStringGrammar,\n sourceCode: string,\n stringStartIndex: number,\n stringLiteral: string\n): string {\n if (stringGrammar.templateSyntax === 'kotlin')\n return preserveKotlinStringTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (stringLiteral.startsWith('`'))\n return preserveJavaScriptTemplateExpressions(grammar, commentOrStringGrammars, stringLiteral);\n if (hasPythonFStringPrefix(sourceCode, stringStartIndex))\n return preservePythonFStringExpressions(grammar, commentOrStringGrammars, stringLiteral);\n return '';\n}\n\nfunction preserveKotlinStringTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const isRawString = quoteLength === 3;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (!isRawString && stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] !== '$') {\n index += 1;\n continue;\n }\n if (stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', {\n slashStartsComments: true,\n slashStartsRegExp: false,\n supportsKotlinStrings: true,\n });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n if (isKotlinIdentifierStart(stringLiteral[index + 1])) {\n let endIndex = index + 2;\n while (isKotlinIdentifierPart(stringLiteral[endIndex])) endIndex += 1;\n expressions.push(stringLiteral.slice(index + 1, endIndex));\n index = endIndex;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction isKotlinIdentifierStart(character: string | undefined): boolean {\n return character !== undefined && /[\\p{L}_]/u.test(character);\n}\n\nfunction isKotlinIdentifierPart(character: string | undefined): boolean {\n return character !== undefined && /[\\p{L}\\p{N}_]/u.test(character);\n}\n\nfunction hasPythonFStringPrefix(sourceCode: string, stringStartIndex: number): boolean {\n return getPythonStringPrefix(sourceCode, stringStartIndex)?.toLowerCase().includes('f') ?? false;\n}\n\nfunction preserveJavaScriptTemplateExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const expressions: string[] = [];\n let index = 1;\n\n while (index < stringLiteral.length - 1) {\n if (stringLiteral[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '$' && stringLiteral[index + 1] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 2, '}', { slashStartsRegExp: true });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction preservePythonFStringExpressions(\n grammar: SourceCodeGrammar,\n commentOrStringGrammars: readonly CommentOrStringGrammar[],\n stringLiteral: string\n): string {\n const quoteLength = getStringQuote(stringLiteral, 0).length;\n const expressions: string[] = [];\n let index = quoteLength;\n\n while (index < stringLiteral.length - quoteLength) {\n if (stringLiteral[index] === '{' && stringLiteral[index + 1] === '{') {\n index += 2;\n continue;\n }\n if (stringLiteral[index] === '{') {\n const expression = readBalancedExpression(stringLiteral, index + 1, '}', { slashStartsRegExp: false });\n expressions.push(\n removeCommentsAndMaybeStringsInSourceCode(\n grammar,\n expression.content,\n { removeStrings: true },\n commentOrStringGrammars\n )\n );\n index = expression.endIndex + 1;\n continue;\n }\n index += stringLiteral[index] === '\\\\' ? 2 : 1;\n }\n\n return expressions.join('\\n');\n}\n\nfunction readBalancedExpression(\n sourceCode: string,\n startIndex: number,\n closeChar: string,\n options: BalancedExpressionOptions\n): { content: string; endIndex: number } {\n let depth = 1;\n let index = startIndex;\n\n while (index < sourceCode.length) {\n const char = sourceCode[index];\n if (char === '\"' && options.supportsKotlinStrings) {\n index = findKotlinStringEndIndex(sourceCode, index);\n continue;\n }\n if (char === '\"' || char === \"'\" || char === '`') {\n index = skipQuotedSpan(sourceCode, index);\n continue;\n }\n if (\n (options.slashStartsComments || options.slashStartsRegExp) &&\n sourceCode[index] === '/' &&\n sourceCode[index + 1] === '/'\n ) {\n index = skipJavaScriptSingleLineComment(sourceCode, index);\n continue;\n }\n if (\n (options.slashStartsComments || options.slashStartsRegExp) &&\n sourceCode[index] === '/' &&\n sourceCode[index + 1] === '*'\n ) {\n index = skipJavaScriptBlockComment(sourceCode, index);\n continue;\n }\n if (options.slashStartsRegExp && char === '/') {\n index = skipJavaScriptRegExpLiteral(sourceCode, index);\n continue;\n }\n if (char === '{') depth += 1;\n if (char === closeChar) {\n depth -= 1;\n if (depth === 0) return { content: sourceCode.slice(startIndex, index), endIndex: index };\n }\n index += 1;\n }\n\n return { content: sourceCode.slice(startIndex), endIndex: sourceCode.length };\n}\n\nfunction skipQuotedSpan(sourceCode: string, startIndex: number): number {\n const quote = getStringQuote(sourceCode, startIndex);\n let index = startIndex + quote.length;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode.startsWith(quote, index)) return index + quote.length;\n index += 1;\n }\n\n return index;\n}\n\nfunction skipJavaScriptRegExpLiteral(sourceCode: string, startIndex: number): number {\n let index = startIndex + 1;\n let inCharacterClass = false;\n\n while (index < sourceCode.length) {\n if (sourceCode[index] === '\\\\') {\n index += 2;\n continue;\n }\n if (sourceCode[index] === '[') inCharacterClass = true;\n if (sourceCode[index] === ']') inCharacterClass = false;\n if (sourceCode[index] === '/' && !inCharacterClass) {\n index += 1;\n while (/[A-Za-z]/.test(sourceCode[index] ?? '')) index += 1;\n return index;\n }\n if (sourceCode[index] === '\\n') return startIndex + 1;\n index += 1;\n }\n\n return startIndex + 1;\n}\n\nfunction skipJavaScriptSingleLineComment(sourceCode: string, startIndex: number): number {\n const newLineIndex = sourceCode.indexOf('\\n', startIndex + 2);\n return newLineIndex === -1 ? sourceCode.length : newLineIndex;\n}\n\nfunction skipJavaScriptBlockComment(sourceCode: string, startIndex: number): number {\n const endIndex = sourceCode.indexOf('*/', startIndex + 2);\n return endIndex === -1 ? sourceCode.length : endIndex + 2;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.cjs","names":["z","parseArgs","readProblemMarkdownFrontMatter","readTestCases","path","judgeByStaticAnalysis","findEntryPointFile","DecisionCode","findLanguageDefinitionByPath","spawnSyncWithTimeout","snapshotWorkingDirectory","copyTestCaseFileInput","readOutputFiles","compareStdoutAsSpaceSeparatedTokens","fs","isSafeSubmissionOutputPath","cleanWorkingDirectory"],"sources":["../../src/presets/stdio.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { z } from 'zod';\n\nimport { cleanWorkingDirectory, snapshotWorkingDirectory } from '../helpers/cleanWorkingDirectory.js';\nimport { compareStdoutAsSpaceSeparatedTokens } from '../helpers/compareStdoutAsSpaceSeparatedTokens.js';\nimport { copyTestCaseFileInput } from '../helpers/copyTestCaseFileInput.js';\nimport { findEntryPointFile } from '../helpers/findEntryPointFile.js';\nimport { findLanguageDefinitionByPath } from '../helpers/findLanguageDefinitionByPath.js';\nimport { judgeByStaticAnalysis } from '../helpers/judgeByStaticAnalysis.js';\nimport { parseArgs } from '../helpers/parseArgs.js';\nimport { printTestCaseResult } from '../helpers/printTestCaseResult.js';\nimport { isSafeSubmissionOutputPath, readOutputFiles } from '../helpers/readOutputFiles.js';\nimport { makeAccessibleToSandboxUser } from '../helpers/sandboxUser.js';\nimport { readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { spawnSyncWithTimeout } from '../helpers/spawnSyncWithTimeout.js';\nimport { DecisionCode } from '../types/decisionCode.js';\n\nconst BUILD_TIMEOUT_SECONDS = 10;\nconst JUDGE_DEFAULT_TIMEOUT_SECONDS = 2;\nconst DEBUG_DEFAULT_TIMEOUT_SECONDS = 10;\n\nconst MAX_STDOUT_LENGTH = 50_000;\n\nconst judgeParamsSchema = z.object({\n language: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nconst debugParamsSchema = judgeParamsSchema.extend({\n stdin: z.string().optional(),\n});\n\n/**\n * A preset judge function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `judge.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `judge.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `judge.ts`:\n * ```bash\n * bun x exercode judge model_answers/java\n * ```\n *\n * Run with the optional parameters:\n * ```bash\n * bun x exercode judge model_answers/java '{ \"language\": \"javascript\" }'\n * ```\n */\nexport async function stdioJudgePreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = judgeParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n\n const staticAnalysisTestCaseResult = await judgeByStaticAnalysis(args.cwd, problemMarkdownFrontMatter);\n if (staticAnalysisTestCaseResult) {\n printTestCaseResult({ testCaseId: testCases[0]?.id ?? 'prebuild', ...staticAnalysisTestCaseResult });\n return;\n }\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const cwdSnapshot = await snapshotWorkingDirectory(args.cwd);\n\n if (testCases.length === 0) {\n printTestCaseResult({ testCaseId: 'default', decisionCode: DecisionCode.ACCEPTED });\n }\n\n for (const testCase of testCases) {\n // prepare test case\n if (testCases.shared?.fileInputPath) await copyTestCaseFileInput(testCases.shared.fileInputPath, args.cwd);\n if (testCase.fileInputPath) await copyTestCaseFileInput(testCase.fileInputPath, args.cwd);\n\n // run\n const timeoutSeconds =\n typeof problemMarkdownFrontMatter.timeLimitMs === 'number'\n ? problemMarkdownFrontMatter.timeLimitMs / 1000\n : JUDGE_DEFAULT_TIMEOUT_SECONDS;\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: testCase.input, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n // calculate decision\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n } else if (!compareStdoutAsSpaceSeparatedTokens(spawnResult.stdout, testCase.output ?? '')) {\n decisionCode = DecisionCode.WRONG_ANSWER;\n } else if (testCase.fileOutputPath) {\n const dirents = await fs.promises.readdir(testCase.fileOutputPath, { withFileTypes: true, recursive: true });\n for (const dirent of dirents) {\n if (!dirent.isFile()) continue;\n const direntRelativePath = path.relative(testCase.fileOutputPath, dirent.parentPath);\n const expected = await fs.promises.readFile(path.join(dirent.parentPath, dirent.name));\n try {\n const receivedPath = path.join(args.cwd, direntRelativePath, dirent.name);\n // A submission-planted symlink to the expected file itself would otherwise compare equal.\n if (!(await isSafeSubmissionOutputPath(args.cwd, receivedPath))) throw new Error('unsafe output path');\n const received = await fs.promises.readFile(receivedPath);\n if (received.compare(expected) !== 0) decisionCode = DecisionCode.WRONG_ANSWER;\n } catch (error) {\n console.error(error);\n decisionCode = DecisionCode.WRONG_ANSWER;\n }\n }\n }\n\n printTestCaseResult({\n testCaseId: testCase.id,\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: testCase.input,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n\n // clean up\n await cleanWorkingDirectory(args.cwd, cwdSnapshot);\n\n if (decisionCode !== DecisionCode.ACCEPTED) break;\n }\n}\n\n/**\n * A preset debug function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `debug.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `debug.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `debug.ts`:\n * ```bash\n * bun x exercode debug model_answers/java '{ \"stdin\": \"1 2\" }'\n * ```\n */\nexport async function stdioDebugPreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = debugParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n {\n const timeoutSeconds = Math.max(\n DEBUG_DEFAULT_TIMEOUT_SECONDS,\n (problemMarkdownFrontMatter.timeLimitMs ?? 0) / 1000\n );\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: params.stdin, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n }\n\n printTestCaseResult({\n testCaseId: 'debug',\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: params.stdin,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stdio.cjs","names":["z","parseArgs","readProblemMarkdownFrontMatter","readTestCases","path","judgeByStaticAnalysis","findEntryPointFile","DecisionCode","findLanguageDefinitionByPath","spawnSyncWithTimeout","snapshotWorkingDirectory","copyTestCaseFileInput","readOutputFiles","compareStdoutAsSpaceSeparatedTokens","fs","isSafeSubmissionOutputPath","cleanWorkingDirectory"],"sources":["../../src/presets/stdio.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { z } from 'zod';\n\nimport { cleanWorkingDirectory, snapshotWorkingDirectory } from '../helpers/cleanWorkingDirectory.js';\nimport { compareStdoutAsSpaceSeparatedTokens } from '../helpers/compareStdoutAsSpaceSeparatedTokens.js';\nimport { copyTestCaseFileInput } from '../helpers/copyTestCaseFileInput.js';\nimport { findEntryPointFile } from '../helpers/findEntryPointFile.js';\nimport { findLanguageDefinitionByPath } from '../helpers/findLanguageDefinitionByPath.js';\nimport { judgeByStaticAnalysis } from '../helpers/judgeByStaticAnalysis.js';\nimport { parseArgs } from '../helpers/parseArgs.js';\nimport { printTestCaseResult } from '../helpers/printTestCaseResult.js';\nimport { isSafeSubmissionOutputPath, readOutputFiles } from '../helpers/readOutputFiles.js';\nimport { makeAccessibleToSandboxUser } from '../helpers/sandboxUser.js';\nimport { readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { spawnSyncWithTimeout } from '../helpers/spawnSyncWithTimeout.js';\nimport { DecisionCode } from '../types/decisionCode.js';\n\nconst BUILD_TIMEOUT_SECONDS = 10;\nconst JUDGE_DEFAULT_TIMEOUT_SECONDS = 2;\nconst DEBUG_DEFAULT_TIMEOUT_SECONDS = 10;\n\nconst MAX_STDOUT_LENGTH = 50_000;\n\nconst judgeParamsSchema = z.object({\n language: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nconst debugParamsSchema = judgeParamsSchema.extend({\n stdin: z.string().optional(),\n});\n\n/**\n * A preset judge function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `judge.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `judge.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `judge.ts`:\n * ```bash\n * bun x exercode-problem judge model_answers/java\n * ```\n *\n * Run with the optional parameters:\n * ```bash\n * bun x exercode-problem judge model_answers/java '{ \"language\": \"javascript\" }'\n * ```\n */\nexport async function stdioJudgePreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = judgeParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n\n const staticAnalysisTestCaseResult = await judgeByStaticAnalysis(args.cwd, problemMarkdownFrontMatter);\n if (staticAnalysisTestCaseResult) {\n printTestCaseResult({ testCaseId: testCases[0]?.id ?? 'prebuild', ...staticAnalysisTestCaseResult });\n return;\n }\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const cwdSnapshot = await snapshotWorkingDirectory(args.cwd);\n\n if (testCases.length === 0) {\n printTestCaseResult({ testCaseId: 'default', decisionCode: DecisionCode.ACCEPTED });\n }\n\n for (const testCase of testCases) {\n // prepare test case\n if (testCases.shared?.fileInputPath) await copyTestCaseFileInput(testCases.shared.fileInputPath, args.cwd);\n if (testCase.fileInputPath) await copyTestCaseFileInput(testCase.fileInputPath, args.cwd);\n\n // run\n const timeoutSeconds =\n typeof problemMarkdownFrontMatter.timeLimitMs === 'number'\n ? problemMarkdownFrontMatter.timeLimitMs / 1000\n : JUDGE_DEFAULT_TIMEOUT_SECONDS;\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: testCase.input, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n // calculate decision\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n } else if (!compareStdoutAsSpaceSeparatedTokens(spawnResult.stdout, testCase.output ?? '')) {\n decisionCode = DecisionCode.WRONG_ANSWER;\n } else if (testCase.fileOutputPath) {\n const dirents = await fs.promises.readdir(testCase.fileOutputPath, { withFileTypes: true, recursive: true });\n for (const dirent of dirents) {\n if (!dirent.isFile()) continue;\n const direntRelativePath = path.relative(testCase.fileOutputPath, dirent.parentPath);\n const expected = await fs.promises.readFile(path.join(dirent.parentPath, dirent.name));\n try {\n const receivedPath = path.join(args.cwd, direntRelativePath, dirent.name);\n // A submission-planted symlink to the expected file itself would otherwise compare equal.\n if (!(await isSafeSubmissionOutputPath(args.cwd, receivedPath))) throw new Error('unsafe output path');\n const received = await fs.promises.readFile(receivedPath);\n if (received.compare(expected) !== 0) decisionCode = DecisionCode.WRONG_ANSWER;\n } catch (error) {\n console.error(error);\n decisionCode = DecisionCode.WRONG_ANSWER;\n }\n }\n }\n\n printTestCaseResult({\n testCaseId: testCase.id,\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: testCase.input,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n\n // clean up\n await cleanWorkingDirectory(args.cwd, cwdSnapshot);\n\n if (decisionCode !== DecisionCode.ACCEPTED) break;\n }\n}\n\n/**\n * A preset debug function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `debug.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `debug.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `debug.ts`:\n * ```bash\n * bun x exercode-problem debug model_answers/java '{ \"stdin\": \"1 2\" }'\n * ```\n */\nexport async function stdioDebugPreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = debugParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n {\n const timeoutSeconds = Math.max(\n DEBUG_DEFAULT_TIMEOUT_SECONDS,\n (problemMarkdownFrontMatter.timeLimitMs ?? 0) / 1000\n );\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: params.stdin, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n }\n\n printTestCaseResult({\n testCaseId: 'debug',\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: params.stdin,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/presets/stdio.d.ts
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* @example
|
|
9
9
|
* Run in a problem directory without `judge.ts`:
|
|
10
10
|
* ```bash
|
|
11
|
-
* bun x exercode judge model_answers/java
|
|
11
|
+
* bun x exercode-problem judge model_answers/java
|
|
12
12
|
* ```
|
|
13
13
|
*
|
|
14
14
|
* Run with the optional parameters:
|
|
15
15
|
* ```bash
|
|
16
|
-
* bun x exercode judge model_answers/java '{ "language": "javascript" }'
|
|
16
|
+
* bun x exercode-problem judge model_answers/java '{ "language": "javascript" }'
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export declare function stdioJudgePreset(problemDir: string): Promise<void>;
|
|
@@ -27,7 +27,7 @@ export declare function stdioJudgePreset(problemDir: string): Promise<void>;
|
|
|
27
27
|
* @example
|
|
28
28
|
* Run in a problem directory without `debug.ts`:
|
|
29
29
|
* ```bash
|
|
30
|
-
* bun x exercode debug model_answers/java '{ "stdin": "1 2" }'
|
|
30
|
+
* bun x exercode-problem debug model_answers/java '{ "stdin": "1 2" }'
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
export declare function stdioDebugPreset(problemDir: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.js","names":[],"sources":["../../src/presets/stdio.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { z } from 'zod';\n\nimport { cleanWorkingDirectory, snapshotWorkingDirectory } from '../helpers/cleanWorkingDirectory.js';\nimport { compareStdoutAsSpaceSeparatedTokens } from '../helpers/compareStdoutAsSpaceSeparatedTokens.js';\nimport { copyTestCaseFileInput } from '../helpers/copyTestCaseFileInput.js';\nimport { findEntryPointFile } from '../helpers/findEntryPointFile.js';\nimport { findLanguageDefinitionByPath } from '../helpers/findLanguageDefinitionByPath.js';\nimport { judgeByStaticAnalysis } from '../helpers/judgeByStaticAnalysis.js';\nimport { parseArgs } from '../helpers/parseArgs.js';\nimport { printTestCaseResult } from '../helpers/printTestCaseResult.js';\nimport { isSafeSubmissionOutputPath, readOutputFiles } from '../helpers/readOutputFiles.js';\nimport { makeAccessibleToSandboxUser } from '../helpers/sandboxUser.js';\nimport { readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { spawnSyncWithTimeout } from '../helpers/spawnSyncWithTimeout.js';\nimport { DecisionCode } from '../types/decisionCode.js';\n\nconst BUILD_TIMEOUT_SECONDS = 10;\nconst JUDGE_DEFAULT_TIMEOUT_SECONDS = 2;\nconst DEBUG_DEFAULT_TIMEOUT_SECONDS = 10;\n\nconst MAX_STDOUT_LENGTH = 50_000;\n\nconst judgeParamsSchema = z.object({\n language: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nconst debugParamsSchema = judgeParamsSchema.extend({\n stdin: z.string().optional(),\n});\n\n/**\n * A preset judge function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `judge.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `judge.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `judge.ts`:\n * ```bash\n * bun x exercode judge model_answers/java\n * ```\n *\n * Run with the optional parameters:\n * ```bash\n * bun x exercode judge model_answers/java '{ \"language\": \"javascript\" }'\n * ```\n */\nexport async function stdioJudgePreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = judgeParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n\n const staticAnalysisTestCaseResult = await judgeByStaticAnalysis(args.cwd, problemMarkdownFrontMatter);\n if (staticAnalysisTestCaseResult) {\n printTestCaseResult({ testCaseId: testCases[0]?.id ?? 'prebuild', ...staticAnalysisTestCaseResult });\n return;\n }\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const cwdSnapshot = await snapshotWorkingDirectory(args.cwd);\n\n if (testCases.length === 0) {\n printTestCaseResult({ testCaseId: 'default', decisionCode: DecisionCode.ACCEPTED });\n }\n\n for (const testCase of testCases) {\n // prepare test case\n if (testCases.shared?.fileInputPath) await copyTestCaseFileInput(testCases.shared.fileInputPath, args.cwd);\n if (testCase.fileInputPath) await copyTestCaseFileInput(testCase.fileInputPath, args.cwd);\n\n // run\n const timeoutSeconds =\n typeof problemMarkdownFrontMatter.timeLimitMs === 'number'\n ? problemMarkdownFrontMatter.timeLimitMs / 1000\n : JUDGE_DEFAULT_TIMEOUT_SECONDS;\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: testCase.input, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n // calculate decision\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n } else if (!compareStdoutAsSpaceSeparatedTokens(spawnResult.stdout, testCase.output ?? '')) {\n decisionCode = DecisionCode.WRONG_ANSWER;\n } else if (testCase.fileOutputPath) {\n const dirents = await fs.promises.readdir(testCase.fileOutputPath, { withFileTypes: true, recursive: true });\n for (const dirent of dirents) {\n if (!dirent.isFile()) continue;\n const direntRelativePath = path.relative(testCase.fileOutputPath, dirent.parentPath);\n const expected = await fs.promises.readFile(path.join(dirent.parentPath, dirent.name));\n try {\n const receivedPath = path.join(args.cwd, direntRelativePath, dirent.name);\n // A submission-planted symlink to the expected file itself would otherwise compare equal.\n if (!(await isSafeSubmissionOutputPath(args.cwd, receivedPath))) throw new Error('unsafe output path');\n const received = await fs.promises.readFile(receivedPath);\n if (received.compare(expected) !== 0) decisionCode = DecisionCode.WRONG_ANSWER;\n } catch (error) {\n console.error(error);\n decisionCode = DecisionCode.WRONG_ANSWER;\n }\n }\n }\n\n printTestCaseResult({\n testCaseId: testCase.id,\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: testCase.input,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n\n // clean up\n await cleanWorkingDirectory(args.cwd, cwdSnapshot);\n\n if (decisionCode !== DecisionCode.ACCEPTED) break;\n }\n}\n\n/**\n * A preset debug function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `debug.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `debug.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `debug.ts`:\n * ```bash\n * bun x exercode debug model_answers/java '{ \"stdin\": \"1 2\" }'\n * ```\n */\nexport async function stdioDebugPreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = debugParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n {\n const timeoutSeconds = Math.max(\n DEBUG_DEFAULT_TIMEOUT_SECONDS,\n (problemMarkdownFrontMatter.timeLimitMs ?? 0) / 1000\n );\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: params.stdin, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n }\n\n printTestCaseResult({\n testCaseId: 'debug',\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: params.stdin,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stdio.js","names":[],"sources":["../../src/presets/stdio.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { z } from 'zod';\n\nimport { cleanWorkingDirectory, snapshotWorkingDirectory } from '../helpers/cleanWorkingDirectory.js';\nimport { compareStdoutAsSpaceSeparatedTokens } from '../helpers/compareStdoutAsSpaceSeparatedTokens.js';\nimport { copyTestCaseFileInput } from '../helpers/copyTestCaseFileInput.js';\nimport { findEntryPointFile } from '../helpers/findEntryPointFile.js';\nimport { findLanguageDefinitionByPath } from '../helpers/findLanguageDefinitionByPath.js';\nimport { judgeByStaticAnalysis } from '../helpers/judgeByStaticAnalysis.js';\nimport { parseArgs } from '../helpers/parseArgs.js';\nimport { printTestCaseResult } from '../helpers/printTestCaseResult.js';\nimport { isSafeSubmissionOutputPath, readOutputFiles } from '../helpers/readOutputFiles.js';\nimport { makeAccessibleToSandboxUser } from '../helpers/sandboxUser.js';\nimport { readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { spawnSyncWithTimeout } from '../helpers/spawnSyncWithTimeout.js';\nimport { DecisionCode } from '../types/decisionCode.js';\n\nconst BUILD_TIMEOUT_SECONDS = 10;\nconst JUDGE_DEFAULT_TIMEOUT_SECONDS = 2;\nconst DEBUG_DEFAULT_TIMEOUT_SECONDS = 10;\n\nconst MAX_STDOUT_LENGTH = 50_000;\n\nconst judgeParamsSchema = z.object({\n language: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nconst debugParamsSchema = judgeParamsSchema.extend({\n stdin: z.string().optional(),\n});\n\n/**\n * A preset judge function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `judge.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `judge.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `judge.ts`:\n * ```bash\n * bun x exercode-problem judge model_answers/java\n * ```\n *\n * Run with the optional parameters:\n * ```bash\n * bun x exercode-problem judge model_answers/java '{ \"language\": \"javascript\" }'\n * ```\n */\nexport async function stdioJudgePreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = judgeParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n\n const staticAnalysisTestCaseResult = await judgeByStaticAnalysis(args.cwd, problemMarkdownFrontMatter);\n if (staticAnalysisTestCaseResult) {\n printTestCaseResult({ testCaseId: testCases[0]?.id ?? 'prebuild', ...staticAnalysisTestCaseResult });\n return;\n }\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: testCases[0]?.id ?? 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const cwdSnapshot = await snapshotWorkingDirectory(args.cwd);\n\n if (testCases.length === 0) {\n printTestCaseResult({ testCaseId: 'default', decisionCode: DecisionCode.ACCEPTED });\n }\n\n for (const testCase of testCases) {\n // prepare test case\n if (testCases.shared?.fileInputPath) await copyTestCaseFileInput(testCases.shared.fileInputPath, args.cwd);\n if (testCase.fileInputPath) await copyTestCaseFileInput(testCase.fileInputPath, args.cwd);\n\n // run\n const timeoutSeconds =\n typeof problemMarkdownFrontMatter.timeLimitMs === 'number'\n ? problemMarkdownFrontMatter.timeLimitMs / 1000\n : JUDGE_DEFAULT_TIMEOUT_SECONDS;\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: testCase.input, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n // calculate decision\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n } else if (!compareStdoutAsSpaceSeparatedTokens(spawnResult.stdout, testCase.output ?? '')) {\n decisionCode = DecisionCode.WRONG_ANSWER;\n } else if (testCase.fileOutputPath) {\n const dirents = await fs.promises.readdir(testCase.fileOutputPath, { withFileTypes: true, recursive: true });\n for (const dirent of dirents) {\n if (!dirent.isFile()) continue;\n const direntRelativePath = path.relative(testCase.fileOutputPath, dirent.parentPath);\n const expected = await fs.promises.readFile(path.join(dirent.parentPath, dirent.name));\n try {\n const receivedPath = path.join(args.cwd, direntRelativePath, dirent.name);\n // A submission-planted symlink to the expected file itself would otherwise compare equal.\n if (!(await isSafeSubmissionOutputPath(args.cwd, receivedPath))) throw new Error('unsafe output path');\n const received = await fs.promises.readFile(receivedPath);\n if (received.compare(expected) !== 0) decisionCode = DecisionCode.WRONG_ANSWER;\n } catch (error) {\n console.error(error);\n decisionCode = DecisionCode.WRONG_ANSWER;\n }\n }\n }\n\n printTestCaseResult({\n testCaseId: testCase.id,\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: testCase.input,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n\n // clean up\n await cleanWorkingDirectory(args.cwd, cwdSnapshot);\n\n if (decisionCode !== DecisionCode.ACCEPTED) break;\n }\n}\n\n/**\n * A preset debug function using stdin and stdout as test cases.\n *\n * A standard stdio problem must NOT commit a `debug.ts` that only calls this preset: the Exercode\n * server applies this preset automatically when `debug.ts` is absent, and committed copies would\n * drift from the server's defaults.\n *\n * @example\n * Run in a problem directory without `debug.ts`:\n * ```bash\n * bun x exercode-problem debug model_answers/java '{ \"stdin\": \"1 2\" }'\n * ```\n */\nexport async function stdioDebugPreset(problemDir: string): Promise<void> {\n const args = parseArgs(process.argv);\n if (!args.cwd) throw new Error('cwd argument required');\n const params = debugParamsSchema.parse(args.params);\n\n // The sandboxed submission must read its sources and write build/run outputs in its directory.\n makeAccessibleToSandboxUser(args.cwd);\n\n const problemMarkdownFrontMatter = await readProblemMarkdownFrontMatter(problemDir);\n\n const originalMainFilePath = await findEntryPointFile(args.cwd, params.language);\n if (!originalMainFilePath) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.MISSING_REQUIRED_SUBMISSION_FILE_ERROR,\n stderr: `main file not found${params.language ? `: language: ${params.language}` : ''}`,\n });\n return;\n }\n\n const languageDefinition = findLanguageDefinitionByPath(originalMainFilePath);\n if (!languageDefinition) {\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: 'unsupported language',\n });\n return;\n }\n\n // `CI` changes affects Chainlit. `FORCE_COLOR` affects Bun.\n const env = { ...process.env, CI: '', FORCE_COLOR: '0' };\n\n let prebuiltMainFilePath: string | undefined;\n\n if (languageDefinition.prebuild) {\n try {\n await languageDefinition.prebuild(args.cwd);\n prebuiltMainFilePath = await findEntryPointFile(args.cwd, params.language);\n } catch (error) {\n console.error('prebuild error', error);\n\n printTestCaseResult({\n testCaseId: 'prebuild',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const mainFilePath = prebuiltMainFilePath ?? originalMainFilePath;\n\n if (languageDefinition.buildCommand) {\n try {\n const buildCommand = languageDefinition.buildCommand(mainFilePath);\n\n const buildSpawnResult = spawnSyncWithTimeout(\n buildCommand[0],\n buildCommand.slice(1),\n { cwd: args.cwd, encoding: 'utf8', env },\n BUILD_TIMEOUT_SECONDS\n );\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (buildSpawnResult.status !== 0) {\n decisionCode = DecisionCode.BUILD_ERROR;\n } else if (buildSpawnResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n decisionCode = DecisionCode.BUILD_TIME_LIMIT_EXCEEDED;\n } else if (\n buildSpawnResult.stdout.length > MAX_STDOUT_LENGTH ||\n buildSpawnResult.stderr.length > MAX_STDOUT_LENGTH\n ) {\n decisionCode = DecisionCode.BUILD_OUTPUT_SIZE_LIMIT_EXCEEDED;\n }\n\n if (decisionCode !== DecisionCode.ACCEPTED) {\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode,\n exitStatus: buildSpawnResult.status ?? undefined,\n stdout: buildSpawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: buildSpawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: buildSpawnResult.timeSeconds,\n memoryBytes: buildSpawnResult.memoryBytes,\n });\n return;\n }\n } catch (error) {\n console.error('build error', error);\n\n printTestCaseResult({\n testCaseId: 'build',\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n {\n const timeoutSeconds = Math.max(\n DEBUG_DEFAULT_TIMEOUT_SECONDS,\n (problemMarkdownFrontMatter.timeLimitMs ?? 0) / 1000\n );\n\n const command = languageDefinition.command(mainFilePath);\n\n const spawnResult = spawnSyncWithTimeout(\n command[0],\n command.slice(1),\n { cwd: args.cwd, encoding: 'utf8', input: params.stdin, env },\n timeoutSeconds\n );\n\n const outputFiles = await readOutputFiles(args.cwd, problemMarkdownFrontMatter.requiredOutputFilePaths ?? []);\n\n let decisionCode: DecisionCode = DecisionCode.ACCEPTED;\n\n if (spawnResult.status !== 0) {\n decisionCode = DecisionCode.RUNTIME_ERROR;\n } else if (spawnResult.timeSeconds > timeoutSeconds) {\n decisionCode = DecisionCode.TIME_LIMIT_EXCEEDED;\n } else if (spawnResult.memoryBytes > (problemMarkdownFrontMatter.memoryLimitByte ?? Number.POSITIVE_INFINITY)) {\n decisionCode = DecisionCode.MEMORY_LIMIT_EXCEEDED;\n } else if (spawnResult.stdout.length > MAX_STDOUT_LENGTH || spawnResult.stderr.length > MAX_STDOUT_LENGTH) {\n decisionCode = DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED;\n } else if (outputFiles.length < (problemMarkdownFrontMatter.requiredOutputFilePaths?.length ?? 0)) {\n decisionCode = DecisionCode.MISSING_REQUIRED_OUTPUT_FILE_ERROR;\n }\n\n printTestCaseResult({\n testCaseId: 'debug',\n decisionCode,\n exitStatus: spawnResult.status ?? undefined,\n stdin: params.stdin,\n stdout: spawnResult.stdout.slice(0, MAX_STDOUT_LENGTH) || undefined,\n stderr: spawnResult.stderr.slice(0, MAX_STDOUT_LENGTH) || undefined,\n timeSeconds: spawnResult.timeSeconds,\n memoryBytes: spawnResult.memoryBytes,\n outputFiles: outputFiles.length > 0 ? outputFiles : undefined,\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/types/language.cjs
CHANGED
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
8
8
|
<AssemblyName>Main</AssemblyName>
|
|
9
9
|
</PropertyGroup>
|
|
10
|
-
</Project>`)},buildCommand:()=>[`dotnet`,`build`,`Main.csproj`,`--configuration`,`Release`,`--verbosity`,`quiet`],command:()=>[`dotnet`,`bin/Release/net8.0/Main.dll`],grammer:a},css:{fileExtensions:[`.css`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//}]}},dart:{fileExtensions:[`.dart`],buildCommand:e=>[`dart`,`compile`,`exe`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},java:{fileExtensions:[`.java`],prebuild:async e=>{let n=/\bpublic\s+class\s+(\w+)\b/;for(let o of await i.default.promises.readdir(e,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await i.default.promises.readFile(r.default.join(e,o.name),`utf8`),[,c]=n.exec(t.removeCommentsInSourceCode(a,s))??[];c&&await i.default.promises.rename(r.default.join(e,o.name),r.default.join(e,`${c}.java`))}},buildCommand:e=>[`javac`,e],command:e=>[`java`,`-Xmx1024m`,e.replace(/\.java$/,``)],grammer:a},javascript:{fileExtensions:[`.js`,`.cjs`,`.mjs`],command:e=>[`bun`,e],grammer:o},jsp:{fileExtensions:[`.jsp`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/},{open:/\n?[ \t]*<%--/,close:/--%>/},{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]}},haskell:{fileExtensions:[`.hs`],buildCommand:e=>[`ghc`,`-o`,`main`,e],command:()=>[`./main`],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\{-/,close:/-\}/},{open:/\n?[ \t]*--/}]}},html:{fileExtensions:[`.html`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/}]}},php:{fileExtensions:[`.php`],command:e=>[`php`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//},{open:/\n?[ \t]*#/}]}},python:{fileExtensions:[`.py`],command:e=>[`python3`,e],grammer:{strings:[{open:/'''/,close:/(?<!\\)(?:\\{2})*'''/},{open:/"""/,close:/(?<!\\)(?:\\{2})*"""/},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*'''/,close:/'''/},{open:/\n?[ \t]*"""/,close:/"""/},{open:/\n?[ \t]*#/}]}},ruby:{fileExtensions:[`.rb`],buildCommand:e=>[`ruby`,`-c`,e],command:e=>[`ruby`,`--jit`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*=begin/,close:/=end/},{open:/\n?[ \t]*#/}]}},rust:{fileExtensions:[`.rs`],buildCommand:e=>[`rustc`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},zig:{fileExtensions:[`.zig`],buildCommand:e=>[`zig`,`build-exe`,e],command:e=>[`./`+e.replace(/\.zig$/,``)],grammer:a},typescript:{fileExtensions:[`.ts`,`.cts`,`.mts`],command:e=>[`bun`,e],grammer:o},text:{fileExtensions:[`.txt`],command:e=>[`cat`,e]}};exports.languageIdToDefinition=s;
|
|
10
|
+
</Project>`)},buildCommand:()=>[`dotnet`,`build`,`Main.csproj`,`--configuration`,`Release`,`--verbosity`,`quiet`],command:()=>[`dotnet`,`bin/Release/net8.0/Main.dll`],grammer:a},css:{fileExtensions:[`.css`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//}]}},dart:{fileExtensions:[`.dart`],buildCommand:e=>[`dart`,`compile`,`exe`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},java:{fileExtensions:[`.java`],prebuild:async e=>{let n=/\bpublic\s+class\s+(\w+)\b/;for(let o of await i.default.promises.readdir(e,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await i.default.promises.readFile(r.default.join(e,o.name),`utf8`),[,c]=n.exec(t.removeCommentsInSourceCode(a,s))??[];c&&await i.default.promises.rename(r.default.join(e,o.name),r.default.join(e,`${c}.java`))}},buildCommand:e=>[`javac`,e],command:e=>[`java`,`-Xmx1024m`,e.replace(/\.java$/,``)],grammer:a},kotlin:{fileExtensions:[`.kt`],buildCommand:e=>[`kotlinc`,e,`-include-runtime`,`-d`,`main.jar`],command:()=>[`java`,`-Xmx1024m`,`-jar`,`main.jar`],grammer:{strings:[{open:/"""/,close:/"""/,templateSyntax:`kotlin`},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/,templateSyntax:`kotlin`}],comments:a.comments}},javascript:{fileExtensions:[`.js`,`.cjs`,`.mjs`],command:e=>[`bun`,e],grammer:o},jsp:{fileExtensions:[`.jsp`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/},{open:/\n?[ \t]*<%--/,close:/--%>/},{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]}},haskell:{fileExtensions:[`.hs`],buildCommand:e=>[`ghc`,`-o`,`main`,e],command:()=>[`./main`],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\{-/,close:/-\}/},{open:/\n?[ \t]*--/}]}},html:{fileExtensions:[`.html`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/}]}},php:{fileExtensions:[`.php`],command:e=>[`php`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//},{open:/\n?[ \t]*#/}]}},python:{fileExtensions:[`.py`],command:e=>[`python3`,e],grammer:{strings:[{open:/'''/,close:/(?<!\\)(?:\\{2})*'''/},{open:/"""/,close:/(?<!\\)(?:\\{2})*"""/},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*'''/,close:/'''/},{open:/\n?[ \t]*"""/,close:/"""/},{open:/\n?[ \t]*#/}]}},ruby:{fileExtensions:[`.rb`],buildCommand:e=>[`ruby`,`-c`,e],command:e=>[`ruby`,`--jit`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*=begin/,close:/=end/},{open:/\n?[ \t]*#/}]}},rust:{fileExtensions:[`.rs`],buildCommand:e=>[`rustc`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},zig:{fileExtensions:[`.zig`],buildCommand:e=>[`zig`,`build-exe`,e],command:e=>[`./`+e.replace(/\.zig$/,``)],grammer:a},typescript:{fileExtensions:[`.ts`,`.cts`,`.mts`],command:e=>[`bun`,e],grammer:o},text:{fileExtensions:[`.txt`],command:e=>[`cat`,e]}};exports.languageIdToDefinition=s;
|
|
11
11
|
//# sourceMappingURL=language.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language.cjs","names":["writeFileWithoutFollowingSymlinks","path","fs","removeCommentsInSourceCode"],"sources":["../../src/types/language.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { removeCommentsInSourceCode } from '../helpers/removeCommentsInSourceCode.js';\nimport { writeFileWithoutFollowingSymlinks } from '../helpers/safeFs.js';\n\nexport interface LanguageDefinition {\n /** File extensions to judge with this config. */\n fileExtensions: readonly string[];\n\n /** Function executed before the build. */\n prebuild?(cwd: string): Promise<void>;\n\n /** Returns the command to build a user program. */\n buildCommand?(filePath: string): [string, ...string[]];\n\n /** Returns the command to run a user program. */\n command(filePath: string): [string, ...string[]];\n\n /** Grammer definition for static analysis. */\n grammer?: {\n strings?: readonly { open: RegExp; close: RegExp }[];\n comments?: readonly { open: RegExp; close?: RegExp }[];\n };\n}\n\nconst cLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nconst javaScriptLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n { open: /`/, close: /(?<!\\\\)(?:\\\\{2})*`/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nexport const languageIdToDefinition: Readonly<Record<string, Readonly<LanguageDefinition>>> = {\n c: {\n fileExtensions: ['.c'],\n buildCommand: (filePath) => ['gcc', '--std=c17', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n cpp: {\n fileExtensions: ['.cpp'],\n buildCommand: (filePath) => ['g++', '--std=c++20', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n csharp: {\n fileExtensions: ['.cs'],\n prebuild: async (cwd) => {\n // No-follow write: the submission owns `cwd` and could point `Main.csproj` at a file only the\n // trusted harness user can write.\n await writeFileWithoutFollowingSymlinks(\n path.join(cwd, 'Main.csproj'),\n `<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n <AssemblyName>Main</AssemblyName>\n </PropertyGroup>\n</Project>`\n );\n },\n buildCommand: () => ['dotnet', 'build', 'Main.csproj', '--configuration', 'Release', '--verbosity', 'quiet'],\n command: () => ['dotnet', 'bin/Release/net8.0/Main.dll'],\n grammer: cLikeGrammer,\n },\n\n css: {\n fileExtensions: ['.css'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }],\n },\n },\n\n dart: {\n fileExtensions: ['.dart'],\n buildCommand: (filePath) => ['dart', 'compile', 'exe', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n java: {\n fileExtensions: ['.java'],\n prebuild: async (cwd) => {\n const publicClassRegex = /\\bpublic\\s+class\\s+(\\w+)\\b/;\n for (const dirent of await fs.promises.readdir(cwd, { withFileTypes: true })) {\n if (!dirent.isFile() || !dirent.name.endsWith('.java')) continue;\n const data = await fs.promises.readFile(path.join(cwd, dirent.name), 'utf8');\n const [, className] = publicClassRegex.exec(removeCommentsInSourceCode(cLikeGrammer, data)) ?? [];\n if (className) await fs.promises.rename(path.join(cwd, dirent.name), path.join(cwd, `${className}.java`));\n }\n },\n buildCommand: (fileName) => ['javac', fileName],\n // For example, Problem 7-3 in WillBooster's Java lecture uses at least 256MB.\n command: (fileName) => ['java', '-Xmx1024m', fileName.replace(/\\.java$/, '')],\n grammer: cLikeGrammer,\n },\n\n javascript: {\n fileExtensions: ['.js', '.cjs', '.mjs'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n jsp: {\n fileExtensions: ['.jsp'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*<!--/, close: /-->/ },\n { open: /\\n?[ \\t]*<%--/, close: /--%>/ },\n { open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// },\n { open: /\\n?[ \\t]*\\/\\// },\n ],\n },\n },\n\n haskell: {\n fileExtensions: ['.hs'],\n buildCommand: (filePath) => ['ghc', '-o', 'main', filePath],\n command: () => ['./main'],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\{-/, close: /-\\}/ }, { open: /\\n?[ \\t]*--/ }],\n },\n },\n\n html: {\n fileExtensions: ['.html'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*<!--/, close: /-->/ }],\n },\n },\n\n php: {\n fileExtensions: ['.php'],\n command: (fileName) => ['php', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n python: {\n fileExtensions: ['.py'],\n command: (fileName) => ['python3', fileName],\n grammer: {\n strings: [\n { open: /'''/, close: /(?<!\\\\)(?:\\\\{2})*'''/ },\n { open: /\"\"\"/, close: /(?<!\\\\)(?:\\\\{2})*\"\"\"/ },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*'''/, close: /'''/ },\n { open: /\\n?[ \\t]*\"\"\"/, close: /\"\"\"/ },\n { open: /\\n?[ \\t]*#/ },\n ],\n },\n },\n\n ruby: {\n fileExtensions: ['.rb'],\n buildCommand: (fileName) => ['ruby', '-c', fileName],\n command: (fileName) => ['ruby', '--jit', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*=begin/, close: /=end/ }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n rust: {\n fileExtensions: ['.rs'],\n buildCommand: (filePath) => ['rustc', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n zig: {\n fileExtensions: ['.zig'],\n buildCommand: (filePath) => ['zig', 'build-exe', filePath],\n command: (filePath) => ['./' + filePath.replace(/\\.zig$/, '')],\n grammer: cLikeGrammer,\n },\n\n typescript: {\n fileExtensions: ['.ts', '.cts', '.mts'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n text: {\n fileExtensions: ['.txt'],\n command: (fileName) => ['cat', fileName],\n },\n} as const;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"language.cjs","names":["writeFileWithoutFollowingSymlinks","path","fs","removeCommentsInSourceCode"],"sources":["../../src/types/language.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { removeCommentsInSourceCode } from '../helpers/removeCommentsInSourceCode.js';\nimport { writeFileWithoutFollowingSymlinks } from '../helpers/safeFs.js';\n\nexport interface LanguageDefinition {\n /** File extensions to judge with this config. */\n fileExtensions: readonly string[];\n\n /** Function executed before the build. */\n prebuild?(cwd: string): Promise<void>;\n\n /** Returns the command to build a user program. */\n buildCommand?(filePath: string): [string, ...string[]];\n\n /** Returns the command to run a user program. */\n command(filePath: string): [string, ...string[]];\n\n /** Grammer definition for static analysis. */\n grammer?: {\n strings?: readonly { open: RegExp; close: RegExp; templateSyntax?: 'kotlin' }[];\n comments?: readonly { open: RegExp; close?: RegExp }[];\n };\n}\n\nconst cLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nconst javaScriptLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n { open: /`/, close: /(?<!\\\\)(?:\\\\{2})*`/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nexport const languageIdToDefinition: Readonly<Record<string, Readonly<LanguageDefinition>>> = {\n c: {\n fileExtensions: ['.c'],\n buildCommand: (filePath) => ['gcc', '--std=c17', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n cpp: {\n fileExtensions: ['.cpp'],\n buildCommand: (filePath) => ['g++', '--std=c++20', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n csharp: {\n fileExtensions: ['.cs'],\n prebuild: async (cwd) => {\n // No-follow write: the submission owns `cwd` and could point `Main.csproj` at a file only the\n // trusted harness user can write.\n await writeFileWithoutFollowingSymlinks(\n path.join(cwd, 'Main.csproj'),\n `<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n <AssemblyName>Main</AssemblyName>\n </PropertyGroup>\n</Project>`\n );\n },\n buildCommand: () => ['dotnet', 'build', 'Main.csproj', '--configuration', 'Release', '--verbosity', 'quiet'],\n command: () => ['dotnet', 'bin/Release/net8.0/Main.dll'],\n grammer: cLikeGrammer,\n },\n\n css: {\n fileExtensions: ['.css'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }],\n },\n },\n\n dart: {\n fileExtensions: ['.dart'],\n buildCommand: (filePath) => ['dart', 'compile', 'exe', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n java: {\n fileExtensions: ['.java'],\n prebuild: async (cwd) => {\n const publicClassRegex = /\\bpublic\\s+class\\s+(\\w+)\\b/;\n for (const dirent of await fs.promises.readdir(cwd, { withFileTypes: true })) {\n if (!dirent.isFile() || !dirent.name.endsWith('.java')) continue;\n const data = await fs.promises.readFile(path.join(cwd, dirent.name), 'utf8');\n const [, className] = publicClassRegex.exec(removeCommentsInSourceCode(cLikeGrammer, data)) ?? [];\n if (className) await fs.promises.rename(path.join(cwd, dirent.name), path.join(cwd, `${className}.java`));\n }\n },\n buildCommand: (fileName) => ['javac', fileName],\n // For example, Problem 7-3 in WillBooster's Java lecture uses at least 256MB.\n command: (fileName) => ['java', '-Xmx1024m', fileName.replace(/\\.java$/, '')],\n grammer: cLikeGrammer,\n },\n\n kotlin: {\n fileExtensions: ['.kt'],\n buildCommand: (filePath) => ['kotlinc', filePath, '-include-runtime', '-d', 'main.jar'],\n command: () => ['java', '-Xmx1024m', '-jar', 'main.jar'],\n grammer: {\n strings: [\n { open: /\"\"\"/, close: /\"\"\"/, templateSyntax: 'kotlin' },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/, templateSyntax: 'kotlin' },\n ],\n comments: cLikeGrammer.comments,\n },\n },\n\n javascript: {\n fileExtensions: ['.js', '.cjs', '.mjs'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n jsp: {\n fileExtensions: ['.jsp'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*<!--/, close: /-->/ },\n { open: /\\n?[ \\t]*<%--/, close: /--%>/ },\n { open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// },\n { open: /\\n?[ \\t]*\\/\\// },\n ],\n },\n },\n\n haskell: {\n fileExtensions: ['.hs'],\n buildCommand: (filePath) => ['ghc', '-o', 'main', filePath],\n command: () => ['./main'],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\{-/, close: /-\\}/ }, { open: /\\n?[ \\t]*--/ }],\n },\n },\n\n html: {\n fileExtensions: ['.html'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*<!--/, close: /-->/ }],\n },\n },\n\n php: {\n fileExtensions: ['.php'],\n command: (fileName) => ['php', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n python: {\n fileExtensions: ['.py'],\n command: (fileName) => ['python3', fileName],\n grammer: {\n strings: [\n { open: /'''/, close: /(?<!\\\\)(?:\\\\{2})*'''/ },\n { open: /\"\"\"/, close: /(?<!\\\\)(?:\\\\{2})*\"\"\"/ },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*'''/, close: /'''/ },\n { open: /\\n?[ \\t]*\"\"\"/, close: /\"\"\"/ },\n { open: /\\n?[ \\t]*#/ },\n ],\n },\n },\n\n ruby: {\n fileExtensions: ['.rb'],\n buildCommand: (fileName) => ['ruby', '-c', fileName],\n command: (fileName) => ['ruby', '--jit', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*=begin/, close: /=end/ }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n rust: {\n fileExtensions: ['.rs'],\n buildCommand: (filePath) => ['rustc', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n zig: {\n fileExtensions: ['.zig'],\n buildCommand: (filePath) => ['zig', 'build-exe', filePath],\n command: (filePath) => ['./' + filePath.replace(/\\.zig$/, '')],\n grammer: cLikeGrammer,\n },\n\n typescript: {\n fileExtensions: ['.ts', '.cts', '.mts'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n text: {\n fileExtensions: ['.txt'],\n command: (fileName) => ['cat', fileName],\n },\n} as const;\n"],"mappings":"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"}
|
package/dist/types/language.d.ts
CHANGED
package/dist/types/language.js
CHANGED
|
@@ -7,5 +7,5 @@ import{removeCommentsInSourceCode as e}from"../helpers/removeCommentsInSourceCod
|
|
|
7
7
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
8
8
|
<AssemblyName>Main</AssemblyName>
|
|
9
9
|
</PropertyGroup>
|
|
10
|
-
</Project>`)},buildCommand:()=>[`dotnet`,`build`,`Main.csproj`,`--configuration`,`Release`,`--verbosity`,`quiet`],command:()=>[`dotnet`,`bin/Release/net8.0/Main.dll`],grammer:i},css:{fileExtensions:[`.css`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//}]}},dart:{fileExtensions:[`.dart`],buildCommand:e=>[`dart`,`compile`,`exe`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},java:{fileExtensions:[`.java`],prebuild:async t=>{let a=/\bpublic\s+class\s+(\w+)\b/;for(let o of await r.promises.readdir(t,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await r.promises.readFile(n.join(t,o.name),`utf8`),[,c]=a.exec(e(i,s))??[];c&&await r.promises.rename(n.join(t,o.name),n.join(t,`${c}.java`))}},buildCommand:e=>[`javac`,e],command:e=>[`java`,`-Xmx1024m`,e.replace(/\.java$/,``)],grammer:i},javascript:{fileExtensions:[`.js`,`.cjs`,`.mjs`],command:e=>[`bun`,e],grammer:a},jsp:{fileExtensions:[`.jsp`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/},{open:/\n?[ \t]*<%--/,close:/--%>/},{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]}},haskell:{fileExtensions:[`.hs`],buildCommand:e=>[`ghc`,`-o`,`main`,e],command:()=>[`./main`],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\{-/,close:/-\}/},{open:/\n?[ \t]*--/}]}},html:{fileExtensions:[`.html`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/}]}},php:{fileExtensions:[`.php`],command:e=>[`php`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//},{open:/\n?[ \t]*#/}]}},python:{fileExtensions:[`.py`],command:e=>[`python3`,e],grammer:{strings:[{open:/'''/,close:/(?<!\\)(?:\\{2})*'''/},{open:/"""/,close:/(?<!\\)(?:\\{2})*"""/},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*'''/,close:/'''/},{open:/\n?[ \t]*"""/,close:/"""/},{open:/\n?[ \t]*#/}]}},ruby:{fileExtensions:[`.rb`],buildCommand:e=>[`ruby`,`-c`,e],command:e=>[`ruby`,`--jit`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*=begin/,close:/=end/},{open:/\n?[ \t]*#/}]}},rust:{fileExtensions:[`.rs`],buildCommand:e=>[`rustc`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},zig:{fileExtensions:[`.zig`],buildCommand:e=>[`zig`,`build-exe`,e],command:e=>[`./`+e.replace(/\.zig$/,``)],grammer:i},typescript:{fileExtensions:[`.ts`,`.cts`,`.mts`],command:e=>[`bun`,e],grammer:a},text:{fileExtensions:[`.txt`],command:e=>[`cat`,e]}};export{o as languageIdToDefinition};
|
|
10
|
+
</Project>`)},buildCommand:()=>[`dotnet`,`build`,`Main.csproj`,`--configuration`,`Release`,`--verbosity`,`quiet`],command:()=>[`dotnet`,`bin/Release/net8.0/Main.dll`],grammer:i},css:{fileExtensions:[`.css`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//}]}},dart:{fileExtensions:[`.dart`],buildCommand:e=>[`dart`,`compile`,`exe`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},java:{fileExtensions:[`.java`],prebuild:async t=>{let a=/\bpublic\s+class\s+(\w+)\b/;for(let o of await r.promises.readdir(t,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await r.promises.readFile(n.join(t,o.name),`utf8`),[,c]=a.exec(e(i,s))??[];c&&await r.promises.rename(n.join(t,o.name),n.join(t,`${c}.java`))}},buildCommand:e=>[`javac`,e],command:e=>[`java`,`-Xmx1024m`,e.replace(/\.java$/,``)],grammer:i},kotlin:{fileExtensions:[`.kt`],buildCommand:e=>[`kotlinc`,e,`-include-runtime`,`-d`,`main.jar`],command:()=>[`java`,`-Xmx1024m`,`-jar`,`main.jar`],grammer:{strings:[{open:/"""/,close:/"""/,templateSyntax:`kotlin`},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/,templateSyntax:`kotlin`}],comments:i.comments}},javascript:{fileExtensions:[`.js`,`.cjs`,`.mjs`],command:e=>[`bun`,e],grammer:a},jsp:{fileExtensions:[`.jsp`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/},{open:/\n?[ \t]*<%--/,close:/--%>/},{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]}},haskell:{fileExtensions:[`.hs`],buildCommand:e=>[`ghc`,`-o`,`main`,e],command:()=>[`./main`],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\{-/,close:/-\}/},{open:/\n?[ \t]*--/}]}},html:{fileExtensions:[`.html`],command:()=>[`echo`,``],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*<!--/,close:/-->/}]}},php:{fileExtensions:[`.php`],command:e=>[`php`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//},{open:/\n?[ \t]*#/}]}},python:{fileExtensions:[`.py`],command:e=>[`python3`,e],grammer:{strings:[{open:/'''/,close:/(?<!\\)(?:\\{2})*'''/},{open:/"""/,close:/(?<!\\)(?:\\{2})*"""/},{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*'''/,close:/'''/},{open:/\n?[ \t]*"""/,close:/"""/},{open:/\n?[ \t]*#/}]}},ruby:{fileExtensions:[`.rb`],buildCommand:e=>[`ruby`,`-c`,e],command:e=>[`ruby`,`--jit`,e],grammer:{strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*=begin/,close:/=end/},{open:/\n?[ \t]*#/}]}},rust:{fileExtensions:[`.rs`],buildCommand:e=>[`rustc`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},zig:{fileExtensions:[`.zig`],buildCommand:e=>[`zig`,`build-exe`,e],command:e=>[`./`+e.replace(/\.zig$/,``)],grammer:i},typescript:{fileExtensions:[`.ts`,`.cts`,`.mts`],command:e=>[`bun`,e],grammer:a},text:{fileExtensions:[`.txt`],command:e=>[`cat`,e]}};export{o as languageIdToDefinition};
|
|
11
11
|
//# sourceMappingURL=language.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language.js","names":[],"sources":["../../src/types/language.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { removeCommentsInSourceCode } from '../helpers/removeCommentsInSourceCode.js';\nimport { writeFileWithoutFollowingSymlinks } from '../helpers/safeFs.js';\n\nexport interface LanguageDefinition {\n /** File extensions to judge with this config. */\n fileExtensions: readonly string[];\n\n /** Function executed before the build. */\n prebuild?(cwd: string): Promise<void>;\n\n /** Returns the command to build a user program. */\n buildCommand?(filePath: string): [string, ...string[]];\n\n /** Returns the command to run a user program. */\n command(filePath: string): [string, ...string[]];\n\n /** Grammer definition for static analysis. */\n grammer?: {\n strings?: readonly { open: RegExp; close: RegExp }[];\n comments?: readonly { open: RegExp; close?: RegExp }[];\n };\n}\n\nconst cLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nconst javaScriptLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n { open: /`/, close: /(?<!\\\\)(?:\\\\{2})*`/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nexport const languageIdToDefinition: Readonly<Record<string, Readonly<LanguageDefinition>>> = {\n c: {\n fileExtensions: ['.c'],\n buildCommand: (filePath) => ['gcc', '--std=c17', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n cpp: {\n fileExtensions: ['.cpp'],\n buildCommand: (filePath) => ['g++', '--std=c++20', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n csharp: {\n fileExtensions: ['.cs'],\n prebuild: async (cwd) => {\n // No-follow write: the submission owns `cwd` and could point `Main.csproj` at a file only the\n // trusted harness user can write.\n await writeFileWithoutFollowingSymlinks(\n path.join(cwd, 'Main.csproj'),\n `<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n <AssemblyName>Main</AssemblyName>\n </PropertyGroup>\n</Project>`\n );\n },\n buildCommand: () => ['dotnet', 'build', 'Main.csproj', '--configuration', 'Release', '--verbosity', 'quiet'],\n command: () => ['dotnet', 'bin/Release/net8.0/Main.dll'],\n grammer: cLikeGrammer,\n },\n\n css: {\n fileExtensions: ['.css'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }],\n },\n },\n\n dart: {\n fileExtensions: ['.dart'],\n buildCommand: (filePath) => ['dart', 'compile', 'exe', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n java: {\n fileExtensions: ['.java'],\n prebuild: async (cwd) => {\n const publicClassRegex = /\\bpublic\\s+class\\s+(\\w+)\\b/;\n for (const dirent of await fs.promises.readdir(cwd, { withFileTypes: true })) {\n if (!dirent.isFile() || !dirent.name.endsWith('.java')) continue;\n const data = await fs.promises.readFile(path.join(cwd, dirent.name), 'utf8');\n const [, className] = publicClassRegex.exec(removeCommentsInSourceCode(cLikeGrammer, data)) ?? [];\n if (className) await fs.promises.rename(path.join(cwd, dirent.name), path.join(cwd, `${className}.java`));\n }\n },\n buildCommand: (fileName) => ['javac', fileName],\n // For example, Problem 7-3 in WillBooster's Java lecture uses at least 256MB.\n command: (fileName) => ['java', '-Xmx1024m', fileName.replace(/\\.java$/, '')],\n grammer: cLikeGrammer,\n },\n\n javascript: {\n fileExtensions: ['.js', '.cjs', '.mjs'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n jsp: {\n fileExtensions: ['.jsp'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*<!--/, close: /-->/ },\n { open: /\\n?[ \\t]*<%--/, close: /--%>/ },\n { open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// },\n { open: /\\n?[ \\t]*\\/\\// },\n ],\n },\n },\n\n haskell: {\n fileExtensions: ['.hs'],\n buildCommand: (filePath) => ['ghc', '-o', 'main', filePath],\n command: () => ['./main'],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\{-/, close: /-\\}/ }, { open: /\\n?[ \\t]*--/ }],\n },\n },\n\n html: {\n fileExtensions: ['.html'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*<!--/, close: /-->/ }],\n },\n },\n\n php: {\n fileExtensions: ['.php'],\n command: (fileName) => ['php', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n python: {\n fileExtensions: ['.py'],\n command: (fileName) => ['python3', fileName],\n grammer: {\n strings: [\n { open: /'''/, close: /(?<!\\\\)(?:\\\\{2})*'''/ },\n { open: /\"\"\"/, close: /(?<!\\\\)(?:\\\\{2})*\"\"\"/ },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*'''/, close: /'''/ },\n { open: /\\n?[ \\t]*\"\"\"/, close: /\"\"\"/ },\n { open: /\\n?[ \\t]*#/ },\n ],\n },\n },\n\n ruby: {\n fileExtensions: ['.rb'],\n buildCommand: (fileName) => ['ruby', '-c', fileName],\n command: (fileName) => ['ruby', '--jit', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*=begin/, close: /=end/ }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n rust: {\n fileExtensions: ['.rs'],\n buildCommand: (filePath) => ['rustc', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n zig: {\n fileExtensions: ['.zig'],\n buildCommand: (filePath) => ['zig', 'build-exe', filePath],\n command: (filePath) => ['./' + filePath.replace(/\\.zig$/, '')],\n grammer: cLikeGrammer,\n },\n\n typescript: {\n fileExtensions: ['.ts', '.cts', '.mts'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n text: {\n fileExtensions: ['.txt'],\n command: (fileName) => ['cat', fileName],\n },\n} as const;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"language.js","names":[],"sources":["../../src/types/language.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { removeCommentsInSourceCode } from '../helpers/removeCommentsInSourceCode.js';\nimport { writeFileWithoutFollowingSymlinks } from '../helpers/safeFs.js';\n\nexport interface LanguageDefinition {\n /** File extensions to judge with this config. */\n fileExtensions: readonly string[];\n\n /** Function executed before the build. */\n prebuild?(cwd: string): Promise<void>;\n\n /** Returns the command to build a user program. */\n buildCommand?(filePath: string): [string, ...string[]];\n\n /** Returns the command to run a user program. */\n command(filePath: string): [string, ...string[]];\n\n /** Grammer definition for static analysis. */\n grammer?: {\n strings?: readonly { open: RegExp; close: RegExp; templateSyntax?: 'kotlin' }[];\n comments?: readonly { open: RegExp; close?: RegExp }[];\n };\n}\n\nconst cLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nconst javaScriptLikeGrammer = {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n { open: /`/, close: /(?<!\\\\)(?:\\\\{2})*`/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }],\n} as const satisfies LanguageDefinition['grammer'];\n\nexport const languageIdToDefinition: Readonly<Record<string, Readonly<LanguageDefinition>>> = {\n c: {\n fileExtensions: ['.c'],\n buildCommand: (filePath) => ['gcc', '--std=c17', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n cpp: {\n fileExtensions: ['.cpp'],\n buildCommand: (filePath) => ['g++', '--std=c++20', '-O2', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n csharp: {\n fileExtensions: ['.cs'],\n prebuild: async (cwd) => {\n // No-follow write: the submission owns `cwd` and could point `Main.csproj` at a file only the\n // trusted harness user can write.\n await writeFileWithoutFollowingSymlinks(\n path.join(cwd, 'Main.csproj'),\n `<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n <AssemblyName>Main</AssemblyName>\n </PropertyGroup>\n</Project>`\n );\n },\n buildCommand: () => ['dotnet', 'build', 'Main.csproj', '--configuration', 'Release', '--verbosity', 'quiet'],\n command: () => ['dotnet', 'bin/Release/net8.0/Main.dll'],\n grammer: cLikeGrammer,\n },\n\n css: {\n fileExtensions: ['.css'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }],\n },\n },\n\n dart: {\n fileExtensions: ['.dart'],\n buildCommand: (filePath) => ['dart', 'compile', 'exe', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n java: {\n fileExtensions: ['.java'],\n prebuild: async (cwd) => {\n const publicClassRegex = /\\bpublic\\s+class\\s+(\\w+)\\b/;\n for (const dirent of await fs.promises.readdir(cwd, { withFileTypes: true })) {\n if (!dirent.isFile() || !dirent.name.endsWith('.java')) continue;\n const data = await fs.promises.readFile(path.join(cwd, dirent.name), 'utf8');\n const [, className] = publicClassRegex.exec(removeCommentsInSourceCode(cLikeGrammer, data)) ?? [];\n if (className) await fs.promises.rename(path.join(cwd, dirent.name), path.join(cwd, `${className}.java`));\n }\n },\n buildCommand: (fileName) => ['javac', fileName],\n // For example, Problem 7-3 in WillBooster's Java lecture uses at least 256MB.\n command: (fileName) => ['java', '-Xmx1024m', fileName.replace(/\\.java$/, '')],\n grammer: cLikeGrammer,\n },\n\n kotlin: {\n fileExtensions: ['.kt'],\n buildCommand: (filePath) => ['kotlinc', filePath, '-include-runtime', '-d', 'main.jar'],\n command: () => ['java', '-Xmx1024m', '-jar', 'main.jar'],\n grammer: {\n strings: [\n { open: /\"\"\"/, close: /\"\"\"/, templateSyntax: 'kotlin' },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/, templateSyntax: 'kotlin' },\n ],\n comments: cLikeGrammer.comments,\n },\n },\n\n javascript: {\n fileExtensions: ['.js', '.cjs', '.mjs'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n jsp: {\n fileExtensions: ['.jsp'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*<!--/, close: /-->/ },\n { open: /\\n?[ \\t]*<%--/, close: /--%>/ },\n { open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// },\n { open: /\\n?[ \\t]*\\/\\// },\n ],\n },\n },\n\n haskell: {\n fileExtensions: ['.hs'],\n buildCommand: (filePath) => ['ghc', '-o', 'main', filePath],\n command: () => ['./main'],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\{-/, close: /-\\}/ }, { open: /\\n?[ \\t]*--/ }],\n },\n },\n\n html: {\n fileExtensions: ['.html'],\n command: () => ['echo', ''],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*<!--/, close: /-->/ }],\n },\n },\n\n php: {\n fileExtensions: ['.php'],\n command: (fileName) => ['php', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*\\/\\*/, close: /\\*\\// }, { open: /\\n?[ \\t]*\\/\\// }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n python: {\n fileExtensions: ['.py'],\n command: (fileName) => ['python3', fileName],\n grammer: {\n strings: [\n { open: /'''/, close: /(?<!\\\\)(?:\\\\{2})*'''/ },\n { open: /\"\"\"/, close: /(?<!\\\\)(?:\\\\{2})*\"\"\"/ },\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [\n { open: /\\n?[ \\t]*'''/, close: /'''/ },\n { open: /\\n?[ \\t]*\"\"\"/, close: /\"\"\"/ },\n { open: /\\n?[ \\t]*#/ },\n ],\n },\n },\n\n ruby: {\n fileExtensions: ['.rb'],\n buildCommand: (fileName) => ['ruby', '-c', fileName],\n command: (fileName) => ['ruby', '--jit', fileName],\n grammer: {\n strings: [\n { open: /'/, close: /(?<!\\\\)(?:\\\\{2})*'/ },\n { open: /\"/, close: /(?<!\\\\)(?:\\\\{2})*\"/ },\n ],\n comments: [{ open: /\\n?[ \\t]*=begin/, close: /=end/ }, { open: /\\n?[ \\t]*#/ }],\n },\n },\n\n rust: {\n fileExtensions: ['.rs'],\n buildCommand: (filePath) => ['rustc', filePath, '-o', 'main'],\n command: () => ['./main'],\n grammer: cLikeGrammer,\n },\n\n zig: {\n fileExtensions: ['.zig'],\n buildCommand: (filePath) => ['zig', 'build-exe', filePath],\n command: (filePath) => ['./' + filePath.replace(/\\.zig$/, '')],\n grammer: cLikeGrammer,\n },\n\n typescript: {\n fileExtensions: ['.ts', '.cts', '.mts'],\n command: (fileName) => ['bun', fileName],\n grammer: javaScriptLikeGrammer,\n },\n\n text: {\n fileExtensions: ['.txt'],\n command: (fileName) => ['cat', fileName],\n },\n} as const;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exercode/problem-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": ":100: A set of utilities for judging programs on Exercode (https://exercode.willbooster.com/).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"exercode",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"module": "dist/index.js",
|
|
31
31
|
"types": "dist/index.d.ts",
|
|
32
32
|
"bin": {
|
|
33
|
-
"exercode": "bin/exercode.mjs"
|
|
33
|
+
"exercode-problem": "bin/exercode-problem.mjs"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"bin/",
|
package/bin/exercode.mjs
DELETED
package/dist/cli/exercode.cjs
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";const e=require("./runSingleHarness.cjs"),t=require("./checkAllProblems.cjs"),n=`Usage: exercode [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]
|
|
2
|
-
exercode judge <answerDir> [paramsJson]
|
|
3
|
-
exercode debug <answerDir> [paramsJson]
|
|
4
|
-
|
|
5
|
-
Without a subcommand, judge all model answers of all problems under rootDir
|
|
6
|
-
(default: the current directory). Use \`judge\` or \`debug\` in a problem
|
|
7
|
-
directory to run one answer directory, e.g.:
|
|
8
|
-
exercode debug model_answers/python '{ "stdin": "1 2" }'`;r();async function r(){let r=process.argv.slice(2);if(r[0]===`--help`||r[0]===`-h`){console.info(n);return}try{if(r[0]===`judge`||r[0]===`debug`){if(r.length<2){console.error(n),process.exitCode=1;return}process.argv.splice(2,1),process.exitCode=await e.runSingleHarness(r[0])}else process.exitCode=await t.checkAllProblems(r)}catch(e){console.error(e),process.exitCode=1}}
|
|
9
|
-
//# sourceMappingURL=exercode.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exercode.cjs","names":["runSingleHarness","checkAllProblems"],"sources":["../../src/cli/exercode.ts"],"sourcesContent":["import { checkAllProblems } from './checkAllProblems.js';\nimport { runSingleHarness } from './runSingleHarness.js';\n\nconst usage = `Usage: exercode [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]\n exercode judge <answerDir> [paramsJson]\n exercode debug <answerDir> [paramsJson]\n\nWithout a subcommand, judge all model answers of all problems under rootDir\n(default: the current directory). Use \\`judge\\` or \\`debug\\` in a problem\ndirectory to run one answer directory, e.g.:\n exercode debug model_answers/python '{ \"stdin\": \"1 2\" }'`;\n\n// oxlint-disable-next-line unicorn/prefer-top-level-await -- the CJS build output does not support top-level await\nvoid main();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n if (args[0] === '--help' || args[0] === '-h') {\n // console.log would be stripped from the built CLI, so print the usage with console.info.\n console.info(usage);\n return;\n }\n try {\n if (args[0] === 'judge' || args[0] === 'debug') {\n if (args.length < 2) {\n console.error(usage);\n process.exitCode = 1;\n return;\n }\n // Harness scripts and presets read the answer directory and params from fixed positions in\n // `process.argv`, so drop the subcommand to restore those positions.\n process.argv.splice(2, 1);\n process.exitCode = await runSingleHarness(args[0]);\n } else {\n process.exitCode = await checkAllProblems(args);\n }\n } catch (error) {\n // Print the whole error: harness failures need their stack and `cause`, not just the message.\n console.error(error);\n process.exitCode = 1;\n }\n}\n"],"mappings":"2FAGM,EAAQ;;;;;;;4DAUT,EAAK,EAEV,eAAe,GAAsB,CACnC,IAAM,EAAO,QAAQ,KAAK,MAAM,CAAC,EACjC,GAAI,EAAK,KAAO,UAAY,EAAK,KAAO,KAAM,CAE5C,QAAQ,KAAK,CAAK,EAClB,MACF,CACA,GAAI,CACF,GAAI,EAAK,KAAO,SAAW,EAAK,KAAO,QAAS,CAC9C,GAAI,EAAK,OAAS,EAAG,CACnB,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,EACnB,MACF,CAGA,QAAQ,KAAK,OAAO,EAAG,CAAC,EACxB,QAAQ,SAAW,MAAMA,EAAAA,iBAAiB,EAAK,EAAE,CACnD,KACE,SAAQ,SAAW,MAAMC,EAAAA,iBAAiB,CAAI,CAElD,OAAS,EAAO,CAEd,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,CACrB,CACF"}
|
package/dist/cli/exercode.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import{runSingleHarness as e}from"./runSingleHarness.js";import{checkAllProblems as t}from"./checkAllProblems.js";const n=`Usage: exercode [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]
|
|
2
|
-
exercode judge <answerDir> [paramsJson]
|
|
3
|
-
exercode debug <answerDir> [paramsJson]
|
|
4
|
-
|
|
5
|
-
Without a subcommand, judge all model answers of all problems under rootDir
|
|
6
|
-
(default: the current directory). Use \`judge\` or \`debug\` in a problem
|
|
7
|
-
directory to run one answer directory, e.g.:
|
|
8
|
-
exercode debug model_answers/python '{ "stdin": "1 2" }'`;r();async function r(){let r=process.argv.slice(2);if(r[0]===`--help`||r[0]===`-h`){console.info(n);return}try{if(r[0]===`judge`||r[0]===`debug`){if(r.length<2){console.error(n),process.exitCode=1;return}process.argv.splice(2,1),process.exitCode=await e(r[0])}else process.exitCode=await t(r)}catch(e){console.error(e),process.exitCode=1}}
|
|
9
|
-
//# sourceMappingURL=exercode.js.map
|
package/dist/cli/exercode.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exercode.js","names":[],"sources":["../../src/cli/exercode.ts"],"sourcesContent":["import { checkAllProblems } from './checkAllProblems.js';\nimport { runSingleHarness } from './runSingleHarness.js';\n\nconst usage = `Usage: exercode [rootDir] [--only <substring>]... [--skip <substring>]... [--concurrency <n>]\n exercode judge <answerDir> [paramsJson]\n exercode debug <answerDir> [paramsJson]\n\nWithout a subcommand, judge all model answers of all problems under rootDir\n(default: the current directory). Use \\`judge\\` or \\`debug\\` in a problem\ndirectory to run one answer directory, e.g.:\n exercode debug model_answers/python '{ \"stdin\": \"1 2\" }'`;\n\n// oxlint-disable-next-line unicorn/prefer-top-level-await -- the CJS build output does not support top-level await\nvoid main();\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n if (args[0] === '--help' || args[0] === '-h') {\n // console.log would be stripped from the built CLI, so print the usage with console.info.\n console.info(usage);\n return;\n }\n try {\n if (args[0] === 'judge' || args[0] === 'debug') {\n if (args.length < 2) {\n console.error(usage);\n process.exitCode = 1;\n return;\n }\n // Harness scripts and presets read the answer directory and params from fixed positions in\n // `process.argv`, so drop the subcommand to restore those positions.\n process.argv.splice(2, 1);\n process.exitCode = await runSingleHarness(args[0]);\n } else {\n process.exitCode = await checkAllProblems(args);\n }\n } catch (error) {\n // Print the whole error: harness failures need their stack and `cause`, not just the message.\n console.error(error);\n process.exitCode = 1;\n }\n}\n"],"mappings":"kHAGA,MAAM,EAAQ;;;;;;;4DAUT,EAAK,EAEV,eAAe,GAAsB,CACnC,IAAM,EAAO,QAAQ,KAAK,MAAM,CAAC,EACjC,GAAI,EAAK,KAAO,UAAY,EAAK,KAAO,KAAM,CAE5C,QAAQ,KAAK,CAAK,EAClB,MACF,CACA,GAAI,CACF,GAAI,EAAK,KAAO,SAAW,EAAK,KAAO,QAAS,CAC9C,GAAI,EAAK,OAAS,EAAG,CACnB,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,EACnB,MACF,CAGA,QAAQ,KAAK,OAAO,EAAG,CAAC,EACxB,QAAQ,SAAW,MAAM,EAAiB,EAAK,EAAE,CACnD,KACE,SAAQ,SAAW,MAAM,EAAiB,CAAI,CAElD,OAAS,EAAO,CAEd,QAAQ,MAAM,CAAK,EACnB,QAAQ,SAAW,CACrB,CACF"}
|
|
File without changes
|