-
Notifications
You must be signed in to change notification settings - Fork 0
/
generator.js
120 lines (112 loc) · 3.08 KB
/
generator.js
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
let fs = require('fs');
let generator = elements => {
let output = '';
let filename = '';
for(let elem of elements) {
switch(elem.type) {
case 'page':
filename = elem.filename;
output = '<html><head><title>Demo Site</title></head><body>';
break;
case 'endpage':
output = '</body></head>';
fs.writeFile(`/output/${filename}`, output, err => {
error(`Couldn't write to file '${filename}'. Error: ${err}`);
});
filename='';
output = '';
break;
case 'heading':
output += heading(elem);
break;
case 'columns':
output += columns(elem);
break;
default:
error(`Unknown type: ${elem.type}.`);
}
}
};
/**
* Generate a header.
* @param {Object} elem heading object. Should have "level" property and "text" property
*/
let heading = elem => {
let level = 1;
if(elem.level) {
level = elem.level;
}
else {
error('Heading requires a level.', elem);
}
if(elem.text) {
return `<h${level}>${elem.text}</h${level}>`;
}
else {
error('Heading requires text.', elem);
}
};
/**
* Generate columns.
* @param {Object} elem columns object. Should have "length" property indicating the number of columns and and a "cols"
* property, an array of arrays of examples.
*/
let columns = elem => {
let output = '';
for(let col of elem.cols) {
let colHTML = `<div style="width:50%; display:inline-block; vertical-align: top">`;
for(let ex of col) {
colHTML += example(ex);
}
colHTML += '</div>';
output += colHTML;
}
return output;
};
/**
* Generate an example.
* @param {Object} elem example object. Should have a "name" property with the name of the example, a "content" prop
* with the content of the example, and an optional "note" property with a note.
*/
let example = elem => {
let output = '';
if(elem.name) {
output += `<p><strong>${elem.name}</strong></p>`;
}
else {
error('Example requires a name.', elem);
}
if(elem.content) {
output += elem.content;
output += `<code><pre>${escapeHTML(elem.content)}</pre></code>`;
}
else {
error('Example requires content.', elem);
}
if(elem.note) {
output += `<p>${elem.note}</p>`;
}
return output;
}
const ESC_MAP = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
/**
* Escapes HTML
* http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/
* @param {string} s string to escape
* @returns {string} escaped string
*/
function escapeHTML(s) {
return s.replace(/[&<>'"]/g, function(c) {
return ESC_MAP[c];
});
}
let error = (msg, elem) => {
throw new Error(`Generator error: ${msg}${elem ? ` Raw output: ${JSON.stringify(elem)}` : ''}`);
}
module.exports = generator;