diff --git a/package.json b/package.json index d2c5c6ca8..366cba720 100644 --- a/package.json +++ b/package.json @@ -10,25 +10,21 @@ "tape": "^4.8.0" }, "name": "30-seconds-of-code", - "description": "A collection of useful Javascript snippets.", + "description": "A collection of useful JavaScript snippets.", "version": "1.0.0", "main": "index.js", "scripts": { - "builder": "node ./scripts/build-script.js", - "linter": "node ./scripts/lint-script.js", - "tagger": "node ./scripts/tag-script.js", - "webber": "node ./scripts/web-script.js", - "tdd": "node ./scripts/tdd-script.js" + "builder": "node ./scripts/build.js", + "linter": "node ./scripts/lint.js", + "tagger": "node ./scripts/tag.js", + "webber": "node ./scripts/web.js", + "tdd": "node ./scripts/tdd.js" }, "repository": { "type": "git", "url": "git+https://github.com/Chalarangelo/30-seconds-of-code.git" }, - "keywords": [ - "javascript", - "snippets", - "list" - ], + "keywords": ["javascript", "snippets", "list"], "author": "Chalarangelo (chalarangelo@gmail.com)", "license": "MIT", "bugs": { diff --git a/scripts/build-script.js b/scripts/build-script.js deleted file mode 100644 index f8cf3ca8a..000000000 --- a/scripts/build-script.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - This is the builder script that generates the README file. - Run using `npm run builder`. -*/ -// Load modules -const fs = require('fs-extra'), path = require('path'), chalk = require('chalk'); -// Set variables for paths -const snippetsPath = './snippets', staticPartsPath = './static-parts'; -// Set variables for script -let snippets = {}, startPart = '', endPart = '', output = '', tagDbData = {}; -// Load helper functions (these are from existing snippets in 30 seconds of code!) -const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {}); -const capitalize = (str, lowerRest = false) => str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1)); -// Start the timer of the script -console.time('Builder'); -// Synchronously read all snippets and sort them as necessary (case-insensitive) -try { - let snippetFilenames = fs.readdirSync(snippetsPath); - snippetFilenames.sort((a, b) => { - a = a.toLowerCase(); - b = b.toLowerCase(); - if (a < b) return -1; - if (a > b) return 1; - return 0; - }); - // Store the data read from each snippet in the appropriate object - for(let snippet of snippetFilenames) snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8'); -} -catch (err){ // Handle errors (hopefully not!) - console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`); - process.exit(1); -} -// Load static parts for the README file -try { - startPart = fs.readFileSync(path.join(staticPartsPath,'README-start.md'),'utf8'); - endPart = fs.readFileSync(path.join(staticPartsPath,'README-end.md'),'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 -try { - tagDbData = objectFromPairs(fs.readFileSync('tag_database','utf8').split('\n').slice(0,-1).map(v => v.split(':').slice(0,2))); -} -catch (err){ // Handle errors (hopefully not!) - console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`); - process.exit(1); -} -// Create the output for the README file -try { - // Add the start static part - output += `${startPart+'\n'}`; - // Loop over tags and snippets to create the table of contents - let uncategorizedOutput = ''; - for(let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))].filter(v => v).sort((a,b) => a.localeCompare(b))){ - if(capitalize(tag, true)=='Uncategorized') { - uncategorizedOutput +=`### _${capitalize(tag, true)}_\n\n
\nView contents\n\n`; - for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) - uncategorizedOutput += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n` - uncategorizedOutput += '\n
\n\n'; - } else { - output +=`### ${capitalize(tag, true)}\n\n
\nView contents\n\n`; - for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) - output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n` - output += '\n
\n\n'; - } - } - output += uncategorizedOutput; - uncategorizedOutput = ''; - // Loop over tags and snippets to create the list of snippets - for(let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))].filter(v => v).sort((a,b) => a.localeCompare(b))){ - if(capitalize(tag, true)=='Uncategorized') { - uncategorizedOutput +=`## _${capitalize(tag, true)}_\n`; - for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) - uncategorizedOutput += `\n${snippets[taggedSnippet[0]+'.md']+'\n
[⬆ back to top](#table-of-contents)\n\n'}`; - } else { - output +=`## ${capitalize(tag, true)}\n`; - for(let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)){ - let data = snippets[taggedSnippet[0]+'.md']; - data = data.slice(0,data.lastIndexOf('```js')) + '
\nExamples\n\n' + data.slice(data.lastIndexOf('```js'),data.lastIndexOf('```')) + data.slice(data.lastIndexOf('```')) + '\n
\n'; - output += `\n${data+'\n
[⬆ Back to top](#table-of-contents)\n\n'}`; - } - } - } - output += uncategorizedOutput; - // Add the ending static part - output += `\n${endPart+'\n'}`; - // Write to the README file - fs.writeFileSync('README.md', output); -} -catch (err){ // Handle errors (hopefully not!) - console.log(`${chalk.red('ERROR!')} During README generation: ${err}`); - process.exit(1); -} -// Log a success message -console.log(`${chalk.green('SUCCESS!')} README file generated!`); -// Log the time taken -console.timeEnd('Builder'); diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 000000000..a6e6d607d --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,127 @@ +/* + This is the builder script that generates the README file. + Run using `npm run builder`. +*/ +// Load modules +const fs = require('fs-extra'), + path = require('path'), + chalk = require('chalk'); +// Set variables for paths +const snippetsPath = './snippets', + staticPartsPath = './static-parts'; +// Set variables for script +let snippets = {}, + startPart = '', + endPart = '', + output = '', + tagDbData = {}; +// Load helper functions (these are from existing snippets in 30 seconds of code!) +const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {}); +const capitalize = (str, lowerRest = false) => + str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1)); +// Start the timer of the script +console.time('Builder'); +// Synchronously read all snippets and sort them as necessary (case-insensitive) +try { + let snippetFilenames = fs.readdirSync(snippetsPath); + snippetFilenames.sort((a, b) => { + a = a.toLowerCase(); + b = b.toLowerCase(); + if (a < b) return -1; + if (a > b) return 1; + return 0; + }); + // Store the data read from each snippet in the appropriate object + for (let snippet of snippetFilenames) + snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8'); +} catch (err) { + // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`); + process.exit(1); +} +// Load static parts for the README file +try { + startPart = fs.readFileSync(path.join(staticPartsPath, 'README-start.md'), 'utf8'); + endPart = fs.readFileSync(path.join(staticPartsPath, 'README-end.md'), '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 +try { + tagDbData = objectFromPairs( + fs + .readFileSync('tag_database', 'utf8') + .split('\n') + .slice(0, -1) + .map(v => v.split(':').slice(0, 2)) + ); +} catch (err) { + // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`); + process.exit(1); +} +// Create the output for the README file +try { + // Add the start static part + output += `${startPart + '\n'}`; + // Loop over tags and snippets to create the table of contents + let uncategorizedOutput = ''; + for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))] + .filter(v => v) + .sort((a, b) => a.localeCompare(b))) { + if (capitalize(tag, true) == 'Uncategorized') { + uncategorizedOutput += `### _${capitalize( + tag, + true + )}_\n\n
\nView contents\n\n`; + for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) + uncategorizedOutput += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`; + uncategorizedOutput += '\n
\n\n'; + } else { + output += `### ${capitalize(tag, true)}\n\n
\nView contents\n\n`; + for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) + output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`; + output += '\n
\n\n'; + } + } + output += uncategorizedOutput; + uncategorizedOutput = ''; + // Loop over tags and snippets to create the list of snippets + for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))] + .filter(v => v) + .sort((a, b) => a.localeCompare(b))) { + if (capitalize(tag, true) == 'Uncategorized') { + uncategorizedOutput += `## _${capitalize(tag, true)}_\n`; + for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) + uncategorizedOutput += `\n${snippets[taggedSnippet[0] + '.md'] + + '\n
[⬆ back to top](#table-of-contents)\n\n'}`; + } else { + output += `## ${capitalize(tag, true)}\n`; + for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) { + let data = snippets[taggedSnippet[0] + '.md']; + data = + data.slice(0, data.lastIndexOf('```js')) + + '
\nExamples\n\n' + + data.slice(data.lastIndexOf('```js'), data.lastIndexOf('```')) + + data.slice(data.lastIndexOf('```')) + + '\n
\n'; + output += `\n${data + '\n
[⬆ Back to top](#table-of-contents)\n\n'}`; + } + } + } + output += uncategorizedOutput; + // Add the ending static part + output += `\n${endPart + '\n'}`; + // Write to the README file + fs.writeFileSync('README.md', output); +} catch (err) { + // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During README generation: ${err}`); + process.exit(1); +} +// Log a success message +console.log(`${chalk.green('SUCCESS!')} README file generated!`); +// Log the time taken +console.timeEnd('Builder'); diff --git a/scripts/lint-script.js b/scripts/lint.js similarity index 95% rename from scripts/lint-script.js rename to scripts/lint.js index ba66f36a8..833ef3dbd 100644 --- a/scripts/lint-script.js +++ b/scripts/lint.js @@ -18,7 +18,8 @@ const codeRE = /```\s*js([\s\S]*?)```/g; console.time('Linter'); try { - const snippets = fs.readdirSync(SNIPPETS_PATH) + const snippets = fs + .readdirSync(SNIPPETS_PATH) .sort((a, b) => a.toLowerCase() - b.toLowerCase()) // turn it into an object so we can add data to it to be used in a different scope .map(name => ({ name })); @@ -46,7 +47,8 @@ try { }); } - const cmd = `semistandard "${TEMP_PATH}" --fix & ` + + const cmd = + `semistandard "${TEMP_PATH}" --fix & ` + `prettier "${TEMP_PATH}/*.js" --single-quote --print-width=100 --write`; cp.exec(cmd, {}, (err, stdout, stderr) => { diff --git a/scripts/tag-script.js b/scripts/tag.js similarity index 51% rename from scripts/tag-script.js rename to scripts/tag.js index b49c6564a..2c8ed9b0a 100644 --- a/scripts/tag-script.js +++ b/scripts/tag.js @@ -3,14 +3,20 @@ Run using `npm run tagger`. */ // Load modules -const fs = require('fs-extra'), path = require('path'), chalk = require('chalk'); +const fs = require('fs-extra'), + path = require('path'), + chalk = require('chalk'); // Set variables for paths const snippetsPath = './snippets'; // Set variables for script -let snippets = {}, output = '', tagDbData = {}, missingTags = 0, tagDbStats = {}; +let snippets = {}, + output = '', + tagDbData = {}, + missingTags = 0, + tagDbStats = {}; // Load helper functions (these are from existing snippets in 30 seconds of code!) -const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {}); -const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0); +const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {}); +const countOccurrences = (arr, value) => arr.reduce((a, v) => (v === value ? a + 1 : a + 0), 0); // Start the timer of the script console.time('Tagger'); // Synchronously read all snippets and sort them as necessary (case-insensitive) @@ -24,43 +30,60 @@ try { return 0; }); // Store the data read from each snippet in the appropriate object - for(let snippet of snippetFilenames) snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8'); -} -catch (err){ // Handle errors (hopefully not!) + for (let snippet of snippetFilenames) + snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8'); +} catch (err) { + // Handle errors (hopefully not!) console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`); process.exit(1); } // Load tag data from the database try { - tagDbData = objectFromPairs(fs.readFileSync('tag_database','utf8').split('\n').slice(0,-1).map(v => v.split(':').slice(0,2))); - tagDbStats = Object.entries(tagDbData).sort((a,b) => a[1].localeCompare(b[1])).reduce((acc, val) => {acc.hasOwnProperty(val[1]) ? acc[val[1]]++ : acc[val[1]] = 1; return acc;}, {}); -} -catch (err){ // Handle errors (hopefully not!) + tagDbData = objectFromPairs( + fs + .readFileSync('tag_database', 'utf8') + .split('\n') + .slice(0, -1) + .map(v => v.split(':').slice(0, 2)) + ); + tagDbStats = Object.entries(tagDbData) + .sort((a, b) => a[1].localeCompare(b[1])) + .reduce((acc, val) => { + acc.hasOwnProperty(val[1]) ? acc[val[1]]++ : (acc[val[1]] = 1); + return acc; + }, {}); +} catch (err) { + // Handle errors (hopefully not!) console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`); process.exit(1); } // Update the listing of snippets in tag_database and log the statistics, along with missing scripts try { - for(let snippet of Object.entries(snippets)) - if(tagDbData.hasOwnProperty(snippet[0].slice(0,-3)) && tagDbData[snippet[0].slice(0,-3)].trim()) - output += `${snippet[0].slice(0,-3)}:${tagDbData[snippet[0].slice(0,-3)].trim()}\n`; + for (let snippet of Object.entries(snippets)) + if ( + tagDbData.hasOwnProperty(snippet[0].slice(0, -3)) && + tagDbData[snippet[0].slice(0, -3)].trim() + ) + output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)].trim()}\n`; else { - output += `${snippet[0].slice(0,-3)}:uncategorized\n`; + output += `${snippet[0].slice(0, -3)}:uncategorized\n`; missingTags++; - console.log(`${chalk.yellow('Tagged uncategorized:')} ${snippet[0].slice(0,-3)}`); + console.log(`${chalk.yellow('Tagged uncategorized:')} ${snippet[0].slice(0, -3)}`); } // Write to tag_database fs.writeFileSync('tag_database', output); -} -catch (err){ // Handle errors (hopefully not!) +} catch (err) { + // Handle errors (hopefully not!) console.log(`${chalk.red('ERROR!')} During tag_database generation: ${err}`); process.exit(1); } // Log statistics for the tag_database file -console.log(`\n${chalk.bgWhite(chalk.black('=== TAG STATS ==='))}`) -for(let tagData of Object.entries(tagDbStats).filter(v => v[0] !== 'undefined')) +console.log(`\n${chalk.bgWhite(chalk.black('=== TAG STATS ==='))}`); +for (let tagData of Object.entries(tagDbStats).filter(v => v[0] !== 'undefined')) console.log(`${chalk.green(tagData[0])}: ${tagData[1]} snippets`); -console.log(`${chalk.blue('New untagged snippets (will be tagged as \'uncategorized\'):')} ${missingTags}\n`); +console.log( + `${chalk.blue("New untagged snippets (will be tagged as 'uncategorized'):")} ${missingTags}\n` +); // Log a success message console.log(`${chalk.green('SUCCESS!')} tag_database file updated!`); // Log the time taken diff --git a/scripts/tdd-script.js b/scripts/tdd-script.js deleted file mode 100644 index 335ee961f..000000000 --- a/scripts/tdd-script.js +++ /dev/null @@ -1,41 +0,0 @@ -const fs = require('fs-extra'); - -const SNIPPETS_PATH = './snippets'; -const TEST_PATH = './test'; - -const snippetFiles = fs.readdirSync(SNIPPETS_PATH, 'utf8') - .map(fileName => fileName.slice(0, -3)); - -fs.removeSync(TEST_PATH); - -snippetFiles - .map(fileName => { fs.ensureDirSync(`${TEST_PATH}/${fileName}`); return fileName}) - .map(fileName => { - - const fileData = fs.readFileSync(`${SNIPPETS_PATH}/${fileName}.md`, 'utf8'); - const fileCode = fileData.slice( fileData.indexOf('```js'), fileData.lastIndexOf('```') + 3 ); - const blockMarkers = fileCode.split('\n').map((line, lineIndex) => line.slice(0, 3) === '```' ? lineIndex : '//CLEAR//').filter(x => !(x === '//CLEAR//')) - const fileFunction = fileCode.split('\n').map(line => line.trim()).filter((_, i) => blockMarkers[0] < i && i < blockMarkers[1]); - const fileExample = fileCode.split('\n').map(line => line.trim()).filter((_, i) => blockMarkers[2] < i && i < blockMarkers[3]); - - const exportFile = `module.exports = ${fileFunction.join('\n').slice(17)}`; - const exportTest = [ - `const test = require('tape');`, - `const ${fileName} = require('./${fileName}.js');`, - `test('Testing ${fileName}', (t) => {`, - `//For more information on all the methods supported by tape\n//Please go to https://github.com/substack/tape`, - `//t.deepEqual(${fileName}(args..), 'Expected');`, - `//t.equal(${fileName}(args..), 'Expected');`, - `//t.false(${fileName}(args..), 'Expected');`, - `//t.true(${fileName}(args..), 'Expected');`, - `//t.throws(${fileName}(args..), 'Expected');`, - `t.end();`, - `});` - ].join('\n') - - - fs.writeFileSync(`${TEST_PATH}/${fileName}/${fileName}.js`, exportFile); - fs.writeFileSync(`${TEST_PATH}/${fileName}/${fileName}.test.js`, exportTest); - - return fileName; - }) diff --git a/scripts/tdd.js b/scripts/tdd.js new file mode 100644 index 000000000..d67396d7b --- /dev/null +++ b/scripts/tdd.js @@ -0,0 +1,50 @@ +const fs = require('fs-extra'); + +const SNIPPETS_PATH = './snippets'; +const TEST_PATH = './test'; + +const snippetFiles = fs.readdirSync(SNIPPETS_PATH, 'utf8').map(fileName => fileName.slice(0, -3)); + +fs.removeSync(TEST_PATH); + +snippetFiles + .map(fileName => { + fs.ensureDirSync(`${TEST_PATH}/${fileName}`); + return fileName; + }) + .map(fileName => { + const fileData = fs.readFileSync(`${SNIPPETS_PATH}/${fileName}.md`, 'utf8'); + const fileCode = fileData.slice(fileData.indexOf('```js'), fileData.lastIndexOf('```') + 3); + const blockMarkers = fileCode + .split('\n') + .map((line, lineIndex) => (line.slice(0, 3) === '```' ? lineIndex : '//CLEAR//')) + .filter(x => !(x === '//CLEAR//')); + const fileFunction = fileCode + .split('\n') + .map(line => line.trim()) + .filter((_, i) => blockMarkers[0] < i && i < blockMarkers[1]); + const fileExample = fileCode + .split('\n') + .map(line => line.trim()) + .filter((_, i) => blockMarkers[2] < i && i < blockMarkers[3]); + + const exportFile = `module.exports = ${fileFunction.join('\n').slice(17)}`; + const exportTest = [ + `const test = require('tape');`, + `const ${fileName} = require('./${fileName}.js');`, + `test('Testing ${fileName}', (t) => {`, + `//For more information on all the methods supported by tape\n//Please go to https://github.com/substack/tape`, + `//t.deepEqual(${fileName}(args..), 'Expected');`, + `//t.equal(${fileName}(args..), 'Expected');`, + `//t.false(${fileName}(args..), 'Expected');`, + `//t.true(${fileName}(args..), 'Expected');`, + `//t.throws(${fileName}(args..), 'Expected');`, + `t.end();`, + `});` + ].join('\n'); + + fs.writeFileSync(`${TEST_PATH}/${fileName}/${fileName}.js`, exportFile); + fs.writeFileSync(`${TEST_PATH}/${fileName}/${fileName}.test.js`, exportTest); + + return fileName; + }); diff --git a/scripts/web-script.js b/scripts/web-script.js deleted file mode 100644 index 1801547fc..000000000 --- a/scripts/web-script.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - 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; -// 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 = {}; -// Load helper functions (these are from existing snippets in 30 seconds of code!) -const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {}); -const capitalize = (str, lowerRest = false) => str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1)); -// Start the timer of the script -console.time('Builder'); -// Synchronously read all snippets and sort them as necessary (case-insensitive) -try { - let snippetFilenames = fs.readdirSync(snippetsPath); - snippetFilenames.sort((a, b) => { - a = a.toLowerCase(); - b = b.toLowerCase(); - if (a < b) return -1; - if (a > b) return 1; - return 0; - }); - // Store the data read from each snippet in the appropriate object - for(let snippet of snippetFilenames) snippets[snippet] = fs.readFileSync(path.join(snippetsPath,snippet),'utf8'); -} -catch (err){ // Handle errors (hopefully not!) - console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`); - process.exit(1); -} -// 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 -try { - tagDbData = objectFromPairs(fs.readFileSync('tag_database','utf8').split('\n').slice(0,-1).map(v => v.split(':').slice(0,2))); -} -catch (err){ // Handle errors (hopefully not!) - console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`); - process.exit(1); -} -// Create the output for the index.html file -try { - // Add the start static part - output += `${startPart+'\n'}`; - let uncategorizedOutput = ''; - // Loop over tags and snippets to create the table of contents - for(let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))].filter(v => v).sort((a,b) => a.localeCompare(b))){ - if(capitalize(tag, true)=='Uncategorized') { - uncategorizedOutput +=`

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

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

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

/g,'').replace(/<\/p>/g,'').replace(/`+md.render(`${capitalize(tag, true)}\n`).replace(/

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

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

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

/g,'

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

/g,'

') + '

'; - } else { - output +=md.render(`## ${capitalize(tag, true)}\n`).replace(/

/g,'

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

/g,'

') + '

'; - } - } - output += uncategorizedOutput; - // Add the ending static part - output += `\n${endPart+'\n'}`; - // 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('Builder'); diff --git a/scripts/web.js b/scripts/web.js new file mode 100644 index 000000000..ac72efc54 --- /dev/null +++ b/scripts/web.js @@ -0,0 +1,192 @@ +/* + 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; +// 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 = {}; +// Load helper functions (these are from existing snippets in 30 seconds of code!) +const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {}); +const capitalize = (str, lowerRest = false) => + str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1)); +// Start the timer of the script +console.time('Builder'); +// Synchronously read all snippets and sort them as necessary (case-insensitive) +try { + let snippetFilenames = fs.readdirSync(snippetsPath); + snippetFilenames.sort((a, b) => { + a = a.toLowerCase(); + b = b.toLowerCase(); + if (a < b) return -1; + if (a > b) return 1; + return 0; + }); + // Store the data read from each snippet in the appropriate object + for (let snippet of snippetFilenames) + snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8'); +} catch (err) { + // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`); + process.exit(1); +} +// 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 +try { + tagDbData = objectFromPairs( + fs + .readFileSync('tag_database', 'utf8') + .split('\n') + .slice(0, -1) + .map(v => v.split(':').slice(0, 2)) + ); +} catch (err) { + // Handle errors (hopefully not!) + console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`); + process.exit(1); +} +// Create the output for the index.html file +try { + // Add the start static part + output += `${startPart + '\n'}`; + let uncategorizedOutput = ''; + // Loop over tags and snippets to create the table of contents + for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))] + .filter(v => v) + .sort((a, b) => a.localeCompare(b))) { + if (capitalize(tag, true) == 'Uncategorized') { + uncategorizedOutput += + `

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

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

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

/g, '') + .replace(/<\/p>/g, '') + .replace(/` + + md + .render(`${capitalize(tag, true)}\n`) + .replace(/

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

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

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

/g, '

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

/g, '

') + + '

'; + } else { + output += md + .render(`## ${capitalize(tag, true)}\n`) + .replace(/

/g, '

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

/g, '

') + + '

'; + } + } + output += uncategorizedOutput; + // Add the ending static part + output += `\n${endPart + '\n'}`; + // 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('Builder');