@exercode/problem-utils 1.18.1 → 1.19.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.
Files changed (67) hide show
  1. package/README.md +26 -1
  2. package/bin/exercode.mjs +2 -0
  3. package/dist/cli/checkAllProblems.cjs +2 -0
  4. package/dist/cli/checkAllProblems.cjs.map +1 -0
  5. package/dist/cli/checkAllProblems.d.ts +6 -0
  6. package/dist/cli/checkAllProblems.js +2 -0
  7. package/dist/cli/checkAllProblems.js.map +1 -0
  8. package/dist/cli/exercode.cjs +9 -0
  9. package/dist/cli/exercode.cjs.map +1 -0
  10. package/dist/cli/exercode.d.ts +1 -0
  11. package/dist/cli/exercode.js +9 -0
  12. package/dist/cli/exercode.js.map +1 -0
  13. package/dist/cli/runSingleHarness.cjs +5 -0
  14. package/dist/cli/runSingleHarness.cjs.map +1 -0
  15. package/dist/cli/runSingleHarness.d.ts +8 -0
  16. package/dist/cli/runSingleHarness.js +5 -0
  17. package/dist/cli/runSingleHarness.js.map +1 -0
  18. package/dist/helpers/checkProblemDirIsolation.cjs +1 -1
  19. package/dist/helpers/checkProblemDirIsolation.cjs.map +1 -1
  20. package/dist/helpers/checkProblemDirIsolation.d.ts +15 -0
  21. package/dist/helpers/checkProblemDirIsolation.js +1 -1
  22. package/dist/helpers/checkProblemDirIsolation.js.map +1 -1
  23. package/dist/helpers/cleanWorkingDirectory.cjs +1 -1
  24. package/dist/helpers/cleanWorkingDirectory.js +1 -1
  25. package/dist/helpers/defaultStdioHarness.cjs +2 -0
  26. package/dist/helpers/defaultStdioHarness.cjs.map +1 -0
  27. package/dist/helpers/defaultStdioHarness.d.ts +19 -0
  28. package/dist/helpers/defaultStdioHarness.js +2 -0
  29. package/dist/helpers/defaultStdioHarness.js.map +1 -0
  30. package/dist/helpers/judgeByStaticAnalysis.cjs +1 -1
  31. package/dist/helpers/judgeByStaticAnalysis.js +1 -1
  32. package/dist/helpers/readOutputFiles.cjs +1 -1
  33. package/dist/helpers/readOutputFiles.js +1 -1
  34. package/dist/helpers/readProblemMarkdownFrontMatter.cjs +1 -1
  35. package/dist/helpers/readProblemMarkdownFrontMatter.cjs.map +1 -1
  36. package/dist/helpers/readProblemMarkdownFrontMatter.d.ts +5 -0
  37. package/dist/helpers/readProblemMarkdownFrontMatter.js +1 -1
  38. package/dist/helpers/readProblemMarkdownFrontMatter.js.map +1 -1
  39. package/dist/helpers/readTestCases.cjs +1 -1
  40. package/dist/helpers/readTestCases.js +1 -1
  41. package/dist/helpers/runCommandInTemporaryPackageManagerProject.cjs +1 -1
  42. package/dist/helpers/runCommandInTemporaryPackageManagerProject.js +1 -1
  43. package/dist/helpers/runCommandInTemporaryPackageManagerProject.js.map +1 -1
  44. package/dist/helpers/safeFs.cjs +1 -1
  45. package/dist/helpers/safeFs.js +1 -1
  46. package/dist/helpers/sandboxUser.cjs +1 -1
  47. package/dist/helpers/sandboxUser.js +1 -1
  48. package/dist/helpers/startHttpServer.cjs +1 -1
  49. package/dist/helpers/startHttpServer.js +1 -1
  50. package/dist/index.cjs +1 -1
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.js +1 -1
  53. package/dist/presets/command.cjs +1 -1
  54. package/dist/presets/command.cjs.map +1 -1
  55. package/dist/presets/command.js +1 -1
  56. package/dist/presets/guiCommand.cjs +3 -3
  57. package/dist/presets/guiCommand.js +3 -3
  58. package/dist/presets/llm.cjs +1 -1
  59. package/dist/presets/llm.js +1 -1
  60. package/dist/presets/stdio.cjs +1 -1
  61. package/dist/presets/stdio.cjs.map +1 -1
  62. package/dist/presets/stdio.d.ts +13 -19
  63. package/dist/presets/stdio.js +1 -1
  64. package/dist/presets/stdio.js.map +1 -1
  65. package/dist/types/language.cjs +2 -2
  66. package/dist/types/language.js +2 -2
  67. package/package.json +9 -5
@@ -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 * @example\n * Create `judge.ts`:\n * ```ts\n * import { stdioJudgePreset } from 'judge-utils/presets/stdio';\n *\n * await stdioJudgePreset(import.meta.dirname);\n * ```\n *\n * Run with the required parameters:\n * ```bash\n * bun judge.ts model_answers/java\n * ```\n *\n * Run with the optional parameters:\n * ```bash\n * bun judge.ts 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 * @example\n * Create `debug.ts`:\n * ```ts\n * import { stdioDebugPreset } from 'judge-utils/presets/stdio';\n *\n * await stdioDebugPreset(import.meta.dirname);\n * ```\n *\n * Run with the required parameters:\n * ```bash\n * bun debug.ts 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 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":"kpCAoBA,MAIM,EAAoB,IAEpB,EAAoB,EAAE,OAAO,CACjC,SAAU,EAAE,MAAM,CAAC,EAAE,OAAO,EAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAChE,CAAC,EAEK,EAAoB,EAAkB,OAAO,CACjD,MAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAC7B,CAAC,EAoBD,eAAsB,EAAiB,EAAmC,CACxE,IAAM,EAAO,EAAU,QAAQ,IAAI,EACnC,GAAI,CAAC,EAAK,IAAK,MAAU,MAAM,uBAAuB,EACtD,IAAM,EAAS,EAAkB,MAAM,EAAK,MAAM,EAGlD,EAA4B,EAAK,GAAG,EAEpC,IAAM,EAA6B,MAAM,EAA+B,CAAU,EAC5E,EAAY,MAAM,EAAc,EAAK,KAAK,EAAY,YAAY,CAAC,EAEnE,EAA+B,MAAM,EAAsB,EAAK,IAAK,CAA0B,EACrG,GAAI,EAA8B,CAChC,EAAoB,CAAE,WAAY,EAAU,EAAE,EAAE,IAAM,WAAY,GAAG,CAA6B,CAAC,EACnG,MACF,CAEA,IAAM,EAAuB,MAAM,EAAmB,EAAK,IAAK,EAAO,QAAQ,EAC/E,GAAI,CAAC,EAAsB,CACzB,EAAoB,CAClB,WAAY,EAAU,EAAE,EAAE,IAAM,WAChC,aAAc,EAAa,uCAC3B,OAAQ,sBAAsB,EAAO,SAAW,eAAe,EAAO,WAAa,IACrF,CAAC,EACD,MACF,CAEA,IAAM,EAAqB,EAA6B,CAAoB,EAC5E,GAAI,CAAC,EAAoB,CACvB,EAAoB,CAClB,WAAY,EAAU,EAAE,EAAE,IAAM,WAChC,aAAc,EAAa,aAC3B,OAAQ,sBACV,CAAC,EACD,MACF,CAGA,IAAM,EAAM,CAAE,GAAG,QAAQ,IAAK,GAAI,GAAI,YAAa,GAAI,EAEnD,EAEJ,GAAI,EAAmB,SACrB,GAAI,CACF,MAAM,EAAmB,SAAS,EAAK,GAAG,EAC1C,EAAuB,MAAM,EAAmB,EAAK,IAAK,EAAO,QAAQ,CAC3E,OAAS,EAAO,CACd,QAAQ,MAAM,iBAAkB,CAAK,EAErC,EAAoB,CAClB,WAAY,EAAU,EAAE,EAAE,IAAM,WAChC,aAAc,EAAa,YAC3B,OAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC/D,CAAC,EACD,MACF,CAGF,IAAM,EAAe,GAAwB,EAE7C,GAAI,EAAmB,aACrB,GAAI,CACF,IAAM,EAAe,EAAmB,aAAa,CAAY,EAE3D,EAAmB,EACvB,EAAa,GACb,EAAa,MAAM,CAAC,EACpB,CAAE,IAAK,EAAK,IAAK,SAAU,OAAQ,KAAI,EACvC,EACF,EAEI,EAA6B,EAAa,SAa9C,GAXI,EAAiB,SAAW,EAErB,EAAiB,YAAc,GACxC,EAAe,EAAa,2BAE5B,EAAiB,OAAO,OAAS,GACjC,EAAiB,OAAO,OAAS,KAEjC,EAAe,EAAa,kCAP5B,EAAe,EAAa,YAU1B,IAAiB,EAAa,SAAU,CAC1C,EAAoB,CAClB,WAAY,EAAU,EAAE,EAAE,IAAM,QAChC,eACA,WAAY,EAAiB,QAAU,IAAA,GACvC,OAAQ,EAAiB,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC/D,OAAQ,EAAiB,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC/D,YAAa,EAAiB,YAC9B,YAAa,EAAiB,WAChC,CAAC,EACD,MACF,CACF,OAAS,EAAO,CACd,QAAQ,MAAM,cAAe,CAAK,EAElC,EAAoB,CAClB,WAAY,EAAU,EAAE,EAAE,IAAM,QAChC,aAAc,EAAa,YAC3B,OAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC/D,CAAC,EACD,MACF,CAGF,IAAM,EAAc,MAAM,EAAyB,EAAK,GAAG,EAEvD,EAAU,SAAW,GACvB,EAAoB,CAAE,WAAY,UAAW,aAAc,EAAa,QAAS,CAAC,EAGpF,IAAK,IAAM,KAAY,EAAW,CAE5B,EAAU,QAAQ,eAAe,MAAM,EAAsB,EAAU,OAAO,cAAe,EAAK,GAAG,EACrG,EAAS,eAAe,MAAM,EAAsB,EAAS,cAAe,EAAK,GAAG,EAGxF,IAAM,EACJ,OAAO,EAA2B,aAAgB,SAC9C,EAA2B,YAAc,IACzC,EAEA,EAAU,EAAmB,QAAQ,CAAY,EAEjD,EAAc,EAClB,EAAQ,GACR,EAAQ,MAAM,CAAC,EACf,CAAE,IAAK,EAAK,IAAK,SAAU,OAAQ,MAAO,EAAS,MAAO,KAAI,EAC9D,CACF,EAEM,EAAc,MAAM,EAAgB,EAAK,IAAK,EAA2B,yBAA2B,CAAC,CAAC,EAGxG,EAA6B,EAAa,SAE9C,GAAI,EAAY,SAAW,EACzB,EAAe,EAAa,mBACvB,GAAI,EAAY,YAAc,EACnC,EAAe,EAAa,yBACvB,GAAI,EAAY,aAAe,EAA2B,iBAAmB,KAClF,EAAe,EAAa,2BACvB,GAAI,EAAY,OAAO,OAAS,GAAqB,EAAY,OAAO,OAAS,EACtF,EAAe,EAAa,gCACvB,GAAI,EAAY,QAAU,EAA2B,yBAAyB,QAAU,GAC7F,EAAe,EAAa,wCACvB,GAAI,CAAC,EAAoC,EAAY,OAAQ,EAAS,QAAU,EAAE,EACvF,EAAe,EAAa,kBACvB,GAAI,EAAS,eAAgB,CAClC,IAAM,EAAU,MAAM,EAAG,SAAS,QAAQ,EAAS,eAAgB,CAAE,cAAe,GAAM,UAAW,EAAK,CAAC,EAC3G,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAI,CAAC,EAAO,OAAO,EAAG,SACtB,IAAM,EAAqB,EAAK,SAAS,EAAS,eAAgB,EAAO,UAAU,EAC7E,EAAW,MAAM,EAAG,SAAS,SAAS,EAAK,KAAK,EAAO,WAAY,EAAO,IAAI,CAAC,EACrF,GAAI,CACF,IAAM,EAAe,EAAK,KAAK,EAAK,IAAK,EAAoB,EAAO,IAAI,EAExE,GAAI,CAAE,MAAM,EAA2B,EAAK,IAAK,CAAY,EAAI,MAAU,MAAM,oBAAoB,GAEjG,MADmB,EAAG,SAAS,SAAS,CAAY,EAAA,CAC3C,QAAQ,CAAQ,IAAM,IAAG,EAAe,EAAa,aACpE,OAAS,EAAO,CACd,QAAQ,MAAM,CAAK,EACnB,EAAe,EAAa,YAC9B,CACF,CACF,CAiBA,GAfA,EAAoB,CAClB,WAAY,EAAS,GACrB,eACA,WAAY,EAAY,QAAU,IAAA,GAClC,MAAO,EAAS,MAChB,OAAQ,EAAY,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC1D,OAAQ,EAAY,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC1D,YAAa,EAAY,YACzB,YAAa,EAAY,YACzB,YAAa,EAAY,OAAS,EAAI,EAAc,IAAA,EACtD,CAAC,EAGD,MAAM,EAAsB,EAAK,IAAK,CAAW,EAE7C,IAAiB,EAAa,SAAU,KAC9C,CACF,CAeA,eAAsB,EAAiB,EAAmC,CACxE,IAAM,EAAO,EAAU,QAAQ,IAAI,EACnC,GAAI,CAAC,EAAK,IAAK,MAAU,MAAM,uBAAuB,EACtD,IAAM,EAAS,EAAkB,MAAM,EAAK,MAAM,EAGlD,EAA4B,EAAK,GAAG,EAEpC,IAAM,EAA6B,MAAM,EAA+B,CAAU,EAE5E,EAAuB,MAAM,EAAmB,EAAK,IAAK,EAAO,QAAQ,EAC/E,GAAI,CAAC,EAAsB,CACzB,EAAoB,CAClB,WAAY,WACZ,aAAc,EAAa,uCAC3B,OAAQ,sBAAsB,EAAO,SAAW,eAAe,EAAO,WAAa,IACrF,CAAC,EACD,MACF,CAEA,IAAM,EAAqB,EAA6B,CAAoB,EAC5E,GAAI,CAAC,EAAoB,CACvB,EAAoB,CAClB,WAAY,WACZ,aAAc,EAAa,aAC3B,OAAQ,sBACV,CAAC,EACD,MACF,CAGA,IAAM,EAAM,CAAE,GAAG,QAAQ,IAAK,GAAI,GAAI,YAAa,GAAI,EAEnD,EAEJ,GAAI,EAAmB,SACrB,GAAI,CACF,MAAM,EAAmB,SAAS,EAAK,GAAG,EAC1C,EAAuB,MAAM,EAAmB,EAAK,IAAK,EAAO,QAAQ,CAC3E,OAAS,EAAO,CACd,QAAQ,MAAM,iBAAkB,CAAK,EAErC,EAAoB,CAClB,WAAY,WACZ,aAAc,EAAa,YAC3B,OAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC/D,CAAC,EACD,MACF,CAGF,IAAM,EAAe,GAAwB,EAE7C,GAAI,EAAmB,aACrB,GAAI,CACF,IAAM,EAAe,EAAmB,aAAa,CAAY,EAE3D,EAAmB,EACvB,EAAa,GACb,EAAa,MAAM,CAAC,EACpB,CAAE,IAAK,EAAK,IAAK,SAAU,OAAQ,KAAI,EACvC,EACF,EAEI,EAA6B,EAAa,SAa9C,GAXI,EAAiB,SAAW,EAErB,EAAiB,YAAc,GACxC,EAAe,EAAa,2BAE5B,EAAiB,OAAO,OAAS,GACjC,EAAiB,OAAO,OAAS,KAEjC,EAAe,EAAa,kCAP5B,EAAe,EAAa,YAU1B,IAAiB,EAAa,SAAU,CAC1C,EAAoB,CAClB,WAAY,QACZ,eACA,WAAY,EAAiB,QAAU,IAAA,GACvC,OAAQ,EAAiB,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC/D,OAAQ,EAAiB,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC/D,YAAa,EAAiB,YAC9B,YAAa,EAAiB,WAChC,CAAC,EACD,MACF,CACF,OAAS,EAAO,CACd,QAAQ,MAAM,cAAe,CAAK,EAElC,EAAoB,CAClB,WAAY,QACZ,aAAc,EAAa,YAC3B,OAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC/D,CAAC,EACD,MACF,CAGF,CACE,IAAM,EAAiB,KAAK,IAC1B,IACC,EAA2B,aAAe,GAAK,GAClD,EAEM,EAAU,EAAmB,QAAQ,CAAY,EAEjD,EAAc,EAClB,EAAQ,GACR,EAAQ,MAAM,CAAC,EACf,CAAE,IAAK,EAAK,IAAK,SAAU,OAAQ,MAAO,EAAO,MAAO,KAAI,EAC5D,CACF,EAEM,EAAc,MAAM,EAAgB,EAAK,IAAK,EAA2B,yBAA2B,CAAC,CAAC,EAExG,EAA6B,EAAa,SAE1C,EAAY,SAAW,EAEhB,EAAY,YAAc,EACnC,EAAe,EAAa,oBACnB,EAAY,aAAe,EAA2B,iBAAmB,KAClF,EAAe,EAAa,sBACnB,EAAY,OAAO,OAAS,GAAqB,EAAY,OAAO,OAAS,EACtF,EAAe,EAAa,2BACnB,EAAY,QAAU,EAA2B,yBAAyB,QAAU,KAC7F,EAAe,EAAa,oCAR5B,EAAe,EAAa,cAW9B,EAAoB,CAClB,WAAY,QACZ,eACA,WAAY,EAAY,QAAU,IAAA,GAClC,MAAO,EAAO,MACd,OAAQ,EAAY,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC1D,OAAQ,EAAY,OAAO,MAAM,EAAG,CAAiB,GAAK,IAAA,GAC1D,YAAa,EAAY,YACzB,YAAa,EAAY,YACzB,YAAa,EAAY,OAAS,EAAI,EAAc,IAAA,EACtD,CAAC,CACH,CACF"}
@@ -1,4 +1,4 @@
1
- "use strict";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../helpers/removeCommentsInSourceCode.cjs"),n=require("../helpers/safeFs.cjs");let r=require("node:fs");r=e.__toESM(r,1);let i=require("node:path");i=e.__toESM(i,1);const a={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},o={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/},{open:/`/,close:/(?<!\\)(?:\\{2})*`/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},s={c:{fileExtensions:[`.c`],buildCommand:e=>[`gcc`,`--std=c17`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},cpp:{fileExtensions:[`.cpp`],buildCommand:e=>[`g++`,`--std=c++20`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},csharp:{fileExtensions:[`.cs`],prebuild:async e=>{await n.writeFileWithoutFollowingSymlinks(i.default.join(e,`Main.csproj`),`<Project Sdk="Microsoft.NET.Sdk">
1
+ "use strict";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../helpers/removeCommentsInSourceCode.cjs"),n=require("../helpers/safeFs.cjs");let r=require("node:path");r=e.__toESM(r,1);let i=require("node:fs");i=e.__toESM(i,1);const a={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},o={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/},{open:/`/,close:/(?<!\\)(?:\\{2})*`/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},s={c:{fileExtensions:[`.c`],buildCommand:e=>[`gcc`,`--std=c17`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},cpp:{fileExtensions:[`.cpp`],buildCommand:e=>[`g++`,`--std=c++20`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:a},csharp:{fileExtensions:[`.cs`],prebuild:async e=>{await n.writeFileWithoutFollowingSymlinks(r.default.join(e,`Main.csproj`),`<Project Sdk="Microsoft.NET.Sdk">
2
2
  <PropertyGroup>
3
3
  <OutputType>Exe</OutputType>
4
4
  <TargetFramework>net8.0</TargetFramework>
@@ -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 r.default.promises.readdir(e,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await r.default.promises.readFile(i.default.join(e,o.name),`utf8`),[,c]=n.exec(t.removeCommentsInSourceCode(a,s))??[];c&&await r.default.promises.rename(i.default.join(e,o.name),i.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},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,4 +1,4 @@
1
- import{removeCommentsInSourceCode as e}from"../helpers/removeCommentsInSourceCode.js";import{writeFileWithoutFollowingSymlinks as t}from"../helpers/safeFs.js";import n from"node:fs";import r from"node:path";const i={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},a={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/},{open:/`/,close:/(?<!\\)(?:\\{2})*`/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},o={c:{fileExtensions:[`.c`],buildCommand:e=>[`gcc`,`--std=c17`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},cpp:{fileExtensions:[`.cpp`],buildCommand:e=>[`g++`,`--std=c++20`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},csharp:{fileExtensions:[`.cs`],prebuild:async e=>{await t(r.join(e,`Main.csproj`),`<Project Sdk="Microsoft.NET.Sdk">
1
+ import{removeCommentsInSourceCode as e}from"../helpers/removeCommentsInSourceCode.js";import{writeFileWithoutFollowingSymlinks as t}from"../helpers/safeFs.js";import n from"node:path";import r from"node:fs";const i={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},a={strings:[{open:/'/,close:/(?<!\\)(?:\\{2})*'/},{open:/"/,close:/(?<!\\)(?:\\{2})*"/},{open:/`/,close:/(?<!\\)(?:\\{2})*`/}],comments:[{open:/\n?[ \t]*\/\*/,close:/\*\//},{open:/\n?[ \t]*\/\//}]},o={c:{fileExtensions:[`.c`],buildCommand:e=>[`gcc`,`--std=c17`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},cpp:{fileExtensions:[`.cpp`],buildCommand:e=>[`g++`,`--std=c++20`,`-O2`,e,`-o`,`main`],command:()=>[`./main`],grammer:i},csharp:{fileExtensions:[`.cs`],prebuild:async e=>{await t(n.join(e,`Main.csproj`),`<Project Sdk="Microsoft.NET.Sdk">
2
2
  <PropertyGroup>
3
3
  <OutputType>Exe</OutputType>
4
4
  <TargetFramework>net8.0</TargetFramework>
@@ -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 n.promises.readdir(t,{withFileTypes:!0})){if(!o.isFile()||!o.name.endsWith(`.java`))continue;let s=await n.promises.readFile(r.join(t,o.name),`utf8`),[,c]=a.exec(e(i,s))??[];c&&await n.promises.rename(r.join(t,o.name),r.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},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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exercode/problem-utils",
3
- "version": "1.18.1",
3
+ "version": "1.19.0",
4
4
  "description": ":100: A set of utilities for judging programs on Exercode (https://exercode.willbooster.com/).",
5
5
  "keywords": [
6
6
  "exercode",
@@ -29,11 +29,15 @@
29
29
  "main": "dist/index.cjs",
30
30
  "module": "dist/index.js",
31
31
  "types": "dist/index.d.ts",
32
+ "bin": {
33
+ "exercode": "bin/exercode.mjs"
34
+ },
32
35
  "files": [
36
+ "bin/",
33
37
  "dist/"
34
38
  ],
35
39
  "scripts": {
36
- "build": "build-ts lib --input src/index.ts src/presets/*.ts",
40
+ "build": "build-ts lib --input src/index.ts src/presets/*.ts src/cli/*.ts",
37
41
  "cleanup": "bun wb lint --fix --format",
38
42
  "format": "bun wb lint --format",
39
43
  "lint": "bun wb lint",
@@ -67,8 +71,8 @@
67
71
  "@willbooster/oxfmt-config": "1.2.2",
68
72
  "@willbooster/oxlint-config": "1.4.8",
69
73
  "@willbooster/prettier-config": "10.4.0",
70
- "@willbooster/wb": "21.4.0",
71
- "build-ts": "21.0.4",
74
+ "@willbooster/wb": "21.7.2",
75
+ "build-ts": "21.0.7",
72
76
  "conventional-changelog-conventionalcommits": "10.2.1",
73
77
  "lefthook": "2.1.10",
74
78
  "oxfmt": "0.62.0",
@@ -76,7 +80,7 @@
76
80
  "oxlint-tsgolint": "7.0.2001",
77
81
  "prettier": "3.9.6",
78
82
  "prettier-plugin-java": "2.10.3",
79
- "puppeteer": "25.4.0",
83
+ "puppeteer": "25.5.0",
80
84
  "semantic-release": "25.0.9",
81
85
  "sort-package-json": "4.0.0",
82
86
  "typescript": "7.0.2",