Five functions are provided in this module: safeName
, toJSON
, segment
, wrapTemplate
, and wrapTemplate
(exported as the main module export). The wrapTemplate
function is the most complex, creating a wrapped HTML template with metadata and rendering it with provided properties, while the other functions perform specific string transformations and handling.
npm run import -- "output google sheet template"
var fs = require('fs');
var path = require('path');
var Mustache = require('mustache');
function safeName(val, render) {
return render(val).replace(/[^a-z0-9\-]/ig, '-').substr(0, 40)
}
function toJSON(val, render) {
return render(JSON.stringify(val))
}
function segment(url, val, render) {
return url.split('/')[render(val)]
}
function wrapTemplate(path, key, html, properties) {
properties['safeName'] = () => safeName
properties['toJSON'] = () => toJSON
properties['segment'] = () => segment.bind(null, path)
var classNames = path.replace(/\//ig, ' ')
+ ' ' + (key !== path.split('/')[0] ? key : '')
+ ' ' + (properties['class'] || '')
var domain = '';
if(typeof properties['domain'] != 'undefined') {
domain = properties['domain'].includes(':') ? '' : 'https://{{domain}}';
}
// automatically set title if it isn't set manually
var result;
if(typeof properties['title'] == 'undefined' && (result = (/<h1>(.*)<\/h1>/ig).exec(html))) {
properties['title'] = result[1];
}
var pageHtml = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="{{logo}}">
{{#base}}<base href="/{{.}}" />{{/base}}
<meta property="og:type" content="website">
<meta property="og:title" content="{{title}}">
<link rel="canonical" href="${domain}/${path}">
<title>{{title}}</title>
{{#banner}}
<style>
body > div.col-1:nth-of-type(2):before {background-image: url('{{{.}}}');}
body > div.col-1:nth-of-type(2):after {background-image: url('{{{.}}}');}
</style>
{{/banner}}
{{#stylesheet}}<link rel="stylesheet" href="{{.}}">{{/stylesheet}}
</head>
<body class="${classNames}">
${html}
{{#script}}<script async src="{{.}}"></script>{{/script}}
</body>
</html>`;
Mustache.parse(pageHtml);
// use properties for view and for partials
return Mustache.render(pageHtml, properties, properties);
}
module.exports = wrapTemplate;
const fs = require('fs');
const path = require('path');
const Mustache = require('mustache');
/**
* Sanitizes the input string to allow only alphanumeric characters, hyphens and limits it to 40 characters.
* @param {string} val Input string to be sanitized
* @param {function} render Function to be used for rendering templates
* @returns {string} Sanitized input string
*/
function safeName(val, render) {
return render(val).replace(/[^a-z0-9\-]/ig, '-').substr(0, 40);
}
/**
* Converts the input value to JSON string.
* @param {*} val Input value to be converted
* @param {function} render Function to be used for rendering templates
* @returns {string} JSON string representation of the input value
*/
function toJSON(val, render) {
return render(JSON.stringify(val));
}
/**
* Splits the URL into segments and returns the specified segment.
* @param {string} url URL to be split
* @param {*} val Index or value to specify which segment to return
* @param {function} render Function to be used for rendering templates
* @returns {string} Specified segment of the URL
*/
function segment(url, val, render) {
return url.split('/')[render(val)];
}
/**
* Wraps the template with the given properties.
* @param {string} path Template path
* @param {string} key Template key
* @param {string} html Template HTML
* @param {object} properties Template properties
* @returns {string} Wrapped template HTML
*/
function wrapTemplate(path, key, html, properties) {
// Initialize properties with render functions
properties['safeName'] = () => safeName;
properties['toJSON'] = () => toJSON;
properties['segment'] = (index) => segment(path, index, (val) => val);
// Generate class names
const classNames = [
path.replace(/\//ig,''),
key!== path.split('/')[0]? key : '',
properties['class'] || '',
].join(' ').trim();
// Set domain meta tag
let domain = '';
if (properties['domain']) {
if (properties['domain'].includes(':')) {
domain = '';
} else {
domain = 'https://{{domain}}';
}
}
properties['domain'] = domain;
// Set title if not provided
if (!properties['title'] && (result = (/<h1>(.*)<\/h1>/ig).exec(html))) {
properties['title'] = result[1];
}
// Define template HTML
const templateHtml = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="{{logo}}">
{{#base}}<base href="/{{.}}" />{{/base}}
<meta property="og:type" content="website">
<meta property="og:title" content="{{title}}">
<link rel="canonical" href="${domain}/${path}">
<title>{{title}}</title>
{{#banner}}
<style>
body > div.col-1:nth-of-type(2):before {background-image: url('{{{.}}}');}
body > div.col-1:nth-of-type(2):after {background-image: url('{{{.}}}');}
</style>
{{/banner}}
{{#stylesheet}}<link rel="stylesheet" href="{{.}}">{{/stylesheet}}
</head>
<body class="${classNames}">
${html}
{{#script}}<script async src="{{.}}"></script>{{/script}}
</body>
</html>
`;
// Parse and render template
Mustache.parse(templateHtml);
return Mustache.render(templateHtml, properties, properties);
}
module.exports = wrapTemplate;
Function Breakdown
safeName(val, render)
render
function to transform val
val
with non-alphanumeric characters replaced with hyphens and truncated to 40 characterstoJSON(val, render)
render
function to transform val
JSON.stringify(val)
renderedsegment(url, val, render)
render
function to transform val
url
with val
as the index to split and retrieve fromwrapTemplate(path, key, html, properties)
path
and key
with hyphensclassNames
for the <body>
elementtitle
from <h1>
tag if present, logo
and base
if present in properties
properties
as datamodule.exports = wrapTemplate;
wrapTemplate
function as the module's main export