Skip to content

Instantly share code, notes, and snippets.

@TravisMullen
Last active September 7, 2021 21:50
Show Gist options
  • Save TravisMullen/db0b9acbd17c5f704ea53351dcd0831b to your computer and use it in GitHub Desktop.
Save TravisMullen/db0b9acbd17c5f704ea53351dcd0831b to your computer and use it in GitHub Desktop.
Covert CSV or TSV file to JSON file.
/**
* 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