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.
		
		
		
		
		
			
		
			
				
					
					
						
							159 lines
						
					
					
						
							4.5 KiB
						
					
					
				
			
		
		
	
	
							159 lines
						
					
					
						
							4.5 KiB
						
					
					
				/* | 
						|
 Copyright 2012-2015, Yahoo Inc. | 
						|
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. | 
						|
 */ | 
						|
'use strict'; | 
						|
 | 
						|
const util = require('util'); | 
						|
/** | 
						|
 * An object with methods that are called during the traversal of the coverage tree. | 
						|
 * A visitor has the following methods that are called during tree traversal. | 
						|
 * | 
						|
 *   * `onStart(root, state)` - called before traversal begins | 
						|
 *   * `onSummary(node, state)` - called for every summary node | 
						|
 *   * `onDetail(node, state)` - called for every detail node | 
						|
 *   * `onSummaryEnd(node, state)` - called after all children have been visited for | 
						|
 *      a summary node. | 
						|
 *   * `onEnd(root, state)` - called after traversal ends | 
						|
 * | 
						|
 * @param delegate - a partial visitor that only implements the methods of interest | 
						|
 *  The visitor object supplies the missing methods as noops. For example, reports | 
						|
 *  that only need the final coverage summary need implement `onStart` and nothing | 
						|
 *  else. Reports that use only detailed coverage information need implement `onDetail` | 
						|
 *  and nothing else. | 
						|
 * @constructor | 
						|
 */ | 
						|
function Visitor(delegate) { | 
						|
    this.delegate = delegate; | 
						|
} | 
						|
 | 
						|
['Start', 'End', 'Summary', 'SummaryEnd', 'Detail'].forEach(k => { | 
						|
    const f = 'on' + k; | 
						|
    Visitor.prototype[f] = function(node, state) { | 
						|
        if (this.delegate[f] && typeof this.delegate[f] === 'function') { | 
						|
            this.delegate[f].call(this.delegate, node, state); | 
						|
        } | 
						|
    }; | 
						|
}); | 
						|
 | 
						|
function CompositeVisitor(visitors) { | 
						|
    if (!Array.isArray(visitors)) { | 
						|
        visitors = [visitors]; | 
						|
    } | 
						|
    this.visitors = visitors.map(v => { | 
						|
        if (v instanceof Visitor) { | 
						|
            return v; | 
						|
        } | 
						|
        return new Visitor(v); | 
						|
    }); | 
						|
} | 
						|
 | 
						|
util.inherits(CompositeVisitor, Visitor); | 
						|
 | 
						|
['Start', 'Summary', 'SummaryEnd', 'Detail', 'End'].forEach(k => { | 
						|
    const f = 'on' + k; | 
						|
    CompositeVisitor.prototype[f] = function(node, state) { | 
						|
        this.visitors.forEach(v => { | 
						|
            v[f](node, state); | 
						|
        }); | 
						|
    }; | 
						|
}); | 
						|
 | 
						|
function Node() {} | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getQualifiedName = function() { | 
						|
    throw new Error('getQualifiedName must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getRelativeName = function() { | 
						|
    throw new Error('getRelativeName must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.isRoot = function() { | 
						|
    return !this.getParent(); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getParent = function() { | 
						|
    throw new Error('getParent must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getChildren = function() { | 
						|
    throw new Error('getChildren must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.isSummary = function() { | 
						|
    throw new Error('isSummary must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getCoverageSummary = function(/* filesOnly */) { | 
						|
    throw new Error('getCoverageSummary must be overridden'); | 
						|
}; | 
						|
 | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Node.prototype.getFileCoverage = function() { | 
						|
    throw new Error('getFileCoverage must be overridden'); | 
						|
}; | 
						|
/** | 
						|
 * visit all nodes depth-first from this node down. Note that `onStart` | 
						|
 * and `onEnd` are never called on the visitor even if the current | 
						|
 * node is the root of the tree. | 
						|
 * @param visitor a full visitor that is called during tree traversal | 
						|
 * @param state optional state that is passed around | 
						|
 */ | 
						|
Node.prototype.visit = function(visitor, state) { | 
						|
    if (this.isSummary()) { | 
						|
        visitor.onSummary(this, state); | 
						|
    } else { | 
						|
        visitor.onDetail(this, state); | 
						|
    } | 
						|
 | 
						|
    this.getChildren().forEach(child => { | 
						|
        child.visit(visitor, state); | 
						|
    }); | 
						|
 | 
						|
    if (this.isSummary()) { | 
						|
        visitor.onSummaryEnd(this, state); | 
						|
    } | 
						|
}; | 
						|
 | 
						|
/** | 
						|
 * abstract base class for a coverage tree. | 
						|
 * @constructor | 
						|
 */ | 
						|
function Tree() {} | 
						|
 | 
						|
/** | 
						|
 * returns the root node of the tree | 
						|
 */ | 
						|
/* istanbul ignore next: abstract method */ | 
						|
Tree.prototype.getRoot = function() { | 
						|
    throw new Error('getRoot must be overridden'); | 
						|
}; | 
						|
 | 
						|
/** | 
						|
 * visits the tree depth-first with the supplied partial visitor | 
						|
 * @param visitor - a potentially partial visitor | 
						|
 * @param state - the state to be passed around during tree traversal | 
						|
 */ | 
						|
Tree.prototype.visit = function(visitor, state) { | 
						|
    if (!(visitor instanceof Visitor)) { | 
						|
        visitor = new Visitor(visitor); | 
						|
    } | 
						|
    visitor.onStart(this.getRoot(), state); | 
						|
    this.getRoot().visit(visitor, state); | 
						|
    visitor.onEnd(this.getRoot(), state); | 
						|
}; | 
						|
 | 
						|
module.exports = { | 
						|
    Tree, | 
						|
    Node, | 
						|
    Visitor, | 
						|
    CompositeVisitor | 
						|
};
 | 
						|
 |