/* This is the web builder script that generates the README file. 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 unescapeHTML = str => str.replace( /&|<|>|'|"/g, tag => ({ '&': '&', '<': '<', '>': '>', ''': "'", '"': '"' }[tag] || tag) ); if(util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) { console.log(`${chalk.green('NOBUILD')} index build terminated, parent commit is a Travis build!`); process.exit(0); } // Compile the mini.css framework and custom CSS styles, using `node-sass`. const sass = require('node-sass'); sass.render( { file: path.join('docs', 'mini', 'flavor.scss'), outFile: path.join('docs', 'mini.css'), outputStyle: 'compressed' }, function(err, result) { if (!err) { fs.writeFile(path.join('docs', 'mini.css'), result.css, function(err2) { if (!err2) console.log(`${chalk.green('SUCCESS!')} mini.css file generated!`); else console.log(`${chalk.red('ERROR!')} During mini.css file generation: ${err}`); }); } else { console.log(`${chalk.red('ERROR!')} During mini.css file generation: ${err}`); } } ); // Set variables for paths const snippetsPath = './snippets', staticPartsPath = './static-parts', docsPath = './docs'; // Set variables for script let snippets = {}, startPart = '', endPart = '', output = '', tagDbData = {}; // Start the timer of the script console.time('Webber'); // Synchronously read all snippets and sort them as necessary (case-insensitive) snippets = util.readSnippets(snippetsPath); // Load static parts for the index.html file try { startPart = fs.readFileSync(path.join(staticPartsPath, 'index-start.html'), 'utf8'); endPart = fs.readFileSync(path.join(staticPartsPath, 'index-end.html'), 'utf8'); } catch (err) { // Handle errors (hopefully not!) console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`); process.exit(1); } // Load tag data from the database tagDbData = util.readTags(); // Create the output for the index.html file try { // Add the start static part output += `${startPart + '\n'}`; // Loop over tags and snippets to create the table of contents for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1][0]))] .filter(v => v) .sort((a, b) => util.capitalize(a, true) === 'Uncategorized' ? 1 : util.capitalize(b, true) === 'Uncategorized' ? -1 : a.localeCompare(b))) { output += `

` + md .render(`${util.capitalize(tag, true)}\n`) .replace(/

/g, '') .replace(/<\/p>/g, '') + `

`; for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) output += md .render(`[${taggedSnippet[0]}](#${taggedSnippet[0].toLowerCase()})\n`) .replace(/

/g, '') .replace(/<\/p>/g, '') .replace(/

`; output += ` `; // Loop over tags and snippets to create the list of snippets for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1][0]))] .filter(v => v) .sort((a, b) => util.capitalize(a, true) === 'Uncategorized' ? 1 : util.capitalize(b, true) === 'Uncategorized' ? -1 : a.localeCompare(b))) { output += md .render(`## ${util.capitalize(tag, true)}\n`) .replace(/

/g, '

'); for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) output += '
' + md .render(`\n${snippets[taggedSnippet[0] + '.md']}`) .replace(/

/g, `${taggedSnippet[1].includes('advanced')?'advanced':''}

`) .replace(/<\/h3>/g, '

') .replace(/
([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `
${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}
`) .replace(/<\/pre>\s+
📋 Copy to clipboard' +
          '
'; } // Add the ending static part output += `\n${endPart + '\n'}`; // Optimize punctuation nodes output = util.optimizeNodes(output, /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `${p1}${p2}${p3}`); // Optimize operator nodes output = util.optimizeNodes(output, /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `${p1}${p2}${p3}`); // Optimize keyword nodes output = util.optimizeNodes(output, /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `${p1}${p2}${p3}`); // do { // const punctuationRegex = /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm; // output = output.replace(punctuationRegex, // (match, p1, p2, p3) => `${p1}${p2}${p3}` // ); // count = 0; // while (punctuationRegex.exec(output) !== null) { // ++count; // } // } while (count > 0); // // Optimize operator nodes // do { // const operatorRegex = /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm; // output = output.replace(operatorRegex, // (match, p1, p2, p3) => `${p1}${p2}${p3}` // ); // count = 0; // while (operatorRegex.exec(output) !== null) { // ++count; // } // } while (count > 0); // // Optimize keyword nodes // do { // const keyWordRegex = /([^\0<]*?)<\/span>([\n\r\s]*)([^\0]*?)<\/span>/gm; // output = output.replace(keyWordRegex, // (match, p1, p2, p3) => `${p1}${p2}${p3}` // ); // count = 0; // while (keyWordRegex.exec(output) !== null) { // ++count; // } // } while (count > 0); // Minify output output = minify(output, { 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 }); // Write to the index.html file fs.writeFileSync(path.join(docsPath, 'index.html'), output); } catch (err) { // Handle errors (hopefully not!) console.log(`${chalk.red('ERROR!')} During index.html generation: ${err}`); process.exit(1); } // Log a success message console.log(`${chalk.green('SUCCESS!')} index.html file generated!`); // Log the time taken console.timeEnd('Webber');