85 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			85 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const is = require('unist-util-is');
 | |
| const position = require('unist-util-position');
 | |
| const { isEmpty } = require('lodash');
 | |
| 
 | |
| const getId = require('./get-id');
 | |
| 
 | |
| const keyToSection = {
 | |
|   head: 'before-user-code',
 | |
|   tail: 'after-user-code'
 | |
| };
 | |
| const supportedLanguages = ['js', 'css', 'html', 'jsx', 'py'];
 | |
| 
 | |
| function defaultFile(lang, id) {
 | |
|   return {
 | |
|     key: `index${lang}`,
 | |
|     ext: lang,
 | |
|     name: 'index',
 | |
|     contents: '',
 | |
|     head: '',
 | |
|     tail: '',
 | |
|     id
 | |
|   };
 | |
| }
 | |
| 
 | |
| function getFileVisitor(seeds, seedKey, validate) {
 | |
|   return (node, index, parent) => {
 | |
|     if (is(node, 'root')) return;
 | |
|     if (is(node, 'code')) {
 | |
|       codeToData(node, seeds, seedKey, validate);
 | |
|       return;
 | |
|     }
 | |
|     idToData(node, index, parent, seeds);
 | |
|   };
 | |
| }
 | |
| 
 | |
| function codeToData(node, seeds, seedKey, validate) {
 | |
|   if (validate) validate(node);
 | |
|   const lang = node.lang;
 | |
|   if (!supportedLanguages.includes(lang))
 | |
|     throw Error(`On line ${
 | |
|       position.start(node).line
 | |
|     } '${lang}' is not a supported language.
 | |
|  Please use one of js, css, html, jsx or py
 | |
| `);
 | |
| 
 | |
|   const key = `index${lang}`;
 | |
|   const id = seeds[key] ? seeds[key].id : '';
 | |
|   // the contents will be missing if there is an id preceding this code
 | |
|   // block.
 | |
|   if (!seeds[key]) {
 | |
|     seeds[key] = defaultFile(lang, id);
 | |
|   }
 | |
|   if (isEmpty(node.value) && seedKey !== 'contents') {
 | |
|     const section = keyToSection[seedKey];
 | |
|     throw Error(`Empty code block in --${section}-- section`);
 | |
|   }
 | |
| 
 | |
|   seeds[key][seedKey] = isEmpty(seeds[key][seedKey])
 | |
|     ? node.value
 | |
|     : seeds[key][seedKey] + '\n' + node.value;
 | |
| }
 | |
| 
 | |
| function idToData(node, index, parent, seeds) {
 | |
|   const id = getId(node);
 | |
| 
 | |
|   // If this is reached, the node type is neither root nor code. If it is not
 | |
|   // an id, there must be a syntax error.
 | |
|   if (!id) {
 | |
|     throw Error(
 | |
|       'Unexpected syntax in seed/solution. Must be ::id{#id} or a code ' +
 | |
|         'block (```) \n'
 | |
|     );
 | |
|   }
 | |
|   const codeNode = parent.children[index + 1];
 | |
|   if (codeNode && is(codeNode, 'code')) {
 | |
|     const key = `index${codeNode.lang}`;
 | |
|     if (seeds[key]) throw Error('::id{#id}s must come before code blocks');
 | |
|     seeds[key] = defaultFile(codeNode.lang, id);
 | |
|   } else {
 | |
|     throw Error('::id{#id}s must come before code blocks');
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports.getFileVisitor = getFileVisitor;
 |