Skip to content

Commit

Permalink
Allow custom containers from consumer
Browse files Browse the repository at this point in the history
  • Loading branch information
astronomersiva committed Jan 1, 2019
1 parent a33446a commit 63ba4d9
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 128 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ ssl: {
removeComments: true
}
```
* `md`: Pass an array of block-level custom containers that can be used by the Markdown parser.
Refer [markdown-it-container](https://github.com/markdown-it/markdown-it-container).
```javascript
{
md: {
containers: [
{
name: 'myCustomContainer',
options: {
validate: function(params) {}
render: function(tokens, idx) {}
}
}
]
}
}
```

### Installation

Expand Down
29 changes: 24 additions & 5 deletions lib/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const {Signale} = require('signale');

const cleanBuild = require('./utils/cleanBuild');
const filterFileList = require('./utils/filterFileList');
const generateHtmlFromMd = require('./utils/generateHtmlFromMd');
const MdRenderer = require('./utils/MarkdownRenderer');
const loadData = require('./utils/loadData');

const { BUILD, POSTS } = require('./utils/constants');
Expand Down Expand Up @@ -43,12 +43,14 @@ class Site {

this._config = require(configFile) || {};

this._mdRenderer = this.setupMdRenderer(this._config);

let posts = glob.sync(`${POSTS}/**/*.md`).map(post => post.replace(`${POSTS}/`, ''));
let filteredPages = filterFileList(posts, 'md');
let filteredPosts = filterFileList(posts, 'md');

for (const post of filteredPages) {
for (const post of filteredPosts) {
let pageContents = fs.readFileSync(`${POSTS}/${post}`).toString();
let { html, meta } = generateHtmlFromMd(pageContents);
let { html, meta } = this._mdRenderer.renderMarkdown(pageContents);
let postPath = this.getPathForPost(post, meta);
let postData = Object.assign({
path: postPath,
Expand Down Expand Up @@ -83,6 +85,23 @@ class Site {
this._data = loadData(this.logger);
}

setupMdRenderer(config) {
let mdRenderer = new MdRenderer();

let customContainers = config.md && config.md.containers;
if (customContainers) {
try {
customContainers.forEach((customContainer) => {
mdRenderer.setupCustomContainer(customContainer.name, customContainer.options);
});
} catch (err) {
throw new Error('Invalid options passed for markdown-it custom containers.');
}
}

return mdRenderer;
}

getPathForPost(post, meta) {
let config = this.getConfig();
let parsedPath = path.parse(post);
Expand All @@ -103,7 +122,7 @@ class Site {

if (['add', 'change'].includes(event)) {
let pageContents = fs.readFileSync(post).toString();
let { html, meta } = generateHtmlFromMd(pageContents);
let { html, meta } = this._mdRenderer.renderMarkdown(pageContents);
let postPath = this.getPathForPost(post, meta);
let postData = Object.assign({
path: postPath,
Expand Down
129 changes: 129 additions & 0 deletions lib/utils/MarkdownRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const fs = require('fs-extra');
const path = require('path');
const sharp = require('sharp');
const markdownIt = require('markdown-it');
const markdownItContainer = require('markdown-it-container');
const frontMatter = require('markdown-it-front-matter');
const mila = require('markdown-it-link-attributes')

const yamlToObject = require('./yamlToObject');
const { BUILD, LAYOUTS } = require('./constants');

const resizeImage = async(src, dest1x, dest2x, res) => {
// hack as sharp doesnt work with /static
if (src.startsWith('/')) {
src = src.replace('/', '');
}

dest1x = path.join(BUILD, dest1x);
dest2x = path.join(BUILD, dest2x);

fs.mkdirpSync(path.dirname(dest1x));

await sharp(src)
.resize(Number(res))
.toFile(dest1x);

await sharp(src)
.resize(Number(res) * 2)
.toFile(dest2x);
}

let meta = {};

module.exports = class MdRender {
constructor() {
let md = markdownIt({ html: true })
.use(frontMatter, function(fm) {
meta = yamlToObject(fm);
})
.use(markdownItContainer, 'include', {
validate: function(params) {
return params.endsWith(':::') && params.includes('include');
},

render: function(tokens, idx) {
let statement = tokens[idx];
if (statement.type === 'container_include_open') {
let [, elements] = statement.info.trim().split(' ');
return fs.readFileSync(`${LAYOUTS}/${elements}`).toString();
}

return '';
}
})
.use(markdownItContainer, 'lego-image', {
validate: function(params) {
return params.endsWith(':::') && params.includes('lego-image');
},

render: function(tokens, idx) {
let statement = tokens[idx];
if (statement.type === 'container_lego-image_open') {
let tagContents = statement.info.replace(':::', '').trim();
let attributesRegex = /(\w+)="([\s\w,.\-_/@]+)"/g;
let attributes = tagContents.match(attributesRegex);
let attributeMap = {};
for (let attribute of attributes) {
let [key, value] = attribute.split('=');
attributeMap[key] = value.replace(/"/g, '');
}

let resolutions = attributeMap.res || '';
resolutions = resolutions.split(',').map(res => res.trim());
let srcset = [];
for (let res of resolutions) {
let { src } = attributeMap;
let extension = path.extname(src);
let dest1x = src.replace(extension, `-${res}${extension}`)
let dest2x = src.replace(extension, `-${res}@2x${extension}`)
resizeImage(src, dest1x, dest2x, res);
srcset.push({ res, dest1x, dest2x });
}

let sourceSrcset = '';
for (let src of srcset) {
sourceSrcset = `
${sourceSrcset}
<source
srcset="${src.dest1x}, ${src.dest2x} 2x"
media="(min-width: ${src.res}px)"
>
`;
}

return `
<picture>
${sourceSrcset}
<img
class="${attributeMap.class || ''}"
alt="${attributeMap.alt || ''}"
src="${attributeMap.src || ''}"
>
</picture>
`;
}

return '';
}
})
.use(mila, {
pattern: /^https?:\/\//,
attrs: {
target: '_blank',
rel: 'noopener'
}
});

this._md = md;
}

setupCustomContainer(name, options) {
this._md = this._md.use(markdownItContainer, name, options);
}

renderMarkdown(markdown) {
let html = this._md.render(markdown);
return { html, meta };
}
};
123 changes: 0 additions & 123 deletions lib/utils/generateHtmlFromMd.js

This file was deleted.

0 comments on commit 63ba4d9

Please sign in to comment.