html-select
Advanced tools
Comparing version 1.3.0 to 2.0.0
@@ -5,2 +5,3 @@ #!/usr/bin/env node | ||
var split = require('split'); | ||
var through = require('through2'); | ||
var fs = require('fs'); | ||
@@ -10,4 +11,4 @@ var minimist = require('minimist'); | ||
var argv = minimist(process.argv.slice(2), { | ||
alias: { h: 'help', i: 'inside' }, | ||
boolean: [ 'inside' ] | ||
alias: { h: 'help', r: 'raw' }, | ||
boolean: [ 'raw' ] | ||
}); | ||
@@ -22,12 +23,18 @@ var selector = argv._.join(' '); | ||
process.stdin | ||
.pipe(split(parseLine)) | ||
.pipe(select(selector, function (e) { | ||
console.log(JSON.stringify(e)); | ||
if (argv.inside) { | ||
e.createReadStream().pipe(process.stdout); | ||
var s = select(); | ||
s.select(selector, function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
if (argv.raw) { | ||
console.log(row[1].toString()); | ||
} | ||
})) | ||
; | ||
else { | ||
console.log(JSON.stringify([ row[0], row[1].toString() ])); | ||
} | ||
next(); | ||
})); | ||
}); | ||
process.stdin.pipe(split(parseLine)).pipe(s); | ||
s.resume(); | ||
function parseLine (s) { | ||
@@ -34,0 +41,0 @@ if (!/\S/.test(s)) return; |
usage: html-select SELECTOR OPTIONS | ||
Given a newline-separated json stream of html tokenize output on stdin, | ||
print matching tags as newline-separated json on stdout. | ||
print content below matching html tokens as json on stdout. | ||
OPTIONS are: | ||
-i, --inside Print the inner html content at matching selectors. | ||
-r, --raw Instead of printing html token data as json, print the html | ||
directly. | ||
@@ -5,7 +5,9 @@ var select = require('../'); | ||
fs.createReadStream(__dirname + '/page.html') | ||
.pipe(tokenize()) | ||
.pipe(select('.content span', function (e) { | ||
console.log('matched:', e); | ||
})) | ||
; | ||
var s = select('ul > li dt', function (e) { | ||
console.log('*** MATCH ***'); | ||
e.createReadStream().on('data', function (row) { | ||
console.log([ row[0], row[1].toString() ]); | ||
}); | ||
}); | ||
fs.createReadStream(__dirname + '/page.html').pipe(tokenize()).pipe(s); | ||
s.resume(); |
247
index.js
@@ -0,148 +1,155 @@ | ||
var through = require('through2'); | ||
var inherits = require('inherits'); | ||
var Writable = require('readable-stream').Writable; | ||
var EventEmitter = require('events').EventEmitter; | ||
var copy = require('shallow-copy'); | ||
var Duplex = require('readable-stream').Duplex; | ||
var cssauron = require('cssauron'); | ||
var Select = require('./lib/select.js'); | ||
var parseTag = require('./lib/parse_tag.js'); | ||
var parseSelector = require('./lib/selector.js'); | ||
var match = require('./lib/match.js'); | ||
var Tag = require('./lib/tag.js'); | ||
var selfClosing = require('./lib/self_closing.js'); | ||
var special = (function () { | ||
var tags = [ | ||
'area', 'base', 'basefont', 'br', 'col', 'hr', 'input', | ||
'img', 'link', 'meta' | ||
]; | ||
var special = {}; | ||
for (var i = 0; i < tags.length; i++) { | ||
special[tags[i]] = true; | ||
} | ||
return special; | ||
})(); | ||
module.exports = Plex; | ||
inherits(Plex, Duplex); | ||
inherits(Selector, Writable); | ||
module.exports = Selector; | ||
function Plex (sel, cb) { | ||
if (!(this instanceof Plex)) return new Plex(sel, cb); | ||
Duplex.call(this, { objectMode: true }); | ||
this._selectors = []; | ||
this._matching = null; | ||
this._pullQueue = []; | ||
this._root = {}; | ||
this._current = this._root; | ||
this._lang = cssauron({ | ||
tag: function (node) { return getTag(node) }, | ||
class: function (node) { return getAttr(node, 'class') }, | ||
id: function (node) { return getAttr(node, 'id') }, | ||
parent: 'parent', | ||
children: 'children', | ||
attr: getAttr | ||
}); | ||
this.on('finish', function () { | ||
this._finished = true; | ||
this._advance(); | ||
}); | ||
if (sel && cb) this.select(sel, cb); | ||
} | ||
function Selector (sel, cb) { | ||
if (!(this instanceof Selector)) return new Selector(sel, cb); | ||
Writable.call(this, { objectMode: true }); | ||
function getTag (node) { | ||
if (node.tag) return node.tag; | ||
if (!node.row) return undefined; | ||
if (!node._parsed) { | ||
var p = parseTag(node.row[1]); | ||
node._parsed = p; | ||
node.tag = p.name; | ||
} | ||
return node.tag; | ||
} | ||
this.selector = parseSelector(sel); | ||
this.stack = []; | ||
this.matches = []; | ||
this.streams = []; | ||
if (cb) this.on('match', cb); | ||
function getAttr (node, key) { | ||
if (node.attributes && !key) return node.attributes; | ||
else if (node.attributes) return node.attributes[key]; | ||
if (!node._parsed) { | ||
if (!node.row) return undefined; | ||
var p = parseTag(node.row[1]); | ||
node._parsed = p; | ||
node.tag = p.tag; | ||
} | ||
node.attributes = node._parsed.getAttributes(); | ||
if (!key) return node.attributes; | ||
else return node.attributes[key]; | ||
} | ||
Selector.prototype._write = function (row, enc, next) { | ||
var type = row[0], buf = row[1]; | ||
if (typeof buf === 'string') buf = Buffer(buf); | ||
if (type === 'open') { | ||
var tag = parseTag(buf); | ||
this._push(tag); | ||
if (special.hasOwnProperty(tag.name)) { | ||
this._pop(); | ||
} | ||
Plex.prototype.select = function (sel, cb) { | ||
var self = this; | ||
var pull = function () { self._advance() }; | ||
var s = new Select(this._lang(sel), pull); | ||
s.on('match', function () { | ||
self._matching = s; | ||
if (cb) cb(s); | ||
s.output.pipe(through.obj(function (row, enc, next) { | ||
self.push(row); | ||
next(); | ||
})); | ||
s.output.on('end', function () { | ||
self._matching = null; | ||
self._advance(); | ||
}); | ||
}); | ||
this._selectors.push(s); | ||
return this; | ||
}; | ||
Plex.prototype._pull = function (cb) { | ||
var buf = this._buffer; | ||
var next = this._next; | ||
if (buf) { | ||
this._buffer = null; | ||
this._next = null; | ||
cb(buf); | ||
next(); | ||
} | ||
for (var i = 0; i < this.streams.length; i++) { | ||
var s = this.streams[i]; | ||
var closing = type === 'close' | ||
&& s._row.index === this.stack.length - 1 | ||
; | ||
s._writes ++; | ||
if ((s._writes > 1 || s._outer) && (s._outer || !closing)) { | ||
s.push(buf); | ||
} | ||
else if (this._finished) { | ||
cb(null); | ||
} | ||
if (type === 'close') { | ||
var tag = parseTag(buf); | ||
this._pop(); | ||
else { | ||
this._pullQueue.push(cb); | ||
} | ||
next(); | ||
}; | ||
Selector.prototype._push = function (tag) { | ||
Plex.prototype._read = function (n) { | ||
if (!this._matching) this._advance(); | ||
}; | ||
Plex.prototype._advance = function () { | ||
var self = this; | ||
var row = { | ||
tag: tag, | ||
matches: [], | ||
streams: [], | ||
tags: [], | ||
index: this.stack.length | ||
}; | ||
for (var i = 0; i < this.matches.length; i++) { | ||
var m = this.matches[i]; | ||
if (m.stopIndex && m.stopIndex < this.stack.length) continue; | ||
m.stopIndex = undefined; | ||
var sel = this.selector[m.index]; | ||
if (sel === '>') { | ||
sel = this.selector[++m.index]; | ||
this._pull(function (row) { | ||
if (row === null) { | ||
for (var i = 0, l = self._selectors.length; i < l; i++) { | ||
var s = self._selectors[i]; | ||
if (s.input) s.input.end(); | ||
} | ||
return self.push(null); | ||
} | ||
var prev = m.index > 0 && this.selector[m.index-1]; | ||
if (match(sel, tag)) { | ||
if (++ m.index === this.selector.length) { | ||
m.index --; | ||
var t = this._fromTag(tag); | ||
row.tags.push(t); | ||
t.on('stream', function (s) { | ||
s._row = row; | ||
row.streams.push(s); | ||
self.streams.push(s); | ||
}); | ||
this.emit('match', t); | ||
break; | ||
} | ||
var p = self._updateTree(row); | ||
for (var i = 0, l = self._selectors.length; i < l; i++) { | ||
self._selectors[i]._exec(self._current, row, p); | ||
} | ||
else if (prev === '>') { | ||
m.stopIndex = this.stack.length; | ||
if (self._current.selfClosing) { | ||
self._current = self._current.parent; | ||
} | ||
if (!self._matching) self.push(row); | ||
}); | ||
}; | ||
Plex.prototype._updateTree = function (row) { | ||
if (row[0] === 'open') { | ||
var node = { parent: this._current, row: row }; | ||
node.selfClosing = node.parent && selfClosing(getTag(node)); | ||
if (!this._current.children) this._current.children = [ node ] | ||
else this._current.children.push(node); | ||
this._current = node; | ||
} | ||
if (match(this.selector[0], tag)) { | ||
if (this.selector.length === 1) { | ||
var t = this._fromTag(tag); | ||
row.tags.push(t); | ||
t.on('stream', function (s) { | ||
s._row = row; | ||
row.streams.push(s); | ||
self.streams.push(s); | ||
}); | ||
this.emit('match', t); | ||
} | ||
else { | ||
var m = { | ||
index: 1, | ||
startIndex: this.stack.length | ||
}; | ||
this.matches.push(m); | ||
row.matches.push(m); | ||
} | ||
else if (row[0] === 'close') { | ||
if (this._current.parent) this._current = this._current.parent; | ||
return parseTag(row[1]); | ||
} | ||
this.stack.push(row); | ||
}; | ||
Selector.prototype._pop = function () { | ||
if (this.stack.length === 0) return; | ||
var s = this.stack.pop(); | ||
for (var i = 0; i < s.matches.length; i++) { | ||
var ix = this.matches.indexOf(s.matches[i]); | ||
if (ix >= 0) this.matches.splice(ix, 1); | ||
Plex.prototype._write = function (buf, enc, next) { | ||
if (this._pullQueue.length) { | ||
this._pullQueue.shift()(buf); | ||
next(); | ||
} | ||
for (var i = 0; i < s.streams.length; i++) { | ||
s.streams[i].push(null); | ||
var ix = this.streams.indexOf(s.streams[i]); | ||
if (ix >= 0) this.streams.splice(ix, 1); | ||
else { | ||
this._buffer = buf; | ||
this._next = next; | ||
} | ||
for (var i = 0; i < s.tags.length; i++) { | ||
s.tags[i]._close(); | ||
} | ||
}; | ||
Selector.prototype._fromTag = function (tag) { | ||
return new Tag(tag); | ||
Plex.prototype._err = function (msg) { | ||
this.emit('error', new Error(msg)); | ||
}; |
module.exports = function (buf) { | ||
if (typeof buf === 'string') buf = Buffer(buf); | ||
var closing = buf[1] === '/'.charCodeAt(0); | ||
@@ -3,0 +5,0 @@ var start = closing ? 2 : 1; |
{ | ||
"name": "html-select", | ||
"version": "1.3.0", | ||
"version": "2.0.0", | ||
"description": "match a tokenized html stream with css selectors", | ||
@@ -10,13 +10,13 @@ "main": "index.js", | ||
"dependencies": { | ||
"shallow-copy": "~0.0.1", | ||
"inherits": "~2.0.1", | ||
"readable-stream": "~1.0.27-1", | ||
"inherits": "^2.0.1", | ||
"through2": "^1.0.0", | ||
"cssauron": "^1.1.0", | ||
"readable-stream": "^1.0.27-1", | ||
"duplexer2": "~0.0.2", | ||
"minimist": "~0.0.8", | ||
"split": "~0.3.0", | ||
"object-inspect": "~0.4.0" | ||
"split": "~0.3.0" | ||
}, | ||
"devDependencies": { | ||
"tape": "~2.12.1", | ||
"html-tokenize": "~1.0.0", | ||
"concat-stream": "^1.4.5" | ||
"tape": "^2.13.0", | ||
"html-tokenize": "^1.0.0" | ||
}, | ||
@@ -23,0 +23,0 @@ "scripts": { |
var select = require('../'); | ||
var test = require('tape'); | ||
var tokenize = require('html-tokenize'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
var fs = require('fs'); | ||
var names = [ | ||
var expected = [ | ||
'echojs', | ||
@@ -36,24 +36,21 @@ 'echojs', | ||
'echojs', | ||
'echojs', | ||
'echojs' | ||
]; | ||
var expected = []; | ||
for (var i = 0; i < names.length; i++) { | ||
expected.push(names[i]); | ||
expected.push('discuss'); | ||
} | ||
expected.push('echojs'); | ||
expected.push('1 comment'); | ||
test('article', function (t) { | ||
t.plan(expected.length * 2); | ||
t.plan(expected.length); | ||
var s = select(); | ||
s.select('article username a[href]', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
if (row[0] === 'text') { | ||
t.equal(row[1].toString('utf8'), expected.shift()); | ||
} | ||
next(); | ||
})); | ||
}); | ||
fs.createReadStream(__dirname + '/article/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('article username a[href]', function (e) { | ||
t.equal(e.name, 'a'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString(), expected.shift(), body+''); | ||
})); | ||
})) | ||
.pipe(tokenize()).pipe(s) | ||
; | ||
s.resume(); | ||
}); |
105
test/attr.js
var select = require('../'); | ||
var test = require('tape'); | ||
var through = require('through2'); | ||
test('quoted attribute', function (t) { | ||
t.plan(2); | ||
var s = select('input[type="text"]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text' }); | ||
var expected = [ [ 'open', '<input type="text">' ] ]; | ||
t.plan(expected.length); | ||
var s = select().select('input[type="text"]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -17,9 +23,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('bare attribute', function (t) { | ||
t.plan(2); | ||
var s = select('input[type=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text' }); | ||
var expected = [ [ 'open', '<input type="text">' ] ]; | ||
t.plan(expected.length); | ||
var s = select(); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -33,9 +46,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('mixed case attribute', function (t) { | ||
t.plan(2); | ||
var s = select('input[type=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text' }); | ||
var expected = [ [ 'open', '<input tYPe="text">' ] ]; | ||
t.plan(expected.length); | ||
var s = select(); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -49,9 +69,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('mixed case [attribute]', function (t) { | ||
t.plan(2); | ||
var s = select('input[TypE=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text' }); | ||
var expected = [ [ 'open', '<input type="text">' ] ]; | ||
t.plan(expected.length); | ||
var s = select('input[TypE=text]'); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -65,9 +92,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('trailing whitespace attribute', function (t) { | ||
t.plan(2); | ||
var s = select('input[TypE=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text', value: 'xyz' }); | ||
var expected = [ [ 'open', '<input type="text" value ="xyz">' ] ]; | ||
t.plan(expected.length); | ||
var s = select('input[TypE=text]'); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -81,9 +115,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('attribute extra whitespace', function (t) { | ||
t.plan(2); | ||
var s = select('input[TypE=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text', value: 'xyz' }); | ||
var expected = [ [ 'open', '<input type="text" value = xyz >' ] ]; | ||
t.plan(expected.length); | ||
var s = select('input[TypE=text]'); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -97,9 +138,16 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('attribute whitespace around quotes', function (t) { | ||
t.plan(2); | ||
var s = select('input[TypE=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.deepEqual(e.attributes, { type: 'text', value: 'xyz' }); | ||
var expected = [ [ 'open', '<input type="text" value = "xyz" >' ] ]; | ||
t.plan(expected.length); | ||
var s = select('input[TypE=text]'); | ||
s.select('input[type=text]', function (e) { | ||
e.createReadStream() | ||
.pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})) | ||
; | ||
}); | ||
@@ -113,2 +161,3 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); |
@@ -5,27 +5,40 @@ var select = require('../'); | ||
var path = require('path'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
var tokenize = require('html-tokenize'); | ||
test('child selector', function (t) { | ||
t.plan(2); | ||
var s = select('.c > input[type=text]', function (e) { | ||
t.equal(e.name, 'input'); | ||
t.equal(e.attributes.value, 'abc'); | ||
var expected = [ [ 'open', Buffer('<input type="text" value="abc">') ] ]; | ||
t.plan(expected.length); | ||
var s = select(); | ||
s.select('.c > input[type=text]', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream('child/index.html').pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('child selector non-immediate descendant', function (t) { | ||
t.plan(2); | ||
var s = select('.b > .e', function (e) { | ||
t.equal(e.name, 'div'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'xyz'); | ||
var expected = [ | ||
[ 'open', Buffer('<div class="e">') ], | ||
[ 'text', Buffer('xyz') ], | ||
[ 'close', Buffer('</div>') ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select(); | ||
s.select('.b > .e', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream('child/index.html').pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('child no-match selector', function (t) { | ||
var s = select('.b > input[type=text]', function (e) { | ||
var s = select(); | ||
s.select('.b > input[type=text]', function (e) { | ||
t.fail('should not have matched'); | ||
@@ -35,6 +48,8 @@ }); | ||
s.on('finish', function () { t.end() }); | ||
s.resume(); | ||
}); | ||
test('child start then no match selector', function (t) { | ||
var s = select('.b > .d', function (e) { | ||
var s = select(); | ||
s.select('.b > .d', function (e) { | ||
t.fail('should not have matched'); | ||
@@ -44,2 +59,3 @@ }); | ||
s.on('finish', function () { t.end() }); | ||
s.resume(); | ||
}); | ||
@@ -46,0 +62,0 @@ |
var select = require('../'); | ||
var test = require('tape'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
test('events', function (t) { | ||
t.plan(4); | ||
var s = select('div b'); | ||
s.on('match', function (e) { | ||
t.equal(e.name, 'b'); | ||
t.deepEqual(e.attributes, { x: '5' }); | ||
var expected = [ | ||
[ 'open', '<b x=5>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ] | ||
]; | ||
t.plan(expected.length + 1); | ||
var s = select(); | ||
s.select('div b', function (e) { | ||
e.on('close', function () { | ||
t.ok(true, 'close event'); | ||
}); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -30,2 +32,3 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); |
var select = require('../'); | ||
var test = require('tape'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
test('many read streams', function (t) { | ||
var expected = [ | ||
{ name: 'b', attributes: {}, body: 'beep boop' }, | ||
{ name: 'b', attributes: { x: '555' }, body: 'eek' }, | ||
]; | ||
t.plan(6); | ||
var s = select('div b', function (e) { | ||
var x = expected.shift(); | ||
t.equal(e.name, x.name); | ||
t.deepEqual(e.attributes, x.attributes); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), x.body); | ||
var expected = { | ||
b: [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ], | ||
[ 'open', '<b x=555>' ], | ||
[ 'text', 'eek' ], | ||
[ 'close', '</b>' ] | ||
], | ||
h1: [ | ||
[ 'open', '<h1>' ], | ||
[ 'text', 'whatever' ], | ||
[ 'close', '</h1>' ], | ||
], | ||
}; | ||
t.plan(expected.b.length + expected.h1.length + 3); | ||
var s = select(); | ||
s.select('div b', function (e) { | ||
e.on('close', function () { t.ok(true, 'closed') }); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.b.shift()); | ||
next(); | ||
})); | ||
}); | ||
s.select('h1', function (e) { | ||
e.on('close', function () { t.ok(true, 'closed') }); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.h1.shift()); | ||
next(); | ||
})); | ||
}); | ||
s.write([ 'open', '<html>' ]); | ||
@@ -43,2 +64,3 @@ s.write([ 'open', '<body>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); |
var select = require('../'); | ||
var test = require('tape'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
test('match once', function (t) { | ||
t.plan(1); | ||
var expected = [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
@@ -23,2 +31,3 @@ s.write([ 'open', '<html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); |
167
test/page.js
@@ -5,84 +5,133 @@ var select = require('../'); | ||
var fs = require('fs'); | ||
var through = require('through2'); | ||
test('page .content', function (t) { | ||
t.plan(2); | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('.content', function (e) { | ||
t.equal(e.name, 'div'); | ||
t.deepEqual(e.attributes, { class: 'content' }); | ||
})) | ||
; | ||
var expected = [ | ||
[ 'open', Buffer('<div class="content">') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'open', Buffer('<span class="greeting">') ], | ||
[ 'text', Buffer('beep boop') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'open', Buffer('<span class="name">') ], | ||
[ 'text', Buffer('robot') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'close', Buffer('</div>') ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('.content', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('page *', function (t) { | ||
t.plan(4); | ||
var expected = [ | ||
{ name: 'span', attributes: { class: 'greeting' } }, | ||
{ name: 'span', attributes: { class: 'name' } } | ||
[ 'open', Buffer('<span class="greeting">') ], | ||
[ 'text', Buffer('beep boop') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'open', Buffer('<span class="name">') ], | ||
[ 'text', Buffer('robot') ], | ||
[ 'close', Buffer('</span>') ] | ||
]; | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('.content *', function (e) { | ||
var x = expected.shift(); | ||
t.equal(e.name, x.name); | ||
t.deepEqual(e.attributes, x.attributes); | ||
})) | ||
; | ||
t.plan(expected.length); | ||
var s = select('.content *', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('page div.content', function (t) { | ||
t.plan(2); | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('div.content', function (e) { | ||
t.equal(e.name, 'div'); | ||
t.deepEqual(e.attributes, { class: 'content' }); | ||
})) | ||
; | ||
var expected = [ | ||
[ 'open', Buffer('<div class="content">') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'open', Buffer('<span class="greeting">') ], | ||
[ 'text', Buffer('beep boop') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'open', Buffer('<span class="name">') ], | ||
[ 'text', Buffer('robot') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'text', Buffer('\n ') ], | ||
[ 'close', Buffer('</div>') ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div.content', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('page .name', function (t) { | ||
t.plan(4); | ||
var expected = [ | ||
{ name: 'h1', attributes: { class: 'name' } }, | ||
{ name: 'span', attributes: { class: 'name' } } | ||
[ 'open', Buffer('<h1 class="name">') ], | ||
[ 'text', Buffer('whoa') ], | ||
[ 'close', Buffer('</h1>') ], | ||
[ 'open', Buffer('<span class="name">') ], | ||
[ 'text', Buffer('robot') ], | ||
[ 'close', Buffer('</span>') ], | ||
]; | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('.name', function (e) { | ||
var x = expected.shift(); | ||
t.equal(e.name, x.name); | ||
t.deepEqual(e.attributes, x.attributes); | ||
})) | ||
; | ||
t.plan(expected.length); | ||
var s = select('.name', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('page span.greeting', function (t) { | ||
t.plan(2); | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('span.greeting', function (e) { | ||
t.equal(e.name, 'span'); | ||
t.deepEqual(e.attributes, { class: 'greeting' }); | ||
})) | ||
; | ||
var expected = [ | ||
[ 'open', Buffer('<span class="greeting">') ], | ||
[ 'text', Buffer('beep boop') ], | ||
[ 'close', Buffer('</span>') ], | ||
]; | ||
t.plan(expected.length); | ||
var s = select('span.greeting', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
test('page .content span', function (t) { | ||
t.plan(4); | ||
var expected = [ | ||
{ name: 'span', attributes: { class: 'greeting' } }, | ||
{ name: 'span', attributes: { class: 'name' } } | ||
[ 'open', Buffer('<span class="greeting">') ], | ||
[ 'text', Buffer('beep boop') ], | ||
[ 'close', Buffer('</span>') ], | ||
[ 'open', Buffer('<span class="name">') ], | ||
[ 'text', Buffer('robot') ], | ||
[ 'close', Buffer('</span>') ] | ||
]; | ||
fs.createReadStream(__dirname + '/page/index.html') | ||
.pipe(tokenize()) | ||
.pipe(select('.content span', function (e) { | ||
var x = expected.shift(); | ||
t.equal(e.name, x.name); | ||
t.deepEqual(e.attributes, x.attributes); | ||
})) | ||
; | ||
t.plan(expected.length); | ||
var s = select('.content span', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
readStream().pipe(tokenize()).pipe(s); | ||
s.resume(); | ||
}); | ||
function readStream () { | ||
return fs.createReadStream(__dirname + '/page/index.html'); | ||
} |
var select = require('../'); | ||
var test = require('tape'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
test('more closes than opens', function (t) { | ||
t.plan(2); | ||
var expected = [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -24,10 +29,15 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('implicit close', function (t) { | ||
t.plan(2); | ||
var expected = [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -44,13 +54,17 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('implicit close outer content', function (t) { | ||
t.end(); | ||
return console.error('SKIPPING'); | ||
t.plan(2); | ||
var expected = [ | ||
[ 'open', '<div>' ], | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</div>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div', function (e) { | ||
t.equal(e.name, 'div'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), '<b>beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -67,2 +81,34 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('implicit closing and resuming', function (t) { | ||
console.log('SKIP'); | ||
return t.end(); | ||
var expected = [ | ||
[ 'open', '<i>' ], | ||
[ 'text', 'pizza' ], | ||
[ 'close', '</i>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div > i', function (e) { | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
}); | ||
s.write([ 'open', '<html>' ]); | ||
s.write([ 'open', '<body>' ]); | ||
s.write([ 'open', '<div>' ]); | ||
s.write([ 'open', '<span>' ]); | ||
s.write([ 'open', '<b>' ]); | ||
s.write([ 'text', 'beep boop' ]); | ||
s.write([ 'close', '</span>' ]); | ||
s.write([ 'open', '<i>' ]); | ||
s.write([ 'text', 'pizza' ]); | ||
s.write([ 'close', '</i>' ]); | ||
s.write([ 'close', '</body>' ]); | ||
s.write([ 'close', '</html>' ]); | ||
s.end(); | ||
s.resume(); | ||
}); |
var select = require('../'); | ||
var test = require('tape'); | ||
var concat = require('concat-stream'); | ||
var through = require('through2'); | ||
test('read stream', function (t) { | ||
t.plan(2); | ||
var expected = [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -23,10 +28,16 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('more read stream', function (t) { | ||
t.plan(2); | ||
var expected = [ | ||
[ 'open', '<b>' ], | ||
[ 'text', 'beep boop' ], | ||
[ 'close', '</b>' ] | ||
]; | ||
t.plan(expected.length); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream().pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), 'beep boop'); | ||
e.createReadStream().pipe(through.obj(function (row, enc, next) { | ||
t.deepEqual(row, expected.shift()); | ||
next(); | ||
})); | ||
@@ -47,22 +58,3 @@ }); | ||
s.end(); | ||
s.resume(); | ||
}); | ||
test('outer read stream', function (t) { | ||
t.plan(2); | ||
var s = select('div b', function (e) { | ||
t.equal(e.name, 'b'); | ||
e.createReadStream({ outer: true }).pipe(concat(function (body) { | ||
t.equal(body.toString('utf8'), '<b>beep boop</b>'); | ||
})); | ||
}); | ||
s.write([ 'open', '<html>' ]); | ||
s.write([ 'open', '<body>' ]); | ||
s.write([ 'open', '<div>' ]); | ||
s.write([ 'open', '<b>' ]); | ||
s.write([ 'text', 'beep boop' ]); | ||
s.write([ 'close', '</b>' ]); | ||
s.write([ 'close', '<div>' ]); | ||
s.write([ 'close', '</body>' ]); | ||
s.write([ 'close', '</html>' ]); | ||
s.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
73664
2
31
1522
270
7
8
1
+ Addedcssauron@^1.1.0
+ Addedduplexer2@~0.0.2
+ Addedthrough2@^1.0.0
+ Addedcssauron@1.4.0(transitive)
+ Addedduplexer2@0.0.2(transitive)
+ Addedreadable-stream@1.1.14(transitive)
+ Addedthrough2@1.1.1(transitive)
+ Addedxtend@4.0.2(transitive)
- Removedobject-inspect@~0.4.0
- Removedshallow-copy@~0.0.1
- Removedobject-inspect@0.4.0(transitive)
- Removedreadable-stream@1.0.34(transitive)
- Removedshallow-copy@0.0.1(transitive)
Updatedinherits@^2.0.1
Updatedreadable-stream@^1.0.27-1