Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tap-parser

Package Overview
Dependencies
Maintainers
2
Versions
106
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tap-parser - npm Package Compare versions

Comparing version 0.7.0 to 1.0.0

old.js

91

bin/cmd.js
#!/usr/bin/env node
var minimist = require('minimist');
var parser = require('../');
var fs = require('fs');
var Parser = require('../')
var etoa = require('events-to-array')
var util = require('util')
var argv = minimist(process.argv.slice(2), {
alias: {
h: 'help', v: 'version',
o: 'outfile', i: 'infile', r: 'results'
},
default: { outfile: '-', infile: '-' },
boolean: [ 'results' ]
});
if (argv.help) {
return fs.createReadStream(__dirname + '/usage.txt')
.pipe(process.stdout)
;
var args = process.argv.slice(2)
var json = null
args.forEach(function (arg, i) {
if (arg === '-j') {
json = args[i + 1] || 2
} else {
var m = arg.match(/^--json(?:=([0-9]+))$/)
if (m)
json = +m[1] || args[i + 1] || 2
}
if (arg === '-h' || arg === '--help')
usage()
})
function usage () {
console.log(function () {/*
Usage:
tap-parser [-j [<indent>] | --json[=indent]]
Parses TAP data from stdin, and outputs an object representing
the data found in the TAP stream to stdout.
If there are any failures in the TAP stream, then exits with a
non-zero status code.
Data is output by default using node's `util.format()` method, but
JSON can be specified using the `-j` or `--json` flag with a number
of spaces to use as the indent (default=2).
*/}.toString().split('\n').slice(1, -1).join('\n'))
if (!process.stdin.isTTY)
process.stdin.resume()
process.exit()
}
if (argv.version) {
console.log(require('../package.json').version);
return;
function format (msg) {
if (json !== null)
return JSON.stringify(msg, null, +json)
else
return util.inspect(events, null, Infinity)
}
var input = argv.infile === '-'
? process.stdin
: fs.createReadStream(argv.infile)
;
var output = argv.outfile === '-'
? process.stdout
: fs.createWriteStream(argv.outfile)
;
var parser = new Parser()
var events = etoa(parser, [ 'pipe', 'unpipe', 'prefinish', 'finish' ])
input.pipe(parser(function (results) {
process.on('exit', function (code) {
if (code === 0) process.exit(results.ok ? 0 : 1);
});
if (argv.results) {
output.write(JSON.stringify(results, null, 2) + '\n');
if (output !== process.stdout) output.end();
}
}));
if (!argv.results) input.pipe(output);
process.stdin.pipe(parser)
process.on('exit', function () {
console.log(format(events))
if (!parser.ok)
process.exit(1)
})

@@ -1,190 +0,440 @@

var Writable = require('readable-stream').Writable;
var inherits = require('inherits');
// Transforms a stream of TAP into a stream of result objects
// and string comments. Emits "results" event with summary.
var Writable = require('stream').Writable
var yaml = require('js-yaml')
var util = require('util')
var assert = require('assert')
var re = {
ok: new RegExp([
'^(not )?ok\\b(?:',
'(?:\\s+(\\d+))?(?:\\s+(?:(?:\\s*-\\s*)?(.*)))?',
')?'
].join('')),
plan: /^(\d+)\.\.(\d+)\b(?:\s+#\s+SKIP\s+(.*)$)?/,
comment: /^#\s*(.+)/,
version: /^TAP\s+version\s+(\d+)/i,
label_todo: /^(.*?)\s*#\s*TODO\s+(.*)$/
};
util.inherits(Parser, Writable)
module.exports = Parser;
inherits(Parser, Writable);
module.exports = Parser
function Parser (cb) {
if (!(this instanceof Parser)) return new Parser(cb);
Writable.call(this, { encoding: 'string' });
if (cb) this.on('results', cb);
this.results = {
ok: undefined,
asserts: [],
pass: [],
fail: [],
todo: [],
errors: []
};
this._lineNum = 1;
this._line = '';
this._planMismatch = false;
this.on('finish', function () {
if (this._line.length) this._online(this._line);
this._finished();
});
this.on('assert', this._onassert);
this.on('plan', this._onplan);
this.on('parseError', function (err) {
this.results.ok = false;
err.line = this._lineNum;
this.results.errors.push(err);
});
var testPointRE = /^(not )?ok(?: ([0-9]+))?(?:(?: - )?(.*))?\n$/
function createResult (line, count) {
if (!testPointRE.test(line))
return null
return new Result(line, count)
}
Parser.prototype._write = function (chunk, enc, next) {
var parts = (this._line + chunk).split('\n');
for (var i = 0; i < parts.length - 1; i++) {
this._online(parts[i]);
this._lineNum ++;
function parseDirective (line) {
line = line.trim()
var re = /^(todo|skip)\b/i
var type = line.match(re)
if (!type)
return false
return [ type[0].toLowerCase(), line.replace(re, '').trim() || true ]
}
function Result (line, count) {
var parsed = line.match(testPointRE)
assert(parsed, 'invalid line to Result')
var ok = !parsed[1]
var id = +(parsed[2] || count + 1)
this.ok = ok
this.id = id
var src = line
Object.defineProperty(this, 'src', {
value: line,
writable: true,
enumerable: false,
configurable: false
})
this.src = line
var rest = parsed[3] || ''
var name
rest = rest.replace(/([^\\]|^)((?:\\\\)*)#/g, '$1\n$2').split('\n')
name = rest.shift()
rest = rest.filter(function (r) { return r.trim() }).join('#')
// now, let's see if there's a directive in there.
var dir = parseDirective(rest.trim())
if (!dir)
name += rest ? '#' + rest : ''
else
this[dir[0]] = dir[1]
if (name)
this.name = name.trim()
return this
}
Object.defineProperty(Result.prototype, 'toString', {
value: function () {
return this.src
},
enumerable: false,
writable: true,
configurable: true
})
function Parser (options, onComplete) {
if (typeof options === 'function') {
onComplete = options
options = {}
}
if (!(this instanceof Parser))
return new Parser(options, onComplete)
options = options || {}
if (onComplete)
this.on('complete', onComplete)
this.indent = options.indent || ''
this.level = options.level || 0
Writable.call(this)
this.buffer = ''
this.bailedOut = false
this.planStart = -1
this.planEnd = -1
this.planComment = ''
this.yamlish = ''
this.yind = ''
this.child = null
this.current = null
this.count = 0
this.pass = 0
this.fail = 0
this.todo = 0
this.skip = 0
this.ok = true
this.postPlan = false
}
Parser.prototype.processYamlish = function () {
var yamlish = this.yamlish
this.yamlish = ''
this.yind = ''
if (!this.current) {
this.emit('extra', yamlish)
return
}
try {
var diags = yaml.safeLoad(yamlish)
} catch (er) {
this.emit('extra', yamlish)
return
}
this.current.src += yamlish
this.current.diag = diags
this.emitResult()
}
Parser.prototype.write = function (chunk, encoding, cb) {
if (typeof encoding === 'string' && encoding !== 'utf8')
chunk = new Buffer(chunk, encoding)
if (Buffer.isBuffer(chunk))
chunk += ''
if (typeof encoding === 'function') {
cb = encoding
encoding = null
}
if (this.bailedOut) {
if (cb)
process.nextTick(cb)
return true
}
this.buffer += chunk
do {
var match = this.buffer.match(/^.*\r?\n/)
if (!match || this.bailedOut)
break
this.buffer = this.buffer.substr(match[0].length)
this._parse(match[0])
} while (this.buffer.length)
if (cb)
process.nextTick(cb)
return true
}
Parser.prototype.end = function (chunk, encoding, cb) {
if (chunk) {
if (typeof encoding === 'function') {
cb = encoding
encoding = null
}
this._line = parts[parts.length - 1];
next();
};
this.write(chunk, encoding)
}
Parser.prototype._onassert = function (res) {
var results = this.results;
results.asserts.push(res);
if (!res.ok && !res.todo) results.ok = false;
var dest = (res.ok ? results.pass : results.fail);
if (res.todo) dest = results.todo;
dest.push(res);
var prev = results.asserts[results.asserts.length - 2];
if (this.buffer)
this.write('\n')
if (!res.number) {
if (prev) res.number = prev.number + 1;
else res.number = 1;
// if we have yamlish, means we didn't finish with a ...
if (this.yamlish)
this.emit('extra', this.yamlish)
this.emitResult()
var skipAll
if (this.planEnd === 0 && this.planStart === 1) {
this.ok = true
skipAll = true
} else if (this.count !== (this.planEnd - this.planStart + 1))
this.ok = false
if (this.ok && !skipAll && this.first !== this.planStart)
this.ok = false
if (this.ok && !skipAll && this.last !== this.planEnd)
this.ok = false
var final = {
ok: this.ok,
count: this.count,
pass: this.pass
}
if (this.fail)
final.fail = this.fail
if (this.bailedOut)
final.bailout = this.bailedOut
if (this.todo)
final.todo = this.todo
if (this.skip)
final.skip = this.skip
if (this.planStart !== -1) {
final.plan = { start: this.planStart, end: this.planEnd }
if (skipAll) {
final.plan.skipAll = true
if (this.planComment)
final.plan.skipReason = this.planComment
}
}
if (prev && prev.number + 1 !== res.number) {
this.emit('parseError', {
message: 'assert out of order'
});
this.emit('complete', final)
Writable.prototype.end.call(this, null, null, cb)
}
Parser.prototype.bailout = function (reason) {
this.bailedOut = reason || true
this.ok = false
this.emit('bailout', reason)
}
Parser.prototype.emitResult = function () {
if (this.child) {
this.child.end()
this.child = null
}
this.yamlish = ''
this.yind = ''
if (!this.current)
return
var res = this.current
this.current = null
this.count++
if (res.ok) {
this.pass++
} else {
this.fail++
if (!res.todo)
this.ok = false
}
if (res.skip)
this.skip++
if (res.todo)
this.todo++
this.emit('assert', res)
}
Parser.prototype.startChild = function (indent, line) {
this.emitResult()
this.child = new Parser({
indent: indent,
parent: this,
level: this.level + 1
})
this.emit('child', this.child)
this.child.on('bailout', this.bailout.bind(this))
var self = this
this.child.on('complete', function (results) {
if (!results.ok)
self.ok = false
})
this.child.write(line.substr(indent.length))
}
Parser.prototype._parse = function (line) {
// normalize line endings
line = line.replace(/\r\n$/, '\n')
// ignore empty lines
if (line === '\n')
return
// After a bailout, everything is ignored
if (this.bailedOut)
return
// comment
if (line.match(/^\s*#/)) {
this.emit('comment', line)
return
}
var bailout = line.match(/^bail out!(.*)\n$/i)
if (bailout) {
var reason = bailout[1].trim()
this.bailout(reason)
return
}
// If version is specified, must be at the very beginning.
var version = line.match(/^TAP Version ([0-9]+)\n$/i)
if (version) {
if (this.planStart === -1 && this.count === 0)
this.emit('version', version[1])
else
this.emit('extra', line)
return
}
// if we got a plan at the end, or a 1..0 plan, then we can't
// have any more results, yamlish, or child sets.
if (this.postPlan) {
this.emit('extra', line)
return
}
// still belongs to the child.
if (this.child && line.indexOf(this.child.indent) === 0) {
line = line.substr(this.child.indent.length)
this.child.write(line)
return
}
var indent = line.match(/^[ \t]+/)
if (indent) {
indent = indent[0]
// if we don't have a current res, then it can't be yamlish,
// must be a child result set
if (!this.current) {
this.startChild(indent, line)
return
}
};
Parser.prototype._onplan = function (plan, skip_reason) {
var results = this.results;
if (results.plan !== undefined) {
this.emit('parseError', {
message: 'unexpected additional plan'
});
return;
// if we are not currently processing yamlish, then it has to
// be either the start of a child, or the start of yamlish.
if (!this.yind) {
// either this starts yamlish, or it is a child.
if (line === indent + '---\n')
this.yind = indent
else
this.startChild(indent, line)
return
}
if (plan.start === 1 && plan.end === 0) {
plan.skip_all = true;
plan.skip_reason = skip_reason; // could be undefined
} else if (skip_reason) {
this.emit('parseError', {
message: 'plan is not empty, but has a SKIP reason',
skip_reason: skip_reason
});
plan.skip_all = false;
plan.skip_reason = skip_reason;
// continue to use the plan
// now we know it is yamlish
// if it's not as indented, then it's broken.
// The whole yamlish chunk is garbage.
if (indent.indexOf(this.yind) !== 0) {
// oops! was not actually yamlish, I guess.
// treat as garbage
this.emit('extra', this.yamlish + line)
this.emitResult()
return
}
results.plan = plan;
this._checkAssertionStart();
};
Parser.prototype._online = function (line) {
var m;
if (m = re.version.exec(line)) {
var ver = /^\d+(\.\d*)?$/.test(m[1]) ? Number(m[1]) : m[1];
this.emit('version', ver);
// yamlish ends with "...\n"
if (line === this.yind + '...\n') {
this.processYamlish()
return
}
else if (m = re.comment.exec(line)) {
this.emit('comment', m[1]);
}
else if (m = re.ok.exec(line)) {
var ok = !m[1];
var num = m[2] && Number(m[2]);
var name = m[3];
var asrt = {
ok: ok,
number: num,
name: name
};
if (m = re.label_todo.exec(name)) {
asrt.name = m[1];
asrt.todo = m[2];
}
this.emit('assert', asrt);
}
else if (m = re.plan.exec(line)) {
this.emit('plan', {
start: Number(m[1]),
end: Number(m[2])
},
m[3]); // reason, if SKIP
}
else this.emit('extra', line)
};
Parser.prototype._checkAssertionStart = function () {
var results = this.results;
if (this._planMismatch) return;
if (!results.asserts[0]) return;
if (!results.plan) return;
if (results.asserts[0].number === results.plan.start) return;
this._planMismatch = true;
this.emit('parseError', {
message: 'plan range mismatch'
});
};
// ok! it is valid yamlish indentation, and not the ...
// save it to parse later.
this.yamlish += line
return
}
Parser.prototype._finished = function () {
var results = this.results;
if (results.plan === undefined) {
this.emit('parseError', {
message: 'no plan found'
});
// not indented. if we were doing yamlish, then it didn't go good
if (this.yind) {
this.emit('extra', this.yamlish)
this.yamlish = ''
this.yind = ''
}
this.emitResult()
var plan = line.match(/^([0-9]+)\.\.([0-9]+)(?:\s+(?:#\s*(.*)))?\n$/)
if (plan) {
if (this.planStart !== -1) {
// this is not valid tap, just garbage
this.emit('extra', line)
return
}
if (results.ok === undefined) results.ok = true;
var skip_all = (results.plan && results.plan.skip_all);
if (results.asserts.length === 0 && ! skip_all) {
this.emit('parseError', {
message: 'no assertions found'
});
} else if (skip_all && results.asserts.length !== 0) {
this.emit('parseError', {
message: 'assertion found after skip_all plan'
});
}
var last = results.asserts.length
&& results.asserts[results.asserts.length - 1].number
;
if (results.ok && last < results.plan.end) {
this.emit('parseError', {
message: 'not enough asserts'
});
}
else if (results.ok && last > results.plan.end) {
this.emit('parseError', {
message: 'too many asserts'
});
}
this.emit('results', results);
};
var start = +(plan[1])
var end = +(plan[2])
var comment = plan[3]
this.planStart = start
this.planEnd = end
var p = { start: start, end: end }
if (comment)
this.planComment = p.comment = comment
this.emit('plan', p)
// This means that the plan is coming at the END of all the tests
// Plans MUST be either at the beginning or the very end. We treat
// plans like '1..0' the same, since they indicate that no tests
// will be coming.
if (this.count !== 0 || this.planEnd === 0)
this.postPlan = true
return
}
var res = createResult(line, this.count)
if (!res) {
this.emit('extra', line)
return
}
if (res.id) {
if (!this.first || res.id < this.first)
this.first = res.id
else if (!this.last || res.id > this.last)
this.last = res.id
}
// hold onto it, because we might get yamlish diagnostics
this.current = res
}
{
"name": "tap-parser",
"version": "0.7.0",
"version": "1.0.0",
"description": "parse the test anything protocol",

@@ -10,9 +10,10 @@ "main": "index.js",

"dependencies": {
"events-to-array": "^1.0.1",
"inherits": "~2.0.1",
"minimist": "^0.2.0",
"readable-stream": "~1.1.11"
"js-yaml": "^3.2.7"
},
"devDependencies": {
"tape": "~2.3.2",
"tap": "~0.4.6"
"glob": "^5.0.2",
"tap": "~0.4.6",
"tape": "^3.5.0"
},

@@ -19,0 +20,0 @@ "scripts": {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc