Files
freeCodeCamp/client/rechallenge/builders.js
Berkeley Martinez ee8ac7b453 feat(rechallenge): Retool challenge framework (#13666)
* feat(rechallenge): Retool challenge framework

* fix(code-storage): should use setContent not updateContent

* fix(rechallenge): fix context issue and temporal zone of death

* fix(rechallenge): Fix frame sources for user code

* fix(polyvinyl): Set should ignore source and transform should keep track of source

* fix(rechallenge): Missing return statement causing issues
2017-04-28 20:30:23 -05:00

100 lines
2.5 KiB
JavaScript

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 {
compileHeadTail,
setExt,
transformContents
} from '../../common/utils/polyvinyl';
import {
fetchScript,
fetchLink
} from '../utils/fetch-and-cache.js';
const htmlCatch = '\n<!--fcc-->\n';
const jsCatch = '\n;/*fcc*/\n';
const wrapInScript = partial(transformContents, (content) => (
`${htmlCatch}<script>${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 ]
// ) => Observable[{ build: String, sources: Dictionary }]
export function concactHtml(required) {
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 => `
<body style='margin:8px;'>
<!-- fcc-start-source -->
${source}
<!-- fcc-end-source -->
</body>
`);
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
})
);
}