2018-09-30 11:37:19 +01:00
|
|
|
import { flow } from 'lodash';
|
|
|
|
|
|
|
|
import { throwers } from '../rechallenge/throwers';
|
|
|
|
import {
|
|
|
|
challengeFilesSelector,
|
|
|
|
isJSEnabledSelector,
|
|
|
|
challengeMetaSelector,
|
|
|
|
backendFormValuesSelector
|
|
|
|
} from '../redux';
|
|
|
|
import { transformers, testJS$JSX } from '../rechallenge/transformers';
|
|
|
|
import { cssToHtml, jsToHtml, concatHtml } from '../rechallenge/builders.js';
|
2018-10-06 02:36:38 +03:00
|
|
|
import { isPromise } from './polyvinyl';
|
2018-09-30 11:37:19 +01:00
|
|
|
|
|
|
|
const frameRunner =
|
|
|
|
"<script src='/js/frame-runner.js' type='text/javascript'></script>";
|
|
|
|
|
|
|
|
const globalRequires = [
|
|
|
|
{
|
|
|
|
link:
|
|
|
|
'https://cdnjs.cloudflare.com/' +
|
|
|
|
'ajax/libs/normalize/4.2.0/normalize.min.css'
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
function filterJSIfDisabled(state) {
|
|
|
|
const isJSEnabled = isJSEnabledSelector(state);
|
|
|
|
return file => !(testJS$JSX(file) && !isJSEnabled);
|
|
|
|
}
|
|
|
|
|
2018-10-06 02:36:38 +03:00
|
|
|
const applyFunction = fn => file => {
|
|
|
|
if (file.error) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
let newFile = fn(file);
|
|
|
|
if (typeof newFile !== 'undefined') {
|
|
|
|
if (isPromise(newFile)) {
|
|
|
|
newFile = newFile.catch(() => {
|
|
|
|
// file.error = e.message;
|
|
|
|
return file;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return newFile;
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
} catch {
|
|
|
|
// file.error = e.message;
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-09-30 11:37:19 +01:00
|
|
|
const applyFunctions = fns => file =>
|
|
|
|
fns.reduce((file, fn) => {
|
2018-10-06 02:36:38 +03:00
|
|
|
if (isPromise(file)) {
|
|
|
|
return file.then(applyFunction(fn));
|
2018-09-30 11:37:19 +01:00
|
|
|
}
|
2018-10-06 02:36:38 +03:00
|
|
|
return applyFunction(fn)(file);
|
2018-09-30 11:37:19 +01:00
|
|
|
}, file);
|
|
|
|
const toHtml = [jsToHtml, cssToHtml];
|
|
|
|
const pipeLine = flow(
|
|
|
|
applyFunctions(throwers),
|
|
|
|
applyFunctions(transformers),
|
|
|
|
applyFunctions(toHtml)
|
|
|
|
);
|
|
|
|
|
2018-12-10 17:29:58 +03:00
|
|
|
export function buildHtmlFromFiles(state) {
|
2018-09-30 11:37:19 +01:00
|
|
|
const files = challengeFilesSelector(state);
|
|
|
|
const { required = [], template } = challengeMetaSelector(state);
|
|
|
|
const finalRequires = [...globalRequires, ...required];
|
|
|
|
const requiredFiles = Object.keys(files)
|
|
|
|
.map(key => files[key])
|
|
|
|
.filter(filterJSIfDisabled(state))
|
|
|
|
.filter(Boolean);
|
|
|
|
const finalFiles = requiredFiles.map(pipeLine);
|
|
|
|
return concatHtml(finalRequires, template, finalFiles);
|
|
|
|
}
|
|
|
|
|
2018-11-26 02:17:38 +03:00
|
|
|
export function buildJSFromFiles(files) {
|
|
|
|
const pipeLine = flow(
|
|
|
|
applyFunctions(throwers),
|
|
|
|
applyFunctions(transformers)
|
|
|
|
);
|
|
|
|
const finalFiles = Object.keys(files)
|
|
|
|
.map(key => files[key])
|
|
|
|
.map(pipeLine);
|
|
|
|
const sourceMap = Promise.all(finalFiles).then(files =>
|
|
|
|
files.reduce((sources, file) => {
|
|
|
|
sources[file.name] = file.source || file.contents;
|
|
|
|
return sources;
|
|
|
|
}, {})
|
|
|
|
);
|
|
|
|
const body = Promise.all(finalFiles).then(files =>
|
|
|
|
files
|
|
|
|
.reduce(
|
|
|
|
(body, file) => [
|
|
|
|
...body,
|
|
|
|
file.head + '\n' + file.contents + '\n' + file.tail
|
|
|
|
],
|
|
|
|
[]
|
|
|
|
)
|
|
|
|
.join('/n')
|
|
|
|
);
|
|
|
|
return Promise.all([body, sourceMap]).then(([body, sources]) => ({
|
|
|
|
solution: body,
|
|
|
|
code: sources && 'index' in sources ? sources['index'] : ''
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2018-09-30 11:37:19 +01:00
|
|
|
export function buildBackendChallenge(state) {
|
|
|
|
const {
|
|
|
|
solution: { value: url }
|
|
|
|
} = backendFormValuesSelector(state);
|
2018-12-10 10:00:26 +03:00
|
|
|
return {
|
2018-12-09 12:53:21 +03:00
|
|
|
build: frameRunner,
|
2018-12-10 10:00:26 +03:00
|
|
|
sources: { url }
|
|
|
|
};
|
2018-09-30 11:37:19 +01:00
|
|
|
}
|