/*
This is the web builder script that generates the web files.
Run using `npm run webber`.
*/
// Load modules
const fs = require('fs-extra'),
path = require('path'),
chalk = require('chalk'),
md = require('markdown-it')(),
minify = require('html-minifier').minify;
const util = require('./util');
var Prism = require('prismjs');
const minifyHTML = str =>
minify(str, {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: false,
minifyCSS: true,
minifyJS: true,
keepClosingSlash: true,
processConditionalComments: true,
removeAttributeQuotes: false,
removeComments: true,
removeEmptyAttributes: false,
removeOptionalTags: false,
removeScriptTypeAttributes: false,
removeStyleLinkTypeAttributes: false,
trimCustomFragments: true
});
const unescapeHTML = str =>
str.replace(
/&|<|>|'|"/g,
tag =>
({
'&': '&',
'<': '<',
'>': '>',
''': "'",
'"': '"'
}[tag] || tag)
);
const generateSnippetCard = (snippetList, snippetKey, addCornerTag = false) => `
${addCornerTag ? `
`: ''}
${md
.render(`\n${addCornerTag ? snippetList[snippetKey[0] + '.md'] : snippetList[snippetKey[0]]}`)
.replace(
/
/g, ' ')
.replace(
//m,
'
'
)
.replace(
/([^\0]*?)<\/code><\/pre>/gm,
(match, p1) =>
`${Prism.highlight(
unescapeHTML(p1),
Prism.languages.javascript
)} `
)
.replace(/<\/div>\s*\s+examples ';
// Loop over tags and snippets to create the list of snippets
for (let tag of taggedData) {
let localOutput = output
.replace(/\$tag/g, util.capitalize(tag))
.replace(new RegExp(`./${tag}#`, 'g'), '#');
if (tag === 'array') localOutput = localOutput.replace(new RegExp('./index#', 'g'), '#');
localOutput += md
.render(`## ${util.capitalize(tag, true)}\n`)
.replace(//g, '');
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
localOutput += generateSnippetCard(snippets, taggedSnippet, true);
// Add the ending static part
localOutput += `\n${endPart + '\n'}`;
// Optimize punctuation nodes
localOutput = util.optimizeNodes(
localOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
// Optimize operator nodes
localOutput = util.optimizeNodes(
localOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
// Optimize keyword nodes
localOutput = util.optimizeNodes(
localOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
pagesOutput.push({ tag: tag, content: localOutput });
}
// Minify output
pagesOutput.forEach(page => {
page.content = minifyHTML(page.content);
fs.writeFileSync(
path.join(docsPath, (page.tag === 'array' ? 'index' : page.tag) + '.html'),
page.content
);
console.log(
`${chalk.green('SUCCESS!')} ${page.tag === 'array' ? 'index' : page.tag}.html file generated!`
);
});
} catch (err) {
// Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During category page generation: ${err}`);
process.exit(1);
}
// Create the output for the archive.html file
try {
// Add the static part
archivedOutput += `${archivedStartPart}\n`;
// Filter README.md from folder
const filteredArchivedSnippets = filterSnippets(archivedSnippets, ['README.md']);
// Generate archived snippets from md files
for (let snippet of Object.entries(filteredArchivedSnippets))
archivedOutput += generateSnippetCard(filteredArchivedSnippets, snippet, false);
// Optimize punctuation nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
// Optimize operator nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
// Optimize keyword nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `${p1}${p2}${p3} `
);
archivedOutput += `${archivedEndPart}`;
// Generate and minify 'archive.html' file
const minifiedArchivedOutput = minifyHTML(archivedOutput);
fs.writeFileSync(path.join(docsPath, 'archive.html'), minifiedArchivedOutput);
console.log(`${chalk.green('SUCCESS!')} archive.html file generated!`);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During archive.html generation: ${err}`);
process.exit(1);
}
// Create the output for the glossary.html file
try {
// Add the static part
glossaryOutput += `${glossaryStartPart}\n`;
// Filter README.md from folder
const filteredGlossarySnippets = filterSnippets(glossarySnippets, ['README.md']);
// Generate glossary snippets from md files
for (let snippet of Object.entries(filteredGlossarySnippets))
glossaryOutput +=
'' +
md
.render(`\n${filteredGlossarySnippets[snippet[0]]}`)
.replace(/
/g, '') +
' ';
glossaryOutput += `${glossaryEndPart}`;
// Generate and minify 'glossary.html' file
const minifiedGlossaryOutput = minifyHTML(glossaryOutput);
fs.writeFileSync(path.join(docsPath, 'glossary.html'), minifiedGlossaryOutput);
console.log(`${chalk.green('SUCCESS!')} glossary.html file generated!`);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During glossary.html generation: ${err}`);
process.exit(1);
}
// Copy static files
staticFiles.forEach(f => {
try {
fs.copyFileSync(path.join(staticPartsPath, f), path.join(docsPath, f));
console.log(`${chalk.green('SUCCESS!')} ${f} file copied!`);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During ${f} copying: ${err}`);
process.exit(1);
}
});
// Log the time taken
console.timeEnd('Webber');