| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  | import { Observable } from 'rx'; | 
					
						
							|  |  |  | import cond from 'lodash/cond'; | 
					
						
							|  |  |  | import identity from 'lodash/identity'; | 
					
						
							|  |  |  | import stubTrue from 'lodash/stubTrue'; | 
					
						
							|  |  |  | import conforms from 'lodash/conforms'; | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  | import castToObservable from '../../../utils/cast-to-observable.js'; | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const HTML$JSReg = /html|js/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const testHTMLJS = conforms({ ext: (ext) => HTML$JSReg.test(ext) }); | 
					
						
							|  |  |  | // const testJS = matchesProperty('ext', 'js');
 | 
					
						
							|  |  |  | const passToNext = [ stubTrue, identity ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Detect if a JS multi-line comment is left open
 | 
					
						
							|  |  |  | const throwIfOpenComments = cond([ | 
					
						
							|  |  |  |   [ | 
					
						
							|  |  |  |     testHTMLJS, | 
					
						
							|  |  |  |     function _checkForComments({ contents }) { | 
					
						
							|  |  |  |       const openingComments = contents.match(/\/\*/gi); | 
					
						
							|  |  |  |       const closingComments = contents.match(/\*\//gi); | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         openingComments && | 
					
						
							|  |  |  |         (!closingComments || openingComments.length > closingComments.length) | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         throw new SyntaxError('Unfinished multi-line comment'); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   ], | 
					
						
							|  |  |  |   passToNext | 
					
						
							|  |  |  | ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Nested dollar sign calls breaks browsers
 | 
					
						
							|  |  |  | const nestedJQCallReg = /\$\s*?\(\s*?\$\s*?\)/gi; | 
					
						
							|  |  |  | const throwIfNestedJquery = cond([ | 
					
						
							|  |  |  |   [ | 
					
						
							|  |  |  |     testHTMLJS, | 
					
						
							|  |  |  |     function({ contents }) { | 
					
						
							|  |  |  |       if (nestedJQCallReg.test(contents)) { | 
					
						
							|  |  |  |         throw new SyntaxError('Nested jQuery calls breaks browsers'); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   ], | 
					
						
							|  |  |  |   passToNext | 
					
						
							|  |  |  | ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const functionReg = /function/g; | 
					
						
							|  |  |  | const functionCallReg = /function\s*?\(|function\s+\w+\s*?\(/gi; | 
					
						
							|  |  |  | // lonely function keywords breaks browsers
 | 
					
						
							|  |  |  | const ThrowIfUnfinishedFunction = cond([ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [ | 
					
						
							|  |  |  |     testHTMLJS, | 
					
						
							|  |  |  |     function({ contents }) { | 
					
						
							|  |  |  |       if ( | 
					
						
							|  |  |  |         functionReg.test(contents) && | 
					
						
							|  |  |  |         !functionCallReg.test(contents) | 
					
						
							|  |  |  |       ) { | 
					
						
							|  |  |  |         throw new SyntaxError( | 
					
						
							|  |  |  |           'Unsafe or unfinished function declaration' | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   ], | 
					
						
							|  |  |  |   passToNext | 
					
						
							|  |  |  | ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // console call stops tests scripts from running
 | 
					
						
							|  |  |  | const unsafeConsoleCallReg = /if\s\(null\)\sconsole\.log\(1\);/gi; | 
					
						
							|  |  |  | const throwIfUnsafeConsoleCall = cond([ | 
					
						
							|  |  |  |   [ | 
					
						
							|  |  |  |     testHTMLJS, | 
					
						
							|  |  |  |     function({ contents }) { | 
					
						
							|  |  |  |       if (unsafeConsoleCallReg.test(contents)) { | 
					
						
							|  |  |  |         throw new SyntaxError( | 
					
						
							|  |  |  |           '`if (null) console.log(1)` detected. This will break tests' | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   ], | 
					
						
							|  |  |  |   passToNext | 
					
						
							|  |  |  | ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Code with the URL hyperdev.com should not be allowed to run,
 | 
					
						
							|  |  |  | const goMixReg = /glitch\.(com|me)/gi; | 
					
						
							|  |  |  | const throwIfGomixDetected = cond([ | 
					
						
							|  |  |  |   [ | 
					
						
							|  |  |  |     testHTMLJS, | 
					
						
							|  |  |  |     function({ contents }) { | 
					
						
							|  |  |  |       if (goMixReg.test(contents)) { | 
					
						
							|  |  |  |         throw new Error('Glitch.com or Glitch.me should not be in the code'); | 
					
						
							| 
									
										
										
										
											2016-10-27 18:41:20 +05:30
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |   ], | 
					
						
							|  |  |  |   passToNext | 
					
						
							|  |  |  | ]); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  | const validators = [ | 
					
						
							|  |  |  |   throwIfOpenComments, | 
					
						
							|  |  |  |   throwIfGomixDetected, | 
					
						
							|  |  |  |   throwIfNestedJquery, | 
					
						
							|  |  |  |   ThrowIfUnfinishedFunction, | 
					
						
							|  |  |  |   throwIfUnsafeConsoleCall | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default function validate(file) { | 
					
						
							|  |  |  |   return validators.reduce((obs, validator) => obs.flatMap(file => { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       return castToObservable(validator(file)); | 
					
						
							|  |  |  |     } catch (err) { | 
					
						
							|  |  |  |       return Observable.throw(err); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-28 18:30:23 -07:00
										 |  |  |   }), Observable.of(file)) | 
					
						
							|  |  |  |     // if no error has occured 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); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-05-06 13:20:18 -07:00
										 |  |  | } |