Scripts linted

This commit is contained in:
Angelos Chalaris
2018-08-03 10:49:29 +03:00
parent 37da7ac424
commit d9593cdce5
13 changed files with 525 additions and 233 deletions

View File

@ -14,45 +14,73 @@ let snippetsArchiveData = require('../snippet_data/snippetsArchive.json');
const OUTPUT_PATH = './snippet_data';
console.time('Analyzer');
// Read data
let snippetTokens = {data: snippetsData.data.map(snippet => {
let tokens = prism.tokenize(snippet.attributes.codeBlocks[0], prism.languages.javascript, 'javascript');
return {
id: snippet.id,
type: 'snippetAnalysis',
attributes: {
codeLength: snippet.attributes.codeBlocks[0].trim().length,
tokenCount: tokens.length,
functionCount: tokens.filter(t => t.type === 'function').length,
operatorCount: tokens.filter(t => t.type === 'operator').length,
keywordCount: tokens.filter(t => t.type === 'keyword').length,
distinctFunctionCount: [...new Set(tokens.filter(t => t.type === 'function').map(t => t.content))].length
},
meta: {
hash: snippet.meta.hash
}
};
}), meta: { specification: "http://jsonapi.org/format/"}};
let snippetArchiveTokens = {data: snippetsArchiveData.data.map(snippet => {
let tokens = prism.tokenize(snippet.attributes.codeBlocks[0], prism.languages.javascript, 'javascript');
return {
id: snippet.id,
type: 'snippetAnalysis',
attributes: {
codeLength: snippet.attributes.codeBlocks[0].trim().length,
tokenCount: tokens.length,
functionCount: tokens.filter(t => t.type === 'function').length,
operatorCount: tokens.filter(t => t.type === 'operator').length,
keywordCount: tokens.filter(t => t.type === 'keyword').length,
distinctFunctionCount: [...new Set(tokens.filter(t => t.type === 'function').map(t => t.content))].length
},
meta: {
hash: snippet.meta.hash
}
};
}), meta: { specification: "http://jsonapi.org/format/"}};
let snippetTokens = {
data: snippetsData.data.map(snippet => {
let tokens = prism.tokenize(
snippet.attributes.codeBlocks[0],
prism.languages.javascript,
'javascript'
);
return {
id: snippet.id,
type: 'snippetAnalysis',
attributes: {
codeLength: snippet.attributes.codeBlocks[0].trim().length,
tokenCount: tokens.length,
functionCount: tokens.filter(t => t.type === 'function').length,
operatorCount: tokens.filter(t => t.type === 'operator').length,
keywordCount: tokens.filter(t => t.type === 'keyword').length,
distinctFunctionCount: [
...new Set(tokens.filter(t => t.type === 'function').map(t => t.content))
].length
},
meta: {
hash: snippet.meta.hash
}
};
}),
meta: { specification: 'http://jsonapi.org/format/' }
};
let snippetArchiveTokens = {
data: snippetsArchiveData.data.map(snippet => {
let tokens = prism.tokenize(
snippet.attributes.codeBlocks[0],
prism.languages.javascript,
'javascript'
);
return {
id: snippet.id,
type: 'snippetAnalysis',
attributes: {
codeLength: snippet.attributes.codeBlocks[0].trim().length,
tokenCount: tokens.length,
functionCount: tokens.filter(t => t.type === 'function').length,
operatorCount: tokens.filter(t => t.type === 'operator').length,
keywordCount: tokens.filter(t => t.type === 'keyword').length,
distinctFunctionCount: [
...new Set(tokens.filter(t => t.type === 'function').map(t => t.content))
].length
},
meta: {
hash: snippet.meta.hash
}
};
}),
meta: { specification: 'http://jsonapi.org/format/' }
};
// Write data
fs.writeFileSync(path.join(OUTPUT_PATH, 'snippetAnalytics.json'), JSON.stringify(snippetTokens, null, 2));
fs.writeFileSync(path.join(OUTPUT_PATH, 'snippetArchiveAnalytics.json'), JSON.stringify(snippetArchiveTokens, null, 2));
fs.writeFileSync(
path.join(OUTPUT_PATH, 'snippetAnalytics.json'),
JSON.stringify(snippetTokens, null, 2)
);
fs.writeFileSync(
path.join(OUTPUT_PATH, 'snippetArchiveAnalytics.json'),
JSON.stringify(snippetArchiveTokens, null, 2)
);
// Display messages and time
console.log(`${chalk.green('SUCCESS!')} snippetAnalyticss.json and snippetArchiveAnalytics.json files generated!`);
console.log(
`${chalk.green(
'SUCCESS!'
)} snippetAnalyticss.json and snippetArchiveAnalytics.json files generated!`
);
console.timeEnd('Analyzer');

View File

@ -12,10 +12,15 @@ const SNIPPETS_PATH = './snippets';
const SNIPPETS_ARCHIVE_PATH = './snippets_archive';
const STATIC_PARTS_PATH = './static-parts';
if (util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) {
console.log(`${chalk.green('NOBUILD')} README build terminated, parent commit is a Travis build!`);
console.log(
`${chalk.green('NOBUILD')} README build terminated, parent commit is a Travis build!`
);
process.exit(0);
}
if (util.isTravisCI() && (process.env['TRAVIS_EVENT_TYPE'] === 'cron' || process.env['TRAVIS_EVENT_TYPE'] === 'api')) {
if (
util.isTravisCI() &&
(process.env['TRAVIS_EVENT_TYPE'] === 'cron' || process.env['TRAVIS_EVENT_TYPE'] === 'api')
) {
console.log(`${chalk.green('ARCHIVE')} Cron job or custom build, building archive README!`);
console.time('Builder');
let snippets = {};
@ -43,8 +48,8 @@ These snippets, while useful and interesting, didn\'t quite make it into the rep
## Table of Contents
`;
for(const snippet of Object.entries(snippets))
output += `* [\`${snippet[0].slice(0,-3)}\`](#${snippet[0].toLowerCase().slice(0,-3)})\n`;
for (const snippet of Object.entries(snippets))
output += `* [\`${snippet[0].slice(0, -3)}\`](#${snippet[0].toLowerCase().slice(0, -3)})\n`;
output += '\n---\n';
for (const snippet of Object.entries(snippets)) {
let data = snippet[1];
@ -58,7 +63,7 @@ These snippets, while useful and interesting, didn\'t quite make it into the rep
}
// Write to the README file of the archive
fs.writeFileSync(path.join(SNIPPETS_ARCHIVE_PATH,'README.md'), output);
fs.writeFileSync(path.join(SNIPPETS_ARCHIVE_PATH, 'README.md'), output);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During README generation for snippets archive: ${err}`);
process.exit(1);
@ -113,7 +118,15 @@ try {
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)))
.sort(
(a, b) =>
util.capitalize(a, true) === 'Uncategorized'
? 1
: util.capitalize(b, true) === 'Uncategorized'
? -1
: a.localeCompare(b)
)
)
];
console.log(tags);
@ -124,11 +137,12 @@ try {
// Loop over tags and snippets to create the table of contents
for (const tag of tags) {
const capitalizedTag = util.capitalize(tag, true);
output += `### ${
EMOJIS[tag] || ''
} ${capitalizedTag}\n\n<details>\n<summary>View contents</summary>\n\n`;
output += `### ${EMOJIS[tag] ||
''} ${capitalizedTag}\n\n<details>\n<summary>View contents</summary>\n\n`;
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()}${taggedSnippet[1].includes('advanced')?'-':''})\n`;
output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()}${
taggedSnippet[1].includes('advanced') ? '-' : ''
})\n`;
}
output += '\n</details>\n\n';
}
@ -140,9 +154,9 @@ try {
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
let data = snippets[taggedSnippet[0] + '.md'];
// Add advanced tag
if(taggedSnippet[1].includes('advanced')) {
if (taggedSnippet[1].includes('advanced')) {
data = data.split(/\r?\n/);
data[0] = data[0] +' ![advanced](/advanced.svg)';
data[0] = data[0] + ' ![advanced](/advanced.svg)';
data = data.join('\n');
}
data =

View File

@ -12,12 +12,18 @@ const SNIPPETS_PATH = './snippets';
const SNIPPETS_ARCHIVE_PATH = './snippets_archive';
const OUTPUT_PATH = './snippet_data';
// Check if running on Travis - only build for cron jobs and custom builds
if(util.isTravisCI() && process.env['TRAVIS_EVENT_TYPE'] !== 'cron' && process.env['TRAVIS_EVENT_TYPE'] !== 'api') {
if (
util.isTravisCI() &&
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
) {
console.log(`${chalk.green('NOBUILD')} snippet extraction terminated, not a cron or api build!`);
process.exit(0);
}
// Read data
let snippets = {}, archivedSnippets = {}, tagDbData = {};
let snippets = {},
archivedSnippets = {},
tagDbData = {};
console.time('Extractor');
snippets = util.readSnippets(SNIPPETS_PATH);
archivedSnippets = util.readSnippets(SNIPPETS_ARCHIVE_PATH);
@ -26,13 +32,15 @@ tagDbData = util.readTags();
let snippetData = {
data: Object.keys(snippets).map(key => {
return {
id: key.slice(0,-3),
id: key.slice(0, -3),
type: 'snippet',
attributes: {
fileName: key,
text: util.getTextualContent(snippets[key]).trim(),
codeBlocks: util.getCodeBlocks(snippets[key]).map(v => v.replace(/```js([\s\S]*?)```/g, '$1').trim()),
tags: tagDbData[key.slice(0,-3)]
codeBlocks: util
.getCodeBlocks(snippets[key])
.map(v => v.replace(/```js([\s\S]*?)```/g, '$1').trim()),
tags: tagDbData[key.slice(0, -3)]
},
meta: {
archived: false,
@ -48,12 +56,14 @@ let snippetData = {
let snippetArchiveData = {
data: Object.keys(archivedSnippets).map(key => {
return {
id: key.slice(0,-3),
id: key.slice(0, -3),
type: 'snippet',
attributes: {
fileName: key,
text: util.getTextualContent(archivedSnippets[key]).trim(),
codeBlocks: util.getCodeBlocks(archivedSnippets[key]).map(v => v.replace(/```js([\s\S]*?)```/g, '$1').trim()),
codeBlocks: util
.getCodeBlocks(archivedSnippets[key])
.map(v => v.replace(/```js([\s\S]*?)```/g, '$1').trim()),
tags: []
},
meta: {
@ -68,7 +78,10 @@ let snippetArchiveData = {
};
// Write files
fs.writeFileSync(path.join(OUTPUT_PATH, 'snippets.json'), JSON.stringify(snippetData, null, 2));
fs.writeFileSync(path.join(OUTPUT_PATH, 'snippetsArchive.json'), JSON.stringify(snippetArchiveData, null, 2));
fs.writeFileSync(
path.join(OUTPUT_PATH, 'snippetsArchive.json'),
JSON.stringify(snippetArchiveData, null, 2)
);
// Display messages and time
console.log(`${chalk.green('SUCCESS!')} snippets.json and snippetsArchive.json files generated!`);
console.timeEnd('Extractor');

View File

@ -10,12 +10,15 @@ const util = require('../util');
const glossaryFiles = util.getFilesInDir('./glossary', false);
try {
const output = glossaryFiles.reduce(
(accumulator, currentFilename) =>
accumulator.toLowerCase().replace(/\.[^/.]+$/, "") + "\n" +
currentFilename.toLowerCase().replace(/\.[^/.]+$/, ""))+'\n';
fs.writeFileSync('glossary/keyword_database', output);
const output =
glossaryFiles.reduce(
(accumulator, currentFilename) =>
accumulator.toLowerCase().replace(/\.[^/.]+$/, '') +
'\n' +
currentFilename.toLowerCase().replace(/\.[^/.]+$/, '')
) + '\n';
fs.writeFileSync('glossary/keyword_database', output);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During glossary keyword_database generation: ${err}`);
console.log(`${chalk.red('ERROR!')} During glossary keyword_database generation: ${err}`);
process.exit(1);
}
}

View File

@ -10,27 +10,34 @@ const util = require('../util');
const glossaryFiles = util.getFilesInDir('./glossary', true, ['keyword_database', 'README.md']);
const fileTitles = [];
const getGlossaryTermMarkdownBlock = (fileName) => {
const getGlossaryTermMarkdownBlock = fileName => {
let fileContent = fs.readFileSync(fileName, 'utf8');
let title = fileContent.match(/###[^\n]*/)[0].replace('### ', '').trim();
let title = fileContent
.match(/###[^\n]*/)[0]
.replace('### ', '')
.trim();
// let description = fileContent.replace(title, '').trim();
fileTitles.push(title);
return fileContent.trim() + "\n";
return fileContent.trim() + '\n';
};
const glossaryFilesContentReducer = (accumulator, currentFilename) => {
// handle first array item
if (accumulator === glossaryFiles[0]) {
return getGlossaryTermMarkdownBlock(accumulator) + "\n" + getGlossaryTermMarkdownBlock(currentFilename);
return (
getGlossaryTermMarkdownBlock(accumulator) +
'\n' +
getGlossaryTermMarkdownBlock(currentFilename)
);
}
return accumulator + "\n" + getGlossaryTermMarkdownBlock(currentFilename);
return accumulator + '\n' + getGlossaryTermMarkdownBlock(currentFilename);
};
const getTermLinkMarkdownBlock = (termTitle) => {
const getTermLinkMarkdownBlock = termTitle => {
let anchor = util.getMarkDownAnchor(termTitle);
return `* [\`${termTitle}\`](#${anchor})` + "\n";
return `* [\`${termTitle}\`](#${anchor})` + '\n';
};
const glossaryTableOfContentsReducer = (accumulator, currentFile) => {
@ -42,14 +49,10 @@ const glossaryTableOfContentsReducer = (accumulator, currentFile) => {
try {
const fileContents = glossaryFiles.reduce(glossaryFilesContentReducer);
const TOC = "## Table of Contents\n\n" + fileTitles.reduce(glossaryTableOfContentsReducer);
const README =
"# 30-seconds-of-code JavaScript Glossary\n\n" +
TOC +
"\n\n" +
fileContents;
fs.writeFileSync('glossary/README.md', README);
const TOC = '## Table of Contents\n\n' + fileTitles.reduce(glossaryTableOfContentsReducer);
const README = '# 30-seconds-of-code JavaScript Glossary\n\n' + TOC + '\n\n' + fileContents;
fs.writeFileSync('glossary/README.md', README);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During glossary README generation: ${err}`);
process.exit(1);

View File

@ -10,7 +10,7 @@ const cp = require('child_process');
const path = require('path');
const chalk = require('chalk');
const util = require('./util');
if(util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) {
if (util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) {
console.log(`${chalk.green('NOBUILD')} Linting terminated, parent commit is a Travis build!`);
process.exit(0);
}

View File

@ -16,34 +16,67 @@ let snippets = util.readSnippets(SNIPPETS_PATH);
const COMMENT_REGEX = /(\/\*[\w\'\s\r\n\*]*\*\/)|(\/\/.*)/g;
locales.forEach(locale => {
const locData = require(path.join('..',LOCALE_PATH,locale));
let existingData = fs.readFileSync(path.join(LOCALE_PATH,locale+'.js'), 'utf8');
const locData = require(path.join('..', LOCALE_PATH, locale));
let existingData = fs.readFileSync(path.join(LOCALE_PATH, locale + '.js'), 'utf8');
let newData = [];
let hashChanges = [];
Object.keys(snippets).forEach(snippet => {
const snippetName = snippet.split('.')[0];
const snippetHash = util.hashData(snippets[snippet]);
if(locData.hasOwnProperty(snippetName)) {
if (locData.hasOwnProperty(snippetName)) {
if (locData[snippetName].hash !== snippetHash) {
existingData = existingData.indexOf(' => '+snippetHash) !== -1 ? existingData : existingData.replace(locData[snippetName].hash, locData[snippetName].hash+' => '+snippetHash);
hashChanges.push({snippetName, oldHash: locData[snippetName].hash.split(' => ')[0], newHash: snippetHash});
existingData =
existingData.indexOf(' => ' + snippetHash) !== -1
? existingData
: existingData.replace(
locData[snippetName].hash,
locData[snippetName].hash + ' => ' + snippetHash
);
hashChanges.push({
snippetName,
oldHash: locData[snippetName].hash.split(' => ')[0],
newHash: snippetHash
});
}
}
else {
} else {
newData.push(`\n'${snippetName}' : {
'description': \`${snippets[snippet].split('```js')[0].replace(/`/g,'\\`')}\`,
'comments': [${(snippets[snippet].match(COMMENT_REGEX) || []).map(v => '`'+v.replace(/`/g,'\\`')+'`')}],
'description': \`${snippets[snippet].split('```js')[0].replace(/`/g, '\\`')}\`,
'comments': [${(snippets[snippet].match(COMMENT_REGEX) || []).map(
v => '`' + v.replace(/`/g, '\\`') + '`'
)}],
'hash': '${snippetHash}'
}`);
}
});
if(!fs.existsSync(path.join(LOCALE_PATH,locale+'.js')) || !existingData.length) existingData = `module.exports = {
if (!fs.existsSync(path.join(LOCALE_PATH, locale + '.js')) || !existingData.length)
existingData = `module.exports = {
'locale': {
'locale': '${locale}'
}};`;
fs.writeFileSync(path.join(LOCALE_PATH,locale+'.js'), newData.length ? `${existingData.trim().slice(0,-2)},${newData.join(',')}};` : existingData);
fs.writeFileSync(path.join(LOCALE_PATH,locale+'_log'), `${new Date()}
fs.writeFileSync(
path.join(LOCALE_PATH, locale + '.js'),
newData.length ? `${existingData.trim().slice(0, -2)},${newData.join(',')}};` : existingData
);
fs.writeFileSync(
path.join(LOCALE_PATH, locale + '_log'),
`${new Date()}
Hash changes: ${hashChanges.length}
${hashChanges.length ? hashChanges.map(v => ('Snippet name:' + v.snippetName +'\n Old hash: ' + v.oldHash + '\n New hash: ' + v.newHash + '\n')).join('\n') : ''}`);
${
hashChanges.length
? hashChanges
.map(
v =>
'Snippet name:' +
v.snippetName +
'\n Old hash: ' +
v.oldHash +
'\n New hash: ' +
v.newHash +
'\n'
)
.join('\n')
: ''
}`
);
});

View File

@ -7,8 +7,14 @@ const cp = require('child_process');
const path = require('path');
const chalk = require('chalk');
const util = require('./util');
if(util.isTravisCI() && process.env['TRAVIS_EVENT_TYPE'] !== 'cron' && process.env['TRAVIS_EVENT_TYPE'] !== 'api') {
console.log(`${chalk.green('NOBUILD')} Module build terminated, not a cron job or a custom build!`);
if (
util.isTravisCI() &&
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
) {
console.log(
`${chalk.green('NOBUILD')} Module build terminated, not a cron job or a custom build!`
);
process.exit(0);
}
// Set variables for paths
@ -32,10 +38,7 @@ try {
let exportStr = 'export default {';
// Read all snippets and store them appropriately
for (const snippet of snippets) {
const snippetData = fs.readFileSync(
path.join(SNIPPETS_PATH, snippet),
'utf8'
);
const snippetData = fs.readFileSync(path.join(SNIPPETS_PATH, snippet), 'utf8');
const snippetName = snippet.replace('.md', '');
// Check if a snippet is Node-only
const isNodeSnippet = tagDatabase

View File

@ -16,7 +16,7 @@ if (!fs.existsSync(DIST)) fs.mkdirSync(DIST);
const es5 = babel({ presets: [['env', { modules: false }]] });
const min = minify({ comments: false });
// Create the bundles
(async() => {
(async () => {
const bundle = await rollup({ input: INPUT_FILE });
const bundleES5 = await rollup({ input: INPUT_FILE, plugins: [es5] });
const bundleMin = await rollup({ input: INPUT_FILE, plugins: [min] });

View File

@ -7,7 +7,7 @@ const fs = require('fs-extra'),
path = require('path'),
chalk = require('chalk');
const util = require('./util');
if(util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) {
if (util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])) {
console.log(`${chalk.green('NOBUILD')} Tagging terminated, parent commit is a Travis build!`);
process.exit(0);
}
@ -28,11 +28,10 @@ console.time('Tagger');
snippets = util.readSnippets(snippetsPath);
// Load tag data from the database
tagDbData = util.readTags();
tagDbStats = Object.entries(tagDbData)
.reduce((acc, val) => {
val[1].forEach(v => acc.hasOwnProperty(v) ? acc[v]++ : (acc[v] = 1));
return acc;
}, {});
tagDbStats = Object.entries(tagDbData).reduce((acc, val) => {
val[1].forEach(v => (acc.hasOwnProperty(v) ? acc[v]++ : (acc[v] = 1)));
return acc;
}, {});
// Update the listing of snippets in tag_database and log the statistics, along with missing scripts
try {
for (let snippet of Object.entries(snippets))
@ -40,7 +39,9 @@ try {
tagDbData.hasOwnProperty(snippet[0].slice(0, -3)) &&
tagDbData[snippet[0].slice(0, -3)].join(',').trim()
)
output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)].join(',').trim()}\n`;
output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)]
.join(',')
.trim()}\n`;
else {
output += `${snippet[0].slice(0, -3)}:uncategorized\n`;
missingTags++;
@ -55,7 +56,9 @@ try {
}
// 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').sort((a,b) => a[0].localeCompare(b[0])))
for (let tagData of Object.entries(tagDbStats)
.filter(v => v[0] !== 'undefined')
.sort((a, b) => a[0].localeCompare(b[0])))
console.log(`${chalk.green(tagData[0])}: ${tagData[1]} snippets`);
console.log(
`${chalk.blue("New untagged snippets (will be tagged as 'uncategorized'):")} ${missingTags}\n`

View File

@ -4,11 +4,16 @@
*/
// Load modules
const fs = require('fs-extra'), path = require('path');
const fs = require('fs-extra'),
path = require('path');
const childProcess = require('child_process');
const chalk = require('chalk');
const util = require('./util');
if(util.isTravisCI() && process.env['TRAVIS_EVENT_TYPE'] !== 'cron' && process.env['TRAVIS_EVENT_TYPE'] !== 'api') {
if (
util.isTravisCI() &&
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
) {
console.log(`${chalk.green('NOBUILD')} Testing terminated, not a cron job or a custom build!`);
process.exit(0);
}
@ -20,8 +25,11 @@ const TEST_PATH = './test';
// Array of snippet names
const snippetFiles = [];
const snippetFilesActive = fs.readdirSync(SNIPPETS_ACTIVE, 'utf8').map(fileName => fileName.slice(0, -3));
const snippetFilesArchive = fs.readdirSync(SNIPPETS_ARCHIVE, 'utf8')
const snippetFilesActive = fs
.readdirSync(SNIPPETS_ACTIVE, 'utf8')
.map(fileName => fileName.slice(0, -3));
const snippetFilesArchive = fs
.readdirSync(SNIPPETS_ARCHIVE, 'utf8')
.filter(fileName => !fileName.includes('README')) // -> Filters out main README.md file in Archieve which isn't a snippet
.map(fileName => fileName.slice(0, -3));
@ -32,15 +40,17 @@ console.time('Tester');
snippetFiles
.map(fileName => {
// Check if fileName for snippet exist in test/ dir, if doesnt create
fs.ensureDirSync(path.join(TEST_PATH,fileName));
fs.ensureDirSync(path.join(TEST_PATH, fileName));
// return fileName for later use
return fileName;
})
.map(fileName => {
const activeOrArchive = snippetFilesActive.includes(fileName) ? SNIPPETS_ACTIVE : SNIPPETS_ARCHIVE;
const activeOrArchive = snippetFilesActive.includes(fileName)
? SNIPPETS_ACTIVE
: SNIPPETS_ARCHIVE;
// Grab snippetData
const fileData = fs.readFileSync(path.join(activeOrArchive,`${fileName}.md`), 'utf8');
const fileData = fs.readFileSync(path.join(activeOrArchive, `${fileName}.md`), 'utf8');
// Grab snippet Code blocks
const fileCode = fileData.slice(fileData.search(/```\s*js/i), fileData.lastIndexOf('```') + 3);
// Split code based on code markers
@ -72,9 +82,9 @@ snippetFiles
].join('\n');
// Write/Update exportFile which is snippetName.js in respective dir
fs.writeFileSync(path.join(TEST_PATH,fileName,`${fileName}.js`), exportFile);
fs.writeFileSync(path.join(TEST_PATH, fileName, `${fileName}.js`), exportFile);
if ( !fs.existsSync(path.join(TEST_PATH,fileName,`${fileName}.test.js`)) ) {
if (!fs.existsSync(path.join(TEST_PATH, fileName, `${fileName}.test.js`))) {
// if snippetName.test.js doesn't exist inrespective dir exportTest
fs.writeFileSync(`${TEST_PATH}/${fileName}/${fileName}.test.js`, exportTest);
}
@ -83,10 +93,9 @@ snippetFiles
return fileName;
});
try {
fs.writeFileSync(path.join(TEST_PATH,'testlog'),`Test log for: ${new Date().toString()}\n`);
fs.writeFileSync(path.join(TEST_PATH, 'testlog'), `Test log for: ${new Date().toString()}\n`);
childProcess.execSync(`npm test`);
}
catch (e) {
fs.appendFileSync(path.join(TEST_PATH,'testlog'));
} catch (e) {
fs.appendFileSync(path.join(TEST_PATH, 'testlog'));
}
console.timeEnd('Tester');

View File

@ -3,8 +3,10 @@ const fs = require('fs-extra'),
chalk = require('chalk'),
crypto = require('crypto');
const getMarkDownAnchor = (paragraphTitle) =>
paragraphTitle.trim().toLowerCase()
const getMarkDownAnchor = paragraphTitle =>
paragraphTitle
.trim()
.toLowerCase()
.replace(/[^\w\- ]+/g, '')
.replace(/\s/g, '-')
.replace(/\-+$/, '');
@ -28,7 +30,7 @@ const getFilesInDir = (directoryPath, withPath, exclude = null) => {
return fileNames;
}, []);
}
return directoryFilenames;
return directoryFilenames;
} catch (err) {
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
@ -66,7 +68,6 @@ const readTags = () => {
return data;
})
);
} catch (err) {
// Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
@ -102,7 +103,11 @@ const capitalize = (str, lowerRest = false) =>
// Checks if current environment is Travis CI
const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
// Creates a hash for a value using the SHA-256 algorithm.
const hashData = val => crypto.createHash('sha256').update(val).digest('hex');
const hashData = val =>
crypto
.createHash('sha256')
.update(val)
.digest('hex');
// Gets the code blocks for a snippet file.
const getCodeBlocks = str => {
const regex = /```[.\S\s]*?```/g;
@ -135,15 +140,15 @@ const getTextualContent = str => {
};
module.exports = {
getMarkDownAnchor,
getFilesInDir,
readSnippets,
readTags,
optimizeNodes,
capitalize,
objectFromPairs,
isTravisCI,
hashData,
shuffle,
getCodeBlocks,
getFilesInDir,
readSnippets,
readTags,
optimizeNodes,
capitalize,
objectFromPairs,
isTravisCI,
hashData,
shuffle,
getCodeBlocks,
getTextualContent
};

View File

@ -19,12 +19,19 @@ const unescapeHTML = str =>
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&#39;': '\'',
'&#39;': "'",
'&quot;': '"'
}[tag] || tag)
);
if(util.isTravisCI() && /^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE']) && process.env['TRAVIS_EVENT_TYPE'] !== 'cron' && process.env['TRAVIS_EVENT_TYPE'] !== 'api') {
console.log(`${chalk.green('NOBUILD')} website build terminated, parent commit is a Travis build!`);
if (
util.isTravisCI() &&
/^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE']) &&
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
) {
console.log(
`${chalk.green('NOBUILD')} website build terminated, parent commit is a Travis build!`
);
process.exit(0);
}
// Compile the mini.css framework and custom CSS styles, using `node-sass`.
@ -35,7 +42,7 @@ sass.render(
outFile: path.join('docs', 'mini.css'),
outputStyle: 'compressed'
},
function (err, result) {
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!`);
@ -54,7 +61,32 @@ const snippetsPath = './snippets',
// Set variables for script
let snippets = {},
archivedSnippets = {},
beginnerSnippetNames = ['everyNth', 'filterNonUnique', 'last', 'maxN', 'minN', 'nthElement', 'offset', 'sample', 'similarity', 'tail', 'currentURL', 'hasClass', 'getMeridiemSuffixOfInteger', 'factorial', 'fibonacci', 'gcd', 'isDivisible', 'isEven', 'isPrime', 'lcm', 'randomIntegerInRange', 'sum', 'reverseString', 'truncateString'],
beginnerSnippetNames = [
'everyNth',
'filterNonUnique',
'last',
'maxN',
'minN',
'nthElement',
'offset',
'sample',
'similarity',
'tail',
'currentURL',
'hasClass',
'getMeridiemSuffixOfInteger',
'factorial',
'fibonacci',
'gcd',
'isDivisible',
'isEven',
'isPrime',
'lcm',
'randomIntegerInRange',
'sum',
'reverseString',
'truncateString'
],
startPart = '',
endPart = '',
output = '',
@ -64,7 +96,6 @@ let snippets = {},
archivedStartPart = '',
archivedEndPart = '',
archivedOutput = '',
indexStaticFile = '',
pagesOutput = [],
tagDbData = {};
@ -74,16 +105,21 @@ console.time('Webber');
snippets = util.readSnippets(snippetsPath);
archivedSnippets = util.readSnippets(archivedSnippetsPath);
// Load static parts for all pages
try {
startPart = fs.readFileSync(path.join(staticPartsPath, 'page-start.html'), 'utf8');
endPart = fs.readFileSync(path.join(staticPartsPath, 'page-end.html'), 'utf8');
beginnerStartPart = fs.readFileSync(path.join(staticPartsPath, 'beginner-page-start.html'), 'utf8');
beginnerStartPart = fs.readFileSync(
path.join(staticPartsPath, 'beginner-page-start.html'),
'utf8'
);
beginnerEndPart = fs.readFileSync(path.join(staticPartsPath, 'beginner-page-end.html'), 'utf8');
archivedStartPart = fs.readFileSync(path.join(staticPartsPath, 'archived-page-start.html'), 'utf8');
archivedStartPart = fs.readFileSync(
path.join(staticPartsPath, 'archived-page-start.html'),
'utf8'
);
archivedEndPart = fs.readFileSync(path.join(staticPartsPath, 'archived-page-end.html'), 'utf8');
indexStaticFile = fs.readFileSync(path.join(staticPartsPath, 'index.html'), 'utf8');
@ -95,7 +131,11 @@ try {
// Load tag data from the database
tagDbData = util.readTags();
// Create the output for the index.html file (only locally or on Travis CRON or custom job)
if(!util.isTravisCI() || (util.isTravisCI() && (process.env['TRAVIS_EVENT_TYPE'] === 'cron' || process.env['TRAVIS_EVENT_TYPE'] === 'api'))) {
if (
!util.isTravisCI() ||
(util.isTravisCI() &&
(process.env['TRAVIS_EVENT_TYPE'] === 'cron' || process.env['TRAVIS_EVENT_TYPE'] === 'api'))
) {
try {
// Shuffle the array of snippets, pick 3
let indexDailyPicks = '';
@ -110,68 +150,123 @@ if(!util.isTravisCI() || (util.isTravisCI() && (process.env['TRAVIS_EVENT_TYPE']
// Generate the html for the picked snippets
for (let snippet of Object.entries(dailyPicks))
indexDailyPicks +=
'<div class="card fluid pick">' +
'<div class="card fluid pick">' +
md
.render(`\n${snippets[snippet[0]]}`)
.replace(/<h3/g, `<h3 id="${snippet[0].toLowerCase()}" class="section double-padded"`)
.replace(/<\/h3>/g, `${snippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''}</h3>`)
.replace(
/<\/h3>/g,
`${snippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''}</h3>`
)
.replace(/<\/h3>/g, '</h3><div class="section double-padded">')
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
.replace(
/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm,
(match, p1) =>
`<pre class="language-js">${Prism.highlight(
unescapeHTML(p1),
Prism.languages.javascript
)}</pre>`
)
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
'<button class="primary clipboard-copy">&#128203;&nbsp;Copy to clipboard</button>' +
'</div></div>';
// Select the first snippet from today's picks
indexDailyPicks = indexDailyPicks.replace('card fluid pick', 'card fluid pick selected');
// Optimize punctuation nodes
indexDailyPicks = util.optimizeNodes(indexDailyPicks, /<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`);
indexDailyPicks = util.optimizeNodes(
indexDailyPicks,
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
);
// Optimize operator nodes
indexDailyPicks = util.optimizeNodes(indexDailyPicks, /<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`);
indexDailyPicks = util.optimizeNodes(
indexDailyPicks,
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
);
// Optimize keyword nodes
indexDailyPicks = util.optimizeNodes(indexDailyPicks, /<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`);
indexDailyPicks = util.optimizeNodes(
indexDailyPicks,
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
);
// Put the daily picks into the page
indexStaticFile = indexStaticFile.replace('$daily-picks', indexDailyPicks);
// Use the Github API to get the needed data
const githubApi = 'api.github.com';
const headers = util.isTravisCI()
? { 'User-Agent': '30-seconds-of-code', 'Authorization': 'token ' + process.env['GH_TOKEN']}
: { 'User-Agent': '30-seconds-of-code'};
? { 'User-Agent': '30-seconds-of-code', Authorization: 'token ' + process.env['GH_TOKEN'] }
: { 'User-Agent': '30-seconds-of-code' };
// Test the API's rate limit (keep for various reasons)
https.get({host: githubApi, path: '/rate_limit?', headers: headers}, res => {
res.on('data', function (chunk) {
https.get({ host: githubApi, path: '/rate_limit?', headers: headers }, res => {
res.on('data', function(chunk) {
console.log(`Remaining requests: ${JSON.parse(chunk).resources.core.remaining}`);
});
});
// Send requests and wait for responses, write to the page
https.get({host: githubApi, path: '/repos/chalarangelo/30-seconds-of-code/commits?per_page=1', headers: headers}, resCommits => {
https.get({host: githubApi, path: '/repos/chalarangelo/30-seconds-of-code/contributors?per_page=1', headers: headers}, resContributors => {
https.get({host: githubApi, path: '/repos/chalarangelo/30-seconds-of-code/stargazers?per_page=1', headers: headers}, resStars => {
let commits = resCommits.headers.link.split('&').slice(-1)[0].replace(/[^\d]/g, ''),
contribs = resContributors.headers.link.split('&').slice(-1)[0].replace(/[^\d]/g, ''),
stars = resStars.headers.link.split('&').slice(-1)[0].replace(/[^\d]/g, '');
indexStaticFile = indexStaticFile.replace(/\$snippet-count/g, Object.keys(snippets).length).replace(/\$commit-count/g, commits).replace(/\$contrib-count/g, contribs).replace(/\$star-count/g, stars);
indexStaticFile = minify(indexStaticFile, {
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
});
// Generate 'index.html' file
fs.writeFileSync(path.join(docsPath, 'index.html'), indexStaticFile);
console.log(`${chalk.green('SUCCESS!')} index.html file generated!`);
});
});
});
https.get(
{
host: githubApi,
path: '/repos/chalarangelo/30-seconds-of-code/commits?per_page=1',
headers: headers
},
resCommits => {
https.get(
{
host: githubApi,
path: '/repos/chalarangelo/30-seconds-of-code/contributors?per_page=1',
headers: headers
},
resContributors => {
https.get(
{
host: githubApi,
path: '/repos/chalarangelo/30-seconds-of-code/stargazers?per_page=1',
headers: headers
},
resStars => {
let commits = resCommits.headers.link
.split('&')
.slice(-1)[0]
.replace(/[^\d]/g, ''),
contribs = resContributors.headers.link
.split('&')
.slice(-1)[0]
.replace(/[^\d]/g, ''),
stars = resStars.headers.link
.split('&')
.slice(-1)[0]
.replace(/[^\d]/g, '');
indexStaticFile = indexStaticFile
.replace(/\$snippet-count/g, Object.keys(snippets).length)
.replace(/\$commit-count/g, commits)
.replace(/\$contrib-count/g, contribs)
.replace(/\$star-count/g, stars);
indexStaticFile = minify(indexStaticFile, {
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
});
// Generate 'index.html' file
fs.writeFileSync(path.join(docsPath, 'index.html'), indexStaticFile);
console.log(`${chalk.green('SUCCESS!')} index.html file generated!`);
}
);
}
);
}
);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During index.html generation: ${err}`);
process.exit(1);
@ -185,13 +280,21 @@ try {
// 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 += '<h3>' +
md
.render(`${util.capitalize(tag, true)}\n`)
.replace(/<p>/g, '')
.replace(/<\/p>/g, '') +
'</h3>';
.sort(
(a, b) =>
util.capitalize(a, true) === 'Uncategorized'
? 1
: util.capitalize(b, true) === 'Uncategorized'
? -1
: a.localeCompare(b)
)) {
output +=
'<h3>' +
md
.render(`${util.capitalize(tag, true)}\n`)
.replace(/<p>/g, '')
.replace(/<\/p>/g, '') +
'</h3>';
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
output += md
.render(`[${taggedSnippet[0]}](./${tag}#${taggedSnippet[0].toLowerCase()})\n`)
@ -200,13 +303,23 @@ try {
.replace(/<a/g, `<a class="sublink-1" tags="${taggedSnippet[1].join(',')}"`);
output += '\n';
}
output += '</nav><main class="col-sm-12 col-md-8 col-lg-9" style="height: 100%;overflow-y: auto; background: #eceef2; padding: 0;">';
output +=
'</nav><main class="col-sm-12 col-md-8 col-lg-9" style="height: 100%;overflow-y: auto; background: #eceef2; padding: 0;">';
output += '<a id="top">&nbsp;</a>';
// 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))) {
let localOutput = output.replace(/\$tag/g, util.capitalize(tag)).replace(new RegExp(`./${tag}#`, 'g'), '#');
.sort(
(a, b) =>
util.capitalize(a, true) === 'Uncategorized'
? 1
: util.capitalize(b, true) === 'Uncategorized'
? -1
: a.localeCompare(b)
)) {
let localOutput = output
.replace(/\$tag/g, util.capitalize(tag))
.replace(new RegExp(`./${tag}#`, 'g'), '#');
localOutput += md
.render(`## ${util.capitalize(tag, true)}\n`)
.replace(/<h2>/g, '<h2 style="text-align:center;">');
@ -215,22 +328,49 @@ try {
'<div class="card fluid">' +
md
.render(`\n${snippets[taggedSnippet[0] + '.md']}`)
.replace(/<h3/g, `<h3 id="${taggedSnippet[0].toLowerCase()}" class="section double-padded"`)
.replace(/<\/h3>/g, `${taggedSnippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''}</h3>`)
.replace(
/<h3/g,
`<h3 id="${taggedSnippet[0].toLowerCase()}" class="section double-padded"`
)
.replace(
/<\/h3>/g,
`${
taggedSnippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''
}</h3>`
)
.replace(/<\/h3>/g, '</h3><div class="section double-padded">')
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
.replace(
/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm,
(match, p1) =>
`<pre class="language-js">${Prism.highlight(
unescapeHTML(p1),
Prism.languages.javascript
)}</pre>`
)
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
'<button class="primary clipboard-copy">&#128203;&nbsp;Copy to clipboard</button>' +
'</div></div>';
// Add the ending static part
localOutput += `\n${endPart + '\n'}`;
// Optimize punctuation nodes
localOutput = util.optimizeNodes(localOutput, /<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`);
localOutput = util.optimizeNodes(
localOutput,
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
);
// Optimize operator nodes
localOutput = util.optimizeNodes(localOutput, /<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`);
localOutput = util.optimizeNodes(
localOutput,
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
);
// Optimize keyword nodes
localOutput = util.optimizeNodes(localOutput, /<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`);
pagesOutput.push({'tag': tag, 'content': localOutput});
localOutput = util.optimizeNodes(
localOutput,
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
);
pagesOutput.push({ tag: tag, content: localOutput });
}
// Minify output
pagesOutput.forEach(page => {
@ -250,7 +390,7 @@ try {
removeStyleLinkTypeAttributes: false,
trimCustomFragments: true
});
fs.writeFileSync(path.join(docsPath, page.tag+'.html'), page.content);
fs.writeFileSync(path.join(docsPath, page.tag + '.html'), page.content);
console.log(`${chalk.green('SUCCESS!')} ${page.tag}.html file generated!`);
});
} catch (err) {
@ -266,7 +406,7 @@ try {
// Filter begginer snippets
const filteredBeginnerSnippets = Object.keys(snippets)
.filter(key => beginnerSnippetNames.map(name => name+'.md').includes(key))
.filter(key => beginnerSnippetNames.map(name => name + '.md').includes(key))
.reduce((obj, key) => {
obj[key] = snippets[key];
return obj;
@ -274,26 +414,47 @@ try {
for (let snippet of Object.entries(filteredBeginnerSnippets))
beginnerOutput +=
'<div class="row">' +
'<div class="col-sm-12 col-md-10 col-lg-8 col-md-offset-1 col-lg-offset-2">' +
'<div class="row">' +
'<div class="col-sm-12 col-md-10 col-lg-8 col-md-offset-1 col-lg-offset-2">' +
'<div class="card fluid">' +
md
.render(`\n${snippets[snippet[0]]}`)
.replace(/<h3/g, `<h3 id="${snippet[0].toLowerCase()}" class="section double-padded"`)
.replace(/<\/h3>/g, `${snippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''}</h3>`)
.replace(
/<\/h3>/g,
`${snippet[1].includes('advanced') ? '<mark class="tag">advanced</mark>' : ''}</h3>`
)
.replace(/<\/h3>/g, '</h3><div class="section double-padded">')
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
.replace(
/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm,
(match, p1) =>
`<pre class="language-js">${Prism.highlight(
unescapeHTML(p1),
Prism.languages.javascript
)}</pre>`
)
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
'<button class="primary clipboard-copy">&#128203;&nbsp;Copy to clipboard</button>' +
'</div></div></div></div>';
// Optimize punctuation nodes
beginnerOutput = util.optimizeNodes(beginnerOutput, /<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`);
// Optimize operator nodes
beginnerOutput = util.optimizeNodes(beginnerOutput, /<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`);
// Optimize keyword nodes
beginnerOutput = util.optimizeNodes(beginnerOutput, /<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`);
// Optimize punctuation nodes
beginnerOutput = util.optimizeNodes(
beginnerOutput,
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
);
// Optimize operator nodes
beginnerOutput = util.optimizeNodes(
beginnerOutput,
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
);
// Optimize keyword nodes
beginnerOutput = util.optimizeNodes(
beginnerOutput,
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
);
beginnerOutput += `${beginnerEndPart}`;
@ -316,7 +477,6 @@ try {
});
fs.writeFileSync(path.join(docsPath, 'beginner.html'), minifiedBeginnerOutput);
console.log(`${chalk.green('SUCCESS!')} beginner.html file generated!`);
} catch (err) {
console.log(`${chalk.red('ERROR!')} During beginner.html generation: ${err}`);
process.exit(1);
@ -334,32 +494,51 @@ try {
.filter(key => !excludeFiles.includes(key))
.reduce((obj, key) => {
obj[key] = archivedSnippets[key];
return obj;
}, {});
return obj;
}, {});
// Generate archived snippets from md files
for (let snippet of Object.entries(filteredArchivedSnippets))
archivedOutput +=
'<div class="row">' +
'<div class="col-sm-12 col-md-10 col-lg-8 col-md-offset-1 col-lg-offset-2">' +
'<div class="row">' +
'<div class="col-sm-12 col-md-10 col-lg-8 col-md-offset-1 col-lg-offset-2">' +
'<div class="card fluid">' +
md
.render(`\n${filteredArchivedSnippets[snippet[0]]}`)
.replace(/<h3/g, `<h3 id="${snippet[0].toLowerCase()}" class="section double-padded"`)
.replace(/<\/h3>/g, '</h3><div class="section double-padded">')
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
.replace(
/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm,
(match, p1) =>
`<pre class="language-js">${Prism.highlight(
unescapeHTML(p1),
Prism.languages.javascript
)}</pre>`
)
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
'<button class="primary clipboard-copy">&#128203;&nbsp;Copy to clipboard</button>' +
'</div></div></div></div>';
// Optimize punctuation nodes
archivedOutput = util.optimizeNodes(archivedOutput, /<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`);
// Optimize operator nodes
archivedOutput = util.optimizeNodes(archivedOutput, /<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`);
// Optimize keyword nodes
archivedOutput = util.optimizeNodes(archivedOutput, /<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm, (match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`);
// Optimize punctuation nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
);
// Optimize operator nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
);
// Optimize keyword nodes
archivedOutput = util.optimizeNodes(
archivedOutput,
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
);
archivedOutput += `${archivedEndPart}`;
archivedOutput += `${archivedEndPart}`;
// Generate and minify 'archive.html' file
const minifiedArchivedOutput = minify(archivedOutput, {
@ -381,7 +560,6 @@ try {
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);