-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathrender.js
More file actions
145 lines (124 loc) · 4.55 KB
/
render.js
File metadata and controls
145 lines (124 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const path = require('path');
const _ = require('lodash');
const { md, parseYamlFrontMatter } = require('./util');
const fs = require('fs-extra');
const Mustache = require('mustache');
const defaults = require('./defaults.json');
const {
getInitialDir,
getTemplate,
getPreprocessor,
getSlideOptions,
getRevealOptions,
getThemeUrl,
getHighlightThemeUrl,
getScriptPaths,
getCssPaths,
getWatch
} = require('./config');
const slidifyProps = ['attributes', 'notesSeparator', 'separator', 'verticalSeparator'];
const getSlidifyOptions = context => _.pick(context, slidifyProps);
const slidify = (markdown, slidifyOptions = _.pick(defaults, slidifyProps)) => {
var options = slidifyOptions;
var separatorRegex = new RegExp(options.separator + (options.verticalSeparator ? '|' + options.verticalSeparator : ''), 'mg');
var horizontalSeparatorRegex = new RegExp(options.separator);
var matches,
lastIndex = 0,
isHorizontal,
wasHorizontal = true,
content,
sectionStack = [];
while (matches = separatorRegex.exec(markdown)) {
var notes = null;
// determine direction (horizontal by default)
isHorizontal = horizontalSeparatorRegex.test(matches[0]);
if (!isHorizontal && wasHorizontal) {
// create vertical stack
sectionStack.push([]);
}
// pluck slide content from markdown input
content = markdown.substring(lastIndex, matches.index);
if (isHorizontal && wasHorizontal) {
// add to horizontal stack
sectionStack.push(content);
}
else {
// add to vertical stack
sectionStack[sectionStack.length - 1].push(content);
}
lastIndex = separatorRegex.lastIndex;
wasHorizontal = isHorizontal;
}
( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) );
var markdownSections = '';
// flatten the hierarchical stack, and insert <section data-markdown> tags
for( var i = 0, len = sectionStack.length; i < len; i++ ) {
// vertical
if( sectionStack[i] instanceof Array ) {
markdownSections += '<section '+ options.attributes +'>';
sectionStack[i].forEach( function( child ) {
if(child.includes("<!-- html -->")){
markdownSections += '<section '+ options.attributes +'>' + child + '</section>';
} else {
markdownSections += md.slidify(child, slidifyOptions);
}
} );
markdownSections += '</section>';
} else {
if(sectionStack[i].includes("<!-- html -->")){
markdownSections += '<section '+ options.attributes +'>' + sectionStack[i] + '</section>';
} else {
markdownSections += md.slidify(sectionStack[i], options);
}
}
}
return markdownSections;
};
const render = async (input, extraOptions = {}) => {
const { yamlOptions, markdown } = parseYamlFrontMatter(input);
const options = Object.assign(getSlideOptions(yamlOptions), extraOptions);
const { title } = options;
const themeUrl = getThemeUrl(options.theme, options.base);
const highlightThemeUrl = getHighlightThemeUrl(options.highlightTheme);
const revealOptions = Object.assign({}, getRevealOptions(options.revealOptions), yamlOptions.revealOptions);
const scriptPaths = getScriptPaths(options.scripts, options.assetsDir, options.base);
const cssPaths = getCssPaths(options.css, options.assetsDir, options.base);
const preprocessorFn = getPreprocessor(options.preprocessor);
const processedMarkdown = await preprocessorFn(markdown, options);
const slides = slidify(processedMarkdown, getSlidifyOptions(options));
const context = Object.assign(options, {
title,
slides,
themeUrl,
highlightThemeUrl,
scriptPaths,
cssPaths,
revealOptionsStr: JSON.stringify(revealOptions),
watch: getWatch()
});
const template = await getTemplate(options.template);
return Mustache.render(template, context);
};
const renderFile = async (filePath, extraOptions) => {
try {
const content = await fs.readFile(filePath);
return render(content.toString(), extraOptions);
} catch (e) {
return render("File not found.", extraOptions)
}
};
function sanitize(entry) {
if (entry.includes("..")) {
entry = sanitize(entry.replace("..", ""))
}
return entry
}
module.exports = async (req, res) => {
const dir = await getInitialDir();
const filePath = path.join(dir, sanitize(decodeURIComponent(req.url)).replace(/\?.*/, ''));
const markup = await renderFile(filePath);
res.send(markup);
};
module.exports.slidify = slidify;
module.exports.render = render;
module.exports.renderFile = renderFile;