forked from matthisk/es6console
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsandbox.js
More file actions
131 lines (102 loc) · 3.1 KB
/
sandbox.js
File metadata and controls
131 lines (102 loc) · 3.1 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
import Compilers from 'compilers';
import { logCall } from 'store/ide';
import { complexFormatter } from 'utils';
// Disable modules so we do not insert use-strict
// on the first line.
const ES2015 = [
'es2015',
{
modules: false,
},
];
import runtimeScript from 'raw-loader!babel-polyfill/dist/polyfill.js';
class LogBuffer {
constructor() {
this.buffer = [];
}
flush() {
let buffer = [...this.buffer];
this.buffer.length = 0;
return buffer;
}
append(...args) {
this.buffer.push(...args);
}
}
export default class SandBox {
constructor() {
this.logBuffer = new LogBuffer();
var body = document.getElementsByTagName('body')[0];
this.frame = document.createElement('iframe');
this.frame.setAttribute('style', 'display: none');
this.frame.onerror = this._handleError.bind(this);
body.appendChild(this.frame);
// this.cnsl.wrapLog(this.frame.contentWindow.console);
this._wrapLog(this.frame.contentWindow.console);
// Todo: Load runtimeScript async
var script = this.frame.contentDocument.createElement('script');
script.type = 'text/javascript';
script.text = runtimeScript;
this.frame.contentDocument.body.appendChild(script);
}
_handleError(e) {
debugger;
}
_wrapLog(console) {
var origConsoleLog = console.log.bind(console);
console.log = (...args) => {
const formattedLog = complexFormatter(...args);
this.logBuffer.append(formattedLog);
origConsoleLog(...args);
};
return (this.origConsoleLog = origConsoleLog);
}
updateUserCode(code, onlyUpdate = false) {
if (onlyUpdate && this.userCode && this.userCode.innerHTML == code) {
return;
}
if (this.userCode) {
this.frame.contentDocument.body.removeChild(this.userCode);
}
try {
this.userCode = this.frame.contentDocument.createElement('script');
this.userCode.type = 'text/javascript';
this.frame.contentDocument.body.appendChild(this.userCode);
this.userCode.innerHTML = code;
} catch (e) {
console.error(['Error in user code:', e.message].join('\n'));
}
// We are not interested in log statements
// originated from updating the runtime
this.logBuffer.flush();
}
runCode(code) {
let out = {
logBuffer: [],
completionValue: null,
};
let compiler = Compilers['Babel (6)'];
try {
code = compiler.compile(code, {
presets: [ES2015],
}).code;
out.completionValue = this.frame.contentWindow.eval.call(null, code);
} catch (e) {
out.error = true;
if (e instanceof this.frame.contentWindow.Error) {
out.completionValue = window[e.name](e.message);
// e is an instance of an Error object from the
// frames window object
} else {
out.completionValue = new Error(e);
}
out.recoverable =
(e instanceof SyntaxError ||
e instanceof this.frame.contentWindow.SyntaxError) &&
e.message.match('Unexpected (token|end)');
}
out.logBuffer = this.logBuffer.flush();
return out;
}
}
export const sandbox = new SandBox();