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.
Files changed (38) hide show
  1. package/dist/commands/generate.js +104 -95
  2. package/dist/constants/chronotypes.js +23 -23
  3. package/dist/constants/colors.js +18 -18
  4. package/dist/constants/index.js +18 -18
  5. package/dist/formatters/index.js +17 -17
  6. package/dist/formatters/timeFormatter.js +28 -29
  7. package/dist/generators/html/templates/achievementsSection.js +42 -43
  8. package/dist/generators/html/templates/commitQualitySection.js +25 -26
  9. package/dist/generators/html/templates/contributionGraph.js +47 -48
  10. package/dist/generators/html/templates/impactSection.js +19 -20
  11. package/dist/generators/html/templates/knowledgeSection.js +86 -87
  12. package/dist/generators/html/templates/streakSection.js +8 -9
  13. package/dist/generators/html/templates/timePatternsSection.js +45 -46
  14. package/dist/generators/html/utils/colorUtils.js +21 -21
  15. package/dist/generators/html/utils/commitMapBuilder.js +23 -24
  16. package/dist/generators/html/utils/dateRangeCalculator.js +56 -57
  17. package/dist/generators/html/utils/developerStatsCalculator.js +28 -29
  18. package/dist/generators/html/utils/scriptLoader.js +15 -16
  19. package/dist/generators/html/utils/styleLoader.js +17 -18
  20. package/dist/generators/html/utils/weekGrouper.js +27 -28
  21. package/dist/index.js +99 -77
  22. package/dist/types/index.js +2 -2
  23. package/dist/utils/achievementDefinitions.js +433 -433
  24. package/dist/utils/achievementEngine.js +169 -170
  25. package/dist/utils/commitQualityAnalyzer.js +367 -368
  26. package/dist/utils/fileHotspotAnalyzer.js +269 -270
  27. package/dist/utils/gitParser.js +136 -125
  28. package/dist/utils/htmlGenerator.js +232 -233
  29. package/dist/utils/impactAnalyzer.js +247 -248
  30. package/dist/utils/knowledgeDistributionAnalyzer.js +373 -374
  31. package/dist/utils/matrixGenerator.js +349 -350
  32. package/dist/utils/slideGenerator.js +170 -171
  33. package/dist/utils/streakCalculator.js +134 -135
  34. package/dist/utils/timePatternAnalyzer.js +304 -305
  35. package/dist/utils/wrappedDisplay.js +124 -115
  36. package/dist/utils/wrappedGenerator.js +376 -377
  37. package/dist/utils/wrappedHtmlGenerator.js +105 -106
  38. package/package.json +10 -10
@@ -1,12 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateWrappedHTML = void 0;
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
- exports.generateWrappedHTML = generateWrappedHTML;
340
- function generateWrappedSlides(summary) {
341
- const slides = [];
342
- // Slide 1: Welcome
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.2",
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": "^4.1.2",
23
- "commander": "^9.0.0",
24
- "date-fns": "^4.1.0",
25
- "ora": "^5.4.1"
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": "^14.0.0",
29
- "shx": "^0.4.0",
30
- "typescript": "^4.0.0"
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/git-wrapped#readme",
51
+ "homepage": "https://gitlab.com/hahn-ai/repo-wrapped#readme",
52
52
  "engines": {
53
- "node": ">=22.0.0"
53
+ "node": ">=24.0.0"
54
54
  }
55
55
  }