json-timeline
Version:
Generate Interactive Timelines stored in JSON Advents with Tags.
267 lines (237 loc) • 8.84 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: json-timeline.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: json-timeline.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>#!/usr/bin/env node
/**
* @file json-timeline
* @module json-timeline
* @description CLI for generating Timelines
* @param {string} adventsPath Path to Advents Directory
* @param {string} outputPath Path to Output Directory
* @param {string} flags Flags: v = verbose, f = force
*/
const path = require('path');
const fs = require('fs');
const loadAdvents = require('./functions/loadAdvents');
const sortAdvents = require('./functions/sortAdvents');
const groupAdvents = require('./functions/groupAdvents');
/**
* @constant
* @type {Object}
* @name FLAGS
* @description Boolean flags for CLI Argument flags
*/
const FLAGS = {
VERBOSE: false,
FORCE: false
};
(function main() {
try {
const [adventsInput, outputInput] = handleArguments(process.argv.slice(2));
vLog(`json-timeline initiated with options { verbose: ${FLAGS.VERBOSE}, force: ${FLAGS.FORCE} }`);
const adventsPath = checkAdventsDirectory(adventsInput);
const adventsContent = processAdvents(adventsPath);
const outputPath = checkOutputDirectory(outputInput);
writeViewFiles(outputPath);
writeAdvents(`${outputPath}/advents.js`, adventsContent);
vLog('json-timeline finished');
} catch (error) {
vLog(error.message, { level: 'ERROR', verbose: true });
process.exit(1);
}
})();
/**
* @function
* @name handleArguments
* @description Handles CLI Arguments for Paths and Flags
* @param {string[]} args [advents, output, flags] CLI arguments
* @returns {string[]} Advents and Output Paths
* @throws An Error if advents or output are undefined
*/
function handleArguments([advents, output, flags]) {
if (advents === undefined || output === undefined) {
throw new Error('Usage: json-timeline path/to/advents/ path/to/output/ [vf]');
}
FLAGS.VERBOSE = flags !== undefined && flags.includes('v');
FLAGS.FORCE = flags !== undefined && flags.includes('f');
return [path.resolve(advents), path.resolve(output)];
}
/**
* @function
* @name checkAdventsDirectory
* @description Check if the Advents Input Path is an Existing Directory
* @param {string} adventsPath Advents Input Path
* @returns {string} Advents Path
* @throws An Error if the Advents Input Path is not an Existing Directory
*/
function checkAdventsDirectory(adventsPath) {
vLog(`Checking Advents Directory: "${adventsPath}"`);
if (fs.existsSync(adventsPath)) {
if (fs.lstatSync(adventsPath).isDirectory()) {
vLog(`Advents Directory "${adventsPath}" already exists`);
} else {
throw new Error(`Advents Path "${adventsPath}" is not a directory`);
}
} else {
throw new Error(`Advents Path "${adventsPath}" does not exist`);
}
return adventsPath;
}
/**
* @function
* @name processAdvents
* @description Process and Return Advents from Advents Directory
* @param {string} adventsPath Advents Path
* @returns {string} advents.js File Contents
* @throws An Error if failed to load Advents
*/
function processAdvents(adventsPath) {
vLog(`Processing Advents from "${adventsPath}"`);
const { advents, tags } = loadAdvents(adventsPath);
const sortedAdvents = sortAdvents(advents);
const groupedAdvents = groupAdvents(sortedAdvents);
return (
`export const advents=${str(groupedAdvents)};` +
`export const tags=new Map(${str([...tags.entries()])});`
);
}
/**
* @function
* @name str
* @description Wrapper for consistent JSON.stringify
* @param {*} input Input Argument
* @returns {string} Stringified Input
*/
function str(input) {
return JSON.stringify(input);
}
/**
* @function
* @name checkAdventsDirectory
* @description Check and Make a Directory of the Output Input Path
* @param {string} outputPath Output Input Path
* @returns {string} Output Path
* @throws An Error if the Output Input Path Exists but is not a Directory
*/
function checkOutputDirectory(outputPath) {
vLog(`Checking Output Directory: "${outputPath}"`);
if (fs.existsSync(outputPath)) {
if (fs.lstatSync(outputPath).isDirectory()) {
vLog(`Output Directory "${outputPath}" already exists`);
} else {
throw new Error(`Output Path "${outputPath}" is not a directory`);
}
} else {
fs.mkdirSync(outputPath);
vLog(`Created Output Directory "${outputPath}"`);
}
return outputPath;
}
/**
* @function
* @name writeViewFiles
* @description Write files in view/ to Output Directory, overwriting if the
* force flag is true
* @param {string} outputPath Output Path
* @throws An Error if an Output Destination File Path is not a file
*/
function writeViewFiles(outputPath) {
vLog(`Writing View Files to "${outputPath}"`);
const viewsDirectory = path.resolve(__dirname, '../views/');
for (const file of fs.readdirSync(viewsDirectory)) {
const sourcePath = `${viewsDirectory}/${file}`;
const destPath = `${outputPath}/${file}`;
if (fs.existsSync(destPath)) {
if (fs.lstatSync(destPath).isFile()) {
if (FLAGS.FORCE) {
copyFile(sourcePath, destPath);
vLog(`Overwritten file "${destPath}"`);
} else {
vLog(`File "${destPath}" already exists`);
}
} else {
throw new Error(`Output Path "${destPath}" is not a file`);
}
} else {
copyFile(sourcePath, destPath);
vLog(`Created file "${destPath}"`);
}
}
}
/**
* @function
* @name copyFile
* @description Copies Source File to Destination File
* @param {string} sourcePath Path to Source File
* @param {string} destPath Path to Destination File
*/
function copyFile(sourcePath, destPath) {
fs.createReadStream(sourcePath).pipe(fs.createWriteStream(destPath));
}
/**
* @function
* @name writeAdvents
* @description Write advents.js content to Destination File
* @param {string} destPath Destination Path
* @param {string} content Content to write to Destination File
* @throws An Error if the Destination Path is not a file
*/
function writeAdvents(destPath, content) {
vLog(`Writing Advents to "${destPath}"`);
if (fs.existsSync(destPath)) {
if (fs.lstatSync(destPath).isFile()) {
fs.writeFileSync(destPath, content);
vLog(`Overwritten file "${destPath}"`);
} else {
throw new Error(`Output Path "${destPath}" is not a file`);
}
} else {
fs.writeFileSync(destPath, content);
vLog(`Created file "${destPath}"`);
}
}
/**
* @function
* @name vLog
* @description Log a message with Level based on Verbose
* @param {string} message Message to Log
* @param {Object} opts Options for Level and Verbose
*/
function vLog(message, opts) {
const options = {
level: 'INFO',
verbose: FLAGS.VERBOSE,
...opts
};
options.verbose && console.log(`[${options.level}]: ${message}`);
}
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-advents.html">advents</a></li><li><a href="module-compareDates.html">compareDates</a></li><li><a href="module-groupAdvents.html">groupAdvents</a></li><li><a href="module-index.html">index</a></li><li><a href="module-isType.html">isType</a></li><li><a href="module-json-timeline.html">json-timeline</a></li><li><a href="module-loadAdvents.html">loadAdvents</a></li><li><a href="module-renderAdvents.html">renderAdvents</a></li><li><a href="module-schemas.html">schemas</a></li><li><a href="module-sortAdvents.html">sortAdvents</a></li><li><a href="module-validateSchema.html">validateSchema</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Mon Dec 14 2020 23:14:56 GMT-0500 (Eastern Standard Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>