From ac5a7548babb52e914de4533dd6e42263c7b2c2a Mon Sep 17 00:00:00 2001 From: Kevin Phillips Date: Tue, 19 Jun 2018 08:36:08 -0500 Subject: [PATCH] 1.1.0 --- dist/amd/can-debug.js | 40 + dist/amd/src/draw-graph/draw-graph.js | 50 ++ dist/amd/src/draw-graph/format-graph.js | 61 ++ dist/amd/src/get-data/get-data.js | 46 ++ dist/amd/src/get-graph/get-graph.js | 95 +++ dist/amd/src/get-graph/make-node.js | 21 + .../get-what-changes-me.js | 15 + .../get-what-i-change/get-what-i-change.js | 15 + dist/amd/src/graph/graph.js | 106 +++ dist/amd/src/label-cycles/label-cycles.js | 32 + dist/amd/src/log-data/log-data.js | 38 + dist/amd/src/proxy-namespace.js | 19 + dist/amd/src/temporarily-bind.js | 48 ++ .../src/what-changes-me/what-changes-me.js | 20 + dist/amd/src/what-i-change/what-i-change.js | 20 + dist/cjs/can-debug.js | 24 + dist/cjs/src/draw-graph/draw-graph.js | 40 + dist/cjs/src/draw-graph/format-graph.js | 54 ++ dist/cjs/src/get-data/get-data.js | 39 + dist/cjs/src/get-graph/get-graph.js | 85 ++ dist/cjs/src/get-graph/make-node.js | 14 + .../get-what-changes-me.js | 7 + .../get-what-i-change/get-what-i-change.js | 7 + dist/cjs/src/graph/graph.js | 104 +++ dist/cjs/src/label-cycles/label-cycles.js | 25 + dist/cjs/src/log-data/log-data.js | 31 + dist/cjs/src/proxy-namespace.js | 13 + dist/cjs/src/temporarily-bind.js | 40 + .../src/what-changes-me/what-changes-me.js | 11 + dist/cjs/src/what-i-change/what-i-change.js | 11 + dist/global/can-debug.js | 766 ++++++++++++++++++ 31 files changed, 1897 insertions(+) create mode 100644 dist/amd/can-debug.js create mode 100644 dist/amd/src/draw-graph/draw-graph.js create mode 100644 dist/amd/src/draw-graph/format-graph.js create mode 100644 dist/amd/src/get-data/get-data.js create mode 100644 dist/amd/src/get-graph/get-graph.js create mode 100644 dist/amd/src/get-graph/make-node.js create mode 100644 dist/amd/src/get-what-changes-me/get-what-changes-me.js create mode 100644 dist/amd/src/get-what-i-change/get-what-i-change.js create mode 100644 dist/amd/src/graph/graph.js create mode 100644 dist/amd/src/label-cycles/label-cycles.js create mode 100644 dist/amd/src/log-data/log-data.js create mode 100644 dist/amd/src/proxy-namespace.js create mode 100644 dist/amd/src/temporarily-bind.js create mode 100644 dist/amd/src/what-changes-me/what-changes-me.js create mode 100644 dist/amd/src/what-i-change/what-i-change.js create mode 100644 dist/cjs/can-debug.js create mode 100644 dist/cjs/src/draw-graph/draw-graph.js create mode 100644 dist/cjs/src/draw-graph/format-graph.js create mode 100644 dist/cjs/src/get-data/get-data.js create mode 100644 dist/cjs/src/get-graph/get-graph.js create mode 100644 dist/cjs/src/get-graph/make-node.js create mode 100644 dist/cjs/src/get-what-changes-me/get-what-changes-me.js create mode 100644 dist/cjs/src/get-what-i-change/get-what-i-change.js create mode 100644 dist/cjs/src/graph/graph.js create mode 100644 dist/cjs/src/label-cycles/label-cycles.js create mode 100644 dist/cjs/src/log-data/log-data.js create mode 100644 dist/cjs/src/proxy-namespace.js create mode 100644 dist/cjs/src/temporarily-bind.js create mode 100644 dist/cjs/src/what-changes-me/what-changes-me.js create mode 100644 dist/cjs/src/what-i-change/what-i-change.js create mode 100644 dist/global/can-debug.js diff --git a/dist/amd/can-debug.js b/dist/amd/can-debug.js new file mode 100644 index 0000000..9c04bfe --- /dev/null +++ b/dist/amd/can-debug.js @@ -0,0 +1,40 @@ +/*can-debug@1.0.4#can-debug*/ +define([ + 'require', + 'exports', + 'module', + 'can-namespace', + './src/proxy-namespace', + './src/temporarily-bind', + './src/get-graph/get-graph', + './src/draw-graph/format-graph', + './src/draw-graph/draw-graph', + './src/what-i-change/what-i-change', + './src/what-changes-me/what-changes-me', + './src/get-what-i-change/get-what-i-change', + './src/get-what-changes-me/get-what-changes-me' +], function (require, exports, module) { + var namespace = require('can-namespace'); + var proxyNamespace = require('./src/proxy-namespace'); + var temporarilyBind = require('./src/temporarily-bind'); + var getGraph = require('./src/get-graph/get-graph'); + var formatGraph = require('./src/draw-graph/format-graph'); + var drawGraph = require('./src/draw-graph/draw-graph'); + var logWhatIChange = require('./src/what-i-change/what-i-change'); + var logWhatChangesMe = require('./src/what-changes-me/what-changes-me'); + var getWhatIChange = require('./src/get-what-i-change/get-what-i-change'); + var getWhatChangesMe = require('./src/get-what-changes-me/get-what-changes-me'); + module.exports = namespace.debug = { + getGraph: temporarilyBind(getGraph), + formatGraph: temporarilyBind(formatGraph), + drawGraph: temporarilyBind(drawGraph), + getWhatIChange: temporarilyBind(getWhatIChange), + getWhatChangesMe: temporarilyBind(getWhatChangesMe), + logWhatIChange: temporarilyBind(logWhatIChange), + logWhatChangesMe: temporarilyBind(logWhatChangesMe) + }; + window.can = typeof Proxy !== 'undefined' ? proxyNamespace(namespace) : namespace; + if (window.__CANJS_DEVTOOLS__) { + window.__CANJS_DEVTOOLS__.register(window.can); + } +}); \ No newline at end of file diff --git a/dist/amd/src/draw-graph/draw-graph.js b/dist/amd/src/draw-graph/draw-graph.js new file mode 100644 index 0000000..86107ff --- /dev/null +++ b/dist/amd/src/draw-graph/draw-graph.js @@ -0,0 +1,50 @@ +/*can-debug@1.0.4#src/draw-graph/draw-graph*/ +define([ + 'require', + 'exports', + 'module', + './format-graph', + '../get-graph/get-graph' +], function (require, exports, module) { + (function (__dirname, require, exports, module) { + var formatGraph = require('./format-graph'); + var getGraph = require('../get-graph/get-graph'); + module.exports = function drawGraph(obj, key) { + var gotKey = arguments.length === 2; + var graph = gotKey ? getGraph(obj, key) : getGraph(obj); + fetch(__dirname + '/vis.js').then(function (res) { + return res.text(); + }).then(function (code) { + var w = window.open('', 'can-debug: Dependency Graph'); + var doc = w.document; + var script = doc.createElement('script'); + script.text = code; + doc.body.appendChild(script); + var data = formatGraph(graph); + var drawScript = doc.createElement('script'); + drawScript.text = ` + var container = document.createElement("div"); + + var options = { + physics: { + solver: "repulsion" + } + }; + + document.title = "can-debug: Dependency Graph"; + document.body.appendChild(container); + + new vis.Network( + container, + { + nodes: new vis.DataSet(${ JSON.stringify(data.nodes) }), + edges: new vis.DataSet(${ JSON.stringify(data.edges) }) + }, + options + ); + `; + doc.body.appendChild(drawScript); + }); + }; + }('/', require, exports, module)); +}); \ No newline at end of file diff --git a/dist/amd/src/draw-graph/format-graph.js b/dist/amd/src/draw-graph/format-graph.js new file mode 100644 index 0000000..74e2645 --- /dev/null +++ b/dist/amd/src/draw-graph/format-graph.js @@ -0,0 +1,61 @@ +/*can-debug@1.0.4#src/draw-graph/format-graph*/ +define([ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + module.exports = function formatGraph(graph) { + var nodeIdMap = new Map(graph.nodes.map(function (node, index) { + return [ + node, + index + 1 + ]; + })); + var nodesDataSet = graph.nodes.map(function (node) { + return { + shape: 'box', + id: nodeIdMap.get(node), + label: canReflect.getName(node.obj) + (node.key ? '.' + node.key : '') + }; + }); + var getArrowData = function getArrowData(meta) { + var regular = { arrows: 'to' }; + var withDashes = { + arrows: 'to', + dashes: true + }; + var map = { + derive: regular, + mutate: withDashes + }; + return map[meta.kind]; + }; + var visited = new Map(); + var arrowsDataSet = []; + graph.nodes.forEach(function (node) { + var visit = function (node) { + if (!visited.has(node)) { + visited.set(node, true); + var arrows = graph.arrows.get(node); + var headId = nodeIdMap.get(node); + arrows.forEach(function (neighbor) { + var tailId = nodeIdMap.get(neighbor); + var meta = graph.arrowsMeta.get(node).get(neighbor); + arrowsDataSet.push(Object.assign({ + from: headId, + to: tailId + }, getArrowData(meta))); + visit(neighbor); + }); + } + }; + visit(node); + }); + return { + nodes: nodesDataSet, + edges: arrowsDataSet + }; + }; +}); \ No newline at end of file diff --git a/dist/amd/src/get-data/get-data.js b/dist/amd/src/get-data/get-data.js new file mode 100644 index 0000000..9bd4ee4 --- /dev/null +++ b/dist/amd/src/get-data/get-data.js @@ -0,0 +1,46 @@ +/*can-debug@1.0.4#src/get-data/get-data*/ +define([ + 'require', + 'exports', + 'module', + '../label-cycles/label-cycles' +], function (require, exports, module) { + var labelCycles = require('../label-cycles/label-cycles'); + var isDisconnected = function isDisconnected(data) { + return !data.derive.length && !data.mutations.length && !data.twoWay.length; + }; + module.exports = function getDebugData(inputGraph, direction) { + var visited = new Map(); + var graph = labelCycles(direction === 'whatChangesMe' ? inputGraph.reverse() : inputGraph); + var visit = function visit(node) { + var data = { + node: node, + derive: [], + mutations: [], + twoWay: [] + }; + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + if (!visited.has(adj)) { + switch (meta.kind) { + case 'twoWay': + data.twoWay.push(visit(adj)); + break; + case 'derive': + data.derive.push(visit(adj)); + break; + case 'mutate': + data.mutations.push(visit(adj)); + break; + default: + throw new Error('Unknow meta.kind value: ', meta.kind); + } + } + }); + return data; + }; + var result = visit(graph.nodes[0]); + return isDisconnected(result) ? null : result; + }; +}); \ No newline at end of file diff --git a/dist/amd/src/get-graph/get-graph.js b/dist/amd/src/get-graph/get-graph.js new file mode 100644 index 0000000..0cc5e71 --- /dev/null +++ b/dist/amd/src/get-graph/get-graph.js @@ -0,0 +1,95 @@ +/*can-debug@1.0.4#src/get-graph/get-graph*/ +define([ + 'require', + 'exports', + 'module', + '../graph/graph', + './make-node', + 'can-reflect', + 'can-reflect-dependencies' +], function (require, exports, module) { + var Graph = require('../graph/graph'); + var makeNode = require('./make-node'); + var canReflect = require('can-reflect'); + var mutateDeps = require('can-reflect-dependencies'); + module.exports = function getGraph(obj, key) { + var order = 0; + var graph = new Graph(); + var gotKey = arguments.length === 2; + var addArrow = function addArrow(direction, parent, child, meta) { + switch (direction) { + case 'whatIChange': + graph.addArrow(parent, child, meta); + break; + case 'whatChangesMe': + graph.addArrow(child, parent, meta); + break; + default: + throw new Error('Unknown direction value: ', meta.direction); + } + }; + var visitKeyDependencies = function visitKeyDependencies(source, meta, cb) { + canReflect.eachKey(source.keyDependencies || {}, function (keys, obj) { + canReflect.each(keys, function (key) { + cb(obj, meta, key); + }); + }); + }; + var visitValueDependencies = function visitValueDependencies(source, meta, cb) { + canReflect.eachIndex(source.valueDependencies || [], function (obj) { + cb(obj, meta); + }); + }; + var visit = function visit(obj, meta, key) { + var gotKey = arguments.length === 3; + var node = graph.findNode(function (node) { + return gotKey ? node.obj === obj && node.key === key : node.obj === obj; + }); + if (node) { + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + return graph; + } + order += 1; + node = gotKey ? makeNode(obj, key) : makeNode(obj); + node.order = order; + graph.addNode(node); + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + var nextMeta; + var data = gotKey ? mutateDeps.getDependencyDataOf(obj, key) : mutateDeps.getDependencyDataOf(obj); + if (data && data.whatIChange) { + nextMeta = { + direction: 'whatIChange', + parent: node + }; + canReflect.eachKey(data.whatIChange, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + if (data && data.whatChangesMe) { + nextMeta = { + direction: 'whatChangesMe', + parent: node + }; + canReflect.eachKey(data.whatChangesMe, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + return graph; + }; + return gotKey ? visit(obj, {}, key) : visit(obj, {}); + }; +}); \ No newline at end of file diff --git a/dist/amd/src/get-graph/make-node.js b/dist/amd/src/get-graph/make-node.js new file mode 100644 index 0000000..8653be5 --- /dev/null +++ b/dist/amd/src/get-graph/make-node.js @@ -0,0 +1,21 @@ +/*can-debug@1.0.4#src/get-graph/make-node*/ +define([ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + module.exports = function makeNode(obj, key) { + var gotKey = arguments.length === 2; + var node = { + obj: obj, + name: canReflect.getName(obj), + value: gotKey ? canReflect.getKeyValue(obj, key) : canReflect.getValue(obj) + }; + if (gotKey) { + node.key = key; + } + return node; + }; +}); \ No newline at end of file diff --git a/dist/amd/src/get-what-changes-me/get-what-changes-me.js b/dist/amd/src/get-what-changes-me/get-what-changes-me.js new file mode 100644 index 0000000..7c2071d --- /dev/null +++ b/dist/amd/src/get-what-changes-me/get-what-changes-me.js @@ -0,0 +1,15 @@ +/*can-debug@1.0.4#src/get-what-changes-me/get-what-changes-me*/ +define([ + 'require', + 'exports', + 'module', + '../get-data/get-data', + '../get-graph/get-graph' +], function (require, exports, module) { + var getData = require('../get-data/get-data'); + var getGraph = require('../get-graph/get-graph'); + module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); + }; +}); \ No newline at end of file diff --git a/dist/amd/src/get-what-i-change/get-what-i-change.js b/dist/amd/src/get-what-i-change/get-what-i-change.js new file mode 100644 index 0000000..452ec2c --- /dev/null +++ b/dist/amd/src/get-what-i-change/get-what-i-change.js @@ -0,0 +1,15 @@ +/*can-debug@1.0.4#src/get-what-i-change/get-what-i-change*/ +define([ + 'require', + 'exports', + 'module', + '../get-data/get-data', + '../get-graph/get-graph' +], function (require, exports, module) { + var getData = require('../get-data/get-data'); + var getGraph = require('../get-graph/get-graph'); + module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); + }; +}); \ No newline at end of file diff --git a/dist/amd/src/graph/graph.js b/dist/amd/src/graph/graph.js new file mode 100644 index 0000000..28bce8e --- /dev/null +++ b/dist/amd/src/graph/graph.js @@ -0,0 +1,106 @@ +/*can-debug@1.0.4#src/graph/graph*/ +define(function (require, exports, module) { + function Graph() { + this.nodes = []; + this.arrows = new Map(); + this.arrowsMeta = new Map(); + } + Graph.prototype.addNode = function addNode(node) { + this.nodes.push(node); + this.arrows.set(node, new Set()); + }; + Graph.prototype.addArrow = function addArrow(head, tail, meta) { + var graph = this; + graph.arrows.get(head).add(tail); + if (meta) { + addArrowMeta(graph, head, tail, meta); + } + }; + Graph.prototype.hasArrow = function hasArrow(head, tail) { + return this.getNeighbors(head).has(tail); + }; + Graph.prototype.getArrowMeta = function getArrowMeta(head, tail) { + return this.arrowsMeta.get(head) && this.arrowsMeta.get(head).get(tail); + }; + Graph.prototype.setArrowMeta = function setArrowMeta(head, tail, meta) { + addArrowMeta(this, head, tail, meta); + }; + Graph.prototype.getNeighbors = function getNeighbors(node) { + return this.arrows.get(node); + }; + Graph.prototype.findNode = function findNode(cb) { + var found = null; + var graph = this; + for (var node of graph.nodes) { + if (cb(node)) { + found = node; + break; + } + } + return found; + }; + Graph.prototype.bfs = function bfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var queue = [node]; + var visited = new Map([[ + node, + true + ]]); + while (queue.length) { + node = queue.shift(); + visit(node); + graph.arrows.get(node).forEach(function (adj) { + if (!visited.has(adj)) { + queue.push(adj); + visited.set(adj, true); + } + }); + } + }; + Graph.prototype.dfs = function dfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var stack = [node]; + var visited = new Map(); + while (stack.length) { + node = stack.pop(); + visit(node); + if (!visited.has(node)) { + visited.set(node, true); + graph.arrows.get(node).forEach(function (adj) { + stack.push(adj); + }); + } + } + }; + Graph.prototype.reverse = function reverse() { + var graph = this; + var reversed = new Graph(); + graph.nodes.forEach(reversed.addNode.bind(reversed)); + graph.nodes.forEach(function (node) { + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + reversed.addArrow(adj, node, meta); + }); + }); + return reversed; + }; + function addArrowMeta(graph, head, tail, meta) { + var entry = graph.arrowsMeta.get(head); + if (entry) { + var arrowMeta = entry.get(tail); + if (!arrowMeta) { + arrowMeta = {}; + } + entry.set(tail, Object.assign(arrowMeta, meta)); + } else { + entry = new Map([[ + tail, + meta + ]]); + graph.arrowsMeta.set(head, entry); + } + } + module.exports = Graph; +}); \ No newline at end of file diff --git a/dist/amd/src/label-cycles/label-cycles.js b/dist/amd/src/label-cycles/label-cycles.js new file mode 100644 index 0000000..39689b8 --- /dev/null +++ b/dist/amd/src/label-cycles/label-cycles.js @@ -0,0 +1,32 @@ +/*can-debug@1.0.4#src/label-cycles/label-cycles*/ +define([ + 'require', + 'exports', + 'module', + '../graph/graph' +], function (require, exports, module) { + var Graph = require('../graph/graph'); + module.exports = function labelCycles(graph) { + var visited = new Map(); + var result = new Graph(); + graph.nodes.forEach(function (node) { + result.addNode(node); + }); + var visit = function visit(node) { + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + if (visited.has(adj)) { + var isTwoWay = graph.hasArrow(node, adj); + if (isTwoWay) { + result.addArrow(adj, node, { kind: 'twoWay' }); + } + } else { + result.addArrow(node, adj, graph.getArrowMeta(node, adj)); + visit(adj); + } + }); + }; + visit(graph.nodes[0]); + return result; + }; +}); \ No newline at end of file diff --git a/dist/amd/src/log-data/log-data.js b/dist/amd/src/log-data/log-data.js new file mode 100644 index 0000000..f33dd78 --- /dev/null +++ b/dist/amd/src/log-data/log-data.js @@ -0,0 +1,38 @@ +/*can-debug@1.0.4#src/log-data/log-data*/ +define([ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + var quoteString = function quoteString(x) { + return typeof x === 'string' ? JSON.stringify(x) : x; + }; + module.exports = function log(data) { + var node = data.node; + var nameParts = [ + node.name, + 'key' in node ? '.' + node.key : '' + ]; + console.group(nameParts.join('')); + console.log('value ', quoteString(node.value)); + console.log('object ', node.obj); + if (data.derive.length) { + console.group('DERIVED FROM'); + canReflect.eachIndex(data.derive, log); + console.groupEnd(); + } + if (data.mutations.length) { + console.group('MUTATED BY'); + canReflect.eachIndex(data.mutations, log); + console.groupEnd(); + } + if (data.twoWay.length) { + console.group('TWO WAY'); + canReflect.eachIndex(data.twoWay, log); + console.groupEnd(); + } + console.groupEnd(); + }; +}); \ No newline at end of file diff --git a/dist/amd/src/proxy-namespace.js b/dist/amd/src/proxy-namespace.js new file mode 100644 index 0000000..dd7545b --- /dev/null +++ b/dist/amd/src/proxy-namespace.js @@ -0,0 +1,19 @@ +/*can-debug@1.0.4#src/proxy-namespace*/ +define(function (require, exports, module) { + (function (global, require, exports, module) { + var warned = false; + module.exports = function proxyNamespace(namespace) { + return new Proxy(namespace, { + get: function get(target, name) { + if (!warned) { + console.warn('Warning: use of \'can\' global should be for debugging purposes only.'); + warned = true; + } + return target[name]; + } + }); + }; + }(function () { + return this; + }(), require, exports, module)); +}); \ No newline at end of file diff --git a/dist/amd/src/temporarily-bind.js b/dist/amd/src/temporarily-bind.js new file mode 100644 index 0000000..6b086d0 --- /dev/null +++ b/dist/amd/src/temporarily-bind.js @@ -0,0 +1,48 @@ +/*can-debug@1.0.4#src/temporarily-bind*/ +define([ + 'require', + 'exports', + 'module', + 'can-symbol', + 'can-reflect' +], function (require, exports, module) { + var canSymbol = require('can-symbol'); + var canReflect = require('can-reflect'); + var onValueSymbol = canSymbol.for('can.onValue'); + var offValueSymbol = canSymbol.for('can.offValue'); + var onKeyValueSymbol = canSymbol.for('can.onKeyValue'); + var offKeyValueSymbol = canSymbol.for('can.offKeyValue'); + var noop = function noop() { + }; + function isFunction(value) { + return typeof value === 'function'; + } + function withKey(obj, key, fn) { + var result; + if (isFunction(obj[onKeyValueSymbol])) { + canReflect.onKeyValue(obj, key, noop); + } + result = fn(obj, key); + if (isFunction(obj[offKeyValueSymbol])) { + canReflect.offKeyValue(obj, key, noop); + } + return result; + } + function withoutKey(obj, fn) { + var result; + if (isFunction(obj[onValueSymbol])) { + canReflect.onValue(obj, noop); + } + result = fn(obj); + if (isFunction(obj[offValueSymbol])) { + canReflect.offValue(obj, noop); + } + return result; + } + module.exports = function temporarilyBind(fn) { + return function (obj, key) { + var gotKey = arguments.length === 2; + return gotKey ? withKey(obj, key, fn) : withoutKey(obj, fn); + }; + }; +}); \ No newline at end of file diff --git a/dist/amd/src/what-changes-me/what-changes-me.js b/dist/amd/src/what-changes-me/what-changes-me.js new file mode 100644 index 0000000..633a1f3 --- /dev/null +++ b/dist/amd/src/what-changes-me/what-changes-me.js @@ -0,0 +1,20 @@ +/*can-debug@1.0.4#src/what-changes-me/what-changes-me*/ +define([ + 'require', + 'exports', + 'module', + '../log-data/log-data', + '../get-data/get-data', + '../get-graph/get-graph' +], function (require, exports, module) { + var log = require('../log-data/log-data'); + var getData = require('../get-data/get-data'); + var getGraph = require('../get-graph/get-graph'); + module.exports = function logWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); + if (data) { + log(data); + } + }; +}); \ No newline at end of file diff --git a/dist/amd/src/what-i-change/what-i-change.js b/dist/amd/src/what-i-change/what-i-change.js new file mode 100644 index 0000000..c4cef37 --- /dev/null +++ b/dist/amd/src/what-i-change/what-i-change.js @@ -0,0 +1,20 @@ +/*can-debug@1.0.4#src/what-i-change/what-i-change*/ +define([ + 'require', + 'exports', + 'module', + '../log-data/log-data', + '../get-data/get-data', + '../get-graph/get-graph' +], function (require, exports, module) { + var log = require('../log-data/log-data'); + var getData = require('../get-data/get-data'); + var getGraph = require('../get-graph/get-graph'); + module.exports = function logWhatIChange(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); + if (data) { + log(data); + } + }; +}); \ No newline at end of file diff --git a/dist/cjs/can-debug.js b/dist/cjs/can-debug.js new file mode 100644 index 0000000..828a3cf --- /dev/null +++ b/dist/cjs/can-debug.js @@ -0,0 +1,24 @@ +/*can-debug@1.0.4#can-debug*/ +var namespace = require('can-namespace'); +var proxyNamespace = require('./src/proxy-namespace.js'); +var temporarilyBind = require('./src/temporarily-bind.js'); +var getGraph = require('./src/get-graph/get-graph.js'); +var formatGraph = require('./src/draw-graph/format-graph.js'); +var drawGraph = require('./src/draw-graph/draw-graph.js'); +var logWhatIChange = require('./src/what-i-change/what-i-change.js'); +var logWhatChangesMe = require('./src/what-changes-me/what-changes-me.js'); +var getWhatIChange = require('./src/get-what-i-change/get-what-i-change.js'); +var getWhatChangesMe = require('./src/get-what-changes-me/get-what-changes-me.js'); +module.exports = namespace.debug = { + getGraph: temporarilyBind(getGraph), + formatGraph: temporarilyBind(formatGraph), + drawGraph: temporarilyBind(drawGraph), + getWhatIChange: temporarilyBind(getWhatIChange), + getWhatChangesMe: temporarilyBind(getWhatChangesMe), + logWhatIChange: temporarilyBind(logWhatIChange), + logWhatChangesMe: temporarilyBind(logWhatChangesMe) +}; +window.can = typeof Proxy !== 'undefined' ? proxyNamespace(namespace) : namespace; +if (window.__CANJS_DEVTOOLS__) { + window.__CANJS_DEVTOOLS__.register(window.can); +} \ No newline at end of file diff --git a/dist/cjs/src/draw-graph/draw-graph.js b/dist/cjs/src/draw-graph/draw-graph.js new file mode 100644 index 0000000..f6400db --- /dev/null +++ b/dist/cjs/src/draw-graph/draw-graph.js @@ -0,0 +1,40 @@ +/*can-debug@1.0.4#src/draw-graph/draw-graph*/ +var formatGraph = require('./format-graph.js'); +var getGraph = require('../get-graph/get-graph.js'); +module.exports = function drawGraph(obj, key) { + var gotKey = arguments.length === 2; + var graph = gotKey ? getGraph(obj, key) : getGraph(obj); + fetch(__dirname + '/vis.js').then(function (res) { + return res.text(); + }).then(function (code) { + var w = window.open('', 'can-debug: Dependency Graph'); + var doc = w.document; + var script = doc.createElement('script'); + script.text = code; + doc.body.appendChild(script); + var data = formatGraph(graph); + var drawScript = doc.createElement('script'); + drawScript.text = ` + var container = document.createElement("div"); + + var options = { + physics: { + solver: "repulsion" + } + }; + + document.title = "can-debug: Dependency Graph"; + document.body.appendChild(container); + + new vis.Network( + container, + { + nodes: new vis.DataSet(${ JSON.stringify(data.nodes) }), + edges: new vis.DataSet(${ JSON.stringify(data.edges) }) + }, + options + ); + `; + doc.body.appendChild(drawScript); + }); +}; \ No newline at end of file diff --git a/dist/cjs/src/draw-graph/format-graph.js b/dist/cjs/src/draw-graph/format-graph.js new file mode 100644 index 0000000..d30f8fb --- /dev/null +++ b/dist/cjs/src/draw-graph/format-graph.js @@ -0,0 +1,54 @@ +/*can-debug@1.0.4#src/draw-graph/format-graph*/ +var canReflect = require('can-reflect'); +module.exports = function formatGraph(graph) { + var nodeIdMap = new Map(graph.nodes.map(function (node, index) { + return [ + node, + index + 1 + ]; + })); + var nodesDataSet = graph.nodes.map(function (node) { + return { + shape: 'box', + id: nodeIdMap.get(node), + label: canReflect.getName(node.obj) + (node.key ? '.' + node.key : '') + }; + }); + var getArrowData = function getArrowData(meta) { + var regular = { arrows: 'to' }; + var withDashes = { + arrows: 'to', + dashes: true + }; + var map = { + derive: regular, + mutate: withDashes + }; + return map[meta.kind]; + }; + var visited = new Map(); + var arrowsDataSet = []; + graph.nodes.forEach(function (node) { + var visit = function (node) { + if (!visited.has(node)) { + visited.set(node, true); + var arrows = graph.arrows.get(node); + var headId = nodeIdMap.get(node); + arrows.forEach(function (neighbor) { + var tailId = nodeIdMap.get(neighbor); + var meta = graph.arrowsMeta.get(node).get(neighbor); + arrowsDataSet.push(Object.assign({ + from: headId, + to: tailId + }, getArrowData(meta))); + visit(neighbor); + }); + } + }; + visit(node); + }); + return { + nodes: nodesDataSet, + edges: arrowsDataSet + }; +}; \ No newline at end of file diff --git a/dist/cjs/src/get-data/get-data.js b/dist/cjs/src/get-data/get-data.js new file mode 100644 index 0000000..39f530a --- /dev/null +++ b/dist/cjs/src/get-data/get-data.js @@ -0,0 +1,39 @@ +/*can-debug@1.0.4#src/get-data/get-data*/ +var labelCycles = require('../label-cycles/label-cycles.js'); +var isDisconnected = function isDisconnected(data) { + return !data.derive.length && !data.mutations.length && !data.twoWay.length; +}; +module.exports = function getDebugData(inputGraph, direction) { + var visited = new Map(); + var graph = labelCycles(direction === 'whatChangesMe' ? inputGraph.reverse() : inputGraph); + var visit = function visit(node) { + var data = { + node: node, + derive: [], + mutations: [], + twoWay: [] + }; + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + if (!visited.has(adj)) { + switch (meta.kind) { + case 'twoWay': + data.twoWay.push(visit(adj)); + break; + case 'derive': + data.derive.push(visit(adj)); + break; + case 'mutate': + data.mutations.push(visit(adj)); + break; + default: + throw new Error('Unknow meta.kind value: ', meta.kind); + } + } + }); + return data; + }; + var result = visit(graph.nodes[0]); + return isDisconnected(result) ? null : result; +}; \ No newline at end of file diff --git a/dist/cjs/src/get-graph/get-graph.js b/dist/cjs/src/get-graph/get-graph.js new file mode 100644 index 0000000..86158a5 --- /dev/null +++ b/dist/cjs/src/get-graph/get-graph.js @@ -0,0 +1,85 @@ +/*can-debug@1.0.4#src/get-graph/get-graph*/ +var Graph = require('../graph/graph.js'); +var makeNode = require('./make-node.js'); +var canReflect = require('can-reflect'); +var mutateDeps = require('can-reflect-dependencies'); +module.exports = function getGraph(obj, key) { + var order = 0; + var graph = new Graph(); + var gotKey = arguments.length === 2; + var addArrow = function addArrow(direction, parent, child, meta) { + switch (direction) { + case 'whatIChange': + graph.addArrow(parent, child, meta); + break; + case 'whatChangesMe': + graph.addArrow(child, parent, meta); + break; + default: + throw new Error('Unknown direction value: ', meta.direction); + } + }; + var visitKeyDependencies = function visitKeyDependencies(source, meta, cb) { + canReflect.eachKey(source.keyDependencies || {}, function (keys, obj) { + canReflect.each(keys, function (key) { + cb(obj, meta, key); + }); + }); + }; + var visitValueDependencies = function visitValueDependencies(source, meta, cb) { + canReflect.eachIndex(source.valueDependencies || [], function (obj) { + cb(obj, meta); + }); + }; + var visit = function visit(obj, meta, key) { + var gotKey = arguments.length === 3; + var node = graph.findNode(function (node) { + return gotKey ? node.obj === obj && node.key === key : node.obj === obj; + }); + if (node) { + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + return graph; + } + order += 1; + node = gotKey ? makeNode(obj, key) : makeNode(obj); + node.order = order; + graph.addNode(node); + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + var nextMeta; + var data = gotKey ? mutateDeps.getDependencyDataOf(obj, key) : mutateDeps.getDependencyDataOf(obj); + if (data && data.whatIChange) { + nextMeta = { + direction: 'whatIChange', + parent: node + }; + canReflect.eachKey(data.whatIChange, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + if (data && data.whatChangesMe) { + nextMeta = { + direction: 'whatChangesMe', + parent: node + }; + canReflect.eachKey(data.whatChangesMe, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + return graph; + }; + return gotKey ? visit(obj, {}, key) : visit(obj, {}); +}; \ No newline at end of file diff --git a/dist/cjs/src/get-graph/make-node.js b/dist/cjs/src/get-graph/make-node.js new file mode 100644 index 0000000..0ff945d --- /dev/null +++ b/dist/cjs/src/get-graph/make-node.js @@ -0,0 +1,14 @@ +/*can-debug@1.0.4#src/get-graph/make-node*/ +var canReflect = require('can-reflect'); +module.exports = function makeNode(obj, key) { + var gotKey = arguments.length === 2; + var node = { + obj: obj, + name: canReflect.getName(obj), + value: gotKey ? canReflect.getKeyValue(obj, key) : canReflect.getValue(obj) + }; + if (gotKey) { + node.key = key; + } + return node; +}; \ No newline at end of file diff --git a/dist/cjs/src/get-what-changes-me/get-what-changes-me.js b/dist/cjs/src/get-what-changes-me/get-what-changes-me.js new file mode 100644 index 0000000..a0d685f --- /dev/null +++ b/dist/cjs/src/get-what-changes-me/get-what-changes-me.js @@ -0,0 +1,7 @@ +/*can-debug@1.0.4#src/get-what-changes-me/get-what-changes-me*/ +var getData = require('../get-data/get-data.js'); +var getGraph = require('../get-graph/get-graph.js'); +module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); +}; \ No newline at end of file diff --git a/dist/cjs/src/get-what-i-change/get-what-i-change.js b/dist/cjs/src/get-what-i-change/get-what-i-change.js new file mode 100644 index 0000000..3663fbf --- /dev/null +++ b/dist/cjs/src/get-what-i-change/get-what-i-change.js @@ -0,0 +1,7 @@ +/*can-debug@1.0.4#src/get-what-i-change/get-what-i-change*/ +var getData = require('../get-data/get-data.js'); +var getGraph = require('../get-graph/get-graph.js'); +module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); +}; \ No newline at end of file diff --git a/dist/cjs/src/graph/graph.js b/dist/cjs/src/graph/graph.js new file mode 100644 index 0000000..bd2ccf9 --- /dev/null +++ b/dist/cjs/src/graph/graph.js @@ -0,0 +1,104 @@ +/*can-debug@1.0.4#src/graph/graph*/ +function Graph() { + this.nodes = []; + this.arrows = new Map(); + this.arrowsMeta = new Map(); +} +Graph.prototype.addNode = function addNode(node) { + this.nodes.push(node); + this.arrows.set(node, new Set()); +}; +Graph.prototype.addArrow = function addArrow(head, tail, meta) { + var graph = this; + graph.arrows.get(head).add(tail); + if (meta) { + addArrowMeta(graph, head, tail, meta); + } +}; +Graph.prototype.hasArrow = function hasArrow(head, tail) { + return this.getNeighbors(head).has(tail); +}; +Graph.prototype.getArrowMeta = function getArrowMeta(head, tail) { + return this.arrowsMeta.get(head) && this.arrowsMeta.get(head).get(tail); +}; +Graph.prototype.setArrowMeta = function setArrowMeta(head, tail, meta) { + addArrowMeta(this, head, tail, meta); +}; +Graph.prototype.getNeighbors = function getNeighbors(node) { + return this.arrows.get(node); +}; +Graph.prototype.findNode = function findNode(cb) { + var found = null; + var graph = this; + for (var node of graph.nodes) { + if (cb(node)) { + found = node; + break; + } + } + return found; +}; +Graph.prototype.bfs = function bfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var queue = [node]; + var visited = new Map([[ + node, + true + ]]); + while (queue.length) { + node = queue.shift(); + visit(node); + graph.arrows.get(node).forEach(function (adj) { + if (!visited.has(adj)) { + queue.push(adj); + visited.set(adj, true); + } + }); + } +}; +Graph.prototype.dfs = function dfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var stack = [node]; + var visited = new Map(); + while (stack.length) { + node = stack.pop(); + visit(node); + if (!visited.has(node)) { + visited.set(node, true); + graph.arrows.get(node).forEach(function (adj) { + stack.push(adj); + }); + } + } +}; +Graph.prototype.reverse = function reverse() { + var graph = this; + var reversed = new Graph(); + graph.nodes.forEach(reversed.addNode.bind(reversed)); + graph.nodes.forEach(function (node) { + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + reversed.addArrow(adj, node, meta); + }); + }); + return reversed; +}; +function addArrowMeta(graph, head, tail, meta) { + var entry = graph.arrowsMeta.get(head); + if (entry) { + var arrowMeta = entry.get(tail); + if (!arrowMeta) { + arrowMeta = {}; + } + entry.set(tail, Object.assign(arrowMeta, meta)); + } else { + entry = new Map([[ + tail, + meta + ]]); + graph.arrowsMeta.set(head, entry); + } +} +module.exports = Graph; \ No newline at end of file diff --git a/dist/cjs/src/label-cycles/label-cycles.js b/dist/cjs/src/label-cycles/label-cycles.js new file mode 100644 index 0000000..5b9bc30 --- /dev/null +++ b/dist/cjs/src/label-cycles/label-cycles.js @@ -0,0 +1,25 @@ +/*can-debug@1.0.4#src/label-cycles/label-cycles*/ +var Graph = require('../graph/graph.js'); +module.exports = function labelCycles(graph) { + var visited = new Map(); + var result = new Graph(); + graph.nodes.forEach(function (node) { + result.addNode(node); + }); + var visit = function visit(node) { + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + if (visited.has(adj)) { + var isTwoWay = graph.hasArrow(node, adj); + if (isTwoWay) { + result.addArrow(adj, node, { kind: 'twoWay' }); + } + } else { + result.addArrow(node, adj, graph.getArrowMeta(node, adj)); + visit(adj); + } + }); + }; + visit(graph.nodes[0]); + return result; +}; \ No newline at end of file diff --git a/dist/cjs/src/log-data/log-data.js b/dist/cjs/src/log-data/log-data.js new file mode 100644 index 0000000..8a9f702 --- /dev/null +++ b/dist/cjs/src/log-data/log-data.js @@ -0,0 +1,31 @@ +/*can-debug@1.0.4#src/log-data/log-data*/ +var canReflect = require('can-reflect'); +var quoteString = function quoteString(x) { + return typeof x === 'string' ? JSON.stringify(x) : x; +}; +module.exports = function log(data) { + var node = data.node; + var nameParts = [ + node.name, + 'key' in node ? '.' + node.key : '' + ]; + console.group(nameParts.join('')); + console.log('value ', quoteString(node.value)); + console.log('object ', node.obj); + if (data.derive.length) { + console.group('DERIVED FROM'); + canReflect.eachIndex(data.derive, log); + console.groupEnd(); + } + if (data.mutations.length) { + console.group('MUTATED BY'); + canReflect.eachIndex(data.mutations, log); + console.groupEnd(); + } + if (data.twoWay.length) { + console.group('TWO WAY'); + canReflect.eachIndex(data.twoWay, log); + console.groupEnd(); + } + console.groupEnd(); +}; \ No newline at end of file diff --git a/dist/cjs/src/proxy-namespace.js b/dist/cjs/src/proxy-namespace.js new file mode 100644 index 0000000..6f12d18 --- /dev/null +++ b/dist/cjs/src/proxy-namespace.js @@ -0,0 +1,13 @@ +/*can-debug@1.0.4#src/proxy-namespace*/ +var warned = false; +module.exports = function proxyNamespace(namespace) { + return new Proxy(namespace, { + get: function get(target, name) { + if (!warned) { + console.warn('Warning: use of \'can\' global should be for debugging purposes only.'); + warned = true; + } + return target[name]; + } + }); +}; \ No newline at end of file diff --git a/dist/cjs/src/temporarily-bind.js b/dist/cjs/src/temporarily-bind.js new file mode 100644 index 0000000..e7157b8 --- /dev/null +++ b/dist/cjs/src/temporarily-bind.js @@ -0,0 +1,40 @@ +/*can-debug@1.0.4#src/temporarily-bind*/ +var canSymbol = require('can-symbol'); +var canReflect = require('can-reflect'); +var onValueSymbol = canSymbol.for('can.onValue'); +var offValueSymbol = canSymbol.for('can.offValue'); +var onKeyValueSymbol = canSymbol.for('can.onKeyValue'); +var offKeyValueSymbol = canSymbol.for('can.offKeyValue'); +var noop = function noop() { +}; +function isFunction(value) { + return typeof value === 'function'; +} +function withKey(obj, key, fn) { + var result; + if (isFunction(obj[onKeyValueSymbol])) { + canReflect.onKeyValue(obj, key, noop); + } + result = fn(obj, key); + if (isFunction(obj[offKeyValueSymbol])) { + canReflect.offKeyValue(obj, key, noop); + } + return result; +} +function withoutKey(obj, fn) { + var result; + if (isFunction(obj[onValueSymbol])) { + canReflect.onValue(obj, noop); + } + result = fn(obj); + if (isFunction(obj[offValueSymbol])) { + canReflect.offValue(obj, noop); + } + return result; +} +module.exports = function temporarilyBind(fn) { + return function (obj, key) { + var gotKey = arguments.length === 2; + return gotKey ? withKey(obj, key, fn) : withoutKey(obj, fn); + }; +}; \ No newline at end of file diff --git a/dist/cjs/src/what-changes-me/what-changes-me.js b/dist/cjs/src/what-changes-me/what-changes-me.js new file mode 100644 index 0000000..1a9296d --- /dev/null +++ b/dist/cjs/src/what-changes-me/what-changes-me.js @@ -0,0 +1,11 @@ +/*can-debug@1.0.4#src/what-changes-me/what-changes-me*/ +var log = require('../log-data/log-data.js'); +var getData = require('../get-data/get-data.js'); +var getGraph = require('../get-graph/get-graph.js'); +module.exports = function logWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); + if (data) { + log(data); + } +}; \ No newline at end of file diff --git a/dist/cjs/src/what-i-change/what-i-change.js b/dist/cjs/src/what-i-change/what-i-change.js new file mode 100644 index 0000000..6e9f3bf --- /dev/null +++ b/dist/cjs/src/what-i-change/what-i-change.js @@ -0,0 +1,11 @@ +/*can-debug@1.0.4#src/what-i-change/what-i-change*/ +var log = require('../log-data/log-data.js'); +var getData = require('../get-data/get-data.js'); +var getGraph = require('../get-graph/get-graph.js'); +module.exports = function logWhatIChange(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); + if (data) { + log(data); + } +}; \ No newline at end of file diff --git a/dist/global/can-debug.js b/dist/global/can-debug.js new file mode 100644 index 0000000..8acc2e7 --- /dev/null +++ b/dist/global/can-debug.js @@ -0,0 +1,766 @@ +/*[global-shim-start]*/ +(function(exports, global, doEval) { + // jshint ignore:line + var origDefine = global.define; + + var get = function(name) { + var parts = name.split("."), + cur = global, + i; + for (i = 0; i < parts.length; i++) { + if (!cur) { + break; + } + cur = cur[parts[i]]; + } + return cur; + }; + var set = function(name, val) { + var parts = name.split("."), + cur = global, + i, + part, + next; + for (i = 0; i < parts.length - 1; i++) { + part = parts[i]; + next = cur[part]; + if (!next) { + next = cur[part] = {}; + } + cur = next; + } + part = parts[parts.length - 1]; + cur[part] = val; + }; + var useDefault = function(mod) { + if (!mod || !mod.__esModule) return false; + var esProps = { __esModule: true, default: true }; + for (var p in mod) { + if (!esProps[p]) return false; + } + return true; + }; + + var hasCjsDependencies = function(deps) { + return ( + deps[0] === "require" && deps[1] === "exports" && deps[2] === "module" + ); + }; + + var modules = + (global.define && global.define.modules) || + (global._define && global._define.modules) || + {}; + var ourDefine = (global.define = function(moduleName, deps, callback) { + var module; + if (typeof deps === "function") { + callback = deps; + deps = []; + } + var args = [], + i; + for (i = 0; i < deps.length; i++) { + args.push( + exports[deps[i]] + ? get(exports[deps[i]]) + : modules[deps[i]] || get(deps[i]) + ); + } + // CJS has no dependencies but 3 callback arguments + if (hasCjsDependencies(deps) || (!deps.length && callback.length)) { + module = { exports: {} }; + args[0] = function(name) { + return exports[name] ? get(exports[name]) : modules[name]; + }; + args[1] = module.exports; + args[2] = module; + } else if (!args[0] && deps[0] === "exports") { + // Babel uses the exports and module object. + module = { exports: {} }; + args[0] = module.exports; + if (deps[1] === "module") { + args[1] = module; + } + } else if (!args[0] && deps[0] === "module") { + args[0] = { id: moduleName }; + } + + global.define = origDefine; + var result = callback ? callback.apply(null, args) : undefined; + global.define = ourDefine; + + // Favor CJS module.exports over the return value + result = module && module.exports ? module.exports : result; + modules[moduleName] = result; + + // Set global exports + var globalExport = exports[moduleName]; + if (globalExport && !get(globalExport)) { + if (useDefault(result)) { + result = result["default"]; + } + set(globalExport, result); + } + }); + global.define.orig = origDefine; + global.define.modules = modules; + global.define.amd = true; + ourDefine("@loader", [], function() { + // shim for @@global-helpers + var noop = function() {}; + return { + get: function() { + return { prepareGlobal: noop, retrieveGlobal: noop }; + }, + global: global, + __exec: function(__load) { + doEval(__load.source, global); + } + }; + }); +})( + {}, + typeof self == "object" && self.Object == Object + ? self + : typeof process === "object" && + Object.prototype.toString.call(process) === "[object process]" + ? global + : window, + function(__$source__, __$global__) { + // jshint ignore:line + eval("(function() { " + __$source__ + " \n }).call(__$global__);"); + } +); + +/*can-debug@1.0.4#src/proxy-namespace*/ +define('can-debug/src/proxy-namespace', function (require, exports, module) { + (function (global, require, exports, module) { + var warned = false; + module.exports = function proxyNamespace(namespace) { + return new Proxy(namespace, { + get: function get(target, name) { + if (!warned) { + console.warn('Warning: use of \'can\' global should be for debugging purposes only.'); + warned = true; + } + return target[name]; + } + }); + }; + }(function () { + return this; + }(), require, exports, module)); +}); +/*can-debug@1.0.4#src/temporarily-bind*/ +define('can-debug/src/temporarily-bind', [ + 'require', + 'exports', + 'module', + 'can-symbol', + 'can-reflect' +], function (require, exports, module) { + var canSymbol = require('can-symbol'); + var canReflect = require('can-reflect'); + var onValueSymbol = canSymbol.for('can.onValue'); + var offValueSymbol = canSymbol.for('can.offValue'); + var onKeyValueSymbol = canSymbol.for('can.onKeyValue'); + var offKeyValueSymbol = canSymbol.for('can.offKeyValue'); + var noop = function noop() { + }; + function isFunction(value) { + return typeof value === 'function'; + } + function withKey(obj, key, fn) { + var result; + if (isFunction(obj[onKeyValueSymbol])) { + canReflect.onKeyValue(obj, key, noop); + } + result = fn(obj, key); + if (isFunction(obj[offKeyValueSymbol])) { + canReflect.offKeyValue(obj, key, noop); + } + return result; + } + function withoutKey(obj, fn) { + var result; + if (isFunction(obj[onValueSymbol])) { + canReflect.onValue(obj, noop); + } + result = fn(obj); + if (isFunction(obj[offValueSymbol])) { + canReflect.offValue(obj, noop); + } + return result; + } + module.exports = function temporarilyBind(fn) { + return function (obj, key) { + var gotKey = arguments.length === 2; + return gotKey ? withKey(obj, key, fn) : withoutKey(obj, fn); + }; + }; +}); +/*can-debug@1.0.4#src/graph/graph*/ +define('can-debug/src/graph/graph', function (require, exports, module) { + function Graph() { + this.nodes = []; + this.arrows = new Map(); + this.arrowsMeta = new Map(); + } + Graph.prototype.addNode = function addNode(node) { + this.nodes.push(node); + this.arrows.set(node, new Set()); + }; + Graph.prototype.addArrow = function addArrow(head, tail, meta) { + var graph = this; + graph.arrows.get(head).add(tail); + if (meta) { + addArrowMeta(graph, head, tail, meta); + } + }; + Graph.prototype.hasArrow = function hasArrow(head, tail) { + return this.getNeighbors(head).has(tail); + }; + Graph.prototype.getArrowMeta = function getArrowMeta(head, tail) { + return this.arrowsMeta.get(head) && this.arrowsMeta.get(head).get(tail); + }; + Graph.prototype.setArrowMeta = function setArrowMeta(head, tail, meta) { + addArrowMeta(this, head, tail, meta); + }; + Graph.prototype.getNeighbors = function getNeighbors(node) { + return this.arrows.get(node); + }; + Graph.prototype.findNode = function findNode(cb) { + var found = null; + var graph = this; + for (var node of graph.nodes) { + if (cb(node)) { + found = node; + break; + } + } + return found; + }; + Graph.prototype.bfs = function bfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var queue = [node]; + var visited = new Map([[ + node, + true + ]]); + while (queue.length) { + node = queue.shift(); + visit(node); + graph.arrows.get(node).forEach(function (adj) { + if (!visited.has(adj)) { + queue.push(adj); + visited.set(adj, true); + } + }); + } + }; + Graph.prototype.dfs = function dfs(visit) { + var graph = this; + var node = graph.nodes[0]; + var stack = [node]; + var visited = new Map(); + while (stack.length) { + node = stack.pop(); + visit(node); + if (!visited.has(node)) { + visited.set(node, true); + graph.arrows.get(node).forEach(function (adj) { + stack.push(adj); + }); + } + } + }; + Graph.prototype.reverse = function reverse() { + var graph = this; + var reversed = new Graph(); + graph.nodes.forEach(reversed.addNode.bind(reversed)); + graph.nodes.forEach(function (node) { + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + reversed.addArrow(adj, node, meta); + }); + }); + return reversed; + }; + function addArrowMeta(graph, head, tail, meta) { + var entry = graph.arrowsMeta.get(head); + if (entry) { + var arrowMeta = entry.get(tail); + if (!arrowMeta) { + arrowMeta = {}; + } + entry.set(tail, Object.assign(arrowMeta, meta)); + } else { + entry = new Map([[ + tail, + meta + ]]); + graph.arrowsMeta.set(head, entry); + } + } + module.exports = Graph; +}); +/*can-debug@1.0.4#src/get-graph/make-node*/ +define('can-debug/src/get-graph/make-node', [ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + module.exports = function makeNode(obj, key) { + var gotKey = arguments.length === 2; + var node = { + obj: obj, + name: canReflect.getName(obj), + value: gotKey ? canReflect.getKeyValue(obj, key) : canReflect.getValue(obj) + }; + if (gotKey) { + node.key = key; + } + return node; + }; +}); +/*can-debug@1.0.4#src/get-graph/get-graph*/ +define('can-debug/src/get-graph/get-graph', [ + 'require', + 'exports', + 'module', + 'can-debug/src/graph/graph', + 'can-debug/src/get-graph/make-node', + 'can-reflect', + 'can-reflect-dependencies' +], function (require, exports, module) { + var Graph = require('can-debug/src/graph/graph'); + var makeNode = require('can-debug/src/get-graph/make-node'); + var canReflect = require('can-reflect'); + var mutateDeps = require('can-reflect-dependencies'); + module.exports = function getGraph(obj, key) { + var order = 0; + var graph = new Graph(); + var gotKey = arguments.length === 2; + var addArrow = function addArrow(direction, parent, child, meta) { + switch (direction) { + case 'whatIChange': + graph.addArrow(parent, child, meta); + break; + case 'whatChangesMe': + graph.addArrow(child, parent, meta); + break; + default: + throw new Error('Unknown direction value: ', meta.direction); + } + }; + var visitKeyDependencies = function visitKeyDependencies(source, meta, cb) { + canReflect.eachKey(source.keyDependencies || {}, function (keys, obj) { + canReflect.each(keys, function (key) { + cb(obj, meta, key); + }); + }); + }; + var visitValueDependencies = function visitValueDependencies(source, meta, cb) { + canReflect.eachIndex(source.valueDependencies || [], function (obj) { + cb(obj, meta); + }); + }; + var visit = function visit(obj, meta, key) { + var gotKey = arguments.length === 3; + var node = graph.findNode(function (node) { + return gotKey ? node.obj === obj && node.key === key : node.obj === obj; + }); + if (node) { + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + return graph; + } + order += 1; + node = gotKey ? makeNode(obj, key) : makeNode(obj); + node.order = order; + graph.addNode(node); + if (meta.parent) { + addArrow(meta.direction, meta.parent, node, { + kind: meta.kind, + direction: meta.direction + }); + } + var nextMeta; + var data = gotKey ? mutateDeps.getDependencyDataOf(obj, key) : mutateDeps.getDependencyDataOf(obj); + if (data && data.whatIChange) { + nextMeta = { + direction: 'whatIChange', + parent: node + }; + canReflect.eachKey(data.whatIChange, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + if (data && data.whatChangesMe) { + nextMeta = { + direction: 'whatChangesMe', + parent: node + }; + canReflect.eachKey(data.whatChangesMe, function (dependencyRecord, kind) { + nextMeta.kind = kind; + visitKeyDependencies(dependencyRecord, nextMeta, visit); + visitValueDependencies(dependencyRecord, nextMeta, visit); + }); + } + return graph; + }; + return gotKey ? visit(obj, {}, key) : visit(obj, {}); + }; +}); +/*can-debug@1.0.4#src/draw-graph/format-graph*/ +define('can-debug/src/draw-graph/format-graph', [ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + module.exports = function formatGraph(graph) { + var nodeIdMap = new Map(graph.nodes.map(function (node, index) { + return [ + node, + index + 1 + ]; + })); + var nodesDataSet = graph.nodes.map(function (node) { + return { + shape: 'box', + id: nodeIdMap.get(node), + label: canReflect.getName(node.obj) + (node.key ? '.' + node.key : '') + }; + }); + var getArrowData = function getArrowData(meta) { + var regular = { arrows: 'to' }; + var withDashes = { + arrows: 'to', + dashes: true + }; + var map = { + derive: regular, + mutate: withDashes + }; + return map[meta.kind]; + }; + var visited = new Map(); + var arrowsDataSet = []; + graph.nodes.forEach(function (node) { + var visit = function (node) { + if (!visited.has(node)) { + visited.set(node, true); + var arrows = graph.arrows.get(node); + var headId = nodeIdMap.get(node); + arrows.forEach(function (neighbor) { + var tailId = nodeIdMap.get(neighbor); + var meta = graph.arrowsMeta.get(node).get(neighbor); + arrowsDataSet.push(Object.assign({ + from: headId, + to: tailId + }, getArrowData(meta))); + visit(neighbor); + }); + } + }; + visit(node); + }); + return { + nodes: nodesDataSet, + edges: arrowsDataSet + }; + }; +}); +/*can-debug@1.0.4#src/draw-graph/draw-graph*/ +define('can-debug/src/draw-graph/draw-graph', [ + 'require', + 'exports', + 'module', + 'can-debug/src/draw-graph/format-graph', + 'can-debug/src/get-graph/get-graph' +], function (require, exports, module) { + (function (__dirname, require, exports, module) { + var formatGraph = require('can-debug/src/draw-graph/format-graph'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + module.exports = function drawGraph(obj, key) { + var gotKey = arguments.length === 2; + var graph = gotKey ? getGraph(obj, key) : getGraph(obj); + fetch(__dirname + '/vis.js').then(function (res) { + return res.text(); + }).then(function (code) { + var w = window.open('', 'can-debug: Dependency Graph'); + var doc = w.document; + var script = doc.createElement('script'); + script.text = code; + doc.body.appendChild(script); + var data = formatGraph(graph); + var drawScript = doc.createElement('script'); + drawScript.text = ` + var container = document.createElement("div"); + + var options = { + physics: { + solver: "repulsion" + } + }; + + document.title = "can-debug: Dependency Graph"; + document.body.appendChild(container); + + new vis.Network( + container, + { + nodes: new vis.DataSet(${ JSON.stringify(data.nodes) }), + edges: new vis.DataSet(${ JSON.stringify(data.edges) }) + }, + options + ); + `; + doc.body.appendChild(drawScript); + }); + }; + }('/', require, exports, module)); +}); +/*can-debug@1.0.4#src/log-data/log-data*/ +define('can-debug/src/log-data/log-data', [ + 'require', + 'exports', + 'module', + 'can-reflect' +], function (require, exports, module) { + var canReflect = require('can-reflect'); + var quoteString = function quoteString(x) { + return typeof x === 'string' ? JSON.stringify(x) : x; + }; + module.exports = function log(data) { + var node = data.node; + var nameParts = [ + node.name, + 'key' in node ? '.' + node.key : '' + ]; + console.group(nameParts.join('')); + console.log('value ', quoteString(node.value)); + console.log('object ', node.obj); + if (data.derive.length) { + console.group('DERIVED FROM'); + canReflect.eachIndex(data.derive, log); + console.groupEnd(); + } + if (data.mutations.length) { + console.group('MUTATED BY'); + canReflect.eachIndex(data.mutations, log); + console.groupEnd(); + } + if (data.twoWay.length) { + console.group('TWO WAY'); + canReflect.eachIndex(data.twoWay, log); + console.groupEnd(); + } + console.groupEnd(); + }; +}); +/*can-debug@1.0.4#src/label-cycles/label-cycles*/ +define('can-debug/src/label-cycles/label-cycles', [ + 'require', + 'exports', + 'module', + 'can-debug/src/graph/graph' +], function (require, exports, module) { + var Graph = require('can-debug/src/graph/graph'); + module.exports = function labelCycles(graph) { + var visited = new Map(); + var result = new Graph(); + graph.nodes.forEach(function (node) { + result.addNode(node); + }); + var visit = function visit(node) { + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + if (visited.has(adj)) { + var isTwoWay = graph.hasArrow(node, adj); + if (isTwoWay) { + result.addArrow(adj, node, { kind: 'twoWay' }); + } + } else { + result.addArrow(node, adj, graph.getArrowMeta(node, adj)); + visit(adj); + } + }); + }; + visit(graph.nodes[0]); + return result; + }; +}); +/*can-debug@1.0.4#src/get-data/get-data*/ +define('can-debug/src/get-data/get-data', [ + 'require', + 'exports', + 'module', + 'can-debug/src/label-cycles/label-cycles' +], function (require, exports, module) { + var labelCycles = require('can-debug/src/label-cycles/label-cycles'); + var isDisconnected = function isDisconnected(data) { + return !data.derive.length && !data.mutations.length && !data.twoWay.length; + }; + module.exports = function getDebugData(inputGraph, direction) { + var visited = new Map(); + var graph = labelCycles(direction === 'whatChangesMe' ? inputGraph.reverse() : inputGraph); + var visit = function visit(node) { + var data = { + node: node, + derive: [], + mutations: [], + twoWay: [] + }; + visited.set(node, true); + graph.getNeighbors(node).forEach(function (adj) { + var meta = graph.getArrowMeta(node, adj); + if (!visited.has(adj)) { + switch (meta.kind) { + case 'twoWay': + data.twoWay.push(visit(adj)); + break; + case 'derive': + data.derive.push(visit(adj)); + break; + case 'mutate': + data.mutations.push(visit(adj)); + break; + default: + throw new Error('Unknow meta.kind value: ', meta.kind); + } + } + }); + return data; + }; + var result = visit(graph.nodes[0]); + return isDisconnected(result) ? null : result; + }; +}); +/*can-debug@1.0.4#src/what-i-change/what-i-change*/ +define('can-debug/src/what-i-change/what-i-change', [ + 'require', + 'exports', + 'module', + 'can-debug/src/log-data/log-data', + 'can-debug/src/get-data/get-data', + 'can-debug/src/get-graph/get-graph' +], function (require, exports, module) { + var log = require('can-debug/src/log-data/log-data'); + var getData = require('can-debug/src/get-data/get-data'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + module.exports = function logWhatIChange(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); + if (data) { + log(data); + } + }; +}); +/*can-debug@1.0.4#src/what-changes-me/what-changes-me*/ +define('can-debug/src/what-changes-me/what-changes-me', [ + 'require', + 'exports', + 'module', + 'can-debug/src/log-data/log-data', + 'can-debug/src/get-data/get-data', + 'can-debug/src/get-graph/get-graph' +], function (require, exports, module) { + var log = require('can-debug/src/log-data/log-data'); + var getData = require('can-debug/src/get-data/get-data'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + module.exports = function logWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + var data = getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); + if (data) { + log(data); + } + }; +}); +/*can-debug@1.0.4#src/get-what-i-change/get-what-i-change*/ +define('can-debug/src/get-what-i-change/get-what-i-change', [ + 'require', + 'exports', + 'module', + 'can-debug/src/get-data/get-data', + 'can-debug/src/get-graph/get-graph' +], function (require, exports, module) { + var getData = require('can-debug/src/get-data/get-data'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatIChange'); + }; +}); +/*can-debug@1.0.4#src/get-what-changes-me/get-what-changes-me*/ +define('can-debug/src/get-what-changes-me/get-what-changes-me', [ + 'require', + 'exports', + 'module', + 'can-debug/src/get-data/get-data', + 'can-debug/src/get-graph/get-graph' +], function (require, exports, module) { + var getData = require('can-debug/src/get-data/get-data'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + module.exports = function getWhatChangesMe(obj, key) { + var gotKey = arguments.length === 2; + return getData(gotKey ? getGraph(obj, key) : getGraph(obj), 'whatChangesMe'); + }; +}); +/*can-debug@1.0.4#can-debug*/ +define('can-debug', [ + 'require', + 'exports', + 'module', + 'can-namespace', + 'can-debug/src/proxy-namespace', + 'can-debug/src/temporarily-bind', + 'can-debug/src/get-graph/get-graph', + 'can-debug/src/draw-graph/format-graph', + 'can-debug/src/draw-graph/draw-graph', + 'can-debug/src/what-i-change/what-i-change', + 'can-debug/src/what-changes-me/what-changes-me', + 'can-debug/src/get-what-i-change/get-what-i-change', + 'can-debug/src/get-what-changes-me/get-what-changes-me' +], function (require, exports, module) { + var namespace = require('can-namespace'); + var proxyNamespace = require('can-debug/src/proxy-namespace'); + var temporarilyBind = require('can-debug/src/temporarily-bind'); + var getGraph = require('can-debug/src/get-graph/get-graph'); + var formatGraph = require('can-debug/src/draw-graph/format-graph'); + var drawGraph = require('can-debug/src/draw-graph/draw-graph'); + var logWhatIChange = require('can-debug/src/what-i-change/what-i-change'); + var logWhatChangesMe = require('can-debug/src/what-changes-me/what-changes-me'); + var getWhatIChange = require('can-debug/src/get-what-i-change/get-what-i-change'); + var getWhatChangesMe = require('can-debug/src/get-what-changes-me/get-what-changes-me'); + module.exports = namespace.debug = { + getGraph: temporarilyBind(getGraph), + formatGraph: temporarilyBind(formatGraph), + drawGraph: temporarilyBind(drawGraph), + getWhatIChange: temporarilyBind(getWhatIChange), + getWhatChangesMe: temporarilyBind(getWhatChangesMe), + logWhatIChange: temporarilyBind(logWhatIChange), + logWhatChangesMe: temporarilyBind(logWhatChangesMe) + }; + window.can = typeof Proxy !== 'undefined' ? proxyNamespace(namespace) : namespace; + if (window.__CANJS_DEVTOOLS__) { + window.__CANJS_DEVTOOLS__.register(window.can); + } +}); +/*[global-shim-end]*/ +(function(global) { // jshint ignore:line + global._define = global.define; + global.define = global.define.orig; +} +)(typeof self == "object" && self.Object == Object ? self : (typeof process === "object" && Object.prototype.toString.call(process) === "[object process]") ? global : window); \ No newline at end of file