@doccident/doccident 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +315 -123
- package/bin/cmd.js +25 -24
- package/dist/doctest.js +89 -102
- package/dist/languages/c.js +58 -0
- package/dist/languages/cobol.js +50 -0
- package/dist/languages/fortran.js +56 -0
- package/dist/languages/go.js +45 -0
- package/dist/languages/interface.js +2 -0
- package/dist/languages/javascript.js +24 -0
- package/dist/languages/python.js +31 -0
- package/dist/languages/rust.js +56 -0
- package/dist/languages/shell.js +37 -0
- package/dist/parse-code-snippets-from-markdown.js +53 -30
- package/dist/reporter.js +78 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +6 -0
- package/package.json +12 -18
package/dist/doctest.js
CHANGED
|
@@ -1,57 +1,64 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
3
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.printResults = void 0;
|
|
4
7
|
exports.runTests = runTests;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
|
+
const parse_code_snippets_from_markdown_1 = __importDefault(require("./parse-code-snippets-from-markdown"));
|
|
12
|
+
const reporter_1 = require("./reporter");
|
|
13
|
+
Object.defineProperty(exports, "printResults", { enumerable: true, get: function () { return reporter_1.printResults; } });
|
|
14
|
+
const python_1 = require("./languages/python");
|
|
15
|
+
const shell_1 = require("./languages/shell");
|
|
16
|
+
const go_1 = require("./languages/go");
|
|
17
|
+
const rust_1 = require("./languages/rust");
|
|
18
|
+
const fortran_1 = require("./languages/fortran");
|
|
19
|
+
const cobol_1 = require("./languages/cobol");
|
|
20
|
+
const c_1 = require("./languages/c");
|
|
21
|
+
const javascript_1 = require("./languages/javascript");
|
|
15
22
|
function runTests(files, config) {
|
|
16
|
-
|
|
23
|
+
const results = files
|
|
17
24
|
.map(read)
|
|
18
25
|
.map(parse_code_snippets_from_markdown_1.default)
|
|
19
26
|
.map(testFile(config));
|
|
20
|
-
return flatten(results);
|
|
27
|
+
return (0, utils_1.flatten)(results);
|
|
21
28
|
}
|
|
22
29
|
function read(fileName) {
|
|
23
|
-
return { contents: (0, fs_1.readFileSync)(fileName, "utf8"), fileName
|
|
30
|
+
return { contents: (0, fs_1.readFileSync)(fileName, "utf8"), fileName };
|
|
24
31
|
}
|
|
25
32
|
function makeTestSandbox(config) {
|
|
26
33
|
function sandboxRequire(moduleName) {
|
|
27
|
-
for (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
for (const regexRequire in config.regexRequire) {
|
|
35
|
+
const regex = new RegExp(regexRequire);
|
|
36
|
+
const match = regex.exec(moduleName);
|
|
37
|
+
const handler = config.regexRequire[regexRequire];
|
|
31
38
|
if (match) {
|
|
32
|
-
return handler
|
|
39
|
+
return handler(...match);
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
|
-
if (config.require[moduleName] === undefined) {
|
|
42
|
+
if (config.require === undefined || config.require[moduleName] === undefined) {
|
|
36
43
|
throw moduleNotFoundError(moduleName);
|
|
37
44
|
}
|
|
38
45
|
return config.require[moduleName];
|
|
39
46
|
}
|
|
40
|
-
|
|
41
|
-
log:
|
|
47
|
+
const sandboxConsole = {
|
|
48
|
+
log: () => null,
|
|
42
49
|
};
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
const sandboxGlobals = { require: sandboxRequire, console: config.testOutput ? console : sandboxConsole };
|
|
51
|
+
const sandbox = Object.assign({}, sandboxGlobals, config.globals);
|
|
45
52
|
return sandbox;
|
|
46
53
|
}
|
|
47
54
|
function testFile(config) {
|
|
48
55
|
return function testFileWithConfig(args) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const codeSnippets = args.codeSnippets;
|
|
57
|
+
const fileName = args.fileName;
|
|
58
|
+
const shareCodeInFile = args.shareCodeInFile;
|
|
59
|
+
let results;
|
|
53
60
|
if (shareCodeInFile) {
|
|
54
|
-
|
|
61
|
+
const sandbox = makeTestSandbox(config);
|
|
55
62
|
results = codeSnippets.map(test(config, fileName, sandbox));
|
|
56
63
|
}
|
|
57
64
|
else {
|
|
@@ -60,99 +67,79 @@ function testFile(config) {
|
|
|
60
67
|
return results;
|
|
61
68
|
};
|
|
62
69
|
}
|
|
63
|
-
function test(config,
|
|
64
|
-
return
|
|
70
|
+
function test(config, _filename, sandbox) {
|
|
71
|
+
return (codeSnippet) => {
|
|
65
72
|
if (codeSnippet.skip) {
|
|
66
|
-
return { status: "skip", codeSnippet
|
|
73
|
+
return { status: "skip", codeSnippet, stack: "" };
|
|
67
74
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
let success = false;
|
|
76
|
+
let stack = "";
|
|
77
|
+
let code = codeSnippet.code;
|
|
71
78
|
if (config.transformCode) {
|
|
72
79
|
try {
|
|
73
80
|
code = config.transformCode(code);
|
|
74
81
|
}
|
|
75
82
|
catch (e) {
|
|
76
|
-
return { status: "fail", codeSnippet
|
|
83
|
+
return { status: "fail", codeSnippet, stack: "Encountered an error while transforming snippet: \n" + e.stack };
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
|
-
|
|
86
|
+
let perSnippetSandbox;
|
|
87
|
+
let activeSandbox;
|
|
88
|
+
let isSharedSandbox = false;
|
|
80
89
|
if (sandbox === undefined) {
|
|
81
90
|
perSnippetSandbox = makeTestSandbox(config);
|
|
91
|
+
activeSandbox = perSnippetSandbox;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
activeSandbox = sandbox;
|
|
95
|
+
isSharedSandbox = true;
|
|
82
96
|
}
|
|
83
97
|
if (config.beforeEach) {
|
|
84
98
|
config.beforeEach();
|
|
85
99
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
let result;
|
|
101
|
+
if (codeSnippet.language === 'python') {
|
|
102
|
+
result = (0, python_1.pythonHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
103
|
+
}
|
|
104
|
+
else if (['bash', 'sh', 'zsh'].includes(codeSnippet.language || '')) {
|
|
105
|
+
result = (0, shell_1.shellHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
106
|
+
}
|
|
107
|
+
else if (codeSnippet.language === 'go') {
|
|
108
|
+
result = (0, go_1.goHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
95
109
|
}
|
|
96
|
-
|
|
97
|
-
|
|
110
|
+
else if (codeSnippet.language === 'rust') {
|
|
111
|
+
result = (0, rust_1.rustHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
112
|
+
}
|
|
113
|
+
else if (codeSnippet.language === 'fortran') {
|
|
114
|
+
result = (0, fortran_1.fortranHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
115
|
+
}
|
|
116
|
+
else if (codeSnippet.language === 'cobol') {
|
|
117
|
+
result = (0, cobol_1.cobolHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
118
|
+
}
|
|
119
|
+
else if (codeSnippet.language === 'c') {
|
|
120
|
+
result = (0, c_1.cHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
result = (0, javascript_1.javascriptHandler)(code, codeSnippet, config, activeSandbox, isSharedSandbox);
|
|
98
124
|
}
|
|
99
|
-
|
|
125
|
+
success = result.success;
|
|
126
|
+
stack = result.stack;
|
|
127
|
+
const status = success ? "pass" : "fail";
|
|
100
128
|
process.stdout.write(success ? chalk_1.default.green(".") : chalk_1.default.red("x"));
|
|
101
|
-
return { status
|
|
129
|
+
return { status, codeSnippet, stack };
|
|
102
130
|
};
|
|
103
131
|
}
|
|
104
|
-
function printResults(results) {
|
|
105
|
-
results.filter(function (result) { return result.status === "fail"; }).forEach(printFailure);
|
|
106
|
-
var passingCount = results.filter(function (result) { return result.status === "pass"; })
|
|
107
|
-
.length;
|
|
108
|
-
var failingCount = results.filter(function (result) { return result.status === "fail"; })
|
|
109
|
-
.length;
|
|
110
|
-
var skippingCount = results.filter(function (result) { return result.status === "skip"; })
|
|
111
|
-
.length;
|
|
112
|
-
function successfulRun() {
|
|
113
|
-
return failingCount === 0;
|
|
114
|
-
}
|
|
115
|
-
console.log(chalk_1.default.green("Passed: " + passingCount));
|
|
116
|
-
if (skippingCount > 0) {
|
|
117
|
-
console.log(chalk_1.default.yellow("Skipped: " + skippingCount));
|
|
118
|
-
}
|
|
119
|
-
if (successfulRun()) {
|
|
120
|
-
console.log(chalk_1.default.green("\nSuccess!"));
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
console.log(chalk_1.default.red("Failed: " + failingCount));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function printFailure(result) {
|
|
127
|
-
console.log(chalk_1.default.red("Failed - ".concat(markDownErrorLocation(result))));
|
|
128
|
-
var stackDetails = relevantStackDetails(result.stack);
|
|
129
|
-
console.log(stackDetails);
|
|
130
|
-
var variableNotDefined = stackDetails.match(/(\w+) is not defined/);
|
|
131
|
-
if (variableNotDefined) {
|
|
132
|
-
var variableName = variableNotDefined[1];
|
|
133
|
-
console.log("You can declare ".concat(chalk_1.default.blue(variableName), " in the ").concat(chalk_1.default.blue("globals"), " section in ").concat(chalk_1.default.grey(".doccident-setup.js")));
|
|
134
|
-
console.log("\nFor example:\n".concat(chalk_1.default.grey("// .doccident-setup.js"), "\nmodule.exports = {\n globals: {\n ").concat(chalk_1.default.blue(variableName), ": ...\n }\n}\n "));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function relevantStackDetails(stack) {
|
|
138
|
-
var match = stack.match(/([\w\W]*?)at eval/) ||
|
|
139
|
-
// eslint-disable-next-line no-useless-escape
|
|
140
|
-
stack.match(/([\w\W]*)at [\w*\/]*?doctest.js/);
|
|
141
|
-
if (match !== null) {
|
|
142
|
-
return match[1];
|
|
143
|
-
}
|
|
144
|
-
return stack;
|
|
145
|
-
}
|
|
146
132
|
function moduleNotFoundError(moduleName) {
|
|
147
|
-
return new Error(
|
|
133
|
+
return new Error(`
|
|
134
|
+
Attempted to require '${chalk_1.default.blue(moduleName)}' but was not found in config.
|
|
135
|
+
You need to include it in the require section of your ${chalk_1.default.grey(".doccident-setup.js")} file.
|
|
136
|
+
|
|
137
|
+
For example:
|
|
138
|
+
${chalk_1.default.grey("// .doccident-setup.js")}
|
|
139
|
+
module.exports = {
|
|
140
|
+
require: {
|
|
141
|
+
${chalk_1.default.blue(`'${moduleName}': require('${moduleName}')`)}
|
|
142
|
+
}
|
|
148
143
|
}
|
|
149
|
-
|
|
150
|
-
var match = result.stack.match(/eval.*<.*>:(\d+):(\d+)/);
|
|
151
|
-
if (match) {
|
|
152
|
-
var mdLineNumber = parseInt(match[1], 10);
|
|
153
|
-
var columnNumber = parseInt(match[2], 10);
|
|
154
|
-
var lineNumber = result.codeSnippet.lineNumber + mdLineNumber;
|
|
155
|
-
return "".concat(result.codeSnippet.fileName, ":").concat(lineNumber, ":").concat(columnNumber);
|
|
156
|
-
}
|
|
157
|
-
return "".concat(result.codeSnippet.fileName, ":").concat(result.codeSnippet.lineNumber);
|
|
144
|
+
`);
|
|
158
145
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const cHandler = (code, _snippet, _config, _sandbox, _isSharedSandbox) => {
|
|
9
|
+
let success = false;
|
|
10
|
+
let stack = "";
|
|
11
|
+
// C execution logic
|
|
12
|
+
// Auto-wrap in main function if not present
|
|
13
|
+
let cCode = code;
|
|
14
|
+
if (!cCode.includes('main(')) {
|
|
15
|
+
cCode = `#include <stdio.h>
|
|
16
|
+
int main() {
|
|
17
|
+
${cCode}
|
|
18
|
+
return 0;
|
|
19
|
+
}`;
|
|
20
|
+
}
|
|
21
|
+
const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
22
|
+
const tempSourceFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_c_${uniqueId}.c`);
|
|
23
|
+
const tempExeFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_c_${uniqueId}`);
|
|
24
|
+
try {
|
|
25
|
+
(0, fs_1.writeFileSync)(tempSourceFile, cCode);
|
|
26
|
+
// Compile with gcc
|
|
27
|
+
const compileResult = (0, child_process_1.spawnSync)('gcc', [tempSourceFile, '-o', tempExeFile], { encoding: 'utf-8' });
|
|
28
|
+
if (compileResult.status !== 0) {
|
|
29
|
+
stack = compileResult.stderr || "C compilation failed";
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Run
|
|
33
|
+
const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8' });
|
|
34
|
+
if (runResult.status === 0) {
|
|
35
|
+
success = true;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
stack = runResult.stderr || "C execution failed with non-zero exit code";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
stack = e.message || "Failed to execute gcc or run binary";
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
try {
|
|
47
|
+
if ((0, fs_1.existsSync)(tempSourceFile))
|
|
48
|
+
(0, fs_1.unlinkSync)(tempSourceFile);
|
|
49
|
+
if ((0, fs_1.existsSync)(tempExeFile))
|
|
50
|
+
(0, fs_1.unlinkSync)(tempExeFile);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Ignore cleanup error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { success, stack };
|
|
57
|
+
};
|
|
58
|
+
exports.cHandler = cHandler;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cobolHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const cobolHandler = (code, _snippet, _config, _sandbox, _isSharedSandbox) => {
|
|
9
|
+
let success = false;
|
|
10
|
+
let stack = "";
|
|
11
|
+
// COBOL execution logic
|
|
12
|
+
// Use shorter filename as cobc has strict length limits
|
|
13
|
+
const uniqueId = Math.random().toString(36).substring(2, 10);
|
|
14
|
+
const tempSourceFile = (0, path_1.join)((0, os_1.tmpdir)(), `cob_${uniqueId}.cob`);
|
|
15
|
+
const tempExeFile = (0, path_1.join)((0, os_1.tmpdir)(), `cob_${uniqueId}`);
|
|
16
|
+
try {
|
|
17
|
+
(0, fs_1.writeFileSync)(tempSourceFile, code);
|
|
18
|
+
// Compile with cobc -x (executable) -free (free format)
|
|
19
|
+
const compileResult = (0, child_process_1.spawnSync)('cobc', ['-x', '-free', '-o', tempExeFile, tempSourceFile], { encoding: 'utf-8' });
|
|
20
|
+
if (compileResult.status !== 0) {
|
|
21
|
+
stack = compileResult.stderr || "COBOL compilation failed";
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
// Run
|
|
25
|
+
const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8' });
|
|
26
|
+
if (runResult.status === 0) {
|
|
27
|
+
success = true;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
stack = runResult.stderr || "COBOL execution failed with non-zero exit code";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
stack = e.message || "Failed to execute cobc or run binary";
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
try {
|
|
39
|
+
if ((0, fs_1.existsSync)(tempSourceFile))
|
|
40
|
+
(0, fs_1.unlinkSync)(tempSourceFile);
|
|
41
|
+
if ((0, fs_1.existsSync)(tempExeFile))
|
|
42
|
+
(0, fs_1.unlinkSync)(tempExeFile);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Ignore cleanup error
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { success, stack };
|
|
49
|
+
};
|
|
50
|
+
exports.cobolHandler = cobolHandler;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fortranHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const fortranHandler = (code, _snippet, _config, _sandbox, _isSharedSandbox) => {
|
|
9
|
+
let success = false;
|
|
10
|
+
let stack = "";
|
|
11
|
+
// Fortran execution logic
|
|
12
|
+
// Auto-wrap if 'program' is missing
|
|
13
|
+
let fortranCode = code;
|
|
14
|
+
if (!fortranCode.toLowerCase().includes('program ')) {
|
|
15
|
+
fortranCode = `program main
|
|
16
|
+
${fortranCode}
|
|
17
|
+
end program main`;
|
|
18
|
+
}
|
|
19
|
+
const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
20
|
+
const tempSourceFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_fortran_${uniqueId}.f90`);
|
|
21
|
+
const tempExeFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_fortran_${uniqueId}`);
|
|
22
|
+
try {
|
|
23
|
+
(0, fs_1.writeFileSync)(tempSourceFile, fortranCode);
|
|
24
|
+
// Compile with gfortran
|
|
25
|
+
const compileResult = (0, child_process_1.spawnSync)('gfortran', [tempSourceFile, '-o', tempExeFile], { encoding: 'utf-8' });
|
|
26
|
+
if (compileResult.status !== 0) {
|
|
27
|
+
stack = compileResult.stderr || "Fortran compilation failed";
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Run
|
|
31
|
+
const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8' });
|
|
32
|
+
if (runResult.status === 0) {
|
|
33
|
+
success = true;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
stack = runResult.stderr || "Fortran execution failed with non-zero exit code";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
stack = e.message || "Failed to execute gfortran or run binary";
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
try {
|
|
45
|
+
if ((0, fs_1.existsSync)(tempSourceFile))
|
|
46
|
+
(0, fs_1.unlinkSync)(tempSourceFile);
|
|
47
|
+
if ((0, fs_1.existsSync)(tempExeFile))
|
|
48
|
+
(0, fs_1.unlinkSync)(tempExeFile);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore cleanup error
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { success, stack };
|
|
55
|
+
};
|
|
56
|
+
exports.fortranHandler = fortranHandler;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.goHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const goHandler = (code, _snippet, _config, _sandbox, _isSharedSandbox) => {
|
|
9
|
+
let success = false;
|
|
10
|
+
let stack = "";
|
|
11
|
+
// No shared context for Go yet, as it's compiled and strict structure
|
|
12
|
+
// We support standalone files or body snippets wrapped in main
|
|
13
|
+
let goCode = code;
|
|
14
|
+
if (!goCode.includes('package main')) {
|
|
15
|
+
goCode = `package main
|
|
16
|
+
import "fmt"
|
|
17
|
+
func main() {
|
|
18
|
+
${goCode}
|
|
19
|
+
}`;
|
|
20
|
+
}
|
|
21
|
+
const tempFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_go_${Date.now()}_${Math.random().toString(36).substring(7)}.go`);
|
|
22
|
+
try {
|
|
23
|
+
(0, fs_1.writeFileSync)(tempFile, goCode);
|
|
24
|
+
const result = (0, child_process_1.spawnSync)('go', ['run', tempFile], { encoding: 'utf-8' });
|
|
25
|
+
if (result.status === 0) {
|
|
26
|
+
success = true;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
stack = result.stderr || "Go execution failed with non-zero exit code";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
stack = e.message || "Failed to execute go run";
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
try {
|
|
37
|
+
(0, fs_1.unlinkSync)(tempFile);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Ignore cleanup error
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { success, stack };
|
|
44
|
+
};
|
|
45
|
+
exports.goHandler = goHandler;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.javascriptHandler = void 0;
|
|
4
|
+
const vm_1 = require("vm");
|
|
5
|
+
const esbuild_1 = require("esbuild");
|
|
6
|
+
const javascriptHandler = (code, _snippet, _config, sandbox, _isSharedSandbox) => {
|
|
7
|
+
let success = false;
|
|
8
|
+
let stack = "";
|
|
9
|
+
try {
|
|
10
|
+
const result = (0, esbuild_1.transformSync)(code, {
|
|
11
|
+
loader: 'ts',
|
|
12
|
+
format: 'cjs',
|
|
13
|
+
target: 'node12'
|
|
14
|
+
});
|
|
15
|
+
const compiledCode = result.code || "";
|
|
16
|
+
(0, vm_1.runInNewContext)(compiledCode, sandbox);
|
|
17
|
+
success = true;
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
stack = e.stack || "";
|
|
21
|
+
}
|
|
22
|
+
return { success, stack };
|
|
23
|
+
};
|
|
24
|
+
exports.javascriptHandler = javascriptHandler;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pythonHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const pythonHandler = (code, _snippet, _config, sandbox, isSharedSandbox) => {
|
|
6
|
+
let success = false;
|
|
7
|
+
let stack = "";
|
|
8
|
+
const context = sandbox;
|
|
9
|
+
// If sharing code, we need to accumulate previous python snippets
|
|
10
|
+
if (isSharedSandbox) {
|
|
11
|
+
if (!context._pythonContext) {
|
|
12
|
+
context._pythonContext = "";
|
|
13
|
+
}
|
|
14
|
+
context._pythonContext += code + "\n";
|
|
15
|
+
code = context._pythonContext;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const result = (0, child_process_1.spawnSync)('python3', [], { input: code, encoding: 'utf-8' });
|
|
19
|
+
if (result.status === 0) {
|
|
20
|
+
success = true;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
stack = result.stderr || "Python execution failed with non-zero exit code";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
stack = e.message || "Failed to spawn python3";
|
|
28
|
+
}
|
|
29
|
+
return { success, stack };
|
|
30
|
+
};
|
|
31
|
+
exports.pythonHandler = pythonHandler;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rustHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const os_1 = require("os");
|
|
8
|
+
const rustHandler = (code, _snippet, _config, _sandbox, _isSharedSandbox) => {
|
|
9
|
+
let success = false;
|
|
10
|
+
let stack = "";
|
|
11
|
+
// Rust execution logic
|
|
12
|
+
// Auto-wrap in main function if not present
|
|
13
|
+
let rustCode = code;
|
|
14
|
+
if (!rustCode.includes('fn main()')) {
|
|
15
|
+
rustCode = `fn main() {
|
|
16
|
+
${rustCode}
|
|
17
|
+
}`;
|
|
18
|
+
}
|
|
19
|
+
const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
20
|
+
const tempSourceFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_rust_${uniqueId}.rs`);
|
|
21
|
+
const tempExeFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_rust_${uniqueId}`);
|
|
22
|
+
try {
|
|
23
|
+
(0, fs_1.writeFileSync)(tempSourceFile, rustCode);
|
|
24
|
+
// Compile
|
|
25
|
+
const compileResult = (0, child_process_1.spawnSync)('rustc', [tempSourceFile, '-o', tempExeFile], { encoding: 'utf-8' });
|
|
26
|
+
if (compileResult.status !== 0) {
|
|
27
|
+
stack = compileResult.stderr || "Rust compilation failed";
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Run
|
|
31
|
+
const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8' });
|
|
32
|
+
if (runResult.status === 0) {
|
|
33
|
+
success = true;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
stack = runResult.stderr || "Rust execution failed with non-zero exit code";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
stack = e.message || "Failed to execute rustc or run binary";
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
try {
|
|
45
|
+
if ((0, fs_1.existsSync)(tempSourceFile))
|
|
46
|
+
(0, fs_1.unlinkSync)(tempSourceFile);
|
|
47
|
+
if ((0, fs_1.existsSync)(tempExeFile))
|
|
48
|
+
(0, fs_1.unlinkSync)(tempExeFile);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore cleanup error
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { success, stack };
|
|
55
|
+
};
|
|
56
|
+
exports.rustHandler = rustHandler;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shellHandler = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const shellHandler = (code, snippet, _config, sandbox, isSharedSandbox) => {
|
|
6
|
+
let success = false;
|
|
7
|
+
let stack = "";
|
|
8
|
+
const context = sandbox;
|
|
9
|
+
const shell = snippet.language || 'bash';
|
|
10
|
+
// If sharing code, we need to accumulate previous shell snippets
|
|
11
|
+
if (isSharedSandbox) {
|
|
12
|
+
if (!context._shellContext) {
|
|
13
|
+
context._shellContext = {};
|
|
14
|
+
}
|
|
15
|
+
if (!context._shellContext[shell]) {
|
|
16
|
+
context._shellContext[shell] = "";
|
|
17
|
+
}
|
|
18
|
+
context._shellContext[shell] += code + "\n";
|
|
19
|
+
code = context._shellContext[shell];
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Use the detected shell
|
|
23
|
+
const result = (0, child_process_1.spawnSync)(shell, ['-s'], { input: code, encoding: 'utf-8' });
|
|
24
|
+
if (result.status === 0) {
|
|
25
|
+
success = true;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const exitCode = result.status !== null ? result.status : 'signal';
|
|
29
|
+
stack = result.stderr || result.stdout || `${shell} execution failed with non-zero exit code: ${exitCode}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
stack = e.message || `Failed to spawn ${shell}`;
|
|
34
|
+
}
|
|
35
|
+
return { success, stack };
|
|
36
|
+
};
|
|
37
|
+
exports.shellHandler = shellHandler;
|