freeCodeCamp/client/commonFramework/execute-challenge-stream.js

128 lines
3.6 KiB
JavaScript
Raw Normal View History

2015-11-17 21:25:16 -08:00
// what are the executeChallenge functions?
// Should be responsible for starting after a submit action
// Should not be responsible for displaying results
// Should return results
// should grab editor value
// depends on main editor
window.common = (function(global) {
const {
ga,
Rx: { Observable },
common = { init: [] }
} = global;
let attempts = 0;
const detectFunctionCall = /function\s*?\(|function\s+\w+\s*?\(/gi;
const detectUnsafeJQ = /\$\s*?\(\s*?\$\s*?\)/gi;
const detectUnsafeConsoleCall = /if\s\(null\)\sconsole\.log\(1\);/gi;
common.executeChallenge$ = function executeChallenge$() {
const code = common.editor.getValue();
const head = common.arrayToNewLineString(common.head);
const tail = common.arrayToNewLineString(common.tail);
attempts++;
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
let openingComments = code.match(/\/\*/gi);
// checks if the number of opening comments(/*) matches the number of
// closing comments(*/)
return Observable.just({ code })
.flatMap(({ code }) => {
2015-11-17 21:25:16 -08:00
if (
code.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
openingComments &&
openingComments.length > code.match(/\*\//gi).length
) {
return Observable.throw({
2015-11-17 21:25:16 -08:00
err: 'SyntaxError: Unfinished multi-line comment',
code
2015-11-17 21:25:16 -08:00
});
}
if (code.match(detectUnsafeJQ)) {
return Observable.throw({
2015-11-17 21:25:16 -08:00
err: 'Unsafe $($)',
code
2015-11-17 21:25:16 -08:00
});
}
if (
code.match(/function/g) &&
!code.match(detectFunctionCall)
) {
return Observable.throw({
2015-11-17 21:25:16 -08:00
err: 'SyntaxError: Unsafe or unfinished function declaration',
code
2015-11-17 21:25:16 -08:00
});
}
if (code.match(detectUnsafeConsoleCall)) {
return Observable.throw({
2015-11-17 21:25:16 -08:00
err: 'Invalid if (null) console.log(1); detected',
code
2015-11-17 21:25:16 -08:00
});
}
// add head and tail and detect loops
return Observable.just({ code: head + code + tail, original: code });
})
2015-11-22 19:42:53 -08:00
.flatMap(data => {
if (common.challengeType === common.challengeTypes.HTML) {
2015-11-22 19:42:53 -08:00
if (common.hasJs(code)) {
return common.addFaux$(data)
.flatMap(code => common.detectLoops$(code))
.flatMap(({ err }) => {
if (err) {
return Observable.throw({ err });
}
return common.runPreviewTests$({
code: data.code,
tests: common.tests.slice()
});
});
}
return common.updatePreview$(data.code)
.flatMap(code => common.runPreviewTests$({
code,
tests: common.tests.slice()
}));
}
2015-11-17 21:25:16 -08:00
return common.addTestsToString(Object.assign(
data,
{
code: common.removeComments(code),
tests: common.tests.slice()
}
2015-11-22 19:42:53 -08:00
))
.flatMap(common.detectLoops$)
.flatMap(({ err, code, data, userTests, original }) => {
if (err) {
return Observable.throw({ err });
}
2015-11-17 21:25:16 -08:00
2015-11-22 19:42:53 -08:00
return common.runTests$({
data,
code,
userTests,
original,
output: data.output.replace(/\\\"/gi, '')
});
});
})
.catch(e => {
return e && e.err ?
Observable.throw(e) :
Observable.throw({ err: e });
2015-11-17 21:25:16 -08:00
});
};
return common;
}(window));