110 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			110 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const getAllBetween = require('./utils/between-headings');
 | |
| // const visit = require('unist-util-visit');
 | |
| const visitChildren = require('unist-util-visit-children');
 | |
| const { root } = require('mdast-builder');
 | |
| const { getFileVisitor } = require('./utils/get-file-visitor');
 | |
| const { isEmpty } = require('lodash');
 | |
| 
 | |
| const editableRegionMarker = '--fcc-editable-region--';
 | |
| 
 | |
| 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');
 | |
| }
 | |
| 
 | |
| // TODO: DRY this.  Start with an array of markers and go from there.
 | |
| function addSeeds() {
 | |
|   function transformer(tree, file) {
 | |
|     const seedTree = root(getAllBetween(tree, `--seed--`));
 | |
|     // Not all challenges have seeds (video challenges, for example), so we stop
 | |
|     // processing in these cases.
 | |
|     if (isEmpty(seedTree.children)) return;
 | |
|     const contentsTree = root(getAllBetween(seedTree, `--seed-contents--`));
 | |
|     const headTree = root(getAllBetween(seedTree, `--before-user-code--`));
 | |
|     const tailTree = root(getAllBetween(seedTree, `--after-user-code--`));
 | |
|     const seeds = {};
 | |
| 
 | |
|     // While before and after code are optional, the contents are not
 | |
|     if (isEmpty(contentsTree.children))
 | |
|       throw Error('## --seed-contents-- must appear in # --seed-- sections');
 | |
| 
 | |
|     const visitForContents = visitChildren(
 | |
|       getFileVisitor(seeds, 'contents', validateEditableMarkers)
 | |
|     );
 | |
|     const visitForHead = visitChildren(getFileVisitor(seeds, 'head'));
 | |
|     const visitForTail = visitChildren(getFileVisitor(seeds, 'tail'));
 | |
|     visitForContents(contentsTree);
 | |
|     visitForHead(headTree);
 | |
|     visitForTail(tailTree);
 | |
|     file.data = {
 | |
|       ...file.data,
 | |
|       files: seeds
 | |
|     };
 | |
| 
 | |
|     // process region markers - remove them from content and add them to data
 | |
|     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');
 | |
|         }
 | |
|         fileData.editableRegionBoundaries = editRegionMarkers;
 | |
|       } else {
 | |
|         fileData.editableRegionBoundaries = [];
 | |
|       }
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   return transformer;
 | |
| }
 | |
| 
 | |
| function validateEditableMarkers({ value, position }) {
 | |
|   const twoMarkersRE = RegExp(
 | |
|     editableRegionMarker + '.*' + editableRegionMarker
 | |
|   );
 | |
|   const formattedMarkerRE = /--fcc - editable - region--/;
 | |
|   const lines = value.split('\n');
 | |
|   const baseLineNumber = position.start.line + 1;
 | |
|   lines.forEach((line, index) => {
 | |
|     if (line.match(twoMarkersRE)) {
 | |
|       throw Error(
 | |
|         `Line ${
 | |
|           baseLineNumber + index
 | |
|         } has two markers. Each line should only have one.`
 | |
|       );
 | |
|     }
 | |
|     if (line.match(formattedMarkerRE)) {
 | |
|       throw Error(
 | |
|         `Line ${
 | |
|           baseLineNumber + index
 | |
|         } has a malformed marker. It should be --fcc-editable-region--`
 | |
|       );
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| module.exports = addSeeds;
 | |
| module.exports.editableRegionMarker = editableRegionMarker;
 |