convert spreadsheet | google sheet layout template | find known routes to sheets | Search

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.

Run example

npm run import -- "output google sheet template"

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;

What the code could have been:

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)

toJSON(val, render)

segment(url, val, render)

wrapTemplate(path, key, html, properties)

module.exports = wrapTemplate;