150 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { Context } from "../struct/context.js";
 | |
| import { Fragment, fragmentFormats } from "../struct/fragment.js";
 | |
| import { BasePaths } from "./base-paths.js";
 | |
| import { FileHelper } from "./file-helper.js";
 | |
| import { FragmentManager } from "./fragment-manager.js";
 | |
| import { SettingsReader } from "./settings-reader.js";
 | |
| import { TemplateManager } from "./template-manager.js";
 | |
| import { tokenTypes } from "./token.js";
 | |
| import { Tokenizer } from "./tokenizer.js";
 | |
| import fs, { write } from 'fs';
 | |
| 
 | |
| export class Renderer {
 | |
|     path;
 | |
|     context;
 | |
| 
 | |
|     constructor(path, context) {
 | |
|         this.path = path;
 | |
|         this.context = context;
 | |
|     }
 | |
| 
 | |
|     readFolder() {
 | |
|         return `${BasePaths.contentRoot()}/${this.path}`;
 | |
|     }
 | |
| 
 | |
|     writeFolder() {
 | |
|         return `${BasePaths.targetRoot()}/${this.path}`;
 | |
|     }
 | |
| 
 | |
|     renderAll() {
 | |
|         // Create output folder
 | |
|         fs.mkdirSync(this.writeFolder());
 | |
| 
 | |
|         // Get all files
 | |
|         const entries = fs.readdirSync(this.readFolder(), { encoding: 'utf-8', withFileTypes: true });
 | |
|         const files = entries.filter(
 | |
|             (e) => e.isFile()
 | |
|         );
 | |
| 
 | |
|         for(let i = 0; i < files.length; i++) {
 | |
|             // Render content files, copy non-content files.
 | |
|             if(FileHelper.isContent(files[i])) {
 | |
|                 this.renderPage(files[i]);
 | |
|             } else if(FileHelper.isSettingsFile(files[i])) {
 | |
|                 // pass
 | |
|             } else {
 | |
|                 this.copyFile(files[i]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Get all subdirectories.
 | |
|         const subdirs = entries.filter(
 | |
|             (e) => e.isDirectory()
 | |
|         );
 | |
| 
 | |
|         for(let i = 0; i < subdirs.length; i++) {
 | |
|             this.renderSubdirectory(subdirs[i]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     copyFile(fileEnt) {
 | |
|         const readPath = `${this.readFolder()}/${fileEnt.name}`;
 | |
|         const writePath = `${this.writeFolder()}/${fileEnt.name}`;
 | |
| 
 | |
|         fs.copyFileSync(readPath, writePath);
 | |
|     }
 | |
| 
 | |
|     renderPage(fileEnt) {
 | |
|         const type = FileHelper.getFragmentType(fileEnt);
 | |
| 
 | |
|         const readPath = `${this.readFolder()}/${fileEnt.name}`;
 | |
|         const content = fs.readFileSync(readPath, { encoding: 'utf-8' });
 | |
| 
 | |
|         const vars = SettingsReader.readSettingsFromContent(content);
 | |
|         const strippedContent = SettingsReader.trimSettingsFromContent(content);
 | |
| 
 | |
|         const fileContext = new Context(vars);
 | |
|         const fullContext = this.context.mergeFrom(fileContext);
 | |
| 
 | |
|         const contentFragment = new Fragment(type, strippedContent);
 | |
|         
 | |
|         let root = contentFragment;
 | |
|         const templateKey = fullContext.get(`template`);
 | |
|         if(templateKey) {
 | |
|             const template = new TemplateManager().get(templateKey);
 | |
|             if(template) {
 | |
|                 root = template;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         const pageOutput = this.renderFragment(root, fullContext, new FragmentManager(contentFragment));
 | |
| 
 | |
|         const writePath = `${this.writeFolder()}/${FileHelper.getOutputFileName(fileEnt)}`;
 | |
|         fs.writeFileSync(writePath, pageOutput);
 | |
|     }
 | |
| 
 | |
|     renderFragment(fragment, localContext, fragmentManager) {
 | |
|         if(!fragment) {
 | |
|             return '';
 | |
|         }
 | |
| 
 | |
|         const tokenizer = new Tokenizer();
 | |
|         const fragmentAsHtml = fragment.toHtml().sourceContent;
 | |
| 
 | |
|         const tokensByVar = tokenizer.tokensByVariable(fragmentAsHtml);
 | |
|         const replacedVarTokens = tokensByVar.map(
 | |
|             (t) => {
 | |
|                 if(t.type === tokenTypes.TEXT) {
 | |
|                     return t.content;
 | |
|                 } else {
 | |
|                     const key = t.content.trim();
 | |
|                     const value = localContext.get(key);
 | |
|                     return value;
 | |
|                 }
 | |
|             }
 | |
|         );
 | |
| 
 | |
|         const fragmentContentAfterVariableReplace = replacedVarTokens.reduce(
 | |
|             (a, b) => `${a}${b}`
 | |
|         );
 | |
| 
 | |
|         const tokensByFragment = tokenizer.tokensByFragment(fragmentContentAfterVariableReplace);
 | |
|         const self = this;
 | |
|         const replacedFragmentTokens = tokensByFragment.map(
 | |
|             (t) => {
 | |
|                 if(t.type === tokenTypes.TEXT) {
 | |
|                     return t.content;
 | |
|                 } else {
 | |
|                     const key = t.content.trim();
 | |
|                     const value = fragmentManager.get(key);
 | |
|                     return self.renderFragment(value, localContext, fragmentManager);
 | |
|                 }
 | |
|             }
 | |
|         );
 | |
| 
 | |
|         const final = replacedFragmentTokens.reduce(
 | |
|             (a, b) => `${a}${b}`
 | |
|         );
 | |
| 
 | |
|         return final;
 | |
|     }
 | |
| 
 | |
|     renderSubdirectory(subDirEnt) {
 | |
|         const subPath = `${this.readFolder()}/${subDirEnt.name}`;
 | |
|         const subdirContext = SettingsReader.readDirectorySettings(subPath);
 | |
|         const nextContext = this.context.copy().mergeFrom(subdirContext);
 | |
| 
 | |
|         const subRenderer = new Renderer(`${this.path}/${subDirEnt.name}`, nextContext);
 | |
|         subRenderer.renderAll();
 | |
|     }
 | |
| } | 
