repo-wrapped 0.0.6 → 0.0.9
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/.github/agents/complete.agent.md +257 -0
- package/.github/agents/feature-scaffold.agent.md +248 -0
- package/.github/agents/jsdoc.agent.md +243 -0
- package/.github/agents/plan.agent.md +202 -0
- package/.github/agents/spec-writer.agent.md +169 -0
- package/.github/agents/test-writer.agent.md +169 -0
- package/.stylelintrc.json +27 -0
- package/README.md +94 -94
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +446 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +446 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +7039 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/commands/generate.js +262 -5
- package/dist/config/defaults.js +158 -0
- package/dist/config/index.js +10 -0
- package/dist/features/achievements/data/achievements.json +284 -0
- package/dist/features/achievements/engine.js +140 -0
- package/dist/features/achievements/evaluators.js +246 -0
- package/dist/features/achievements/helpers.js +58 -0
- package/dist/features/achievements/index.js +57 -0
- package/dist/features/achievements/loader.js +88 -0
- package/dist/features/achievements/template.js +155 -0
- package/dist/features/achievements/types.js +7 -0
- package/dist/features/commit-quality/analyzer.js +378 -0
- package/dist/features/commit-quality/analyzer.test.js +484 -0
- package/dist/features/commit-quality/index.js +28 -0
- package/dist/features/commit-quality/template.js +114 -0
- package/dist/features/commit-quality/types.js +2 -0
- package/dist/features/comparison/analyzer.js +222 -0
- package/dist/features/comparison/index.js +28 -0
- package/dist/features/comparison/template.js +119 -0
- package/dist/features/comparison/types.js +2 -0
- package/dist/features/contribution-graph/index.js +9 -0
- package/dist/features/contribution-graph/template.js +89 -0
- package/dist/features/events/index.js +31 -0
- package/dist/features/events/parser.js +253 -0
- package/dist/features/events/template.js +113 -0
- package/dist/features/events/types.js +2 -0
- package/dist/features/executive-summary/generator.js +275 -0
- package/dist/features/executive-summary/index.js +27 -0
- package/dist/features/executive-summary/template.js +80 -0
- package/dist/features/executive-summary/types.js +2 -0
- package/dist/features/gaps/analyzer.js +298 -0
- package/dist/features/gaps/analyzer.test.js +517 -0
- package/dist/features/gaps/index.js +27 -0
- package/dist/features/gaps/template.js +190 -0
- package/dist/features/gaps/types.js +2 -0
- package/dist/features/impact/analyzer.js +248 -0
- package/dist/features/impact/index.js +26 -0
- package/dist/features/impact/template.js +118 -0
- package/dist/features/impact/types.js +2 -0
- package/dist/features/index.js +40 -0
- package/dist/features/knowledge/analyzer.js +385 -0
- package/dist/features/knowledge/index.js +26 -0
- package/dist/features/knowledge/template.js +239 -0
- package/dist/features/knowledge/types.js +2 -0
- package/dist/features/streaks/calculator.js +184 -0
- package/dist/features/streaks/calculator.test.js +366 -0
- package/dist/features/streaks/index.js +36 -0
- package/dist/features/streaks/template.js +41 -0
- package/dist/features/streaks/types.js +9 -0
- package/dist/features/team/analyzer.js +316 -0
- package/dist/features/team/index.js +30 -0
- package/dist/features/team/template.js +146 -0
- package/dist/features/team/types.js +2 -0
- package/dist/features/time-patterns/analyzer.js +319 -0
- package/dist/features/time-patterns/analyzer.test.js +278 -0
- package/dist/features/time-patterns/index.js +37 -0
- package/dist/features/time-patterns/template.js +109 -0
- package/dist/features/time-patterns/types.js +9 -0
- package/dist/features/velocity/analyzer.js +257 -0
- package/dist/features/velocity/analyzer.test.js +383 -0
- package/dist/features/velocity/index.js +27 -0
- package/dist/features/velocity/template.js +189 -0
- package/dist/features/velocity/types.js +2 -0
- package/dist/generators/html/scripts/knowledge.js +17 -0
- package/dist/generators/html/styles/base.css +10 -6
- package/dist/generators/html/styles/components.css +121 -1
- package/dist/generators/html/styles/knowledge.css +21 -0
- package/dist/generators/html/styles/leaddev.css +1335 -0
- package/dist/generators/html/styles/strategic-insights.css +1337 -0
- package/dist/generators/html/templates/commitQualitySection.js +28 -2
- package/dist/generators/html/templates/comparisonSection.js +119 -0
- package/dist/generators/html/templates/eventsSection.js +113 -0
- package/dist/generators/html/templates/executiveSummarySection.js +80 -0
- package/dist/generators/html/templates/gapSection.js +190 -0
- package/dist/generators/html/templates/impactSection.js +8 -6
- package/dist/generators/html/templates/knowledgeSection.js +16 -2
- package/dist/generators/html/templates/teamSection.js +146 -0
- package/dist/generators/html/templates/velocitySection.js +189 -0
- package/dist/generators/html/types.js +7 -0
- package/dist/generators/html/utils/analysisRunner.js +93 -0
- package/dist/generators/html/utils/cardBuilder.js +47 -0
- package/dist/generators/html/utils/contextBuilder.js +54 -0
- package/dist/generators/html/utils/htmlDocumentBuilder.js +396 -0
- package/dist/generators/html/utils/kpiBuilder.js +76 -0
- package/dist/generators/html/utils/sectionWrapper.js +71 -0
- package/dist/generators/html/utils/styleLoader.js +2 -1
- package/dist/html/analysisRunner.js +93 -0
- package/dist/html/htmlDocumentBuilder.js +396 -0
- package/dist/html/index.js +29 -0
- package/dist/html/shared/colorUtils.js +61 -0
- package/dist/html/shared/commitMapBuilder.js +23 -0
- package/dist/html/shared/components/cardBuilder.js +47 -0
- package/dist/html/shared/components/index.js +18 -0
- package/dist/html/shared/components/kpiBuilder.js +76 -0
- package/dist/html/shared/components/sectionWrapper.js +71 -0
- package/dist/html/shared/contextBuilder.js +54 -0
- package/dist/html/shared/dateRangeCalculator.js +56 -0
- package/dist/html/shared/developerStatsCalculator.js +28 -0
- package/dist/html/shared/index.js +39 -0
- package/dist/html/shared/scriptLoader.js +15 -0
- package/dist/html/shared/scripts/export.js +125 -0
- package/dist/html/shared/scripts/knowledge.js +137 -0
- package/dist/html/shared/scripts/modal.js +68 -0
- package/dist/html/shared/scripts/navigation.js +156 -0
- package/dist/html/shared/scripts/tabs.js +18 -0
- package/dist/html/shared/scripts/tooltip.js +21 -0
- package/dist/html/shared/styleLoader.js +18 -0
- package/dist/html/shared/styles/achievements.css +387 -0
- package/dist/html/shared/styles/base.css +822 -0
- package/dist/html/shared/styles/components.css +1511 -0
- package/dist/html/shared/styles/knowledge.css +242 -0
- package/dist/html/shared/styles/strategic-insights.css +1337 -0
- package/dist/html/shared/weekGrouper.js +27 -0
- package/dist/html/types.js +7 -0
- package/dist/index.js +54 -21
- package/dist/test/helpers/commitFactory.js +166 -0
- package/dist/test/helpers/dateUtils.js +101 -0
- package/dist/test/helpers/index.js +29 -0
- package/dist/test/setup.js +17 -0
- package/dist/test/smoke.test.js +94 -0
- package/dist/types/achievements.js +7 -0
- package/dist/types/analysis.js +7 -0
- package/dist/types/core.js +7 -0
- package/dist/types/index.js +38 -0
- package/dist/types/options.js +7 -0
- package/dist/types/shared.js +7 -0
- package/dist/types/strategic.js +7 -0
- package/dist/types/summary.js +7 -0
- package/dist/utils/achievementDefinitions.js +22 -22
- package/dist/utils/analyzerContextBuilder.js +124 -0
- package/dist/utils/commitQualityAnalyzer.js +13 -2
- package/dist/utils/emptyResults.js +95 -0
- package/dist/utils/eventAnnotationParser.js +253 -0
- package/dist/utils/executiveSummaryGenerator.js +275 -0
- package/dist/utils/fileHotspotAnalyzer.js +4 -12
- package/dist/utils/gapAnalyzer.js +298 -0
- package/dist/utils/gitParser.test.js +363 -0
- package/dist/utils/htmlGenerator.js +126 -450
- package/dist/utils/impactAnalyzer.js +20 -19
- package/dist/utils/knowledgeDistributionAnalyzer.js +32 -27
- package/dist/utils/matrixGenerator.js +13 -13
- package/dist/utils/rangeComparisonAnalyzer.js +222 -0
- package/dist/utils/streakCalculator.js +77 -27
- package/dist/utils/teamAnalyzer.js +316 -0
- package/dist/utils/timePatternAnalyzer.js +18 -3
- package/dist/utils/velocityAnalyzer.js +257 -0
- package/dist/utils/wrappedGenerator.js +8 -8
- package/package.json +74 -55
- package/vitest.config.ts +46 -0
- package/dist/cli.js +0 -24
- package/dist/commands/index.js +0 -24
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.groupDaysIntoWeeks = groupDaysIntoWeeks;
|
|
4
|
+
exports.getDayLabels = getDayLabels;
|
|
5
|
+
const date_fns_1 = require("date-fns");
|
|
6
|
+
/**
|
|
7
|
+
* Groups days into weeks for the contribution graph
|
|
8
|
+
*/
|
|
9
|
+
function groupDaysIntoWeeks(startDate, endDate) {
|
|
10
|
+
const days = (0, date_fns_1.eachDayOfInterval)({ start: startDate, end: endDate });
|
|
11
|
+
const weeks = [];
|
|
12
|
+
let currentWeek = [];
|
|
13
|
+
days.forEach(day => {
|
|
14
|
+
currentWeek.push(day);
|
|
15
|
+
if (currentWeek.length === 7) {
|
|
16
|
+
weeks.push(currentWeek);
|
|
17
|
+
currentWeek = [];
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return weeks;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets day labels for the contribution graph
|
|
24
|
+
*/
|
|
25
|
+
function getDayLabels() {
|
|
26
|
+
return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
27
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -18,27 +18,45 @@ program
|
|
|
18
18
|
.name('repo-wrapped')
|
|
19
19
|
.description('Generate Git repository analytics and visualizations')
|
|
20
20
|
.version('1.0.0')
|
|
21
|
-
.addHelpText('after', `
|
|
22
|
-
Commands:
|
|
23
|
-
generate [path] Generate commit visualization (default command)
|
|
24
|
-
wrapped [year] [path] Generate Year in Code summary
|
|
25
|
-
|
|
26
|
-
Generate Options:
|
|
27
|
-
-y, --year <year> Year to analyze (default: current year)
|
|
28
|
-
-m, --months <months> Number of months to show (default: 12)
|
|
29
|
-
-a, --all Analyze entire repository lifetime
|
|
30
|
-
--html Generate HTML report and open in browser
|
|
31
|
-
--body-check Include commit body in quality scoring
|
|
32
|
-
--deep-analysis Enable file-level knowledge distribution analysis
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
--
|
|
36
|
-
--
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
Commands:
|
|
23
|
+
generate [path] Generate commit visualization (default command)
|
|
24
|
+
wrapped [year] [path] Generate Year in Code summary
|
|
25
|
+
|
|
26
|
+
Generate Options:
|
|
27
|
+
-y, --year <year> Year to analyze (default: current year)
|
|
28
|
+
-m, --months <months> Number of months to show (default: 12)
|
|
29
|
+
-a, --all Analyze entire repository lifetime
|
|
30
|
+
--html Generate HTML report and open in browser
|
|
31
|
+
--body-check Include commit body in quality scoring
|
|
32
|
+
--deep-analysis Enable file-level knowledge distribution analysis
|
|
33
|
+
|
|
34
|
+
Strategic Insights:
|
|
35
|
+
--velocity Enable velocity timeline analysis
|
|
36
|
+
--velocity-window <w> Rolling average window in weeks (default: 4)
|
|
37
|
+
--gap-analysis Enable gap detection and blocker analysis
|
|
38
|
+
--gap-threshold <days> Minimum gap days to report (default: 3)
|
|
39
|
+
--compare <r1> <r2> Compare two date ranges (format: YYYY-MM-DD..YYYY-MM-DD)
|
|
40
|
+
--compare-labels <l> Labels for comparison (format: "Label1,Label2")
|
|
41
|
+
--author <name> Filter to specific author (partial match)
|
|
42
|
+
--authors <names> Filter to multiple authors (comma-separated)
|
|
43
|
+
--team <file> Path to team members file (one name per line)
|
|
44
|
+
--exclude-author <name> Exclude specific author (e.g., bots)
|
|
45
|
+
--executive-summary Generate executive summary with KPIs
|
|
46
|
+
--summary-only Output only the executive summary (terminal or HTML)
|
|
47
|
+
--events <file> Path to events annotation JSON file
|
|
48
|
+
|
|
49
|
+
Wrapped Options:
|
|
50
|
+
--html Generate HTML slideshow and open in browser
|
|
51
|
+
--compare Compare with previous year
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
repo-wrapped generate . --html
|
|
55
|
+
repo-wrapped generate . --all --html --deep-analysis
|
|
56
|
+
repo-wrapped generate . --velocity --gap-analysis --executive-summary
|
|
57
|
+
repo-wrapped generate . --compare "2025-01-01..2025-06-30" "2025-07-01..2025-12-31"
|
|
58
|
+
repo-wrapped generate . --author "John" --html
|
|
59
|
+
repo-wrapped wrapped 2025 . --html
|
|
42
60
|
`);
|
|
43
61
|
program
|
|
44
62
|
.command('generate')
|
|
@@ -50,6 +68,21 @@ program
|
|
|
50
68
|
.option('--html', 'Generate HTML output and open in browser')
|
|
51
69
|
.option('--body-check', 'Include commit body in quality scoring')
|
|
52
70
|
.option('--deep-analysis', 'Enable file-level analysis for detailed knowledge distribution')
|
|
71
|
+
// Lead Developer Insights options
|
|
72
|
+
.option('--velocity', 'Enable velocity timeline analysis')
|
|
73
|
+
.option('--velocity-window <weeks>', 'Rolling average window in weeks', '4')
|
|
74
|
+
.option('--gap-analysis', 'Enable gap detection and blocker analysis')
|
|
75
|
+
.option('--gap-threshold <days>', 'Minimum gap days to report', '3')
|
|
76
|
+
.option('--compare <ranges...>', 'Compare two date ranges (format: YYYY-MM-DD..YYYY-MM-DD)')
|
|
77
|
+
.option('--compare-labels <labels>', 'Labels for comparison (comma-separated)')
|
|
78
|
+
.option('--author <name>', 'Filter to specific author (partial match)')
|
|
79
|
+
.option('--authors <names>', 'Filter to multiple authors (comma-separated)')
|
|
80
|
+
.option('--team <file>', 'Path to team members file (one name per line)')
|
|
81
|
+
.option('--exclude-author <name>', 'Exclude specific author')
|
|
82
|
+
.option('--exclude-authors <names>', 'Exclude multiple authors (comma-separated)')
|
|
83
|
+
.option('--executive-summary', 'Generate executive summary with KPIs')
|
|
84
|
+
.option('--summary-only', 'Output only the executive summary')
|
|
85
|
+
.option('--events <file>', 'Path to events annotation JSON file')
|
|
53
86
|
.action(generate_js_1.generateMatrix);
|
|
54
87
|
program
|
|
55
88
|
.command('wrapped')
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test Commit Factory
|
|
4
|
+
*
|
|
5
|
+
* Provides utilities for creating test commit data with sensible defaults.
|
|
6
|
+
* Use these helpers to create consistent test data across all test files.
|
|
7
|
+
*
|
|
8
|
+
* @module test/helpers/commitFactory
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createCommit = createCommit;
|
|
12
|
+
exports.createCommitSequence = createCommitSequence;
|
|
13
|
+
exports.createWorkWeekCommits = createWorkWeekCommits;
|
|
14
|
+
exports.createCommitsByHour = createCommitsByHour;
|
|
15
|
+
exports.createConventionalCommits = createConventionalCommits;
|
|
16
|
+
exports.resetHashCounter = resetHashCounter;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a single CommitData object with default values.
|
|
19
|
+
* Override any property by passing it in the overrides object.
|
|
20
|
+
*
|
|
21
|
+
* @param overrides - Partial commit data to override defaults
|
|
22
|
+
* @returns Complete CommitData object
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Basic usage
|
|
27
|
+
* const commit = createCommit();
|
|
28
|
+
*
|
|
29
|
+
* // With overrides
|
|
30
|
+
* const feat = createCommit({ message: 'feat: add login' });
|
|
31
|
+
*
|
|
32
|
+
* // With specific date
|
|
33
|
+
* const oldCommit = createCommit({ date: '2025-01-01T10:00:00Z' });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function createCommit(overrides = {}) {
|
|
37
|
+
return {
|
|
38
|
+
hash: generateHash(),
|
|
39
|
+
author: 'Test Author',
|
|
40
|
+
date: '2025-06-15T10:00:00Z',
|
|
41
|
+
message: 'test: example commit message',
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates an array of commits on consecutive days.
|
|
47
|
+
*
|
|
48
|
+
* @param count - Number of commits to create
|
|
49
|
+
* @param options - Configuration options
|
|
50
|
+
* @returns Array of CommitData objects
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // 5 commits on consecutive days
|
|
55
|
+
* const commits = createCommitSequence(5);
|
|
56
|
+
*
|
|
57
|
+
* // Starting from a specific date
|
|
58
|
+
* const commits = createCommitSequence(3, {
|
|
59
|
+
* startDate: new Date('2025-01-01')
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* // With gaps between commits
|
|
63
|
+
* const commits = createCommitSequence(3, { intervalDays: 7 });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function createCommitSequence(count, options = {}) {
|
|
67
|
+
const { startDate = new Date('2025-06-01'), intervalDays = 1, author = 'Test Author', messagePrefix = 'test', } = options;
|
|
68
|
+
return Array.from({ length: count }, (_, i) => {
|
|
69
|
+
const date = new Date(startDate);
|
|
70
|
+
date.setDate(date.getDate() + i * intervalDays);
|
|
71
|
+
return createCommit({
|
|
72
|
+
hash: `hash${String(i).padStart(3, '0')}`,
|
|
73
|
+
date: date.toISOString(),
|
|
74
|
+
author,
|
|
75
|
+
message: `${messagePrefix}: commit ${i + 1}`,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates commits for a full work week (Monday-Friday).
|
|
81
|
+
*
|
|
82
|
+
* @param weekStartMonday - The Monday to start the week
|
|
83
|
+
* @param commitsPerDay - Number of commits per day (default: 1)
|
|
84
|
+
* @returns Array of commits for Mon-Fri
|
|
85
|
+
*/
|
|
86
|
+
function createWorkWeekCommits(weekStartMonday, commitsPerDay = 1) {
|
|
87
|
+
const commits = [];
|
|
88
|
+
for (let day = 0; day < 5; day++) {
|
|
89
|
+
for (let c = 0; c < commitsPerDay; c++) {
|
|
90
|
+
const date = new Date(weekStartMonday);
|
|
91
|
+
date.setDate(date.getDate() + day);
|
|
92
|
+
date.setHours(9 + c, 0, 0, 0);
|
|
93
|
+
commits.push(createCommit({
|
|
94
|
+
hash: `week${day}commit${c}`,
|
|
95
|
+
date: date.toISOString(),
|
|
96
|
+
message: `feat: day ${day + 1} commit ${c + 1}`,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return commits;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Creates commits with specific hour distribution for time pattern testing.
|
|
104
|
+
*
|
|
105
|
+
* @param hourCommitMap - Map of hour (0-23) to number of commits
|
|
106
|
+
* @param baseDate - Base date for all commits
|
|
107
|
+
* @returns Array of commits at specified hours
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* // 3 commits at 9am, 5 commits at 2pm
|
|
112
|
+
* const commits = createCommitsByHour({ 9: 3, 14: 5 });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
function createCommitsByHour(hourCommitMap, baseDate = new Date('2025-06-15')) {
|
|
116
|
+
const commits = [];
|
|
117
|
+
for (const [hour, count] of Object.entries(hourCommitMap)) {
|
|
118
|
+
for (let i = 0; i < count; i++) {
|
|
119
|
+
const date = new Date(baseDate);
|
|
120
|
+
date.setHours(Number(hour), i * 10, 0, 0);
|
|
121
|
+
commits.push(createCommit({
|
|
122
|
+
hash: `hour${hour}commit${i}`,
|
|
123
|
+
date: date.toISOString(),
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return commits;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Creates commits with various conventional commit types for quality testing.
|
|
131
|
+
*
|
|
132
|
+
* @param typeCounts - Map of commit type to count
|
|
133
|
+
* @returns Array of commits with specified types
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const commits = createConventionalCommits({
|
|
138
|
+
* feat: 5,
|
|
139
|
+
* fix: 3,
|
|
140
|
+
* docs: 1,
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
function createConventionalCommits(typeCounts) {
|
|
145
|
+
const commits = [];
|
|
146
|
+
for (const [type, count] of Object.entries(typeCounts)) {
|
|
147
|
+
for (let i = 0; i < count; i++) {
|
|
148
|
+
commits.push(createCommit({
|
|
149
|
+
hash: `${type}${i}`,
|
|
150
|
+
message: `${type}: example ${type} commit ${i + 1}`,
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return commits;
|
|
155
|
+
}
|
|
156
|
+
// Internal helper
|
|
157
|
+
let hashCounter = 0;
|
|
158
|
+
function generateHash() {
|
|
159
|
+
return `abc${String(++hashCounter).padStart(10, '0')}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Resets the hash counter. Call this in beforeEach for deterministic hashes.
|
|
163
|
+
*/
|
|
164
|
+
function resetHashCounter() {
|
|
165
|
+
hashCounter = 0;
|
|
166
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Date Testing Utilities
|
|
4
|
+
*
|
|
5
|
+
* Helpers for working with dates in tests.
|
|
6
|
+
*
|
|
7
|
+
* @module test/helpers/dateUtils
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.TEST_TODAY = void 0;
|
|
11
|
+
exports.getMonday = getMonday;
|
|
12
|
+
exports.daysAgo = daysAgo;
|
|
13
|
+
exports.daysFromNow = daysFromNow;
|
|
14
|
+
exports.isWeekend = isWeekend;
|
|
15
|
+
exports.getBusinessDaysBetween = getBusinessDaysBetween;
|
|
16
|
+
exports.mockDateNow = mockDateNow;
|
|
17
|
+
exports.toISOString = toISOString;
|
|
18
|
+
exports.parseDate = parseDate;
|
|
19
|
+
/**
|
|
20
|
+
* Gets the Monday of a given week.
|
|
21
|
+
*
|
|
22
|
+
* @param date - Any date in the target week
|
|
23
|
+
* @returns The Monday of that week
|
|
24
|
+
*/
|
|
25
|
+
function getMonday(date) {
|
|
26
|
+
const d = new Date(date);
|
|
27
|
+
const day = d.getDay();
|
|
28
|
+
const diff = d.getDate() - day + (day === 0 ? -6 : 1);
|
|
29
|
+
d.setDate(diff);
|
|
30
|
+
d.setHours(0, 0, 0, 0);
|
|
31
|
+
return d;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a date N days ago from a base date.
|
|
35
|
+
*
|
|
36
|
+
* @param days - Number of days ago
|
|
37
|
+
* @param from - Base date (default: 2025-06-15)
|
|
38
|
+
* @returns Date N days before the base
|
|
39
|
+
*/
|
|
40
|
+
function daysAgo(days, from = new Date('2025-06-15')) {
|
|
41
|
+
const date = new Date(from);
|
|
42
|
+
date.setDate(date.getDate() - days);
|
|
43
|
+
return date;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates a date N days from now relative to base date.
|
|
47
|
+
*/
|
|
48
|
+
function daysFromNow(days, from = new Date('2025-06-15')) {
|
|
49
|
+
const date = new Date(from);
|
|
50
|
+
date.setDate(date.getDate() + days);
|
|
51
|
+
return date;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a date is a weekend (Saturday or Sunday).
|
|
55
|
+
*/
|
|
56
|
+
function isWeekend(date) {
|
|
57
|
+
const day = date.getDay();
|
|
58
|
+
return day === 0 || day === 6;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets business days between two dates (Mon-Fri).
|
|
62
|
+
*/
|
|
63
|
+
function getBusinessDaysBetween(start, end) {
|
|
64
|
+
let count = 0;
|
|
65
|
+
const current = new Date(start);
|
|
66
|
+
while (current <= end) {
|
|
67
|
+
if (!isWeekend(current)) {
|
|
68
|
+
count++;
|
|
69
|
+
}
|
|
70
|
+
current.setDate(current.getDate() + 1);
|
|
71
|
+
}
|
|
72
|
+
return count;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Fixed "today" for deterministic tests.
|
|
76
|
+
* Use this instead of new Date() in tests.
|
|
77
|
+
*/
|
|
78
|
+
exports.TEST_TODAY = new Date('2025-06-15T12:00:00Z');
|
|
79
|
+
/**
|
|
80
|
+
* Mock Date.now() to return a fixed timestamp.
|
|
81
|
+
* Call in beforeEach and restore in afterEach.
|
|
82
|
+
*/
|
|
83
|
+
function mockDateNow(fixedDate = exports.TEST_TODAY) {
|
|
84
|
+
const originalNow = Date.now;
|
|
85
|
+
Date.now = () => fixedDate.getTime();
|
|
86
|
+
return () => {
|
|
87
|
+
Date.now = originalNow;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Converts a Date to ISO string for CommitData compatibility.
|
|
92
|
+
*/
|
|
93
|
+
function toISOString(date) {
|
|
94
|
+
return date.toISOString();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Parses an ISO date string to Date object.
|
|
98
|
+
*/
|
|
99
|
+
function parseDate(isoString) {
|
|
100
|
+
return new Date(isoString);
|
|
101
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test Helpers
|
|
4
|
+
*
|
|
5
|
+
* Central export for all test utilities.
|
|
6
|
+
*
|
|
7
|
+
* @module test/helpers
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createCommit, createCommitSequence, daysAgo } from '../test/helpers';
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
25
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
__exportStar(require("./commitFactory"), exports);
|
|
29
|
+
__exportStar(require("./dateUtils"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Global Test Setup
|
|
4
|
+
*
|
|
5
|
+
* Runs before all tests. Configure global mocks and settings here.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const vitest_1 = require("vitest");
|
|
9
|
+
const commitFactory_1 = require("./helpers/commitFactory");
|
|
10
|
+
// Reset hash counter before each test for deterministic results
|
|
11
|
+
(0, vitest_1.beforeEach)(() => {
|
|
12
|
+
(0, commitFactory_1.resetHashCounter)();
|
|
13
|
+
});
|
|
14
|
+
// Global cleanup if needed
|
|
15
|
+
(0, vitest_1.afterEach)(() => {
|
|
16
|
+
// Add any global cleanup here
|
|
17
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Smoke Test for Test Infrastructure
|
|
4
|
+
*
|
|
5
|
+
* Verifies that the test setup and helpers work correctly.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const vitest_1 = require("vitest");
|
|
9
|
+
const helpers_1 = require("./helpers");
|
|
10
|
+
const dateUtils_1 = require("./helpers/dateUtils");
|
|
11
|
+
(0, vitest_1.describe)('Test Infrastructure', () => {
|
|
12
|
+
(0, vitest_1.describe)('commitFactory', () => {
|
|
13
|
+
(0, vitest_1.it)('creates a valid commit with defaults', () => {
|
|
14
|
+
const commit = (0, helpers_1.createCommit)();
|
|
15
|
+
(0, vitest_1.expect)(commit.hash).toBeDefined();
|
|
16
|
+
(0, vitest_1.expect)(commit.author).toBe('Test Author');
|
|
17
|
+
(0, vitest_1.expect)(commit.date).toBeDefined();
|
|
18
|
+
(0, vitest_1.expect)(commit.message).toBe('test: example commit message');
|
|
19
|
+
});
|
|
20
|
+
(0, vitest_1.it)('creates a commit with overrides', () => {
|
|
21
|
+
const commit = (0, helpers_1.createCommit)({
|
|
22
|
+
author: 'Custom Author',
|
|
23
|
+
message: 'feat: custom feature',
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.expect)(commit.author).toBe('Custom Author');
|
|
26
|
+
(0, vitest_1.expect)(commit.message).toBe('feat: custom feature');
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)('creates a sequence of commits', () => {
|
|
29
|
+
const commits = (0, helpers_1.createCommitSequence)(5);
|
|
30
|
+
(0, vitest_1.expect)(commits).toHaveLength(5);
|
|
31
|
+
commits.forEach((commit, i) => {
|
|
32
|
+
(0, vitest_1.expect)(commit.hash).toBe(`hash${String(i).padStart(3, '0')}`);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.it)('creates commits on consecutive days', () => {
|
|
36
|
+
const commits = (0, helpers_1.createCommitSequence)(3, {
|
|
37
|
+
startDate: new Date('2025-06-01'),
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.expect)(new Date(commits[0].date).getDate()).toBe(1);
|
|
40
|
+
(0, vitest_1.expect)(new Date(commits[1].date).getDate()).toBe(2);
|
|
41
|
+
(0, vitest_1.expect)(new Date(commits[2].date).getDate()).toBe(3);
|
|
42
|
+
});
|
|
43
|
+
(0, vitest_1.it)('creates work week commits', () => {
|
|
44
|
+
const monday = new Date('2025-06-02'); // A Monday
|
|
45
|
+
const commits = (0, helpers_1.createWorkWeekCommits)(monday);
|
|
46
|
+
(0, vitest_1.expect)(commits).toHaveLength(5);
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)('creates commits by hour', () => {
|
|
49
|
+
const commits = (0, helpers_1.createCommitsByHour)({ 9: 2, 14: 3 });
|
|
50
|
+
(0, vitest_1.expect)(commits).toHaveLength(5);
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)('creates conventional commits', () => {
|
|
53
|
+
const commits = (0, helpers_1.createConventionalCommits)({
|
|
54
|
+
feat: 2,
|
|
55
|
+
fix: 1,
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.expect)(commits).toHaveLength(3);
|
|
58
|
+
(0, vitest_1.expect)(commits.filter((c) => c.message.startsWith('feat:'))).toHaveLength(2);
|
|
59
|
+
(0, vitest_1.expect)(commits.filter((c) => c.message.startsWith('fix:'))).toHaveLength(1);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.describe)('dateUtils', () => {
|
|
63
|
+
(0, vitest_1.it)('TEST_TODAY is a fixed date', () => {
|
|
64
|
+
(0, vitest_1.expect)(dateUtils_1.TEST_TODAY).toEqual(new Date('2025-06-15T12:00:00Z'));
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.it)('getMonday returns the Monday of a week', () => {
|
|
67
|
+
const wednesday = new Date('2025-06-11'); // Wednesday
|
|
68
|
+
const monday = (0, dateUtils_1.getMonday)(wednesday);
|
|
69
|
+
(0, vitest_1.expect)(monday.getDay()).toBe(1); // Monday
|
|
70
|
+
(0, vitest_1.expect)(monday.getDate()).toBe(9); // June 9, 2025
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.it)('daysAgo calculates correct date', () => {
|
|
73
|
+
const result = (0, dateUtils_1.daysAgo)(5, new Date('2025-06-15'));
|
|
74
|
+
(0, vitest_1.expect)(result.getDate()).toBe(10);
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)('daysFromNow calculates correct date', () => {
|
|
77
|
+
const result = (0, dateUtils_1.daysFromNow)(5, new Date('2025-06-15'));
|
|
78
|
+
(0, vitest_1.expect)(result.getDate()).toBe(20);
|
|
79
|
+
});
|
|
80
|
+
(0, vitest_1.it)('isWeekend detects weekends correctly', () => {
|
|
81
|
+
const saturday = new Date('2025-06-14');
|
|
82
|
+
const sunday = new Date('2025-06-15');
|
|
83
|
+
const monday = new Date('2025-06-16');
|
|
84
|
+
(0, vitest_1.expect)((0, dateUtils_1.isWeekend)(saturday)).toBe(true);
|
|
85
|
+
(0, vitest_1.expect)((0, dateUtils_1.isWeekend)(sunday)).toBe(true);
|
|
86
|
+
(0, vitest_1.expect)((0, dateUtils_1.isWeekend)(monday)).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)('getBusinessDaysBetween counts correctly', () => {
|
|
89
|
+
const start = new Date('2025-06-09'); // Monday
|
|
90
|
+
const end = new Date('2025-06-13'); // Friday
|
|
91
|
+
(0, vitest_1.expect)((0, dateUtils_1.getBusinessDaysBetween)(start, end)).toBe(5);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
package/dist/types/index.js
CHANGED
|
@@ -1,2 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Type definitions for repo-wrapped.
|
|
4
|
+
*
|
|
5
|
+
* This module re-exports all types for backward compatibility.
|
|
6
|
+
* For new code, consider importing from specific domain modules:
|
|
7
|
+
*
|
|
8
|
+
* - `./shared` - Shared type aliases (RiskLevel, TrendDirection, etc.)
|
|
9
|
+
* - `./core` - Core data structures (CommitData, StreakData, etc.)
|
|
10
|
+
* - `./analysis` - File analysis types (FileHotspot, ImpactAnalysis, etc.)
|
|
11
|
+
* - `../features/achievements` - Achievement system types
|
|
12
|
+
* - `./strategic` - Strategic insights (Velocity, Gaps, Team, etc.)
|
|
13
|
+
* - `./summary` - Year-in-code summary types
|
|
14
|
+
* - `./options` - CLI and generation options
|
|
15
|
+
*
|
|
16
|
+
* @module types
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
30
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
31
|
+
};
|
|
2
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
// Re-export all types for backward compatibility
|
|
34
|
+
__exportStar(require("./shared"), exports);
|
|
35
|
+
__exportStar(require("./core"), exports);
|
|
36
|
+
__exportStar(require("./analysis"), exports);
|
|
37
|
+
__exportStar(require("../features/achievements/types"), exports);
|
|
38
|
+
__exportStar(require("./strategic"), exports);
|
|
39
|
+
__exportStar(require("./summary"), exports);
|
|
40
|
+
__exportStar(require("./options"), exports);
|