| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | const visit = require('unist-util-visit'); | 
					
						
							|  |  |  | const { selectAll, select } = require('hast-util-select'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { sectionFilter } = require('./utils'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const seedRE = /(.+)-seed$/; | 
					
						
							|  |  |  | const headRE = /(.+)-setup$/; | 
					
						
							|  |  |  | const tailRE = /(.+)-teardown$/; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-01 23:14:46 -07:00
										 |  |  | const editableRegionMarker = '--fcc-editable-region--'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | function defaultFile(lang) { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     key: `index${lang}`, | 
					
						
							|  |  |  |     ext: lang, | 
					
						
							|  |  |  |     name: 'index', | 
					
						
							|  |  |  |     contents: '', | 
					
						
							|  |  |  |     head: '', | 
					
						
							|  |  |  |     tail: '' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  | function createCodeGetter(codeKey, regEx, seeds) { | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |   return container => { | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       properties: { id } | 
					
						
							|  |  |  |     } = container; | 
					
						
							|  |  |  |     const lang = id.match(regEx)[1]; | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |     const key = `index${lang}`; | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |     const code = select('code', container).children[0].value; | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |     if (key in seeds) { | 
					
						
							|  |  |  |       seeds[key] = { | 
					
						
							|  |  |  |         ...seeds[key], | 
					
						
							|  |  |  |         [codeKey]: code | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |       }; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |       seeds[key] = { | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |         ...defaultFile(lang), | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |         [codeKey]: code | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-01 23:14:46 -07:00
										 |  |  | // TODO: any reason to worry about CRLF?
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function findRegionMarkers(file) { | 
					
						
							|  |  |  |   const lines = file.contents.split('\n'); | 
					
						
							|  |  |  |   const editableLines = lines | 
					
						
							|  |  |  |     .map((line, id) => (line.trim() === editableRegionMarker ? id : -1)) | 
					
						
							|  |  |  |     .filter(id => id >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (editableLines.length > 2) { | 
					
						
							|  |  |  |     throw Error('Editable region has too many markers' + editableLines); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (editableLines.length === 0) { | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } else if (editableLines.length === 1) { | 
					
						
							|  |  |  |     throw Error(`Editable region not closed`); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return editableLines; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function removeLines(contents, toRemove) { | 
					
						
							|  |  |  |   const lines = contents.split('\n'); | 
					
						
							|  |  |  |   return lines.filter((_, id) => !toRemove.includes(id)).join('\n'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | function createPlugin() { | 
					
						
							|  |  |  |   return function transformer(tree, file) { | 
					
						
							|  |  |  |     function visitor(node) { | 
					
						
							|  |  |  |       if (sectionFilter(node, 'challengeSeed')) { | 
					
						
							|  |  |  |         let seeds = {}; | 
					
						
							|  |  |  |         const codeDivs = selectAll('div', node); | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         const seedContainers = codeDivs.filter(({ properties: { id } }) => | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |           seedRE.test(id) | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         seedContainers.forEach(createCodeGetter('contents', seedRE, seeds)); | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         const headContainers = codeDivs.filter(({ properties: { id } }) => | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |           headRE.test(id) | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         headContainers.forEach(createCodeGetter('head', headRE, seeds)); | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         const tailContainers = codeDivs.filter(({ properties: { id } }) => | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |           tailRE.test(id) | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2020-02-08 13:29:10 -05:00
										 |  |  |         tailContainers.forEach(createCodeGetter('tail', tailRE, seeds)); | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         file.data = { | 
					
						
							|  |  |  |           ...file.data, | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |           files: seeds | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2020-07-01 23:14:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // TODO: make this readable.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |         Object.keys(seeds).forEach(key => { | 
					
						
							|  |  |  |           const fileData = seeds[key]; | 
					
						
							|  |  |  |           const editRegionMarkers = findRegionMarkers(fileData); | 
					
						
							|  |  |  |           if (editRegionMarkers) { | 
					
						
							|  |  |  |             fileData.contents = removeLines( | 
					
						
							|  |  |  |               fileData.contents, | 
					
						
							|  |  |  |               editRegionMarkers | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (editRegionMarkers[1] <= editRegionMarkers[0]) { | 
					
						
							|  |  |  |               throw Error('Editable region must be non zero'); | 
					
						
							| 
									
										
										
										
											2020-07-01 23:14:46 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  |             fileData.editableRegionBoundaries = editRegionMarkers; | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             fileData.editableRegionBoundaries = []; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-07-01 23:14:46 -07:00
										 |  |  |         // TODO: TESTS!
 | 
					
						
							| 
									
										
										
										
											2018-09-30 20:13:52 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     visit(tree, 'element', visitor); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 16:52:49 +02:00
										 |  |  | exports.challengeSeedToData = createPlugin; | 
					
						
							|  |  |  | exports.createCodeGetter = createCodeGetter; | 
					
						
							| 
									
										
										
										
											2020-07-13 18:59:40 +02:00
										 |  |  | exports.defaultFile = defaultFile; |