|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- /*
- Copyright 2012-2015, Yahoo Inc.
- Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
- */
- 'use strict';
-
- /**
- * 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
- */
- class Visitor {
- constructor(delegate) {
- this.delegate = delegate;
- }
- }
-
- ['Start', 'End', 'Summary', 'SummaryEnd', 'Detail']
- .map(k => `on${k}`)
- .forEach(fn => {
- Object.defineProperty(Visitor.prototype, fn, {
- writable: true,
- value(node, state) {
- if (typeof this.delegate[fn] === 'function') {
- this.delegate[fn](node, state);
- }
- }
- });
- });
-
- class CompositeVisitor extends Visitor {
- constructor(visitors) {
- super();
-
- if (!Array.isArray(visitors)) {
- visitors = [visitors];
- }
- this.visitors = visitors.map(v => {
- if (v instanceof Visitor) {
- return v;
- }
- return new Visitor(v);
- });
- }
- }
-
- ['Start', 'Summary', 'SummaryEnd', 'Detail', 'End']
- .map(k => `on${k}`)
- .forEach(fn => {
- Object.defineProperty(CompositeVisitor.prototype, fn, {
- value(node, state) {
- this.visitors.forEach(v => {
- v[fn](node, state);
- });
- }
- });
- });
-
- class BaseNode {
- isRoot() {
- return !this.getParent();
- }
-
- /**
- * 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
- */
- visit(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
- */
- class BaseTree {
- constructor(root) {
- this.root = root;
- }
-
- /**
- * returns the root node of the tree
- */
- getRoot() {
- return this.root;
- }
-
- /**
- * 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
- */
- visit(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 = {
- BaseTree,
- BaseNode,
- Visitor,
- CompositeVisitor
- };
|