Comparing version 0.2.0 to 0.2.2
100
index.js
#!/usr/bin/env node | ||
'use strict'; /*jslint node: true, es5: true, indent: 2 */ | ||
var os = require('os'); | ||
var util = require('util'); | ||
var stream = require('stream'); | ||
var Parser = exports.Parser = require('./parser'); | ||
@@ -15,2 +18,46 @@ var Stringifier = exports.Stringifier = require('./stringifier'); | ||
var JSONStringifier = function(opts) { | ||
stream.Transform.call(this, {objectMode: true}); | ||
this._readableState.objectMode = false; | ||
}; | ||
util.inherits(JSONStringifier, stream.Transform); | ||
JSONStringifier.prototype._transform = function(chunk, encoding, callback) { | ||
this.push(JSON.stringify(chunk) + os.EOL, encoding); | ||
callback(); | ||
}; | ||
var ObjectFilter = function(fields) { | ||
// objects in, objects out | ||
stream.Transform.call(this, {objectMode: true}); | ||
this.fields = {}; | ||
for (var i = 0, l = fields.length; i < l; i++) { | ||
this.fields[fields[i]] = 1; | ||
} | ||
}; | ||
util.inherits(ObjectFilter, stream.Transform); | ||
ObjectFilter.prototype._transform = function(chunk, encoding, callback) { | ||
var filtered = {}; | ||
for (var field in this.fields) | ||
filtered[field] = chunk[field]; | ||
this.push(filtered, encoding); | ||
callback(); | ||
}; | ||
var ObjectOmitter = function(fields) { | ||
// objects in, objects out | ||
stream.Transform.call(this, {objectMode: true}); | ||
this.fields = {}; | ||
for (var i = 0, l = fields.length; i < l; i++) { | ||
this.fields[fields[i]] = 1; | ||
} | ||
}; | ||
util.inherits(ObjectOmitter, stream.Transform); | ||
ObjectOmitter.prototype._transform = function(chunk, encoding, callback) { | ||
for (var field in this.fields) | ||
delete chunk[field]; | ||
this.push(chunk, encoding); | ||
callback(); | ||
}; | ||
if (require.main === module) { | ||
@@ -21,19 +68,52 @@ var optimist = require('optimist') | ||
'', | ||
' argv will be passed directly to the Stringifier constructor.', | ||
' process.stdin will be set to utf8', | ||
'Usage: <sprints.txt sv [options] > sprints.csv', | ||
'', | ||
' cat data.tsv | sv > data.csv' | ||
].join('\n')); | ||
'Options:', | ||
' -p, --peek 10 infer columns from first ten lines of input', | ||
' -d, --delimiter , field separator', | ||
' -q, --quotechar " mark beginning and end of fields containing delimiter', | ||
' -e, --escapechar \\ escape quotechars when quoted', | ||
' -j, --json write one JSON object per row', | ||
' --filter a,b keep only fields a and b in the results', | ||
' --omit c,d leave out fields x and y from the results', | ||
' (do not use filter and omit together)', | ||
'', | ||
'Only STDIN is supported, and it is coerced to utf8', | ||
].join('\n')) | ||
.string('delimiter') | ||
.boolean(['json',]) | ||
.alias({ | ||
p: 'peek', | ||
d: 'delimiter', | ||
q: 'quotechar', | ||
e: 'escapechar', | ||
j: 'json', | ||
}); | ||
var argv = optimist.argv; | ||
var parser = new Parser(); | ||
var stringifier = new Stringifier(optimist.argv); | ||
if (process.stdin.isTTY) { | ||
if (argv.help) { | ||
optimist.showHelp(); | ||
console.error("You must supply data via STDIN"); | ||
console.log('ARGV: ' + process.argv.join(' ')); | ||
} | ||
else if (process.stdin.isTTY) { | ||
optimist.showHelp(); | ||
console.error('You must supply data via STDIN'); | ||
} | ||
else { | ||
var stringifier = argv.json ? new JSONStringifier() : new Stringifier(argv); | ||
process.stdin.setEncoding('utf8'); | ||
process.stdin.pipe(parser).pipe(stringifier).pipe(process.stdout); | ||
var parser = process.stdin.pipe(new Parser()); | ||
var filtered = null; | ||
if (argv.filter) { | ||
filtered = parser.pipe(new ObjectFilter(argv.filter.split(/,/g))); | ||
} | ||
else if (argv.omit) { | ||
filtered = parser.pipe(new ObjectOmitter(argv.omit.split(/,/g))); | ||
} | ||
else { | ||
filtered = parser; | ||
} | ||
filtered.pipe(stringifier).pipe(process.stdout); | ||
} | ||
} |
{ | ||
"name": "sv", | ||
"version": "0.2.0", | ||
"version": "0.2.2", | ||
"description": "Any separated values.", | ||
@@ -25,6 +25,6 @@ "keywords": [ | ||
"dependencies": { | ||
"optimist": "*" | ||
"optimist": "0.5.2" | ||
}, | ||
"devDependencies": { | ||
"tap": "*" | ||
"tap": "0.4.x" | ||
}, | ||
@@ -31,0 +31,0 @@ "scripts": { |
@@ -82,5 +82,10 @@ 'use strict'; /*jslint node: true, es5: true, indent: 2 */ | ||
for (var i = 0; i < end; i++) { | ||
// if we are on an escape char, simply skip over it (++) and the (default) | ||
if (buffer[i] === this.escapechar) { | ||
i++; | ||
// excel is bizarre. An escape before a quotechar doesn't count. | ||
if (buffer[i+1] !== this.quotechar) { | ||
i++; | ||
} | ||
} | ||
// if we are outside quoting and on a " | ||
else if (!inside && buffer[i] === this.quotechar) { | ||
@@ -90,10 +95,23 @@ inside = true; | ||
} | ||
// if we are inside quoting and on a " | ||
else if (inside && buffer[i] === this.quotechar) { | ||
inside = false; | ||
cells.push(buffer.toString(this.encoding, start, i)); | ||
// assume that an end quotechar is always followed by a delimiter | ||
// advance so that buffer[i] == '\t' | ||
// handle excel dialect: double quotechar => single literal quotechar | ||
if (buffer[i+1] === this.quotechar) { | ||
// double quotechar | ||
// `inside` remains true | ||
// we need to collapse out the current index. this might be optimized somehow | ||
// buffer.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd])# | ||
buffer.copy(buffer, i, i+1); | ||
end--; | ||
} | ||
else { | ||
// otherwise, assume that an end quotechar is always followed by a delimiter. | ||
// advance so that buffer[i] == '\t' | ||
inside = false; | ||
cells.push(buffer.toString(this.encoding, start, i)); | ||
start = i + 2; | ||
} | ||
i++; | ||
start = i + 1; | ||
} | ||
// otherwise we just wait for the delimiter | ||
else if (!inside && buffer[i] === this.delimiter) { | ||
@@ -106,3 +124,3 @@ cells.push(buffer.toString(this.encoding, start, i)); | ||
// we may have consumed the last field, already, if it was quoted. | ||
cells.push(buffer.toString(this.encoding, start)); | ||
cells.push(buffer.toString(this.encoding, start, end)); | ||
} | ||
@@ -120,3 +138,2 @@ | ||
Parser.prototype._flush = function(callback) { | ||
// console.log('_flush'); | ||
// if there was a trailing newline, this._buffer.length = 0 | ||
@@ -123,0 +140,0 @@ if (this._buffer && this._buffer.length) |
@@ -12,7 +12,9 @@ 'use strict'; /*jslint node: true, es5: true, indent: 2 */ | ||
if (typeof(obj) !== 'string' && !util.isArray(obj)) { | ||
var keys = Object.keys(obj); | ||
for (var key, k = 0; (key = keys[k]); k++) { | ||
if (!(key in seen)) { | ||
columns.push(key); | ||
seen[key] = 1; | ||
for (var key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
// maybe should also check that obj[key] != null | ||
if (!(key in seen)) { | ||
columns.push(key); | ||
seen[key] = 1; | ||
} | ||
} | ||
@@ -19,0 +21,0 @@ } |
@@ -1,2 +0,2 @@ | ||
'use strict'; /*jslint node: true, es5: true, indent: 2, multistr: true */ | ||
'use strict'; /*jslint node: true, es5: true, indent: 2 */ | ||
var fs = require('fs'); | ||
@@ -62,1 +62,20 @@ var test = require('tap').test; | ||
}); | ||
test('excel parser', function (t) { | ||
var input = [ | ||
'index name time', | ||
'1 "chris ""breezy"" brown" 1:18', | ||
'2 "stephen" 1:16', | ||
].join('\n'); | ||
var rows = []; | ||
var parser = new sv.Parser(); | ||
parser.on('data', function(obj) { | ||
rows.push(obj); | ||
}); | ||
parser.end(input, function() { | ||
t.equal(rows.length, 2, 'There should be two rows.'); | ||
t.equal(rows[0].name, 'chris "breezy" brown', 'The paired double quotes should be interpreted as just one double quote.'); | ||
t.end(); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
23170
11
557
0
0
+ Addedoptimist@0.5.2(transitive)
- Removedminimist@0.0.10(transitive)
- Removedoptimist@0.6.1(transitive)
Updatedoptimist@0.5.2