Last active
September 7, 2021 21:50
-
-
Save TravisMullen/db0b9acbd17c5f704ea53351dcd0831b to your computer and use it in GitHub Desktop.
Covert CSV or TSV file to JSON file.
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
/** | |
* Standardize Task Data. | |
* Service to be run in nodejs as an npm process (`npm run pre:serve`) | |
* Drop into directory with CSV/TSV files to be parsed, and run as | |
* @example `node path/to/csv-to-json.js` | |
*/ | |
const { once } = require('events') | |
const { createReadStream } = require('fs') | |
const { createInterface } = require('readline') | |
const { writeFile, readdir } = require('fs/promises') | |
const { basename } = require('path') | |
/** | |
* Write the data to a JSON file. | |
* @param {String} data | |
* @param {String} fileName | |
* @async | |
*/ | |
const writeJSONfile = async (data, fileName = 'all.json') => { | |
/** | |
* Location to write file. | |
* @type String | |
* */ | |
const fileTarget = `${__dirname}/${fileName}` | |
console.log(`Writing ${fileName} to ${fileTarget}`) | |
try { | |
/** @todo Enable this abort controller */ | |
// const controller = new AbortController(); | |
// const { signal } = controller; | |
/** Define a writeFile process */ | |
const promise = writeFile(fileTarget, | |
/** Formate JSON to have 2 space indentation. */ | |
JSON.stringify(data, null, 2) | |
) | |
// Abort the request before the promise settles. | |
// controller.abort(); | |
await promise | |
} catch (err) { | |
// When a request is aborted - err is an AbortError | |
console.error(err) | |
} | |
} | |
/** | |
* Reads directory with components and finds them (as `.vue` files.) | |
* @async | |
* @param targetDirectory Directory of where components can be found | |
* @returns {Promise{Array}} List of Key:Value pairs of component names and locations | |
*/ | |
const findBundleTargets = async (targetDirectory = `${__dirname}`) => { | |
const filesPaths = [] | |
try { | |
/** | |
* Async read contents of directory | |
* @see {@link https://nodejs.org/api/fs.html} | |
*/ | |
const files = await readdir( | |
targetDirectory, | |
{ | |
withFileTypes: true, | |
encoding: 'utf8' | |
} | |
) | |
/** | |
* Iterate over found components. | |
*/ | |
for (const { name } of files) { | |
/** Filter `.vue` only files. */ | |
if (name.endsWith('.csv')) { | |
/** Transpile filename or a keyname */ | |
// const keyName = name.replace(/\.csv/g, '') | |
/** Add filename and keyname to list */ | |
// filesPaths.push({ [keyName]: `../${targetDirectory}/${name}` }) | |
filesPaths.push(`${targetDirectory}/${name}`) | |
} | |
} | |
} catch (err) { | |
/** Logs Errors cause this is a development service */ | |
console.error(err) | |
} | |
/** Return list of components for export */ | |
return filesPaths | |
} | |
/** | |
* Process CSV or TSV file by line. | |
* @param {String} filePath | |
* @returns {Array<Object>} Collection to be stringified to JSON | |
*/ | |
const processLineByLine = async (filePath) => { | |
let lineCount = 0 | |
const compiledJson = [] | |
let keys | |
try { | |
const rl = createInterface({ | |
input: createReadStream(filePath), | |
crlfDelay: Infinity | |
}) | |
rl.on('line', (line) => { | |
++lineCount | |
// Process the line. | |
if (lineCount === 1) { | |
// assign column names | |
keys = line.split('\t') // split CSV or TSV by tab | |
} else { | |
// assign value to column for each row | |
const data = line.split('\t') | |
// in object format to be saved as JSON | |
const entry = {} | |
for (const index in data) { | |
// match keyName, | |
// assign value | |
if (data[index] !== '') { | |
entry[keys[index]] = data[index] | |
} | |
} | |
// assigned `sourceFile`; file name is sourceFile value | |
entry.sourceFile = basename(filePath, '.csv') | |
compiledJson.push(entry) | |
} | |
}) | |
await once(rl, 'close') | |
console.log('Data processed for:', filePath) | |
} catch (err) { | |
console.error(err) | |
} | |
return compiledJson | |
} | |
/** Define service implementation chain. */ | |
const doBundle = async () => { | |
const targetFiles = await findBundleTargets() | |
const rendered = [] | |
for (const filePath of targetFiles) { | |
rendered.push(await processLineByLine(filePath)) | |
} | |
await writeJSONfile( | |
rendered.flat(), | |
'all-data.json' | |
) | |
console.log('--- Bundle Complete! ---') | |
} | |
/** [Self] Invoking function chain so calling the file runs the service. */ | |
doBundle() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment