Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: pgte/woosh
base: 39cb9a1e1d
...
head fork: pgte/woosh
compare: master
Checking mergeability… Don't worry, you can still create the pull request.
  • 7 commits
  • 43 files changed
  • 0 commit comments
  • 1 contributor
Showing with 1,516 additions and 287 deletions.
  1. +1 −0  .gitignore
  2. +78 −0 README.markdown
  3. +0 −5 README.md
  4. +14 −0 example/select.html
  5. +11 −0 example/select.js
  6. +25 −0 example/update.html
  7. +14 −0 example/update.js
  8. +150 −0 index.js
  9. +97 −0 lib/map.js
  10. +127 −0 lib/node.js
  11. +242 −0 lib/select.js
  12. +42 −23 package.json
  13. +13 −0 test/attr.html
  14. +32 −0 test/attr.js
  15. +13 −0 test/attr_target.html
  16. +1 −0  test/{fixtures/template_one.html → compose.html}
  17. +67 −0 test/compose_streaming.js
  18. +41 −0 test/compose_target.html
  19. +35 −0 test/dsl.js
  20. +45 −0 test/dsl_compose_streaming.js
  21. +0 −4 test/fixtures/partial_one.html
  22. +0 −4 test/fixtures/partial_two.html
  23. +0 −32 test/fixtures/template_one_composed_target.html
  24. +0 −20 test/fixtures/template_one_composed_target_2.html
  25. +5 −0 test/partial.html
  26. +15 −0 test/script.html
  27. +18 −0 test/script.js
  28. +8 −0 test/script_replace.html
  29. +24 −0 test/script_replace.js
  30. +8 −0 test/script_replace_target.html
  31. +15 −0 test/select.html
  32. +33 −0 test/select.js
  33. +45 −0 test/selectors.html
  34. +49 −0 test/selectors.js
  35. +23 −0 test/special.html
  36. +47 −0 test/special.js
  37. +0 −161 test/test.js
  38. +30 −0 test/update.html
  39. +47 −0 test/update.js
  40. +38 −0 test/update_short.js
  41. +62 −0 test/update_streaming.js
  42. +1 −0  test/{fixtures/template_one_target.html → update_target.html}
  43. +0 −38 woosh.js
View
1  .gitignore
@@ -0,0 +1 @@
+node_modules
View
78 README.markdown
@@ -0,0 +1,78 @@
+Woosh
+=======
+
+Modified version of Substack's Trumpet:
+
+See https://github.com/substack/node-trumpet
+
+Supports streaming in a composable way, which means you can do:
+
+```js
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+var BufferedStream = require('bufferedstream');
+
+test('compose with streams', function (t) {
+ t.plan(2);
+ var html = fs.readFileSync(__dirname + '/compose_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/compose.html').pipe(tr);
+
+ var spans = [ 'tacos', 'y', 'burritos' ];
+
+ tr.select('.b span', function (node) {
+ node.update(function (html) {
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr);
+ return tr;
+ });
+ });
+
+ tr.select('.c', function (node) {
+ node.update(function() {
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr);
+ tr.select('.b span', function(node) {
+ node.update(function(html) {
+ return html.toUpperCase();
+ });
+ });
+ return tr;
+ });
+ });
+
+ tr.select('.d', function (node) {
+ node.remove();
+ });
+
+ tr.select('.e', function (node) {
+ node.remove();
+ });
+
+ tr.select('.f', function (node) {
+ node.replace(function() {
+ var stream = new BufferedStream();
+ stream.end('<b>NOTHING TO SEE HERE</b>');
+ return stream;
+ });
+ });
+
+ tr.select('.g', function (node) {
+ node.replace(function (html) {
+ t.equal(html, '<div class="g">EVERYTHING IS TERRIBLE</div>');
+ var stream = new BufferedStream();
+ stream.end('<blink>TERRIBLE</blink>');
+ return stream;
+ });
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
+```
View
5 README.md
@@ -1,5 +0,0 @@
-# UNDER CONSTRUCTION
-
-# Woosh
-
-Composable Streamable Templates.
View
14 example/select.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+ </div>
+ <div class="a">!!!</div>
+ </body>
+</html>
View
11 example/select.js
@@ -0,0 +1,11 @@
+var trumpet = require('../');
+var tr = trumpet();
+
+tr.select('.b span', function (node) {
+ node.html(function (html) {
+ console.log(node.name + ': ' + html);
+ });
+});
+
+var fs = require('fs');
+fs.createReadStream(__dirname + '/select.html').pipe(tr);
View
25 example/update.html
@@ -0,0 +1,25 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+ </div>
+ <div class="a">!!!</div>
+ <div class="e"><i><u>...</u></i></div>
+
+ <div class="c">
+ <span>beep</span>
+ <span>boop</span>
+ </div>
+
+ <div class="d">
+ <span>x</span>
+ <span>y</span>
+ </div>
+ </body>
+</html>
View
14 example/update.js
@@ -0,0 +1,14 @@
+var trumpet = require('../');
+var tr = trumpet();
+
+tr.update('.b span', function (html, node) {
+ return html.toUpperCase();
+});
+
+tr.update('.c', '---');
+tr.remove('.d');
+tr.remove('.e');
+
+var fs = require('fs');
+tr.pipe(process.stdout, { end : false });
+fs.createReadStream(__dirname + '/update.html').pipe(tr);
View
150 index.js
@@ -0,0 +1,150 @@
+var sax = require('sax-pausable');
+var select = require('./lib/select');
+var map = require('./lib/map');
+var BufferedStream = require('bufferedstream');
+var Middle = require('middle');
+
+module.exports = function (opts) {
+ if (!opts) opts = {};
+ if (!opts.special) {
+ opts.special = [
+ 'area', 'base', 'basefont', 'br', 'col',
+ 'hr', 'input', 'img', 'link', 'meta'
+ ];
+ }
+ opts.special = opts.special.map(function (x) { return x.toUpperCase() });
+ if (! opts.bufferSize) { opts.bufferSize = 1024; }
+
+ var parser = sax.parser(false);
+ var stream = select(parser, opts);
+
+ var bufferedStream = new BufferedStream(opts.bufferSize);
+ var middle = new Middle(bufferedStream, stream);
+
+ middle.select = function() {
+ return stream.select.apply(stream, arguments);
+ };
+ middle.update = function() {
+ return stream.update.apply(stream, arguments);
+ };
+ middle.remove = function() {
+ return stream.remove.apply(stream, arguments);
+ };
+ middle.replace = function() {
+ return stream.replace.apply(stream, arguments);
+ };
+
+ parser.onerror = function (err) {
+ stream.emit("error", err)
+ }
+
+ function write (buf) {
+ stream.emit('data', buf);
+ }
+
+ var buffered = '';
+ var pos = 0;
+ var update = function (type, tag, done) {
+ if (typeof tag === 'function') {
+ done = tag;
+ tag = undefined;
+ }
+
+ if (type === 'script') {
+ var len = tag.length;
+ }
+ else if (type === 'text') {
+ var len = parser.startTagPosition - pos - 1;
+ }
+ else if (type === 'open' && tag && tag.name === 'SCRIPT'
+ && tag.attributes.src) {
+ var len = 0;
+ }
+ else {
+ var len = parser.position - parser.startTagPosition + 1;
+ }
+ pos = parser.position;
+
+ var src = buffered.slice(0, len);
+ buffered = buffered.slice(len);
+
+ stream.raw(src, done);
+ return src;
+ };
+
+ stream.write = function (buf) {
+ var s = buf.toString();
+ buffered += s;
+ parser.write(buf.toString());
+ };
+
+ stream.end = function (buf, next) {
+ if (buf !== undefined) stream.write(buf);
+
+ if (pos < parser.position) {
+ var s = buffered.slice(0, parser.position - pos);
+ stream.raw(s);
+ }
+ parser.close();
+
+ };
+
+ parser.onopentag = function (tag) {
+ stream.pre('open', tag);
+ update('open', tag, function() {
+ stream.post('open', tag);
+ });
+ };
+
+ parser.onend = function() {
+ stream.emit('end');
+ };
+
+ //
+ // Pausing and resuming
+ //
+
+ var paused = false;
+
+ oldResume = parser.resume;
+ parser.resume = function() {
+ paused = false;
+ oldResume.call(parser);
+ bufferedStream.resume();
+ };
+
+ oldPause = parser.pause;
+ parser.pause = function() {
+ bufferedStream.pause();
+ paused = true;
+ oldPause.call(parser);
+ };
+
+ parser.onclosetag = function (name) {
+ parser.pause();
+ stream.pre('close', name, function() {
+ update('close', function() {
+ stream.post('close', name);
+ parser.resume();
+ });
+ });
+ };
+
+ parser.ontext = function (text) {
+ stream.pre('text', text);
+ update('text', function() {
+ stream.post('text', text);
+ });
+ };
+
+ parser.onscript = function (src) {
+ stream.pre('script', src);
+ update('script', src, function() {
+ stream.post('script', src);
+ });
+ };
+
+ middle.map = map;
+
+ return middle;
+};
View
97 lib/map.js
@@ -0,0 +1,97 @@
+var Stream = require('stream').Stream;
+var BufferedStream = require('bufferedstream');
+
+var actions = ['remove', 'replace', 'update'];
+
+function actionFromVal(val) {
+ var remainingActions = actions.filter(function(action) {
+ return val.hasOwnProperty(action);
+ });
+ if (! remainingActions.length) return;
+ if (remainingActions.length > 1) {
+ try {
+ throw new Error('Ambiguous action, don\'t know what to do with' + JSON.stringify(val));
+ } catch (e) {
+ throw new Error('Ambiguous action, don\'t know what to do with it:' + val.toString());
+ }
+ }
+ return remainingActions[0];
+}
+
+function handleStream(selector, action, stream) {
+ var buffer = [], ended = false;
+ stream.on('data', function(d) { buffer.push(d); });
+ stream.on('end', function() { ended = true; });
+
+ this.select(selector, function(node) {
+ node[action](function(html) {
+ var index = 0;
+ var bs = new BufferedStream();
+
+ (function flush() {
+ if (buffer.length > index) {
+ bs.write(buffer[index]);
+ index ++;
+ }
+ if (buffer.length > index || ! ended) {
+ process.nextTick(flush);
+ } else {
+ bs.end();
+ }
+ }());
+
+ return bs;
+ });
+ });
+}
+
+function map(mapping) {
+ var self = this;
+
+ if (typeof mapping !== 'object') {
+ throw new Error('Map argument should be object literal');
+ }
+
+ Object.keys(mapping).forEach(function(selector) {
+ var val = mapping[selector];
+
+ switch (typeof val) {
+
+ case 'string':
+ case 'function':
+
+ self.update(selector, val);
+
+ break;
+
+ case 'object':
+
+ if (val instanceof Stream) {
+
+ handleStream.call(self, selector, 'update', val);
+
+ } else {
+
+ var action = actionFromVal(val);
+ if (! action) {
+ throw new Error('Value for selector `' + selector +
+ '` should contain action field, either remove, replace or update');
+ }
+ var replaceBy = val[action];
+ if (replaceBy instanceof Stream) {
+ handleStream.call(self, selector, action, replaceBy);
+ } else {
+ self[action](selector, replaceBy);
+ }
+ }
+
+ break;
+
+ default:
+ throw new Error('Invalid type of value ' + (typeof val) + ' for selector `' + selector + '`');
+
+ }
+ });
+}
+
+module.exports = map;
View
127 lib/node.js
@@ -0,0 +1,127 @@
+var ent = require('ent');
+var Stream = require('stream').Stream;
+
+module.exports = function (tag, sel, level) {
+ return new Node(tag, sel, level);
+};
+
+function expire () {
+ throw new Error('Parse expired. You had your chance.');
+}
+
+function Node (tag, sel, level) {
+ this.name = tag.name.toLowerCase();
+ this.attributes = tag.attributes;
+ this.p = { level : level };
+
+ this.tag = tag;
+ this.sel = sel;
+}
+
+function emit(value, out, done) {
+ var self = this;
+ var sel = self.sel;
+
+ if (value instanceof Stream) {
+ var stream = value;
+ stream.on('data', function(d) {
+ out.emit('data', d);
+ });
+ stream.on('end', function() {
+ sel.updating = false;
+ done();
+ });
+ } else {
+ out.emit('data', value);
+ sel.updating = false;
+ done();
+ }
+}
+
+Node.prototype.html = function (cb) {
+ var p = this.p, sel = this.sel;
+ if (this.expired) expire();
+
+ p.buffered = '';
+ p.callback = function(html, final, done) {
+ cb(html);
+ done();
+ };
+ p.writes = 0;
+ sel.pending.push(p);
+};
+
+Node.prototype.update = function (cb, attrs) {
+ var self = this;
+ var p = self.p, sel = self.sel;
+ if (self.expired) expire();
+ if (typeof cb === 'object') {
+ attrs = cb;
+ cb = String; // identify function
+ }
+
+ if (attrs) {
+ var attrText = Object.keys(attrs).map(function (key) {
+ return key + '="' + ent.encode(attrs[key]) + '"';
+ }).join(' ');
+
+ if (attrText.length) attrText = ' ' + attrText;
+ var isSpecial = sel.special.indexOf(self.name) >= 0;
+
+ p.buffered = '';
+ p.callback = function (html, final, done) {
+ var this_ = this;
+ final(function (s, done) {
+ var d = typeof cb === 'function' ? cb(html) : cb;
+ var data = '<' + self.name + attrText + '>' + d;
+ emit.call(self, data + s, this_, done);
+ });
+ sel.updating = false;
+ done();
+ };
+ sel.updating = true;
+ sel.removing = true;
+ sel.pending.push(p);
+ p.writes = 0;
+
+ return;
+ }
+
+ p.buffered = '';
+ p.callback = function (html, final, done) {
+ emit.call(self, typeof cb === 'function' ? cb(html) : cb, this, done);
+ };
+ p.writes = 0;
+ sel.updating = true;
+ sel.pending.push(p);
+};
+
+Node.prototype.replace = function (cb) {
+ var self = this, p = this.p, sel = this.sel;
+ if (this.expired) expire();
+
+ p.buffered = '';
+ p.callback = function (html, final, done) {
+ var this_ = this;
+ final(function (s, done) {
+ emit.call(self, typeof cb === 'function' ? cb(html + s) : cb, this_, done);
+ });
+ sel.updating = false;
+ done();
+ };
+ sel.updating = true;
+ sel.removing = true;
+ sel.pending.push(p);
+};
+
+Node.prototype.remove = function () {
+ var p = this.p, sel = this.sel;
+ if (this.expired) expire();
+ sel.updating = true;
+ sel.removing = true;
+ p.callback = function (html, final, done) {
+ sel.updating = false;
+ done();
+ };
+ sel.pending.push(p);
+};
View
242 lib/select.js
@@ -0,0 +1,242 @@
+var Stream = require('stream').Stream;
+var async = require('async');
+var createNode = require('./node');
+
+module.exports = function (parser, opts) {
+ var stream = new Stream;
+ stream.writable = true;
+ stream.readable = true;
+
+ var selectors = [];
+
+ stream.select = function (s, fn) {
+ var sel = createSelector(s, fn, opts.special);
+ selectors.push(sel);
+ return stream;
+ };
+
+ stream.update = function (s, fn) {
+ return stream.select(s, function (node) {
+ if (typeof fn === 'function') {
+ node.update(function (html) { return fn(html, node); });
+ }
+ else node.update(fn);
+ });
+ };
+
+ stream.remove = function (s, fn) {
+ return stream.select(s, function (node) {
+ node.remove();
+ if (typeof fn === 'function') fn(node);
+ });
+ };
+
+ stream.replace = function (s, fn) {
+ return stream.select(s, function (node) {
+ if (typeof fn === 'function') {
+ node.replace(function (html) { return fn(html, node); });
+ }
+ else node.replace(fn);
+ });
+ };
+
+ var updating = false;
+
+ stream.pre = function (name, t, cb) {
+ var this_ = this;
+
+ function callback() {
+ if (cb) { cb.apply(this_, arguments); }
+ }
+
+ if (name === 'open') {
+ selectors.forEach(function (sel) {
+ sel(t, parser);
+ if (sel.removing) updating = true;
+ });
+ callback();
+ }
+ else if (name === 'close') {
+ var level = parser.tags.reduce(function (sum, t) {
+ return sum + (opts.special.indexOf(t.name) < 0 ? 1 : 0);
+ }, 0);
+
+ async.forEach(selectors, function(sel, done) {
+ var up = sel.updating;
+ async.filter(sel.pending, function(p, next) {
+ var done = level < p.level;
+ if (done && sel.removing) {
+ p.callback.call(stream, p.buffered, function (cb) {
+ sel.nextRaw.push(cb);
+ }, function() {
+ next(! done);
+ });
+ }
+ else {
+ if (done) p.callback.call(stream, p.buffered, undefined, function() {
+ next (! done);
+ });
+ else next(! done);
+ }
+ }, function(pending) {
+ sel.pending = pending;
+
+ if (up && !sel.updating) {
+ if (sel.removing) {
+ sel.removeOnPost = true;
+ }
+ else updating = false;
+ }
+
+ done();
+ });
+ }, callback);
+ }
+ };
+
+ stream.post = function (name, t) {
+ if (name === 'open') {
+ selectors.forEach(function (sel) {
+ if (sel.updating) {
+ updating = true;
+ }
+ sel.pending.forEach(function (p) {
+ if (p.writes === 0) {
+ p.buffered = '';
+ }
+ if (typeof p.writes === 'number') p.writes ++;
+ });
+ });
+
+ for (var i = 0; i < parser.tags.length; i++) {
+ var t = parser.tags[i];
+ if (opts.special.indexOf(t.name) >= 0) {
+ parser.tags.splice(i, 1);
+ i--;
+ }
+ }
+ }
+ else if (name == 'close') {
+ selectors.forEach(function (sel) {
+ if (sel.removeOnPost) {
+ updating = false;
+ sel.removing = false;
+ sel.removeOnPost = false;
+ }
+ });
+ }
+ };
+
+ stream.raw = function (s, done) {
+ async.forEach(selectors, function (sel, next) {
+ async.forEach(sel.nextRaw.splice(0), function(cb, next) {
+ cb(s, next);
+ }, function() {
+ sel.pending.forEach(function (p) {
+ p.buffered += s;
+ });
+ next();
+ });
+ }, function() {
+ if (!updating) stream.emit('data', s);
+ if (done) { done(); }
+ });
+ };
+
+ stream.pause = function() {
+ parser.pause();
+ };
+
+ stream.resume = function() {
+ parser.resume();
+ };
+
+ return stream;
+};
+
+function createSelector (selector, fn, special) {
+ var saveSiblings = false;
+ var parts = selector.split(/([\s>+]+)/).map(function (s) {
+ if (s.match(/^\s+$/)) return;
+
+ var op = s.trim();
+ if (op === '+') saveSiblings = true;
+ if (op === '>' || op === '+') return { combinator : op };
+
+ var m = {
+ name : s.match(/^([\w-]+|\*)/),
+ class : s.match(/\.([\w-]+)/),
+ id : s.match(/#([\w-]+)/),
+ pseudo : s.match(/:([\w-]+)/),
+ attribute : s.match(/\[([^\]]+)\]/),
+ };
+
+ return {
+ name : m.name && m.name[1].toUpperCase(),
+ class : m.class && m.class[1],
+ id : m.id && m.id[1],
+ pseudo : m.pseudo && m.pseudo[1],
+ attribute : m.attribute && m.attribute[1],
+ };
+ }).filter(Boolean);
+
+ var depth = parts.reduce(function (sum, s) {
+ return sum + (s.combinator ? 0 : 1);
+ }, 0);
+
+ var siblings = [];
+
+ var sel = function (tag, parser) {
+ var tags = parser.tags;
+
+ if (!siblings[tags.length]) siblings[tags.length] = [];
+ siblings[tags.length].push(tag);
+
+ if (depth > tags.length) return;
+
+ // hypothesis: the selector matches
+ var j = parts.length - 1;
+ var i = tags.length - 1;
+
+ function check (t, p) {
+ // try to falsify the hypothesis on each tag/part match:
+ if (p.name !== '*' && p.name && p.name !== t.name) return false;
+ if (p.class && p.class !== t.attributes.class) return false;
+ if (p.id && p.id !== t.attributes.id) return false;
+ return true;
+ }
+
+ for (; j >= 0; j--, i--) {
+ var t = tags[i];
+ var p = parts[j];
+ if (p.combinator === '>') {
+ for (var ii = i; ii >= 0; ii--) {
+ if (check(tags[ii], parts[j-1])) {
+ break;
+ }
+ }
+ if (ii < 0) return;
+ j -= 2;
+ }
+ else if (p.combinator === '+') {
+ var ts = siblings[i + 2];
+ t = ts[ts.length - 2];
+ if (!t) return;
+ p = parts[j - 1];
+ if (!check(t, p)) return;
+ j -= 2;
+ }
+ else if (!check(t, p)) return;
+ }
+
+ var node = createNode(tag, sel, tags.length);
+ fn(node);
+ node.expired = true;
+ };
+
+ sel.special = special;
+ sel.pending = [];
+ sel.nextRaw = [];
+
+ return sel;
+}
View
65 package.json
@@ -1,24 +1,43 @@
{
- "name": "woosh",
- "description": "Streaming composable templates",
- "version": "0.0.1",
- "author": {
- "name": "Pedro Teixeira"
- },
- "repository": {
- "type": "git",
- "url": "http://github.com/pgte/woosh.git"
- },
- "tags": ["streaming", "http", "framework"],
- "main": "./woosh.js",
- "engines": { "node": ">= 0.6.0" },
- "dependencies": {
- "trumpet": "*"
- },
- "devDependencies": {
- "tap": "*"
- },
- "scripts": {
- "test": "node node_modules/tap/bin/tap.js test/test.js"
- }
-}
+ "name" : "woosh",
+ "version" : "0.1.1",
+ "description" : "parse and transform streaming html using css selectors in a composable way",
+ "main" : "index.js",
+ "directories" : {
+ "lib" : ".",
+ "example" : "example",
+ "test" : "test"
+ },
+ "dependencies" : {
+ "sax-pausable" : "0.1.x",
+ "ent" : "~0.0.4",
+ "bufferedstream": "1.0.x",
+ "middle": "0.0.x",
+ "async": "0.1.x"
+ },
+ "devDependencies" : {
+ "tap" : "~0.2.3"
+ },
+ "scripts" : {
+ "test" : "tap test/*.js"
+ },
+ "repository" : {
+ "type" : "git",
+ "url" : "http://github.com/pgte/woosh.git"
+ },
+ "keywords" : [
+ "html",
+ "streaming",
+ "parser",
+ "transform",
+ "selectors",
+ "css"
+ ],
+ "author" : {
+ "name" : "Pedro Teixeira",
+ "email" : "pedro.teixeira@gmail.com",
+ "url" : "http://metaduck.com"
+ },
+ "license" : "MIT/X11",
+ "engine" : { "node" : ">=0.8" }
+}
View
13 test/attr.html
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <title>beep</title>
+ <link rel=stylesheet href="/beepity.css">
+ </head>
+ <body>
+ <div class="b">
+ <span foo="x">tacos</span>
+ <span bar="y">y</span>
+ <span baz="z">burritos</span>
+ </div>
+ </body>
+</html>
View
32 test/attr.js
@@ -0,0 +1,32 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('attr update', function (t) {
+ var html = fs.readFileSync(__dirname + '/attr_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/attr.html').pipe(tr);
+
+ var names = [ 'foo', 'bar', 'baz' ];
+ var attrMap = { foo : 'X', bar : 'YY', baz : 'ZZZ' };
+
+ tr.select('.b span', function (node) {
+ var attrs = node.attributes;
+ var name = names.shift();
+ t.ok(attrs[name]);
+ attrs[name] = attrMap[name];
+
+ node.update(function (html) {
+ return '¡' + html.toUpperCase() + '!';
+ }, attrs);
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ t.end();
+ });
+});
View
13 test/attr_target.html
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <title>beep</title>
+ <link rel=stylesheet href="/beepity.css">
+ </head>
+ <body>
+ <div class="b">
+ <span foo="X">¡TACOS!</span>
+ <span bar="YY">¡Y!</span>
+ <span baz="ZZZ">¡BURRITOS!</span>
+ </div>
+ </body>
+</html>
View
1  test/fixtures/template_one.html → test/compose.html
@@ -25,5 +25,6 @@
<h1>TOP SECRET</h1>
<div>THE MOON IS A HOAX.</div>
</div>
+ <div class="g">EVERYTHING IS TERRIBLE</div>
</body>
</html>
View
67 test/compose_streaming.js
@@ -0,0 +1,67 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+var BufferedStream = require('bufferedstream');
+
+test('compose with streams', function (t) {
+ t.plan(2);
+ var html = fs.readFileSync(__dirname + '/compose_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/compose.html').pipe(tr);
+
+ var spans = [ 'tacos', 'y', 'burritos' ];
+
+ tr.select('.b span', function (node) {
+ node.update(function (html) {
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr);
+ return tr;
+ });
+ });
+
+ tr.select('.c', function (node) {
+ node.update(function() {
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr);
+ tr.select('.b span', function(node) {
+ node.update(function(html) {
+ return html.toUpperCase();
+ });
+ });
+ return tr;
+ });
+ });
+
+ tr.select('.d', function (node) {
+ node.remove();
+ });
+
+ tr.select('.e', function (node) {
+ node.remove();
+ });
+
+ tr.select('.f', function (node) {
+ node.replace(function() {
+ var stream = new BufferedStream();
+ stream.end('<b>NOTHING TO SEE HERE</b>');
+ return stream;
+ });
+ });
+
+ tr.select('.g', function (node) {
+ node.replace(function (html) {
+ t.equal(html, '<div class="g">EVERYTHING IS TERRIBLE</div>');
+ var stream = new BufferedStream();
+ stream.end('<blink>TERRIBLE</blink>');
+ return stream;
+ });
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
View
41 test/compose_target.html
@@ -0,0 +1,41 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span><div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+</div>
+</span>
+ <span><div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+</div>
+</span>
+ <span><div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+</div>
+</span>
+ </div>
+ <div class="a">!!!</div>
+
+
+ <div class="c"><div class="b">
+ <span>TACOS</span>
+ <span>Y</span>
+ <span>BURRITOS</span>
+</div>
+</div>
+
+
+ <b>NOTHING TO SEE HERE</b>
+ <blink>TERRIBLE</blink>
+ </body>
+</html>
View
35 test/dsl.js
@@ -0,0 +1,35 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('supports a mapping DSL', function (t) {
+ t.plan(1);
+ var html = fs.readFileSync(__dirname + '/update_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/update.html').pipe(tr);
+
+ tr.map({
+ '.b span': function(html) {
+ return html.toUpperCase();
+ },
+
+ '.c': '---',
+
+ '.d': { remove: true },
+
+ '.e': { remove: true },
+
+ '.f': { replace: '<b>NOTHING TO SEE HERE</b>' },
+
+ '.g': { replace: '<blink>TERRIBLE</blink>' }
+ });
+
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf; });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
View
45 test/dsl_compose_streaming.js
@@ -0,0 +1,45 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+var BufferedStream = require('bufferedstream');
+
+test('compose with streams', function (t) {
+ t.plan(1);
+ var html = fs.readFileSync(__dirname + '/compose_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/compose.html').pipe(tr);
+
+ var tr2 = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr2);
+
+ var tr3 = trumpet();
+ fs.createReadStream(__dirname + '/partial.html').pipe(tr3);
+ tr3.select('.b span', function(node) {
+ node.update(function(html) {
+ return html.toUpperCase();
+ });
+ });
+
+ var stream = new BufferedStream();
+ stream.end('<b>NOTHING TO SEE HERE</b>');
+
+ var stream2 = new BufferedStream();
+ stream2.end('<blink>TERRIBLE</blink>');
+
+ tr.map({
+ '.b span': tr2,
+ '.c': tr3,
+ '.d': { remove: true },
+ '.e': { remove: true },
+ '.f': { replace: stream },
+ '.g': { replace: stream2}
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
View
4 test/fixtures/partial_one.html
@@ -1,4 +0,0 @@
-<div class="d">
- <span>x</span>
- <span>y</span>
-</div>
View
4 test/fixtures/partial_two.html
@@ -1,4 +0,0 @@
-<div class="e">
- <span>x</span>
- <span>y</span>
-</div>
View
32 test/fixtures/template_one_composed_target.html
@@ -1,32 +0,0 @@
-<html>
- <head>
- <title>beep</title>
- </head>
- <body>
- <div class="a">¡¡¡</div>
- <div class="b">
- <span><div class="d">
- <span>x</span>
- <span>y</span>
-</div></span>
- <span><div class="d">
- <span>x</span>
- <span>y</span>
-</div></span>
- <span><div class="d">
- <span>x</span>
- <span>y</span>
-</div></span>
- </div>
- <div class="a">!!!</div>
-
-
- <div class="c">---</div>
-
-
- <div class="e">
- <span>x</span>
- <span>y</span>
-</div>
- </body>
-</html>
View
20 test/fixtures/template_one_composed_target_2.html
@@ -1,20 +0,0 @@
-<html>
- <head>
- <title>beep</title>
- </head>
- <body>
- <div class="a">¡¡¡</div>
- <div class="b">
- <span><div class="d">HAHA</div></span>
- <span><div class="d">HAHA</div></span>
- <span><div class="d">HAHA</div></span>
- </div>
- <div class="a">!!!</div>
-
-
- <div class="c">---</div>
-
-
- HEHE
- </body>
-</html>
View
5 test/partial.html
@@ -0,0 +1,5 @@
+<div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+</div>
View
15 test/script.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+ <script type="text/javascript">console.log(i<j)</script>
+ </div>
+ <div class="a">!!!</div>
+ </body>
+</html>
View
18 test/script.js
@@ -0,0 +1,18 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('script', function (t) {
+ t.plan(2);
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/script.html').pipe(tr);
+
+ tr.select('script', function (node) {
+ t.equal(node.attributes.type, 'text/javascript');
+ node.html(function (src) {
+ t.equal(src, 'console.log(i<j)');
+ t.end();
+ });
+ });
+});
View
8 test/script_replace.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>beep</title>
+ <script src="replace_me.js"></script>
+ </head>
+ <body>
+ </body>
+</html>
View
24 test/script_replace.js
@@ -0,0 +1,24 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('script replace', function (t) {
+ var html = fs.readFileSync(__dirname + '/script_replace_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/script_replace.html').pipe(tr);
+
+ tr.select('script', function (node) {
+ node.replace(function (html) {
+ return '<script>beepBoop()</script>';
+ });
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ t.end();
+ });
+});
View
8 test/script_replace_target.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>beep</title>
+ <script>beepBoop()</script>
+ </head>
+ <body>
+ </body>
+</html>
View
15 test/select.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+ </div>
+ <div class="a">!!!</div>
+ <div class="c"><b>beep</b><i>boop</i></div>
+ </body>
+</html>
View
33 test/select.js
@@ -0,0 +1,33 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('select', function (t) {
+ t.plan(11);
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/select.html').pipe(tr);
+
+ var spans = [ 'tacos', 'y', 'burritos' ];
+
+ tr.select('.b span', function (node) {
+ t.deepEqual(node.attributes, {});
+ node.html(function (html) {
+ t.equal(html, spans.shift());
+ });
+ });
+
+ var as = [ '¡¡¡', '!!!' ];
+ tr.select('.a', function (node) {
+ t.deepEqual(node.attributes, { class : 'a' });
+ node.html(function (html) {
+ t.equal(html, as.shift());
+ });
+ });
+
+ tr.select('.c', function (node) {
+ node.html(function (html) {
+ t.equal(html, '<b>beep</b><i>boop</i>');
+ });
+ });
+});
View
45 test/selectors.html
@@ -0,0 +1,45 @@
+<html>
+ <head>
+ <title>beep</title>
+ <link rel=stylesheet href="/beepity.css">
+ </head>
+ <body>
+ <div class="b">
+ <span>tacos</span>
+ <span><b><u>y</u></b></span>
+ <span><i>burritos</i></span>
+ </div>
+
+ <div class="c">C</div>
+ <div class="d">D</div>
+
+ <div class="e">
+ <span class="x">X</span>
+ <span class="y">Y</span>
+ <span class="z">Z</span>
+
+ <div class="q">
+ <div class="r">
+ <div class="s">
+ <span class="m"></span>
+ <span class="n">
+ <beep>
+ <span class="v">vvv</span>
+ <span class="u">
+ <v>vvv</v>
+ <w>www</w>
+ </span>
+ </beep>
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="f"></div>
+ <div class="e">
+ <span class="y">FALSEY</span>
+ <span class="z">FALSEZ</span>
+ </div>
+ </body>
+</html>
View
49 test/selectors.js
@@ -0,0 +1,49 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('select', function (t) {
+ t.plan(6);
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/selectors.html').pipe(tr);
+
+ tr.select('* u', function (node) {
+ t.equal(node.name, 'u');
+ node.html(function (html) {
+ t.equal(html, 'y');
+ });
+ });
+
+ tr.select('.b > i', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'burritos');
+ });
+ });
+
+ tr.select('span > div', function (node) {
+ t.fail('there are no divs inside spans');
+ });
+
+ tr.select('.b + .c', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'C');
+ });
+ });
+
+ tr.select('.d + .e .y + .z', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'Z');
+ });
+ });
+
+ tr.select('.b + .d', function (node) {
+ t.fail('b is not an immediate sibling of d');
+ });
+
+ tr.select('.q > .s .m + .n * .v + .u v + w', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'www');
+ });
+ });
+});
View
23 test/special.html
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">
+ <img src="/beep.png">
+ <div class="b">boop</div>
+ </div>
+
+ <input type="text">
+
+ <div class="c">
+ <input type="text">
+ <br>
+ <input type="password">
+ <br>
+ <div class="d">wooo</div>
+ <hr>
+ <input type="submit">
+ </div>
+ </body>
+</html>
View
47 test/special.js
@@ -0,0 +1,47 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('special tags', function (t) {
+ t.plan(10);
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/special.html').pipe(tr);
+
+ tr.select('.a .b', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'boop');
+ });
+ });
+
+ tr.select('.c .d', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'wooo');
+ });
+ });
+
+ var types = [ 'text', 'text', 'password', 'submit' ];
+ tr.select('input', function (node) {
+ t.equal(node.attributes.type, types.shift());
+ });
+
+ tr.select('hr + input', function (node) {
+ t.equal(node.attributes.type, 'submit');
+ });
+
+ tr.select('br + .d', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'wooo');
+ });
+ });
+
+ tr.select('img + .b', function (node) {
+ node.html(function (html) {
+ t.equal(html, 'boop');
+ });
+ });
+
+ tr.select('.d + hr', function (node) {
+ t.equal(node.name, 'hr');
+ });
+});
View
161 test/test.js
@@ -1,161 +0,0 @@
-var test = require('tap').test
- , woosh = require('../')
- , fs = require('fs')
-
-
-test('template one synchronously', function(t) {
- var html = fs.readFileSync(__dirname + '/fixtures/template_one_target.html', 'utf8')
- var stream = woosh(__dirname + '/fixtures/template_one.html');
-
- stream('.b span', function(node) {
- node.update(function(html) { return html.toUpperCase() })
- })
- ('.c', function (node) {
- node.update('---')
- })
- ('.d', function (node) {
- node.remove()
- })
- ('.e', function (node) {
- node.remove()
- })
- ('.f', function (node) {
- node.replace('<b>NOTHING TO SEE HERE</b>')
- })
- ;
-
- var data = ''
- stream.on('data', function (buf) { data += buf })
-
- stream.on('end', function () {
- t.equal(data, html)
- t.end()
- })
-})
-
-test('template one synchronously with options object', function(t) {
- var html = fs.readFileSync(__dirname + '/fixtures/template_one_target.html', 'utf8')
- var selectors = {
- '.b span':
- function(node) {
- node.update(function(html) { return html.toUpperCase() })
- }
- , '.c': '---'
- , '.d':
- function (node) {
- node.remove()
- }
- , '.e':
- function (node) {
- node.remove()
- }
- , '.f':
- function (node) {
- node.replace('<b>NOTHING TO SEE HERE</b>')
- }
- }
-
- var stream = woosh(__dirname + '/fixtures/template_one.html', selectors);
-
- var data = ''
- stream.on('data', function (buf) { data += buf })
-
- stream.on('end', function () {
- t.equal(data, html)
- t.end()
- })
-})
-
-test('template one asynchronously', function(t) {
- var html = fs.readFileSync(__dirname + '/fixtures/template_one_target.html', 'utf8')
- var stream = woosh(__dirname + '/fixtures/template_one.html');
-
- stream('.b span', function(node) {
- node.update(function(html, done) { setTimeout(function() { done(html.toUpperCase()) }, 100) })
- })
- ('.c', function (node) {
- node.update('---')
- })
- ('.d', function (node) {
- node.remove()
- })
- ('.e', function (node) {
- node.remove()
- })
- ('.f', function (node) {
- node.replace(function(html, done) { setTimeout(function() { done('<b>NOTHING TO SEE HERE</b>') }, 100) })
- })
- ;
-
- var data = ''
- stream.on('data', function (buf) { data += buf })
-
- stream.on('end', function () {
- t.equal(data, html)
- t.end()
- })
-})
-
-test('compose 1 with no inner changes', function(t) {
- var html = fs.readFileSync(__dirname + '/fixtures/template_one_composed_target.html', 'utf8')
- var stream = woosh(__dirname + '/fixtures/template_one.html');
-
- stream('.b span', function(node) {
- node.update(function(html, done) {
- done(woosh(__dirname + '/fixtures/partial_one.html'))
- })
- })
- ('.c', function (node) {
- node.update('---')
- })
- ('.d', function (node) {
- node.remove()
- })
- ('.e', function (node) {
- node.remove()
- })
- ('.f', function (node) {
- node.replace(woosh(__dirname + '/fixtures/partial_two.html'))
- })
- ;
-
- var data = ''
- stream.on('data', function (buf) { data += buf })
-
- stream.on('end', function () {
- t.equal(data, html)
- t.end()
- })
-})
-
-test('compose 1 with some inner changes', function(t) {
- var html = fs.readFileSync(__dirname + '/fixtures/template_one_composed_target_2.html', 'utf8')
- var stream = woosh(__dirname + '/fixtures/template_one.html');
-
- stream('.b span', function(node) {
- node.update(function(html, done) {
- done(woosh(__dirname + '/fixtures/partial_one.html', {'.d': 'HAHA'}))
- })
- })
- ('.c', function (node) {
- node.update('---')
- })
- ('.d', function (node) {
- node.remove()
- })
- ('.e', function (node) {
- node.remove()
- })
- ('.f', function (node) {
- node.replace(woosh(__dirname + '/fixtures/partial_two.html', {'.e': function(node) { node.replace('HEHE')}}))
- })
- ;
-
- var data = ''
- stream.on('data', function (buf) { data += buf })
-
- stream.on('end', function () {
- t.equal(data, html)
- t.end()
- })
-})
View
30 test/update.html
@@ -0,0 +1,30 @@
+<html>
+ <head>
+ <title>beep</title>
+ </head>
+ <body>
+ <div class="a">¡¡¡</div>
+ <div class="b">
+ <span>tacos</span>
+ <span>y</span>
+ <span>burritos</span>
+ </div>
+ <div class="a">!!!</div>
+ <div class="e"><span>...</span></div>
+
+ <div class="c">
+ <span>beep</span>
+ <span>boop</span>
+ </div>
+
+ <div class="d">
+ <span>x</span>
+ <span>y</span>
+ </div>
+ <div class="f">
+ <h1>TOP SECRET</h1>
+ <div>THE MOON IS A HOAX.</div>
+ </div>
+ <div class="g">EVERYTHING IS TERRIBLE</div>
+ </body>
+</html>
View
47 test/update.js
@@ -0,0 +1,47 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('update', function (t) {
+ t.plan(2);
+ var html = fs.readFileSync(__dirname + '/update_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/update.html').pipe(tr);
+
+ tr.select('.b span', function (node) {
+ node.update(function (html) {
+ return html.toUpperCase();
+ });
+ });
+
+ tr.select('.c', function (node) {
+ node.update('---');
+ });
+
+ tr.select('.d', function (node) {
+ node.remove();
+ });
+
+ tr.select('.e', function (node) {
+ node.remove();
+ });
+
+ tr.select('.f', function (node) {
+ node.replace('<b>NOTHING TO SEE HERE</b>');
+ });
+
+ tr.select('.g', function (node) {
+ node.replace(function (html) {
+ t.equal(html, '<div class="g">EVERYTHING IS TERRIBLE</div>');
+ return '<blink>TERRIBLE</blink>';
+ });
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
View
38 test/update_short.js
@@ -0,0 +1,38 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+
+test('update', function (t) {
+ t.plan(7);
+ var html = fs.readFileSync(__dirname + '/update_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/update.html').pipe(tr);
+
+ var spans = [ 'tacos', 'y', 'burritos' ];
+
+ tr.update('.b span', function (html, node) {
+ t.equal(node.name, 'span');
+ return html.toUpperCase();
+ });
+
+ tr.update('.c', '---');
+ tr.remove('.d');
+ tr.remove('.e');
+ tr.replace('.f', '<b>NOTHING TO SEE HERE</b>');
+
+ tr.replace('.g', function (html, node) {
+ t.equal(node.name, 'div');
+ t.same(node.attributes, { class : 'g' });
+ t.equal(html, '<div class="g">EVERYTHING IS TERRIBLE</div>');
+ return '<blink>TERRIBLE</blink>';
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ t.end();
+ });
+});
View
62 test/update_streaming.js
@@ -0,0 +1,62 @@
+var test = require('tap').test;
+var trumpet = require('../');
+var fs = require('fs');
+var BufferedStream = require('bufferedstream');
+
+test('update streaming', function (t) {
+ t.plan(2);
+ var html = fs.readFileSync(__dirname + '/update_target.html', 'utf8');
+
+ var tr = trumpet();
+ fs.createReadStream(__dirname + '/update.html').pipe(tr);
+
+ var spans = [ 'tacos', 'y', 'burritos' ];
+
+ tr.select('.b span', function (node) {
+ node.update(function (html) {
+ var stream = new BufferedStream();
+ stream.end(html.toUpperCase());
+ return stream;
+ });
+ });
+
+ tr.select('.c', function (node) {
+ node.update(function() {
+ var stream = new BufferedStream();
+ stream.end('---');
+ return stream;
+ });
+ });
+
+ tr.select('.d', function (node) {
+ node.remove();
+ });
+
+ tr.select('.e', function (node) {
+ node.remove();
+ });
+
+ tr.select('.f', function (node) {
+ node.replace(function() {
+ var stream = new BufferedStream();
+ stream.end('<b>NOTHING TO SEE HERE</b>');
+ return stream;
+ });
+ });
+
+ tr.select('.g', function (node) {
+ node.replace(function (html) {
+ t.equal(html, '<div class="g">EVERYTHING IS TERRIBLE</div>');
+ var stream = new BufferedStream();
+ stream.end('<blink>TERRIBLE</blink>');
+ return stream;
+ });
+ });
+
+ var data = '';
+ tr.on('data', function (buf) { data += buf });
+
+ tr.on('end', function () {
+ t.equal(data, html);
+ });
+});
View
1  test/fixtures/template_one_target.html → test/update_target.html
@@ -16,5 +16,6 @@
<b>NOTHING TO SEE HERE</b>
+ <blink>TERRIBLE</blink>
</body>
</html>
View
38 woosh.js
@@ -1,38 +0,0 @@
-var trumpet = require('trumpet')
- , fs = require('fs')
- , Stream = require('stream').Stream
- , inherits = require('util').inherits
-
-function Woosh(filePath, selectors) {
- var tr = trumpet()
- fs.createReadStream(filePath).pipe(tr);
-
- function stream(selector, callback) {
- // Default behaviour for inline values
- if (typeof callback !== 'function') {
- var value = callback
- callback = function(node) {
- node.update(value)
- }
- }
- tr.select(selector, callback)
- return stream
- }
-
- stream.__proto__ = Stream.prototype
- Stream.call(stream)
-
- tr.on('data', function(d) { stream.emit('data', d) })
- tr.on('end', function() { stream.emit('end') })
-
- if (selectors && typeof selectors == 'object') {
- for(var selector in selectors) {
- stream(selector, selectors[selector])
- }
- }
-
- return stream;
-
-}
-
-module.exports = Woosh

No commit comments for this range

Something went wrong with that request. Please try again.