dt-stream
Version:
Δt stream adapter - async & dynamic templating engine
360 lines (309 loc) • 9.87 kB
JavaScript
(function() {
var EVENTS, Entry, OrderedEmitter, Stream, StreamAdapter, attrStr, prettify, streamify, _ref,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Stream = require('stream').Stream;
OrderedEmitter = require('ordered-emitter');
_ref = require('./util'), prettify = _ref.prettify, attrStr = _ref.attrStr;
EVENTS = ['add', 'close', 'end', 'remove', 'attr', 'text', 'raw', 'data'];
Entry = (function() {
function Entry(stream, el, parent) {
var idx, _ref1, _ref2, _ref3, _ref4, _ref5,
_this = this;
this.stream = stream;
this.parent = parent;
this["delete"] = __bind(this["delete"], this);
this.release = __bind(this.release, this);
this.do_job = __bind(this.do_job, this);
this.order = new OrderedEmitter({
span: true
});
this.released = false;
this.isnext = this.parent != null ? false : true;
this.children = 0;
this.order.on('entry', this.do_job);
if (this.isnext) {
return;
}
if ((_ref1 = this.parent) != null) {
_ref1._stream.write(function() {
if (!el.isempty || el.closed === true) {
_this.release();
}
return _this.isnext = true;
});
}
idx = (_ref2 = (_ref3 = this.parent) != null ? _ref3._stream.children : void 0) != null ? _ref2 : -1;
if ((_ref4 = this.parent) != null) {
_ref4._stream.children++;
}
el.ready(function() {
var _ref5;
return (_ref5 = this.parent) != null ? _ref5._stream.emit('close scope', {
order: idx + 1
}) : void 0;
});
if ((_ref5 = this.parent) != null) {
_ref5._stream.release();
}
}
Entry.prototype.do_job = function(_arg) {
var job;
job = _arg.job;
if (!job) {
return;
}
if (this.stream.paused) {
return this.stream.queue.push(job);
} else {
return job();
}
};
Entry.prototype.emit = function() {
var _ref1;
return (_ref1 = this.order) != null ? _ref1.emit.apply(_ref1, arguments) : void 0;
};
Entry.prototype.write = function(job) {
var payload;
payload = {
job: job,
order: ++this.children
};
if (this.stream.paused) {
if (this.children > 1 && this.isnext) {
this.stream.queue.push(this.release);
}
return this.stream.queue.push(this.emit.bind(this, 'entry', payload));
} else {
if (this.children > 1 && this.isnext) {
this.release();
}
return this.emit('entry', payload);
}
};
Entry.prototype.release = function() {
if (this.released) {
return;
}
this.emit('open scope', {
order: 0
});
return this.released = true;
};
Entry.prototype["delete"] = function() {
this.order.removeAllListeners();
this.order.reset();
this.order.clear();
delete this.parent;
return delete this.order;
};
return Entry;
})();
StreamAdapter = (function(_super) {
__extends(StreamAdapter, _super);
function StreamAdapter(template, opts) {
var _base, _ref1, _ref2, _ref3, _ref4;
this.template = template;
if (opts == null) {
opts = {};
}
this.close = __bind(this.close, this);
StreamAdapter.__super__.constructor.call(this);
this.builder = (_ref1 = this.template.xml) != null ? _ref1 : this.template;
if ((_ref2 = (_base = this.builder).apdaters) == null) {
_base.apdaters = {};
}
this.builder.apdaters['stream'] = this;
this.autoremove = (_ref3 = opts.autoremove) != null ? _ref3 : true;
this.setEncoding((_ref4 = opts.encoding) != null ? _ref4 : 'utf8');
this.opened_tags = 0;
this.readable = true;
this.paused = false;
this.queue = [];
if (opts.stream) {
this.pipe(opts.stream);
}
this.initialize();
}
StreamAdapter.prototype.initialize = function() {
this.template.stream = this;
this.builder._stream = new Entry(this, this.builder);
this.listen();
return this.template.register('ready', this.approve_ready);
};
StreamAdapter.prototype.approve_ready = function(tag, next) {
if (tag._stream_ready === true) {
return next(tag);
} else {
return tag._stream_ready = function() {
return next(tag);
};
}
};
StreamAdapter.prototype.listen = function() {
var _this = this;
return EVENTS.forEach(function(event) {
return _this.template.on(event, _this["on" + event].bind(_this));
});
};
StreamAdapter.prototype.write = function(data) {
if (!data) {
return;
}
if (this.paused) {
this.emit('error', "write data while paused");
}
return this.emit('data', data);
};
StreamAdapter.prototype.close = function() {
this.builder.closed = true;
this.readable = false;
this.emit('end');
return this.emit('close');
};
StreamAdapter.prototype.setEncoding = function(encoding) {
this.encoding = encoding;
};
StreamAdapter.prototype.pause = function() {
if (this.paused) {
return;
}
this.paused = true;
this.emit('pause');
return this.template.emit('pause');
};
StreamAdapter.prototype.resume = function() {
var _base;
if (this.paused) {
this.emit('resume');
this.template.emit('resume');
this.paused = false;
}
while (!this.paused && this.queue.length) {
if (typeof (_base = this.queue.shift()) === "function") {
_base();
}
}
if ((this.closed != null) && !this.queue.length) {
if (typeof this.closed === "function") {
this.closed();
}
this.closed = true;
}
};
StreamAdapter.prototype.onadd = function(parent, el) {
var _this = this;
if (!parent.writable) {
console.warn("creating " + (el.toString()) + " in closed " + (parent.toString()) + " omitted");
return;
}
el._stream = new Entry(this, el, parent);
this.opened_tags++;
el._stream.write(function() {
if (el === el.builder) {
return;
}
if (el.isempty && el.closed === true) {
return _this.write(prettify(el, "<" + el.name + (attrStr(el.attrs)) + "/>"));
} else {
return _this.write(prettify(el, "<" + el.name + (attrStr(el.attrs)) + ">"));
}
});
if (!this.autoremove) {
return;
}
return el.ready(function() {
if (el.closed === 'removed') {
return _this.onremove(el);
} else {
return el.remove();
}
});
};
StreamAdapter.prototype.onremove = function(el) {
if (el._stream == null) {
return;
}
this.opened_tags--;
if (this.opened_tags === 0 && this.builder.closed === 'pending' && !this.queue.length) {
if (typeof this.closed === "function") {
this.closed();
}
this.closed = true;
}
return el._stream.write(function() {
el._stream["delete"]();
return delete el._stream;
});
};
StreamAdapter.prototype.onclose = function(el) {
var _ref1,
_this = this;
return (_ref1 = el._stream) != null ? _ref1.write(function() {
if (!(el.isempty || el === el.builder)) {
_this.write(prettify(el, "</" + el.name + ">"));
}
if (typeof el._stream_ready === "function") {
el._stream_ready();
}
return el._stream_ready = true;
}) : void 0;
};
StreamAdapter.prototype.ondata = function(el, data) {
var _ref1,
_this = this;
return (_ref1 = el._stream) != null ? _ref1.write(function() {
return _this.write(data);
}) : void 0;
};
StreamAdapter.prototype.ontext = function(el, text) {
var _ref1,
_this = this;
return (_ref1 = el._stream) != null ? _ref1.write(function() {
return _this.write(prettify(el, text));
}) : void 0;
};
StreamAdapter.prototype.onraw = function(el, html) {
var _ref1,
_this = this;
return (_ref1 = el._stream) != null ? _ref1.write(function() {
return _this.write(html);
}) : void 0;
};
StreamAdapter.prototype.onattr = function(el, key, value) {
if (!el.isempty) {
return;
}
if (el._stream_ready !== true) {
return;
}
return console.warn("attributes of " + (el.toString()) + " don't change anymore");
};
StreamAdapter.prototype.onend = function() {
if ((this.closed != null) || this.opened_tags === 0) {
return this.close();
}
this.builder.closed = 'pending';
return this.closed = this.close;
};
return StreamAdapter;
})(Stream);
streamify = function(tpl, opts) {
new StreamAdapter(tpl, opts);
return tpl;
};
streamify.Adapter = StreamAdapter;
module.exports = streamify;
if (process.title === 'browser') {
(function() {
if (this.dynamictemplate != null) {
return this.dynamictemplate.streamify = streamify;
} else {
return this.dynamictemplate = {
streamify: streamify
};
}
}).call(window);
}
}).call(this);