108 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			108 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;
 |