@exercode/problem-utils 4.0.0 → 4.1.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/dist/helpers/startHttpServer.cjs +1 -1
- package/dist/helpers/startHttpServer.cjs.map +1 -1
- package/dist/helpers/startHttpServer.js +1 -1
- package/dist/helpers/startHttpServer.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/presets/tomcat.cjs +10 -0
- package/dist/presets/tomcat.cjs.map +1 -0
- package/dist/presets/tomcat.d.ts +8 -0
- package/dist/presets/tomcat.js +10 -0
- package/dist/presets/tomcat.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("node:http");r=e.__toESM(r,1);function i(e){let i=r.default.createServer((r,i)=>{let a=new URL(r.url??`/`,`http://127.0.0.1`).pathname;a===`/`&&(a=`/index.html`);let s=a.endsWith(`/`)?n.default.join(a,`index.html`):a,c=n.default.join(e,s);if(t.default.existsSync(c))try{let e=t.default.readFileSync(c);i.writeHead(200,{"Access-Control-Allow-Origin":`*`,Pragma:`no-cache`,"Cache-Control":`no-cache`,"Content-Type":o(s)}),i.end(e)}catch{i.statusCode=500,i.end()}else i.statusCode=404,i.end()});i.listen();let a=i.address();if(!a)throw Error(`server has been unexpectedly closed`);return{[Symbol.asyncDispose]:async()=>{i.closeAllConnections(),await new Promise(e=>{i.close(()=>{e()})})},url:typeof a==`string`?a:`http://127.0.0.1:${a.port}`,port:typeof a==`object`?a.port:void 0}}const a={".css":`text/css`,".html":`text/html`,".js":`text/javascript`,".gif":`image/gif`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`};function o(e){for(let[t,n]of Object.entries(a))if(e.endsWith(t))return n;return`text/plain`}exports.startHttpServer=i;
|
|
1
|
+
"use strict";const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("node:http");r=e.__toESM(r,1);function i(e){let i=r.default.createServer((r,i)=>{let a;try{let e=new URL(r.url??`/`,`http://127.0.0.1`).pathname;a=decodeURIComponent(e.replaceAll(/%(?![\da-f]{2})/giu,`%25`))}catch{i.writeHead(400),i.end();return}a===`/`&&(a=`/index.html`);let s=a.endsWith(`/`)?n.default.join(a,`index.html`):a,c=n.default.join(e,s);if(t.default.existsSync(c))try{let e=t.default.readFileSync(c);i.writeHead(200,{"Access-Control-Allow-Origin":`*`,Pragma:`no-cache`,"Cache-Control":`no-cache`,"Content-Type":o(s)}),i.end(e)}catch{i.statusCode=500,i.end()}else i.statusCode=404,i.end()});i.listen();let a=i.address();if(!a)throw Error(`server has been unexpectedly closed`);return{[Symbol.asyncDispose]:async()=>{i.closeAllConnections(),await new Promise(e=>{i.close(()=>{e()})})},url:typeof a==`string`?a:`http://127.0.0.1:${a.port}`,port:typeof a==`object`?a.port:void 0}}const a={".css":`text/css`,".html":`text/html`,".js":`text/javascript`,".gif":`image/gif`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`};function o(e){for(let[t,n]of Object.entries(a))if(e.endsWith(t))return n;return`text/plain`}exports.startHttpServer=i;
|
|
2
2
|
//# sourceMappingURL=startHttpServer.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startHttpServer.cjs","names":["http","path","fs"],"sources":["../../src/helpers/startHttpServer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport http from 'node:http';\nimport path from 'node:path';\n\nexport interface HttpServer {\n [Symbol.asyncDispose](): Promise<void>;\n url: string;\n port: number | undefined;\n}\n\n/**\n * Start a HTTP server for testing web pages.\n */\nexport function startHttpServer(dir: string): HttpServer {\n const server = http.createServer((request, response) => {\n let pathname = new URL(request.url ?? '/', 'http://127.0.0.1').pathname;\n\n if (pathname === '/') {\n pathname = '/index.html';\n }\n\n const pathnameWithIndexHtml = pathname.endsWith('/') ? path.join(pathname, 'index.html') : pathname;\n\n const filePath = path.join(dir, pathnameWithIndexHtml);\n\n if (fs.existsSync(filePath)) {\n try {\n const buffer = fs.readFileSync(filePath);\n response.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n Pragma: 'no-cache',\n 'Cache-Control': 'no-cache',\n 'Content-Type': getContentType(pathnameWithIndexHtml),\n });\n response.end(buffer);\n } catch {\n response.statusCode = 500;\n response.end();\n }\n } else {\n response.statusCode = 404;\n response.end();\n }\n });\n\n server.listen();\n\n const address = server.address();\n if (!address) throw new Error('server has been unexpectedly closed');\n\n return {\n [Symbol.asyncDispose]: async () => {\n server.closeAllConnections();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n url: typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`,\n port: typeof address === 'object' ? address.port : undefined,\n };\n}\n\nconst CONTENT_TYPE_BY_SUFFIX: Record<string, string> = {\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'text/javascript',\n '.gif': 'image/gif',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n};\n\nfunction getContentType(pathname: string): string {\n for (const [suffix, contentType] of Object.entries(CONTENT_TYPE_BY_SUFFIX)) {\n if (pathname.endsWith(suffix)) return contentType;\n }\n return 'text/plain';\n}\n"],"mappings":"oMAaA,SAAgB,EAAgB,EAAyB,CACvD,IAAM,EAASA,EAAAA,QAAK,cAAc,EAAS,IAAa,CACtD,IAAI,
|
|
1
|
+
{"version":3,"file":"startHttpServer.cjs","names":["http","path","fs"],"sources":["../../src/helpers/startHttpServer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport http from 'node:http';\nimport path from 'node:path';\n\nexport interface HttpServer {\n [Symbol.asyncDispose](): Promise<void>;\n url: string;\n port: number | undefined;\n}\n\n/**\n * Start a HTTP server for testing web pages.\n */\nexport function startHttpServer(dir: string): HttpServer {\n const server = http.createServer((request, response) => {\n let pathname: string;\n try {\n const encodedPathname = new URL(request.url ?? '/', 'http://127.0.0.1').pathname;\n pathname = decodeURIComponent(encodedPathname.replaceAll(/%(?![\\da-f]{2})/giu, '%25'));\n } catch {\n response.writeHead(400);\n response.end();\n return;\n }\n\n if (pathname === '/') {\n pathname = '/index.html';\n }\n\n const pathnameWithIndexHtml = pathname.endsWith('/') ? path.join(pathname, 'index.html') : pathname;\n\n const filePath = path.join(dir, pathnameWithIndexHtml);\n\n if (fs.existsSync(filePath)) {\n try {\n const buffer = fs.readFileSync(filePath);\n response.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n Pragma: 'no-cache',\n 'Cache-Control': 'no-cache',\n 'Content-Type': getContentType(pathnameWithIndexHtml),\n });\n response.end(buffer);\n } catch {\n response.statusCode = 500;\n response.end();\n }\n } else {\n response.statusCode = 404;\n response.end();\n }\n });\n\n server.listen();\n\n const address = server.address();\n if (!address) throw new Error('server has been unexpectedly closed');\n\n return {\n [Symbol.asyncDispose]: async () => {\n server.closeAllConnections();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n url: typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`,\n port: typeof address === 'object' ? address.port : undefined,\n };\n}\n\nconst CONTENT_TYPE_BY_SUFFIX: Record<string, string> = {\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'text/javascript',\n '.gif': 'image/gif',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n};\n\nfunction getContentType(pathname: string): string {\n for (const [suffix, contentType] of Object.entries(CONTENT_TYPE_BY_SUFFIX)) {\n if (pathname.endsWith(suffix)) return contentType;\n }\n return 'text/plain';\n}\n"],"mappings":"oMAaA,SAAgB,EAAgB,EAAyB,CACvD,IAAM,EAASA,EAAAA,QAAK,cAAc,EAAS,IAAa,CACtD,IAAI,EACJ,GAAI,CACF,IAAM,EAAkB,IAAI,IAAI,EAAQ,KAAO,IAAK,kBAAkB,CAAC,CAAC,SACxE,EAAW,mBAAmB,EAAgB,WAAW,qBAAsB,KAAK,CAAC,CACvF,MAAQ,CACN,EAAS,UAAU,GAAG,EACtB,EAAS,IAAI,EACb,MACF,CAEI,IAAa,MACf,EAAW,eAGb,IAAM,EAAwB,EAAS,SAAS,GAAG,EAAIC,EAAAA,QAAK,KAAK,EAAU,YAAY,EAAI,EAErF,EAAWA,EAAAA,QAAK,KAAK,EAAK,CAAqB,EAErD,GAAIC,EAAAA,QAAG,WAAW,CAAQ,EACxB,GAAI,CACF,IAAM,EAASA,EAAAA,QAAG,aAAa,CAAQ,EACvC,EAAS,UAAU,IAAK,CACtB,8BAA+B,IAC/B,OAAQ,WACR,gBAAiB,WACjB,eAAgB,EAAe,CAAqB,CACtD,CAAC,EACD,EAAS,IAAI,CAAM,CACrB,MAAQ,CACN,EAAS,WAAa,IACtB,EAAS,IAAI,CACf,KAEA,GAAS,WAAa,IACtB,EAAS,IAAI,CAEjB,CAAC,EAED,EAAO,OAAO,EAEd,IAAM,EAAU,EAAO,QAAQ,EAC/B,GAAI,CAAC,EAAS,MAAU,MAAM,qCAAqC,EAEnE,MAAO,EACJ,OAAO,cAAe,SAAY,CACjC,EAAO,oBAAoB,EAC3B,MAAM,IAAI,QAAe,GAAY,CACnC,EAAO,UAAY,CACjB,EAAQ,CACV,CAAC,CACH,CAAC,CACH,EACA,IAAK,OAAO,GAAY,SAAW,EAAU,oBAAoB,EAAQ,OACzE,KAAM,OAAO,GAAY,SAAW,EAAQ,KAAO,IAAA,EACrD,CACF,CAEA,MAAM,EAAiD,CACrD,OAAQ,WACR,QAAS,YACT,MAAO,kBACP,OAAQ,YACR,OAAQ,aACR,OAAQ,YACR,OAAQ,eACV,EAEA,SAAS,EAAe,EAA0B,CAChD,IAAK,GAAM,CAAC,EAAQ,KAAgB,OAAO,QAAQ,CAAsB,EACvE,GAAI,EAAS,SAAS,CAAM,EAAG,OAAO,EAExC,MAAO,YACT"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"node:fs";import t from"node:path";import n from"node:http";function r(r){let i=n.createServer((n,i)=>{let o=new URL(n.url??`/`,`http://127.0.0.1`).pathname;o===`/`&&(o=`/index.html`);let s=o.endsWith(`/`)?t.join(o,`index.html`):o,c=t.join(r,s);if(e.existsSync(c))try{let t=e.readFileSync(c);i.writeHead(200,{"Access-Control-Allow-Origin":`*`,Pragma:`no-cache`,"Cache-Control":`no-cache`,"Content-Type":a(s)}),i.end(t)}catch{i.statusCode=500,i.end()}else i.statusCode=404,i.end()});i.listen();let o=i.address();if(!o)throw Error(`server has been unexpectedly closed`);return{[Symbol.asyncDispose]:async()=>{i.closeAllConnections(),await new Promise(e=>{i.close(()=>{e()})})},url:typeof o==`string`?o:`http://127.0.0.1:${o.port}`,port:typeof o==`object`?o.port:void 0}}const i={".css":`text/css`,".html":`text/html`,".js":`text/javascript`,".gif":`image/gif`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`};function a(e){for(let[t,n]of Object.entries(i))if(e.endsWith(t))return n;return`text/plain`}export{r as startHttpServer};
|
|
1
|
+
import e from"node:fs";import t from"node:path";import n from"node:http";function r(r){let i=n.createServer((n,i)=>{let o;try{let e=new URL(n.url??`/`,`http://127.0.0.1`).pathname;o=decodeURIComponent(e.replaceAll(/%(?![\da-f]{2})/giu,`%25`))}catch{i.writeHead(400),i.end();return}o===`/`&&(o=`/index.html`);let s=o.endsWith(`/`)?t.join(o,`index.html`):o,c=t.join(r,s);if(e.existsSync(c))try{let t=e.readFileSync(c);i.writeHead(200,{"Access-Control-Allow-Origin":`*`,Pragma:`no-cache`,"Cache-Control":`no-cache`,"Content-Type":a(s)}),i.end(t)}catch{i.statusCode=500,i.end()}else i.statusCode=404,i.end()});i.listen();let o=i.address();if(!o)throw Error(`server has been unexpectedly closed`);return{[Symbol.asyncDispose]:async()=>{i.closeAllConnections(),await new Promise(e=>{i.close(()=>{e()})})},url:typeof o==`string`?o:`http://127.0.0.1:${o.port}`,port:typeof o==`object`?o.port:void 0}}const i={".css":`text/css`,".html":`text/html`,".js":`text/javascript`,".gif":`image/gif`,".jpg":`image/jpeg`,".png":`image/png`,".svg":`image/svg+xml`};function a(e){for(let[t,n]of Object.entries(i))if(e.endsWith(t))return n;return`text/plain`}export{r as startHttpServer};
|
|
2
2
|
//# sourceMappingURL=startHttpServer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startHttpServer.js","names":[],"sources":["../../src/helpers/startHttpServer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport http from 'node:http';\nimport path from 'node:path';\n\nexport interface HttpServer {\n [Symbol.asyncDispose](): Promise<void>;\n url: string;\n port: number | undefined;\n}\n\n/**\n * Start a HTTP server for testing web pages.\n */\nexport function startHttpServer(dir: string): HttpServer {\n const server = http.createServer((request, response) => {\n let pathname = new URL(request.url ?? '/', 'http://127.0.0.1').pathname;\n\n if (pathname === '/') {\n pathname = '/index.html';\n }\n\n const pathnameWithIndexHtml = pathname.endsWith('/') ? path.join(pathname, 'index.html') : pathname;\n\n const filePath = path.join(dir, pathnameWithIndexHtml);\n\n if (fs.existsSync(filePath)) {\n try {\n const buffer = fs.readFileSync(filePath);\n response.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n Pragma: 'no-cache',\n 'Cache-Control': 'no-cache',\n 'Content-Type': getContentType(pathnameWithIndexHtml),\n });\n response.end(buffer);\n } catch {\n response.statusCode = 500;\n response.end();\n }\n } else {\n response.statusCode = 404;\n response.end();\n }\n });\n\n server.listen();\n\n const address = server.address();\n if (!address) throw new Error('server has been unexpectedly closed');\n\n return {\n [Symbol.asyncDispose]: async () => {\n server.closeAllConnections();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n url: typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`,\n port: typeof address === 'object' ? address.port : undefined,\n };\n}\n\nconst CONTENT_TYPE_BY_SUFFIX: Record<string, string> = {\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'text/javascript',\n '.gif': 'image/gif',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n};\n\nfunction getContentType(pathname: string): string {\n for (const [suffix, contentType] of Object.entries(CONTENT_TYPE_BY_SUFFIX)) {\n if (pathname.endsWith(suffix)) return contentType;\n }\n return 'text/plain';\n}\n"],"mappings":"yEAaA,SAAgB,EAAgB,EAAyB,CACvD,IAAM,EAAS,EAAK,cAAc,EAAS,IAAa,CACtD,IAAI,
|
|
1
|
+
{"version":3,"file":"startHttpServer.js","names":[],"sources":["../../src/helpers/startHttpServer.ts"],"sourcesContent":["import fs from 'node:fs';\nimport http from 'node:http';\nimport path from 'node:path';\n\nexport interface HttpServer {\n [Symbol.asyncDispose](): Promise<void>;\n url: string;\n port: number | undefined;\n}\n\n/**\n * Start a HTTP server for testing web pages.\n */\nexport function startHttpServer(dir: string): HttpServer {\n const server = http.createServer((request, response) => {\n let pathname: string;\n try {\n const encodedPathname = new URL(request.url ?? '/', 'http://127.0.0.1').pathname;\n pathname = decodeURIComponent(encodedPathname.replaceAll(/%(?![\\da-f]{2})/giu, '%25'));\n } catch {\n response.writeHead(400);\n response.end();\n return;\n }\n\n if (pathname === '/') {\n pathname = '/index.html';\n }\n\n const pathnameWithIndexHtml = pathname.endsWith('/') ? path.join(pathname, 'index.html') : pathname;\n\n const filePath = path.join(dir, pathnameWithIndexHtml);\n\n if (fs.existsSync(filePath)) {\n try {\n const buffer = fs.readFileSync(filePath);\n response.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n Pragma: 'no-cache',\n 'Cache-Control': 'no-cache',\n 'Content-Type': getContentType(pathnameWithIndexHtml),\n });\n response.end(buffer);\n } catch {\n response.statusCode = 500;\n response.end();\n }\n } else {\n response.statusCode = 404;\n response.end();\n }\n });\n\n server.listen();\n\n const address = server.address();\n if (!address) throw new Error('server has been unexpectedly closed');\n\n return {\n [Symbol.asyncDispose]: async () => {\n server.closeAllConnections();\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve();\n });\n });\n },\n url: typeof address === 'string' ? address : `http://127.0.0.1:${address.port}`,\n port: typeof address === 'object' ? address.port : undefined,\n };\n}\n\nconst CONTENT_TYPE_BY_SUFFIX: Record<string, string> = {\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'text/javascript',\n '.gif': 'image/gif',\n '.jpg': 'image/jpeg',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n};\n\nfunction getContentType(pathname: string): string {\n for (const [suffix, contentType] of Object.entries(CONTENT_TYPE_BY_SUFFIX)) {\n if (pathname.endsWith(suffix)) return contentType;\n }\n return 'text/plain';\n}\n"],"mappings":"yEAaA,SAAgB,EAAgB,EAAyB,CACvD,IAAM,EAAS,EAAK,cAAc,EAAS,IAAa,CACtD,IAAI,EACJ,GAAI,CACF,IAAM,EAAkB,IAAI,IAAI,EAAQ,KAAO,IAAK,kBAAkB,CAAC,CAAC,SACxE,EAAW,mBAAmB,EAAgB,WAAW,qBAAsB,KAAK,CAAC,CACvF,MAAQ,CACN,EAAS,UAAU,GAAG,EACtB,EAAS,IAAI,EACb,MACF,CAEI,IAAa,MACf,EAAW,eAGb,IAAM,EAAwB,EAAS,SAAS,GAAG,EAAI,EAAK,KAAK,EAAU,YAAY,EAAI,EAErF,EAAW,EAAK,KAAK,EAAK,CAAqB,EAErD,GAAI,EAAG,WAAW,CAAQ,EACxB,GAAI,CACF,IAAM,EAAS,EAAG,aAAa,CAAQ,EACvC,EAAS,UAAU,IAAK,CACtB,8BAA+B,IAC/B,OAAQ,WACR,gBAAiB,WACjB,eAAgB,EAAe,CAAqB,CACtD,CAAC,EACD,EAAS,IAAI,CAAM,CACrB,MAAQ,CACN,EAAS,WAAa,IACtB,EAAS,IAAI,CACf,KAEA,GAAS,WAAa,IACtB,EAAS,IAAI,CAEjB,CAAC,EAED,EAAO,OAAO,EAEd,IAAM,EAAU,EAAO,QAAQ,EAC/B,GAAI,CAAC,EAAS,MAAU,MAAM,qCAAqC,EAEnE,MAAO,EACJ,OAAO,cAAe,SAAY,CACjC,EAAO,oBAAoB,EAC3B,MAAM,IAAI,QAAe,GAAY,CACnC,EAAO,UAAY,CACjB,EAAQ,CACV,CAAC,CACH,CAAC,CACH,EACA,IAAK,OAAO,GAAY,SAAW,EAAU,oBAAoB,EAAQ,OACzE,KAAM,OAAO,GAAY,SAAW,EAAQ,KAAO,IAAA,EACrD,CACF,CAEA,MAAM,EAAiD,CACrD,OAAQ,WACR,QAAS,YACT,MAAO,kBACP,OAAQ,YACR,OAAQ,aACR,OAAQ,YACR,OAAQ,eACV,EAEA,SAAS,EAAe,EAA0B,CAChD,IAAK,GAAM,CAAC,EAAQ,KAAgB,OAAO,QAAQ,CAAsB,EACvE,GAAI,EAAS,SAAS,CAAM,EAAG,OAAO,EAExC,MAAO,YACT"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./helpers/compareStdoutAsSpaceSeparatedTokens.cjs"),t=require("./types/testCaseResult.cjs"),n=require("./helpers/printTestCaseResult.cjs"),r=require("./helpers/compareExpectedOutputFiles.cjs"),i=require("./helpers/defaultStdioHarness.cjs"),a=require("./helpers/parseArgs.cjs"),o=require("./helpers/parseCsv.cjs"),s=require("./helpers/readTestCases.cjs"),c=require("./helpers/removeCommentsInSourceCode.cjs"),l=require("./helpers/runCommandInTemporaryPackageManagerProject.cjs"),u=require("./helpers/runPythonInTemporaryUvProject.cjs"),d=require("./helpers/sourceCodeGrammars.cjs"),f=require("./helpers/startHttpServer.cjs"),p=require("./types/problem.cjs"),m=require("./learningMaterial/
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./helpers/compareStdoutAsSpaceSeparatedTokens.cjs"),t=require("./types/testCaseResult.cjs"),n=require("./helpers/printTestCaseResult.cjs"),r=require("./helpers/compareExpectedOutputFiles.cjs"),i=require("./helpers/defaultStdioHarness.cjs"),a=require("./helpers/parseArgs.cjs"),o=require("./helpers/parseCsv.cjs"),s=require("./helpers/readTestCases.cjs"),c=require("./helpers/removeCommentsInSourceCode.cjs"),l=require("./helpers/runCommandInTemporaryPackageManagerProject.cjs"),u=require("./helpers/runPythonInTemporaryUvProject.cjs"),d=require("./helpers/sourceCodeGrammars.cjs"),f=require("./helpers/startHttpServer.cjs"),p=require("./types/problem.cjs"),m=require("./learningMaterial/frontmatter.cjs"),h=require("./learningMaterial/validationResult.cjs"),g=require("./learningMaterial/validateMaterial.cjs"),_=require("./learningMaterial/validateContest.cjs"),v=require("./learningMaterial/validateCourse.cjs"),y=require("./learningMaterial/validateProblem.cjs"),b=require("./types/decisionCode.cjs");exports.CsvParseError=o.CsvParseError,exports.DecisionCode=b.DecisionCode,exports.HARNESS_FILE_PRESETS=i.HARNESS_FILE_PRESETS,exports.MAX_COMPARED_FILE_BYTES=r.MAX_COMPARED_FILE_BYTES,exports.MAX_REPORTED_FILE_BYTES=r.MAX_REPORTED_FILE_BYTES,exports.TEST_CASE_RESULT_PREFIX=t.TEST_CASE_RESULT_PREFIX,exports.codeRuleSchema=p.codeRuleSchema,exports.compareExpectedOutputFiles=r.compareExpectedOutputFiles,exports.compareStdoutAsSpaceSeparatedTokens=e.compareStdoutAsSpaceSeparatedTokens,exports.copyPackageManagerProjectFiles=l.copyPackageManagerProjectFiles,exports.encodeFileForTestCaseResult=n.encodeFileForTestCaseResult,exports.findDefaultStdioHarnessFiles=i.findDefaultStdioHarnessFiles,exports.formatValidationReport=h.formatValidationReport,exports.formatZodIssues=h.formatZodIssues,exports.isDefaultStdioHarnessSource=i.isDefaultStdioHarnessSource,exports.judgeAgainstExpectations=r.judgeAgainstExpectations,exports.languageIdToSourceCodeGrammar=d.languageIdToSourceCodeGrammar,exports.mergeComparisonOutputFiles=r.mergeComparisonOutputFiles,exports.mergeSubmissionPeriods=g.mergeSubmissionPeriods,exports.normalizeCodeRule=p.normalizeCodeRule,exports.parseArgs=a.parseArgs,exports.parseCsv=o.parseCsv,exports.parseCsvRecords=o.parseCsvRecords,exports.parseFrontmatter=m.parseFrontmatter,exports.printTestCaseResult=n.printTestCaseResult,exports.problemMarkdownFrontMatterSchema=p.problemMarkdownFrontMatterSchema,exports.readTestCases=s.readTestCases,exports.removeCommentsAndStringsInSourceCode=c.removeCommentsAndStringsInSourceCode,exports.removeCommentsInSourceCode=c.removeCommentsInSourceCode,exports.reportDuplicateIds=h.reportDuplicateIds,exports.reportExcessChatMarkers=g.reportExcessChatMarkers,exports.reportForeignProblemCourseIds=g.reportForeignProblemCourseIds,exports.runCommandInTemporaryPackageManagerProject=l.runCommandInTemporaryPackageManagerProject,exports.runPythonInTemporaryUvProject=u.runPythonInTemporaryUvProject,exports.startHttpServer=f.startHttpServer,exports.testCaseResultSchema=t.testCaseResultSchema,exports.validateContestFile=_.validateContestFile,exports.validateCourseDirectory=v.validateCourseDirectory,exports.validateMaterialFile=g.validateMaterialFile,exports.validateProblemDirectory=y.validateProblemDirectory,exports.validateSubmissionPeriods=g.validateSubmissionPeriods;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{compareStdoutAsSpaceSeparatedTokens as e}from"./helpers/compareStdoutAsSpaceSeparatedTokens.js";import{TEST_CASE_RESULT_PREFIX as t,testCaseResultSchema as n}from"./types/testCaseResult.js";import{encodeFileForTestCaseResult as r,printTestCaseResult as i}from"./helpers/printTestCaseResult.js";import{MAX_COMPARED_FILE_BYTES as a,MAX_REPORTED_FILE_BYTES as o,compareExpectedOutputFiles as s,judgeAgainstExpectations as c,mergeComparisonOutputFiles as l}from"./helpers/compareExpectedOutputFiles.js";import{HARNESS_FILE_PRESETS as u,findDefaultStdioHarnessFiles as d,isDefaultStdioHarnessSource as f}from"./helpers/defaultStdioHarness.js";import{parseArgs as p}from"./helpers/parseArgs.js";import{CsvParseError as m,parseCsv as h,parseCsvRecords as g}from"./helpers/parseCsv.js";import{readTestCases as _}from"./helpers/readTestCases.js";import{removeCommentsAndStringsInSourceCode as v,removeCommentsInSourceCode as y}from"./helpers/removeCommentsInSourceCode.js";import{copyPackageManagerProjectFiles as b,runCommandInTemporaryPackageManagerProject as x}from"./helpers/runCommandInTemporaryPackageManagerProject.js";import{runPythonInTemporaryUvProject as S}from"./helpers/runPythonInTemporaryUvProject.js";import{languageIdToSourceCodeGrammar as C}from"./helpers/sourceCodeGrammars.js";import{startHttpServer as w}from"./helpers/startHttpServer.js";import{codeRuleSchema as T,normalizeCodeRule as E,problemMarkdownFrontMatterSchema as D}from"./types/problem.js";import{formatValidationReport as
|
|
1
|
+
import{compareStdoutAsSpaceSeparatedTokens as e}from"./helpers/compareStdoutAsSpaceSeparatedTokens.js";import{TEST_CASE_RESULT_PREFIX as t,testCaseResultSchema as n}from"./types/testCaseResult.js";import{encodeFileForTestCaseResult as r,printTestCaseResult as i}from"./helpers/printTestCaseResult.js";import{MAX_COMPARED_FILE_BYTES as a,MAX_REPORTED_FILE_BYTES as o,compareExpectedOutputFiles as s,judgeAgainstExpectations as c,mergeComparisonOutputFiles as l}from"./helpers/compareExpectedOutputFiles.js";import{HARNESS_FILE_PRESETS as u,findDefaultStdioHarnessFiles as d,isDefaultStdioHarnessSource as f}from"./helpers/defaultStdioHarness.js";import{parseArgs as p}from"./helpers/parseArgs.js";import{CsvParseError as m,parseCsv as h,parseCsvRecords as g}from"./helpers/parseCsv.js";import{readTestCases as _}from"./helpers/readTestCases.js";import{removeCommentsAndStringsInSourceCode as v,removeCommentsInSourceCode as y}from"./helpers/removeCommentsInSourceCode.js";import{copyPackageManagerProjectFiles as b,runCommandInTemporaryPackageManagerProject as x}from"./helpers/runCommandInTemporaryPackageManagerProject.js";import{runPythonInTemporaryUvProject as S}from"./helpers/runPythonInTemporaryUvProject.js";import{languageIdToSourceCodeGrammar as C}from"./helpers/sourceCodeGrammars.js";import{startHttpServer as w}from"./helpers/startHttpServer.js";import{codeRuleSchema as T,normalizeCodeRule as E,problemMarkdownFrontMatterSchema as D}from"./types/problem.js";import{parseFrontmatter as O}from"./learningMaterial/frontmatter.js";import{formatValidationReport as k,formatZodIssues as A,reportDuplicateIds as j}from"./learningMaterial/validationResult.js";import{mergeSubmissionPeriods as M,reportExcessChatMarkers as N,reportForeignProblemCourseIds as P,validateMaterialFile as F,validateSubmissionPeriods as I}from"./learningMaterial/validateMaterial.js";import{validateContestFile as L}from"./learningMaterial/validateContest.js";import{validateCourseDirectory as R}from"./learningMaterial/validateCourse.js";import{validateProblemDirectory as z}from"./learningMaterial/validateProblem.js";import{DecisionCode as B}from"./types/decisionCode.js";export{m as CsvParseError,B as DecisionCode,u as HARNESS_FILE_PRESETS,a as MAX_COMPARED_FILE_BYTES,o as MAX_REPORTED_FILE_BYTES,t as TEST_CASE_RESULT_PREFIX,T as codeRuleSchema,s as compareExpectedOutputFiles,e as compareStdoutAsSpaceSeparatedTokens,b as copyPackageManagerProjectFiles,r as encodeFileForTestCaseResult,d as findDefaultStdioHarnessFiles,k as formatValidationReport,A as formatZodIssues,f as isDefaultStdioHarnessSource,c as judgeAgainstExpectations,C as languageIdToSourceCodeGrammar,l as mergeComparisonOutputFiles,M as mergeSubmissionPeriods,E as normalizeCodeRule,p as parseArgs,h as parseCsv,g as parseCsvRecords,O as parseFrontmatter,i as printTestCaseResult,D as problemMarkdownFrontMatterSchema,_ as readTestCases,v as removeCommentsAndStringsInSourceCode,y as removeCommentsInSourceCode,j as reportDuplicateIds,N as reportExcessChatMarkers,P as reportForeignProblemCourseIds,x as runCommandInTemporaryPackageManagerProject,S as runPythonInTemporaryUvProject,w as startHttpServer,n as testCaseResultSchema,L as validateContestFile,R as validateCourseDirectory,F as validateMaterialFile,z as validateProblemDirectory,I as validateSubmissionPeriods};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../helpers/printTestCaseResult.cjs"),n=require("../helpers/parseArgs.cjs"),r=require("../types/decisionCode.cjs");let i=require("node:fs");i=e.__toESM(i,1);let a=require("node:path");a=e.__toESM(a,1);let o=require("zod"),s=require("node:os"),c=require("node:child_process"),l=require("node:http");l=e.__toESM(l,1);let u=require("node:timers/promises");const d=`judge`,f=5e4,p=`http://localhost:59000`,m=new Set([`.java`,`.jsp`,`.html`,`.htm`,`.xml`,`.js`,`.css`]);async function h(e){if(process.argv.includes(`--evaluate`)){try{await e.evaluate()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exitCode=1}return}let{cwd:o}=n.parseArgs(process.argv);if(!o)throw Error(`cwd argument required`);let c=`test1`,l=await y(o,e.forbiddenTexts??[]);if(l){t.printTestCaseResult({testCaseId:c,...l});return}let u=await i.default.promises.mkdtemp(a.default.join((0,s.tmpdir)(),`tomcat_judge_`)),d=a.default.join(u,`build`),f,p;try{await i.default.promises.mkdir(d,{recursive:!0}),await g(d,o,e);let n=S(d);if(n){t.printTestCaseResult({testCaseId:c,...n});return}p=M(),f=await w(p,u),await k(p,f),await T(d,f),await E(p,f);let r=D(d,e.problemDirectoryPath);t.printTestCaseResult({testCaseId:c,...r})}catch(e){t.printTestCaseResult({testCaseId:c,decisionCode:r.DecisionCode.JUDGE_NOT_AVAILABLE,stderr:e instanceof Error?e.message:String(e)})}finally{try{p&&f&&await k(p,f)}catch{}await i.default.promises.rm(u,{recursive:!0,force:!0})}}async function g(e,t,n){await i.default.promises.mkdir(a.default.join(e,`src/main/java`),{recursive:!0}),await i.default.promises.mkdir(a.default.join(e,`src/main/webapp/WEB-INF/jsp`),{recursive:!0}),await i.default.promises.copyFile(a.default.join(n.problemDirectoryPath,`pom.xml`),a.default.join(e,`pom.xml`));let r=await b(t);for(let o of r){let r=a.default.join(t,o),s=await _(e,o,r,n.jspDirectory);await i.default.promises.mkdir(a.default.dirname(s),{recursive:!0}),await i.default.promises.copyFile(r,s)}}async function _(e,t,n,r){let i=t.replaceAll(`\\`,`/`);if(i.startsWith(`src/main/`))return a.default.join(e,i);if(i.startsWith(`WEB-INF/`)||i.startsWith(`META-INF/`))return a.default.join(e,`src/main/webapp`,i);let o=a.default.extname(t).toLowerCase();return o===`.java`?a.default.join(e,`src/main/java`,await v(n,t)):o===`.jsp`?a.default.join(e,`src/main/webapp`,r,a.default.basename(t)):a.default.join(e,`src/main/webapp`,i)}async function v(e,t){let n=await i.default.promises.readFile(e,`utf8`),r=/^\s*package\s+([a-zA-Z0-9_.]+)\s*;/m.exec(n);return r?.[1]?a.default.join(r[1].replaceAll(`.`,`/`),a.default.basename(t)):t}async function y(e,t){let n=[];for(let r of await b(e)){if(!m.has(a.default.extname(r).toLowerCase()))continue;let o=await i.default.promises.readFile(a.default.join(e,r),`utf8`);for(let e of t)o.includes(e)&&n.push({path:r,pattern:e})}if(n.length!==0)return{decisionCode:r.DecisionCode.FORBIDDEN_PATTERNS_IN_CODE_ERROR,feedbackMarkdown:`ソースコード中に禁止された文字列が含まれています。
|
|
2
|
+
ソースコードを修正してから再度提出してください。
|
|
3
|
+
|
|
4
|
+
| ファイル | 禁止パターン |
|
|
5
|
+
| -------- | ------------ |
|
|
6
|
+
`+n.map(e=>`| \`${e.path}\` | \`${e.pattern}\` |`).join(`
|
|
7
|
+
`)}}async function b(e){let t=[];return await x(e,``,t),t.toSorted()}async function x(e,t,n){let r=t?a.default.join(e,t):e,o=await i.default.promises.readdir(r,{withFileTypes:!0});for(let r of o){let i=t?a.default.join(t,r.name):r.name;if(r.isDirectory()){await x(e,i,n);continue}r.isFile()&&n.push(i)}}function S(e){let t=O([`mvn`,`clean`,`package`,`--quiet`,`--batch-mode`,`--offline`],e,60);if(t.timeSeconds>60)return{decisionCode:r.DecisionCode.BUILD_TIME_LIMIT_EXCEEDED,stderr:F(t.stderr),stdout:F(t.stdout),exitStatus:t.status,timeSeconds:t.timeSeconds,memoryBytes:t.memoryBytes};if(t.status!==0)return{decisionCode:r.DecisionCode.BUILD_ERROR,stderr:C(t.stdout,t.stderr),stdout:F(t.stdout),exitStatus:t.status,timeSeconds:t.timeSeconds,memoryBytes:t.memoryBytes}}function C(e,t){return F(`${e}
|
|
8
|
+
${t}`.trim())}async function w(e,t){let n=a.default.join(t,`catalina-base`);await i.default.promises.cp(a.default.join(e,`conf`),a.default.join(n,`conf`),{recursive:!0,dereference:!0});for(let e of[`logs`,`temp`,`webapps`,`work`])await i.default.promises.mkdir(a.default.join(n,e),{recursive:!0});let r=a.default.join(n,`conf`,`server.xml`),o=await i.default.promises.readFile(r,`utf8`);return await i.default.promises.writeFile(r,o.replaceAll(`port="8080"`,`port="59000"`),`utf8`),n}async function T(e,t){let n=a.default.join(e,`target`,`${d}.war`),r=a.default.join(t,`webapps`),o=a.default.join(r,d),s=a.default.join(r,`${d}.war`);await i.default.promises.mkdir(r,{recursive:!0}),await i.default.promises.rm(o,{recursive:!0,force:!0}),await i.default.promises.rm(s,{force:!0}),await i.default.promises.copyFile(n,s)}async function E(e,t){let n=O([a.default.join(e,`bin`,`startup.sh`)],void 0,10,{...process.env,CATALINA_BASE:t,CATALINA_HOME:e});if(n.status!==0)throw Error(`Failed to start Tomcat: ${n.stderr.trim()||n.stdout.trim()}`);if(!await A(!0,1e4))throw Error(`Tomcat failed to start within 10 seconds`)}function D(e,t){let n=O([`bun`,`run`,`./judge.ts`,`--evaluate`],t,30,{...process.env,WORKING_DIRECTORY_PATH:e}),i=P(a.default.join(e,`__SCREENSHOTS.json`));return n.timeSeconds>30?{decisionCode:r.DecisionCode.TIME_LIMIT_EXCEEDED,stderr:F(n.stderr),stdout:F(n.stdout),exitStatus:n.status,timeSeconds:n.timeSeconds,memoryBytes:n.memoryBytes,outputFiles:i}:n.stdout.length>f||n.stderr.length>f?{decisionCode:r.DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED,stderr:F(n.stderr),stdout:F(n.stdout),exitStatus:n.status,timeSeconds:n.timeSeconds,memoryBytes:n.memoryBytes,outputFiles:i}:n.status===0?{decisionCode:r.DecisionCode.ACCEPTED,stderr:F(n.stderr)||void 0,stdout:F(n.stdout)||void 0,exitStatus:n.status,timeSeconds:n.timeSeconds,memoryBytes:n.memoryBytes,outputFiles:i}:{decisionCode:r.DecisionCode.WRONG_ANSWER,stderr:F(n.stderr),stdout:F(n.stdout),exitStatus:n.status,timeSeconds:n.timeSeconds,memoryBytes:n.memoryBytes,outputFiles:i}}function O(e,t,n,r=process.env){let i=Date.now(),a=process.platform===`darwin`?`gtime`:`/usr/bin/time`,o=(0,c.spawnSync)(`timeout`,[n.toFixed(3),a,`--format`,`%e %M`,...e],{cwd:t,env:r,encoding:`utf8`}),s=(Date.now()-i)/1e3,l=[o.stderr,o.error?.message].filter(Boolean).join(`
|
|
9
|
+
`),u=/(?:^|\n)(\d+(?:\.\d+)?) (\d+)\s*$/u.exec(l),d=u?l.slice(0,u.index):l,f=Number(u?.[1])||s,p=1024*Number(u?.[2]??0);return{status:o.status===124?0:o.status??void 0,stdout:o.stdout,stderr:d,timeSeconds:o.status===124?n+.001:f,memoryBytes:p}}async function k(e,t){await j()&&(O([a.default.join(e,`bin`,`catalina.sh`),`stop`],void 0,10,{...process.env,CATALINA_BASE:t,CATALINA_HOME:e}),await A(!1,1e4))}async function A(e,t){let n=Date.now();for(;Date.now()-n<t;){if(await j()===e)return!0;await(0,u.setTimeout)(200)}return await j()===e}async function j(){return await new Promise(e=>{let t=l.default.get(p,t=>{t.resume();let n=t.statusCode??0;e(n>=200&&n<300||n===404)});t.on(`error`,()=>e(!1)),t.setTimeout(1e3,()=>t.destroy())})}function M(){let e=process.env.CATALINA_HOME;if(!e)throw Error(`CATALINA_HOME is not set`);return N(e),a.default.resolve(e)}function N(e){if(!i.default.existsSync(a.default.join(e,`bin`,`catalina.sh`))||!i.default.existsSync(a.default.join(e,`conf`,`server.xml`)))throw Error(`Invalid CATALINA_HOME path`)}function P(e){if(!i.default.existsSync(e))return;let t=JSON.parse(i.default.readFileSync(e,`utf8`)),n=o.z.array(o.z.unknown()).safeParse(t);if(!n.success)return;let r=o.z.object({path:o.z.string(),data:o.z.string(),encoding:o.z.literal(`base64`).optional()});return n.data.flatMap(e=>{let t=r.safeParse(e);return t.success?[t.data]:[]})}function F(e){return e.slice(0,f)}function I(e){return`${p}/${d}${e.startsWith(`/`)?e:`/${e}`}`}exports.buildTomcatUrl=I,exports.tomcatJudgePreset=h;
|
|
10
|
+
//# sourceMappingURL=tomcat.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomcat.cjs","names":["parseArgs","fs","path","tmpdir","DecisionCode","spawnSync","sleep","http","z"],"sources":["../../src/presets/tomcat.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport http from 'node:http';\nimport { tmpdir } from 'node:os';\nimport path from 'node:path';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { DecisionCode, parseArgs, printTestCaseResult, type TestCaseResult } from '../index.js';\nimport { z } from 'zod';\n\nexport interface TomcatJudgePresetOptions {\n problemDirectoryPath: string;\n jspDirectory: '' | 'WEB-INF/jsp';\n forbiddenTexts?: readonly string[];\n evaluate: () => Promise<void>;\n}\n\ntype JudgeResult = Omit<TestCaseResult, 'testCaseId'>;\ntype OutputFile = NonNullable<TestCaseResult['outputFiles']>[number];\ninterface CommandResult {\n status: number | undefined;\n stdout: string;\n stderr: string;\n timeSeconds: number;\n memoryBytes: number;\n}\nconst APPLICATION_NAME = 'judge';\nconst BUILD_TIMEOUT_SECONDS = 60;\nconst EVALUATE_TIMEOUT_SECONDS = 30;\nconst MAX_OUTPUT_LENGTH = 50_000;\nconst TOMCAT_BASE_URL = 'http://localhost:59000';\nconst SOURCE_FILE_EXTENSIONS = new Set(['.java', '.jsp', '.html', '.htm', '.xml', '.js', '.css']);\n\nexport async function tomcatJudgePreset(options: TomcatJudgePresetOptions): Promise<void> {\n if (process.argv.includes('--evaluate')) {\n try {\n await options.evaluate();\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n return;\n }\n\n const { cwd: submissionDir } = parseArgs(process.argv);\n if (!submissionDir) throw new Error('cwd argument required');\n const testCaseId = 'test1';\n const staticAnalysisResult = await judgeByStaticAnalysis(submissionDir, options.forbiddenTexts ?? []);\n if (staticAnalysisResult) {\n printTestCaseResult({ testCaseId, ...staticAnalysisResult });\n return;\n }\n\n const runRootDir = await fs.promises.mkdtemp(path.join(tmpdir(), 'tomcat_judge_'));\n const buildDir = path.join(runRootDir, 'build');\n let catalinaBaseDir: string | undefined;\n let catalinaHome: string | undefined;\n\n try {\n await fs.promises.mkdir(buildDir, { recursive: true });\n await prepareBuildDirectory(buildDir, submissionDir, options);\n\n const buildResult = buildWithMaven(buildDir);\n if (buildResult) {\n printTestCaseResult({ testCaseId, ...buildResult });\n return;\n }\n\n catalinaHome = getCatalinaHome();\n catalinaBaseDir = await createCatalinaBaseDir(catalinaHome, runRootDir);\n await ensureTomcatStopped(catalinaHome, catalinaBaseDir);\n await deployWarFile(buildDir, catalinaBaseDir);\n await startTomcat(catalinaHome, catalinaBaseDir);\n\n const judgeResult = runJudgeScript(buildDir, options.problemDirectoryPath);\n printTestCaseResult({ testCaseId, ...judgeResult });\n } catch (error) {\n printTestCaseResult({\n testCaseId,\n decisionCode: DecisionCode.JUDGE_NOT_AVAILABLE,\n stderr: error instanceof Error ? error.message : String(error),\n });\n } finally {\n try {\n if (catalinaHome && catalinaBaseDir) {\n await ensureTomcatStopped(catalinaHome, catalinaBaseDir);\n }\n } catch {\n // 判定結果を優先し、後始末の失敗は握りつぶす。\n }\n await fs.promises.rm(runRootDir, { recursive: true, force: true });\n }\n}\n\nasync function prepareBuildDirectory(\n buildDir: string,\n submissionDir: string,\n options: TomcatJudgePresetOptions\n): Promise<void> {\n await fs.promises.mkdir(path.join(buildDir, 'src/main/java'), { recursive: true });\n await fs.promises.mkdir(path.join(buildDir, 'src/main/webapp/WEB-INF/jsp'), { recursive: true });\n await fs.promises.copyFile(path.join(options.problemDirectoryPath, 'pom.xml'), path.join(buildDir, 'pom.xml'));\n\n const submissionFiles = await listSubmissionFiles(submissionDir);\n for (const relativePath of submissionFiles) {\n const sourcePath = path.join(submissionDir, relativePath);\n const targetPath = await resolveTargetPath(buildDir, relativePath, sourcePath, options.jspDirectory);\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n await fs.promises.copyFile(sourcePath, targetPath);\n }\n}\n\nasync function resolveTargetPath(\n buildDir: string,\n relativePath: string,\n sourcePath: string,\n jspDirectory: string\n): Promise<string> {\n const normalizedRelativePath = relativePath.replaceAll('\\\\', '/');\n if (normalizedRelativePath.startsWith('src/main/')) {\n return path.join(buildDir, normalizedRelativePath);\n }\n if (normalizedRelativePath.startsWith('WEB-INF/') || normalizedRelativePath.startsWith('META-INF/')) {\n return path.join(buildDir, 'src/main/webapp', normalizedRelativePath);\n }\n\n const extension = path.extname(relativePath).toLowerCase();\n if (extension === '.java') {\n return path.join(buildDir, 'src/main/java', await resolveJavaRelativePath(sourcePath, relativePath));\n }\n if (extension === '.jsp') {\n return path.join(buildDir, 'src/main/webapp', jspDirectory, path.basename(relativePath));\n }\n\n return path.join(buildDir, 'src/main/webapp', normalizedRelativePath);\n}\n\nasync function resolveJavaRelativePath(sourcePath: string, fallbackRelativePath: string): Promise<string> {\n const sourceCode = await fs.promises.readFile(sourcePath, 'utf8');\n const packageMatch = /^\\s*package\\s+([a-zA-Z0-9_.]+)\\s*;/m.exec(sourceCode);\n if (!packageMatch?.[1]) {\n return fallbackRelativePath;\n }\n\n return path.join(packageMatch[1].replaceAll('.', '/'), path.basename(fallbackRelativePath));\n}\n\nasync function judgeByStaticAnalysis(\n submissionDir: string,\n forbiddenTexts: readonly string[]\n): Promise<Pick<JudgeResult, 'decisionCode' | 'feedbackMarkdown'> | undefined> {\n const forbiddenMatches: { path: string; pattern: string }[] = [];\n for (const relativePath of await listSubmissionFiles(submissionDir)) {\n if (!SOURCE_FILE_EXTENSIONS.has(path.extname(relativePath).toLowerCase())) {\n continue;\n }\n\n const sourceCode = await fs.promises.readFile(path.join(submissionDir, relativePath), 'utf8');\n for (const forbiddenText of forbiddenTexts) {\n if (sourceCode.includes(forbiddenText)) {\n forbiddenMatches.push({ path: relativePath, pattern: forbiddenText });\n }\n }\n }\n\n if (forbiddenMatches.length === 0) {\n return undefined;\n }\n\n return {\n decisionCode: DecisionCode.FORBIDDEN_PATTERNS_IN_CODE_ERROR,\n feedbackMarkdown:\n 'ソースコード中に禁止された文字列が含まれています。\\nソースコードを修正してから再度提出してください。\\n\\n| ファイル | 禁止パターン |\\n| -------- | ------------ |\\n' +\n forbiddenMatches.map((match) => `| \\`${match.path}\\` | \\`${match.pattern}\\` |`).join('\\n'),\n };\n}\n\nasync function listSubmissionFiles(rootDir: string): Promise<string[]> {\n const filePaths: string[] = [];\n await collectSubmissionFiles(rootDir, '', filePaths);\n return filePaths.toSorted();\n}\n\nasync function collectSubmissionFiles(rootDir: string, relativeDir: string, filePaths: string[]): Promise<void> {\n const currentDir = relativeDir ? path.join(rootDir, relativeDir) : rootDir;\n const entries = await fs.promises.readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const entryRelativePath = relativeDir ? path.join(relativeDir, entry.name) : entry.name;\n if (entry.isDirectory()) {\n await collectSubmissionFiles(rootDir, entryRelativePath, filePaths);\n continue;\n }\n if (entry.isFile()) {\n filePaths.push(entryRelativePath);\n }\n }\n}\n\nfunction buildWithMaven(buildDir: string): JudgeResult | undefined {\n const commandResult = runCommand(\n ['mvn', 'clean', 'package', '--quiet', '--batch-mode', '--offline'],\n buildDir,\n BUILD_TIMEOUT_SECONDS\n );\n if (commandResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n return {\n decisionCode: DecisionCode.BUILD_TIME_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n };\n }\n if (commandResult.status === 0) {\n return undefined;\n }\n\n return {\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: formatMavenBuildError(commandResult.stdout, commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n };\n}\n\nfunction formatMavenBuildError(stdout: string, stderr: string): string {\n return truncateOutput(\n `${stdout}\n${stderr}`.trim()\n );\n}\n\nasync function createCatalinaBaseDir(catalinaHome: string, runRootDir: string): Promise<string> {\n const catalinaBaseDir = path.join(runRootDir, 'catalina-base');\n await fs.promises.cp(path.join(catalinaHome, 'conf'), path.join(catalinaBaseDir, 'conf'), {\n recursive: true,\n dereference: true,\n });\n for (const directoryName of ['logs', 'temp', 'webapps', 'work']) {\n await fs.promises.mkdir(path.join(catalinaBaseDir, directoryName), { recursive: true });\n }\n\n const serverXmlPath = path.join(catalinaBaseDir, 'conf', 'server.xml');\n const serverXml = await fs.promises.readFile(serverXmlPath, 'utf8');\n await fs.promises.writeFile(serverXmlPath, serverXml.replaceAll('port=\"8080\"', 'port=\"59000\"'), 'utf8');\n return catalinaBaseDir;\n}\n\nasync function deployWarFile(buildDir: string, catalinaBaseDir: string): Promise<void> {\n const warFilePath = path.join(buildDir, 'target', `${APPLICATION_NAME}.war`);\n const webappsDir = path.join(catalinaBaseDir, 'webapps');\n const deployedDirectoryPath = path.join(webappsDir, APPLICATION_NAME);\n const deployedWarPath = path.join(webappsDir, `${APPLICATION_NAME}.war`);\n await fs.promises.mkdir(webappsDir, { recursive: true });\n await fs.promises.rm(deployedDirectoryPath, { recursive: true, force: true });\n await fs.promises.rm(deployedWarPath, { force: true });\n await fs.promises.copyFile(warFilePath, deployedWarPath);\n}\n\nasync function startTomcat(catalinaHome: string, catalinaBaseDir: string): Promise<void> {\n const startupScriptPath = path.join(catalinaHome, 'bin', 'startup.sh');\n const startupResult = runCommand([startupScriptPath], undefined, 10, {\n ...process.env,\n CATALINA_BASE: catalinaBaseDir,\n CATALINA_HOME: catalinaHome,\n });\n if (startupResult.status !== 0) {\n throw new Error(`Failed to start Tomcat: ${startupResult.stderr.trim() || startupResult.stdout.trim()}`);\n }\n\n const started = await waitForTomcatState(true, 10_000);\n if (!started) {\n throw new Error('Tomcat failed to start within 10 seconds');\n }\n}\n\nfunction runJudgeScript(buildDir: string, problemDirectoryPath: string): JudgeResult {\n const commandResult = runCommand(\n ['bun', 'run', './judge.ts', '--evaluate'],\n problemDirectoryPath,\n EVALUATE_TIMEOUT_SECONDS,\n {\n ...process.env,\n WORKING_DIRECTORY_PATH: buildDir,\n }\n );\n\n const outputFiles = readOutputFiles(path.join(buildDir, '__SCREENSHOTS.json'));\n if (commandResult.timeSeconds > EVALUATE_TIMEOUT_SECONDS) {\n return {\n decisionCode: DecisionCode.TIME_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n if (commandResult.stdout.length > MAX_OUTPUT_LENGTH || commandResult.stderr.length > MAX_OUTPUT_LENGTH) {\n return {\n decisionCode: DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n if (commandResult.status !== 0) {\n return {\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n\n return {\n decisionCode: DecisionCode.ACCEPTED,\n stderr: truncateOutput(commandResult.stderr) || undefined,\n stdout: truncateOutput(commandResult.stdout) || undefined,\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n}\n\nfunction runCommand(\n command: readonly [string, ...string[]],\n cwd: string | undefined,\n timeoutSeconds: number,\n env: NodeJS.ProcessEnv = process.env\n): CommandResult {\n const startAt = Date.now();\n const timeCommand = process.platform === 'darwin' ? 'gtime' : '/usr/bin/time';\n // Hosts provide GNU timeout on PATH; Homebrew coreutils also installs the unprefixed command.\n const timedResult = spawnSync('timeout', [timeoutSeconds.toFixed(3), timeCommand, '--format', '%e %M', ...command], {\n cwd,\n env,\n encoding: 'utf8',\n });\n const elapsedSeconds = (Date.now() - startAt) / 1000;\n const stderrWithError = [timedResult.stderr, timedResult.error?.message].filter(Boolean).join('\\n');\n const memoryMatch = /(?:^|\\n)(\\d+(?:\\.\\d+)?) (\\d+)\\s*$/u.exec(stderrWithError);\n const stderr = memoryMatch ? stderrWithError.slice(0, memoryMatch.index) : stderrWithError;\n const timeSeconds = Number(memoryMatch?.[1]) || elapsedSeconds;\n const memoryBytes = 1024 * Number(memoryMatch?.[2] ?? 0);\n\n return {\n status: timedResult.status === 124 ? 0 : (timedResult.status ?? undefined),\n stdout: timedResult.stdout,\n stderr,\n timeSeconds: timedResult.status === 124 ? timeoutSeconds + 0.001 : timeSeconds,\n memoryBytes,\n };\n}\n\nasync function ensureTomcatStopped(catalinaHome: string, catalinaBaseDir: string): Promise<void> {\n if (!(await isTomcatRunning())) {\n return;\n }\n\n runCommand([path.join(catalinaHome, 'bin', 'catalina.sh'), 'stop'], undefined, 10, {\n ...process.env,\n CATALINA_BASE: catalinaBaseDir,\n CATALINA_HOME: catalinaHome,\n });\n await waitForTomcatState(false, 10_000);\n}\n\nasync function waitForTomcatState(expectedRunning: boolean, timeoutMs: number): Promise<boolean> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < timeoutMs) {\n if ((await isTomcatRunning()) === expectedRunning) {\n return true;\n }\n await sleep(200);\n }\n return (await isTomcatRunning()) === expectedRunning;\n}\n\nasync function isTomcatRunning(): Promise<boolean> {\n return await new Promise<boolean>((resolve) => {\n const request = http.get(TOMCAT_BASE_URL, (response) => {\n response.resume();\n const status = response.statusCode ?? 0;\n resolve((status >= 200 && status < 300) || status === 404);\n });\n request.on('error', () => resolve(false));\n request.setTimeout(1000, () => request.destroy());\n });\n}\n\nfunction getCatalinaHome(): string {\n const catalinaHome = process.env.CATALINA_HOME;\n if (!catalinaHome) {\n throw new Error('CATALINA_HOME is not set');\n }\n\n validateCatalinaHome(catalinaHome);\n return path.resolve(catalinaHome);\n}\n\nfunction validateCatalinaHome(catalinaHome: string): void {\n if (\n !fs.existsSync(path.join(catalinaHome, 'bin', 'catalina.sh')) ||\n !fs.existsSync(path.join(catalinaHome, 'conf', 'server.xml'))\n ) {\n throw new Error('Invalid CATALINA_HOME path');\n }\n}\n\nfunction readOutputFiles(filePath: string): OutputFile[] | undefined {\n if (!fs.existsSync(filePath)) {\n return undefined;\n }\n\n // Malformed evaluator JSON remains a harness error (JUDGE_NOT_AVAILABLE), not missing screenshots.\n const parsed: unknown = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n const values = z.array(z.unknown()).safeParse(parsed);\n if (!values.success) return undefined;\n const outputFileSchema = z.object({\n path: z.string(),\n data: z.string(),\n encoding: z.literal('base64').optional(),\n });\n return values.data.flatMap((value) => {\n const result = outputFileSchema.safeParse(value);\n return result.success ? [result.data] : [];\n });\n}\n\nfunction truncateOutput(value: string): string {\n return value.slice(0, MAX_OUTPUT_LENGTH);\n}\n\nexport function buildTomcatUrl(urlPath: string): string {\n return `${TOMCAT_BASE_URL}/${APPLICATION_NAME}${urlPath.startsWith('/') ? urlPath : `/${urlPath}`}`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface TomcatJudgePresetOptions {
|
|
2
|
+
problemDirectoryPath: string;
|
|
3
|
+
jspDirectory: '' | 'WEB-INF/jsp';
|
|
4
|
+
forbiddenTexts?: readonly string[];
|
|
5
|
+
evaluate: () => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare function tomcatJudgePreset(options: TomcatJudgePresetOptions): Promise<void>;
|
|
8
|
+
export declare function buildTomcatUrl(urlPath: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{printTestCaseResult as e}from"../helpers/printTestCaseResult.js";import{parseArgs as t}from"../helpers/parseArgs.js";import{DecisionCode as n}from"../types/decisionCode.js";import r from"node:fs";import i from"node:path";import{z as a}from"zod";import{tmpdir as o}from"node:os";import{spawnSync as s}from"node:child_process";import c from"node:http";import{setTimeout as l}from"node:timers/promises";const u=`judge`,d=5e4,f=`http://localhost:59000`,p=new Set([`.java`,`.jsp`,`.html`,`.htm`,`.xml`,`.js`,`.css`]);async function m(a){if(process.argv.includes(`--evaluate`)){try{await a.evaluate()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exitCode=1}return}let{cwd:s}=t(process.argv);if(!s)throw Error(`cwd argument required`);let c=`test1`,l=await v(s,a.forbiddenTexts??[]);if(l){e({testCaseId:c,...l});return}let u=await r.promises.mkdtemp(i.join(o(),`tomcat_judge_`)),d=i.join(u,`build`),f,p;try{await r.promises.mkdir(d,{recursive:!0}),await h(d,s,a);let t=x(d);if(t){e({testCaseId:c,...t});return}p=j(),f=await C(p,u),await O(p,f),await w(d,f),await T(p,f);let n=E(d,a.problemDirectoryPath);e({testCaseId:c,...n})}catch(t){e({testCaseId:c,decisionCode:n.JUDGE_NOT_AVAILABLE,stderr:t instanceof Error?t.message:String(t)})}finally{try{p&&f&&await O(p,f)}catch{}await r.promises.rm(u,{recursive:!0,force:!0})}}async function h(e,t,n){await r.promises.mkdir(i.join(e,`src/main/java`),{recursive:!0}),await r.promises.mkdir(i.join(e,`src/main/webapp/WEB-INF/jsp`),{recursive:!0}),await r.promises.copyFile(i.join(n.problemDirectoryPath,`pom.xml`),i.join(e,`pom.xml`));let a=await y(t);for(let o of a){let a=i.join(t,o),s=await g(e,o,a,n.jspDirectory);await r.promises.mkdir(i.dirname(s),{recursive:!0}),await r.promises.copyFile(a,s)}}async function g(e,t,n,r){let a=t.replaceAll(`\\`,`/`);if(a.startsWith(`src/main/`))return i.join(e,a);if(a.startsWith(`WEB-INF/`)||a.startsWith(`META-INF/`))return i.join(e,`src/main/webapp`,a);let o=i.extname(t).toLowerCase();return o===`.java`?i.join(e,`src/main/java`,await _(n,t)):o===`.jsp`?i.join(e,`src/main/webapp`,r,i.basename(t)):i.join(e,`src/main/webapp`,a)}async function _(e,t){let n=await r.promises.readFile(e,`utf8`),a=/^\s*package\s+([a-zA-Z0-9_.]+)\s*;/m.exec(n);return a?.[1]?i.join(a[1].replaceAll(`.`,`/`),i.basename(t)):t}async function v(e,t){let a=[];for(let n of await y(e)){if(!p.has(i.extname(n).toLowerCase()))continue;let o=await r.promises.readFile(i.join(e,n),`utf8`);for(let e of t)o.includes(e)&&a.push({path:n,pattern:e})}if(a.length!==0)return{decisionCode:n.FORBIDDEN_PATTERNS_IN_CODE_ERROR,feedbackMarkdown:`ソースコード中に禁止された文字列が含まれています。
|
|
2
|
+
ソースコードを修正してから再度提出してください。
|
|
3
|
+
|
|
4
|
+
| ファイル | 禁止パターン |
|
|
5
|
+
| -------- | ------------ |
|
|
6
|
+
`+a.map(e=>`| \`${e.path}\` | \`${e.pattern}\` |`).join(`
|
|
7
|
+
`)}}async function y(e){let t=[];return await b(e,``,t),t.toSorted()}async function b(e,t,n){let a=t?i.join(e,t):e,o=await r.promises.readdir(a,{withFileTypes:!0});for(let r of o){let a=t?i.join(t,r.name):r.name;if(r.isDirectory()){await b(e,a,n);continue}r.isFile()&&n.push(a)}}function x(e){let t=D([`mvn`,`clean`,`package`,`--quiet`,`--batch-mode`,`--offline`],e,60);if(t.timeSeconds>60)return{decisionCode:n.BUILD_TIME_LIMIT_EXCEEDED,stderr:P(t.stderr),stdout:P(t.stdout),exitStatus:t.status,timeSeconds:t.timeSeconds,memoryBytes:t.memoryBytes};if(t.status!==0)return{decisionCode:n.BUILD_ERROR,stderr:S(t.stdout,t.stderr),stdout:P(t.stdout),exitStatus:t.status,timeSeconds:t.timeSeconds,memoryBytes:t.memoryBytes}}function S(e,t){return P(`${e}
|
|
8
|
+
${t}`.trim())}async function C(e,t){let n=i.join(t,`catalina-base`);await r.promises.cp(i.join(e,`conf`),i.join(n,`conf`),{recursive:!0,dereference:!0});for(let e of[`logs`,`temp`,`webapps`,`work`])await r.promises.mkdir(i.join(n,e),{recursive:!0});let a=i.join(n,`conf`,`server.xml`),o=await r.promises.readFile(a,`utf8`);return await r.promises.writeFile(a,o.replaceAll(`port="8080"`,`port="59000"`),`utf8`),n}async function w(e,t){let n=i.join(e,`target`,`${u}.war`),a=i.join(t,`webapps`),o=i.join(a,u),s=i.join(a,`${u}.war`);await r.promises.mkdir(a,{recursive:!0}),await r.promises.rm(o,{recursive:!0,force:!0}),await r.promises.rm(s,{force:!0}),await r.promises.copyFile(n,s)}async function T(e,t){let n=D([i.join(e,`bin`,`startup.sh`)],void 0,10,{...process.env,CATALINA_BASE:t,CATALINA_HOME:e});if(n.status!==0)throw Error(`Failed to start Tomcat: ${n.stderr.trim()||n.stdout.trim()}`);if(!await k(!0,1e4))throw Error(`Tomcat failed to start within 10 seconds`)}function E(e,t){let r=D([`bun`,`run`,`./judge.ts`,`--evaluate`],t,30,{...process.env,WORKING_DIRECTORY_PATH:e}),a=N(i.join(e,`__SCREENSHOTS.json`));return r.timeSeconds>30?{decisionCode:n.TIME_LIMIT_EXCEEDED,stderr:P(r.stderr),stdout:P(r.stdout),exitStatus:r.status,timeSeconds:r.timeSeconds,memoryBytes:r.memoryBytes,outputFiles:a}:r.stdout.length>d||r.stderr.length>d?{decisionCode:n.OUTPUT_SIZE_LIMIT_EXCEEDED,stderr:P(r.stderr),stdout:P(r.stdout),exitStatus:r.status,timeSeconds:r.timeSeconds,memoryBytes:r.memoryBytes,outputFiles:a}:r.status===0?{decisionCode:n.ACCEPTED,stderr:P(r.stderr)||void 0,stdout:P(r.stdout)||void 0,exitStatus:r.status,timeSeconds:r.timeSeconds,memoryBytes:r.memoryBytes,outputFiles:a}:{decisionCode:n.WRONG_ANSWER,stderr:P(r.stderr),stdout:P(r.stdout),exitStatus:r.status,timeSeconds:r.timeSeconds,memoryBytes:r.memoryBytes,outputFiles:a}}function D(e,t,n,r=process.env){let i=Date.now(),a=process.platform===`darwin`?`gtime`:`/usr/bin/time`,o=s(`timeout`,[n.toFixed(3),a,`--format`,`%e %M`,...e],{cwd:t,env:r,encoding:`utf8`}),c=(Date.now()-i)/1e3,l=[o.stderr,o.error?.message].filter(Boolean).join(`
|
|
9
|
+
`),u=/(?:^|\n)(\d+(?:\.\d+)?) (\d+)\s*$/u.exec(l),d=u?l.slice(0,u.index):l,f=Number(u?.[1])||c,p=1024*Number(u?.[2]??0);return{status:o.status===124?0:o.status??void 0,stdout:o.stdout,stderr:d,timeSeconds:o.status===124?n+.001:f,memoryBytes:p}}async function O(e,t){await A()&&(D([i.join(e,`bin`,`catalina.sh`),`stop`],void 0,10,{...process.env,CATALINA_BASE:t,CATALINA_HOME:e}),await k(!1,1e4))}async function k(e,t){let n=Date.now();for(;Date.now()-n<t;){if(await A()===e)return!0;await l(200)}return await A()===e}async function A(){return await new Promise(e=>{let t=c.get(f,t=>{t.resume();let n=t.statusCode??0;e(n>=200&&n<300||n===404)});t.on(`error`,()=>e(!1)),t.setTimeout(1e3,()=>t.destroy())})}function j(){let e=process.env.CATALINA_HOME;if(!e)throw Error(`CATALINA_HOME is not set`);return M(e),i.resolve(e)}function M(e){if(!r.existsSync(i.join(e,`bin`,`catalina.sh`))||!r.existsSync(i.join(e,`conf`,`server.xml`)))throw Error(`Invalid CATALINA_HOME path`)}function N(e){if(!r.existsSync(e))return;let t=JSON.parse(r.readFileSync(e,`utf8`)),n=a.array(a.unknown()).safeParse(t);if(!n.success)return;let i=a.object({path:a.string(),data:a.string(),encoding:a.literal(`base64`).optional()});return n.data.flatMap(e=>{let t=i.safeParse(e);return t.success?[t.data]:[]})}function P(e){return e.slice(0,d)}function F(e){return`${f}/${u}${e.startsWith(`/`)?e:`/${e}`}`}export{F as buildTomcatUrl,m as tomcatJudgePreset};
|
|
10
|
+
//# sourceMappingURL=tomcat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tomcat.js","names":["sleep"],"sources":["../../src/presets/tomcat.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport http from 'node:http';\nimport { tmpdir } from 'node:os';\nimport path from 'node:path';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { DecisionCode, parseArgs, printTestCaseResult, type TestCaseResult } from '../index.js';\nimport { z } from 'zod';\n\nexport interface TomcatJudgePresetOptions {\n problemDirectoryPath: string;\n jspDirectory: '' | 'WEB-INF/jsp';\n forbiddenTexts?: readonly string[];\n evaluate: () => Promise<void>;\n}\n\ntype JudgeResult = Omit<TestCaseResult, 'testCaseId'>;\ntype OutputFile = NonNullable<TestCaseResult['outputFiles']>[number];\ninterface CommandResult {\n status: number | undefined;\n stdout: string;\n stderr: string;\n timeSeconds: number;\n memoryBytes: number;\n}\nconst APPLICATION_NAME = 'judge';\nconst BUILD_TIMEOUT_SECONDS = 60;\nconst EVALUATE_TIMEOUT_SECONDS = 30;\nconst MAX_OUTPUT_LENGTH = 50_000;\nconst TOMCAT_BASE_URL = 'http://localhost:59000';\nconst SOURCE_FILE_EXTENSIONS = new Set(['.java', '.jsp', '.html', '.htm', '.xml', '.js', '.css']);\n\nexport async function tomcatJudgePreset(options: TomcatJudgePresetOptions): Promise<void> {\n if (process.argv.includes('--evaluate')) {\n try {\n await options.evaluate();\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n return;\n }\n\n const { cwd: submissionDir } = parseArgs(process.argv);\n if (!submissionDir) throw new Error('cwd argument required');\n const testCaseId = 'test1';\n const staticAnalysisResult = await judgeByStaticAnalysis(submissionDir, options.forbiddenTexts ?? []);\n if (staticAnalysisResult) {\n printTestCaseResult({ testCaseId, ...staticAnalysisResult });\n return;\n }\n\n const runRootDir = await fs.promises.mkdtemp(path.join(tmpdir(), 'tomcat_judge_'));\n const buildDir = path.join(runRootDir, 'build');\n let catalinaBaseDir: string | undefined;\n let catalinaHome: string | undefined;\n\n try {\n await fs.promises.mkdir(buildDir, { recursive: true });\n await prepareBuildDirectory(buildDir, submissionDir, options);\n\n const buildResult = buildWithMaven(buildDir);\n if (buildResult) {\n printTestCaseResult({ testCaseId, ...buildResult });\n return;\n }\n\n catalinaHome = getCatalinaHome();\n catalinaBaseDir = await createCatalinaBaseDir(catalinaHome, runRootDir);\n await ensureTomcatStopped(catalinaHome, catalinaBaseDir);\n await deployWarFile(buildDir, catalinaBaseDir);\n await startTomcat(catalinaHome, catalinaBaseDir);\n\n const judgeResult = runJudgeScript(buildDir, options.problemDirectoryPath);\n printTestCaseResult({ testCaseId, ...judgeResult });\n } catch (error) {\n printTestCaseResult({\n testCaseId,\n decisionCode: DecisionCode.JUDGE_NOT_AVAILABLE,\n stderr: error instanceof Error ? error.message : String(error),\n });\n } finally {\n try {\n if (catalinaHome && catalinaBaseDir) {\n await ensureTomcatStopped(catalinaHome, catalinaBaseDir);\n }\n } catch {\n // 判定結果を優先し、後始末の失敗は握りつぶす。\n }\n await fs.promises.rm(runRootDir, { recursive: true, force: true });\n }\n}\n\nasync function prepareBuildDirectory(\n buildDir: string,\n submissionDir: string,\n options: TomcatJudgePresetOptions\n): Promise<void> {\n await fs.promises.mkdir(path.join(buildDir, 'src/main/java'), { recursive: true });\n await fs.promises.mkdir(path.join(buildDir, 'src/main/webapp/WEB-INF/jsp'), { recursive: true });\n await fs.promises.copyFile(path.join(options.problemDirectoryPath, 'pom.xml'), path.join(buildDir, 'pom.xml'));\n\n const submissionFiles = await listSubmissionFiles(submissionDir);\n for (const relativePath of submissionFiles) {\n const sourcePath = path.join(submissionDir, relativePath);\n const targetPath = await resolveTargetPath(buildDir, relativePath, sourcePath, options.jspDirectory);\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n await fs.promises.copyFile(sourcePath, targetPath);\n }\n}\n\nasync function resolveTargetPath(\n buildDir: string,\n relativePath: string,\n sourcePath: string,\n jspDirectory: string\n): Promise<string> {\n const normalizedRelativePath = relativePath.replaceAll('\\\\', '/');\n if (normalizedRelativePath.startsWith('src/main/')) {\n return path.join(buildDir, normalizedRelativePath);\n }\n if (normalizedRelativePath.startsWith('WEB-INF/') || normalizedRelativePath.startsWith('META-INF/')) {\n return path.join(buildDir, 'src/main/webapp', normalizedRelativePath);\n }\n\n const extension = path.extname(relativePath).toLowerCase();\n if (extension === '.java') {\n return path.join(buildDir, 'src/main/java', await resolveJavaRelativePath(sourcePath, relativePath));\n }\n if (extension === '.jsp') {\n return path.join(buildDir, 'src/main/webapp', jspDirectory, path.basename(relativePath));\n }\n\n return path.join(buildDir, 'src/main/webapp', normalizedRelativePath);\n}\n\nasync function resolveJavaRelativePath(sourcePath: string, fallbackRelativePath: string): Promise<string> {\n const sourceCode = await fs.promises.readFile(sourcePath, 'utf8');\n const packageMatch = /^\\s*package\\s+([a-zA-Z0-9_.]+)\\s*;/m.exec(sourceCode);\n if (!packageMatch?.[1]) {\n return fallbackRelativePath;\n }\n\n return path.join(packageMatch[1].replaceAll('.', '/'), path.basename(fallbackRelativePath));\n}\n\nasync function judgeByStaticAnalysis(\n submissionDir: string,\n forbiddenTexts: readonly string[]\n): Promise<Pick<JudgeResult, 'decisionCode' | 'feedbackMarkdown'> | undefined> {\n const forbiddenMatches: { path: string; pattern: string }[] = [];\n for (const relativePath of await listSubmissionFiles(submissionDir)) {\n if (!SOURCE_FILE_EXTENSIONS.has(path.extname(relativePath).toLowerCase())) {\n continue;\n }\n\n const sourceCode = await fs.promises.readFile(path.join(submissionDir, relativePath), 'utf8');\n for (const forbiddenText of forbiddenTexts) {\n if (sourceCode.includes(forbiddenText)) {\n forbiddenMatches.push({ path: relativePath, pattern: forbiddenText });\n }\n }\n }\n\n if (forbiddenMatches.length === 0) {\n return undefined;\n }\n\n return {\n decisionCode: DecisionCode.FORBIDDEN_PATTERNS_IN_CODE_ERROR,\n feedbackMarkdown:\n 'ソースコード中に禁止された文字列が含まれています。\\nソースコードを修正してから再度提出してください。\\n\\n| ファイル | 禁止パターン |\\n| -------- | ------------ |\\n' +\n forbiddenMatches.map((match) => `| \\`${match.path}\\` | \\`${match.pattern}\\` |`).join('\\n'),\n };\n}\n\nasync function listSubmissionFiles(rootDir: string): Promise<string[]> {\n const filePaths: string[] = [];\n await collectSubmissionFiles(rootDir, '', filePaths);\n return filePaths.toSorted();\n}\n\nasync function collectSubmissionFiles(rootDir: string, relativeDir: string, filePaths: string[]): Promise<void> {\n const currentDir = relativeDir ? path.join(rootDir, relativeDir) : rootDir;\n const entries = await fs.promises.readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const entryRelativePath = relativeDir ? path.join(relativeDir, entry.name) : entry.name;\n if (entry.isDirectory()) {\n await collectSubmissionFiles(rootDir, entryRelativePath, filePaths);\n continue;\n }\n if (entry.isFile()) {\n filePaths.push(entryRelativePath);\n }\n }\n}\n\nfunction buildWithMaven(buildDir: string): JudgeResult | undefined {\n const commandResult = runCommand(\n ['mvn', 'clean', 'package', '--quiet', '--batch-mode', '--offline'],\n buildDir,\n BUILD_TIMEOUT_SECONDS\n );\n if (commandResult.timeSeconds > BUILD_TIMEOUT_SECONDS) {\n return {\n decisionCode: DecisionCode.BUILD_TIME_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n };\n }\n if (commandResult.status === 0) {\n return undefined;\n }\n\n return {\n decisionCode: DecisionCode.BUILD_ERROR,\n stderr: formatMavenBuildError(commandResult.stdout, commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n };\n}\n\nfunction formatMavenBuildError(stdout: string, stderr: string): string {\n return truncateOutput(\n `${stdout}\n${stderr}`.trim()\n );\n}\n\nasync function createCatalinaBaseDir(catalinaHome: string, runRootDir: string): Promise<string> {\n const catalinaBaseDir = path.join(runRootDir, 'catalina-base');\n await fs.promises.cp(path.join(catalinaHome, 'conf'), path.join(catalinaBaseDir, 'conf'), {\n recursive: true,\n dereference: true,\n });\n for (const directoryName of ['logs', 'temp', 'webapps', 'work']) {\n await fs.promises.mkdir(path.join(catalinaBaseDir, directoryName), { recursive: true });\n }\n\n const serverXmlPath = path.join(catalinaBaseDir, 'conf', 'server.xml');\n const serverXml = await fs.promises.readFile(serverXmlPath, 'utf8');\n await fs.promises.writeFile(serverXmlPath, serverXml.replaceAll('port=\"8080\"', 'port=\"59000\"'), 'utf8');\n return catalinaBaseDir;\n}\n\nasync function deployWarFile(buildDir: string, catalinaBaseDir: string): Promise<void> {\n const warFilePath = path.join(buildDir, 'target', `${APPLICATION_NAME}.war`);\n const webappsDir = path.join(catalinaBaseDir, 'webapps');\n const deployedDirectoryPath = path.join(webappsDir, APPLICATION_NAME);\n const deployedWarPath = path.join(webappsDir, `${APPLICATION_NAME}.war`);\n await fs.promises.mkdir(webappsDir, { recursive: true });\n await fs.promises.rm(deployedDirectoryPath, { recursive: true, force: true });\n await fs.promises.rm(deployedWarPath, { force: true });\n await fs.promises.copyFile(warFilePath, deployedWarPath);\n}\n\nasync function startTomcat(catalinaHome: string, catalinaBaseDir: string): Promise<void> {\n const startupScriptPath = path.join(catalinaHome, 'bin', 'startup.sh');\n const startupResult = runCommand([startupScriptPath], undefined, 10, {\n ...process.env,\n CATALINA_BASE: catalinaBaseDir,\n CATALINA_HOME: catalinaHome,\n });\n if (startupResult.status !== 0) {\n throw new Error(`Failed to start Tomcat: ${startupResult.stderr.trim() || startupResult.stdout.trim()}`);\n }\n\n const started = await waitForTomcatState(true, 10_000);\n if (!started) {\n throw new Error('Tomcat failed to start within 10 seconds');\n }\n}\n\nfunction runJudgeScript(buildDir: string, problemDirectoryPath: string): JudgeResult {\n const commandResult = runCommand(\n ['bun', 'run', './judge.ts', '--evaluate'],\n problemDirectoryPath,\n EVALUATE_TIMEOUT_SECONDS,\n {\n ...process.env,\n WORKING_DIRECTORY_PATH: buildDir,\n }\n );\n\n const outputFiles = readOutputFiles(path.join(buildDir, '__SCREENSHOTS.json'));\n if (commandResult.timeSeconds > EVALUATE_TIMEOUT_SECONDS) {\n return {\n decisionCode: DecisionCode.TIME_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n if (commandResult.stdout.length > MAX_OUTPUT_LENGTH || commandResult.stderr.length > MAX_OUTPUT_LENGTH) {\n return {\n decisionCode: DecisionCode.OUTPUT_SIZE_LIMIT_EXCEEDED,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n if (commandResult.status !== 0) {\n return {\n decisionCode: DecisionCode.WRONG_ANSWER,\n stderr: truncateOutput(commandResult.stderr),\n stdout: truncateOutput(commandResult.stdout),\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n }\n\n return {\n decisionCode: DecisionCode.ACCEPTED,\n stderr: truncateOutput(commandResult.stderr) || undefined,\n stdout: truncateOutput(commandResult.stdout) || undefined,\n exitStatus: commandResult.status,\n timeSeconds: commandResult.timeSeconds,\n memoryBytes: commandResult.memoryBytes,\n outputFiles,\n };\n}\n\nfunction runCommand(\n command: readonly [string, ...string[]],\n cwd: string | undefined,\n timeoutSeconds: number,\n env: NodeJS.ProcessEnv = process.env\n): CommandResult {\n const startAt = Date.now();\n const timeCommand = process.platform === 'darwin' ? 'gtime' : '/usr/bin/time';\n // Hosts provide GNU timeout on PATH; Homebrew coreutils also installs the unprefixed command.\n const timedResult = spawnSync('timeout', [timeoutSeconds.toFixed(3), timeCommand, '--format', '%e %M', ...command], {\n cwd,\n env,\n encoding: 'utf8',\n });\n const elapsedSeconds = (Date.now() - startAt) / 1000;\n const stderrWithError = [timedResult.stderr, timedResult.error?.message].filter(Boolean).join('\\n');\n const memoryMatch = /(?:^|\\n)(\\d+(?:\\.\\d+)?) (\\d+)\\s*$/u.exec(stderrWithError);\n const stderr = memoryMatch ? stderrWithError.slice(0, memoryMatch.index) : stderrWithError;\n const timeSeconds = Number(memoryMatch?.[1]) || elapsedSeconds;\n const memoryBytes = 1024 * Number(memoryMatch?.[2] ?? 0);\n\n return {\n status: timedResult.status === 124 ? 0 : (timedResult.status ?? undefined),\n stdout: timedResult.stdout,\n stderr,\n timeSeconds: timedResult.status === 124 ? timeoutSeconds + 0.001 : timeSeconds,\n memoryBytes,\n };\n}\n\nasync function ensureTomcatStopped(catalinaHome: string, catalinaBaseDir: string): Promise<void> {\n if (!(await isTomcatRunning())) {\n return;\n }\n\n runCommand([path.join(catalinaHome, 'bin', 'catalina.sh'), 'stop'], undefined, 10, {\n ...process.env,\n CATALINA_BASE: catalinaBaseDir,\n CATALINA_HOME: catalinaHome,\n });\n await waitForTomcatState(false, 10_000);\n}\n\nasync function waitForTomcatState(expectedRunning: boolean, timeoutMs: number): Promise<boolean> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < timeoutMs) {\n if ((await isTomcatRunning()) === expectedRunning) {\n return true;\n }\n await sleep(200);\n }\n return (await isTomcatRunning()) === expectedRunning;\n}\n\nasync function isTomcatRunning(): Promise<boolean> {\n return await new Promise<boolean>((resolve) => {\n const request = http.get(TOMCAT_BASE_URL, (response) => {\n response.resume();\n const status = response.statusCode ?? 0;\n resolve((status >= 200 && status < 300) || status === 404);\n });\n request.on('error', () => resolve(false));\n request.setTimeout(1000, () => request.destroy());\n });\n}\n\nfunction getCatalinaHome(): string {\n const catalinaHome = process.env.CATALINA_HOME;\n if (!catalinaHome) {\n throw new Error('CATALINA_HOME is not set');\n }\n\n validateCatalinaHome(catalinaHome);\n return path.resolve(catalinaHome);\n}\n\nfunction validateCatalinaHome(catalinaHome: string): void {\n if (\n !fs.existsSync(path.join(catalinaHome, 'bin', 'catalina.sh')) ||\n !fs.existsSync(path.join(catalinaHome, 'conf', 'server.xml'))\n ) {\n throw new Error('Invalid CATALINA_HOME path');\n }\n}\n\nfunction readOutputFiles(filePath: string): OutputFile[] | undefined {\n if (!fs.existsSync(filePath)) {\n return undefined;\n }\n\n // Malformed evaluator JSON remains a harness error (JUDGE_NOT_AVAILABLE), not missing screenshots.\n const parsed: unknown = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n const values = z.array(z.unknown()).safeParse(parsed);\n if (!values.success) return undefined;\n const outputFileSchema = z.object({\n path: z.string(),\n data: z.string(),\n encoding: z.literal('base64').optional(),\n });\n return values.data.flatMap((value) => {\n const result = outputFileSchema.safeParse(value);\n return result.success ? [result.data] : [];\n });\n}\n\nfunction truncateOutput(value: string): string {\n return value.slice(0, MAX_OUTPUT_LENGTH);\n}\n\nexport function buildTomcatUrl(urlPath: string): string {\n return `${TOMCAT_BASE_URL}/${APPLICATION_NAME}${urlPath.startsWith('/') ? urlPath : `/${urlPath}`}`;\n}\n"],"mappings":"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"}
|