repo-wrapped 0.0.2 → 0.0.4
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/commands/generate.js +104 -95
- package/dist/constants/chronotypes.js +23 -23
- package/dist/constants/colors.js +18 -18
- package/dist/constants/index.js +18 -18
- package/dist/formatters/index.js +17 -17
- package/dist/formatters/timeFormatter.js +28 -29
- package/dist/generators/html/templates/achievementsSection.js +42 -43
- package/dist/generators/html/templates/commitQualitySection.js +25 -26
- package/dist/generators/html/templates/contributionGraph.js +47 -48
- package/dist/generators/html/templates/impactSection.js +19 -20
- package/dist/generators/html/templates/knowledgeSection.js +86 -87
- package/dist/generators/html/templates/streakSection.js +8 -9
- package/dist/generators/html/templates/timePatternsSection.js +45 -46
- package/dist/generators/html/utils/colorUtils.js +21 -21
- package/dist/generators/html/utils/commitMapBuilder.js +23 -24
- package/dist/generators/html/utils/dateRangeCalculator.js +56 -57
- package/dist/generators/html/utils/developerStatsCalculator.js +28 -29
- package/dist/generators/html/utils/scriptLoader.js +15 -16
- package/dist/generators/html/utils/styleLoader.js +17 -18
- package/dist/generators/html/utils/weekGrouper.js +27 -28
- package/dist/index.js +99 -77
- package/dist/types/index.js +2 -2
- package/dist/utils/achievementDefinitions.js +433 -433
- package/dist/utils/achievementEngine.js +169 -170
- package/dist/utils/commitQualityAnalyzer.js +367 -368
- package/dist/utils/fileHotspotAnalyzer.js +269 -270
- package/dist/utils/gitParser.js +136 -125
- package/dist/utils/htmlGenerator.js +232 -233
- package/dist/utils/impactAnalyzer.js +247 -248
- package/dist/utils/knowledgeDistributionAnalyzer.js +373 -374
- package/dist/utils/matrixGenerator.js +349 -350
- package/dist/utils/slideGenerator.js +170 -171
- package/dist/utils/streakCalculator.js +134 -135
- package/dist/utils/timePatternAnalyzer.js +304 -305
- package/dist/utils/wrappedDisplay.js +124 -115
- package/dist/utils/wrappedGenerator.js +376 -377
- package/dist/utils/wrappedHtmlGenerator.js +105 -106
- package/package.json +10 -10
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateWrappedHTML =
|
|
4
|
-
const constants_1 = require("../constants");
|
|
5
|
-
const formatters_1 = require("../formatters");
|
|
6
|
-
function generateWrappedHTML(summary) {
|
|
7
|
-
const { writeFileSync } = require('fs');
|
|
8
|
-
const { join } = require('path');
|
|
9
|
-
const os = require('os');
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateWrappedHTML = generateWrappedHTML;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const formatters_1 = require("../formatters");
|
|
6
|
+
function generateWrappedHTML(summary) {
|
|
7
|
+
const { writeFileSync } = require('fs');
|
|
8
|
+
const { join } = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
10
|
const html = `<!DOCTYPE html>
|
|
11
11
|
<html lang="en">
|
|
12
12
|
<head>
|
|
@@ -329,64 +329,63 @@ function generateWrappedHTML(summary) {
|
|
|
329
329
|
updateButtons();
|
|
330
330
|
</script>
|
|
331
331
|
</body>
|
|
332
|
-
</html>`;
|
|
333
|
-
// Write to temp file
|
|
334
|
-
const tmpDir = os.tmpdir();
|
|
335
|
-
const filePath = join(tmpDir, `year-in-code-${summary.year}.html`);
|
|
336
|
-
writeFileSync(filePath, html);
|
|
337
|
-
return filePath;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
slides.push({
|
|
332
|
+
</html>`;
|
|
333
|
+
// Write to temp file
|
|
334
|
+
const tmpDir = os.tmpdir();
|
|
335
|
+
const filePath = join(tmpDir, `year-in-code-${summary.year}.html`);
|
|
336
|
+
writeFileSync(filePath, html);
|
|
337
|
+
return filePath;
|
|
338
|
+
}
|
|
339
|
+
function generateWrappedSlides(summary) {
|
|
340
|
+
const slides = [];
|
|
341
|
+
// Slide 1: Welcome
|
|
342
|
+
slides.push({
|
|
344
343
|
html: `
|
|
345
344
|
<h1>YOUR ${summary.year} IN CODE</h1>
|
|
346
345
|
<p class="subtitle">Hey ${summary.developer},</p>
|
|
347
346
|
<p class="subtitle">Let's look back at your year!</p>
|
|
348
|
-
`
|
|
349
|
-
});
|
|
350
|
-
// Slide 2: Big Number
|
|
351
|
-
slides.push({
|
|
347
|
+
`
|
|
348
|
+
});
|
|
349
|
+
// Slide 2: Big Number
|
|
350
|
+
slides.push({
|
|
352
351
|
html: `
|
|
353
352
|
<p class="subtitle">You made</p>
|
|
354
353
|
<div class="big-number">${summary.overview.totalCommits.toLocaleString()}</div>
|
|
355
354
|
<h2>COMMITS</h2>
|
|
356
355
|
<p class="subtitle">That's ${summary.overview.avgCommitsPerDay.toFixed(1)} commits per active day!</p>
|
|
357
|
-
`
|
|
358
|
-
});
|
|
359
|
-
// Slide 3: Personality
|
|
360
|
-
const peakHourStr = (0, formatters_1.formatHourShort)(summary.timing.peakHour);
|
|
361
|
-
slides.push({
|
|
356
|
+
`
|
|
357
|
+
});
|
|
358
|
+
// Slide 3: Personality
|
|
359
|
+
const peakHourStr = (0, formatters_1.formatHourShort)(summary.timing.peakHour);
|
|
360
|
+
slides.push({
|
|
362
361
|
html: `
|
|
363
362
|
<h2>Your coding vibe:</h2>
|
|
364
363
|
<div class="big-number">${constants_1.WRAPPED_CHRONOTYPE_EMOJIS[summary.timing.chronotype]}</div>
|
|
365
364
|
<h2>${constants_1.WRAPPED_CHRONOTYPE_LABELS[summary.timing.chronotype]}</h2>
|
|
366
365
|
<p class="subtitle">Peak hour: ${peakHourStr}</p>
|
|
367
366
|
<p class="subtitle">Favorite day: ${summary.timing.peakDay}</p>
|
|
368
|
-
`
|
|
369
|
-
});
|
|
370
|
-
// Slide 4: Streak
|
|
371
|
-
slides.push({
|
|
367
|
+
`
|
|
368
|
+
});
|
|
369
|
+
// Slide 4: Streak
|
|
370
|
+
slides.push({
|
|
372
371
|
html: `
|
|
373
372
|
<h2>Your longest streak:</h2>
|
|
374
373
|
<div class="big-number">🔥 ${summary.streaks.longest.days}</div>
|
|
375
374
|
<h2>DAYS</h2>
|
|
376
375
|
<p class="subtitle">${new Date(summary.streaks.longest.start).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} - ${new Date(summary.streaks.longest.end).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}</p>
|
|
377
376
|
<p class="subtitle">Consistency is key! 💪</p>
|
|
378
|
-
`
|
|
379
|
-
});
|
|
380
|
-
// Slide 5: Top Month
|
|
381
|
-
slides.push({
|
|
377
|
+
`
|
|
378
|
+
});
|
|
379
|
+
// Slide 5: Top Month
|
|
380
|
+
slides.push({
|
|
382
381
|
html: `
|
|
383
382
|
<h2>Your most productive month:</h2>
|
|
384
383
|
<div class="big-number">${summary.timing.mostProductiveMonth}</div>
|
|
385
384
|
<p class="subtitle">You were on fire! 🔥</p>
|
|
386
|
-
`
|
|
387
|
-
});
|
|
388
|
-
// Slide 6: Impact
|
|
389
|
-
slides.push({
|
|
385
|
+
`
|
|
386
|
+
});
|
|
387
|
+
// Slide 6: Impact
|
|
388
|
+
slides.push({
|
|
390
389
|
html: `
|
|
391
390
|
<h2>Code impact:</h2>
|
|
392
391
|
<div class="stats-grid">
|
|
@@ -401,12 +400,12 @@ function generateWrappedSlides(summary) {
|
|
|
401
400
|
</div>
|
|
402
401
|
<p class="subtitle">${summary.impact.filesChanged} files changed</p>
|
|
403
402
|
<p class="subtitle">Making waves in the codebase! 🌊</p>
|
|
404
|
-
`
|
|
405
|
-
});
|
|
406
|
-
// Slide 7: Distribution
|
|
407
|
-
const total = Object.values(summary.workDistribution).reduce((sum, val) => sum + val, 0);
|
|
408
|
-
const getPercentage = (value) => total > 0 ? ((value / total) * 100).toFixed(0) : '0';
|
|
409
|
-
slides.push({
|
|
403
|
+
`
|
|
404
|
+
});
|
|
405
|
+
// Slide 7: Distribution
|
|
406
|
+
const total = Object.values(summary.workDistribution).reduce((sum, val) => sum + val, 0);
|
|
407
|
+
const getPercentage = (value) => total > 0 ? ((value / total) * 100).toFixed(0) : '0';
|
|
408
|
+
slides.push({
|
|
410
409
|
html: `
|
|
411
410
|
<h2>What you worked on:</h2>
|
|
412
411
|
<div class="stats-grid">
|
|
@@ -428,34 +427,34 @@ function generateWrappedSlides(summary) {
|
|
|
428
427
|
</div>
|
|
429
428
|
</div>
|
|
430
429
|
<p class="subtitle">${summary.workDistribution.features > summary.workDistribution.fixes ? 'Feature-focused year! ✨' : 'Bug-squashing hero! 🦸'}</p>
|
|
431
|
-
`
|
|
432
|
-
});
|
|
433
|
-
// Slide 8: Collaboration
|
|
434
|
-
let collabHTML = '';
|
|
435
|
-
if (summary.collaboration.uniqueContributors === 0) {
|
|
430
|
+
`
|
|
431
|
+
});
|
|
432
|
+
// Slide 8: Collaboration
|
|
433
|
+
let collabHTML = '';
|
|
434
|
+
if (summary.collaboration.uniqueContributors === 0) {
|
|
436
435
|
collabHTML = `
|
|
437
436
|
<h2>Solo developer!</h2>
|
|
438
437
|
<div class="big-number">🚀</div>
|
|
439
438
|
<p class="subtitle">Building independently</p>
|
|
440
|
-
`;
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
439
|
+
`;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
443
442
|
const topCollabPart = summary.collaboration.topCollaborator ? `
|
|
444
443
|
<p class="subtitle">Most commits with:</p>
|
|
445
444
|
<p class="subtitle"><strong>${summary.collaboration.topCollaborator.name}</strong> (${summary.collaboration.topCollaborator.sharedDays} shared days)</p>
|
|
446
|
-
` : '';
|
|
445
|
+
` : '';
|
|
447
446
|
collabHTML = `
|
|
448
447
|
<h2>You worked alongside:</h2>
|
|
449
448
|
<div class="big-number">${summary.collaboration.uniqueContributors}</div>
|
|
450
449
|
<h2>Developer${summary.collaboration.uniqueContributors === 1 ? '' : 's'}</h2>
|
|
451
450
|
${topCollabPart}
|
|
452
451
|
<p class="subtitle">Great teamwork! 🤝</p>
|
|
453
|
-
`;
|
|
454
|
-
}
|
|
455
|
-
slides.push({ html: collabHTML });
|
|
456
|
-
// Slide 9: Quality
|
|
457
|
-
const stars = '⭐'.repeat(Math.min(5, Math.ceil(summary.quality.overallScore / 2)));
|
|
458
|
-
slides.push({
|
|
452
|
+
`;
|
|
453
|
+
}
|
|
454
|
+
slides.push({ html: collabHTML });
|
|
455
|
+
// Slide 9: Quality
|
|
456
|
+
const stars = '⭐'.repeat(Math.min(5, Math.ceil(summary.quality.overallScore / 2)));
|
|
457
|
+
slides.push({
|
|
459
458
|
html: `
|
|
460
459
|
<h2>Commit quality score:</h2>
|
|
461
460
|
<div class="big-number">${summary.quality.overallScore.toFixed(1)}</div>
|
|
@@ -463,47 +462,47 @@ function generateWrappedSlides(summary) {
|
|
|
463
462
|
<div class="big-number">${stars}</div>
|
|
464
463
|
<p class="subtitle">${summary.quality.conventionalPercentage.toFixed(0)}% conventional commits</p>
|
|
465
464
|
<p class="subtitle">Well documented code! 📚</p>
|
|
466
|
-
`
|
|
467
|
-
});
|
|
468
|
-
// Slide 10: Fun Facts
|
|
469
|
-
let factsHTML = '<ul class="fun-facts">';
|
|
470
|
-
if (summary.funFacts.holidayCommits.length > 0) {
|
|
471
|
-
factsHTML += `<li><span class="emoji">🎄</span> Committed on ${summary.funFacts.holidayCommits.join(', ')}</li>`;
|
|
472
|
-
}
|
|
473
|
-
if (summary.funFacts.midnightCommits > 0) {
|
|
474
|
-
factsHTML += `<li><span class="emoji">🌙</span> ${summary.funFacts.midnightCommits} commit${summary.funFacts.midnightCommits === 1 ? '' : 's'} past midnight</li>`;
|
|
475
|
-
}
|
|
476
|
-
if (summary.funFacts.weekendCommits > 0) {
|
|
477
|
-
factsHTML += `<li><span class="emoji">🎉</span> ${summary.funFacts.weekendCommits} weekend commit${summary.funFacts.weekendCommits === 1 ? '' : 's'}</li>`;
|
|
478
|
-
}
|
|
479
|
-
if (summary.funFacts.busiestDay) {
|
|
480
|
-
const dateStr = new Date(summary.funFacts.busiestDay.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
481
|
-
factsHTML += `<li><span class="emoji">📅</span> Busiest day: ${dateStr} (${summary.funFacts.busiestDay.commits} commits)</li>`;
|
|
482
|
-
}
|
|
483
|
-
factsHTML += '</ul><p class="subtitle">Dedication level: 💯</p>';
|
|
484
|
-
slides.push({
|
|
465
|
+
`
|
|
466
|
+
});
|
|
467
|
+
// Slide 10: Fun Facts
|
|
468
|
+
let factsHTML = '<ul class="fun-facts">';
|
|
469
|
+
if (summary.funFacts.holidayCommits.length > 0) {
|
|
470
|
+
factsHTML += `<li><span class="emoji">🎄</span> Committed on ${summary.funFacts.holidayCommits.join(', ')}</li>`;
|
|
471
|
+
}
|
|
472
|
+
if (summary.funFacts.midnightCommits > 0) {
|
|
473
|
+
factsHTML += `<li><span class="emoji">🌙</span> ${summary.funFacts.midnightCommits} commit${summary.funFacts.midnightCommits === 1 ? '' : 's'} past midnight</li>`;
|
|
474
|
+
}
|
|
475
|
+
if (summary.funFacts.weekendCommits > 0) {
|
|
476
|
+
factsHTML += `<li><span class="emoji">🎉</span> ${summary.funFacts.weekendCommits} weekend commit${summary.funFacts.weekendCommits === 1 ? '' : 's'}</li>`;
|
|
477
|
+
}
|
|
478
|
+
if (summary.funFacts.busiestDay) {
|
|
479
|
+
const dateStr = new Date(summary.funFacts.busiestDay.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
480
|
+
factsHTML += `<li><span class="emoji">📅</span> Busiest day: ${dateStr} (${summary.funFacts.busiestDay.commits} commits)</li>`;
|
|
481
|
+
}
|
|
482
|
+
factsHTML += '</ul><p class="subtitle">Dedication level: 💯</p>';
|
|
483
|
+
slides.push({
|
|
485
484
|
html: `
|
|
486
485
|
<h2>Fun facts about your year:</h2>
|
|
487
486
|
${factsHTML}
|
|
488
|
-
`
|
|
489
|
-
});
|
|
490
|
-
// Slide 11: Achievements
|
|
491
|
-
if (summary.achievements.total > 0) {
|
|
492
|
-
const topBadges = summary.achievements.earned.slice(0, 5);
|
|
493
|
-
const badgesHTML = topBadges.map(badge => `<div class="badge-item">✨ ${badge}</div>`).join('');
|
|
494
|
-
slides.push({
|
|
487
|
+
`
|
|
488
|
+
});
|
|
489
|
+
// Slide 11: Achievements
|
|
490
|
+
if (summary.achievements.total > 0) {
|
|
491
|
+
const topBadges = summary.achievements.earned.slice(0, 5);
|
|
492
|
+
const badgesHTML = topBadges.map(badge => `<div class="badge-item">✨ ${badge}</div>`).join('');
|
|
493
|
+
slides.push({
|
|
495
494
|
html: `
|
|
496
495
|
<h2>Badges earned in ${summary.year}:</h2>
|
|
497
496
|
<div class="badges-grid">${badgesHTML}</div>
|
|
498
497
|
<p class="subtitle">${summary.achievements.total} total achievement${summary.achievements.total === 1 ? '' : 's'}! 🏆</p>
|
|
499
|
-
`
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
// Slide 12: Comparison (if available)
|
|
503
|
-
if (summary.comparison) {
|
|
504
|
-
const { comparison } = summary;
|
|
505
|
-
const getTrendArrow = (trend) => trend === 'up' ? '<span class="trend-up">↑</span>' : trend === 'down' ? '<span class="trend-down">↓</span>' : '→';
|
|
506
|
-
slides.push({
|
|
498
|
+
`
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
// Slide 12: Comparison (if available)
|
|
502
|
+
if (summary.comparison) {
|
|
503
|
+
const { comparison } = summary;
|
|
504
|
+
const getTrendArrow = (trend) => trend === 'up' ? '<span class="trend-up">↑</span>' : trend === 'down' ? '<span class="trend-down">↓</span>' : '→';
|
|
505
|
+
slides.push({
|
|
507
506
|
html: `
|
|
508
507
|
<h2>${summary.year} vs ${summary.year - 1}:</h2>
|
|
509
508
|
<div class="comparison-row">
|
|
@@ -519,11 +518,11 @@ function generateWrappedSlides(summary) {
|
|
|
519
518
|
<span>${comparison.currentYear.quality.toFixed(1)} ${getTrendArrow(comparison.changes.quality.trend)}</span>
|
|
520
519
|
</div>
|
|
521
520
|
<p class="subtitle">${comparison.insights[0] || 'Keep up the great work!'}</p>
|
|
522
|
-
`
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
// Slide 13: Finale
|
|
526
|
-
slides.push({
|
|
521
|
+
`
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
// Slide 13: Finale
|
|
525
|
+
slides.push({
|
|
527
526
|
html: `
|
|
528
527
|
<h1>That's your ${summary.year}!</h1>
|
|
529
528
|
<div class="stats-grid">
|
|
@@ -546,7 +545,7 @@ function generateWrappedSlides(summary) {
|
|
|
546
545
|
</div>
|
|
547
546
|
<h2>Here's to ${summary.year + 1}! 🚀</h2>
|
|
548
547
|
<p class="subtitle">#YearInCode #DevLife</p>
|
|
549
|
-
`
|
|
550
|
-
});
|
|
551
|
-
return slides;
|
|
552
|
-
}
|
|
548
|
+
`
|
|
549
|
+
});
|
|
550
|
+
return slides;
|
|
551
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repo-wrapped",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "A tool to generate Git repository analytics and visualizations in CLI or HTML.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"repo-wrapped": "dist/index.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"chalk": "
|
|
23
|
-
"commander": "
|
|
24
|
-
"date-fns": "
|
|
25
|
-
"ora": "
|
|
22
|
+
"chalk": "5.6.2",
|
|
23
|
+
"commander": "14.0.3",
|
|
24
|
+
"date-fns": "4.1.0",
|
|
25
|
+
"ora": "9.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@types/node": "
|
|
29
|
-
"shx": "
|
|
30
|
-
"typescript": "
|
|
28
|
+
"@types/node": "25.1.0",
|
|
29
|
+
"shx": "0.4.0",
|
|
30
|
+
"typescript": "5.9.3"
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"cli",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"bugs": {
|
|
49
49
|
"url": "https://gitlab.com/hahn-ai/repo-wrapped/issues"
|
|
50
50
|
},
|
|
51
|
-
"homepage": "https://gitlab.com/hahn-ai/
|
|
51
|
+
"homepage": "https://gitlab.com/hahn-ai/repo-wrapped#readme",
|
|
52
52
|
"engines": {
|
|
53
|
-
"node": ">=
|
|
53
|
+
"node": ">=24.0.0"
|
|
54
54
|
}
|
|
55
55
|
}
|