Compare commits
	
		
			No commits in common. "325b747bd841b1e80a12791e52e57aade02d50ca" and "c0dc360579715b6c08389e5caa8693897318d6d1" have entirely different histories.
		
	
	
		
			325b747bd8
			...
			c0dc360579
		
	
		
							
								
								
									
										52
									
								
								build.js
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								build.js
									
									
									
									
									
								
							| @ -1,20 +1,46 @@ | |||||||
| import fs from 'fs'; | import fs from 'fs'; | ||||||
| import { BasePaths } from './lib/render/base-paths.js'; | import Showdown from 'showdown'; | ||||||
| import { Renderer } from './lib/render/renderer.js'; | import 'dotenv/config'; | ||||||
| import { FileHelper } from './lib/render/file-helper.js'; | import { ENV } from './lib/env.js'; | ||||||
| import { SettingsReader } from './lib/render/settings-reader.js'; |  | ||||||
| import { Context } from './lib/struct/context.js'; |  | ||||||
| 
 | 
 | ||||||
| // Delete prior output, if exists.
 | const converter = new Showdown.Converter(); | ||||||
| if(fs.existsSync(BasePaths.targetRoot())) { | 
 | ||||||
|     fs.rmSync(BasePaths.targetRoot(), { recursive: true, force: true }); | let inputDir = 'content/'; | ||||||
|  | if(ENV.getIsSet('VS_INPUT_DIR')) { | ||||||
|  |     inputDir = ENV.getString('VS_INPUT_DIR'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // fs.mkdirSync(BasePaths.targetRoot());
 | let outputDir = 'build/'; | ||||||
|  | if(ENV.getIsSet('VS_OUTPUT_DIR')) { | ||||||
|  |     outputDir = ENV.getString('VS_OUTPUT_DIR'); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| const startPath = ''; | const fileEntities = fs.readdirSync(inputDir, {recursive: true, withFileTypes: true, encoding: 'utf8'}); | ||||||
| const rootContext = SettingsReader.readDirectorySettings(`${BasePaths.contentRoot()}/${startPath}`); |  | ||||||
| 
 | 
 | ||||||
| const renderer = new Renderer(startPath, rootContext); | fileEntities.forEach((fileEnt) => { | ||||||
|  |     const filenameTokens = fileEnt.name.split('.'); | ||||||
|  |     const extension = filenameTokens[filenameTokens.length - 1]; | ||||||
| 
 | 
 | ||||||
| renderer.renderAll(); |     if(extension === 'md') { | ||||||
|  |         const fullPath = fileEnt.parentPath + fileEnt.name; | ||||||
|  | 
 | ||||||
|  |         const content = fs.readFileSync(fullPath, {encoding: 'utf8'}); | ||||||
|  | 
 | ||||||
|  |         const converted = converter.makeHtml(content); | ||||||
|  | 
 | ||||||
|  |         let outputFileName = ""; | ||||||
|  |         for(let i = 0; i < filenameTokens.length - 1; i++) { | ||||||
|  |             outputFileName += filenameTokens[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         outputFileName += '.html'; | ||||||
|  | 
 | ||||||
|  |         const trimmedPath = fileEnt.parentPath.replace(inputDir, ""); | ||||||
|  | 
 | ||||||
|  |         const outputPath = outputDir + trimmedPath + outputFileName; | ||||||
|  | 
 | ||||||
|  |         fs.writeFileSync(outputPath, converted); | ||||||
|  | 
 | ||||||
|  |         console.log(`Converted ${fullPath} -> ${outputPath}`); | ||||||
|  |     } | ||||||
|  | }); | ||||||
| @ -1 +0,0 @@ | |||||||
| test variable = <* test_var *> |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| { |  | ||||||
|     "test_var": "Outer settings", |  | ||||||
|     "template": "base-template" |  | ||||||
| } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| { |  | ||||||
|     "test_var": "Inner setting", |  | ||||||
|     "template": "" |  | ||||||
| } |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Hello world from another directory! |  | ||||||
| 
 |  | ||||||
| <{ var-test }> |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| # Hello world! |  | ||||||
| 
 |  | ||||||
| <{ var-test }> |  | ||||||
| @ -1,6 +0,0 @@ | |||||||
| <div> |  | ||||||
|     <h3> |  | ||||||
|         Outer wrapper! |  | ||||||
|     </h3> |  | ||||||
|     <{ content }> |  | ||||||
| </div> |  | ||||||
							
								
								
									
										1
									
								
								content/test.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								content/test.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | # Here's a test! | ||||||
| @ -1,2 +0,0 @@ | |||||||
| export const DEFAULT_SOURCE_BASE = './content'; |  | ||||||
| export const DEFUALT_TARGET_BASE = './build'; |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| import { DEFAULT_SOURCE_BASE, DEFUALT_TARGET_BASE } from "../constants.js"; |  | ||||||
| import { ENV } from "../env.js" |  | ||||||
| 
 |  | ||||||
| export const BasePaths = { |  | ||||||
|     sourceRoot() { |  | ||||||
|         const overridePath = ENV.getString(`VS_INPUT_DIR`); |  | ||||||
| 
 |  | ||||||
|         return overridePath ?? DEFAULT_SOURCE_BASE; |  | ||||||
|     }, |  | ||||||
|     targetRoot() { |  | ||||||
|         const overridePath = ENV.getString(`VS_OUTPUT_DIR`); |  | ||||||
| 
 |  | ||||||
|         return overridePath ?? DEFUALT_TARGET_BASE; |  | ||||||
|     }, |  | ||||||
|     templates() { |  | ||||||
|         return `${this.sourceRoot()}/templates`; |  | ||||||
|     }, |  | ||||||
|     fragments() { |  | ||||||
|         return `${this.sourceRoot()}/fragments`; |  | ||||||
|     }, |  | ||||||
|     contentRoot() { |  | ||||||
|         return `${this.sourceRoot()}/site`; |  | ||||||
|     }, |  | ||||||
| } |  | ||||||
| @ -1,66 +0,0 @@ | |||||||
| import { fragmentFormats } from "../struct/fragment.js"; |  | ||||||
| 
 |  | ||||||
| export const FileHelper = { |  | ||||||
|     isContent(fileEnt) { |  | ||||||
|         return this.isFragment(fileEnt); |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     isFragment(fileEnt) { |  | ||||||
|         if(!fileEnt.isFile()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         const contentExtensions = [ |  | ||||||
|             '.vs.md', |  | ||||||
|             '.vs.html', |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         const matchesAnyContentExtensions = contentExtensions.some( |  | ||||||
|             (ext) => fileEnt.name.endsWith(ext) |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         return matchesAnyContentExtensions; |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     isSettingsFile(fileEnt) { |  | ||||||
|         if(!fileEnt.isFile()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return fileEnt.name === '_settings.json'; |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     getFragmentType(fileEnt) { |  | ||||||
|         const filePath = fileEnt.name; |  | ||||||
|          |  | ||||||
|         if(filePath.endsWith('.vs.md')) { |  | ||||||
|             return fragmentFormats.V_MARKDOWN; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(filePath.endsWith('.vs.html')) { |  | ||||||
|             return fragmentFormats.V_HTML; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return null; |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     getOutputFileName(fileEnt) { |  | ||||||
|         if(this.isContent(fileEnt)) { |  | ||||||
|             const stripped = this.getBaseName(fileEnt); |  | ||||||
| 
 |  | ||||||
|             return `${stripped}.html`; |  | ||||||
|         } else { |  | ||||||
|             return fileEnt.name; |  | ||||||
|         } |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     getBaseName(fileEnt) { |  | ||||||
|         const isMd = (this.getFragmentType(fileEnt) === fragmentFormats.V_MARKDOWN); |  | ||||||
|         const ext = isMd ? '.vs.md' : '.vs.html'; |  | ||||||
| 
 |  | ||||||
|         const idx = fileEnt.name.lastIndexOf(ext); |  | ||||||
|         const stripped = fileEnt.name.substring(0, idx); |  | ||||||
| 
 |  | ||||||
|         return stripped; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,69 +0,0 @@ | |||||||
| import fs from 'fs'; |  | ||||||
| import { BasePaths } from "./base-paths.js"; |  | ||||||
| import { FileHelper } from './file-helper.js'; |  | ||||||
| import { Fragment } from '../struct/fragment.js'; |  | ||||||
| 
 |  | ||||||
| export const SPECIAL_CONTENT_SYMBOL = `content`; |  | ||||||
| 
 |  | ||||||
| const FragmentSuperManager = { |  | ||||||
|     fragments: null, |  | ||||||
|     initialized: false, |  | ||||||
| 
 |  | ||||||
|     initialize() { |  | ||||||
|         const fragmentDir = BasePaths.fragments(); |  | ||||||
|         const entries = fs.readdirSync(fragmentDir, { encoding: 'utf-8', withFileTypes: true }); |  | ||||||
|         const fragmentEntries = entries.filter( |  | ||||||
|             (e) => FileHelper.isFragment(e) |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         let fragments = []; |  | ||||||
| 
 |  | ||||||
|         for(let i = 0; i < fragmentEntries.length; i++) { |  | ||||||
|             const type = FileHelper.getFragmentType(fragmentEntries[i]); |  | ||||||
|             const path = fragmentEntries[i].parentPath + '/' + fragmentEntries[i].name; |  | ||||||
|             const contents = fs.readFileSync(path, { encoding: 'utf-8' }); |  | ||||||
| 
 |  | ||||||
|             const fragment = new Fragment(type, contents); |  | ||||||
| 
 |  | ||||||
|             const name = FileHelper.getBaseName(fragmentEntries[i]); |  | ||||||
| 
 |  | ||||||
|             fragments.push({ |  | ||||||
|                 name: name, |  | ||||||
|                 fragment: fragment |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         this.fragments = fragments; |  | ||||||
|         this.initialized = true; |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     get(key)  { |  | ||||||
|         const match = this.fragments?.find( |  | ||||||
|             (e) => e.name === key |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         return match?.fragment; |  | ||||||
|     }, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export class FragmentManager { |  | ||||||
|     contentFragment; |  | ||||||
|     _fragmentSuperManager; |  | ||||||
| 
 |  | ||||||
|     constructor(contentFragment) { |  | ||||||
|         this.contentFragment = contentFragment; |  | ||||||
|         this._fragmentSuperManager = FragmentSuperManager; |  | ||||||
| 
 |  | ||||||
|         if(!FragmentSuperManager.initialized) { |  | ||||||
|             FragmentSuperManager.initialize(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     get(key) { |  | ||||||
|         if(key === SPECIAL_CONTENT_SYMBOL) { |  | ||||||
|             return this.contentFragment; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return this._fragmentSuperManager.get(key); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,150 +0,0 @@ | |||||||
| 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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,35 +0,0 @@ | |||||||
| import fs from 'fs'; |  | ||||||
| import { Variable } from '../struct/variable.js'; |  | ||||||
| import { Context } from '../struct/context.js'; |  | ||||||
| 
 |  | ||||||
| export const SettingsReader = { |  | ||||||
|     trimSettingsFromContent(rawContent) { |  | ||||||
|         return rawContent; |  | ||||||
|     }, |  | ||||||
|     readSettingsFromContent(rawContent) { |  | ||||||
|         return []; |  | ||||||
|     }, |  | ||||||
|     readDirectorySettings(directoryPath) { |  | ||||||
|         if(!fs.existsSync(directoryPath)) { |  | ||||||
|             return new Context(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(!directoryPath.endsWith('/')) { |  | ||||||
|             directoryPath += '/'; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         const settingsPath = directoryPath + '_settings.json'; |  | ||||||
|         if(!fs.existsSync(settingsPath)) { |  | ||||||
|             return new Context(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         const settingsFileContent = fs.readFileSync(settingsPath, { encoding: 'utf-8' }); |  | ||||||
|         const dict = JSON.parse(settingsFileContent); |  | ||||||
| 
 |  | ||||||
|         const vars = Object.keys(dict).map( |  | ||||||
|             (k) => new Variable(k, dict[k]) |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         return new Context(vars); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| @ -1,64 +0,0 @@ | |||||||
| import fs from 'fs'; |  | ||||||
| import { Fragment, fragmentFormats } from "../struct/fragment.js"; |  | ||||||
| import { BasePaths } from "./base-paths.js"; |  | ||||||
| import { FileHelper } from './file-helper.js'; |  | ||||||
| 
 |  | ||||||
| const TemplateSuperManager = { |  | ||||||
|     templates: null, |  | ||||||
|     initalized: false, |  | ||||||
| 
 |  | ||||||
|     initialize() { |  | ||||||
|         const templateDir = BasePaths.templates(); |  | ||||||
|         const entries = fs.readdirSync(templateDir, { encoding: 'utf-8', withFileTypes: true }); |  | ||||||
|         const templateEntries = entries.filter( |  | ||||||
|             (e) => FileHelper.isFragment(e) |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         let templates = []; |  | ||||||
| 
 |  | ||||||
|         for(let i = 0; i < templateEntries.length; i++) { |  | ||||||
|             const type = FileHelper.getFragmentType(templateEntries[i]); |  | ||||||
|             const path = templateEntries[i].parentPath + '/' + templateEntries[i].name; |  | ||||||
|             const contents = fs.readFileSync(path, { encoding: 'utf-8' }); |  | ||||||
| 
 |  | ||||||
|             const template = new Fragment(type, contents); |  | ||||||
| 
 |  | ||||||
|             const name = FileHelper.getBaseName(templateEntries[i]); |  | ||||||
| 
 |  | ||||||
|             templates.push({ |  | ||||||
|                 name: name, |  | ||||||
|                 template: template |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         this.templates = templates; |  | ||||||
|         this.initialized = true; |  | ||||||
|     }, |  | ||||||
| 
 |  | ||||||
|     get(key) { |  | ||||||
|         if(!this.initalized) { |  | ||||||
|             this.initialize(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         const match = this.templates.find( |  | ||||||
|             (t) => t.name === key |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         return match?.template; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export class TemplateManager { |  | ||||||
|     _templateSuperManager; |  | ||||||
| 
 |  | ||||||
|     constructor() { |  | ||||||
|         this._templateSuperManager = TemplateSuperManager; |  | ||||||
|         if(!TemplateSuperManager.initalized) { |  | ||||||
|             TemplateSuperManager.initialize(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     get(key) { |  | ||||||
|         return this._templateSuperManager.get(key); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| export const tokenTypes = { |  | ||||||
|     TEXT: 'text', |  | ||||||
|     VARIABLE: 'variable', |  | ||||||
|     FRAGMENT: 'fragment', |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export class Token { |  | ||||||
|     type; |  | ||||||
|     content; |  | ||||||
| 
 |  | ||||||
|     constructor(type, token) { |  | ||||||
|         this.type = type; |  | ||||||
|         this.content = token; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,61 +0,0 @@ | |||||||
| import { Token, tokenTypes } from "./token.js"; |  | ||||||
| 
 |  | ||||||
| const VARIABLE_TOKEN_DEF = { |  | ||||||
|     start: '<*', |  | ||||||
|     end: '*>', |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const FRAGMENT_TOKEN_DEF = { |  | ||||||
|     start: '<{', |  | ||||||
|     end: '}>', |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export class Tokenizer { |  | ||||||
|     constructor() { |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     tokensByVariable(fragmentText) { |  | ||||||
|         const forward_split_tokens = fragmentText.split(VARIABLE_TOKEN_DEF.start); |  | ||||||
| 
 |  | ||||||
|         let tokens = [ |  | ||||||
|             new Token(tokenTypes.TEXT, forward_split_tokens[0]) |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         for(let i = 1; i < forward_split_tokens.length; i++) { |  | ||||||
|             const back_split = forward_split_tokens[i].split(VARIABLE_TOKEN_DEF.end); |  | ||||||
| 
 |  | ||||||
|             if(back_split.length !== 2) { |  | ||||||
|                 console.error(`Difficulty parsing token: ${forward_split_tokens[i]}. Keeping as plain-text`); |  | ||||||
|                 tokens.push(new Token(tokenTypes.TEXT, forward_split_tokens[i])); |  | ||||||
|             } else { |  | ||||||
|                 tokens.push(new Token(tokenTypes.VARIABLE, back_split[0])); |  | ||||||
|                 tokens.push(new Token(tokenTypes.TEXT, back_split[1])); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return tokens; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     tokensByFragment(fragmentText) { |  | ||||||
|         const forward_split_tokens = fragmentText.split(FRAGMENT_TOKEN_DEF.start); |  | ||||||
| 
 |  | ||||||
|         let tokens = [ |  | ||||||
|             new Token(tokenTypes.TEXT, forward_split_tokens[0]) |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         for(let i = 1; i < forward_split_tokens.length; i++) { |  | ||||||
|             const back_split = forward_split_tokens[i].split(FRAGMENT_TOKEN_DEF.end); |  | ||||||
| 
 |  | ||||||
|             if(back_split.length !== 2) { |  | ||||||
|                 console.error(`Difficulty parsing token: ${forward_split_tokens[i]}. Keeping as plain-text`); |  | ||||||
|                 tokens.push(new Token(tokenTypes.TEXT, forward_split_tokens[i])); |  | ||||||
|             } else { |  | ||||||
|                 tokens.push(new Token(tokenTypes.FRAGMENT, back_split[0])); |  | ||||||
|                 tokens.push(new Token(tokenTypes.TEXT, back_split[1])); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return tokens; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,50 +0,0 @@ | |||||||
| import { Variable } from "./variable.js"; |  | ||||||
| 
 |  | ||||||
| export class Context { |  | ||||||
|     variables; |  | ||||||
| 
 |  | ||||||
|     constructor(vars) { |  | ||||||
|         if(vars) { |  | ||||||
|             this.variables = vars.map(v => new Variable(v.key, v.value)); |  | ||||||
|         } else { |  | ||||||
|             this.variables = []; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     copy() { |  | ||||||
|         return new Context(this.variables); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     hasVariable(key) { |  | ||||||
|         return this.variables.some( |  | ||||||
|             (v) => v.key === key |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     get(key) { |  | ||||||
|         const match = this.variables.find( |  | ||||||
|             (v) => v.key === key |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         return match?.value ?? ""; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     set(key, value) { |  | ||||||
|         const withoutOld = this.variables.filter( |  | ||||||
|             (v) => v.key !== key |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         this.variables = [ |  | ||||||
|             ...withoutOld, |  | ||||||
|             new Variable(key, value) |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     mergeFrom(other) { |  | ||||||
|         for(let i = 0; i < other.variables.length; i++) { |  | ||||||
|             this.set(other.variables[i].key, other.variables[i].value); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,34 +0,0 @@ | |||||||
| import Showdown from 'showdown'; |  | ||||||
| 
 |  | ||||||
| export const fragmentFormats = { |  | ||||||
|     V_HTML: ".vs.html", |  | ||||||
|     V_MARKDOWN: ".vs.md", |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export class Fragment { |  | ||||||
|     format; |  | ||||||
|     sourceContent; |  | ||||||
| 
 |  | ||||||
|     constructor(format, sourceContent) { |  | ||||||
|         this.format = format; |  | ||||||
|         this.sourceContent = sourceContent; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     toHtml() { |  | ||||||
|         if(this.format === fragmentFormats.V_MARKDOWN) { |  | ||||||
|             const converter = new Showdown.Converter(); |  | ||||||
| 
 |  | ||||||
|             const htmlContent = converter.makeHtml(this.sourceContent); |  | ||||||
| 
 |  | ||||||
|             return new Fragment( |  | ||||||
|                 fragmentFormats.V_HTML, |  | ||||||
|                 htmlContent |  | ||||||
|             ); |  | ||||||
|         } else { |  | ||||||
|             return new Fragment( |  | ||||||
|                 this.format, |  | ||||||
|                 this.sourceContent |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,9 +0,0 @@ | |||||||
| export class Variable { |  | ||||||
|     key; |  | ||||||
|     value; |  | ||||||
| 
 |  | ||||||
|     constructor(k, v) { |  | ||||||
|         this.key = k; |  | ||||||
|         this.value = v; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										8
									
								
								serve.js
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								serve.js
									
									
									
									
									
								
							| @ -3,14 +3,14 @@ import handler from 'serve-handler'; | |||||||
| import http from 'http'; | import http from 'http'; | ||||||
| import 'dotenv/config'; | import 'dotenv/config'; | ||||||
| import { ENV } from './lib/env.js'; | import { ENV } from './lib/env.js'; | ||||||
| import { BasePaths } from './lib/render/base-paths.js'; |  | ||||||
| 
 | 
 | ||||||
| const isDebugEnabled = ENV.getBoolean('VS_DEBUG'); | const isDebugEnabled = ENV.getBoolean('VS_DEBUG'); | ||||||
| 
 | const hasOverrideDirectory = ENV.getIsSet('VS_OUTPUT_DIR'); | ||||||
| const directory = BasePaths.targetRoot(); | const overrideDirectory = ENV.getString('VS_OUTPUT_DIR'); | ||||||
|  | const defaultDirectory = 'build'; | ||||||
| 
 | 
 | ||||||
| const options = { | const options = { | ||||||
|     public: directory, |     public: hasOverrideDirectory ? overrideDirectory : defaultDirectory, | ||||||
|     directoryListing: isDebugEnabled, |     directoryListing: isDebugEnabled, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user