@tramvai/module-deps-graph 2.70.1 → 2.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ import { createPapiMethod } from '@tramvai/papi';
2
+ import { getGraph } from '../utils/get-graph.es.js';
3
+
4
+ const depsGraph = ({ di }) => {
5
+ return createPapiMethod({
6
+ method: 'get',
7
+ path: '/deps-graph',
8
+ async handler({ parsedUrl: { query }, responseManager }) {
9
+ var _a;
10
+ const graphs = getGraph({ di, searchValue: (_a = query.search) !== null && _a !== void 0 ? _a : '' });
11
+ function isLineVisible(line, graph) {
12
+ var _a;
13
+ return (!query.lines && graph) || ((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(line) !== -1;
14
+ }
15
+ responseManager.setHeader('content-type', 'text/html');
16
+ responseManager.setBody(`
17
+ <script src="//d3js.org/d3.v6.min.js"></script>
18
+ <script src="https://unpkg.com/@hpcc-js/wasm@1.4.1/dist/index.min.js"></script>
19
+ <script src="https://unpkg.com/d3-graphviz@4.0.0/build/d3-graphviz.js"></script>
20
+
21
+ <div style="cursor: pointer; text-align: center; background: rgba(170,170,170,.7); position: fixed; right: 10px; top: 10px; width: 30px; height: 30px; font-size: 20px;" onClick="backToTop()">
22
+ 🠕
23
+ </div>
24
+
25
+ <h3>Search:</h3>
26
+ <input placeholder="Search module and token names..." value="${query.search || ''}" style="padding: 10px 4px; width: 450px" onkeyup="event.keyCode === 13 && applySearch(this.value)" onblur="applySearch(this.value)"/><br/>
27
+
28
+ <h3>Command Lines:</h3>
29
+ ${graphs
30
+ .map(([token, graph]) => {
31
+ var _a;
32
+ return `
33
+ <input id="${token}" type="checkbox" ${((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(token) !== -1 ? 'checked' : ''} onchange="toggleLine('${token}')"/><label ${!graph ? 'style="color: gray"' : ''} for="${token}">${token}</label>
34
+ `;
35
+ })
36
+ .join('<br/>')}
37
+
38
+
39
+ <h3>Graphs:</h3>
40
+ ${graphs
41
+ .map(([token, graph]) => `
42
+ <section style="display: ${isLineVisible(token, graph) ? 'block' : 'none'}">
43
+ <h3>${token}</h3>
44
+ <div id="${token}_graph"></div>
45
+ <hr style="margin: 15px 0;"/>
46
+ </section>
47
+ `)
48
+ .join('')}
49
+ <script>
50
+ window.toggleLine = function(line) {
51
+ const searchParams = new URLSearchParams(location.search)
52
+ const lines = searchParams.get('lines')
53
+ let selected = lines ? lines.split(',') : []
54
+ if (selected.indexOf(line) !== -1) {
55
+ selected.splice(selected.indexOf(line), 1)
56
+ } else {
57
+ selected = selected.concat(line)
58
+ }
59
+
60
+ searchParams.set('lines', selected.join(','))
61
+ location.search = searchParams.toString()
62
+ }
63
+
64
+ window.applySearch = function(search) {
65
+ const searchParams = new URLSearchParams(location.search)
66
+ searchParams.set('search', search)
67
+ location.search = searchParams.toString()
68
+ }
69
+
70
+ const searchParams = new URLSearchParams(location.search)
71
+ const selectedLines = searchParams.get('lines')
72
+ const graphs = ${JSON.stringify(graphs)}
73
+ const renderedGraphs = graphs
74
+ .filter(([token]) => {
75
+ return !selectedLines || selectedLines.split(',').find(t => t === token)
76
+ })
77
+
78
+ window.backToTop = function() {
79
+ window.scrollTo({
80
+ top: 0,
81
+ left: 0,
82
+ behavior: "smooth"
83
+ })
84
+
85
+ renderedGraphs
86
+ .forEach(([token]) => {
87
+ d3.select('#' + token + '_graph')
88
+ .graphviz()
89
+ .resetZoom(500);
90
+ })
91
+ }
92
+
93
+ renderedGraphs
94
+ .forEach(([token, graph]) => {
95
+ d3.select('#' + token + '_graph')
96
+ .graphviz()
97
+ .renderDot(graph);
98
+ })
99
+ </script>
100
+ `);
101
+ },
102
+ });
103
+ };
104
+
105
+ export { depsGraph };
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var papi = require('@tramvai/papi');
6
+ var getGraph = require('../utils/get-graph.js');
7
+
8
+ const depsGraph = ({ di }) => {
9
+ return papi.createPapiMethod({
10
+ method: 'get',
11
+ path: '/deps-graph',
12
+ async handler({ parsedUrl: { query }, responseManager }) {
13
+ var _a;
14
+ const graphs = getGraph.getGraph({ di, searchValue: (_a = query.search) !== null && _a !== void 0 ? _a : '' });
15
+ function isLineVisible(line, graph) {
16
+ var _a;
17
+ return (!query.lines && graph) || ((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(line) !== -1;
18
+ }
19
+ responseManager.setHeader('content-type', 'text/html');
20
+ responseManager.setBody(`
21
+ <script src="//d3js.org/d3.v6.min.js"></script>
22
+ <script src="https://unpkg.com/@hpcc-js/wasm@1.4.1/dist/index.min.js"></script>
23
+ <script src="https://unpkg.com/d3-graphviz@4.0.0/build/d3-graphviz.js"></script>
24
+
25
+ <div style="cursor: pointer; text-align: center; background: rgba(170,170,170,.7); position: fixed; right: 10px; top: 10px; width: 30px; height: 30px; font-size: 20px;" onClick="backToTop()">
26
+ 🠕
27
+ </div>
28
+
29
+ <h3>Search:</h3>
30
+ <input placeholder="Search module and token names..." value="${query.search || ''}" style="padding: 10px 4px; width: 450px" onkeyup="event.keyCode === 13 && applySearch(this.value)" onblur="applySearch(this.value)"/><br/>
31
+
32
+ <h3>Command Lines:</h3>
33
+ ${graphs
34
+ .map(([token, graph]) => {
35
+ var _a;
36
+ return `
37
+ <input id="${token}" type="checkbox" ${((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(token) !== -1 ? 'checked' : ''} onchange="toggleLine('${token}')"/><label ${!graph ? 'style="color: gray"' : ''} for="${token}">${token}</label>
38
+ `;
39
+ })
40
+ .join('<br/>')}
41
+
42
+
43
+ <h3>Graphs:</h3>
44
+ ${graphs
45
+ .map(([token, graph]) => `
46
+ <section style="display: ${isLineVisible(token, graph) ? 'block' : 'none'}">
47
+ <h3>${token}</h3>
48
+ <div id="${token}_graph"></div>
49
+ <hr style="margin: 15px 0;"/>
50
+ </section>
51
+ `)
52
+ .join('')}
53
+ <script>
54
+ window.toggleLine = function(line) {
55
+ const searchParams = new URLSearchParams(location.search)
56
+ const lines = searchParams.get('lines')
57
+ let selected = lines ? lines.split(',') : []
58
+ if (selected.indexOf(line) !== -1) {
59
+ selected.splice(selected.indexOf(line), 1)
60
+ } else {
61
+ selected = selected.concat(line)
62
+ }
63
+
64
+ searchParams.set('lines', selected.join(','))
65
+ location.search = searchParams.toString()
66
+ }
67
+
68
+ window.applySearch = function(search) {
69
+ const searchParams = new URLSearchParams(location.search)
70
+ searchParams.set('search', search)
71
+ location.search = searchParams.toString()
72
+ }
73
+
74
+ const searchParams = new URLSearchParams(location.search)
75
+ const selectedLines = searchParams.get('lines')
76
+ const graphs = ${JSON.stringify(graphs)}
77
+ const renderedGraphs = graphs
78
+ .filter(([token]) => {
79
+ return !selectedLines || selectedLines.split(',').find(t => t === token)
80
+ })
81
+
82
+ window.backToTop = function() {
83
+ window.scrollTo({
84
+ top: 0,
85
+ left: 0,
86
+ behavior: "smooth"
87
+ })
88
+
89
+ renderedGraphs
90
+ .forEach(([token]) => {
91
+ d3.select('#' + token + '_graph')
92
+ .graphviz()
93
+ .resetZoom(500);
94
+ })
95
+ }
96
+
97
+ renderedGraphs
98
+ .forEach(([token, graph]) => {
99
+ d3.select('#' + token + '_graph')
100
+ .graphviz()
101
+ .renderDot(graph);
102
+ })
103
+ </script>
104
+ `);
105
+ },
106
+ });
107
+ };
108
+
109
+ exports.depsGraph = depsGraph;
package/lib/server.es.js CHANGED
@@ -1,241 +1,8 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { SERVER_MODULE_PAPI_PUBLIC_ROUTE } from '@tramvai/tokens-server';
3
3
  import { DI_TOKEN } from '@tinkoff/dippy';
4
- import { commandLineListTokens, Module, provide } from '@tramvai/core';
5
- import { createPapiMethod } from '@tramvai/papi';
6
-
7
- function traverseGraphUp(node, cb) {
8
- if (node) {
9
- cb(node);
10
- traverseGraphUp(node.parentNode, cb);
11
- }
12
- }
13
- const getGraph = ({ di, searchValue }) => {
14
- function getDepsFromRecord(container, parentNode, rank, record) {
15
- const deps = [];
16
- Object.values(record.resolvedDeps).forEach((k) => {
17
- const depGraph = buildDepsGraph(container, parentNode, rank,
18
- // @ts-ignore
19
- k.token ? k.token.toString() : k.toString());
20
- if (depGraph) {
21
- deps.push(depGraph);
22
- }
23
- });
24
- return deps;
25
- }
26
- function buildDepsGraph(container, parentNode, rank, token, recordOfMulti) {
27
- var _a, _b;
28
- const record = recordOfMulti || container.getRecord(Symbol.for(token));
29
- if (!record) {
30
- return null;
31
- }
32
- const moduleName = record.stack
33
- ? (_a = /\/(module(?:-|s\/)[\w-]*?)\//.exec(record.stack)) === null || _a === void 0 ? void 0 : _a[1].replace('modules/', '')
34
- : undefined;
35
- const searchMatch = searchValue &&
36
- ((token && token.indexOf(searchValue) !== -1) ||
37
- (moduleName && moduleName.indexOf(searchValue) !== -1));
38
- if (searchMatch) {
39
- traverseGraphUp(parentNode, (g) => {
40
- // eslint-disable-next-line no-param-reassign
41
- g.parentEdgeMatch = true;
42
- });
43
- }
44
- const node = {
45
- token,
46
- moduleName,
47
- record,
48
- match: searchMatch,
49
- childEdgeMatch: parentNode && (parentNode.match || parentNode.childEdgeMatch),
50
- parentNode,
51
- deps: [],
52
- rank,
53
- multi: !!record.multi,
54
- multiInstance: !!record.multi || !!recordOfMulti,
55
- };
56
- if ((_b = record.multi) === null || _b === void 0 ? void 0 : _b.length) {
57
- node.deps = record.multi.reduce((acc, r) => acc.concat(buildDepsGraph(container, node, rank + 1, token, r)), []);
58
- }
59
- else if (record === null || record === void 0 ? void 0 : record.resolvedDeps) {
60
- node.deps = getDepsFromRecord(container, node, rank + 1, record);
61
- }
62
- return node;
63
- }
64
- function formatGraphToDot(rootGraph) {
65
- const edges = [];
66
- const nodes = [];
67
- const groupsRank = {};
68
- const groupsByRank = {};
69
- function recurse(parentNodeId, node) {
70
- const nodeId = node.moduleName ? `${node.token}:${node.moduleName}` : node.token;
71
- const addNodeAndEdge = !searchValue || node.childEdgeMatch || node.parentEdgeMatch || node.match;
72
- if (!addNodeAndEdge) {
73
- return;
74
- }
75
- if (parentNodeId) {
76
- if (!edges.find((e) => e.from === parentNodeId && e.to === nodeId)) {
77
- edges.push({ from: parentNodeId, to: nodeId });
78
- }
79
- }
80
- if (!nodes.find((n) => n.id === nodeId)) {
81
- nodes.push({
82
- id: nodeId,
83
- label: node.moduleName ? `<b>${node.moduleName}</b> | ${node.token}` : node.token,
84
- multiInstance: node.multiInstance,
85
- match: node.match,
86
- });
87
- }
88
- if (!groupsRank[nodeId] || groupsRank[nodeId] < node.rank) {
89
- groupsRank[nodeId] = node.rank;
90
- }
91
- node.deps.forEach((d) => {
92
- recurse(node.multi ? parentNodeId : nodeId, d);
93
- });
94
- }
95
- recurse(null, rootGraph);
96
- Object.keys(groupsRank).forEach((nodeId) => {
97
- const rank = groupsRank[nodeId];
98
- groupsByRank[rank] = groupsByRank[rank] || [];
99
- groupsByRank[rank].push(nodeId);
100
- });
101
- const res = !nodes.length
102
- ? ''
103
- : `digraph g {
104
- rankdir = "LR";
105
- nodesep=0.1;
106
- ranksep=0.3;
107
- compound=true;
108
- concentrate=true;
109
- center=true;
110
- node [fontsize = "16", shape = "record", height=0.1, color=lightblue2];
111
- edge [];
112
- ${nodes
113
- .map((n) => {
114
- return `"${n.id}"[label=<${n.label}>]${n.multiInstance ? '[color="gold"]' : ''}${n.match ? '[color="red"]' : ''};`;
115
- })
116
- .join('\n')}
117
- ${edges
118
- .map((e) => {
119
- return `"${e.from}"->"${e.to}";`;
120
- })
121
- .join('\n')}
122
- ${Object.values(groupsByRank)
123
- .map((ids) => {
124
- return `{ rank = "same"; ${ids.map((id) => `"${id}"`).join(';')} }`;
125
- })
126
- .join('\n')}
127
- }`;
128
- return res;
129
- }
130
- return Object.values(commandLineListTokens)
131
- .map((k) => {
132
- const g = buildDepsGraph(di, null, 0, k.toString());
133
- return g ? [k.toString(), g] : null;
134
- })
135
- .filter(Boolean)
136
- .map(([k, g]) => [k, formatGraphToDot(g)]);
137
- };
138
-
139
- const depsGraph = ({ di }) => {
140
- return createPapiMethod({
141
- method: 'get',
142
- path: '/deps-graph',
143
- async handler({ parsedUrl: { query }, responseManager }) {
144
- var _a;
145
- const graphs = getGraph({ di, searchValue: (_a = query.search) !== null && _a !== void 0 ? _a : '' });
146
- function isLineVisible(line, graph) {
147
- var _a;
148
- return (!query.lines && graph) || ((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(line) !== -1;
149
- }
150
- responseManager.setHeader('content-type', 'text/html');
151
- responseManager.setBody(`
152
- <script src="//d3js.org/d3.v6.min.js"></script>
153
- <script src="https://unpkg.com/@hpcc-js/wasm@1.4.1/dist/index.min.js"></script>
154
- <script src="https://unpkg.com/d3-graphviz@4.0.0/build/d3-graphviz.js"></script>
155
-
156
- <div style="cursor: pointer; text-align: center; background: rgba(170,170,170,.7); position: fixed; right: 10px; top: 10px; width: 30px; height: 30px; font-size: 20px;" onClick="backToTop()">
157
- 🠕
158
- </div>
159
-
160
- <h3>Search:</h3>
161
- <input placeholder="Search module and token names..." value="${query.search || ''}" style="padding: 10px 4px; width: 450px" onkeyup="event.keyCode === 13 && applySearch(this.value)" onblur="applySearch(this.value)"/><br/>
162
-
163
- <h3>Command Lines:</h3>
164
- ${graphs
165
- .map(([token, graph]) => {
166
- var _a;
167
- return `
168
- <input id="${token}" type="checkbox" ${((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(token) !== -1 ? 'checked' : ''} onchange="toggleLine('${token}')"/><label ${!graph ? 'style="color: gray"' : ''} for="${token}">${token}</label>
169
- `;
170
- })
171
- .join('<br/>')}
172
-
173
-
174
- <h3>Graphs:</h3>
175
- ${graphs
176
- .map(([token, graph]) => `
177
- <section style="display: ${isLineVisible(token, graph) ? 'block' : 'none'}">
178
- <h3>${token}</h3>
179
- <div id="${token}_graph"></div>
180
- <hr style="margin: 15px 0;"/>
181
- </section>
182
- `)
183
- .join('')}
184
- <script>
185
- window.toggleLine = function(line) {
186
- const searchParams = new URLSearchParams(location.search)
187
- const lines = searchParams.get('lines')
188
- let selected = lines ? lines.split(',') : []
189
- if (selected.indexOf(line) !== -1) {
190
- selected.splice(selected.indexOf(line), 1)
191
- } else {
192
- selected = selected.concat(line)
193
- }
194
-
195
- searchParams.set('lines', selected.join(','))
196
- location.search = searchParams.toString()
197
- }
198
-
199
- window.applySearch = function(search) {
200
- const searchParams = new URLSearchParams(location.search)
201
- searchParams.set('search', search)
202
- location.search = searchParams.toString()
203
- }
204
-
205
- const searchParams = new URLSearchParams(location.search)
206
- const selectedLines = searchParams.get('lines')
207
- const graphs = ${JSON.stringify(graphs)}
208
- const renderedGraphs = graphs
209
- .filter(([token]) => {
210
- return !selectedLines || selectedLines.split(',').find(t => t === token)
211
- })
212
-
213
- window.backToTop = function() {
214
- window.scrollTo({
215
- top: 0,
216
- left: 0,
217
- behavior: "smooth"
218
- })
219
-
220
- renderedGraphs
221
- .forEach(([token]) => {
222
- d3.select('#' + token + '_graph')
223
- .graphviz()
224
- .resetZoom(500);
225
- })
226
- }
227
-
228
- renderedGraphs
229
- .forEach(([token, graph]) => {
230
- d3.select('#' + token + '_graph')
231
- .graphviz()
232
- .renderDot(graph);
233
- })
234
- </script>
235
- `);
236
- },
237
- });
238
- };
4
+ import { Module, provide } from '@tramvai/core';
5
+ import { depsGraph } from './papi/deps-graph.es.js';
239
6
 
240
7
  let DepsGraphModule = class DepsGraphModule {
241
8
  };
package/lib/server.js CHANGED
@@ -6,240 +6,7 @@ var tslib = require('tslib');
6
6
  var tokensServer = require('@tramvai/tokens-server');
7
7
  var dippy = require('@tinkoff/dippy');
8
8
  var core = require('@tramvai/core');
9
- var papi = require('@tramvai/papi');
10
-
11
- function traverseGraphUp(node, cb) {
12
- if (node) {
13
- cb(node);
14
- traverseGraphUp(node.parentNode, cb);
15
- }
16
- }
17
- const getGraph = ({ di, searchValue }) => {
18
- function getDepsFromRecord(container, parentNode, rank, record) {
19
- const deps = [];
20
- Object.values(record.resolvedDeps).forEach((k) => {
21
- const depGraph = buildDepsGraph(container, parentNode, rank,
22
- // @ts-ignore
23
- k.token ? k.token.toString() : k.toString());
24
- if (depGraph) {
25
- deps.push(depGraph);
26
- }
27
- });
28
- return deps;
29
- }
30
- function buildDepsGraph(container, parentNode, rank, token, recordOfMulti) {
31
- var _a, _b;
32
- const record = recordOfMulti || container.getRecord(Symbol.for(token));
33
- if (!record) {
34
- return null;
35
- }
36
- const moduleName = record.stack
37
- ? (_a = /\/(module(?:-|s\/)[\w-]*?)\//.exec(record.stack)) === null || _a === void 0 ? void 0 : _a[1].replace('modules/', '')
38
- : undefined;
39
- const searchMatch = searchValue &&
40
- ((token && token.indexOf(searchValue) !== -1) ||
41
- (moduleName && moduleName.indexOf(searchValue) !== -1));
42
- if (searchMatch) {
43
- traverseGraphUp(parentNode, (g) => {
44
- // eslint-disable-next-line no-param-reassign
45
- g.parentEdgeMatch = true;
46
- });
47
- }
48
- const node = {
49
- token,
50
- moduleName,
51
- record,
52
- match: searchMatch,
53
- childEdgeMatch: parentNode && (parentNode.match || parentNode.childEdgeMatch),
54
- parentNode,
55
- deps: [],
56
- rank,
57
- multi: !!record.multi,
58
- multiInstance: !!record.multi || !!recordOfMulti,
59
- };
60
- if ((_b = record.multi) === null || _b === void 0 ? void 0 : _b.length) {
61
- node.deps = record.multi.reduce((acc, r) => acc.concat(buildDepsGraph(container, node, rank + 1, token, r)), []);
62
- }
63
- else if (record === null || record === void 0 ? void 0 : record.resolvedDeps) {
64
- node.deps = getDepsFromRecord(container, node, rank + 1, record);
65
- }
66
- return node;
67
- }
68
- function formatGraphToDot(rootGraph) {
69
- const edges = [];
70
- const nodes = [];
71
- const groupsRank = {};
72
- const groupsByRank = {};
73
- function recurse(parentNodeId, node) {
74
- const nodeId = node.moduleName ? `${node.token}:${node.moduleName}` : node.token;
75
- const addNodeAndEdge = !searchValue || node.childEdgeMatch || node.parentEdgeMatch || node.match;
76
- if (!addNodeAndEdge) {
77
- return;
78
- }
79
- if (parentNodeId) {
80
- if (!edges.find((e) => e.from === parentNodeId && e.to === nodeId)) {
81
- edges.push({ from: parentNodeId, to: nodeId });
82
- }
83
- }
84
- if (!nodes.find((n) => n.id === nodeId)) {
85
- nodes.push({
86
- id: nodeId,
87
- label: node.moduleName ? `<b>${node.moduleName}</b> | ${node.token}` : node.token,
88
- multiInstance: node.multiInstance,
89
- match: node.match,
90
- });
91
- }
92
- if (!groupsRank[nodeId] || groupsRank[nodeId] < node.rank) {
93
- groupsRank[nodeId] = node.rank;
94
- }
95
- node.deps.forEach((d) => {
96
- recurse(node.multi ? parentNodeId : nodeId, d);
97
- });
98
- }
99
- recurse(null, rootGraph);
100
- Object.keys(groupsRank).forEach((nodeId) => {
101
- const rank = groupsRank[nodeId];
102
- groupsByRank[rank] = groupsByRank[rank] || [];
103
- groupsByRank[rank].push(nodeId);
104
- });
105
- const res = !nodes.length
106
- ? ''
107
- : `digraph g {
108
- rankdir = "LR";
109
- nodesep=0.1;
110
- ranksep=0.3;
111
- compound=true;
112
- concentrate=true;
113
- center=true;
114
- node [fontsize = "16", shape = "record", height=0.1, color=lightblue2];
115
- edge [];
116
- ${nodes
117
- .map((n) => {
118
- return `"${n.id}"[label=<${n.label}>]${n.multiInstance ? '[color="gold"]' : ''}${n.match ? '[color="red"]' : ''};`;
119
- })
120
- .join('\n')}
121
- ${edges
122
- .map((e) => {
123
- return `"${e.from}"->"${e.to}";`;
124
- })
125
- .join('\n')}
126
- ${Object.values(groupsByRank)
127
- .map((ids) => {
128
- return `{ rank = "same"; ${ids.map((id) => `"${id}"`).join(';')} }`;
129
- })
130
- .join('\n')}
131
- }`;
132
- return res;
133
- }
134
- return Object.values(core.commandLineListTokens)
135
- .map((k) => {
136
- const g = buildDepsGraph(di, null, 0, k.toString());
137
- return g ? [k.toString(), g] : null;
138
- })
139
- .filter(Boolean)
140
- .map(([k, g]) => [k, formatGraphToDot(g)]);
141
- };
142
-
143
- const depsGraph = ({ di }) => {
144
- return papi.createPapiMethod({
145
- method: 'get',
146
- path: '/deps-graph',
147
- async handler({ parsedUrl: { query }, responseManager }) {
148
- var _a;
149
- const graphs = getGraph({ di, searchValue: (_a = query.search) !== null && _a !== void 0 ? _a : '' });
150
- function isLineVisible(line, graph) {
151
- var _a;
152
- return (!query.lines && graph) || ((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(line) !== -1;
153
- }
154
- responseManager.setHeader('content-type', 'text/html');
155
- responseManager.setBody(`
156
- <script src="//d3js.org/d3.v6.min.js"></script>
157
- <script src="https://unpkg.com/@hpcc-js/wasm@1.4.1/dist/index.min.js"></script>
158
- <script src="https://unpkg.com/d3-graphviz@4.0.0/build/d3-graphviz.js"></script>
159
-
160
- <div style="cursor: pointer; text-align: center; background: rgba(170,170,170,.7); position: fixed; right: 10px; top: 10px; width: 30px; height: 30px; font-size: 20px;" onClick="backToTop()">
161
- 🠕
162
- </div>
163
-
164
- <h3>Search:</h3>
165
- <input placeholder="Search module and token names..." value="${query.search || ''}" style="padding: 10px 4px; width: 450px" onkeyup="event.keyCode === 13 && applySearch(this.value)" onblur="applySearch(this.value)"/><br/>
166
-
167
- <h3>Command Lines:</h3>
168
- ${graphs
169
- .map(([token, graph]) => {
170
- var _a;
171
- return `
172
- <input id="${token}" type="checkbox" ${((_a = query.lines) !== null && _a !== void 0 ? _a : '').search(token) !== -1 ? 'checked' : ''} onchange="toggleLine('${token}')"/><label ${!graph ? 'style="color: gray"' : ''} for="${token}">${token}</label>
173
- `;
174
- })
175
- .join('<br/>')}
176
-
177
-
178
- <h3>Graphs:</h3>
179
- ${graphs
180
- .map(([token, graph]) => `
181
- <section style="display: ${isLineVisible(token, graph) ? 'block' : 'none'}">
182
- <h3>${token}</h3>
183
- <div id="${token}_graph"></div>
184
- <hr style="margin: 15px 0;"/>
185
- </section>
186
- `)
187
- .join('')}
188
- <script>
189
- window.toggleLine = function(line) {
190
- const searchParams = new URLSearchParams(location.search)
191
- const lines = searchParams.get('lines')
192
- let selected = lines ? lines.split(',') : []
193
- if (selected.indexOf(line) !== -1) {
194
- selected.splice(selected.indexOf(line), 1)
195
- } else {
196
- selected = selected.concat(line)
197
- }
198
-
199
- searchParams.set('lines', selected.join(','))
200
- location.search = searchParams.toString()
201
- }
202
-
203
- window.applySearch = function(search) {
204
- const searchParams = new URLSearchParams(location.search)
205
- searchParams.set('search', search)
206
- location.search = searchParams.toString()
207
- }
208
-
209
- const searchParams = new URLSearchParams(location.search)
210
- const selectedLines = searchParams.get('lines')
211
- const graphs = ${JSON.stringify(graphs)}
212
- const renderedGraphs = graphs
213
- .filter(([token]) => {
214
- return !selectedLines || selectedLines.split(',').find(t => t === token)
215
- })
216
-
217
- window.backToTop = function() {
218
- window.scrollTo({
219
- top: 0,
220
- left: 0,
221
- behavior: "smooth"
222
- })
223
-
224
- renderedGraphs
225
- .forEach(([token]) => {
226
- d3.select('#' + token + '_graph')
227
- .graphviz()
228
- .resetZoom(500);
229
- })
230
- }
231
-
232
- renderedGraphs
233
- .forEach(([token, graph]) => {
234
- d3.select('#' + token + '_graph')
235
- .graphviz()
236
- .renderDot(graph);
237
- })
238
- </script>
239
- `);
240
- },
241
- });
242
- };
9
+ var depsGraph = require('./papi/deps-graph.js');
243
10
 
244
11
  exports.DepsGraphModule = class DepsGraphModule {
245
12
  };
@@ -250,7 +17,7 @@ exports.DepsGraphModule = tslib.__decorate([
250
17
  core.provide({
251
18
  provide: tokensServer.SERVER_MODULE_PAPI_PUBLIC_ROUTE,
252
19
  multi: true,
253
- useFactory: depsGraph,
20
+ useFactory: depsGraph.depsGraph,
254
21
  deps: {
255
22
  di: dippy.DI_TOKEN,
256
23
  },
@@ -0,0 +1,135 @@
1
+ import { commandLineListTokens } from '@tramvai/core';
2
+
3
+ function traverseGraphUp(node, cb) {
4
+ if (node) {
5
+ cb(node);
6
+ traverseGraphUp(node.parentNode, cb);
7
+ }
8
+ }
9
+ const getGraph = ({ di, searchValue }) => {
10
+ function getDepsFromRecord(container, parentNode, rank, record) {
11
+ const deps = [];
12
+ Object.values(record.resolvedDeps).forEach((k) => {
13
+ const depGraph = buildDepsGraph(container, parentNode, rank,
14
+ // @ts-ignore
15
+ k.token ? k.token.toString() : k.toString());
16
+ if (depGraph) {
17
+ deps.push(depGraph);
18
+ }
19
+ });
20
+ return deps;
21
+ }
22
+ function buildDepsGraph(container, parentNode, rank, token, recordOfMulti) {
23
+ var _a, _b;
24
+ const record = recordOfMulti || container.getRecord(Symbol.for(token));
25
+ if (!record) {
26
+ return null;
27
+ }
28
+ const moduleName = record.stack
29
+ ? (_a = /\/(module(?:-|s\/)[\w-]*?)\//.exec(record.stack)) === null || _a === void 0 ? void 0 : _a[1].replace('modules/', '')
30
+ : undefined;
31
+ const searchMatch = searchValue &&
32
+ ((token && token.indexOf(searchValue) !== -1) ||
33
+ (moduleName && moduleName.indexOf(searchValue) !== -1));
34
+ if (searchMatch) {
35
+ traverseGraphUp(parentNode, (g) => {
36
+ // eslint-disable-next-line no-param-reassign
37
+ g.parentEdgeMatch = true;
38
+ });
39
+ }
40
+ const node = {
41
+ token,
42
+ moduleName,
43
+ record,
44
+ match: searchMatch,
45
+ childEdgeMatch: parentNode && (parentNode.match || parentNode.childEdgeMatch),
46
+ parentNode,
47
+ deps: [],
48
+ rank,
49
+ multi: !!record.multi,
50
+ multiInstance: !!record.multi || !!recordOfMulti,
51
+ };
52
+ if ((_b = record.multi) === null || _b === void 0 ? void 0 : _b.length) {
53
+ node.deps = record.multi.reduce((acc, r) => acc.concat(buildDepsGraph(container, node, rank + 1, token, r)), []);
54
+ }
55
+ else if (record === null || record === void 0 ? void 0 : record.resolvedDeps) {
56
+ node.deps = getDepsFromRecord(container, node, rank + 1, record);
57
+ }
58
+ return node;
59
+ }
60
+ function formatGraphToDot(rootGraph) {
61
+ const edges = [];
62
+ const nodes = [];
63
+ const groupsRank = {};
64
+ const groupsByRank = {};
65
+ function recurse(parentNodeId, node) {
66
+ const nodeId = node.moduleName ? `${node.token}:${node.moduleName}` : node.token;
67
+ const addNodeAndEdge = !searchValue || node.childEdgeMatch || node.parentEdgeMatch || node.match;
68
+ if (!addNodeAndEdge) {
69
+ return;
70
+ }
71
+ if (parentNodeId) {
72
+ if (!edges.find((e) => e.from === parentNodeId && e.to === nodeId)) {
73
+ edges.push({ from: parentNodeId, to: nodeId });
74
+ }
75
+ }
76
+ if (!nodes.find((n) => n.id === nodeId)) {
77
+ nodes.push({
78
+ id: nodeId,
79
+ label: node.moduleName ? `<b>${node.moduleName}</b> | ${node.token}` : node.token,
80
+ multiInstance: node.multiInstance,
81
+ match: node.match,
82
+ });
83
+ }
84
+ if (!groupsRank[nodeId] || groupsRank[nodeId] < node.rank) {
85
+ groupsRank[nodeId] = node.rank;
86
+ }
87
+ node.deps.forEach((d) => {
88
+ recurse(node.multi ? parentNodeId : nodeId, d);
89
+ });
90
+ }
91
+ recurse(null, rootGraph);
92
+ Object.keys(groupsRank).forEach((nodeId) => {
93
+ const rank = groupsRank[nodeId];
94
+ groupsByRank[rank] = groupsByRank[rank] || [];
95
+ groupsByRank[rank].push(nodeId);
96
+ });
97
+ const res = !nodes.length
98
+ ? ''
99
+ : `digraph g {
100
+ rankdir = "LR";
101
+ nodesep=0.1;
102
+ ranksep=0.3;
103
+ compound=true;
104
+ concentrate=true;
105
+ center=true;
106
+ node [fontsize = "16", shape = "record", height=0.1, color=lightblue2];
107
+ edge [];
108
+ ${nodes
109
+ .map((n) => {
110
+ return `"${n.id}"[label=<${n.label}>]${n.multiInstance ? '[color="gold"]' : ''}${n.match ? '[color="red"]' : ''};`;
111
+ })
112
+ .join('\n')}
113
+ ${edges
114
+ .map((e) => {
115
+ return `"${e.from}"->"${e.to}";`;
116
+ })
117
+ .join('\n')}
118
+ ${Object.values(groupsByRank)
119
+ .map((ids) => {
120
+ return `{ rank = "same"; ${ids.map((id) => `"${id}"`).join(';')} }`;
121
+ })
122
+ .join('\n')}
123
+ }`;
124
+ return res;
125
+ }
126
+ return Object.values(commandLineListTokens)
127
+ .map((k) => {
128
+ const g = buildDepsGraph(di, null, 0, k.toString());
129
+ return g ? [k.toString(), g] : null;
130
+ })
131
+ .filter(Boolean)
132
+ .map(([k, g]) => [k, formatGraphToDot(g)]);
133
+ };
134
+
135
+ export { getGraph };
@@ -0,0 +1,139 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var core = require('@tramvai/core');
6
+
7
+ function traverseGraphUp(node, cb) {
8
+ if (node) {
9
+ cb(node);
10
+ traverseGraphUp(node.parentNode, cb);
11
+ }
12
+ }
13
+ const getGraph = ({ di, searchValue }) => {
14
+ function getDepsFromRecord(container, parentNode, rank, record) {
15
+ const deps = [];
16
+ Object.values(record.resolvedDeps).forEach((k) => {
17
+ const depGraph = buildDepsGraph(container, parentNode, rank,
18
+ // @ts-ignore
19
+ k.token ? k.token.toString() : k.toString());
20
+ if (depGraph) {
21
+ deps.push(depGraph);
22
+ }
23
+ });
24
+ return deps;
25
+ }
26
+ function buildDepsGraph(container, parentNode, rank, token, recordOfMulti) {
27
+ var _a, _b;
28
+ const record = recordOfMulti || container.getRecord(Symbol.for(token));
29
+ if (!record) {
30
+ return null;
31
+ }
32
+ const moduleName = record.stack
33
+ ? (_a = /\/(module(?:-|s\/)[\w-]*?)\//.exec(record.stack)) === null || _a === void 0 ? void 0 : _a[1].replace('modules/', '')
34
+ : undefined;
35
+ const searchMatch = searchValue &&
36
+ ((token && token.indexOf(searchValue) !== -1) ||
37
+ (moduleName && moduleName.indexOf(searchValue) !== -1));
38
+ if (searchMatch) {
39
+ traverseGraphUp(parentNode, (g) => {
40
+ // eslint-disable-next-line no-param-reassign
41
+ g.parentEdgeMatch = true;
42
+ });
43
+ }
44
+ const node = {
45
+ token,
46
+ moduleName,
47
+ record,
48
+ match: searchMatch,
49
+ childEdgeMatch: parentNode && (parentNode.match || parentNode.childEdgeMatch),
50
+ parentNode,
51
+ deps: [],
52
+ rank,
53
+ multi: !!record.multi,
54
+ multiInstance: !!record.multi || !!recordOfMulti,
55
+ };
56
+ if ((_b = record.multi) === null || _b === void 0 ? void 0 : _b.length) {
57
+ node.deps = record.multi.reduce((acc, r) => acc.concat(buildDepsGraph(container, node, rank + 1, token, r)), []);
58
+ }
59
+ else if (record === null || record === void 0 ? void 0 : record.resolvedDeps) {
60
+ node.deps = getDepsFromRecord(container, node, rank + 1, record);
61
+ }
62
+ return node;
63
+ }
64
+ function formatGraphToDot(rootGraph) {
65
+ const edges = [];
66
+ const nodes = [];
67
+ const groupsRank = {};
68
+ const groupsByRank = {};
69
+ function recurse(parentNodeId, node) {
70
+ const nodeId = node.moduleName ? `${node.token}:${node.moduleName}` : node.token;
71
+ const addNodeAndEdge = !searchValue || node.childEdgeMatch || node.parentEdgeMatch || node.match;
72
+ if (!addNodeAndEdge) {
73
+ return;
74
+ }
75
+ if (parentNodeId) {
76
+ if (!edges.find((e) => e.from === parentNodeId && e.to === nodeId)) {
77
+ edges.push({ from: parentNodeId, to: nodeId });
78
+ }
79
+ }
80
+ if (!nodes.find((n) => n.id === nodeId)) {
81
+ nodes.push({
82
+ id: nodeId,
83
+ label: node.moduleName ? `<b>${node.moduleName}</b> | ${node.token}` : node.token,
84
+ multiInstance: node.multiInstance,
85
+ match: node.match,
86
+ });
87
+ }
88
+ if (!groupsRank[nodeId] || groupsRank[nodeId] < node.rank) {
89
+ groupsRank[nodeId] = node.rank;
90
+ }
91
+ node.deps.forEach((d) => {
92
+ recurse(node.multi ? parentNodeId : nodeId, d);
93
+ });
94
+ }
95
+ recurse(null, rootGraph);
96
+ Object.keys(groupsRank).forEach((nodeId) => {
97
+ const rank = groupsRank[nodeId];
98
+ groupsByRank[rank] = groupsByRank[rank] || [];
99
+ groupsByRank[rank].push(nodeId);
100
+ });
101
+ const res = !nodes.length
102
+ ? ''
103
+ : `digraph g {
104
+ rankdir = "LR";
105
+ nodesep=0.1;
106
+ ranksep=0.3;
107
+ compound=true;
108
+ concentrate=true;
109
+ center=true;
110
+ node [fontsize = "16", shape = "record", height=0.1, color=lightblue2];
111
+ edge [];
112
+ ${nodes
113
+ .map((n) => {
114
+ return `"${n.id}"[label=<${n.label}>]${n.multiInstance ? '[color="gold"]' : ''}${n.match ? '[color="red"]' : ''};`;
115
+ })
116
+ .join('\n')}
117
+ ${edges
118
+ .map((e) => {
119
+ return `"${e.from}"->"${e.to}";`;
120
+ })
121
+ .join('\n')}
122
+ ${Object.values(groupsByRank)
123
+ .map((ids) => {
124
+ return `{ rank = "same"; ${ids.map((id) => `"${id}"`).join(';')} }`;
125
+ })
126
+ .join('\n')}
127
+ }`;
128
+ return res;
129
+ }
130
+ return Object.values(core.commandLineListTokens)
131
+ .map((k) => {
132
+ const g = buildDepsGraph(di, null, 0, k.toString());
133
+ return g ? [k.toString(), g] : null;
134
+ })
135
+ .filter(Boolean)
136
+ .map(([k, g]) => [k, formatGraphToDot(g)]);
137
+ };
138
+
139
+ exports.getGraph = getGraph;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/module-deps-graph",
3
- "version": "2.70.1",
3
+ "version": "2.72.0",
4
4
  "description": "",
5
5
  "browser": "lib/browser.js",
6
6
  "main": "lib/server.js",
@@ -14,16 +14,15 @@
14
14
  "url": "git@github.com:Tinkoff/tramvai.git"
15
15
  },
16
16
  "scripts": {
17
- "build": "tramvai-build --for-publish",
18
- "watch": "tsc -w",
19
- "build-for-publish": "true"
17
+ "build": "tramvai-build --forPublish --preserveModules",
18
+ "watch": "tsc -w"
20
19
  },
21
20
  "peerDependencies": {
22
- "@tramvai/core": "2.70.1",
23
- "@tramvai/tokens-common": "2.70.1",
24
- "@tramvai/tokens-server": "2.70.1",
25
- "@tramvai/papi": "2.70.1",
26
- "@tinkoff/dippy": "0.8.12",
21
+ "@tramvai/core": "2.72.0",
22
+ "@tramvai/tokens-common": "2.72.0",
23
+ "@tramvai/tokens-server": "2.72.0",
24
+ "@tramvai/papi": "2.72.0",
25
+ "@tinkoff/dippy": "0.8.13",
27
26
  "tslib": "^2.4.0"
28
27
  },
29
28
  "module": "lib/server.es.js",