| 
									
										
										
										
											2021-08-02 15:39:40 +02:00
										 |  |  | const { isEmpty } = require('lodash'); | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | const is = require('unist-util-is'); | 
					
						
							|  |  |  | const position = require('unist-util-position'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 { | 
					
						
							|  |  |  |     ext: lang, | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  |     name: getFilenames(lang), | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  |     contents: '', | 
					
						
							|  |  |  |     head: '', | 
					
						
							|  |  |  |     tail: '', | 
					
						
							|  |  |  |     id | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  | function getFilenames(lang) { | 
					
						
							|  |  |  |   const langToFilename = { | 
					
						
							|  |  |  |     js: 'script', | 
					
						
							|  |  |  |     css: 'styles' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   return langToFilename[lang] ?? 'index'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | 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 | 
					
						
							|  |  |  | `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  |   const fileId = `index${lang}`; | 
					
						
							|  |  |  |   const id = seeds[fileId] ? seeds[fileId].id : ''; | 
					
						
							| 
									
										
										
										
											2021-01-19 14:09:58 +09:00
										 |  |  |   // the contents will be missing if there is an id preceding this code
 | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  |   // block.
 | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  |   if (!seeds[fileId]) { | 
					
						
							|  |  |  |     seeds[fileId] = defaultFile(lang, id); | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (isEmpty(node.value) && seedKey !== 'contents') { | 
					
						
							|  |  |  |     const section = keyToSection[seedKey]; | 
					
						
							|  |  |  |     throw Error(`Empty code block in --${section}-- section`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  |   seeds[fileId][seedKey] = isEmpty(seeds[fileId][seedKey]) | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  |     ? node.value | 
					
						
							| 
									
										
										
										
											2021-12-03 21:32:29 +01:00
										 |  |  |     : seeds[fileId][seedKey] + '\n' + node.value; | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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')) { | 
					
						
							| 
									
										
										
										
											2021-08-12 19:48:28 +01:00
										 |  |  |     const fileKey = `index${codeNode.lang}`; | 
					
						
							|  |  |  |     if (seeds[fileKey]) throw Error('::id{#id}s must come before code blocks'); | 
					
						
							|  |  |  |     seeds[fileKey] = defaultFile(codeNode.lang, id); | 
					
						
							| 
									
										
										
										
											2020-11-27 19:02:05 +01:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     throw Error('::id{#id}s must come before code blocks'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports.getFileVisitor = getFileVisitor; |