-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathjavascript.js
More file actions
147 lines (123 loc) · 4.46 KB
/
Copy pathjavascript.js
File metadata and controls
147 lines (123 loc) · 4.46 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
/**
* kernels/javascript.js — JavaScript kernel.
* Executes code natively in the browser via AsyncFunction.
* Captures console.log output and returns last expression value.
*/
class JavaScriptKernel {
constructor() {
this._ready = false;
}
static displayName = 'JavaScript';
async init() {
this._ready = true;
}
isReady() {
return this._ready;
}
getName() {
return 'JavaScript (Browser)';
}
getLanguage() {
return 'javascript';
}
async execute(code) {
if (!this._ready) {
throw new Error(window.t('kernel.javascriptNotInitialized'));
}
const trimmed = code.trim();
if (!trimmed) {
return { stdout: '', result: null, error: null };
}
// Capture console output
const logs = [];
const orig = {
log: console.log,
warn: console.warn,
error: console.error,
info: console.info,
};
const capture = (prefix) => (...args) => {
const line = args.map(a => {
if (a === undefined) return 'undefined';
if (a === null) return 'null';
if (typeof a === 'object') {
try { return JSON.stringify(a, null, 2); } catch (_) {}
}
return String(a);
}).join(' ');
logs.push(prefix ? `[${prefix}] ${line}` : line);
};
console.log = capture('');
console.warn = capture('warn');
console.error = capture('error');
console.info = capture('');
try {
// Try to auto-return the last expression value.
// If the code ends with an expression statement (not assignment,
// declaration, control flow, etc.), prepend "return" to it.
const execCode = this._autoReturn(trimmed);
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const fn = new AsyncFunction(execCode);
const result = await fn();
const stdout = logs.map(l => l.startsWith('[') ? l : l).join('\n');
let formattedResult = null;
if (result !== undefined && result !== null) {
let text;
if (typeof result === 'object') {
try { text = JSON.stringify(result, null, 2); } catch (_) { text = String(result); }
} else {
text = String(result);
}
formattedResult = { type: 'text', content: text };
}
return { stdout, result: formattedResult, error: null };
} catch (err) {
return { stdout: logs.join('\n'), result: null, error: err.message };
} finally {
console.log = orig.log;
console.warn = orig.warn;
console.error = orig.error;
console.info = orig.info;
}
}
/**
* If the last statement looks like a bare expression, prepend "return "
* so the cell displays its value (like browser devtools).
* Skips if the code already contains a return, or ends with a block,
* declaration, assignment, or control-flow keyword.
*/
_autoReturn(code) {
// If the code explicitly returns, don't touch it
if (/\breturn\b/.test(code)) return code;
// Split into lines, find the last non-empty line
const lines = code.split('\n');
let lastIdx = lines.length - 1;
while (lastIdx >= 0 && !lines[lastIdx].trim()) lastIdx--;
if (lastIdx < 0) return code;
const lastLine = lines[lastIdx].trim();
// Don't auto-return statements that aren't expressions
if (lastLine.endsWith(';')) {
// Semicolon suppresses output (like Python)
return code;
}
if (/^(let |const |var |function |class |if |for |while |switch |try |throw |import |export )/.test(lastLine)) {
return code;
}
if (lastLine.endsWith('{') || lastLine.endsWith('}')) {
return code;
}
// Prepend return to the last line
lines[lastIdx] = 'return ' + lines[lastIdx];
return lines.join('\n');
}
getMemoryUsage() {
return 0; // Native browser JS, no WASM allocation
}
destroy() {
this._ready = false;
}
}
// Register with kernel manager
if (window.kernelManager) {
window.kernelManager.register('javascript', JavaScriptKernel);
}