-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathframework-validation.js
More file actions
161 lines (140 loc) · 5.97 KB
/
framework-validation.js
File metadata and controls
161 lines (140 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* Framework lesson validation - syntax-only checking for lessons
* that require external dependencies (Flask, Spring Boot, etc.)
*/
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
const BASE_TMP_DIR = (process.env.RUN_TMP_DIR && process.env.RUN_TMP_DIR.trim()) || os.tmpdir();
/**
* Validate Python syntax only (don't execute)
*/
function validatePythonSyntax(code, frameworkName, callback) {
// Use python -m py_compile for syntax checking
const tempDir = fs.mkdtempSync(path.join(BASE_TMP_DIR, 'py-syntax-'));
const filePath = path.join(tempDir, 'check.py');
fs.writeFileSync(filePath, code);
// Use python -m py_compile for syntax checking
const pythonCmd = process.platform === 'win32' ? 'py' : 'python3';
const args = process.platform === 'win32' ? ['-3', '-m', 'py_compile', filePath] : ['-m', 'py_compile', filePath];
const check = spawn(pythonCmd, args);
let stderr = '';
check.stderr.on('data', (data) => {
stderr += data.toString();
});
check.on('close', (code) => {
// Cleanup
try {
fs.unlinkSync(filePath);
fs.rmdirSync(tempDir, { recursive: true });
} catch (_) { /* ignore cleanup errors */ }
if (code === 0) {
// Syntax valid
callback(null, {
success: true,
isFramework: true,
frameworkName: frameworkName || 'Framework',
message: 'Syntax Valid',
output: `✓ Python syntax is correct!\n\nℹ️ This is a ${frameworkName || 'framework'} lesson.\nTo run this code locally, install: pip install ${(frameworkName || 'framework').toLowerCase()}\n\nYour code will be validated for syntax only in this platform.`
});
} else {
// Syntax error
callback(null, {
success: false,
isFramework: true,
frameworkName: frameworkName || 'Framework',
error: true,
type: 'syntax',
output: stderr || 'Syntax error in code'
});
}
});
check.on('error', (err) => {
// Cleanup
try {
fs.unlinkSync(filePath);
fs.rmdirSync(tempDir, { recursive: true });
} catch (_) { /* ignore */ }
callback(err);
});
}
/**
* Validate Java syntax only (compile but don't run)
*/
function validateJavaSyntax(code, frameworkName, callback) {
const tempDir = fs.mkdtempSync(path.join(BASE_TMP_DIR, 'java-syntax-'));
const filePath = path.join(tempDir, 'Main.java');
fs.writeFileSync(filePath, code);
// Compile only - don't execute
const compile = spawn('javac', [filePath], { cwd: tempDir });
let compileError = '';
compile.stderr.on('data', (data) => {
compileError += data.toString();
});
compile.on('close', (code) => {
// Cleanup
try {
// Remove .java and .class files
fs.readdirSync(tempDir).forEach(file => {
fs.unlinkSync(path.join(tempDir, file));
});
fs.rmdirSync(tempDir);
} catch (_) { /* ignore cleanup errors */ }
if (code === 0) {
// Compilation successful
callback(null, {
success: true,
isFramework: true,
frameworkName: frameworkName || 'Framework',
message: 'Syntax Valid',
output: `✓ Java code compiles successfully!\n\nℹ️ This is a ${frameworkName || 'framework'} lesson.\nTo run this code locally, add the framework dependency to your pom.xml or build.gradle\n\nYour code has been validated for compilation only in this platform.`
});
} else {
// Check if errors are only framework-related (missing packages/symbols)
// These are expected for framework code without dependencies
const isOnlyFrameworkErrors = compileError &&
!compileError.includes('class, interface, enum, or record expected') &&
!compileError.includes('illegal start of expression') &&
!compileError.includes('not a statement') &&
!compileError.includes(';' + ' expected') &&
!compileError.includes('reached end of file while parsing') &&
(compileError.includes('package') && compileError.includes('does not exist') ||
compileError.includes('cannot find symbol'));
if (isOnlyFrameworkErrors) {
// Framework imports missing, but syntax is valid
callback(null, {
success: true,
isFramework: true,
frameworkName: frameworkName || 'Framework',
message: 'Syntax Valid',
output: `✓ Java syntax is correct!\n\nℹ️ This is a ${frameworkName || 'framework'} lesson.\nTo run this code locally, add the framework dependency to your pom.xml or build.gradle\n\nYour code has been validated for syntax only in this platform.\n\nNote: Framework imports are not available in this environment, but your code structure is correct.`
});
} else {
// Actual syntax error
callback(null, {
success: false,
isFramework: true,
frameworkName: frameworkName || 'Framework',
error: true,
type: 'compilation',
output: compileError || 'Compilation error'
});
}
}
});
compile.on('error', (err) => {
// Cleanup
try {
fs.readdirSync(tempDir).forEach(file => {
fs.unlinkSync(path.join(tempDir, file));
});
fs.rmdirSync(tempDir);
} catch (_) { /* ignore */ }
callback(err);
});
}
module.exports = {
validatePythonSyntax,
validateJavaSyntax
};