Initial work on new framework
This commit is contained in:
		
							
								
								
									
										21
									
								
								client/new-framework/add-loop-protect.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								client/new-framework/add-loop-protect.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import loopProtect from 'loopProtect';
 | 
			
		||||
 | 
			
		||||
loopProtect.hit = function hit(line) {
 | 
			
		||||
  var err = 'Error: Exiting potential infinite loop at line ' +
 | 
			
		||||
    line +
 | 
			
		||||
    '. To disable loop protection, write: \n\\/\\/ noprotect\nas the first' +
 | 
			
		||||
    'line. Beware that if you do have an infinite loop in your code' +
 | 
			
		||||
    'this will crash your browser.';
 | 
			
		||||
  console.error(err);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Observable[Observable[File]]::addLoopProtect() => Observable[String]
 | 
			
		||||
export default function addLoopProtect() {
 | 
			
		||||
  const source = this;
 | 
			
		||||
  return source.map(files$ => files$.map(file => {
 | 
			
		||||
    if (file.extname === 'js') {
 | 
			
		||||
      file.contents = loopProtect(file.contents);
 | 
			
		||||
    }
 | 
			
		||||
    return file;
 | 
			
		||||
  }));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								client/new-framework/execute-challenge-saga.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								client/new-framework/execute-challenge-saga.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import createTypes from '../../common/app/utils/create-types';
 | 
			
		||||
const filterTypes = [
 | 
			
		||||
  execute
 | 
			
		||||
];
 | 
			
		||||
export default function executeChallengeSaga(action$, getState) {
 | 
			
		||||
  return action$
 | 
			
		||||
    .filter(({ type }) => filterTypes.some(_type => _type === type))
 | 
			
		||||
    .map(action => {
 | 
			
		||||
      if (action.type === execute) {
 | 
			
		||||
        const editors = getState().editors;
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								client/new-framework/polyvinyl.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								client/new-framework/polyvinyl.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
// originally base off of https://github.com/gulpjs/vinyl
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import replaceExt from 'replace-ext';
 | 
			
		||||
 | 
			
		||||
export default class File {
 | 
			
		||||
  constructor({
 | 
			
		||||
    path,
 | 
			
		||||
    history = [],
 | 
			
		||||
    base,
 | 
			
		||||
    contents = ''
 | 
			
		||||
  } = {}) {
 | 
			
		||||
    // Record path change
 | 
			
		||||
    this.history = path ? [path] : history;
 | 
			
		||||
    this.base = base || this.cwd;
 | 
			
		||||
    this.contents = contents;
 | 
			
		||||
    this._isPolyVinyl = true;
 | 
			
		||||
    this.error = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static isPolyVinyl = function(file) {
 | 
			
		||||
    return file && file._isPolyVinyl === true || false;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  isEmpty() {
 | 
			
		||||
    return !this._contents;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get contents() {
 | 
			
		||||
    return this._contents;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set contents(val) {
 | 
			
		||||
    if (typeof val !== 'string') {
 | 
			
		||||
      throw new TypeError('File.contents can only a String');
 | 
			
		||||
    }
 | 
			
		||||
    this._contents = val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get basename() {
 | 
			
		||||
    if (!this.path) {
 | 
			
		||||
      throw new Error('No path specified! Can not get basename.');
 | 
			
		||||
    }
 | 
			
		||||
    return path.basename(this.path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set basename(basename) {
 | 
			
		||||
    if (!this.path) {
 | 
			
		||||
      throw new Error('No path specified! Can not set basename.');
 | 
			
		||||
    }
 | 
			
		||||
    this.path = path.join(path.dirname(this.path), basename);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get extname() {
 | 
			
		||||
    if (!this.path) {
 | 
			
		||||
      throw new Error('No path specified! Can not get extname.');
 | 
			
		||||
    }
 | 
			
		||||
    return path.extname(this.path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set extname(extname) {
 | 
			
		||||
    if (!this.path) {
 | 
			
		||||
      throw new Error('No path specified! Can not set extname.');
 | 
			
		||||
    }
 | 
			
		||||
    this.path = replaceExt(this.path, extname);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get path() {
 | 
			
		||||
    return this.history[this.history.length - 1];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set path(path) {
 | 
			
		||||
    if (typeof path !== 'string') {
 | 
			
		||||
      throw new TypeError('path should be string');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Record history only when path changed
 | 
			
		||||
    if (path && path !== this.path) {
 | 
			
		||||
      this.history.push(path);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get error() {
 | 
			
		||||
    return this._error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set error(err) {
 | 
			
		||||
    if (typeof err !== 'object') {
 | 
			
		||||
      throw new TypeError('error must be an object or null');
 | 
			
		||||
    }
 | 
			
		||||
    this.error = err;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								client/new-framework/redux/types.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								client/new-framework/redux/types.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										89
									
								
								client/new-framework/throw-unsafe-code.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								client/new-framework/throw-unsafe-code.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
import { helpers, Observable } from 'rx';
 | 
			
		||||
 | 
			
		||||
const throwForJsHtml = {
 | 
			
		||||
  extname: /js|html/,
 | 
			
		||||
  throwers: [
 | 
			
		||||
    {
 | 
			
		||||
      name: 'multiline-comment',
 | 
			
		||||
      description: 'Detect if a JS multi-line comment is left open',
 | 
			
		||||
      thrower: function checkForComments({ content }) {
 | 
			
		||||
        const openingComments = content.match(/\/\*/gi);
 | 
			
		||||
        const closingComments = content.match(/\*\//gi);
 | 
			
		||||
        if (
 | 
			
		||||
          openingComments &&
 | 
			
		||||
          (!closingComments || openingComments.length > closingComments.length)
 | 
			
		||||
        ) {
 | 
			
		||||
          throw new Error('SyntaxError: Unfinished multi-line comment');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'nested-jQuery',
 | 
			
		||||
      description: 'Nested dollar sign calls breaks browsers',
 | 
			
		||||
      detectUnsafeJQ: /\$\s*?\(\s*?\$\s*?\)/gi,
 | 
			
		||||
      thrower: function checkForNestedJquery({ content }) {
 | 
			
		||||
        if (content.match(this.detectUnsafeJQ)) {
 | 
			
		||||
          throw new Error('Unsafe $($)');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'unfinished-function',
 | 
			
		||||
      description: 'lonely function keywords breaks browsers',
 | 
			
		||||
      detectFunctionCall: /function\s*?\(|function\s+\w+\s*?\(/gi,
 | 
			
		||||
      thower: function checkForUnfinishedFunction({ content: code }) {
 | 
			
		||||
        if (
 | 
			
		||||
          code.match(/function/g) &&
 | 
			
		||||
          !code.match(this.detectFunctionCall)
 | 
			
		||||
        ) {
 | 
			
		||||
          throw new Error(
 | 
			
		||||
            'SyntaxError: Unsafe or unfinished function declaration'
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'unsafe console call',
 | 
			
		||||
      description: 'console call stops tests scripts from running',
 | 
			
		||||
      detectUnsafeConsoleCall: /if\s\(null\)\sconsole\.log\(1\);/gi,
 | 
			
		||||
      thrower: function checkForUnsafeConsole({ content }) {
 | 
			
		||||
        if (content.match(this.detectUnsafeConsoleCall)) {
 | 
			
		||||
          throw new Error('Invalid if (null) console.log(1); detected');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function pretester() {
 | 
			
		||||
  const source = this;
 | 
			
		||||
  return source.map(file$ => file$.flatMap(file => {
 | 
			
		||||
    if (!throwForJsHtml.extname.test(file.extname)) {
 | 
			
		||||
      return Observable.just(file);
 | 
			
		||||
    }
 | 
			
		||||
    return Observable.from(throwForJsHtml.throwers)
 | 
			
		||||
      .flatMap(({ thrower }) => {
 | 
			
		||||
        try {
 | 
			
		||||
          let finalObs;
 | 
			
		||||
          const maybeObservableOrPromise = thrower(file);
 | 
			
		||||
          if (helpers.isPromise(maybeObservableOrPromise)) {
 | 
			
		||||
            finalObs = Observable.fromPromise(maybeObservableOrPromise);
 | 
			
		||||
          } else if (Observable.isObservable(maybeObservableOrPromise)) {
 | 
			
		||||
            finalObs = maybeObservableOrPromise;
 | 
			
		||||
          } else {
 | 
			
		||||
            finalObs = Observable.just(maybeObservableOrPromise);
 | 
			
		||||
          }
 | 
			
		||||
          return finalObs;
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          return Observable.throw(err);
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      // if none of the throwers throw, wait for last one
 | 
			
		||||
      .last({ defaultValue: null })
 | 
			
		||||
      // then map to the original file
 | 
			
		||||
      .map(file)
 | 
			
		||||
      // if err add it to the file
 | 
			
		||||
      // and return file
 | 
			
		||||
      .catch(err => {
 | 
			
		||||
        file.error = err;
 | 
			
		||||
        return Observable.just(file);
 | 
			
		||||
      });
 | 
			
		||||
  }));
 | 
			
		||||
}
 | 
			
		||||
@@ -81,6 +81,7 @@
 | 
			
		||||
    "pmx": "~0.6.2",
 | 
			
		||||
    "react": "^15.0.2",
 | 
			
		||||
    "react-bootstrap": "~0.29.4",
 | 
			
		||||
    "react-codemirror": "^0.2.6",
 | 
			
		||||
    "react-css-transition-replace": "^1.2.0-beta",
 | 
			
		||||
    "react-dom": "^15.0.2",
 | 
			
		||||
    "react-fontawesome": "^0.3.3",
 | 
			
		||||
@@ -97,6 +98,7 @@
 | 
			
		||||
    "redux-actions": "^0.9.1",
 | 
			
		||||
    "redux-epic": "^0.1.1",
 | 
			
		||||
    "redux-form": "^5.2.3",
 | 
			
		||||
    "replace-ext": "0.0.1",
 | 
			
		||||
    "request": "^2.65.0",
 | 
			
		||||
    "reselect": "^2.0.2",
 | 
			
		||||
    "rx": "^4.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -39,16 +39,16 @@ module.exports = {
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  externals: {
 | 
			
		||||
    'codemirror': 'CodeMirror'
 | 
			
		||||
    codemirror: 'CodeMirror'
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [
 | 
			
		||||
    new webpack.optimize.DedupePlugin(),
 | 
			
		||||
    new webpack.optimize.OccurenceOrderPlugin(true),
 | 
			
		||||
    new webpack.DefinePlugin({
 | 
			
		||||
      'process.env': {
 | 
			
		||||
        'NODE_ENV': JSON.stringify(__DEV__ ? 'development' : 'production')
 | 
			
		||||
        NODE_ENV: JSON.stringify(__DEV__ ? 'development' : 'production')
 | 
			
		||||
      },
 | 
			
		||||
      '__DEVTOOLS__': !__DEV__
 | 
			
		||||
      __DEVTOOLS__: !__DEV__
 | 
			
		||||
    })
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user