From a227ab4323772b2cd1412680a3546ed06cea4626 Mon Sep 17 00:00:00 2001
From: Louis Capitanchik <contact@louiscap.co>
Date: Mon, 22 Jan 2018 00:05:58 +0000
Subject: [PATCH] Initial Implementation

---
 .eslintrc.json    |  5 ++-
 index.js          | 90 +++++++++++++++++++++++++++++++++++++++++++++--
 package-lock.json | 21 +++++++----
 package.json      |  6 +++-
 4 files changed, 112 insertions(+), 10 deletions(-)

diff --git a/.eslintrc.json b/.eslintrc.json
index e2dc1f6..c6f6bd6 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,3 +1,6 @@
 {
-	"extends": "@bark"
+	"extends": "@bark",
+	"parserOptions": {
+		"ecmaVersion": 8
+	}
 }
\ No newline at end of file
diff --git a/index.js b/index.js
index a0bffd9..930c038 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,89 @@
-module.exports = function createMustacheMiddleware(viewDir) {
-	
+const path = require('path')
+const fs = require('fs-jetpack')
+const Mustache = require('mustache')
+
+function createPathsFromContext(context = '', filename) {
+	const { name } = path.parse(filename)
+	return [
+		path.join(context, filename),
+		path.join(context, name),
+	]
+}
+
+function createFileMap(dir, root, ext, debug) {
+	const cache = {}
+	const tree = dir.inspectTree(root)
+	if (tree.type !== 'dir') {
+		throw new TypeError(`[koa-mustache] viewDir must be an actual directory, found ${ tree.type }`)
+	}
+
+	const processing = tree.children
+	while (processing.length > 0) {
+		const current = processing.shift()
+
+		if (current.type === 'dir') {
+			for (const child of current.children) {
+				child.context = current.context ? path.join(current.context, current.name) : current.name
+				processing.push(child)
+			}
+		} else if (current.type === 'file') {
+			if (path.extname(current.name) === ext) {
+				const [pathWithExt, pathWithoutExt] = createPathsFromContext(current.context, current.name)
+				const content = dir.read(dir.path(root, pathWithExt), 'utf8')
+
+				debug(`[koa-mustache] Loading file ${ pathWithExt }`)
+
+				Mustache.parse(content)
+				cache[pathWithExt] = content
+				cache[pathWithoutExt] = content
+			}
+		}
+	}
+	return cache
+}
+
+module.exports = function createMustacheMiddleware(viewDir, opts = {}) {
+	const useCache = opts.hasOwnProperty('cache') ? opts.cache : process.env.NODE_ENV === 'production'
+	const extension = opts.hasOwnProperty('extension') ? opts.extension : '.mustache'
+	const partialDir = opts.hasOwnProperty('partials') ? opts.partials : 'partials'
+	const debug = opts.debug || (() => {}) // eslint-disable-line no-empty-function
+
+	const viewRoot = fs.cwd(viewDir)
+
+	const cache = useCache ? createFileMap(viewRoot, '.', extension, debug) : {}
+	const partials = createFileMap(viewRoot, partialDir, extension, debug)
+
+	return function attachRenderFunc(ctx, next) {
+		ctx.render = async function renderTemplateData(template, data = {}) {
+			if (useCache) {
+				const templateContent = cache[template]
+				if (templateContent == null) {
+					this.status = 404
+				} else {
+					this.status = 200
+					this.body = Mustache.render(templateContent, data, partials)
+				}
+			} else {
+				let fileData = await viewRoot.inspectAsync(template)
+				if (fileData == null) {
+					template += extension
+					fileData = await viewRoot.inspectAsync(template)
+					if (fileData == null) {
+						this.status = 404
+						return
+					}
+				}
+
+				if (fileData.type === 'file') {
+					const contents = await viewRoot.readAsync(template, 'utf8')
+					this.status = 200
+					this.body = Mustache.render(contents, data, partials)
+				} else {
+					this.status = 500
+				}
+			}
+		}.bind(ctx)
+
+		return next()
+	}
 }
diff --git a/package-lock.json b/package-lock.json
index 2b5f952..2e0f916 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -137,14 +137,12 @@
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
     "brace-expansion": {
       "version": "1.1.8",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
       "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
-      "dev": true,
       "requires": {
         "balanced-match": "1.0.0",
         "concat-map": "0.0.1"
@@ -247,8 +245,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "concat-stream": {
       "version": "1.6.0",
@@ -491,6 +488,14 @@
         "write": "0.2.1"
       }
     },
+    "fs-jetpack": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-1.2.0.tgz",
+      "integrity": "sha512-wEncEDStClGlHrQvqClINppjLdjQMcy3UFhu4DKrbTCIQHmiC+7r3nNvnc+3aiHxHaPfWXdA8UdCHNHGLJKciA==",
+      "requires": {
+        "minimatch": "3.0.4"
+      }
+    },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -732,7 +737,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "1.1.8"
       }
@@ -758,6 +762,11 @@
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
       "dev": true
     },
+    "mustache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz",
+      "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA="
+    },
     "mute-stream": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
diff --git a/package.json b/package.json
index ed88a18..10de461 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@commander-lol/koa-mustache",
-  "version": "1.0.0",
+  "version": "1.0.1-beta1",
   "description": "Mustache rendering for Koa 2+",
   "main": "index.js",
   "scripts": {
@@ -18,5 +18,9 @@
   "devDependencies": {
     "@bark/eslint-config": "^0.1.2",
     "eslint": "^4.16.0"
+  },
+  "dependencies": {
+    "fs-jetpack": "^1.2.0",
+    "mustache": "^2.3.0"
   }
 }
-- 
GitLab