You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					146 lines
				
				3.6 KiB
			
		
		
			
		
	
	
					146 lines
				
				3.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								var Traverse = require('traverse');
							 | 
						||
| 
								 | 
							
								var EventEmitter = require('events').EventEmitter;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = Chainsaw;
							 | 
						||
| 
								 | 
							
								function Chainsaw (builder) {
							 | 
						||
| 
								 | 
							
								    var saw = Chainsaw.saw(builder, {});
							 | 
						||
| 
								 | 
							
								    var r = builder.call(saw.handlers, saw);
							 | 
						||
| 
								 | 
							
								    if (r !== undefined) saw.handlers = r;
							 | 
						||
| 
								 | 
							
								    saw.record();
							 | 
						||
| 
								 | 
							
								    return saw.chain();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Chainsaw.light = function ChainsawLight (builder) {
							 | 
						||
| 
								 | 
							
								    var saw = Chainsaw.saw(builder, {});
							 | 
						||
| 
								 | 
							
								    var r = builder.call(saw.handlers, saw);
							 | 
						||
| 
								 | 
							
								    if (r !== undefined) saw.handlers = r;
							 | 
						||
| 
								 | 
							
								    return saw.chain();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Chainsaw.saw = function (builder, handlers) {
							 | 
						||
| 
								 | 
							
								    var saw = new EventEmitter;
							 | 
						||
| 
								 | 
							
								    saw.handlers = handlers;
							 | 
						||
| 
								 | 
							
								    saw.actions = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.chain = function () {
							 | 
						||
| 
								 | 
							
								        var ch = Traverse(saw.handlers).map(function (node) {
							 | 
						||
| 
								 | 
							
								            if (this.isRoot) return node;
							 | 
						||
| 
								 | 
							
								            var ps = this.path;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (typeof node === 'function') {
							 | 
						||
| 
								 | 
							
								                this.update(function () {
							 | 
						||
| 
								 | 
							
								                    saw.actions.push({
							 | 
						||
| 
								 | 
							
								                        path : ps,
							 | 
						||
| 
								 | 
							
								                        args : [].slice.call(arguments)
							 | 
						||
| 
								 | 
							
								                    });
							 | 
						||
| 
								 | 
							
								                    return ch;
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        process.nextTick(function () {
							 | 
						||
| 
								 | 
							
								            saw.emit('begin');
							 | 
						||
| 
								 | 
							
								            saw.next();
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return ch;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.pop = function () {
							 | 
						||
| 
								 | 
							
								        return saw.actions.shift();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.next = function () {
							 | 
						||
| 
								 | 
							
								        var action = saw.pop();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!action) {
							 | 
						||
| 
								 | 
							
								            saw.emit('end');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (!action.trap) {
							 | 
						||
| 
								 | 
							
								            var node = saw.handlers;
							 | 
						||
| 
								 | 
							
								            action.path.forEach(function (key) { node = node[key] });
							 | 
						||
| 
								 | 
							
								            node.apply(saw.handlers, action.args);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.nest = function (cb) {
							 | 
						||
| 
								 | 
							
								        var args = [].slice.call(arguments, 1);
							 | 
						||
| 
								 | 
							
								        var autonext = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (typeof cb === 'boolean') {
							 | 
						||
| 
								 | 
							
								            var autonext = cb;
							 | 
						||
| 
								 | 
							
								            cb = args.shift();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var s = Chainsaw.saw(builder, {});
							 | 
						||
| 
								 | 
							
								        var r = builder.call(s.handlers, s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (r !== undefined) s.handlers = r;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // If we are recording...
							 | 
						||
| 
								 | 
							
								        if ("undefined" !== typeof saw.step) {
							 | 
						||
| 
								 | 
							
								            // ... our children should, too
							 | 
						||
| 
								 | 
							
								            s.record();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        cb.apply(s.chain(), args);
							 | 
						||
| 
								 | 
							
								        if (autonext !== false) s.on('end', saw.next);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.record = function () {
							 | 
						||
| 
								 | 
							
								        upgradeChainsaw(saw);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ['trap', 'down', 'jump'].forEach(function (method) {
							 | 
						||
| 
								 | 
							
								        saw[method] = function () {
							 | 
						||
| 
								 | 
							
								            throw new Error("To use the trap, down and jump features, please "+
							 | 
						||
| 
								 | 
							
								                            "call record() first to start recording actions.");
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return saw;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function upgradeChainsaw(saw) {
							 | 
						||
| 
								 | 
							
								    saw.step = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // override pop
							 | 
						||
| 
								 | 
							
								    saw.pop = function () {
							 | 
						||
| 
								 | 
							
								        return saw.actions[saw.step++];
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.trap = function (name, cb) {
							 | 
						||
| 
								 | 
							
								        var ps = Array.isArray(name) ? name : [name];
							 | 
						||
| 
								 | 
							
								        saw.actions.push({
							 | 
						||
| 
								 | 
							
								            path : ps,
							 | 
						||
| 
								 | 
							
								            step : saw.step,
							 | 
						||
| 
								 | 
							
								            cb : cb,
							 | 
						||
| 
								 | 
							
								            trap : true
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.down = function (name) {
							 | 
						||
| 
								 | 
							
								        var ps = (Array.isArray(name) ? name : [name]).join('/');
							 | 
						||
| 
								 | 
							
								        var i = saw.actions.slice(saw.step).map(function (x) {
							 | 
						||
| 
								 | 
							
								            if (x.trap && x.step <= saw.step) return false;
							 | 
						||
| 
								 | 
							
								            return x.path.join('/') == ps;
							 | 
						||
| 
								 | 
							
								        }).indexOf(true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (i >= 0) saw.step += i;
							 | 
						||
| 
								 | 
							
								        else saw.step = saw.actions.length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        var act = saw.actions[saw.step - 1];
							 | 
						||
| 
								 | 
							
								        if (act && act.trap) {
							 | 
						||
| 
								 | 
							
								            // It's a trap!
							 | 
						||
| 
								 | 
							
								            saw.step = act.step;
							 | 
						||
| 
								 | 
							
								            act.cb();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else saw.next();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    saw.jump = function (step) {
							 | 
						||
| 
								 | 
							
								        saw.step = step;
							 | 
						||
| 
								 | 
							
								        saw.next();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								};
							 |