├── go.sum
├── go.mod
├── show.gif
├── src
├── index.js
├── temp-index.html
├── css
│ └── styles.css
├── js
│ ├── graph.js
│ └── tree.js
└── static
│ ├── tree.json
│ ├── an-tree.json
│ └── graph.json
├── .gitignore
├── gosrc
├── util_test.go
├── util.go
├── graphutil.go
├── treeutil.go
├── graphutil_test.go
└── treeutil_test.go
├── README-CN.md
├── README.md
├── LICENSE
├── package.json
├── plugin
└── pack-all-in-go-plugin.js
├── webpack.config.js
└── gmchart
└── main.go
/go.sum:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/PaulXu-cn/go-mod-graph-chart
2 |
3 | go 1.14
4 |
--------------------------------------------------------------------------------
/show.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PaulXu-cn/go-mod-graph-chart/HEAD/show.gif
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import graph from './js/graph.js';
2 | import tree from './js/tree.js';
3 |
4 | var hostPath = window.location.href;
5 | var paths = hostPath.split("#");
6 | // 这判断下,什么模式
7 | if (0 < paths.length && "graph" == (paths[paths.length - 1]).toLowerCase()) {
8 | graph();
9 | } else {
10 | tree();
11 | }
12 |
--------------------------------------------------------------------------------
/src/temp-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= htmlWebpackPlugin.options.title %>
7 |
8 |
9 |
10 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.o
7 | *.dylib
8 |
9 | # Test binary, built with `go test -c`
10 | *.test
11 |
12 | # Output of the go coverage tool, specifically when used with LiteIDE
13 | *.out
14 | .idea/
15 |
16 | # Dependency directories (remove the comment below to include it)
17 | vendor/
18 | node_modules/
19 |
20 | dist/*
21 | gmchart/*
22 |
--------------------------------------------------------------------------------
/gosrc/util_test.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import "testing"
4 |
5 | func TestCheckTcpConnect(t *testing.T) {
6 | var urlTests = []struct {
7 | expected bool // expected result
8 | in string // input
9 | }{
10 | {true, "1024"},
11 | {true, "2048"},
12 | {false, "80"},
13 | {false, "8080"},
14 | }
15 |
16 | for _, tt := range urlTests {
17 | actual := CheckTcpConnect("0.0.0.0", tt.in)
18 | if (nil == actual) != tt.expected {
19 | t.Errorf("CheckTcpConnect(%s) = %t; expected %t", tt.in, actual, tt.expected)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | 中文
2 |
3 | [](https://github.com/nikolaydubina/go-recipes)
4 |
5 | # go-mod-graph-chart
6 | 一个能将 `go mod graph` 输出内容可视化的无依赖小工具
7 |
8 | ## 安装
9 |
10 | ```shell
11 | $ go get -u github.com/PaulXu-cn/go-mod-graph-chart/gmchart
12 | ```
13 |
14 | Go v1.16 或者更高版本使用如下命令安装
15 |
16 | ```shell
17 | $ go install github.com/PaulXu-cn/go-mod-graph-chart/gmchart@latest
18 | ```
19 |
20 | ## 使用
21 |
22 | ```shell
23 | $ cd goProject
24 | $ go mod graph | gmchart
25 | ```
26 |
27 | 执行 `go mod graph` 命令,输出的文本作为该程序的输入,该程序会起一个http服务,并打开 `url` 展示图表
28 |
29 | 
30 | ## 改动重建
31 |
32 | 如果你改动了 `JS` 代码,记得重新构建前端项目,然后重新构建 `go` 项目
33 | ```shell
34 | $ npm run build
35 | $ go install ./gmchart
36 | ```
37 |
38 | ## 开源协议
39 |
40 | MIT
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | English | [中文](./README-CN.md)
2 |
3 | [](https://github.com/nikolaydubina/go-recipes)
4 |
5 | # go-mod-graph-chart
6 | A tool build chart by `go mod graph` output with zero dependencies
7 |
8 | ## Install
9 |
10 | ```shell
11 | $ go get -u github.com/PaulXu-cn/go-mod-graph-chart/gmchart
12 | ```
13 |
14 | Go v1.16 or higher
15 |
16 | ```shell
17 | $ go install github.com/PaulXu-cn/go-mod-graph-chart/gmchart@latest
18 | ```
19 |
20 | ## Usage
21 |
22 | ```shell
23 | $ cd goProject
24 | $ go mod graph | gmchart
25 | ```
26 |
27 | The program will start a http server and open the url in default browser.
28 |
29 | 
30 |
31 | ## Change & Rebuild
32 |
33 | If you has changed js code, the front-end project needs to be rebuilt,and then `go install`
34 | ```shell
35 | $ npm run build
36 | $ go install ./gmchart
37 | ```
38 |
39 | ## License
40 |
41 | MIT
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 PaulXu-cn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-webpack-project",
3 | "version": "1.0.0",
4 | "description": "My webpack project",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "cross-env NODE_ENV=production webpack",
9 | "dev": "cross-env NODE_ENV=development webpack serve --mode development"
10 | },
11 | "keywords": [
12 | "go",
13 | "mod",
14 | "graph",
15 | "d3"
16 | ],
17 | "author": "Paul Xu",
18 | "license": "MIT",
19 | "dependencies": {
20 | "d3": "^5.16.0",
21 | "npm": "^8.6.0"
22 | },
23 | "devDependencies": {
24 | "@webpack-cli/init": "^1.0.3",
25 | "@webpack-cli/serve": "^1.2.0",
26 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
27 | "cross-env": "^7.0.3",
28 | "css-loader": "^5.0.1",
29 | "html-loader": "^1.3.2",
30 | "html-webpack-plugin": "^4.5.0",
31 | "mini-css-extract-plugin": "^1.3.3",
32 | "style-loader": "^2.0.0",
33 | "terser-webpack-plugin": "^5.0.3",
34 | "uglify-js": "^3.12.2",
35 | "webpack": "^5.11.1",
36 | "webpack-cli": "^4.2.0",
37 | "webpack-dev-server": "^3.11.0",
38 | "webpack-parallel-uglify-plugin": "^2.0.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/css/styles.css:
--------------------------------------------------------------------------------
1 |
2 | .tree-path {
3 | fill: none;
4 | stroke: black;
5 | stroke-width: 1.5px;
6 | opacity: 0.6;
7 | }
8 |
9 | .tree-circle {
10 | stroke-width: 1;
11 | }
12 |
13 | .tree-circle.on {
14 | stroke-width: 3;
15 | stroke: black;
16 | }
17 |
18 | .tree-text {
19 | opacity: 0.7;
20 | stroke-width: 0.2px;
21 | stroke: white;
22 | }
23 |
24 | .tree-text.on {
25 | opacity: 1;
26 | stroke-width: 0.8px;
27 | stroke: black;
28 | }
29 |
30 | .mask {
31 | background-color: rgba(100, 100, 100, 0.6);
32 | /* opacity:0.6; */
33 | position: fixed;
34 | top: 0;
35 | left: 0;
36 | right: 0;
37 | bottom: 0;
38 | z-index: 1000;
39 | transition: all 0.3s ease-in-out;
40 | visibility: visible;
41 | }
42 |
43 | .sub-board {
44 | background-color: white;
45 | position: fixed;
46 | opacity: 1;
47 | top: 0px;
48 | bottom: 0px;
49 | left: 0px;
50 | right: 0px;
51 | width: 640px;
52 | height: 480px;
53 | margin-left:auto;
54 | margin-right:auto;
55 | margin-top: auto;
56 | margin-bottom: auto;
57 | z-index: 1001;
58 | visibility: visible;
59 | overflow-y: auto;
60 | overflow-x: hidden;
61 | }
62 |
63 | div.hide {
64 | display: none;
65 | }
--------------------------------------------------------------------------------
/plugin/pack-all-in-go-plugin.js:
--------------------------------------------------------------------------------
1 | class PackAllInGoPlugin {
2 | apply(compiler) {
3 | // emit is asynchronous hook, tapping into it using tapAsync, you can use tapPromise/tap(synchronous) as well
4 | compiler.hooks.emit.tapAsync('PackAllInGoPlugin', (compilation, callback) => {
5 | // Create a header string for the generated file:
6 | var filelist = '';
7 | var indexHtml, mainJs;
8 | var goCode = `package godist
9 |
10 | func GetFile(file string) string {
11 | switch {
12 | case \`index.html\` == file:
13 | return IndexHtml
14 | case \`main.js\` == file:
15 | return MainJson
16 | case \`favicon.ico\` == file:
17 | return Favicon
18 | default:
19 | return ""
20 | }
21 | }
22 |
23 | var IndexHtml = \`--index.html--\`
24 |
25 | var MainJson = \`--main.js--\`
26 |
27 | var Favicon = \`favicon.ico\``
28 |
29 | // Loop through all compiled assets,
30 | // adding a new line item for each filename.
31 | for (var filename in compilation.assets) {
32 | if ("main.js" == filename) {
33 | let jsCode = compilation.assets[filename].source()
34 | let jsCodeString = jsCode.slice();
35 | jsCodeString = jsCodeString.replace(/\`/g, "\` + \"\`\" + \`")
36 | goCode = goCode.replace('--main.js--', jsCodeString)
37 | } else if ("index.html") {
38 | let htmlCode = compilation.assets[filename].source()
39 | goCode = goCode.replace('--index.html--', htmlCode)
40 | }
41 | }
42 |
43 | // 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
44 | compilation.assets['../godist/static.go'] = {
45 | source: function() {
46 | return goCode;
47 | },
48 | size: function() {
49 | return goCode.length;
50 | }
51 | };
52 |
53 | callback();
54 | });
55 | }
56 | }
57 |
58 | module.exports = PackAllInGoPlugin;
59 |
--------------------------------------------------------------------------------
/gosrc/util.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "net"
7 | "net/url"
8 | "os"
9 | "os/exec"
10 | "runtime"
11 | "strconv"
12 | "strings"
13 | "time"
14 | )
15 |
16 | func CheckTcpConnect(host string, port string) (err error) {
17 | timeout := time.Second
18 | conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout)
19 | if err != nil {
20 | return
21 | }
22 | if conn != nil {
23 | defer conn.Close()
24 | return
25 | }
26 | return
27 | }
28 |
29 | func GetUnUsePort() uint32 {
30 | for i := 0; i < 10; i++ {
31 | if i < 1024 {
32 | continue
33 | }
34 | var newPort = rand.Intn(65535)
35 | if err := CheckTcpConnect("127.0.0.1", strconv.Itoa(newPort)); nil != err {
36 | return uint32(newPort)
37 | }
38 | }
39 | return 0
40 | }
41 |
42 | // browsers returns a list of commands to attempt for web visualization.
43 | func browsers() []string {
44 | var cmds []string
45 | if userBrowser := os.Getenv("BROWSER"); userBrowser != "" {
46 | cmds = append(cmds, userBrowser)
47 | }
48 | switch runtime.GOOS {
49 | case "darwin":
50 | cmds = append(cmds, "/usr/bin/open")
51 | case "windows":
52 | cmds = append(cmds, "cmd /c start")
53 | default:
54 | // Commands opening browsers are prioritized over xdg-open, so browser()
55 | // command can be used on linux to open the .svg file generated by the -web
56 | // command (the .svg file includes embedded javascript so is best viewed in
57 | // a browser).
58 | cmds = append(cmds, []string{"chrome", "google-chrome", "chromium", "firefox", "sensible-browser"}...)
59 | if os.Getenv("DISPLAY") != "" {
60 | // xdg-open is only for use in a desktop environment.
61 | cmds = append(cmds, "xdg-open")
62 | }
63 | }
64 | return cmds
65 | }
66 |
67 | // open browser with url
68 | func OpenBrowser(targetUrl string) (err error) {
69 | // Construct URL.
70 | u, _ := url.Parse(targetUrl)
71 |
72 | for _, b := range browsers() {
73 | args := strings.Split(b, " ")
74 | if len(args) == 0 {
75 | continue
76 | }
77 | viewer := exec.Command(args[0], append(args[1:], u.String())...)
78 | viewer.Stderr = os.Stderr
79 | if err = viewer.Start(); err == nil {
80 | return
81 | }
82 | }
83 | // No visualizer succeeded, so just print URL.
84 | fmt.Println(u.String())
85 | return
86 | }
87 |
--------------------------------------------------------------------------------
/gosrc/graphutil.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | "os/exec"
8 | "strings"
9 | "time"
10 | )
11 |
12 | type Node struct {
13 | Id uint32 `json:"id"`
14 | Name string `json:"name"`
15 | Value uint32 `json:"value"`
16 | }
17 |
18 | type Link struct {
19 | Source uint32 `json:"source"`
20 | Target uint32 `json:"target"`
21 | Weight uint32 `json:"weight"`
22 | Width uint32 `json:"width"`
23 | }
24 |
25 | func GraphToNodeLinks(graph string) (nodes map[string]Node, links []Link) {
26 | nodes = map[string]Node{}
27 | links = []Link{}
28 | var key uint32 = 0
29 | for _, line := range strings.Split(graph, "\n") {
30 | if 1 > len(line) {
31 | continue
32 | }
33 | splitStr := strings.Split(line, " ")
34 | if 2 > len(splitStr) {
35 | panic(fmt.Sprintf("go mod graph output format error——%s", line))
36 | }
37 | var nKey uint32 = 0
38 | var nKey1 uint32 = 0
39 | node, ok := nodes[splitStr[0]]
40 | if ok {
41 | // 权重自增
42 | node.Value++
43 | nodes[splitStr[0]] = node
44 | nKey = node.Id
45 | } else {
46 | // 新增node
47 | var newNode = Node{
48 | Id: key,
49 | Name: splitStr[0],
50 | Value: 1,
51 | }
52 | nodes[splitStr[0]] = newNode
53 | nKey = key
54 | key++
55 | }
56 |
57 | node1, ok1 := nodes[splitStr[1]]
58 | if ok1 {
59 | node1.Value++
60 | nodes[splitStr[0]] = node
61 | nKey1 = node1.Id
62 | } else {
63 | // 新增node
64 | var newNode = Node{
65 | Id: key,
66 | Name: splitStr[1],
67 | Value: 1,
68 | }
69 | nodes[splitStr[1]] = newNode
70 | nKey1 = key
71 | key++
72 | }
73 |
74 | newLink := Link{
75 | Source: nKey,
76 | Target: nKey1,
77 | Weight: 1,
78 | Width: 1,
79 | }
80 | links = append(links, newLink)
81 | }
82 | return
83 | }
84 |
85 | func GetGoModGraph() string {
86 | var goModGraph string = ""
87 |
88 | go func() {
89 | var scanner = bufio.NewScanner(os.Stdin)
90 | for scanner.Scan() {
91 | goModGraph += scanner.Text() + "\n"
92 | }
93 | }()
94 |
95 | time.Sleep(2000 * time.Millisecond)
96 | if 1 > len(goModGraph) {
97 | fmt.Printf("no output pass in by pipe!\n")
98 | cmd := exec.Command("go mod graph")
99 | if out, err := cmd.CombinedOutput(); nil != err {
100 | panic(fmt.Sprintf("go mod graph cmd run failed: %+v", err))
101 | } else {
102 | return string(out)
103 | }
104 | }
105 | return goModGraph
106 | }
107 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 |
5 |
6 |
7 | /*
8 | * SplitChunksPlugin is enabled by default and replaced
9 | * deprecated CommonsChunkPlugin. It automatically identifies modules which
10 | * should be splitted of chunk by heuristics using module duplication count and
11 | * module category (i. e. node_modules). And splits the chunks…
12 | *
13 | * It is safe to remove "splitChunks" from the generated configuration
14 | * and was added as an educational example.
15 | *
16 | * https://webpack.js.org/plugins/split-chunks-plugin/
17 | *
18 | */
19 |
20 | /*
21 | * We've enabled TerserPlugin for you! This minifies your app
22 | * in order to load faster and run less javascript.
23 | *
24 | * https://github.com/webpack-contrib/terser-webpack-plugin
25 | *
26 | */
27 |
28 | const TerserPlugin = require('terser-webpack-plugin');
29 |
30 |
31 | /*
32 | * webpack Html Plugin
33 | */
34 | const HtmlWebpackPlugin = require('html-webpack-plugin');
35 |
36 |
37 | /*
38 | * 引入 ParallelUglifyPlugin 插件
39 | */
40 | const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
41 |
42 |
43 | /*
44 | * 引入自定义插件
45 | */
46 | const PackAllInGoPlugin = require('./plugin/pack-all-in-go-plugin');
47 |
48 |
49 | const isDev = process.env.NODE_ENV === 'development'
50 |
51 |
52 | config = {
53 | mode: 'development',
54 | devtool: false, // 编译成果 保留换行
55 | plugins: [
56 | new HtmlWebpackPlugin({
57 | title: 'go mod graph charting',
58 | filename: 'index.html',
59 | template: './src/temp-index.html'
60 | }),
61 | new ParallelUglifyPlugin({
62 | // 传递给 UglifyJS的参数如下:
63 | uglifyJS: {
64 | output: {
65 | /*
66 | 是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
67 | 可以设置为false
68 | */
69 | beautify: true,
70 | /*
71 | 是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
72 | */
73 | comments: false
74 | },
75 | compress: {
76 | /*
77 | 是否在UglifyJS删除没有用到的代码时输出警告信息,默认为输出,可以设置为false关闭这些作用
78 | 不大的警告
79 | */
80 | warnings: false,
81 |
82 | /*
83 | 是否删除代码中所有的console语句,默认为不删除,开启后,会删除所有的console语句
84 | */
85 | drop_console: true,
86 |
87 | /*
88 | 是否内嵌虽然已经定义了,但是只用到一次的变量,比如将 var x = 1; y = x, 转换成 y = 5, 默认为不
89 | 转换,为了达到更好的压缩效果,可以设置为false
90 | */
91 | collapse_vars: true,
92 |
93 | /*
94 | 是否提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx' 转换成
95 | var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,可以设置为false
96 | */
97 | reduce_vars: true
98 | },
99 | beautify: {
100 | semicolons: false
101 | }
102 | },
103 | test: /.js$/g,
104 | include: [],
105 | exclude: [],
106 | cacheDir: '',
107 | workerCount: '',
108 | sourceMap: false
109 | }),
110 | new webpack.ProgressPlugin(),
111 | new PackAllInGoPlugin({options: true})
112 | ],
113 |
114 | module: {
115 | rules: [{
116 | test: /.css$/,
117 |
118 | use: [{
119 | loader: "style-loader"
120 | }, {
121 | loader: "css-loader",
122 |
123 | options: {
124 | sourceMap: true
125 | }
126 | }]
127 | }]
128 | },
129 |
130 | optimization: {
131 | minimizer: [new TerserPlugin({
132 | terserOptions: {
133 | comments: false
134 | },
135 | extractComments: false
136 | })],
137 |
138 | splitChunks: {
139 | cacheGroups: {
140 | vendors: {
141 | priority: -10,
142 | test: /[\\/]node_modules[\\/]/
143 | }
144 | },
145 |
146 | chunks: 'async',
147 | minChunks: 1,
148 | minSize: 30000,
149 | name: false
150 | }
151 | }
152 | }
153 |
154 |
155 | if (isDev) {
156 | config.devServer = {
157 | host: '0.0.0.0',
158 | contentBase: path.join(__dirname, 'src', 'static'),
159 | open: true,
160 | port: 8080,
161 | overlay: {
162 | errors: true
163 | }
164 | }
165 | } else {
166 | }
167 |
168 |
169 | module.exports = config
170 |
--------------------------------------------------------------------------------
/src/js/graph.js:
--------------------------------------------------------------------------------
1 | import * as d3 from 'd3';
2 | import CSS from '../css/styles.css';
3 |
4 | var width = 1000, height = 1000;
5 | var num = 1;
6 |
7 | export default function graph() {
8 | width = num * 30;
9 | height = num * 30;
10 |
11 | let colorScale, color, circles, lines, texts, arrowMarker, tickCount, simulation;
12 | let svg = d3.select('#app').append('svg').attr('width', width).attr('height', height);
13 |
14 | let nodes = [{ name: 'haha', value: 12 }, { name: '323', value: 32 }, { name: '我们', value: 24 }, { name: 'yes~', value: 43 }, { name: 'sukabulei', value: 18 }],
15 | links = [
16 | { 'source': 0, 'target': 3, weight: 1 },
17 | { 'source': 3, 'target': 4, weight: 1 },
18 | { 'source': 1, 'target': 2, weight: 0.5 },
19 | ];
20 |
21 | function dragstarted(d) {
22 | d3.select(this).raise().attr("stroke", "black");
23 | simulation.stop();
24 | }
25 | function dragged(d) {
26 | d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
27 | ticked();
28 | }
29 | function dragended(d) {
30 | d3.select(this).attr("stroke", null);
31 | simulation.restart();
32 | }
33 | const drag = d3.drag()
34 | .on("start", dragstarted)
35 | .on("drag", dragged)
36 | .on("end", dragended);
37 |
38 | const render_init = function () {
39 | var defs = svg.append("defs");
40 |
41 | arrowMarker = defs.append("marker")
42 | .attr("id", "arrow")
43 | .attr("markerUnits", "strokeWidth")
44 | .attr("markerWidth", "12")
45 | .attr("markerHeight", "12")
46 | .attr("viewBox", "0 0 12 12")
47 | .attr("refX", "6")
48 | .attr("refY", "6")
49 | .attr("orient", "auto");
50 |
51 | var arrow_path = "M2,2 L10,6 L2,10 L6,6 L2,2";
52 |
53 | arrowMarker.append("path")
54 | .attr("d", arrow_path)
55 | .attr("fill", "black");
56 |
57 | lines = svg.selectAll('line').data(links)
58 | .enter().append('line')
59 | .attr('stroke', 'black')
60 | .attr('opacity', 0.8)
61 | // .attr('stroke-width', d => d.width * 5)
62 | .attr('stroke-width', 1)
63 | .attr("marker-end", "url(#arrow)");
64 |
65 | circles = svg.selectAll('circle').data(nodes)
66 | .enter().append('circle')
67 | .attr('r', 8)
68 | .attr('fill', function (d, i) { return color(i); })
69 | .call(drag);
70 |
71 | texts = d3.select('svg').selectAll('.circle-text').data(nodes)
72 | .enter().append('text').classed('circle-text', true).text(d => d.name)
73 | .attr('fill', 'gray')
74 | .attr('transform', `translate(10, 5)`);
75 | }
76 |
77 | tickCount = 1;
78 |
79 | function ticked() {
80 | lines.attr('x1', function (d) { return d.source.x; }).
81 | attr('y1', function (d) { return d.source.y; }).
82 | attr('x2', function (d) { if (0 < d.source.x - d.target.x) { return d.target.x + 8; } else { return d.target.x - 8; } }).
83 | attr('y2', function (d) { if (0 < d.source.y - d.target.y) { return d.target.y + 8; } else { return d.target.y - 8; } }).
84 | attr("marker-end", "url(#arrow)").
85 | attr('d', function (d) { return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y }).
86 | classed('edgeline', true);
87 |
88 | circles.attr('cx', function (d) { return d.x; })
89 | .attr('cy', function (d) { return d.y; })
90 |
91 | texts.attr('x', function (d) { return d.x; }).attr('y', d => d.y);
92 |
93 | // if (tickCount++ > 1000) {
94 | // return false;
95 | // }
96 | }
97 |
98 | function strengthFunc(link) {
99 | return link.weight * 0.01;
100 | }
101 |
102 | function distanceFunc(link) {
103 | return 200 * (1 / link.weight);
104 | }
105 |
106 | d3.json('/graph.json').then(data => {
107 | links = data.data.links;
108 | nodes = data.data.nodes;
109 | num = data.data.num;
110 |
111 | width = num * 30;
112 | height = num * 30;
113 | d3.select('#app').select('svg').attr('width', width).attr('height', height);
114 |
115 | colorScale = d3.scaleDiverging(d3.interpolatePuOr).domain([0, (nodes.length - 1)]);
116 | color = d3.scaleDiverging(d3.interpolateRainbow).domain([0, nodes.length - 1])
117 | tickCount = 1;
118 |
119 | render_init();
120 |
121 | simulation = d3.forceSimulation(nodes)
122 | .force('charge', d3.forceManyBody)
123 | .force('center', d3.forceCenter(width / 2, height / 2))
124 | .force('link', d3.forceLink(links).strength(strengthFunc).distance(distanceFunc))
125 | .alphaTarget(0.3)
126 | .on('tick', ticked);
127 |
128 | setTimeout(function () {
129 | window.scrollTo(width / 2, height / 2)
130 | }, 1000);
131 | })
132 | }
--------------------------------------------------------------------------------
/gmchart/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "flag"
6 | "fmt"
7 | "net"
8 | "net/http"
9 | "os"
10 | "strconv"
11 | "strings"
12 | "time"
13 |
14 | dist "github.com/PaulXu-cn/go-mod-graph-chart/godist"
15 | src "github.com/PaulXu-cn/go-mod-graph-chart/gosrc"
16 | )
17 |
18 | var (
19 | debug int = 0
20 | keep int = 0
21 | port int = 0
22 | mode string = "tree"
23 | )
24 |
25 | func init() {
26 | flag.IntVar(&debug, "debug", 0, "whether debug model")
27 | flag.IntVar(&keep, "keep", 0, "set no zero http server never exit")
28 | flag.IntVar(&port, "port", 0, "set http server port or random port number")
29 | flag.StringVar(&mode, "mode", "tree", "work mode, [tree/graph]")
30 | }
31 |
32 | func IndexHandler(w http.ResponseWriter, r *http.Request) {
33 | var header = w.Header()
34 | header.Add("Content-type", "text/html; charset=utf-8")
35 | var indexStr = dist.GetFile("index.html")
36 | w.Write([]byte(indexStr))
37 | w.WriteHeader(http.StatusOK)
38 | }
39 |
40 | func MainJsHandler(w http.ResponseWriter, r *http.Request) {
41 | var header = w.Header()
42 | header.Add("Content-type", "text/javascript; charset=utf-8")
43 | var indexStr = dist.GetFile("main.js")
44 | w.Write([]byte(indexStr))
45 | w.WriteHeader(http.StatusOK)
46 | }
47 |
48 | func PingHandler(w http.ResponseWriter, r *http.Request) {
49 | var header = w.Header()
50 | header.Add("content-type", "text/json; charset=utf-8")
51 | var jsonStr = "{\"message\": \"pong\"}"
52 | w.Write([]byte(jsonStr))
53 | w.WriteHeader(http.StatusOK)
54 | }
55 |
56 | type GraphData struct {
57 | Nodes []src.Node `json:"nodes"`
58 | Links []src.Link `json:"links"`
59 | Num uint32 `json:"num"`
60 | }
61 |
62 | type GraphJson struct {
63 | Message string `json:"message"`
64 | Data GraphData `json:"data"`
65 | }
66 |
67 | type TreeData struct {
68 | Tree src.Tree `json:"tree"`
69 | Depth uint32 `json:"depth"`
70 | Width uint32 `json:"width"`
71 | }
72 |
73 | type TreeJson struct {
74 | Message string `json:"message"`
75 | Data TreeData `json:"data"`
76 | }
77 |
78 | type AnTreeData struct {
79 | Tree map[string]*src.Tree `json:"tree"`
80 | }
81 |
82 | type AnTreeJson struct {
83 | Message string `json:"message"`
84 | Data AnTreeData `json:"data"`
85 | }
86 |
87 | func main() {
88 | flag.Parse()
89 | fmt.Println("go mod graph version v0.5.3")
90 | var goModGraph string = src.GetGoModGraph()
91 |
92 | // nodes and links
93 | nodes, links := src.GraphToNodeLinks(goModGraph)
94 | nodeArr := map[uint32]src.Node{}
95 | for _, item := range nodes {
96 | nodeArr[item.Id] = item
97 | }
98 | nodeSortArr := []src.Node{}
99 | for key := 0; key < len(nodes); key++ {
100 | nodeSortArr = append(nodeSortArr, nodeArr[uint32(key)])
101 | }
102 |
103 | // tree
104 | tree, depth, width, anotherTree := src.BuildTree(goModGraph)
105 |
106 | if 0 < debug {
107 | // 如果是 debug 模式
108 | re, _ := json.Marshal(&nodeSortArr)
109 | fmt.Printf("nodes : %s\n\n", string(re))
110 | re, _ = json.Marshal(&links)
111 | fmt.Printf("links : %s\n\n", string(re))
112 | re, _ = json.Marshal(&tree)
113 | fmt.Printf("tree : %s\n", string(re))
114 | return
115 | }
116 |
117 | mux := http.NewServeMux()
118 | mux.HandleFunc("/", IndexHandler)
119 | mux.HandleFunc("/main.js", MainJsHandler)
120 | mux.HandleFunc("/ping", PingHandler)
121 |
122 | mux.HandleFunc("/graph.json", func(w http.ResponseWriter, r *http.Request) {
123 | var header = w.Header()
124 | header.Add("Content-type", "text/javascript; charset=utf-8")
125 | w.WriteHeader(http.StatusOK)
126 | var graph = GraphJson{
127 | Message: "success",
128 | Data: GraphData{
129 | Nodes: nodeSortArr,
130 | Links: links,
131 | Num: uint32(len(nodeSortArr)),
132 | },
133 | }
134 | var graphStr, _ = json.Marshal(graph)
135 | w.Write(graphStr)
136 | })
137 |
138 | mux.HandleFunc("/tree.json", func(w http.ResponseWriter, r *http.Request) {
139 | var header = w.Header()
140 | header.Add("Content-type", "text/javascript; charset=utf-8")
141 | w.WriteHeader(http.StatusOK)
142 | var tree = TreeJson{
143 | Message: "success",
144 | Data: TreeData{
145 | Tree: *tree,
146 | Depth: depth,
147 | Width: width,
148 | },
149 | }
150 | var treeStr, _ = json.Marshal(tree)
151 | w.Write(treeStr)
152 | })
153 |
154 | var host = "0.0.0.0"
155 | // 监听并在 0.0.0.0:xx 上启动服务
156 | li, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
157 | if nil != err {
158 | fmt.Printf("gmchart server listen err(%v)\n", err)
159 | }
160 |
161 | mux.HandleFunc("/an-tree.json", func (w http.ResponseWriter, r *http.Request) {
162 | var header = w.Header()
163 | header.Add("Content-type", "text/javascript; charset=utf-8")
164 | w.WriteHeader(http.StatusOK)
165 | var tree = AnTreeJson{
166 | Message: "success",
167 | Data: AnTreeData{
168 | Tree: anotherTree,
169 | },
170 | }
171 | var treeStr, _ = json.Marshal(tree)
172 | w.Write(treeStr)
173 | })
174 |
175 | server := &http.Server{
176 | Handler: mux,
177 | }
178 | addr := li.Addr().String()
179 | var addrs = strings.Split(addr, ":")
180 | var printAddr = "http://127.0.0.1:" + addrs[len(addrs)-1] // 这里127.0.0.1 写死,兼容win
181 | if strings.ToLower(mode) == "graph" {
182 | printAddr += "/#graph"
183 | }
184 |
185 | go func() error {
186 | // open it by default browser
187 | return src.OpenBrowser(printAddr)
188 | }()
189 |
190 | if 1 > keep {
191 | go func() error {
192 | fmt.Printf("the go mod graph will top in 60s\nvisit it by %s\n", printAddr)
193 | time.Sleep(60 * time.Second)
194 | os.Exit(0)
195 | return nil
196 | }()
197 | }
198 |
199 | err = server.Serve(li)
200 | if err != nil {
201 | fmt.Printf("gmchart server start err(%v)\n", err)
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/gosrc/treeutil.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | type RouteNode struct {
9 | Id uint32 `json:"id"`
10 | Name string `json:"name"`
11 | Value uint32 `json:"value"`
12 | Route []uint32 `json:"-"`
13 | }
14 |
15 | type Tree struct {
16 | Id uint32 `json:"-"`
17 | Name string `json:"name"`
18 | Value uint32 `json:"value"`
19 | Children []*Tree `json:"children"`
20 | }
21 |
22 | var routeNodes = map[string]RouteNode{}
23 |
24 | func BuildTree(graph string) (root *Tree, depth uint32, width uint32, repeatDependNodes map[string]*Tree) {
25 | root = new(Tree)
26 | repeatDependNodes = make(map[string]*Tree, 0)
27 | var roots = make(map[string]*Tree, 0)
28 | var key uint32 = 0
29 | for _, line := range strings.Split(graph, "\n") {
30 | if 1 > len(line) {
31 | continue
32 | }
33 | splitStr := strings.Split(line, " ")
34 | if 2 > len(splitStr) {
35 | panic(fmt.Sprintf("go mod graph output format error——%s", line))
36 | }
37 |
38 | var tree = new(Tree)
39 | var theRouteNode1 = GetRouteNode(splitStr[0])
40 | if nil == theRouteNode1 {
41 | // 寻找父节点
42 | tree.Name = splitStr[0]
43 | tree.Id = key
44 | tree.Value = 1
45 |
46 | if newRoot, ok := roots[splitStr[0]]; ok {
47 | newRoot.Value++
48 | } else {
49 | newRoot = &Tree{
50 | Id: key,
51 | Name: splitStr[0],
52 | Value: 1,
53 | }
54 | roots[splitStr[0]] = newRoot
55 | InsertTreeRoute(newRoot, []uint32{})
56 | }
57 | if 1 > len(root.Name) {
58 | // 如果 root 为空
59 | root.Id = tree.Id
60 | root.Name = tree.Name
61 | root.Value = tree.Value
62 | InsertTreeRoute(tree, []uint32{})
63 | key ++
64 | }
65 | theRouteNode1val := routeNodes[tree.Name]
66 | theRouteNode1 = &theRouteNode1val
67 | } else {
68 | // 重复正常
69 | //fmt.Println("重复的依赖节点")
70 | }
71 |
72 | var tree2 = new(Tree)
73 | tree2.Name = splitStr[1]
74 | tree2.Id = key
75 | tree2.Value = 1
76 |
77 | // 依赖节点
78 | var theRouteNode2 = GetRouteNode(splitStr[1])
79 | if nil == theRouteNode2 {
80 | // 新节点
81 | AppendTreeAfter(root, splitStr[0], tree2)
82 | key ++
83 | } else {
84 | // 这是规则外的
85 | //fmt.Println("重复的依赖节点", splitStr[1])
86 | tree2.Id = theRouteNode2.Id // 重复了就要用原来的
87 | var theRouteKeys = append([]uint32{0}, theRouteNode2.Route...)
88 | var theParentNode = &Tree{}
89 | if getNode := GetNodeByKeys([]*Tree{root}, theRouteKeys); nil != getNode {
90 | theParentNode = getNode
91 | }
92 | var newRepeatDependNode = Tree{}
93 | if value, ok := repeatDependNodes[theRouteNode2.Name]; !ok {
94 | newRepeatDependNode = Tree{
95 | Name: tree2.Name,
96 | Value: tree2.Value,
97 | Id: tree2.Id,
98 | Children: []*Tree{
99 | { // 之前的那个节点也带上啊a
100 | Name: theParentNode.Name,
101 | Value: theParentNode.Value,
102 | Id: theParentNode.Id,
103 | },
104 | {
105 | Name: theRouteNode1.Name,
106 | Value: theRouteNode1.Value,
107 | Id: theRouteNode1.Id,
108 | },
109 | },
110 | }
111 | repeatDependNodes[tree2.Name] = &newRepeatDependNode
112 | } else {
113 | value.Children = append(value.Children, &Tree{
114 | Name: theRouteNode1.Name,
115 | Value: theRouteNode1.Value,
116 | Id: theRouteNode1.Id,
117 | })
118 | repeatDependNodes[tree2.Name] = value
119 | }
120 | }
121 | }
122 | depth, width = CalculateDepthHeight(root)
123 | return
124 | }
125 |
126 | func AppendTreeAfter(parentTreeNode *Tree, parent string, new *Tree) {
127 | routeKey := FindTreeRoute(parent)
128 | resultKeys := insertTree(parentTreeNode, routeKey, new)
129 | InsertTreeRoute(new, resultKeys)
130 | }
131 |
132 | func insertTree(parentTree *Tree, keys []uint32, new *Tree) (route []uint32) {
133 | if 1 > len(keys) {
134 | // 如果没有,直接挂根节点下
135 | if nil == parentTree.Children {
136 | parentTree.Children = make([]*Tree, 0)
137 | }
138 | parentTree.Children = append(parentTree.Children, new)
139 | parentTree.Value++
140 | return []uint32{uint32(len(parentTree.Children)-1)}
141 | }
142 | theKey := keys[0]
143 | if nil != parentTree.Children && 0 < len(parentTree.Children) {
144 | if int(theKey) > len(parentTree.Children) {
145 | fmt.Println("out range of arr length")
146 | }
147 | var theChild = parentTree.Children[theKey]
148 | if 1 == len(keys) {
149 | if nil == theChild.Children {
150 | theChild.Children = make([]*Tree, 0)
151 | }
152 | theChild.Children = append(theChild.Children, new)
153 | parentTree.Value++
154 | return []uint32{theKey, uint32(len(theChild.Children)-1)}
155 | } else {
156 | // 进入下级
157 | lastKeys := insertTree(theChild, keys[1:], new)
158 | return append([]uint32{theKey}, lastKeys...)
159 | }
160 | } else {
161 |
162 | }
163 | return
164 | }
165 |
166 | func GetRouteNode(key string) (*RouteNode) {
167 | if routeNode, ok := routeNodes[key]; ok {
168 | return &routeNode
169 | } else {
170 | // 没找到
171 | return nil
172 | }
173 | if "" == key {
174 | return nil
175 | } else {
176 | return nil
177 | }
178 | }
179 |
180 | func FindTreeRoute(key string) (route []uint32) {
181 | if routeNode, ok := routeNodes[key]; ok {
182 | return routeNode.Route
183 | }
184 | if "" == key {
185 | return []uint32{}
186 | } else {
187 | panic("有问题")
188 | }
189 | }
190 |
191 | func InsertTreeRoute(newTree *Tree, keys []uint32) {
192 | if the, ok := routeNodes[newTree.Name]; ok {
193 | the.Route = keys
194 | } else {
195 | routeNodes[newTree.Name] = RouteNode {
196 | Id: newTree.Id,
197 | Name: newTree.Name,
198 | Route: keys,
199 | Value: newTree.Value,
200 | }
201 | }
202 | return
203 | }
204 |
205 | func CalculateDepthHeight(root *Tree) (depth uint32, width uint32) {
206 | depth = calcDepth(root.Children)
207 | var treeWidths = &[]uint32{1}
208 | calcWidth(root.Children, treeWidths, 1)
209 | width = (*treeWidths)[0]
210 | for _, item := range *treeWidths {
211 | if width < item {
212 | width = item
213 | }
214 | }
215 | return
216 | }
217 |
218 | func calcDepth(node []*Tree) (depth uint32) {
219 | if nil != node && 0 < len(node) {
220 | // 有
221 | var maxDepth uint32 = 0
222 | var theDepth uint32 = 0
223 | for _, item := range node {
224 | theDepth = calcDepth(item.Children)
225 | if theDepth > maxDepth {
226 | // 如果更深
227 | maxDepth = theDepth
228 | }
229 | }
230 | return maxDepth + 1
231 | }
232 | // 没有
233 | return 1
234 | }
235 |
236 | func calcWidth(node []*Tree, treeWidths *[]uint32, level int) {
237 | if nil != node && 0 < len(node) {
238 | // 有
239 | var theWidth uint32 = uint32(len(node))
240 | if level < len(*treeWidths) {
241 | var originWidth = (*treeWidths)[level]
242 | (*treeWidths)[level] = originWidth + theWidth
243 | } else {
244 | *treeWidths = append(*treeWidths, theWidth)
245 | }
246 | for _, item := range node {
247 | calcWidth(item.Children, treeWidths, level + 1)
248 | }
249 | }
250 | }
251 |
252 | func GetNodeByKeys(tree []*Tree, keys []uint32) (re *Tree) {
253 | if 1 > len(keys) {
254 | return nil
255 | }
256 | if int(keys[0]) >= len(tree) {
257 | return nil
258 | }
259 | node := tree[keys[0]]
260 | if 1 < len(keys) {
261 | return GetNodeByKeys(node.Children, keys[1:])
262 | } else if 1 == len(keys) {
263 | return node
264 | } else {
265 | return nil
266 | }
267 | }
--------------------------------------------------------------------------------
/src/static/tree.json:
--------------------------------------------------------------------------------
1 | {"message":"success","data":{"tree":{"name":"go-mod-graph-charting","value":39,"children":[{"name":"github.com/gin-gonic/gin@v1.6.3","value":9,"children":[{"name":"github.com/gin-contrib/sse@v0.1.0","value":1,"children":[{"name":"github.com/stretchr/testify@v1.3.0","value":1,"children":null}]},{"name":"github.com/go-playground/validator/v10@v10.2.0","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.3.3","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null},{"name":"github.com/mattn/go-isatty@v0.0.12","value":1,"children":[{"name":"golang.org/x/sys@v0.0.0-20200116001909-b77594299b42","value":1,"children":null}]},{"name":"github.com/stretchr/testify@v1.4.0","value":1,"children":[{"name":"github.com/davecgh/go-spew@v1.1.0","value":1,"children":null},{"name":"github.com/pmezard/go-difflib@v1.0.0","value":1,"children":null},{"name":"github.com/stretchr/objx@v0.1.0","value":1,"children":null},{"name":"gopkg.in/yaml.v2@v2.2.2","value":1,"children":null}]},{"name":"github.com/ugorji/go/codec@v1.1.7","value":1,"children":[{"name":"github.com/ugorji/go@v1.1.7","value":1,"children":null}]},{"name":"gopkg.in/yaml.v2@v2.2.8","value":1,"children":[{"name":"gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405","value":1,"children":null}]}]},{"name":"github.com/go-playground/validator/v10@v10.4.1","value":3,"children":[{"name":"github.com/go-playground/assert/v2@v2.0.1","value":1,"children":null},{"name":"github.com/go-playground/locales@v0.13.0","value":2,"children":[{"name":"golang.org/x/text@v0.3.2","value":1,"children":[{"name":"golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e","value":1,"children":null}]}]},{"name":"github.com/go-playground/universal-translator@v0.17.0","value":1,"children":null},{"name":"github.com/leodido/go-urn@v1.2.0","value":1,"children":null},{"name":"golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9","value":1,"children":[{"name":"golang.org/x/sys@v0.0.0-20190412213103-97732733099d","value":1,"children":null}]}]},{"name":"github.com/golang/protobuf@v1.4.3","value":2,"children":[{"name":"google.golang.org/protobuf@v1.23.0","value":2,"children":[{"name":"github.com/golang/protobuf@v1.4.0","value":2,"children":[{"name":"google.golang.org/protobuf@v1.21.0","value":2,"children":[{"name":"github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0","value":2,"children":[{"name":"google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967","value":2,"children":[{"name":"github.com/golang/protobuf@v1.4.0-rc.2","value":2,"children":[{"name":"google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60","value":2,"children":[{"name":"github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208","value":3,"children":[{"name":"google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64","value":2,"children":[{"name":"github.com/golang/protobuf@v1.4.0-rc.1","value":2,"children":[{"name":"google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd","value":1,"children":[{"name":"github.com/google/go-cmp@v0.3.0","value":1,"children":null}]}]},{"name":"github.com/google/go-cmp@v0.3.1","value":1,"children":null}]}]}]}]}]}]}]}]}]}]},{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":[{"name":"github.com/davecgh/go-spew@v1.1.1","value":1,"children":null},{"name":"github.com/google/gofuzz@v1.0.0","value":1,"children":null},{"name":"github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421","value":1,"children":null},{"name":"github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742","value":1,"children":null}]},{"name":"github.com/leodido/go-urn@v1.2.1","value":2,"children":[{"name":"github.com/stretchr/testify@v1.6.1","value":1,"children":[{"name":"gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c","value":1,"children":null}]}]},{"name":"github.com/modern-go/concurrent@v0.0.0-20180306012644-bacd9c7ef1dd","value":1,"children":null},{"name":"github.com/modern-go/reflect2@v1.0.1","value":1,"children":null},{"name":"github.com/ugorji/go@v1.2.2","value":1,"children":[{"name":"github.com/ugorji/go/codec@v1.2.2","value":1,"children":null}]},{"name":"golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad","value":3,"children":[{"name":"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3","value":2,"children":[{"name":"golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2","value":1,"children":[{"name":"golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a","value":1,"children":null}]},{"name":"golang.org/x/text@v0.3.0","value":1,"children":null}]},{"name":"golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037","value":1,"children":null},{"name":"golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221","value":1,"children":null}]},{"name":"golang.org/x/sys@v0.0.0-20201223074533-0d417f636930","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.25.0","value":9,"children":[{"name":"github.com/golang/protobuf@v1.4.1","value":1,"children":[{"name":"github.com/google/go-cmp@v0.4.0","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.22.0","value":1,"children":null}]},{"name":"github.com/google/go-cmp@v0.5.0","value":1,"children":[{"name":"golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543","value":1,"children":null}]},{"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":12,"children":[{"name":"golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3","value":1,"children":[{"name":"golang.org/x/tools@v0.0.0-20190311212946-11955173bddd","value":1,"children":null}]},{"name":"golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135","value":1,"children":[{"name":"golang.org/x/net@v0.0.0-20190311183353-d8887717615a","value":1,"children":null},{"name":"golang.org/x/sync@v0.0.0-20190423024810-112230192c58","value":1,"children":null}]},{"name":"google.golang.org/grpc@v1.27.0","value":9,"children":[{"name":"github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473","value":1,"children":[{"name":"github.com/census-instrumentation/opencensus-proto@v0.2.1","value":1,"children":null},{"name":"github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},{"name":"github.com/envoyproxy/protoc-gen-validate@v0.1.0","value":1,"children":null},{"name":"github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b","value":1,"children":null},{"name":"github.com/golang/mock@v1.1.1","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.3.2","value":1,"children":null},{"name":"github.com/google/go-cmp@v0.2.0","value":1,"children":null},{"name":"golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be","value":1,"children":null},{"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":15,"children":[{"name":"golang.org/x/exp@v0.0.0-20190121172915-509febef88a4","value":1,"children":null},{"name":"golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961","value":1,"children":null},{"name":"golang.org/x/tools@v0.0.0-20190226205152-f727befe758c","value":2,"children":[{"name":"golang.org/x/net@v0.0.0-20190213061140-3a22650c66bd","value":1,"children":null},{"name":"golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f","value":1,"children":null},{"name":"google.golang.org/appengine@v1.4.0","value":1,"children":[{"name":"golang.org/x/net@v0.0.0-20180724234803-3673e40ba225","value":1,"children":null}]}]},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":[{"name":"cloud.google.com/go@v0.26.0","value":1,"children":null},{"name":"github.com/BurntSushi/toml@v0.3.1","value":1,"children":null},{"name":"github.com/client9/misspell@v0.3.4","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.2.0","value":1,"children":null},{"name":"golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3","value":1,"children":null},{"name":"golang.org/x/net@v0.0.0-20180826012351-8a410e7b638d","value":1,"children":null},{"name":"golang.org/x/sync@v0.0.0-20180314180146-1d60e4601c6f","value":1,"children":null},{"name":"golang.org/x/sys@v0.0.0-20180830151530-49385e6e1522","value":1,"children":null},{"name":"golang.org/x/tools@v0.0.0-20190114222345-bf090417da8b","value":1,"children":null},{"name":"google.golang.org/appengine@v1.1.0","value":1,"children":null},{"name":"google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8","value":1,"children":null}]},{"name":"honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099","value":1,"children":null}]}]},{"name":"google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc","value":1,"children":null},{"name":"honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc","value":1,"children":null}]}]},{"name":"gopkg.in/yaml.v2@v2.4.0","value":1,"children":null}]},"depth":14,"width":26}}
--------------------------------------------------------------------------------
/src/js/tree.js:
--------------------------------------------------------------------------------
1 | import * as d3 from 'd3';
2 | import CSS from '../css/styles.css';
3 |
4 | var treeWidth = 1;
5 | var treeDepth = 1;
6 |
7 | var width = 4000;
8 | var height = 2500;
9 |
10 | var innerWidth = 0
11 | var innerHeight = 0;
12 |
13 | var subWidth = 640;
14 | var subHeight = 480;
15 |
16 | var root;
17 | var color;
18 | var anTree;
19 |
20 | const margin = { top: 5, right: 200, bottom: 5, left: 200 };
21 |
22 | export default function tree() {
23 | const svg = d3.select('#app').append('svg').attr('id', 'svg')
24 | .attr('width', width).attr('height', height);
25 | const subSvg = d3.select('#sub-board').append('svg').attr('id', 'sub-svg')
26 | .attr('width', subWidth).attr('height', subHeight);
27 |
28 | let markerBoxWidth = 10;
29 | let markerBoxHeight = 10;
30 | let refX = 10;
31 | let refY = 4;
32 | svg.append('defs')
33 | .append('marker')
34 | .attr('id', 'arrow')
35 | .attr('viewBox', [0, 0, markerBoxWidth, markerBoxHeight])
36 | .attr('refX', refX)
37 | .attr('refY', refY)
38 | .attr('markerWidth', markerBoxWidth)
39 | .attr('markerHeight', markerBoxHeight)
40 | .attr('orient', 'auto-start-reverse')
41 | .append('path')
42 | .attr('d', d3.line()([[0, 0], [8, 4], [0, 8], [0, 7], [9, 4], [0, 1], [0, 0]]))
43 | .attr('stroke', 'black');
44 |
45 |
46 | const g = svg.append('g')
47 | .attr('transform', `translate(${margin.left}, ${margin.top})`);
48 |
49 | const fill = d => {
50 | if (d.depth === 0)
51 | return color(d.data.name)
52 | else
53 | return color(d.parent.data.name)
54 | }
55 |
56 | document.getElementById('mask').addEventListener('click', function (ev) {
57 | if ('mask' == ev.target.getAttribute('id')) {
58 | // ev.target.setAttribute("class", "mask hide");
59 | document.getElementById('mask').setAttribute("class", "mask hide");
60 | }
61 | });
62 |
63 | const subRender = function (data) {
64 | let anotation = 500;
65 | color = d3.scaleOrdinal()
66 | .domain(data.descendants().filter(d => d.depth <= 1).map(d => d.data.name))
67 | .range(d3.schemeCategory10);
68 |
69 | subSvg.selectAll("path")
70 | .data(data.links())
71 | .join("path")
72 | .classed('tree-path', true)
73 | .attr("d", d3.linkHorizontal().x(d => anotation - d.y).y(d => d.x));
74 |
75 | subSvg.selectAll('circle').data(data.descendants()).join('circle')
76 | // optionally, we can use stroke-linejoin to beautify the path connection;
77 | //.attr("stroke-linejoin", "round")
78 | .classed('tree-circle', true)
79 | .attr("fill", fill)
80 | .attr('id', (d, i) => `circle-${i}`)
81 | .attr('cx', d => anotation - d.y)
82 | .attr('cy', d => d.x)
83 | .attr("r", function (d) {
84 | if (d.children) {
85 | return 6 + Math.sqrt(d.children.length) * 3;
86 | } else {
87 | return 7;
88 | }
89 | });
90 |
91 | subSvg.selectAll('text').data(data.descendants()).join('text')
92 | .classed('tree-text', true)
93 | .attr("text-anchor", d => d.children ? "end" : "start")
94 | .attr('id', (d, i) => `text-${i}`)
95 | // note that if d is a child, d.children is undefined which is actually false!
96 | .attr('x', d => (d.children ? -6 : 6) + (anotation - d.y))
97 | .attr('y', function (d) { return d.depth % 2 ? d.x - 3 : d.x + 14 })
98 | .text(function (d) {
99 | // 默认最多只展示版本号,不展示hash
100 | return d.data.name.replace(/(@[\w\.]*?)(-)(.*$)/, "$1")
101 | });
102 | }
103 |
104 | const renderSubTree = function (d, i) {
105 | let theName = d.data.name;
106 | let subTree = undefined;
107 | if (anTree[theName] !== undefined) {
108 | subTree = anTree[theName]
109 | } else {
110 | return
111 | }
112 |
113 | document.getElementById('mask').setAttribute("class", "mask");
114 |
115 | let theSubHeight = subTree.children.length * 150;
116 | d3.select('#sub-board').select('#sub-svg').attr('width', subWidth).attr('height', theSubHeight);
117 |
118 | let subRoot = d3.hierarchy(subTree);
119 | subRoot = d3.tree().size([theSubHeight, subWidth - 200])(subRoot);
120 | subRender(subRoot);
121 | }
122 |
123 | const render = function (data, anData) {
124 | color = d3.scaleOrdinal()
125 | .domain(data.descendants().filter(d => d.depth <= 1).map(d => d.data.name))
126 | .range(d3.schemeCategory10);
127 |
128 | g.selectAll("path")
129 | .data(data.links())
130 | .join("path")
131 | .classed('tree-path', true)
132 | .attr("d", d3.linkHorizontal().x(d => d.y).y(d => d.x))
133 | .attr("marker-end", function (d, i) {
134 | let check = anData[d.target.data.name];
135 | if (undefined != check) {
136 | return "url(#arrow)"
137 | }
138 | });
139 |
140 | g.selectAll('circle').data(data.descendants()).join('circle')
141 | // optionally, we can use stroke-linejoin to beautify the path connection;
142 | //.attr("stroke-linejoin", "round")
143 | .classed('tree-circle', true)
144 | .attr("fill", fill)
145 | .attr('id', (d, i) => `circle-${i}`)
146 | .attr('cx', d => d.y)
147 | .attr('cy', d => d.x)
148 | .attr("r", function (d) {
149 | if (d.children) {
150 | return 6 + Math.sqrt(d.children.length) * 3;
151 | } else {
152 | return 7;
153 | }
154 | }).on('mouseover', function (d, i) {
155 | d3.select(this).classed('on', true);
156 | d3.select("#text-" + i).classed('on', true);
157 | }).on('mouseout', function (d, i) {
158 | d3.select(this).classed('on', false).attr('stroke', fill(d));
159 | d3.select("#text-" + i).classed('on', false);
160 | }).on('click', renderSubTree);
161 |
162 | g.selectAll('text').data(data.descendants()).join('text')
163 | .classed('tree-text', true)
164 | .attr("text-anchor", d => d.children ? "end" : "start")
165 | .attr('id', (d, i) => `text-${i}`)
166 | // note that if d is a child, d.children is undefined which is actually false!
167 | .attr('x', d => (d.children ? -6 : 6) + d.y)
168 | .attr('y', function (d) { return d.depth % 2 ? d.x - 3 : d.x + 14 })
169 | .text(function (d) {
170 | // 默认最多只展示版本号,不展示hash
171 | return d.data.name.replace(/(@[\w\.]*?)(-)(.*$)/, "$1")
172 | })
173 | .on('mouseover', function (d, i) {
174 | // 鼠标放上去时,才展示后面的hash值
175 | d3.select(this).classed('on', true).text(d => d.data.name);
176 | d3.select("#circle-" + i).classed('on', true);
177 | }).on('mouseout', function (d, i) {
178 | d3.select(this).classed('on', false).text(function (d) {
179 | return d.data.name.replace(/(@[\w\.]*?)(-)(.*$)/, "$1")
180 | });
181 | d3.select("#circle-" + i).classed('on', false).attr('stroke', fill(d));
182 | }).on('click', renderSubTree);
183 | }
184 |
185 | d3.json('/an-tree.json').then(data => {
186 | anTree = data.data.tree;
187 |
188 | d3.json('/tree.json').then(data => {
189 | let treeData = data.data.tree;
190 | treeWidth = data.data.width;
191 | treeDepth = data.data.depth;
192 |
193 | innerWidth = treeDepth * 450;
194 | innerHeight = treeWidth * 70;
195 |
196 | width = innerWidth + margin.left + margin.right;
197 | height = innerHeight + margin.top + margin.bottom;
198 |
199 | d3.select('#app').select('svg').attr('width', width).attr('height', height);
200 |
201 | root = d3.hierarchy(treeData);
202 | // alternatively, we can set size of each node;
203 | // root = d3.tree().nodeSize([30, width / (root.height + 1)])(root);
204 | root = d3.tree().size([innerHeight, innerWidth])(root);
205 | render(root, anTree);
206 |
207 | setTimeout(function () {
208 | window.scrollTo(0, height / 2)
209 | }, 1000);
210 | });
211 | });
212 |
213 | }
214 |
--------------------------------------------------------------------------------
/src/static/an-tree.json:
--------------------------------------------------------------------------------
1 | {"message":"success","data":{"tree":{"cloud.google.com/go@v0.26.0":{"name":"cloud.google.com/go@v0.26.0","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/BurntSushi/toml@v0.3.1":{"name":"github.com/BurntSushi/toml@v0.3.1","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/client9/misspell@v0.3.4":{"name":"github.com/client9/misspell@v0.3.4","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/davecgh/go-spew@v1.1.0":{"name":"github.com/davecgh/go-spew@v1.1.0","value":1,"children":[{"name":"github.com/stretchr/testify@v1.4.0","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.6.1","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.3.0","value":1,"children":null}]},"github.com/davecgh/go-spew@v1.1.1":{"name":"github.com/davecgh/go-spew@v1.1.1","value":1,"children":[{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null}]},"github.com/envoyproxy/protoc-gen-validate@v0.1.0":{"name":"github.com/envoyproxy/protoc-gen-validate@v0.1.0","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":7,"children":null},{"name":"github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473","value":1,"children":null}]},"github.com/go-playground/assert/v2@v2.0.1":{"name":"github.com/go-playground/assert/v2@v2.0.1","value":1,"children":[{"name":"github.com/go-playground/validator/v10@v10.4.1","value":2,"children":null},{"name":"github.com/go-playground/validator/v10@v10.2.0","value":1,"children":null}]},"github.com/go-playground/locales@v0.13.0":{"name":"github.com/go-playground/locales@v0.13.0","value":1,"children":[{"name":"github.com/go-playground/validator/v10@v10.4.1","value":2,"children":null},{"name":"github.com/go-playground/validator/v10@v10.2.0","value":1,"children":null},{"name":"github.com/go-playground/universal-translator@v0.17.0","value":1,"children":null}]},"github.com/go-playground/universal-translator@v0.17.0":{"name":"github.com/go-playground/universal-translator@v0.17.0","value":1,"children":[{"name":"github.com/go-playground/validator/v10@v10.4.1","value":2,"children":null},{"name":"github.com/go-playground/validator/v10@v10.2.0","value":1,"children":null}]},"github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b":{"name":"github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":6,"children":null},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/golang/mock@v1.1.1":{"name":"github.com/golang/mock@v1.1.1","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":6,"children":null},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/golang/protobuf@v1.2.0":{"name":"github.com/golang/protobuf@v1.2.0","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/appengine@v1.4.0","value":1,"children":null},{"name":"github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/golang/protobuf@v1.3.2":{"name":"github.com/golang/protobuf@v1.3.2","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":1,"children":null},{"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":1,"children":null},{"name":"github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473","value":1,"children":null}]},"github.com/golang/protobuf@v1.4.0":{"name":"github.com/golang/protobuf@v1.4.0","value":1,"children":[{"name":"google.golang.org/protobuf@v1.23.0","value":2,"children":null},{"name":"google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.22.0","value":1,"children":null}]},"github.com/golang/protobuf@v1.4.1":{"name":"github.com/golang/protobuf@v1.4.1","value":1,"children":[{"name":"google.golang.org/protobuf@v1.25.0","value":4,"children":null},{"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":1,"children":null}]},"github.com/google/go-cmp@v0.2.0":{"name":"github.com/google/go-cmp@v0.2.0","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":9,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"github.com/google/go-cmp@v0.3.1":{"name":"github.com/google/go-cmp@v0.3.1","value":1,"children":[{"name":"google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.0-rc.1","value":1,"children":null}]},"github.com/google/go-cmp@v0.4.0":{"name":"github.com/google/go-cmp@v0.4.0","value":1,"children":[{"name":"github.com/golang/protobuf@v1.4.1","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.3","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.23.0","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.0","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.21.0","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967","value":1,"children":null},{"name":"google.golang.org/protobuf@v1.22.0","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.0-rc.2","value":1,"children":null},{"name":"google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60","value":1,"children":null},{"name":"github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208","value":1,"children":null}]},"github.com/google/gofuzz@v1.0.0":{"name":"github.com/google/gofuzz@v1.0.0","value":1,"children":[{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null}]},"github.com/leodido/go-urn@v1.2.0":{"name":"github.com/leodido/go-urn@v1.2.0","value":1,"children":[{"name":"github.com/go-playground/validator/v10@v10.4.1","value":2,"children":null},{"name":"github.com/go-playground/validator/v10@v10.2.0","value":1,"children":null}]},"github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421":{"name":"github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421","value":1,"children":[{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null}]},"github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742":{"name":"github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742","value":1,"children":[{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null}]},"github.com/pmezard/go-difflib@v1.0.0":{"name":"github.com/pmezard/go-difflib@v1.0.0","value":1,"children":[{"name":"github.com/stretchr/testify@v1.4.0","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.6.1","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.3.0","value":1,"children":null}]},"github.com/stretchr/objx@v0.1.0":{"name":"github.com/stretchr/objx@v0.1.0","value":1,"children":[{"name":"github.com/stretchr/testify@v1.4.0","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.6.1","value":1,"children":null},{"name":"github.com/stretchr/testify@v1.3.0","value":1,"children":null}]},"github.com/stretchr/testify@v1.3.0":{"name":"github.com/stretchr/testify@v1.3.0","value":1,"children":[{"name":"github.com/gin-contrib/sse@v0.1.0","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.10","value":1,"children":null},{"name":"github.com/json-iterator/go@v1.1.9","value":1,"children":null}]},"github.com/stretchr/testify@v1.4.0":{"name":"github.com/stretchr/testify@v1.4.0","value":1,"children":[{"name":"github.com/gin-gonic/gin@v1.6.3","value":9,"children":null},{"name":"github.com/leodido/go-urn@v1.2.0","value":1,"children":null}]},"github.com/ugorji/go/codec@v1.1.7":{"name":"github.com/ugorji/go/codec@v1.1.7","value":1,"children":[{"name":"github.com/gin-gonic/gin@v1.6.3","value":8,"children":null},{"name":"github.com/ugorji/go@v1.1.7","value":1,"children":null}]},"github.com/ugorji/go@v1.2.2":{"name":"github.com/ugorji/go@v1.2.2","value":1,"children":[{"name":"go-mod-graph-charting","value":39,"children":null},{"name":"github.com/ugorji/go/codec@v1.2.2","value":1,"children":null}]},"golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2":{"name":"golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2","value":1,"children":[{"name":"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3","value":2,"children":null},{"name":"golang.org/x/net@v0.0.0-20190311183353-d8887717615a","value":1,"children":null}]},"golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3":{"name":"golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3","value":1,"children":[{"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":12,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"golang.org/x/net@v0.0.0-20190311183353-d8887717615a":{"name":"golang.org/x/net@v0.0.0-20190311183353-d8887717615a","value":1,"children":[{"name":"golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135","value":1,"children":null},{"name":"golang.org/x/tools@v0.0.0-20190311212946-11955173bddd","value":1,"children":null},{"name":"google.golang.org/grpc@v1.27.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3":{"name":"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3","value":1,"children":[{"name":"golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad","value":3,"children":null},{"name":"golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9","value":1,"children":null}]},"golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be":{"name":"golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":6,"children":null},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f":{"name":"golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f","value":1,"children":[{"name":"golang.org/x/tools@v0.0.0-20190226205152-f727befe758c","value":2,"children":null},{"name":"github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4","value":1,"children":null}]},"golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a":{"name":"golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a","value":1,"children":[{"name":"golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2","value":1,"children":null},{"name":"google.golang.org/grpc@v1.27.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037":{"name":"golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037","value":1,"children":[{"name":"golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad","value":3,"children":null},{"name":"golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221","value":1,"children":null}]},"golang.org/x/text@v0.3.0":{"name":"golang.org/x/text@v0.3.0","value":1,"children":[{"name":"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3","value":2,"children":null},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"golang.org/x/net@v0.0.0-20190311183353-d8887717615a","value":1,"children":null},{"name":"google.golang.org/appengine@v1.4.0","value":1,"children":null}]},"golang.org/x/tools@v0.0.0-20190226205152-f727befe758c":{"name":"golang.org/x/tools@v0.0.0-20190226205152-f727befe758c","value":1,"children":[{"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":15,"children":null},{"name":"golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961","value":1,"children":null}]},"golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135":{"name":"golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135","value":1,"children":[{"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":12,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543":{"name":"golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543","value":1,"children":[{"name":"github.com/google/go-cmp@v0.5.0","value":1,"children":null},{"name":"github.com/google/go-cmp@v0.4.0","value":1,"children":null}]},"google.golang.org/appengine@v1.1.0":{"name":"google.golang.org/appengine@v1.1.0","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8":{"name":"google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8","value":1,"children":[{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]},"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55":{"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":1,"children":[{"name":"google.golang.org/grpc@v1.27.0","value":8,"children":null},{"name":"github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473","value":1,"children":null}]},"gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405":{"name":"gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405","value":1,"children":[{"name":"gopkg.in/yaml.v2@v2.2.8","value":1,"children":null},{"name":"gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c","value":1,"children":null},{"name":"gopkg.in/yaml.v2@v2.4.0","value":1,"children":null},{"name":"gopkg.in/yaml.v2@v2.2.2","value":1,"children":null}]},"honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099":{"name":"honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099","value":1,"children":[{"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":12,"children":null},{"name":"google.golang.org/grpc@v1.19.0","value":1,"children":null}]},"honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc":{"name":"honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc","value":1,"children":[{"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":12,"children":null},{"name":"google.golang.org/grpc@v1.23.0","value":1,"children":null}]}}}}
--------------------------------------------------------------------------------
/src/static/graph.json:
--------------------------------------------------------------------------------
1 | {"message":"success","data":{"nodes":[{"id":0,"name":"go-mod-graph-charting","value":12},{"id":1,"name":"github.com/gin-gonic/gin@v1.6.3","value":9},{"id":2,"name":"github.com/go-playground/validator/v10@v10.4.1","value":6},{"id":3,"name":"github.com/golang/protobuf@v1.4.3","value":3},{"id":4,"name":"github.com/json-iterator/go@v1.1.10","value":6},{"id":5,"name":"github.com/leodido/go-urn@v1.2.1","value":2},{"id":6,"name":"github.com/modern-go/concurrent@v0.0.0-20180306012644-bacd9c7ef1dd","value":1},{"id":7,"name":"github.com/modern-go/reflect2@v1.0.1","value":1},{"id":8,"name":"github.com/ugorji/go@v1.2.2","value":2},{"id":9,"name":"golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad","value":4},{"id":10,"name":"golang.org/x/sys@v0.0.0-20201223074533-0d417f636930","value":1},{"id":11,"name":"google.golang.org/protobuf@v1.25.0","value":4},{"id":12,"name":"gopkg.in/yaml.v2@v2.4.0","value":2},{"id":13,"name":"github.com/stretchr/testify@v1.6.1","value":5},{"id":14,"name":"github.com/gin-contrib/sse@v0.1.0","value":2},{"id":15,"name":"github.com/go-playground/validator/v10@v10.2.0","value":5},{"id":16,"name":"github.com/golang/protobuf@v1.3.3","value":1},{"id":17,"name":"github.com/json-iterator/go@v1.1.9","value":6},{"id":18,"name":"github.com/mattn/go-isatty@v0.0.12","value":2},{"id":19,"name":"github.com/stretchr/testify@v1.4.0","value":5},{"id":20,"name":"github.com/ugorji/go/codec@v1.1.7","value":2},{"id":21,"name":"gopkg.in/yaml.v2@v2.2.8","value":2},{"id":22,"name":"github.com/davecgh/go-spew@v1.1.0","value":1},{"id":23,"name":"github.com/pmezard/go-difflib@v1.0.0","value":1},{"id":24,"name":"github.com/stretchr/objx@v0.1.0","value":1},{"id":25,"name":"gopkg.in/yaml.v2@v2.2.2","value":2},{"id":26,"name":"github.com/ugorji/go@v1.1.7","value":2},{"id":27,"name":"gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c","value":2},{"id":28,"name":"golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3","value":3},{"id":29,"name":"golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037","value":1},{"id":30,"name":"golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221","value":2},{"id":31,"name":"github.com/golang/protobuf@v1.4.1","value":3},{"id":32,"name":"github.com/google/go-cmp@v0.5.0","value":2},{"id":33,"name":"google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013","value":7},{"id":34,"name":"github.com/google/go-cmp@v0.4.0","value":2},{"id":35,"name":"google.golang.org/protobuf@v1.22.0","value":3},{"id":36,"name":"github.com/ugorji/go/codec@v1.2.2","value":2},{"id":37,"name":"gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405","value":1},{"id":38,"name":"github.com/stretchr/testify@v1.3.0","value":4},{"id":39,"name":"github.com/davecgh/go-spew@v1.1.1","value":1},{"id":40,"name":"github.com/google/gofuzz@v1.0.0","value":1},{"id":41,"name":"github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421","value":1},{"id":42,"name":"github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742","value":1},{"id":43,"name":"google.golang.org/protobuf@v1.23.0","value":3},{"id":44,"name":"golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2","value":2},{"id":45,"name":"golang.org/x/text@v0.3.0","value":1},{"id":46,"name":"golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543","value":1},{"id":47,"name":"golang.org/x/sys@v0.0.0-20200116001909-b77594299b42","value":1},{"id":48,"name":"github.com/go-playground/assert/v2@v2.0.1","value":1},{"id":49,"name":"github.com/go-playground/locales@v0.13.0","value":2},{"id":50,"name":"github.com/go-playground/universal-translator@v0.17.0","value":2},{"id":51,"name":"github.com/leodido/go-urn@v1.2.0","value":2},{"id":52,"name":"golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9","value":3},{"id":53,"name":"golang.org/x/sys@v0.0.0-20190412213103-97732733099d","value":1},{"id":54,"name":"github.com/golang/protobuf@v1.4.0","value":3},{"id":55,"name":"google.golang.org/protobuf@v1.21.0","value":3},{"id":56,"name":"golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3","value":2},{"id":57,"name":"golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135","value":3},{"id":58,"name":"google.golang.org/grpc@v1.27.0","value":11},{"id":59,"name":"google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc","value":3},{"id":60,"name":"honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc","value":1},{"id":61,"name":"github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0","value":3},{"id":62,"name":"golang.org/x/tools@v0.0.0-20190311212946-11955173bddd","value":2},{"id":63,"name":"golang.org/x/text@v0.3.2","value":2},{"id":64,"name":"golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e","value":1},{"id":65,"name":"golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a","value":1},{"id":66,"name":"google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967","value":3},{"id":67,"name":"golang.org/x/net@v0.0.0-20190311183353-d8887717615a","value":3},{"id":68,"name":"golang.org/x/sync@v0.0.0-20190423024810-112230192c58","value":1},{"id":69,"name":"github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473","value":7},{"id":70,"name":"github.com/envoyproxy/protoc-gen-validate@v0.1.0","value":1},{"id":71,"name":"github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b","value":1},{"id":72,"name":"github.com/golang/mock@v1.1.1","value":1},{"id":73,"name":"github.com/golang/protobuf@v1.3.2","value":1},{"id":74,"name":"github.com/google/go-cmp@v0.2.0","value":1},{"id":75,"name":"golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be","value":1},{"id":76,"name":"google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55","value":7},{"id":77,"name":"golang.org/x/exp@v0.0.0-20190121172915-509febef88a4","value":1},{"id":78,"name":"golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961","value":2},{"id":79,"name":"golang.org/x/tools@v0.0.0-20190226205152-f727befe758c","value":4},{"id":80,"name":"google.golang.org/grpc@v1.19.0","value":17},{"id":81,"name":"honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099","value":1},{"id":82,"name":"cloud.google.com/go@v0.26.0","value":1},{"id":83,"name":"github.com/BurntSushi/toml@v0.3.1","value":1},{"id":84,"name":"github.com/client9/misspell@v0.3.4","value":1},{"id":85,"name":"github.com/golang/protobuf@v1.2.0","value":1},{"id":86,"name":"golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3","value":1},{"id":87,"name":"golang.org/x/net@v0.0.0-20180826012351-8a410e7b638d","value":1},{"id":88,"name":"golang.org/x/sync@v0.0.0-20180314180146-1d60e4601c6f","value":1},{"id":89,"name":"golang.org/x/sys@v0.0.0-20180830151530-49385e6e1522","value":1},{"id":90,"name":"golang.org/x/tools@v0.0.0-20190114222345-bf090417da8b","value":1},{"id":91,"name":"google.golang.org/appengine@v1.1.0","value":1},{"id":92,"name":"google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8","value":1},{"id":93,"name":"github.com/census-instrumentation/opencensus-proto@v0.2.1","value":1},{"id":94,"name":"github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4","value":3},{"id":95,"name":"google.golang.org/grpc@v1.23.0","value":16},{"id":96,"name":"golang.org/x/net@v0.0.0-20190213061140-3a22650c66bd","value":1},{"id":97,"name":"golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f","value":1},{"id":98,"name":"google.golang.org/appengine@v1.4.0","value":4},{"id":99,"name":"golang.org/x/net@v0.0.0-20180724234803-3673e40ba225","value":1},{"id":100,"name":"github.com/golang/protobuf@v1.4.0-rc.2","value":3},{"id":101,"name":"google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60","value":3},{"id":102,"name":"github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208","value":3},{"id":103,"name":"google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64","value":3},{"id":104,"name":"github.com/golang/protobuf@v1.4.0-rc.1","value":3},{"id":105,"name":"github.com/google/go-cmp@v0.3.1","value":1},{"id":106,"name":"google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd","value":2},{"id":107,"name":"github.com/google/go-cmp@v0.3.0","value":1}],"links":[{"source":0,"target":1,"weight":1,"width":1},{"source":0,"target":2,"weight":1,"width":1},{"source":0,"target":3,"weight":1,"width":1},{"source":0,"target":4,"weight":1,"width":1},{"source":0,"target":5,"weight":1,"width":1},{"source":0,"target":6,"weight":1,"width":1},{"source":0,"target":7,"weight":1,"width":1},{"source":0,"target":8,"weight":1,"width":1},{"source":0,"target":9,"weight":1,"width":1},{"source":0,"target":10,"weight":1,"width":1},{"source":0,"target":11,"weight":1,"width":1},{"source":0,"target":12,"weight":1,"width":1},{"source":5,"target":13,"weight":1,"width":1},{"source":1,"target":14,"weight":1,"width":1},{"source":1,"target":15,"weight":1,"width":1},{"source":1,"target":16,"weight":1,"width":1},{"source":1,"target":17,"weight":1,"width":1},{"source":1,"target":18,"weight":1,"width":1},{"source":1,"target":19,"weight":1,"width":1},{"source":1,"target":20,"weight":1,"width":1},{"source":1,"target":21,"weight":1,"width":1},{"source":19,"target":22,"weight":1,"width":1},{"source":19,"target":23,"weight":1,"width":1},{"source":19,"target":24,"weight":1,"width":1},{"source":19,"target":25,"weight":1,"width":1},{"source":20,"target":26,"weight":1,"width":1},{"source":13,"target":22,"weight":1,"width":1},{"source":13,"target":23,"weight":1,"width":1},{"source":13,"target":24,"weight":1,"width":1},{"source":13,"target":27,"weight":1,"width":1},{"source":9,"target":28,"weight":1,"width":1},{"source":9,"target":29,"weight":1,"width":1},{"source":9,"target":30,"weight":1,"width":1},{"source":11,"target":31,"weight":1,"width":1},{"source":11,"target":32,"weight":1,"width":1},{"source":11,"target":33,"weight":1,"width":1},{"source":31,"target":34,"weight":1,"width":1},{"source":31,"target":35,"weight":1,"width":1},{"source":8,"target":36,"weight":1,"width":1},{"source":21,"target":37,"weight":1,"width":1},{"source":14,"target":38,"weight":1,"width":1},{"source":4,"target":39,"weight":1,"width":1},{"source":4,"target":40,"weight":1,"width":1},{"source":4,"target":41,"weight":1,"width":1},{"source":4,"target":42,"weight":1,"width":1},{"source":4,"target":38,"weight":1,"width":1},{"source":3,"target":34,"weight":1,"width":1},{"source":3,"target":43,"weight":1,"width":1},{"source":28,"target":44,"weight":1,"width":1},{"source":28,"target":45,"weight":1,"width":1},{"source":27,"target":37,"weight":1,"width":1},{"source":17,"target":39,"weight":1,"width":1},{"source":17,"target":40,"weight":1,"width":1},{"source":17,"target":41,"weight":1,"width":1},{"source":17,"target":42,"weight":1,"width":1},{"source":17,"target":38,"weight":1,"width":1},{"source":38,"target":22,"weight":1,"width":1},{"source":38,"target":23,"weight":1,"width":1},{"source":38,"target":24,"weight":1,"width":1},{"source":32,"target":46,"weight":1,"width":1},{"source":34,"target":46,"weight":1,"width":1},{"source":26,"target":20,"weight":1,"width":1},{"source":12,"target":37,"weight":1,"width":1},{"source":18,"target":47,"weight":1,"width":1},{"source":2,"target":48,"weight":1,"width":1},{"source":2,"target":49,"weight":1,"width":1},{"source":2,"target":50,"weight":1,"width":1},{"source":2,"target":51,"weight":1,"width":1},{"source":2,"target":52,"weight":1,"width":1},{"source":51,"target":19,"weight":1,"width":1},{"source":52,"target":28,"weight":1,"width":1},{"source":52,"target":53,"weight":1,"width":1},{"source":15,"target":48,"weight":1,"width":1},{"source":15,"target":49,"weight":1,"width":1},{"source":15,"target":50,"weight":1,"width":1},{"source":15,"target":51,"weight":1,"width":1},{"source":50,"target":49,"weight":1,"width":1},{"source":43,"target":54,"weight":1,"width":1},{"source":43,"target":34,"weight":1,"width":1},{"source":36,"target":8,"weight":1,"width":1},{"source":54,"target":34,"weight":1,"width":1},{"source":54,"target":55,"weight":1,"width":1},{"source":33,"target":31,"weight":1,"width":1},{"source":33,"target":56,"weight":1,"width":1},{"source":33,"target":57,"weight":1,"width":1},{"source":33,"target":58,"weight":1,"width":1},{"source":33,"target":59,"weight":1,"width":1},{"source":33,"target":60,"weight":1,"width":1},{"source":55,"target":61,"weight":1,"width":1},{"source":55,"target":34,"weight":1,"width":1},{"source":56,"target":62,"weight":1,"width":1},{"source":30,"target":29,"weight":1,"width":1},{"source":49,"target":63,"weight":1,"width":1},{"source":63,"target":64,"weight":1,"width":1},{"source":44,"target":65,"weight":1,"width":1},{"source":61,"target":34,"weight":1,"width":1},{"source":61,"target":66,"weight":1,"width":1},{"source":57,"target":67,"weight":1,"width":1},{"source":57,"target":68,"weight":1,"width":1},{"source":62,"target":67,"weight":1,"width":1},{"source":59,"target":54,"weight":1,"width":1},{"source":59,"target":34,"weight":1,"width":1},{"source":25,"target":37,"weight":1,"width":1},{"source":58,"target":69,"weight":1,"width":1},{"source":58,"target":70,"weight":1,"width":1},{"source":58,"target":71,"weight":1,"width":1},{"source":58,"target":72,"weight":1,"width":1},{"source":58,"target":73,"weight":1,"width":1},{"source":58,"target":74,"weight":1,"width":1},{"source":58,"target":67,"weight":1,"width":1},{"source":58,"target":75,"weight":1,"width":1},{"source":58,"target":65,"weight":1,"width":1},{"source":58,"target":76,"weight":1,"width":1},{"source":76,"target":73,"weight":1,"width":1},{"source":76,"target":77,"weight":1,"width":1},{"source":76,"target":78,"weight":1,"width":1},{"source":76,"target":79,"weight":1,"width":1},{"source":76,"target":80,"weight":1,"width":1},{"source":76,"target":81,"weight":1,"width":1},{"source":80,"target":82,"weight":1,"width":1},{"source":80,"target":83,"weight":1,"width":1},{"source":80,"target":84,"weight":1,"width":1},{"source":80,"target":71,"weight":1,"width":1},{"source":80,"target":72,"weight":1,"width":1},{"source":80,"target":85,"weight":1,"width":1},{"source":80,"target":86,"weight":1,"width":1},{"source":80,"target":87,"weight":1,"width":1},{"source":80,"target":75,"weight":1,"width":1},{"source":80,"target":88,"weight":1,"width":1},{"source":80,"target":89,"weight":1,"width":1},{"source":80,"target":45,"weight":1,"width":1},{"source":80,"target":90,"weight":1,"width":1},{"source":80,"target":91,"weight":1,"width":1},{"source":80,"target":92,"weight":1,"width":1},{"source":80,"target":81,"weight":1,"width":1},{"source":67,"target":44,"weight":1,"width":1},{"source":67,"target":45,"weight":1,"width":1},{"source":69,"target":93,"weight":1,"width":1},{"source":69,"target":70,"weight":1,"width":1},{"source":69,"target":73,"weight":1,"width":1},{"source":69,"target":94,"weight":1,"width":1},{"source":69,"target":76,"weight":1,"width":1},{"source":69,"target":95,"weight":1,"width":1},{"source":79,"target":96,"weight":1,"width":1},{"source":79,"target":97,"weight":1,"width":1},{"source":79,"target":98,"weight":1,"width":1},{"source":98,"target":85,"weight":1,"width":1},{"source":98,"target":99,"weight":1,"width":1},{"source":98,"target":45,"weight":1,"width":1},{"source":66,"target":100,"weight":1,"width":1},{"source":66,"target":34,"weight":1,"width":1},{"source":35,"target":54,"weight":1,"width":1},{"source":35,"target":34,"weight":1,"width":1},{"source":100,"target":34,"weight":1,"width":1},{"source":100,"target":101,"weight":1,"width":1},{"source":101,"target":102,"weight":1,"width":1},{"source":101,"target":34,"weight":1,"width":1},{"source":94,"target":85,"weight":1,"width":1},{"source":94,"target":97,"weight":1,"width":1},{"source":78,"target":79,"weight":1,"width":1},{"source":102,"target":34,"weight":1,"width":1},{"source":102,"target":103,"weight":1,"width":1},{"source":95,"target":82,"weight":1,"width":1},{"source":95,"target":83,"weight":1,"width":1},{"source":95,"target":84,"weight":1,"width":1},{"source":95,"target":71,"weight":1,"width":1},{"source":95,"target":72,"weight":1,"width":1},{"source":95,"target":85,"weight":1,"width":1},{"source":95,"target":74,"weight":1,"width":1},{"source":95,"target":56,"weight":1,"width":1},{"source":95,"target":67,"weight":1,"width":1},{"source":95,"target":75,"weight":1,"width":1},{"source":95,"target":65,"weight":1,"width":1},{"source":95,"target":57,"weight":1,"width":1},{"source":95,"target":91,"weight":1,"width":1},{"source":95,"target":92,"weight":1,"width":1},{"source":95,"target":60,"weight":1,"width":1},{"source":103,"target":104,"weight":1,"width":1},{"source":103,"target":105,"weight":1,"width":1},{"source":104,"target":105,"weight":1,"width":1},{"source":104,"target":106,"weight":1,"width":1},{"source":106,"target":107,"weight":1,"width":1}],"num":108}}
--------------------------------------------------------------------------------
/gosrc/graphutil_test.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import "testing"
4 |
5 | func TestGraphToNodeLinks(t *testing.T) {
6 | var urlTests = []struct {
7 | expected bool // expected result
8 | in string // input
9 | }{
10 | {true, `go-mod-graph-charting github.com/gin-gonic/gin@v1.6.3
11 | go-mod-graph-charting github.com/go-playground/validator/v10@v10.4.1
12 | go-mod-graph-charting github.com/golang/protobuf@v1.4.3
13 | go-mod-graph-charting github.com/json-iterator/go@v1.1.10
14 | go-mod-graph-charting github.com/leodido/go-urn@v1.2.1
15 | go-mod-graph-charting github.com/modern-go/concurrent@v0.0.0-20180306012644-bacd9c7ef1dd
16 | go-mod-graph-charting github.com/modern-go/reflect2@v1.0.1
17 | go-mod-graph-charting github.com/ugorji/go@v1.2.2
18 | go-mod-graph-charting golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad
19 | go-mod-graph-charting golang.org/x/sys@v0.0.0-20201223074533-0d417f636930
20 | go-mod-graph-charting google.golang.org/protobuf@v1.25.0
21 | go-mod-graph-charting gopkg.in/yaml.v2@v2.4.0
22 | github.com/leodido/go-urn@v1.2.1 github.com/stretchr/testify@v1.6.1
23 | github.com/gin-gonic/gin@v1.6.3 github.com/gin-contrib/sse@v0.1.0
24 | github.com/gin-gonic/gin@v1.6.3 github.com/go-playground/validator/v10@v10.2.0
25 | github.com/gin-gonic/gin@v1.6.3 github.com/golang/protobuf@v1.3.3
26 | github.com/gin-gonic/gin@v1.6.3 github.com/json-iterator/go@v1.1.9
27 | github.com/gin-gonic/gin@v1.6.3 github.com/mattn/go-isatty@v0.0.12
28 | github.com/gin-gonic/gin@v1.6.3 github.com/stretchr/testify@v1.4.0
29 | github.com/gin-gonic/gin@v1.6.3 github.com/ugorji/go/codec@v1.1.7
30 | github.com/gin-gonic/gin@v1.6.3 gopkg.in/yaml.v2@v2.2.8
31 | github.com/stretchr/testify@v1.4.0 github.com/davecgh/go-spew@v1.1.0
32 | github.com/stretchr/testify@v1.4.0 github.com/pmezard/go-difflib@v1.0.0
33 | github.com/stretchr/testify@v1.4.0 github.com/stretchr/objx@v0.1.0
34 | github.com/stretchr/testify@v1.4.0 gopkg.in/yaml.v2@v2.2.2
35 | github.com/ugorji/go/codec@v1.1.7 github.com/ugorji/go@v1.1.7
36 | github.com/stretchr/testify@v1.6.1 github.com/davecgh/go-spew@v1.1.0
37 | github.com/stretchr/testify@v1.6.1 github.com/pmezard/go-difflib@v1.0.0
38 | github.com/stretchr/testify@v1.6.1 github.com/stretchr/objx@v0.1.0
39 | github.com/stretchr/testify@v1.6.1 gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c
40 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3
41 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037
42 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221
43 | google.golang.org/protobuf@v1.25.0 github.com/golang/protobuf@v1.4.1
44 | google.golang.org/protobuf@v1.25.0 github.com/google/go-cmp@v0.5.0
45 | google.golang.org/protobuf@v1.25.0 google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013
46 | github.com/golang/protobuf@v1.4.1 github.com/google/go-cmp@v0.4.0
47 | github.com/golang/protobuf@v1.4.1 google.golang.org/protobuf@v1.22.0
48 | github.com/ugorji/go@v1.2.2 github.com/ugorji/go/codec@v1.2.2
49 | gopkg.in/yaml.v2@v2.2.8 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
50 | github.com/gin-contrib/sse@v0.1.0 github.com/stretchr/testify@v1.3.0
51 | github.com/json-iterator/go@v1.1.10 github.com/davecgh/go-spew@v1.1.1
52 | github.com/json-iterator/go@v1.1.10 github.com/google/gofuzz@v1.0.0
53 | github.com/json-iterator/go@v1.1.10 github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421
54 | github.com/json-iterator/go@v1.1.10 github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742
55 | github.com/json-iterator/go@v1.1.10 github.com/stretchr/testify@v1.3.0
56 | github.com/golang/protobuf@v1.4.3 github.com/google/go-cmp@v0.4.0
57 | github.com/golang/protobuf@v1.4.3 google.golang.org/protobuf@v1.23.0
58 | golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2
59 | golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/text@v0.3.0
60 | gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
61 | github.com/json-iterator/go@v1.1.9 github.com/davecgh/go-spew@v1.1.1
62 | github.com/json-iterator/go@v1.1.9 github.com/google/gofuzz@v1.0.0
63 | github.com/json-iterator/go@v1.1.9 github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421
64 | github.com/json-iterator/go@v1.1.9 github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742
65 | github.com/json-iterator/go@v1.1.9 github.com/stretchr/testify@v1.3.0
66 | github.com/stretchr/testify@v1.3.0 github.com/davecgh/go-spew@v1.1.0
67 | github.com/stretchr/testify@v1.3.0 github.com/pmezard/go-difflib@v1.0.0
68 | github.com/stretchr/testify@v1.3.0 github.com/stretchr/objx@v0.1.0
69 | github.com/google/go-cmp@v0.5.0 golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
70 | github.com/google/go-cmp@v0.4.0 golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
71 | github.com/ugorji/go@v1.1.7 github.com/ugorji/go/codec@v1.1.7
72 | gopkg.in/yaml.v2@v2.4.0 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
73 | github.com/mattn/go-isatty@v0.0.12 golang.org/x/sys@v0.0.0-20200116001909-b77594299b42
74 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/assert/v2@v2.0.1
75 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/locales@v0.13.0
76 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/universal-translator@v0.17.0
77 | github.com/go-playground/validator/v10@v10.4.1 github.com/leodido/go-urn@v1.2.0
78 | github.com/go-playground/validator/v10@v10.4.1 golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9
79 | github.com/leodido/go-urn@v1.2.0 github.com/stretchr/testify@v1.4.0
80 | golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9 golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3
81 | golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9 golang.org/x/sys@v0.0.0-20190412213103-97732733099d
82 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/assert/v2@v2.0.1
83 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/locales@v0.13.0
84 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/universal-translator@v0.17.0
85 | github.com/go-playground/validator/v10@v10.2.0 github.com/leodido/go-urn@v1.2.0
86 | github.com/go-playground/universal-translator@v0.17.0 github.com/go-playground/locales@v0.13.0
87 | google.golang.org/protobuf@v1.23.0 github.com/golang/protobuf@v1.4.0
88 | google.golang.org/protobuf@v1.23.0 github.com/google/go-cmp@v0.4.0
89 | github.com/ugorji/go/codec@v1.2.2 github.com/ugorji/go@v1.2.2
90 | github.com/golang/protobuf@v1.4.0 github.com/google/go-cmp@v0.4.0
91 | github.com/golang/protobuf@v1.4.0 google.golang.org/protobuf@v1.21.0
92 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 github.com/golang/protobuf@v1.4.1
93 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3
94 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135
95 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/grpc@v1.27.0
96 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc
97 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc
98 | google.golang.org/protobuf@v1.21.0 github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0
99 | google.golang.org/protobuf@v1.21.0 github.com/google/go-cmp@v0.4.0
100 | golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3 golang.org/x/tools@v0.0.0-20190311212946-11955173bddd
101 | golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221 golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037
102 | github.com/go-playground/locales@v0.13.0 golang.org/x/text@v0.3.2
103 | golang.org/x/text@v0.3.2 golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e
104 | golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
105 | github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0 github.com/google/go-cmp@v0.4.0
106 | github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0 google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967
107 | golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
108 | golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135 golang.org/x/sync@v0.0.0-20190423024810-112230192c58
109 | golang.org/x/tools@v0.0.0-20190311212946-11955173bddd golang.org/x/net@v0.0.0-20190311183353-d8887717615a
110 | google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc github.com/golang/protobuf@v1.4.0
111 | google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc github.com/google/go-cmp@v0.4.0
112 | gopkg.in/yaml.v2@v2.2.2 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
113 | google.golang.org/grpc@v1.27.0 github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473
114 | google.golang.org/grpc@v1.27.0 github.com/envoyproxy/protoc-gen-validate@v0.1.0
115 | google.golang.org/grpc@v1.27.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
116 | google.golang.org/grpc@v1.27.0 github.com/golang/mock@v1.1.1
117 | google.golang.org/grpc@v1.27.0 github.com/golang/protobuf@v1.3.2
118 | google.golang.org/grpc@v1.27.0 github.com/google/go-cmp@v0.2.0
119 | google.golang.org/grpc@v1.27.0 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
120 | google.golang.org/grpc@v1.27.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
121 | google.golang.org/grpc@v1.27.0 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
122 | google.golang.org/grpc@v1.27.0 google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55
123 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 github.com/golang/protobuf@v1.3.2
124 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/exp@v0.0.0-20190121172915-509febef88a4
125 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961
126 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/tools@v0.0.0-20190226205152-f727befe758c
127 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 google.golang.org/grpc@v1.19.0
128 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099
129 | google.golang.org/grpc@v1.19.0 cloud.google.com/go@v0.26.0
130 | google.golang.org/grpc@v1.19.0 github.com/BurntSushi/toml@v0.3.1
131 | google.golang.org/grpc@v1.19.0 github.com/client9/misspell@v0.3.4
132 | google.golang.org/grpc@v1.19.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
133 | google.golang.org/grpc@v1.19.0 github.com/golang/mock@v1.1.1
134 | google.golang.org/grpc@v1.19.0 github.com/golang/protobuf@v1.2.0
135 | google.golang.org/grpc@v1.19.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
136 | google.golang.org/grpc@v1.19.0 golang.org/x/net@v0.0.0-20180826012351-8a410e7b638d
137 | google.golang.org/grpc@v1.19.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
138 | google.golang.org/grpc@v1.19.0 golang.org/x/sync@v0.0.0-20180314180146-1d60e4601c6f
139 | google.golang.org/grpc@v1.19.0 golang.org/x/sys@v0.0.0-20180830151530-49385e6e1522
140 | google.golang.org/grpc@v1.19.0 golang.org/x/text@v0.3.0
141 | google.golang.org/grpc@v1.19.0 golang.org/x/tools@v0.0.0-20190114222345-bf090417da8b
142 | google.golang.org/grpc@v1.19.0 google.golang.org/appengine@v1.1.0
143 | google.golang.org/grpc@v1.19.0 google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8
144 | google.golang.org/grpc@v1.19.0 honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099
145 | golang.org/x/net@v0.0.0-20190311183353-d8887717615a golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2
146 | golang.org/x/net@v0.0.0-20190311183353-d8887717615a golang.org/x/text@v0.3.0
147 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/census-instrumentation/opencensus-proto@v0.2.1
148 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/envoyproxy/protoc-gen-validate@v0.1.0
149 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/golang/protobuf@v1.3.2
150 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4
151 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55
152 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 google.golang.org/grpc@v1.23.0
153 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c golang.org/x/net@v0.0.0-20190213061140-3a22650c66bd
154 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f
155 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c google.golang.org/appengine@v1.4.0
156 | google.golang.org/appengine@v1.4.0 github.com/golang/protobuf@v1.2.0
157 | google.golang.org/appengine@v1.4.0 golang.org/x/net@v0.0.0-20180724234803-3673e40ba225
158 | google.golang.org/appengine@v1.4.0 golang.org/x/text@v0.3.0
159 | google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967 github.com/golang/protobuf@v1.4.0-rc.2
160 | google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967 github.com/google/go-cmp@v0.4.0
161 | google.golang.org/protobuf@v1.22.0 github.com/golang/protobuf@v1.4.0
162 | google.golang.org/protobuf@v1.22.0 github.com/google/go-cmp@v0.4.0
163 | github.com/golang/protobuf@v1.4.0-rc.2 github.com/google/go-cmp@v0.4.0
164 | github.com/golang/protobuf@v1.4.0-rc.2 google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60
165 | google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60 github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208
166 | google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60 github.com/google/go-cmp@v0.4.0
167 | github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4 github.com/golang/protobuf@v1.2.0
168 | github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4 golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f
169 | golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961 golang.org/x/tools@v0.0.0-20190226205152-f727befe758c
170 | github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208 github.com/google/go-cmp@v0.4.0
171 | github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208 google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64
172 | google.golang.org/grpc@v1.23.0 cloud.google.com/go@v0.26.0
173 | google.golang.org/grpc@v1.23.0 github.com/BurntSushi/toml@v0.3.1
174 | google.golang.org/grpc@v1.23.0 github.com/client9/misspell@v0.3.4
175 | google.golang.org/grpc@v1.23.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
176 | google.golang.org/grpc@v1.23.0 github.com/golang/mock@v1.1.1
177 | google.golang.org/grpc@v1.23.0 github.com/golang/protobuf@v1.2.0
178 | google.golang.org/grpc@v1.23.0 github.com/google/go-cmp@v0.2.0
179 | google.golang.org/grpc@v1.23.0 golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3
180 | google.golang.org/grpc@v1.23.0 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
181 | google.golang.org/grpc@v1.23.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
182 | google.golang.org/grpc@v1.23.0 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
183 | google.golang.org/grpc@v1.23.0 golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135
184 | google.golang.org/grpc@v1.23.0 google.golang.org/appengine@v1.1.0
185 | google.golang.org/grpc@v1.23.0 google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8
186 | google.golang.org/grpc@v1.23.0 honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc
187 | google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64 github.com/golang/protobuf@v1.4.0-rc.1
188 | google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64 github.com/google/go-cmp@v0.3.1
189 | github.com/golang/protobuf@v1.4.0-rc.1 github.com/google/go-cmp@v0.3.1
190 | github.com/golang/protobuf@v1.4.0-rc.1 google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd
191 | google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd github.com/google/go-cmp@v0.3.0`},
192 | }
193 |
194 | for _, tt := range urlTests {
195 | actual1, actual2 := GraphToNodeLinks(tt.in)
196 | if (nil != actual1 && nil != actual2) != tt.expected {
197 | t.Errorf("GraphToNodeLinks(%s) = %v, %v; expected %t", tt.in, actual1, actual2, tt.expected)
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/gosrc/treeutil_test.go:
--------------------------------------------------------------------------------
1 | package gosrc
2 |
3 | import (
4 | "encoding/json"
5 | "testing"
6 | )
7 |
8 | func TestBuildTree(t *testing.T) {
9 | var urlTests = []struct {
10 | expected bool // expected result
11 | in string // input
12 | }{
13 | {true, `go-mod-graph-charting github.com/gin-gonic/gin@v1.6.3
14 | go-mod-graph-charting github.com/go-playground/validator/v10@v10.4.1
15 | go-mod-graph-charting github.com/golang/protobuf@v1.4.3
16 | go-mod-graph-charting github.com/json-iterator/go@v1.1.10
17 | go-mod-graph-charting github.com/leodido/go-urn@v1.2.1
18 | go-mod-graph-charting github.com/modern-go/concurrent@v0.0.0-20180306012644-bacd9c7ef1dd
19 | go-mod-graph-charting github.com/modern-go/reflect2@v1.0.1
20 | go-mod-graph-charting github.com/ugorji/go@v1.2.2
21 | go-mod-graph-charting golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad
22 | go-mod-graph-charting golang.org/x/sys@v0.0.0-20201223074533-0d417f636930
23 | go-mod-graph-charting google.golang.org/protobuf@v1.25.0
24 | go-mod-graph-charting gopkg.in/yaml.v2@v2.4.0
25 | github.com/leodido/go-urn@v1.2.1 github.com/stretchr/testify@v1.6.1
26 | github.com/gin-gonic/gin@v1.6.3 github.com/gin-contrib/sse@v0.1.0
27 | github.com/gin-gonic/gin@v1.6.3 github.com/go-playground/validator/v10@v10.2.0
28 | github.com/gin-gonic/gin@v1.6.3 github.com/golang/protobuf@v1.3.3
29 | github.com/gin-gonic/gin@v1.6.3 github.com/json-iterator/go@v1.1.9
30 | github.com/gin-gonic/gin@v1.6.3 github.com/mattn/go-isatty@v0.0.12
31 | github.com/gin-gonic/gin@v1.6.3 github.com/stretchr/testify@v1.4.0
32 | github.com/gin-gonic/gin@v1.6.3 github.com/ugorji/go/codec@v1.1.7
33 | github.com/gin-gonic/gin@v1.6.3 gopkg.in/yaml.v2@v2.2.8
34 | github.com/stretchr/testify@v1.4.0 github.com/davecgh/go-spew@v1.1.0
35 | github.com/stretchr/testify@v1.4.0 github.com/pmezard/go-difflib@v1.0.0
36 | github.com/stretchr/testify@v1.4.0 github.com/stretchr/objx@v0.1.0
37 | github.com/stretchr/testify@v1.4.0 gopkg.in/yaml.v2@v2.2.2
38 | github.com/ugorji/go/codec@v1.1.7 github.com/ugorji/go@v1.1.7
39 | github.com/stretchr/testify@v1.6.1 github.com/davecgh/go-spew@v1.1.0
40 | github.com/stretchr/testify@v1.6.1 github.com/pmezard/go-difflib@v1.0.0
41 | github.com/stretchr/testify@v1.6.1 github.com/stretchr/objx@v0.1.0
42 | github.com/stretchr/testify@v1.6.1 gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c
43 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3
44 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037
45 | golang.org/x/crypto@v0.0.0-20201221181555-eec23a3978ad golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221
46 | google.golang.org/protobuf@v1.25.0 github.com/golang/protobuf@v1.4.1
47 | google.golang.org/protobuf@v1.25.0 github.com/google/go-cmp@v0.5.0
48 | google.golang.org/protobuf@v1.25.0 google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013
49 | github.com/golang/protobuf@v1.4.1 github.com/google/go-cmp@v0.4.0
50 | github.com/golang/protobuf@v1.4.1 google.golang.org/protobuf@v1.22.0
51 | github.com/ugorji/go@v1.2.2 github.com/ugorji/go/codec@v1.2.2
52 | gopkg.in/yaml.v2@v2.2.8 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
53 | github.com/gin-contrib/sse@v0.1.0 github.com/stretchr/testify@v1.3.0
54 | github.com/json-iterator/go@v1.1.10 github.com/davecgh/go-spew@v1.1.1
55 | github.com/json-iterator/go@v1.1.10 github.com/google/gofuzz@v1.0.0
56 | github.com/json-iterator/go@v1.1.10 github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421
57 | github.com/json-iterator/go@v1.1.10 github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742
58 | github.com/json-iterator/go@v1.1.10 github.com/stretchr/testify@v1.3.0
59 | github.com/golang/protobuf@v1.4.3 github.com/google/go-cmp@v0.4.0
60 | github.com/golang/protobuf@v1.4.3 google.golang.org/protobuf@v1.23.0
61 | golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2
62 | golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/text@v0.3.0
63 | gopkg.in/yaml.v3@v3.0.0-20200313102051-9f266ea9e77c gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
64 | github.com/json-iterator/go@v1.1.9 github.com/davecgh/go-spew@v1.1.1
65 | github.com/json-iterator/go@v1.1.9 github.com/google/gofuzz@v1.0.0
66 | github.com/json-iterator/go@v1.1.9 github.com/modern-go/concurrent@v0.0.0-20180228061459-e0a39a4cb421
67 | github.com/json-iterator/go@v1.1.9 github.com/modern-go/reflect2@v0.0.0-20180701023420-4b7aa43c6742
68 | github.com/json-iterator/go@v1.1.9 github.com/stretchr/testify@v1.3.0
69 | github.com/stretchr/testify@v1.3.0 github.com/davecgh/go-spew@v1.1.0
70 | github.com/stretchr/testify@v1.3.0 github.com/pmezard/go-difflib@v1.0.0
71 | github.com/stretchr/testify@v1.3.0 github.com/stretchr/objx@v0.1.0
72 | github.com/google/go-cmp@v0.5.0 golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
73 | github.com/google/go-cmp@v0.4.0 golang.org/x/xerrors@v0.0.0-20191204190536-9bdfabe68543
74 | github.com/ugorji/go@v1.1.7 github.com/ugorji/go/codec@v1.1.7
75 | gopkg.in/yaml.v2@v2.4.0 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
76 | github.com/mattn/go-isatty@v0.0.12 golang.org/x/sys@v0.0.0-20200116001909-b77594299b42
77 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/assert/v2@v2.0.1
78 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/locales@v0.13.0
79 | github.com/go-playground/validator/v10@v10.4.1 github.com/go-playground/universal-translator@v0.17.0
80 | github.com/go-playground/validator/v10@v10.4.1 github.com/leodido/go-urn@v1.2.0
81 | github.com/go-playground/validator/v10@v10.4.1 golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9
82 | github.com/leodido/go-urn@v1.2.0 github.com/stretchr/testify@v1.4.0
83 | golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9 golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3
84 | golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9 golang.org/x/sys@v0.0.0-20190412213103-97732733099d
85 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/assert/v2@v2.0.1
86 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/locales@v0.13.0
87 | github.com/go-playground/validator/v10@v10.2.0 github.com/go-playground/universal-translator@v0.17.0
88 | github.com/go-playground/validator/v10@v10.2.0 github.com/leodido/go-urn@v1.2.0
89 | github.com/go-playground/universal-translator@v0.17.0 github.com/go-playground/locales@v0.13.0
90 | google.golang.org/protobuf@v1.23.0 github.com/golang/protobuf@v1.4.0
91 | google.golang.org/protobuf@v1.23.0 github.com/google/go-cmp@v0.4.0
92 | github.com/ugorji/go/codec@v1.2.2 github.com/ugorji/go@v1.2.2
93 | github.com/golang/protobuf@v1.4.0 github.com/google/go-cmp@v0.4.0
94 | github.com/golang/protobuf@v1.4.0 google.golang.org/protobuf@v1.21.0
95 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 github.com/golang/protobuf@v1.4.1
96 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3
97 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135
98 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/grpc@v1.27.0
99 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc
100 | google.golang.org/genproto@v0.0.0-20200526211855-cb27e3aa2013 honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc
101 | google.golang.org/protobuf@v1.21.0 github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0
102 | google.golang.org/protobuf@v1.21.0 github.com/google/go-cmp@v0.4.0
103 | golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3 golang.org/x/tools@v0.0.0-20190311212946-11955173bddd
104 | golang.org/x/term@v0.0.0-20201117132131-f5c789dd3221 golang.org/x/sys@v0.0.0-20191026070338-33540a1f6037
105 | github.com/go-playground/locales@v0.13.0 golang.org/x/text@v0.3.2
106 | golang.org/x/text@v0.3.2 golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e
107 | golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
108 | github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0 github.com/google/go-cmp@v0.4.0
109 | github.com/golang/protobuf@v1.4.0-rc.4.0.20200313231945-b860323f09d0 google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967
110 | golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
111 | golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135 golang.org/x/sync@v0.0.0-20190423024810-112230192c58
112 | golang.org/x/tools@v0.0.0-20190311212946-11955173bddd golang.org/x/net@v0.0.0-20190311183353-d8887717615a
113 | google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc github.com/golang/protobuf@v1.4.0
114 | google.golang.org/protobuf@v1.23.1-0.20200526195155-81db48ad09cc github.com/google/go-cmp@v0.4.0
115 | gopkg.in/yaml.v2@v2.2.2 gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405
116 | google.golang.org/grpc@v1.27.0 github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473
117 | google.golang.org/grpc@v1.27.0 github.com/envoyproxy/protoc-gen-validate@v0.1.0
118 | google.golang.org/grpc@v1.27.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
119 | google.golang.org/grpc@v1.27.0 github.com/golang/mock@v1.1.1
120 | google.golang.org/grpc@v1.27.0 github.com/golang/protobuf@v1.3.2
121 | google.golang.org/grpc@v1.27.0 github.com/google/go-cmp@v0.2.0
122 | google.golang.org/grpc@v1.27.0 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
123 | google.golang.org/grpc@v1.27.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
124 | google.golang.org/grpc@v1.27.0 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
125 | google.golang.org/grpc@v1.27.0 google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55
126 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 github.com/golang/protobuf@v1.3.2
127 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/exp@v0.0.0-20190121172915-509febef88a4
128 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961
129 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 golang.org/x/tools@v0.0.0-20190226205152-f727befe758c
130 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 google.golang.org/grpc@v1.19.0
131 | google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55 honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099
132 | google.golang.org/grpc@v1.19.0 cloud.google.com/go@v0.26.0
133 | google.golang.org/grpc@v1.19.0 github.com/BurntSushi/toml@v0.3.1
134 | google.golang.org/grpc@v1.19.0 github.com/client9/misspell@v0.3.4
135 | google.golang.org/grpc@v1.19.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
136 | google.golang.org/grpc@v1.19.0 github.com/golang/mock@v1.1.1
137 | google.golang.org/grpc@v1.19.0 github.com/golang/protobuf@v1.2.0
138 | google.golang.org/grpc@v1.19.0 golang.org/x/lint@v0.0.0-20181026193005-c67002cb31c3
139 | google.golang.org/grpc@v1.19.0 golang.org/x/net@v0.0.0-20180826012351-8a410e7b638d
140 | google.golang.org/grpc@v1.19.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
141 | google.golang.org/grpc@v1.19.0 golang.org/x/sync@v0.0.0-20180314180146-1d60e4601c6f
142 | google.golang.org/grpc@v1.19.0 golang.org/x/sys@v0.0.0-20180830151530-49385e6e1522
143 | google.golang.org/grpc@v1.19.0 golang.org/x/text@v0.3.0
144 | google.golang.org/grpc@v1.19.0 golang.org/x/tools@v0.0.0-20190114222345-bf090417da8b
145 | google.golang.org/grpc@v1.19.0 google.golang.org/appengine@v1.1.0
146 | google.golang.org/grpc@v1.19.0 google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8
147 | google.golang.org/grpc@v1.19.0 honnef.co/go/tools@v0.0.0-20190102054323-c2f93a96b099
148 | golang.org/x/net@v0.0.0-20190311183353-d8887717615a golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2
149 | golang.org/x/net@v0.0.0-20190311183353-d8887717615a golang.org/x/text@v0.3.0
150 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/census-instrumentation/opencensus-proto@v0.2.1
151 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/envoyproxy/protoc-gen-validate@v0.1.0
152 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/golang/protobuf@v1.3.2
153 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4
154 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 google.golang.org/genproto@v0.0.0-20190819201941-24fa4b261c55
155 | github.com/envoyproxy/go-control-plane@v0.9.1-0.20191026205805-5f8ba28d4473 google.golang.org/grpc@v1.23.0
156 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c golang.org/x/net@v0.0.0-20190213061140-3a22650c66bd
157 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f
158 | golang.org/x/tools@v0.0.0-20190226205152-f727befe758c google.golang.org/appengine@v1.4.0
159 | google.golang.org/appengine@v1.4.0 github.com/golang/protobuf@v1.2.0
160 | google.golang.org/appengine@v1.4.0 golang.org/x/net@v0.0.0-20180724234803-3673e40ba225
161 | google.golang.org/appengine@v1.4.0 golang.org/x/text@v0.3.0
162 | google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967 github.com/golang/protobuf@v1.4.0-rc.2
163 | google.golang.org/protobuf@v1.20.1-0.20200309200217-e05f789c0967 github.com/google/go-cmp@v0.4.0
164 | google.golang.org/protobuf@v1.22.0 github.com/golang/protobuf@v1.4.0
165 | google.golang.org/protobuf@v1.22.0 github.com/google/go-cmp@v0.4.0
166 | github.com/golang/protobuf@v1.4.0-rc.2 github.com/google/go-cmp@v0.4.0
167 | github.com/golang/protobuf@v1.4.0-rc.2 google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60
168 | google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60 github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208
169 | google.golang.org/protobuf@v0.0.0-20200228230310-ab0ca4ff8a60 github.com/google/go-cmp@v0.4.0
170 | github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4 github.com/golang/protobuf@v1.2.0
171 | github.com/prometheus/client_model@v0.0.0-20190812154241-14fe0d1b01d4 golang.org/x/sync@v0.0.0-20181108010431-42b317875d0f
172 | golang.org/x/lint@v0.0.0-20190227174305-5b3e6a55c961 golang.org/x/tools@v0.0.0-20190226205152-f727befe758c
173 | github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208 github.com/google/go-cmp@v0.4.0
174 | github.com/golang/protobuf@v1.4.0-rc.1.0.20200221234624-67d41d38c208 google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64
175 | google.golang.org/grpc@v1.23.0 cloud.google.com/go@v0.26.0
176 | google.golang.org/grpc@v1.23.0 github.com/BurntSushi/toml@v0.3.1
177 | google.golang.org/grpc@v1.23.0 github.com/client9/misspell@v0.3.4
178 | google.golang.org/grpc@v1.23.0 github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b
179 | google.golang.org/grpc@v1.23.0 github.com/golang/mock@v1.1.1
180 | google.golang.org/grpc@v1.23.0 github.com/golang/protobuf@v1.2.0
181 | google.golang.org/grpc@v1.23.0 github.com/google/go-cmp@v0.2.0
182 | google.golang.org/grpc@v1.23.0 golang.org/x/lint@v0.0.0-20190313153728-d0100b6bd8b3
183 | google.golang.org/grpc@v1.23.0 golang.org/x/net@v0.0.0-20190311183353-d8887717615a
184 | google.golang.org/grpc@v1.23.0 golang.org/x/oauth2@v0.0.0-20180821212333-d2e6202438be
185 | google.golang.org/grpc@v1.23.0 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
186 | google.golang.org/grpc@v1.23.0 golang.org/x/tools@v0.0.0-20190524140312-2c0ae7006135
187 | google.golang.org/grpc@v1.23.0 google.golang.org/appengine@v1.1.0
188 | google.golang.org/grpc@v1.23.0 google.golang.org/genproto@v0.0.0-20180817151627-c66870c02cf8
189 | google.golang.org/grpc@v1.23.0 honnef.co/go/tools@v0.0.0-20190523083050-ea95bdfd59fc
190 | google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64 github.com/golang/protobuf@v1.4.0-rc.1
191 | google.golang.org/protobuf@v0.0.0-20200221191635-4d8936d0db64 github.com/google/go-cmp@v0.3.1
192 | github.com/golang/protobuf@v1.4.0-rc.1 github.com/google/go-cmp@v0.3.1
193 | github.com/golang/protobuf@v1.4.0-rc.1 google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd
194 | google.golang.org/protobuf@v0.0.0-20200109180630-ec00e32a8dfd github.com/google/go-cmp@v0.3.0`},
195 | }
196 |
197 | for _, tt := range urlTests {
198 | actual, _, _, actual2 := BuildTree(tt.in)
199 | if (nil != actual) != tt.expected {
200 | t.Errorf("BuildTree(%s) = %v, %v, expected %t", tt.in, actual, actual2, tt.expected)
201 | } else {
202 | v1, _ :=json.Marshal(actual)
203 | v2, _ :=json.Marshal(actual2)
204 | t.Logf("tree: %s\n an-tree: %s\n", v1, v2)
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------