From 303ad38b8e14ae3c141d31ef20ff94bf8a33c445 Mon Sep 17 00:00:00 2001 From: Stuart Taylor Date: Mon, 8 Jan 2018 00:00:34 +0000 Subject: [PATCH] feat(rechallenge): Remove JS files from build pipline if JS is disabled --- .../routes/Challenges/rechallenge/builders.js | 14 +++------- .../Challenges/rechallenge/transformers.js | 24 ++++------------ .../redux/execute-challenge-epic.js | 2 +- common/app/routes/Challenges/utils/build.js | 28 +++++++++++-------- common/utils/polyvinyl.js | 22 +++------------ 5 files changed, 31 insertions(+), 59 deletions(-) diff --git a/common/app/routes/Challenges/rechallenge/builders.js b/common/app/routes/Challenges/rechallenge/builders.js index d5f833953b..4863d6b94f 100644 --- a/common/app/routes/Challenges/rechallenge/builders.js +++ b/common/app/routes/Challenges/rechallenge/builders.js @@ -50,28 +50,22 @@ const wrapInStyle = partial(transformContents, (content) => ( const setExtToHTML = partial(setExt, 'html'); const padContentWithJsCatch = partial(compileHeadTail, jsCatch); const padContentWithHTMLCatch = partial(compileHeadTail, htmlCatch); -function transformErrorProtect(fn) { - return cond([ - [ matchesProperty('transformError', false), fn ], - [ stubTrue, identity ] - ]); -} -export const jsToHtml = transformErrorProtect(cond([ +export const jsToHtml = cond([ [ matchesProperty('ext', 'js'), flow(padContentWithJsCatch, wrapInScript, setExtToHTML) ], [ stubTrue, identity ] -])); +]); -export const cssToHtml = transformErrorProtect(cond([ +export const cssToHtml = cond([ [ matchesProperty('ext', 'css'), flow(padContentWithHTMLCatch, wrapInStyle, setExtToHTML) ], [ stubTrue, identity ] -])); +]); // FileStream::concactHtml( // required: [ ...Object ], diff --git a/common/app/routes/Challenges/rechallenge/transformers.js b/common/app/routes/Challenges/rechallenge/transformers.js index fb46b3cc6f..60b584bc68 100644 --- a/common/app/routes/Challenges/rechallenge/transformers.js +++ b/common/app/routes/Challenges/rechallenge/transformers.js @@ -37,7 +37,7 @@ const NBSPReg = new RegExp(String.fromCharCode(160), 'g'); const isJS = matchesProperty('ext', 'js'); const testHTMLJS = overSome(isJS, matchesProperty('ext', 'html')); -const testJS$JSX = overSome(isJS, matchesProperty('ext', 'jsx')); +export const testJS$JSX = overSome(isJS, matchesProperty('ext', 'jsx')); // work around the absence of multi-flile editing // this can be replaced with `matchesProperty('ext', 'sass')` @@ -107,42 +107,28 @@ export const replaceNBSP = cond([ [ stubTrue, identity ] ]); -const transformErrorWarn = '/* __fcc--TransformError__ */'; - -function tryJSTransform(wrap = identity, defaultAssignment = 'code') { +function tryTransform(wrap = identity) { return function transformWrappedPoly(source) { const result = attempt(wrap, source); if (isError(result)) { const friendlyError = `${result}` .match(/[\w\W]+?\n/)[0] .replace(' unknown:', ''); - console.error(friendlyError); - return `var ${defaultAssignment} = null; ${transformErrorWarn}`; + throw new Error(friendlyError); } return result; }; } -function checkForTransformError(file) { - const potentialError = file.contents.includes(transformErrorWarn); - if (potentialError) { - return { - ...vinyl.setTransformError(true, file) - }; - } - return file; -} - export const babelTransformer = cond([ [ testJS$JSX, flow( partial( vinyl.transformHeadTailAndContents, - tryJSTransform(babelTransformCode, 'JSX') + tryTransform(babelTransformCode) ), - partial(vinyl.setExt, 'js'), - checkForTransformError + partial(vinyl.setExt, 'js') ) ], [ stubTrue, identity ] diff --git a/common/app/routes/Challenges/redux/execute-challenge-epic.js b/common/app/routes/Challenges/redux/execute-challenge-epic.js index b3ee5a2b3a..9913711ebd 100644 --- a/common/app/routes/Challenges/redux/execute-challenge-epic.js +++ b/common/app/routes/Challenges/redux/execute-challenge-epic.js @@ -42,6 +42,7 @@ export function updateMainEpic(actions, { getState }, { document }) { const proxyLogger = new Subject(); const frameMain = createMainFramer(document, getState, proxyLogger); const buildAndFrameMain = actions::ofType( + types.unlockUntrustedCode, types.modernEditorUpdated, types.classicEditorUpdated, types.executeChallenge, @@ -62,7 +63,6 @@ export function updateMainEpic(actions, { getState }, { document }) { }); } - export function executeChallengeEpic(actions, { getState }, { document }) { return Observable.of(document) // if document is not defined then none of this epic will run diff --git a/common/app/routes/Challenges/utils/build.js b/common/app/routes/Challenges/utils/build.js index dc3d4455b2..61a196abf5 100644 --- a/common/app/routes/Challenges/utils/build.js +++ b/common/app/routes/Challenges/utils/build.js @@ -6,11 +6,13 @@ import throwers from '../rechallenge/throwers'; import { backendFormValuesSelector, challengeTemplateSelector, - challengeRequiredSelector + challengeRequiredSelector, + isJSEnabledSelector } from '../redux'; import { applyTransformers, - proxyLoggerTransformer + proxyLoggerTransformer, + testJS$JSX } from '../rechallenge/transformers'; import { cssToHtml, @@ -42,23 +44,27 @@ const globalRequires = [ jQuery ]; -function postTransformCheck(file) { - if (file.transformError) { - // this will enable us to tap into the dipatch pipeline - // and disable JS in the preview - throw new Error('There was an error whilst transforming your code'); - } - return file; +function filterJSIfDisabled(state) { + const isJSEnabled = isJSEnabledSelector(state); + return file => { + if (testJS$JSX(file) && !isJSEnabled) { + return null; + } + return file; + }; } export function buildFromFiles(state, shouldProxyConsole) { const files = filesSelector(state); const required = challengeRequiredSelector(state); const finalRequires = [...globalRequires, ...required ]; - return createFileStream(files) + const requiredFiles = Object.keys(files) + .map(key => files[key]) + .filter(filterJSIfDisabled(state)) + .filter(Boolean); + return createFileStream(requiredFiles) ::pipe(throwers) ::pipe(applyTransformers) - ::pipe(postTransformCheck) ::pipe(shouldProxyConsole ? proxyLoggerTransformer : identity) ::pipe(jsToHtml) ::pipe(cssToHtml) diff --git a/common/utils/polyvinyl.js b/common/utils/polyvinyl.js index b0f060d0e5..47f1f4b763 100644 --- a/common/utils/polyvinyl.js +++ b/common/utils/polyvinyl.js @@ -5,11 +5,11 @@ import castToObservable from '../app/utils/cast-to-observable.js'; // createFileStream( -// files: Dictionary[Path, PolyVinyl] +// files: List[ PolyVinyl ] // ) => Observable[...Observable[...PolyVinyl]] -export function createFileStream(files = {}) { +export function createFileStream(files = []) { return Observable.of( - Observable.from(Object.keys(files).map(key => files[key])) + Observable.from(files) ); } @@ -77,8 +77,7 @@ export function createPoly({ path: name + '.' + ext, key: name + ext, contents, - error: null, - transformError: false + error: null }; } @@ -156,19 +155,6 @@ export function setError(error, poly) { error }; } -// setTransformError(transformError: Boolean, poly: PolyVinyl) => PolyVinyl -export function setTransformError(transformError, poly) { - invariant( - typeof transformError === 'boolean', - 'transformError must be a boolean, but got %', - transformError - ); - checkPoly(poly); - return { - ...poly, - transformError - }; -} // clearHeadTail(poly: PolyVinyl) => PolyVinyl export function clearHeadTail(poly) {