@anxin233/gitviz 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +239 -20
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -11470,12 +11470,46 @@ var GitParser = class {
|
|
|
11470
11470
|
return false;
|
|
11471
11471
|
}
|
|
11472
11472
|
}
|
|
11473
|
-
async
|
|
11474
|
-
|
|
11473
|
+
async getBranches() {
|
|
11474
|
+
try {
|
|
11475
|
+
const branchSummary = await this.git.branch(["-a"]);
|
|
11476
|
+
const branches = [];
|
|
11477
|
+
const seenBranches = /* @__PURE__ */ new Set();
|
|
11478
|
+
for (const branchName of branchSummary.all) {
|
|
11479
|
+
if (branchName.includes("remotes/origin/HEAD"))
|
|
11480
|
+
continue;
|
|
11481
|
+
const cleanName = branchName.replace("remotes/origin/", "").replace(/^\*\s*/, "");
|
|
11482
|
+
if (seenBranches.has(cleanName))
|
|
11483
|
+
continue;
|
|
11484
|
+
seenBranches.add(cleanName);
|
|
11485
|
+
try {
|
|
11486
|
+
const log = await this.git.log({ maxCount: 1, [branchName]: null });
|
|
11487
|
+
if (log.latest) {
|
|
11488
|
+
const commitCount = await this.git.raw(["rev-list", "--count", branchName]);
|
|
11489
|
+
branches.push({
|
|
11490
|
+
name: cleanName,
|
|
11491
|
+
commits: parseInt(commitCount.trim()),
|
|
11492
|
+
lastCommit: new Date(log.latest.date)
|
|
11493
|
+
});
|
|
11494
|
+
}
|
|
11495
|
+
} catch {
|
|
11496
|
+
}
|
|
11497
|
+
}
|
|
11498
|
+
return branches;
|
|
11499
|
+
} catch {
|
|
11500
|
+
return [];
|
|
11501
|
+
}
|
|
11502
|
+
}
|
|
11503
|
+
async parseCommits(limit = 1e3, branch) {
|
|
11504
|
+
const logOptions = {
|
|
11475
11505
|
maxCount: limit,
|
|
11476
11506
|
"--numstat": null,
|
|
11477
11507
|
"--pretty": "format:%H|%an|%ae|%ai|%s"
|
|
11478
|
-
}
|
|
11508
|
+
};
|
|
11509
|
+
if (branch) {
|
|
11510
|
+
logOptions[branch] = null;
|
|
11511
|
+
}
|
|
11512
|
+
const log = await this.git.log(logOptions);
|
|
11479
11513
|
const commits = [];
|
|
11480
11514
|
for (const commit of log.all) {
|
|
11481
11515
|
let diffSummary;
|
|
@@ -11501,7 +11535,8 @@ var GitParser = class {
|
|
|
11501
11535
|
message: commit.message,
|
|
11502
11536
|
files: diffSummary.files.map((f) => f.file),
|
|
11503
11537
|
insertions: diffSummary.insertions,
|
|
11504
|
-
deletions: diffSummary.deletions
|
|
11538
|
+
deletions: diffSummary.deletions,
|
|
11539
|
+
branch
|
|
11505
11540
|
});
|
|
11506
11541
|
}
|
|
11507
11542
|
return commits;
|
|
@@ -11575,7 +11610,8 @@ var Analyzer = class {
|
|
|
11575
11610
|
return {
|
|
11576
11611
|
timeline: this.generateTimelineData(analysis.commits),
|
|
11577
11612
|
contributors: this.generateContributorData(analysis.contributors),
|
|
11578
|
-
heatmap: this.generateHeatmapData(analysis.files)
|
|
11613
|
+
heatmap: this.generateHeatmapData(analysis.files),
|
|
11614
|
+
branches: this.generateBranchData(analysis.branches || [])
|
|
11579
11615
|
};
|
|
11580
11616
|
}
|
|
11581
11617
|
generateTimelineData(commits) {
|
|
@@ -11611,6 +11647,13 @@ var Analyzer = class {
|
|
|
11611
11647
|
heat: f.changes / maxChanges
|
|
11612
11648
|
})).sort((a, b) => b.changes - a.changes).slice(0, 50);
|
|
11613
11649
|
}
|
|
11650
|
+
generateBranchData(branches) {
|
|
11651
|
+
return branches.map((b) => ({
|
|
11652
|
+
name: b.name,
|
|
11653
|
+
commits: b.commits,
|
|
11654
|
+
lastCommit: b.lastCommit.toISOString().split("T")[0]
|
|
11655
|
+
})).sort((a, b) => b.commits - a.commits);
|
|
11656
|
+
}
|
|
11614
11657
|
};
|
|
11615
11658
|
|
|
11616
11659
|
// src/visualizers/html-generator.ts
|
|
@@ -11638,6 +11681,12 @@ function generateHTML(data, repoName) {
|
|
|
11638
11681
|
padding: 3rem;
|
|
11639
11682
|
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
11640
11683
|
}
|
|
11684
|
+
.header {
|
|
11685
|
+
display: flex;
|
|
11686
|
+
justify-content: space-between;
|
|
11687
|
+
align-items: center;
|
|
11688
|
+
margin-bottom: 2rem;
|
|
11689
|
+
}
|
|
11641
11690
|
h1 {
|
|
11642
11691
|
font-size: 3rem;
|
|
11643
11692
|
margin-bottom: 0.5rem;
|
|
@@ -11649,7 +11698,33 @@ function generateHTML(data, repoName) {
|
|
|
11649
11698
|
.subtitle {
|
|
11650
11699
|
color: #666;
|
|
11651
11700
|
font-size: 1.2rem;
|
|
11652
|
-
margin-bottom:
|
|
11701
|
+
margin-bottom: 1rem;
|
|
11702
|
+
}
|
|
11703
|
+
.controls {
|
|
11704
|
+
display: flex;
|
|
11705
|
+
gap: 1rem;
|
|
11706
|
+
align-items: center;
|
|
11707
|
+
}
|
|
11708
|
+
.lang-switch {
|
|
11709
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
11710
|
+
color: white;
|
|
11711
|
+
border: none;
|
|
11712
|
+
padding: 0.5rem 1.5rem;
|
|
11713
|
+
border-radius: 8px;
|
|
11714
|
+
cursor: pointer;
|
|
11715
|
+
font-size: 1rem;
|
|
11716
|
+
transition: transform 0.2s;
|
|
11717
|
+
}
|
|
11718
|
+
.lang-switch:hover {
|
|
11719
|
+
transform: translateY(-2px);
|
|
11720
|
+
}
|
|
11721
|
+
.branch-selector {
|
|
11722
|
+
padding: 0.5rem 1rem;
|
|
11723
|
+
border: 2px solid #667eea;
|
|
11724
|
+
border-radius: 8px;
|
|
11725
|
+
font-size: 1rem;
|
|
11726
|
+
cursor: pointer;
|
|
11727
|
+
background: white;
|
|
11653
11728
|
}
|
|
11654
11729
|
.section {
|
|
11655
11730
|
margin-bottom: 4rem;
|
|
@@ -11678,6 +11753,7 @@ function generateHTML(data, repoName) {
|
|
|
11678
11753
|
pointer-events: none;
|
|
11679
11754
|
opacity: 0;
|
|
11680
11755
|
transition: opacity 0.3s;
|
|
11756
|
+
z-index: 1000;
|
|
11681
11757
|
}
|
|
11682
11758
|
.stats {
|
|
11683
11759
|
display: grid;
|
|
@@ -11701,40 +11777,106 @@ function generateHTML(data, repoName) {
|
|
|
11701
11777
|
font-size: 1rem;
|
|
11702
11778
|
opacity: 0.9;
|
|
11703
11779
|
}
|
|
11780
|
+
.branch-comparison {
|
|
11781
|
+
display: grid;
|
|
11782
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
11783
|
+
gap: 1rem;
|
|
11784
|
+
margin-bottom: 2rem;
|
|
11785
|
+
}
|
|
11786
|
+
.branch-card {
|
|
11787
|
+
background: white;
|
|
11788
|
+
border: 2px solid #667eea;
|
|
11789
|
+
border-radius: 12px;
|
|
11790
|
+
padding: 1.5rem;
|
|
11791
|
+
cursor: pointer;
|
|
11792
|
+
transition: all 0.3s;
|
|
11793
|
+
}
|
|
11794
|
+
.branch-card:hover {
|
|
11795
|
+
transform: translateY(-4px);
|
|
11796
|
+
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
|
|
11797
|
+
}
|
|
11798
|
+
.branch-card.active {
|
|
11799
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
11800
|
+
color: white;
|
|
11801
|
+
}
|
|
11802
|
+
.branch-name {
|
|
11803
|
+
font-size: 1.2rem;
|
|
11804
|
+
font-weight: bold;
|
|
11805
|
+
margin-bottom: 0.5rem;
|
|
11806
|
+
}
|
|
11807
|
+
.branch-info {
|
|
11808
|
+
font-size: 0.9rem;
|
|
11809
|
+
opacity: 0.8;
|
|
11810
|
+
}
|
|
11811
|
+
.hidden {
|
|
11812
|
+
display: none;
|
|
11813
|
+
}
|
|
11704
11814
|
</style>
|
|
11705
11815
|
</head>
|
|
11706
11816
|
<body>
|
|
11707
11817
|
<div class="container">
|
|
11708
|
-
<
|
|
11709
|
-
|
|
11818
|
+
<div class="header">
|
|
11819
|
+
<div>
|
|
11820
|
+
<h1>\u{1F4CA} GitViz</h1>
|
|
11821
|
+
<p class="subtitle" data-i18n="subtitle">Repository: ${repoName}</p>
|
|
11822
|
+
</div>
|
|
11823
|
+
<div class="controls">
|
|
11824
|
+
<button class="lang-switch" onclick="toggleLanguage()">
|
|
11825
|
+
<span id="lang-text">\u4E2D\u6587</span>
|
|
11826
|
+
</button>
|
|
11827
|
+
</div>
|
|
11828
|
+
</div>
|
|
11710
11829
|
|
|
11711
11830
|
<div class="stats">
|
|
11712
11831
|
<div class="stat-card">
|
|
11713
11832
|
<div class="stat-value">${data.timeline.reduce((sum, d) => sum + d.commits, 0)}</div>
|
|
11714
|
-
<div class="stat-label">Total Commits</div>
|
|
11833
|
+
<div class="stat-label" data-i18n="totalCommits">Total Commits</div>
|
|
11715
11834
|
</div>
|
|
11716
11835
|
<div class="stat-card">
|
|
11717
11836
|
<div class="stat-value">${data.contributors.length}</div>
|
|
11718
|
-
<div class="stat-label">Contributors</div>
|
|
11837
|
+
<div class="stat-label" data-i18n="contributors">Contributors</div>
|
|
11719
11838
|
</div>
|
|
11720
11839
|
<div class="stat-card">
|
|
11721
11840
|
<div class="stat-value">${data.heatmap.length}</div>
|
|
11722
|
-
<div class="stat-label">Files Changed</div>
|
|
11841
|
+
<div class="stat-label" data-i18n="filesChanged">Files Changed</div>
|
|
11723
11842
|
</div>
|
|
11843
|
+
${data.branches && data.branches.length > 0 ? `
|
|
11844
|
+
<div class="stat-card">
|
|
11845
|
+
<div class="stat-value">${data.branches.length}</div>
|
|
11846
|
+
<div class="stat-label" data-i18n="branches">Branches</div>
|
|
11847
|
+
</div>
|
|
11848
|
+
` : ""}
|
|
11724
11849
|
</div>
|
|
11725
11850
|
|
|
11851
|
+
${data.branches && data.branches.length > 1 ? `
|
|
11726
11852
|
<div class="section">
|
|
11727
|
-
<h2>\u{
|
|
11853
|
+
<h2 data-i18n="branchComparison">\u{1F33F} Branch Comparison</h2>
|
|
11854
|
+
<div class="branch-comparison" id="branchComparison">
|
|
11855
|
+
${data.branches.map((branch, idx) => `
|
|
11856
|
+
<div class="branch-card ${idx === 0 ? "active" : ""}" onclick="selectBranch('${branch.name}', this)">
|
|
11857
|
+
<div class="branch-name">${branch.name}</div>
|
|
11858
|
+
<div class="branch-info">
|
|
11859
|
+
<div><span data-i18n="commits">Commits</span>: ${branch.commits}</div>
|
|
11860
|
+
<div><span data-i18n="lastCommit">Last Commit</span>: ${branch.lastCommit}</div>
|
|
11861
|
+
</div>
|
|
11862
|
+
</div>
|
|
11863
|
+
`).join("")}
|
|
11864
|
+
</div>
|
|
11865
|
+
</div>
|
|
11866
|
+
` : ""}
|
|
11867
|
+
|
|
11868
|
+
<div class="section">
|
|
11869
|
+
<h2 data-i18n="commitTimeline">\u{1F4C8} Commit Timeline</h2>
|
|
11728
11870
|
<div class="chart" id="timeline"></div>
|
|
11729
11871
|
</div>
|
|
11730
11872
|
|
|
11731
11873
|
<div class="section">
|
|
11732
|
-
<h2>\u{1F465} Top Contributors</h2>
|
|
11874
|
+
<h2 data-i18n="topContributors">\u{1F465} Top Contributors</h2>
|
|
11733
11875
|
<div class="chart" id="contributors"></div>
|
|
11734
11876
|
</div>
|
|
11735
11877
|
|
|
11736
11878
|
<div class="section">
|
|
11737
|
-
<h2>\u{1F525} File Change Heatmap</h2>
|
|
11879
|
+
<h2 data-i18n="fileHeatmap">\u{1F525} File Change Heatmap</h2>
|
|
11738
11880
|
<div class="chart" id="heatmap"></div>
|
|
11739
11881
|
</div>
|
|
11740
11882
|
</div>
|
|
@@ -11743,6 +11885,74 @@ function generateHTML(data, repoName) {
|
|
|
11743
11885
|
|
|
11744
11886
|
<script>
|
|
11745
11887
|
const data = ${JSON.stringify(data)};
|
|
11888
|
+
let currentLang = 'en';
|
|
11889
|
+
let selectedBranch = null;
|
|
11890
|
+
|
|
11891
|
+
// \u56FD\u9645\u5316\u6587\u672C
|
|
11892
|
+
const i18n = {
|
|
11893
|
+
en: {
|
|
11894
|
+
subtitle: 'Repository: ${repoName}',
|
|
11895
|
+
totalCommits: 'Total Commits',
|
|
11896
|
+
contributors: 'Contributors',
|
|
11897
|
+
filesChanged: 'Files Changed',
|
|
11898
|
+
branches: 'Branches',
|
|
11899
|
+
branchComparison: '\u{1F33F} Branch Comparison',
|
|
11900
|
+
commits: 'Commits',
|
|
11901
|
+
lastCommit: 'Last Commit',
|
|
11902
|
+
commitTimeline: '\u{1F4C8} Commit Timeline',
|
|
11903
|
+
topContributors: '\u{1F465} Top Contributors',
|
|
11904
|
+
fileHeatmap: '\u{1F525} File Change Heatmap',
|
|
11905
|
+
date: 'Date',
|
|
11906
|
+
changes: 'Changes',
|
|
11907
|
+
insertions: 'Insertions',
|
|
11908
|
+
deletions: 'Deletions',
|
|
11909
|
+
lines: 'Lines'
|
|
11910
|
+
},
|
|
11911
|
+
zh: {
|
|
11912
|
+
subtitle: '\u4ED3\u5E93: ${repoName}',
|
|
11913
|
+
totalCommits: '\u603B\u63D0\u4EA4\u6570',
|
|
11914
|
+
contributors: '\u8D21\u732E\u8005',
|
|
11915
|
+
filesChanged: '\u6587\u4EF6\u53D8\u66F4',
|
|
11916
|
+
branches: '\u5206\u652F\u6570',
|
|
11917
|
+
branchComparison: '\u{1F33F} \u5206\u652F\u5BF9\u6BD4',
|
|
11918
|
+
commits: '\u63D0\u4EA4\u6570',
|
|
11919
|
+
lastCommit: '\u6700\u540E\u63D0\u4EA4',
|
|
11920
|
+
commitTimeline: '\u{1F4C8} \u63D0\u4EA4\u65F6\u95F4\u7EBF',
|
|
11921
|
+
topContributors: '\u{1F465} \u9876\u7EA7\u8D21\u732E\u8005',
|
|
11922
|
+
fileHeatmap: '\u{1F525} \u6587\u4EF6\u53D8\u66F4\u70ED\u529B\u56FE',
|
|
11923
|
+
date: '\u65E5\u671F',
|
|
11924
|
+
changes: '\u53D8\u66F4',
|
|
11925
|
+
insertions: '\u65B0\u589E',
|
|
11926
|
+
deletions: '\u5220\u9664',
|
|
11927
|
+
lines: '\u4EE3\u7801\u884C'
|
|
11928
|
+
}
|
|
11929
|
+
};
|
|
11930
|
+
|
|
11931
|
+
function toggleLanguage() {
|
|
11932
|
+
currentLang = currentLang === 'en' ? 'zh' : 'en';
|
|
11933
|
+
document.getElementById('lang-text').textContent = currentLang === 'en' ? '\u4E2D\u6587' : 'English';
|
|
11934
|
+
|
|
11935
|
+
// \u66F4\u65B0\u6240\u6709\u5E26 data-i18n \u5C5E\u6027\u7684\u5143\u7D20
|
|
11936
|
+
document.querySelectorAll('[data-i18n]').forEach(el => {
|
|
11937
|
+
const key = el.getAttribute('data-i18n');
|
|
11938
|
+
if (i18n[currentLang][key]) {
|
|
11939
|
+
el.textContent = i18n[currentLang][key];
|
|
11940
|
+
}
|
|
11941
|
+
});
|
|
11942
|
+
}
|
|
11943
|
+
|
|
11944
|
+
function selectBranch(branchName, element) {
|
|
11945
|
+
selectedBranch = branchName;
|
|
11946
|
+
|
|
11947
|
+
// \u66F4\u65B0\u9009\u4E2D\u72B6\u6001
|
|
11948
|
+
document.querySelectorAll('.branch-card').forEach(card => {
|
|
11949
|
+
card.classList.remove('active');
|
|
11950
|
+
});
|
|
11951
|
+
element.classList.add('active');
|
|
11952
|
+
|
|
11953
|
+
// \u8FD9\u91CC\u53EF\u4EE5\u6DFB\u52A0\u6839\u636E\u5206\u652F\u8FC7\u6EE4\u6570\u636E\u7684\u903B\u8F91
|
|
11954
|
+
console.log('Selected branch:', branchName);
|
|
11955
|
+
}
|
|
11746
11956
|
|
|
11747
11957
|
// Timeline Chart
|
|
11748
11958
|
{
|
|
@@ -11785,9 +11995,11 @@ function generateHTML(data, repoName) {
|
|
|
11785
11995
|
.attr("width", x.bandwidth())
|
|
11786
11996
|
.attr("height", d => height - y(d.commits))
|
|
11787
11997
|
.on("mouseover", function(event, d) {
|
|
11788
|
-
d3.select("#tooltip")
|
|
11998
|
+
const tooltip = d3.select("#tooltip");
|
|
11999
|
+
const lang = currentLang;
|
|
12000
|
+
tooltip
|
|
11789
12001
|
.style("opacity", 1)
|
|
11790
|
-
.html(\`<strong>\${d.date}</strong><br
|
|
12002
|
+
.html(\`<strong>\${d.date}</strong><br/>\${i18n[lang].commits}: \${d.commits}<br/>+\${d.insertions} -\${d.deletions}\`)
|
|
11791
12003
|
.style("left", (event.pageX + 10) + "px")
|
|
11792
12004
|
.style("top", (event.pageY - 10) + "px");
|
|
11793
12005
|
})
|
|
@@ -11840,9 +12052,11 @@ function generateHTML(data, repoName) {
|
|
|
11840
12052
|
.attr("width", x.bandwidth())
|
|
11841
12053
|
.attr("height", d => height - y(d.commits))
|
|
11842
12054
|
.on("mouseover", function(event, d) {
|
|
11843
|
-
d3.select("#tooltip")
|
|
12055
|
+
const tooltip = d3.select("#tooltip");
|
|
12056
|
+
const lang = currentLang;
|
|
12057
|
+
tooltip
|
|
11844
12058
|
.style("opacity", 1)
|
|
11845
|
-
.html(\`<strong>\${d.name}</strong><br
|
|
12059
|
+
.html(\`<strong>\${d.name}</strong><br/>\${i18n[lang].commits}: \${d.commits}<br/>\${i18n[lang].lines}: \${d.lines}\`)
|
|
11846
12060
|
.style("left", (event.pageX + 10) + "px")
|
|
11847
12061
|
.style("top", (event.pageY - 10) + "px");
|
|
11848
12062
|
})
|
|
@@ -11881,9 +12095,11 @@ function generateHTML(data, repoName) {
|
|
|
11881
12095
|
.attr("height", y.bandwidth())
|
|
11882
12096
|
.attr("fill", d => colorScale(d.heat))
|
|
11883
12097
|
.on("mouseover", function(event, d) {
|
|
11884
|
-
d3.select("#tooltip")
|
|
12098
|
+
const tooltip = d3.select("#tooltip");
|
|
12099
|
+
const lang = currentLang;
|
|
12100
|
+
tooltip
|
|
11885
12101
|
.style("opacity", 1)
|
|
11886
|
-
.html(\`<strong>\${d.file}</strong><br
|
|
12102
|
+
.html(\`<strong>\${d.file}</strong><br/>\${i18n[lang].changes}: \${d.changes}\`)
|
|
11887
12103
|
.style("left", (event.pageX + 10) + "px")
|
|
11888
12104
|
.style("top", (event.pageY - 10) + "px");
|
|
11889
12105
|
})
|
|
@@ -11932,9 +12148,12 @@ program2.command("analyze").description("Analyze a Git repository and generate v
|
|
|
11932
12148
|
spinner.fail(source_default.red("Error: No commits found"));
|
|
11933
12149
|
process.exit(1);
|
|
11934
12150
|
}
|
|
12151
|
+
spinner.text = "Getting branch information...";
|
|
12152
|
+
const branches = await parser4.getBranches();
|
|
11935
12153
|
spinner.text = `Analyzing ${commits.length} commits...`;
|
|
11936
12154
|
const analyzer = new Analyzer();
|
|
11937
12155
|
const analysis = analyzer.analyze(commits);
|
|
12156
|
+
analysis.branches = branches;
|
|
11938
12157
|
spinner.text = "Generating visualization data...";
|
|
11939
12158
|
const vizData = analyzer.generateVisualizationData(analysis);
|
|
11940
12159
|
spinner.text = "Creating HTML report...";
|
package/package.json
CHANGED