Last active
March 19, 2020 20:00
-
-
Save manavm1990/3fd932151def3a5a3fb754ccaa291783 to your computer and use it in GitHub Desktop.
Misc. data transformation utility functions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { promises as fs } from "fs"; | |
import { dirname, join } from "path"; | |
import { fileURLToPath } from "url"; | |
// (https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194) | |
const __dirname = dirname(fileURLToPath(import.meta.url)); | |
/** | |
* Create a 'data object' based on JSON files. | |
* @param keys | |
* @param JSONDir | |
* @return {Promise} The πs will be the names of the files in the given directory ππ½ and values will be the JSON data, of course π. | |
* @throws Will throw error if cannot read in all data | |
*/ | |
function readDataFromJSONFiles(keys, JSONDir) { | |
return ( | |
Promise.all( | |
keys | |
// Strip keys from full filenames | |
.map(key => key.substring(0, key.indexOf("."))) | |
// Create data object by asynchronously reading the JSON data in each file. | |
.map(async key => ({ | |
[key]: JSON.parse(await fs.readFile(`./${JSONDir}/${key}.json`)) | |
})) | |
) | |
/** | |
* 'Promise.all' will have an Array from 'map' ππ½. | |
* Each element will be a separate object. | |
* From this, we 'combine' that into the data object that we need. | |
*/ | |
.then(fileContents => | |
fileContents.reduce( | |
(accumulator, data) => ({ ...accumulator, ...data }), | |
{} | |
) | |
) | |
.catch(error => { | |
throw error; | |
}) | |
); | |
} | |
/** | |
* Filters data by removing keys that have values that don't include some string. | |
* @param {Object} o | |
* @param {Object} o.data | |
* @param {string} o.key | |
* @param {string} o.str | |
*/ | |
export function filterByStringInclusionCondition({ data, key, str } = {}) { | |
return data.filter(entry => entry[key].includes(str)); | |
} | |
/** | |
* @param {string} dir - name of directory containing the JSON data. | |
* @return {Promise|String} | |
*/ | |
export async function loadJSON(dir = "JSON") { | |
let keys; | |
try { | |
keys = await fs.readdir(join(__dirname, dir)); | |
} catch (error) { | |
console.error(`Error reading directory, ${dir}.`, error); | |
} | |
try { | |
return await readDataFromJSONFiles(keys, dir); | |
} catch (error) { | |
return `Error reading in JSON files: ${error}`; | |
} | |
} | |
export function stripBackslashes(str) { | |
return str.replace(/\\/g, ""); | |
} | |
export function stripHTML(str) { | |
return str.replace(/(<([^>]+)>)/gi, ""); | |
} | |
export function stripHTMLCharacterCodes(str) { | |
return str.replace(/&[A-Za-z]+(?<!>|<);/gi, ""); | |
} | |
// TODO: How to curry multiple CBs? | |
/** | |
* Update values of given πs (each 'key' should be present already) in an object. | |
* @param {Object} data | |
* @param {Array} keys | |
* @param {Function} cb - the 'update' to perform | |
* @return {Object} | |
*/ | |
export function updateSpecifiedKeys({ data, keys, cb } = {}) { | |
return data.map(d => | |
// For every 'd', update all of the VALUES for some specified ARRAY of πs...'reduce' πs down to just 1 'updated object'. | |
keys.reduce( | |
(updatedObject, currentKey) => ({ | |
...d, | |
...updatedObject, | |
...{ [currentKey]: cb(d[currentKey]) } | |
}), | |
{} | |
) | |
); | |
} | |
export function writeJSONData(data, fileName) { | |
fs.writeFile(`./${fileName}.json`, JSON.stringify(data, null, 2)) | |
.then(() => { | |
console.log("Rote file!"); | |
}) | |
.catch(error => { | |
console.error(`Error riting file: ${error}`); | |
}); | |
} |
This assumes that the π s exist in each data
Object.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Blog post explanation