parserblade
A all-in-one parser for Javascript, heavily inspired by: https://github.com/nathanmac/Parser. It allows you to work with JSON, XML, CSV and YAML more without worrying about which module install. It's designed to work just as JSON.parse
and JSON.stringify
does, with some improvements.
See docs for more info and examples.
Installation
$ npm install --save parserblade
Usage
Every filetype has two main methods: stringify()
and parse()
, both receives two arguments, data
containing any type of data and an options object.
CSV
const { csv } = require('parserblade')
// Parsing
const input = 'title,platform\nStardew Valley,Steam'
const result = csv.parse(input)
console.log(result) // [ { title: 'Stardew Valley', platform: 'Steam' } ]
// Stringifying
console.log(
csv.stringify(result)
) // 'title,platform\nStardew Valley,Steam'
YAML
const { yaml } = require('parserblade')
// Parsing
const input = 'title: Stardew Valley\nplatform: Steam'
const result = yaml.parse(input)
console.log(result) // { title: 'Stardew Valley', platform: 'Steam' }
// Stringifying
console.log(
yaml.stringify(result)
) // 'title: Stardew Valley\nplatform: Steam'
XML
const { xml } = require('parserblade')
// Parsing
const input = '<?xml version="1.0" encoding="utf-8"?><package>lodash</package>'
const result = xml.parse(input)
console.log(result) // { package: 'lodash' }
// Stringifying
console.log(
xml.stringify(result)
) // '<?xml version="1.0" encoding="utf-8"?><package>lodash</package>'
License
MIT ©
JSON
Parse
There's no magic here. It just calls native's JSON.parse
, currently there's no additional parameters.
const assert = require('assert')
const { json } = require('parserblade')
const input = '[{"game":"Stardew Valley"}]'
const result = json.parse(input)
assert.deepStrictEqual(
result,
[ { game: 'Stardew Valley' } ]
)
Stringify
There's no magic here. It just calls native's JSON.stringify
, currently there's no additional parameters.
const assert = require('assert')
const { json } = require('parserblade')
const input = [ { game: 'Stardew Valley' } ]
const result = json.stringify(input)
assert.equal(
result,
'[{"game":"Stardew Valley"}]'
)
Valid
Just checks if given string is a valid JSON data
const assert = require('assert')
const { json } = require('parserblade')
const result = json.valid('{')
assert.equal(
result,
false
)
Stream
Stringify an array
const { json } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
if (!next) {
this.push(null)
} else {
this.push(next)
}
}
})
const writer = json.pipeStringify()
const toFile = fs.createWriteStream('./data-test.json')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
Stringify an object
You must pass { type: 'object' }
as param. Defaults to array
.
Data must be an array of [ key, value ]
. Like from Object.entries({ game: 'Stardew Valley' })
const { json } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = Object.entries({
name: 'Rodolfo'
})
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
if (!next) {
this.push(null)
} else {
this.push(next)
}
}
})
const writer = json.pipeStringify({ type: 'object' })
const toFile = fs.createWriteStream('./data-test.json')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
Parse
const { json } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.json')
const reader = fs.createReadStream(filepath)
const writer = json.pipeParse()
reader
.pipe(writer)
.on('data', console.log)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
CSV
Works with CSV data. I haven't tested with xlsx or other similar data types yet.
Usage
Both csv.parse()
and csv.stringify()
accepts the data to be parsed/stringified as the first argument, and an option's object as the second.
Parse
Parses CSV string to JS data, automatically uses first line as headers. Pass data as first argument.
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'title,platform\nStardew Valley,Steam'
const result = csv.parse(input)
assert.deepStrictEqual(
result,
[ { title: 'Stardew Valley', platform: 'Steam' } ]
)
Parse headers
Don't use first line as headers. Pass { headers: false }
as second parameter.
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })
assert.deepStrictEqual(
result,
[
['name', 'email'],
['Netflix', 'contact@netflix.com']
]
)
Specify headers passing { headers: ['name', 'email'] }
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })
assert.deepStrictEqual(
result,
[
{ name: 'Netflix', email: 'contact@netflix.com' }
]
)
Specify a function to transform headers passing { headers: header => header.toUpperCase() }
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })
assert.deepStrictEqual(
result,
[
{ NAME: 'Netflix', EMAIL: 'contact@netflix.com' }
]
)
Parse with custom delimiters
Uses custom delimiters. Anything you want! Pass { delimiter: ';' }
as option.
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name;email\nNetflix;contact@netflix.com'
const result = csv.parse(input, { delimiter: ';' })
assert.deepStrictEqual(
result,
[ { name: 'Netflix', email: 'contact@netflix.com' } ]
)
Parse skipping some lines
Pass { skipLines: 2 }
as option.
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'coll streaming platforms\nname,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { skipLines: 2 })
assert.deepStrictEqual(
result,
[ { name: 'Netflix', email: 'contact@netflix.com' } ]
)
Parse offset
Pass { offset: 2 }
as option.
const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com\nAmazon,contact@amazon.com'
const result = csv.parse(input, { offset: 2 })
assert.deepStrictEqual(
result,
[ { name: 'Netflix', email: 'contact@netflix.com' } ]
)
Stringify
Simply transforms JS array of objects into CSV
const assert = require('assert')
const { csv } = require('parserblade')
const input = [
{ name: 'Netflix', email: 'contact@netflix.com' }
]
const result = csv.stringify(input)
assert.equal(
result,
'name,email\nNetflix,contact@netflix.com'
)
Stringify omitting headers
Pass { headers: false }
as options
const assert = require('assert')
const { csv } = require('parserblade')
const input = [
{ name: 'Netflix', email: 'contact@netflix.com' }
]
const result = csv.stringify(input)
assert.equal(
result,
'Netflix,contact@netflix.com'
)
Stringify with custom column names/headers
Specifying custom columns is easy in many forms, like just pass { columns: [ { key: '', header: '' } ] }
as options.
Or { columns: ['name', 'email'] }
.
Or { columns: { name: 'Name', email: 'Email' } }
.
const assert = require('assert')
const { csv } = require('parserblade')
const input = [
{ name: 'Netflix', email: 'contact@netflix.com' }
]
const columns = [
{ key: 'name', header: 'Platform' },
{ key: 'email', header: 'e-mail' }
]
const result = csv.stringify(input, { columns })
assert.equal(
result,
'Platform,e-mail\nNetflix,contact@netflix.com'
)
Valid
Just checks if given string is a valid CSV
const assert = require('assert')
const { csv } = require('parserblade')
const result = csv.valid('name\nstardew,pokemon')
assert.equal(
result,
false
)
Stream
pipeStringify
Turns JS data into CSV
const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
this.push(next || null)
}
})
const writer = csv.pipeStringify()
const toFile = fs.createWriteStream('./data-test.csv')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeStringify with custom delimiter
const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
this.push(next || null)
}
})
const writer = csv.pipeStringify({ delimiter: ';' })
const toFile = fs.createWriteStream('./data-test.csv')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeStringify with custom column names
const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
this.push(next || null)
}
})
const columns = [
{ key: 'game', header: 'title' }
]
const writer = csv.pipeStringify({ columns })
const toFile = fs.createWriteStream('./data-test.csv')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeStringify reordering columns
const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')
const input = [{ game: 'Killing Floor', platform: 'Windows 10' }, { game: 'Stardew Valley', platform: 'Windows 10' }]
const reader = new Readable({
objectMode: true,
read (size) {
const next = input.shift()
this.push(next || null)
}
})
const columns = [
{ key: 'platform' },
{ key: 'game' }
]
const writer = csv.pipeStringify({ columns })
const toFile = fs.createWriteStream('./data-test.csv')
reader
.pipe(writer)
.pipe(toFile)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeParse
const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')
const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse()
reader
.pipe(writer)
.on('readable', console.log)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeParse setting custom delimiter
const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')
const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse({ delimiter: ';' })
reader
.pipe(writer)
.on('readable', console.log)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
pipeParse without using first line as header
const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')
const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse({ headers: false })
reader
.pipe(writer)
.on('readable', console.log)
.on('error', console.log)
.on('end', () => {
console.log('done')
})
XML
Works with XML data. I haven't tested with xlsx or other similar data types yet. There's a lot of things to improve here.
Usage
Both xml.parse()
and xml.stringify()
accepts the data to be parsed/stringified as the first argument, and an option's object as the second.
Parse
const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><games><name>Naruto Shippuden Storm 3</name><platform>playstation</platform></games>'
const result = xml.parse(input)
assert.deepStrictEqual(
result,
{
games: {
name: { _text: 'Naruto Shippuden Storm 3' },
platform: { _text: 'playstation' }
}
}
)
const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><packages><name>mongoose</name><name>sequelize</name></packages>'
const result = xml.parse(input)
assert.deepStrictEqual(
result,
{
packages: {
name: [
{ _text: 'mongoose' },
{ _text: 'sequelize' }
]
}
}
)
Parse XML including declaration
Pass { showDeclaration: true }
as option.
const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><packages><name>mongoose</name><name>sequelize</name></packages>'
const result = xml.parse(input, { showDeclaration: true })
assert.deepStrictEqual(
result,
{
_declaration: {
_attributes: {
encoding: 'utf-8',
version: 1
}
},
packages: {
name: [
{ _text: 'mongoose' },
{ _text: 'sequelize' }
]
}
}
)
Parse XML in verbose mode
Pass { verbose: true }
as option.
const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><games><name>Naruto Shippuden Storm 3</name><platform>playstation</platform></games>'
const result = xml.parse(input, { verbose: true })
const expected = {
elements: [
{
type: 'element',
name: 'games',
elements: [
{
type: 'element',
name: 'name',
elements: [
{
type: 'text',
text: 'Naruto Shippuden Storm 3'
}
]
},
{
type: 'element',
name: 'platform',
elements: [
{
type: 'text',
text: 'playstation'
}
]
},
]
}
]
}
assert.deepStrictEqual(
result,
expected
)
Stringify
const assert = require('assert')
const { xml } = require('parserblade')
const input = { game: 'Stardew Valley' }
const result = xml.stringify(input)
assert.deepStrictEqual(
result,
'<?xml version="1.0" encoding="utf-8"?><game>Stardew Valley</game>'
)
Stringify without XML declaration
const assert = require('assert')
const { xml } = require('parserblade')
const input = { game: 'Stardew Valley' }
const result = xml.stringify(input, { ignoreDeclaration: true })
assert.deepStrictEqual(
result,
'<game>Stardew Valley</game>'
)
Stringify array
const assert = require('assert')
const { xml } = require('parserblade')
const input = {
packages: [
{ name: 'lodash' }
]
}
const result = xml.stringify(input)
assert.deepStrictEqual(
result,
'<?xml version="1.0" encoding="utf-8"?><packages><name>lodash</name></packages>'
)
Stringify with metadata
const assert = require('assert')
const { xml } = require('parserblade')
const input = {
packages: [
{
_text: 'lodash',
_attributes: { lang: 'nodejs' }
},
{
_text: 'flash',
_attributes: { lang: 'python' }
}
]
}
const result = xml.stringify(input)
assert.deepStrictEqual(
result,
'<?xml version="1.0" encoding="utf-8"?><packages lang="nodejs">lodash</packages><packages lang="python">flash</packages>'
)
Valid
Just checks if given string is a valid XML
const assert = require('assert')
const { xml } = require('parserblade')
const result = xml.valid('phrase<tag />')
assert.equal(
result,
false
)
Stream
pipeParse
You may specify in which depth it should emit data, defaults to 0.
const { Readable } = require('stream')
const { xml } = require('parserblade')
const input = `
<?xml version="1.0" encoding="utf-8"?>
<info>
<name>Naruto Shippuden Storm 3</name>
<platform>
platform
<another>
This is another tag
</another>
<another>
Third tag another
</another>
</platform>
<site url="netflix">
Netflix
<description>
Possible description here
</description>
</site>
</info>
`.split('')
const reader = new Readable({
read () {
const next = input.shift()
if (typeof next === 'string') {
this.push(next)
} else {
this.push(null)
}
}
})
reader
.pipe(xml.pipeParse())
.on('data', console.log)
.on('error', console.log)
.on('end', () => console.log('stream ended'))
pipeStringify
You can set which tag wraps everything with { mainTag: { name, text, attributes } }
const { Readable } = require('stream')
const { xml } = require('parserblade')
const input = [{ name: 'Starcraft II' }]
const reader = new Readable({
objectMode: true,
read () {
const next = input.shift()
this.push(next || null)
}
})
reader
.pipe(xml.pipeParse({ mainTag: { name: 'games' } }))
.on('data', console.log)
.on('error', console.log)
.on('end', () => console.log('stream ended'))
YAML
Usage
Both yaml.parse()
and yaml.stringify()
accepts the data to be parsed/stringified as the first argument, and an option's object as the second.
Parse
const assert = require('assert'')
const { yaml } = require('parserblade')
const input = 'series: Bleach\nseasons: 16'
const result = yaml.parse(data)
assert.deepStrictEqual(
result,
{ series: 'Bleach', seasons: 16 }
)
Stringify
const assert = require('assert'')
const { yaml } = require('parserblade')
const input = { series: 'Bleach', seasons: 16 }
const result = yaml.parse(data)
assert.equal(
result,
'series: Bleach\nseasons: 16'
)
Valid
Just checks if given string is a valid YAML
const assert = require('assert')
const { yaml } = require('parserblade')
const result = yaml.valid('[name:\nStardew')
assert.equal(
result,
false
)