Files
freeCodeCamp/common/app/routes/Challenges/rechallenge/builders.js
Kristofer Koishigawa 3df65c30cd fix(common): Fix for loopProtect undefined error (#16263)
Edited the file so that the loopProtect code, which is in the head of
the iframe on www.freecodecamp.org, is in the same script tag as the
base challenge content that get's rendered to the page. While the
loopProtect code is not rendered to the page like the rest of the
challenge code, it's within the same scope and seems to function
normally.

BREAKING CHANGE: None that I know of, but will keep checking.

Closes #16260
2017-12-22 14:51:21 -05:00

119 lines
3.1 KiB
JavaScript

import _ from 'lodash';
import { Observable } from 'rx';
import cond from 'lodash/cond';
import flow from 'lodash/flow';
import identity from 'lodash/identity';
import matchesProperty from 'lodash/matchesProperty';
import partial from 'lodash/partial';
import stubTrue from 'lodash/stubTrue';
import {
fetchScript,
fetchLink
} from '../utils/fetch-and-cache.js';
import {
compileHeadTail,
setExt,
transformContents
} from '../../../../utils/polyvinyl';
const htmlCatch = '\n<!--fcc-->\n';
const jsCatch = '\n;/*fcc*/\n';
const loopProtector = `
window.loopProtect = parent.loopProtect;
window.__err = null;
window.loopProtect.hit = function(line) {
window.__err = new Error(
'Potential infinite loop at line ' +
line +
'. To disable loop protection, write:' +
' // noprotect as the first' +
' line. Beware that if you do have an infinite loop in your code' +
' this will crash your browser.'
);
};
`;
const defaultTemplate = ({ source }) => `
<body style='margin:8px;'>
<!-- fcc-start-source -->
${source}
<!-- fcc-end-source -->
</body>
`;
const wrapInScript = partial(transformContents, (content) => (
`${htmlCatch}<script>${loopProtector}${content}${jsCatch}</script>`
));
const wrapInStyle = partial(transformContents, (content) => (
`${htmlCatch}<style>${content}</style>`
));
const setExtToHTML = partial(setExt, 'html');
const padContentWithJsCatch = partial(compileHeadTail, jsCatch);
const padContentWithHTMLCatch = partial(compileHeadTail, htmlCatch);
export const jsToHtml = cond([
[
matchesProperty('ext', 'js'),
flow(padContentWithJsCatch, wrapInScript, setExtToHTML)
],
[ stubTrue, identity ]
]);
export const cssToHtml = cond([
[
matchesProperty('ext', 'css'),
flow(padContentWithHTMLCatch, wrapInStyle, setExtToHTML)
],
[ stubTrue, identity ]
]);
// FileStream::concactHtml(
// required: [ ...Object ],
// template: String
// ) => Observable[{ build: String, sources: Dictionary }]
export function concactHtml(required, template) {
const createBody = template ? _.template(template) : defaultTemplate;
const source = this.shareReplay();
const sourceMap = source
.flatMap(files => files.reduce((sources, file) => {
sources[file.name] = file.source || file.contents;
return sources;
}, {}));
const head = Observable.from(required)
.flatMap(required => {
if (required.src) {
return fetchScript(required);
}
if (required.link) {
return fetchLink(required);
}
return Observable.just('');
})
.reduce((head, required) => head + required, '')
.map(head => `<head>${head}</head>`);
const body = source
.flatMap(file => file.reduce((body, file) => {
return body + file.contents + htmlCatch;
}, ''))
.map(source => ({ source }))
.map(createBody);
return Observable
.combineLatest(
head,
body,
fetchScript({
src: '/js/frame-runner.js',
crossDomain: false,
cacheBreaker: true
}),
sourceMap,
(head, body, frameRunner, sources) => ({
build: head + body + frameRunner,
sources
})
);
}