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();
|
|
}
|
|
} |