aboutsummaryrefslogtreecommitdiff
path: root/node_modules/istanbul/lib/util/tree-summarizer.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/istanbul/lib/util/tree-summarizer.js')
-rw-r--r--node_modules/istanbul/lib/util/tree-summarizer.js213
1 files changed, 213 insertions, 0 deletions
diff --git a/node_modules/istanbul/lib/util/tree-summarizer.js b/node_modules/istanbul/lib/util/tree-summarizer.js
new file mode 100644
index 000000000..df350f50e
--- /dev/null
+++ b/node_modules/istanbul/lib/util/tree-summarizer.js
@@ -0,0 +1,213 @@
+/*
+ Copyright (c) 2012, Yahoo! Inc. All rights reserved.
+ Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
+ */
+
+var path = require('path'),
+ SEP = path.sep || '/',
+ utils = require('../object-utils');
+
+function commonArrayPrefix(first, second) {
+ var len = first.length < second.length ? first.length : second.length,
+ i,
+ ret = [];
+ for (i = 0; i < len; i += 1) {
+ if (first[i] === second[i]) {
+ ret.push(first[i]);
+ } else {
+ break;
+ }
+ }
+ return ret;
+}
+
+function findCommonArrayPrefix(args) {
+ if (args.length === 0) {
+ return [];
+ }
+
+ var separated = args.map(function (arg) { return arg.split(SEP); }),
+ ret = separated.pop();
+
+ if (separated.length === 0) {
+ return ret.slice(0, ret.length - 1);
+ } else {
+ return separated.reduce(commonArrayPrefix, ret);
+ }
+}
+
+function Node(fullName, kind, metrics) {
+ this.name = fullName;
+ this.fullName = fullName;
+ this.kind = kind;
+ this.metrics = metrics || null;
+ this.parent = null;
+ this.children = [];
+}
+
+Node.prototype = {
+ displayShortName: function () {
+ return this.relativeName;
+ },
+ fullPath: function () {
+ return this.fullName;
+ },
+ addChild: function (child) {
+ this.children.push(child);
+ child.parent = this;
+ },
+ toJSON: function () {
+ return {
+ name: this.name,
+ relativeName: this.relativeName,
+ fullName: this.fullName,
+ kind: this.kind,
+ metrics: this.metrics,
+ parent: this.parent === null ? null : this.parent.name,
+ children: this.children.map(function (node) { return node.toJSON(); })
+ };
+ }
+};
+
+function TreeSummary(summaryMap, commonPrefix) {
+ this.prefix = commonPrefix;
+ this.convertToTree(summaryMap, commonPrefix);
+}
+
+TreeSummary.prototype = {
+ getNode: function (shortName) {
+ return this.map[shortName];
+ },
+ convertToTree: function (summaryMap, arrayPrefix) {
+ var nodes = [],
+ rootPath = arrayPrefix.join(SEP) + SEP,
+ root = new Node(rootPath, 'dir'),
+ tmp,
+ tmpChildren,
+ seen = {},
+ filesUnderRoot = false;
+
+ seen[rootPath] = root;
+ Object.keys(summaryMap).forEach(function (key) {
+ var metrics = summaryMap[key],
+ node,
+ parentPath,
+ parent;
+ node = new Node(key, 'file', metrics);
+ seen[key] = node;
+ nodes.push(node);
+ parentPath = path.dirname(key) + SEP;
+ if (parentPath === SEP + SEP || parentPath === '.' + SEP) {
+ parentPath = SEP + '__root__' + SEP;
+ }
+ parent = seen[parentPath];
+ if (!parent) {
+ parent = new Node(parentPath, 'dir');
+ root.addChild(parent);
+ seen[parentPath] = parent;
+ }
+ parent.addChild(node);
+ if (parent === root) { filesUnderRoot = true; }
+ });
+
+ if (filesUnderRoot && arrayPrefix.length > 0) {
+ arrayPrefix.pop(); //start at one level above
+ tmp = root;
+ tmpChildren = tmp.children;
+ tmp.children = [];
+ root = new Node(arrayPrefix.join(SEP) + SEP, 'dir');
+ root.addChild(tmp);
+ tmpChildren.forEach(function (child) {
+ if (child.kind === 'dir') {
+ root.addChild(child);
+ } else {
+ tmp.addChild(child);
+ }
+ });
+ }
+ this.fixupNodes(root, arrayPrefix.join(SEP) + SEP);
+ this.calculateMetrics(root);
+ this.root = root;
+ this.map = {};
+ this.indexAndSortTree(root, this.map);
+ },
+
+ fixupNodes: function (node, prefix, parent) {
+ var that = this;
+ if (node.name.indexOf(prefix) === 0) {
+ node.name = node.name.substring(prefix.length);
+ }
+ if (node.name.charAt(0) === SEP) {
+ node.name = node.name.substring(1);
+ }
+ if (parent) {
+ if (parent.name !== '__root__' + SEP) {
+ node.relativeName = node.name.substring(parent.name.length);
+ } else {
+ node.relativeName = node.name;
+ }
+ } else {
+ node.relativeName = node.name.substring(prefix.length);
+ }
+ node.children.forEach(function (child) {
+ that.fixupNodes(child, prefix, node);
+ });
+ },
+ calculateMetrics: function (entry) {
+ var that = this,
+ fileChildren;
+ if (entry.kind !== 'dir') {return; }
+ entry.children.forEach(function (child) {
+ that.calculateMetrics(child);
+ });
+ entry.metrics = utils.mergeSummaryObjects.apply(
+ null,
+ entry.children.map(function (child) { return child.metrics; })
+ );
+ // calclulate "java-style" package metrics where there is no hierarchy
+ // across packages
+ fileChildren = entry.children.filter(function (n) { return n.kind !== 'dir'; });
+ if (fileChildren.length > 0) {
+ entry.packageMetrics = utils.mergeSummaryObjects.apply(
+ null,
+ fileChildren.map(function (child) { return child.metrics; })
+ );
+ } else {
+ entry.packageMetrics = null;
+ }
+ },
+ indexAndSortTree: function (node, map) {
+ var that = this;
+ map[node.name] = node;
+ node.children.sort(function (a, b) {
+ a = a.relativeName;
+ b = b.relativeName;
+ return a < b ? -1 : a > b ? 1 : 0;
+ });
+ node.children.forEach(function (child) {
+ that.indexAndSortTree(child, map);
+ });
+ },
+ toJSON: function () {
+ return {
+ prefix: this.prefix,
+ root: this.root.toJSON()
+ };
+ }
+};
+
+function TreeSummarizer() {
+ this.summaryMap = {};
+}
+
+TreeSummarizer.prototype = {
+ addFileCoverageSummary: function (filePath, metrics) {
+ this.summaryMap[filePath] = metrics;
+ },
+ getTreeSummary: function () {
+ var commonArrayPrefix = findCommonArrayPrefix(Object.keys(this.summaryMap));
+ return new TreeSummary(this.summaryMap, commonArrayPrefix);
+ }
+};
+
+module.exports = TreeSummarizer;