src/ampl.js

Summary

Maintainability
A
1 hr
Test Coverage
import Remarkable from 'remarkable';
import htmlparser from 'htmlparser2';

import { getDims, updateImgTags } from './imageDims.js';
import { createAmpPage } from './templates.js';

const remarkable = new Remarkable('full');

export const parse = (markdown, opts, callback) => {
  markdown2AmpHTML({ markdown }, HTML =>
    callback(createAmpPage(HTML, opts))
  );
};

export const markdown2AmpHTML = (opts, callback) => {
  const { markdown } = opts;
  const htmlRaw = remarkable.render(markdown);
  parseHtml(htmlRaw, (html, { imageUrls }) =>
    getDims(imageUrls, (dimensions) =>
      callback(updateImgTags(html, dimensions))
    )
  );
};

const attribStr = attribs => Object.keys(attribs).map(attribKey =>
    ` ${attribKey}="${attribs[attribKey]}"`
).join('');

const createParseRules = () => [
  (urls => ({
    label: "imageUrls",
    target: "img",
    onOpenTag: attribs => urls.push(attribs.src),
    getResults: () => urls
  }))([])
];

const parseHtml = (html, callback) => {
  const parseRules = createParseRules();
  const tagStack = [{text: "<!doctype html>"}];
  const parser = new htmlparser.Parser({
    onopentag: (name, attribs) => {
      tagStack.push({name, attribs,
        text: ""
      });
      parseRules.forEach(rule => {
        if (rule.onOpenTag && !(rule.target && rule.target !== name)) {
          rule.onOpenTag(attribs);
        }
      });
    },
    ontext: text => {
      tagStack[tagStack.length-1].text += text;
    },
    onclosetag: name => {
      const tag = tagStack.pop();
      tagStack[tagStack.length-1].text +=
        `<${tag.name} ${attribStr(tag.attribs)}>${tag.text}</${tag.name}>`;
    },
    onend: () => {
      const ruleOutput = parseRules.reduce((data, rule) => {
        if (typeof rule.getResults === 'function') {
          data[rule.label] = rule.getResults();
        }
        return data;
      }, {});
      callback(tagStack[0].text, ruleOutput);
    }
  });
  parser.write(html);
  parser.end();
};

export default parse;