import { attempt, cond, flow, identity, isError, matchesProperty, overSome, partial, stubTrue } from 'lodash'; import * as Babel from 'babel-standalone'; import presetEs2015 from 'babel-preset-es2015'; import presetReact from 'babel-preset-react'; import { Observable } from 'rxjs'; import protect from 'loop-protect'; import * as vinyl from '../utils/polyvinyl.js'; const { castToObservable } = vinyl; const protectTimeout = 100; Babel.registerPlugin('loopProtection', protect(protectTimeout)); const babelOptions = { plugins: ['loopProtection'], presets: [presetEs2015, presetReact] }; const babelTransformCode = code => Babel.transform(code, babelOptions).code; // const sourceReg = // /()([\s\S]*?)(?=)/g; const console$logReg = /(?:\b)console(\.log\S+)/g; const NBSPReg = new RegExp(String.fromCharCode(160), 'g'); const isJS = matchesProperty('ext', 'js'); const testHTMLJS = overSome(isJS, matchesProperty('ext', 'html')); 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')` // when the time comes const sassRE = /type='text\/sass'/i; const testSASS = file => sassRE.test(file.contents); // This can be done in the transformer when we have multi-file editing const browserSassCompiler = ` `; // if shouldProxyConsole then we change instances of console log // to `window.__console.log` // this let's us tap into logging into the console. // currently we only do this to the main window and not the test window export const proxyLoggerTransformer = partial( vinyl.transformHeadTailAndContents, source => source.replace(console$logReg, (match, methodCall) => { return 'window.__console' + methodCall; }) ); export const replaceNBSP = cond([ [ testHTMLJS, partial(vinyl.transformContents, contents => contents.replace(NBSPReg, ' ')) ], [stubTrue, identity] ]); function tryTransform(wrap = identity) { return function transformWrappedPoly(source) { const result = attempt(wrap, source); if (isError(result)) { console.error(result); // note(Bouncey): Error thrown here to collapse the build pipeline // At the minute, it will not bubble up // We collapse the pipeline so the app doesn't fall over trying // parse bad code (syntax/type errors etc...) throw new Error(); } return result; }; } export const babelTransformer = cond([ [ testJS$JSX, flow( partial( vinyl.transformHeadTailAndContents, tryTransform(babelTransformCode) ), partial(vinyl.setExt, 'js') ) ], [stubTrue, identity] ]); export const sassTransformer = cond([ [testSASS, partial(vinyl.appendToTail, browserSassCompiler)], [stubTrue, identity] ]); export const _transformers = [replaceNBSP, babelTransformer, sassTransformer]; export function applyTransformers(file, transformers = _transformers) { return transformers.reduce((obs, transformer) => { return obs.flatMap(file => castToObservable(transformer(file))); }, Observable.of(file)); }