@muverse/core 0.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.
Files changed (117) hide show
  1. package/README.md +22 -0
  2. package/dist/adapters/gradle/constants.d.ts +13 -0
  3. package/dist/adapters/gradle/constants.d.ts.map +1 -0
  4. package/dist/adapters/gradle/constants.js +12 -0
  5. package/dist/adapters/gradle/gradle-project-information.d.ts +18 -0
  6. package/dist/adapters/gradle/gradle-project-information.d.ts.map +1 -0
  7. package/dist/adapters/gradle/gradle-project-information.js +93 -0
  8. package/dist/adapters/gradle/gradle-properties.d.ts +15 -0
  9. package/dist/adapters/gradle/gradle-properties.d.ts.map +1 -0
  10. package/dist/adapters/gradle/gradle-properties.js +46 -0
  11. package/dist/adapters/gradle/init-project-information.gradle.kts +143 -0
  12. package/dist/adapters/gradle/services/gradle-adapter-identifier.d.ts +21 -0
  13. package/dist/adapters/gradle/services/gradle-adapter-identifier.d.ts.map +1 -0
  14. package/dist/adapters/gradle/services/gradle-adapter-identifier.js +44 -0
  15. package/dist/adapters/gradle/services/gradle-module-detector.d.ts +18 -0
  16. package/dist/adapters/gradle/services/gradle-module-detector.d.ts.map +1 -0
  17. package/dist/adapters/gradle/services/gradle-module-detector.js +26 -0
  18. package/dist/adapters/gradle/services/gradle-module-system-factory.d.ts +23 -0
  19. package/dist/adapters/gradle/services/gradle-module-system-factory.d.ts.map +1 -0
  20. package/dist/adapters/gradle/services/gradle-module-system-factory.js +27 -0
  21. package/dist/adapters/gradle/services/gradle-version-update-strategy.d.ts +21 -0
  22. package/dist/adapters/gradle/services/gradle-version-update-strategy.d.ts.map +1 -0
  23. package/dist/adapters/gradle/services/gradle-version-update-strategy.js +36 -0
  24. package/dist/adapters/project-information.d.ts +58 -0
  25. package/dist/adapters/project-information.d.ts.map +1 -0
  26. package/dist/adapters/project-information.js +1 -0
  27. package/dist/changelog/index.d.ts +27 -0
  28. package/dist/changelog/index.d.ts.map +1 -0
  29. package/dist/changelog/index.js +204 -0
  30. package/dist/config/index.d.ts +122 -0
  31. package/dist/config/index.d.ts.map +1 -0
  32. package/dist/config/index.js +115 -0
  33. package/dist/factories/adapter-identifier-registry.d.ts +12 -0
  34. package/dist/factories/adapter-identifier-registry.d.ts.map +1 -0
  35. package/dist/factories/adapter-identifier-registry.js +24 -0
  36. package/dist/factories/module-system-factory.d.ts +10 -0
  37. package/dist/factories/module-system-factory.d.ts.map +1 -0
  38. package/dist/factories/module-system-factory.js +18 -0
  39. package/dist/git/index.d.ts +253 -0
  40. package/dist/git/index.d.ts.map +1 -0
  41. package/dist/git/index.js +581 -0
  42. package/dist/index.d.ts +23 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +22 -0
  45. package/dist/semver/index.d.ts +85 -0
  46. package/dist/semver/index.d.ts.map +1 -0
  47. package/dist/semver/index.js +176 -0
  48. package/dist/services/adapter-identifier-registry.d.ts +38 -0
  49. package/dist/services/adapter-identifier-registry.d.ts.map +1 -0
  50. package/dist/services/adapter-identifier-registry.js +59 -0
  51. package/dist/services/adapter-identifier.d.ts +31 -0
  52. package/dist/services/adapter-identifier.d.ts.map +1 -0
  53. package/dist/services/adapter-identifier.js +1 -0
  54. package/dist/services/adapter-metadata-provider.d.ts +51 -0
  55. package/dist/services/adapter-metadata-provider.d.ts.map +1 -0
  56. package/dist/services/adapter-metadata-provider.js +66 -0
  57. package/dist/services/changelog-generator.d.ts +13 -0
  58. package/dist/services/changelog-generator.d.ts.map +1 -0
  59. package/dist/services/changelog-generator.js +26 -0
  60. package/dist/services/commit-analyzer.d.ts +44 -0
  61. package/dist/services/commit-analyzer.d.ts.map +1 -0
  62. package/dist/services/commit-analyzer.js +86 -0
  63. package/dist/services/configuration-loader.d.ts +23 -0
  64. package/dist/services/configuration-loader.d.ts.map +1 -0
  65. package/dist/services/configuration-loader.js +79 -0
  66. package/dist/services/configuration-validator.d.ts +16 -0
  67. package/dist/services/configuration-validator.d.ts.map +1 -0
  68. package/dist/services/configuration-validator.js +24 -0
  69. package/dist/services/git-operations.d.ts +16 -0
  70. package/dist/services/git-operations.d.ts.map +1 -0
  71. package/dist/services/git-operations.js +89 -0
  72. package/dist/services/module-detector.d.ts +24 -0
  73. package/dist/services/module-detector.d.ts.map +1 -0
  74. package/dist/services/module-detector.js +1 -0
  75. package/dist/services/module-registry.d.ts +45 -0
  76. package/dist/services/module-registry.d.ts.map +1 -0
  77. package/dist/services/module-registry.js +57 -0
  78. package/dist/services/module-system-factory.d.ts +24 -0
  79. package/dist/services/module-system-factory.d.ts.map +1 -0
  80. package/dist/services/module-system-factory.js +1 -0
  81. package/dist/services/verse-runner.d.ts +45 -0
  82. package/dist/services/verse-runner.d.ts.map +1 -0
  83. package/dist/services/verse-runner.js +182 -0
  84. package/dist/services/version-applier.d.ts +26 -0
  85. package/dist/services/version-applier.d.ts.map +1 -0
  86. package/dist/services/version-applier.js +63 -0
  87. package/dist/services/version-bumper.d.ts +156 -0
  88. package/dist/services/version-bumper.d.ts.map +1 -0
  89. package/dist/services/version-bumper.js +291 -0
  90. package/dist/services/version-manager.d.ts +68 -0
  91. package/dist/services/version-manager.d.ts.map +1 -0
  92. package/dist/services/version-manager.js +94 -0
  93. package/dist/services/version-update-strategy.d.ts +18 -0
  94. package/dist/services/version-update-strategy.d.ts.map +1 -0
  95. package/dist/services/version-update-strategy.js +1 -0
  96. package/dist/utils/banner.d.ts +2 -0
  97. package/dist/utils/banner.d.ts.map +1 -0
  98. package/dist/utils/banner.js +8 -0
  99. package/dist/utils/commits.d.ts +12 -0
  100. package/dist/utils/commits.d.ts.map +1 -0
  101. package/dist/utils/commits.js +24 -0
  102. package/dist/utils/file.d.ts +7 -0
  103. package/dist/utils/file.d.ts.map +1 -0
  104. package/dist/utils/file.js +19 -0
  105. package/dist/utils/index.d.ts +6 -0
  106. package/dist/utils/index.d.ts.map +1 -0
  107. package/dist/utils/index.js +5 -0
  108. package/dist/utils/logger.d.ts +14 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +22 -0
  111. package/dist/utils/properties.d.ts +16 -0
  112. package/dist/utils/properties.d.ts.map +1 -0
  113. package/dist/utils/properties.js +62 -0
  114. package/dist/utils/versioning.d.ts +8 -0
  115. package/dist/utils/versioning.d.ts.map +1 -0
  116. package/dist/utils/versioning.js +17 -0
  117. package/package.json +70 -0
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Version Bumper Service for μVERSE.
3
+ * Implements core version calculation logic: analyzes commits, cascades changes through
4
+ * dependencies, and applies versions with support for prereleases, metadata, and snapshots.
5
+ */
6
+ import { logger } from "../utils/logger.js";
7
+ import { getDependencyBumpType } from "../config/index.js";
8
+ import { calculateBumpFromCommits } from "../utils/commits.js";
9
+ import { bumpSemVer, bumpToPrerelease, formatSemVer, addBuildMetadata, generateTimestampPrereleaseId, maxBumpType, } from "../semver/index.js";
10
+ import { getCurrentCommitShortSha } from "../git/index.js";
11
+ import { applySnapshotSuffix } from "../utils/versioning.js";
12
+ /**
13
+ * Service for calculating version bumps across modules.
14
+ * Handles commit analysis, dependency cascade effects, and various versioning strategies
15
+ * (regular, prerelease, snapshot).
16
+ */
17
+ export class VersionBumper {
18
+ moduleRegistry;
19
+ options;
20
+ /**
21
+ * Creates a new VersionBumper instance.
22
+ * @param moduleRegistry - Registry containing all modules and their interdependencies
23
+ * @param options - Configuration options controlling version bump behavior
24
+ */
25
+ constructor(moduleRegistry, options) {
26
+ this.moduleRegistry = moduleRegistry;
27
+ this.options = options;
28
+ }
29
+ /**
30
+ * Calculates version bumps for all modules based on their commits.
31
+ * Orchestrates a three-phase process: initial bumps (commit analysis), cascade effects (dependency propagation),
32
+ * and version application (applying strategies like prerelease, timestamps, build metadata).
33
+ * @param moduleCommits - Map of module IDs to their commits since last version
34
+ * @returns Promise resolving to array of processed module changes (only modules that need updates)
35
+ * @throws {Error} If git operations fail
36
+ */
37
+ async calculateVersionBumps(moduleCommits) {
38
+ logger.info("🔢 Calculating version bumps from commits...");
39
+ // Generate timestamp-based prerelease ID if timestamp versions are enabled
40
+ let effectivePrereleaseId = this.options.prereleaseId;
41
+ if (this.options.timestampVersions && this.options.prereleaseMode) {
42
+ effectivePrereleaseId = generateTimestampPrereleaseId(this.options.prereleaseId);
43
+ logger.info(`🕐 Generated timestamp prerelease ID: ${effectivePrereleaseId}`);
44
+ }
45
+ // Get current commit short SHA if build metadata is enabled
46
+ let shortSha;
47
+ if (this.options.addBuildMetadata) {
48
+ shortSha = await getCurrentCommitShortSha({ cwd: this.options.repoRoot });
49
+ logger.info(`📋 Build metadata will include short SHA: ${shortSha}`);
50
+ }
51
+ // Step 1: Calculate initial bump types for all modules
52
+ const processingModuleChanges = this.calculateInitialBumps(moduleCommits);
53
+ // Step 2: Calculate cascade effects
54
+ logger.info("🌊 Calculating cascade effects...");
55
+ const cascadedChanges = this.calculateCascadeEffects(processingModuleChanges);
56
+ // Step 3: Apply version calculations and transformations
57
+ logger.info("🔢 Calculating actual versions...");
58
+ return this.applyVersionCalculations(cascadedChanges, effectivePrereleaseId, shortSha);
59
+ }
60
+ /**
61
+ * Calculates initial version bump types for all modules based on commits.
62
+ *
63
+ * This is Phase 1 of the version calculation process. It analyzes commits for each
64
+ * module to determine the required version bump type using Conventional Commits
65
+ * specification.
66
+ *
67
+ * The method creates a `ProcessingModuleChange` for **every** module in the registry,
68
+ * not just those with commits. The `needsProcessing` flag determines which modules
69
+ * will ultimately be updated.
70
+ *
71
+ * **Processing Decision Logic**:
72
+ * - Module has commits requiring bump: `needsProcessing = true, reason = 'commits'`
73
+ * - Prerelease mode with bumpUnchanged: `needsProcessing = true, reason = 'prerelease-unchanged'`
74
+ * - Build metadata enabled: `needsProcessing = true, reason = 'build-metadata'`
75
+ * - Otherwise: `needsProcessing = false, reason = 'unchanged'`
76
+ *
77
+ * @param moduleCommits - Map of module IDs to their commits since last version.
78
+ *
79
+ * @returns Array of processing module changes for all modules in the registry
80
+ */
81
+ calculateInitialBumps(moduleCommits) {
82
+ const processingModuleChanges = [];
83
+ // Iterate through ALL modules in the registry
84
+ for (const [projectId, projectInfo] of this.moduleRegistry.getModules()) {
85
+ const commits = moduleCommits.get(projectId) || [];
86
+ // Determine bump type from commits only
87
+ // Uses Conventional Commits spec to analyze commit types
88
+ const bumpType = calculateBumpFromCommits(commits, this.options.config);
89
+ // Determine processing requirements and reason
90
+ let reason = "unchanged";
91
+ let needsProcessing = false;
92
+ if (bumpType !== "none") {
93
+ // Module has commits that require version changes
94
+ needsProcessing = true;
95
+ reason = "commits";
96
+ }
97
+ else if (this.options.prereleaseMode && this.options.bumpUnchanged) {
98
+ // Prerelease mode with bumpUnchanged - include modules with no changes
99
+ needsProcessing = true;
100
+ reason = "prerelease-unchanged";
101
+ }
102
+ else if (this.options.addBuildMetadata) {
103
+ // Build metadata mode - all modules need updates for metadata
104
+ needsProcessing = true;
105
+ reason = "build-metadata";
106
+ }
107
+ // Create module change for ALL modules - processing flag determines behavior
108
+ processingModuleChanges.push({
109
+ module: projectInfo,
110
+ fromVersion: projectInfo.version,
111
+ toVersion: "", // Will be calculated later
112
+ bumpType: bumpType,
113
+ reason: reason,
114
+ needsProcessing: needsProcessing,
115
+ });
116
+ }
117
+ return processingModuleChanges;
118
+ }
119
+ /**
120
+ * Calculates cascade effects when modules change.
121
+ *
122
+ * This is Phase 2 of the version calculation process. It propagates version changes
123
+ * through the module dependency graph, ensuring that when a module changes, all
124
+ * modules that depend on it are also bumped appropriately.
125
+ *
126
+ * **Algorithm**: Uses a breadth-first traversal of the dependency graph:
127
+ * 1. Start with all modules marked for processing (needsProcessing = true)
128
+ * 2. For each module being processed, find all modules that depend on it
129
+ * 3. Calculate required bump for dependents using dependency bump rules
130
+ * 4. If dependent needs a higher bump, update it and add to processing queue
131
+ * 5. Continue until no more cascades are needed
132
+ *
133
+ * **Complexity**: O(V + E) where V = number of modules, E = number of dependencies
134
+ *
135
+ * **In-Place Modification**: This method modifies the input array in place for
136
+ * efficiency. The same array reference is returned with cascade effects applied.
137
+ *
138
+ * @param allModuleChanges - Array of all module changes (will be modified in place).
139
+ * Should include all modules from calculateInitialBumps().
140
+ *
141
+ * @returns The same array with cascade effects applied
142
+ */
143
+ calculateCascadeEffects(allModuleChanges) {
144
+ const processed = new Set();
145
+ const moduleMap = new Map();
146
+ // Create module map for O(1) lookups
147
+ for (const change of allModuleChanges) {
148
+ moduleMap.set(change.module.id, change);
149
+ }
150
+ // Start with ALL modules - treat them completely equally
151
+ const queue = [...allModuleChanges];
152
+ while (queue.length > 0) {
153
+ const currentChange = queue.shift();
154
+ // No processing needed, mark as processed
155
+ if (!currentChange.needsProcessing || currentChange.bumpType === "none") {
156
+ logger.debug(`🔄 Skipping module ${currentChange.module.id} - no processing needed`);
157
+ processed.add(currentChange.module.id);
158
+ continue;
159
+ }
160
+ // Skip if already processed
161
+ if (processed.has(currentChange.module.id)) {
162
+ logger.debug(`🔄 Skipping module ${currentChange.module.id} - already processed`);
163
+ continue;
164
+ }
165
+ // Mark as processed to avoid duplicate work
166
+ processed.add(currentChange.module.id);
167
+ const currentModuleInfo = this.moduleRegistry.getModule(currentChange.module.id);
168
+ // Iterate through all modules that depend on the current module
169
+ for (const dependentName of currentModuleInfo.affectedModules) {
170
+ logger.debug(`➡️ Processing dependent module ${dependentName} affected by ${currentChange.module.id} with bump ${currentChange.bumpType}`);
171
+ // Get the dependent module using O(1) lookup
172
+ const existingChange = moduleMap.get(dependentName);
173
+ if (!existingChange) {
174
+ logger.debug(`⚠️ Dependent module ${dependentName} not found in module changes list`);
175
+ continue; // Module not found in our module list
176
+ }
177
+ // Calculate the bump needed for the dependent
178
+ // Uses configuration rules to determine how changes propagate
179
+ const requiredBump = getDependencyBumpType(currentChange.bumpType, this.options.config);
180
+ if (requiredBump === "none") {
181
+ logger.debug(`➡️ No cascade bump needed for module ${dependentName} from ${currentChange.module.id}`);
182
+ continue; // No cascade needed
183
+ }
184
+ // Update the existing change with cascade information
185
+ // Take the maximum bump type if multiple dependencies affect this module
186
+ const mergedBump = maxBumpType([existingChange.bumpType, requiredBump]);
187
+ if (mergedBump !== existingChange.bumpType) {
188
+ logger.debug(`🔄 Cascading bump for module ${dependentName} from ${existingChange.bumpType} to ${mergedBump} due to ${currentChange.module.id}`);
189
+ // Update the module change in place
190
+ existingChange.bumpType = mergedBump;
191
+ existingChange.reason = "cascade";
192
+ existingChange.needsProcessing = true;
193
+ // Add to queue for further processing (transitive cascades)
194
+ processed.delete(dependentName); // Allow re-processing
195
+ queue.push(existingChange);
196
+ }
197
+ else {
198
+ logger.debug(`🔄 No changes needed for module ${dependentName} - already at ${existingChange.bumpType}`);
199
+ }
200
+ }
201
+ }
202
+ // Return the modified array (same reference, but with cascade effects applied)
203
+ return allModuleChanges;
204
+ }
205
+ /**
206
+ * Applies version calculations and transformations to all modules.
207
+ *
208
+ * This is Phase 3 (final) of the version calculation process. It takes modules
209
+ * with calculated bump types and applies version transformations including:
210
+ * - Semantic version bumping (major, minor, patch)
211
+ * - Prerelease version generation
212
+ * - Build metadata appending
213
+ * - Snapshot suffix appending
214
+ *
215
+ * **Version Application Scenarios**:
216
+ * 1. **Commits + Regular Mode**: Bump semantic version normally
217
+ * 2. **Commits + Prerelease Mode**: Bump to prerelease version
218
+ * 3. **No Commits + Prerelease + bumpUnchanged**: Force prerelease bump
219
+ * 4. **Build Metadata Mode**: Append git SHA as metadata
220
+ * 5. **Snapshot Mode**: Append -SNAPSHOT suffix
221
+ *
222
+ * @param processingModuleChanges - All module changes with calculated bump types
223
+ * from cascade effects phase.
224
+ *
225
+ * @param effectivePrereleaseId - Prerelease identifier to use (may include timestamp).
226
+ * Example: 'alpha', 'alpha.20251021143022'
227
+ *
228
+ * @param shortSha - Optional git commit short SHA for build metadata.
229
+ * Example: 'a1b2c3d'
230
+ *
231
+ * @returns Array of processed module changes ready for application (only modules with needsProcessing = true)
232
+ */
233
+ applyVersionCalculations(processingModuleChanges, effectivePrereleaseId, shortSha) {
234
+ const processedModuleChanges = [];
235
+ for (const change of processingModuleChanges) {
236
+ let newVersion = change.fromVersion;
237
+ // Only apply version changes if module needs processing
238
+ if (change.needsProcessing) {
239
+ // Apply version bumps based on module state
240
+ if (change.bumpType !== "none" && this.options.prereleaseMode) {
241
+ // Scenario 1: Commits with changes in prerelease mode
242
+ // Bump semantic version AND add prerelease identifier
243
+ newVersion = bumpToPrerelease(change.fromVersion, change.bumpType, effectivePrereleaseId);
244
+ }
245
+ else if (change.bumpType !== "none" && !this.options.prereleaseMode) {
246
+ // Scenario 2: Commits with changes in normal mode
247
+ // Standard semantic version bump (major.minor.patch)
248
+ newVersion = bumpSemVer(change.fromVersion, change.bumpType);
249
+ }
250
+ else if (change.reason === "prerelease-unchanged") {
251
+ // Scenario 3: No changes but force prerelease bump (bumpUnchanged enabled)
252
+ // Keep semantic version, just add prerelease identifier
253
+ newVersion = bumpToPrerelease(change.fromVersion, "none", effectivePrereleaseId);
254
+ }
255
+ // Scenario 4: reason === 'build-metadata' or 'unchanged' - no version bump, keep fromVersion
256
+ // Add build metadata if enabled (applies to all scenarios)
257
+ // Build metadata doesn't affect version precedence per semver spec
258
+ if (this.options.addBuildMetadata && shortSha) {
259
+ newVersion = addBuildMetadata(newVersion, shortSha);
260
+ }
261
+ }
262
+ // Convert to string version
263
+ change.toVersion = formatSemVer(newVersion);
264
+ // Apply append snapshot suffix if enabled (to all modules in append mode)
265
+ if (this.options.appendSnapshot &&
266
+ this.options.adapter.capabilities.supportsSnapshots) {
267
+ const originalVersion = change.toVersion;
268
+ change.toVersion = applySnapshotSuffix(change.toVersion);
269
+ // If snapshot suffix was actually added and module wasn't already being processed, mark it for processing
270
+ if (!change.needsProcessing && change.toVersion !== originalVersion) {
271
+ change.needsProcessing = true;
272
+ change.reason = "gradle-snapshot";
273
+ }
274
+ }
275
+ // Add to update collection only if module needs processing
276
+ if (change.needsProcessing) {
277
+ // Convert to ProcessedModuleChange since we know needsProcessing is true
278
+ const processedChange = {
279
+ module: change.module,
280
+ fromVersion: change.fromVersion,
281
+ toVersion: change.toVersion,
282
+ bumpType: change.bumpType,
283
+ reason: change.reason, // Safe cast since needsProcessing is true
284
+ };
285
+ processedModuleChanges.push(processedChange);
286
+ }
287
+ }
288
+ logger.info(`📈 Calculated versions for ${processedModuleChanges.length} modules requiring updates`);
289
+ return processedModuleChanges;
290
+ }
291
+ }
@@ -0,0 +1,68 @@
1
+ import { SemVer } from "semver";
2
+ import { ModuleRegistry } from "./module-registry.js";
3
+ import { VersionUpdateStrategy } from "./version-update-strategy.js";
4
+ /**
5
+ * Manages version updates for modules with staged commits and batch persistence.
6
+ *
7
+ * @remarks
8
+ * Implements a two-phase update strategy:
9
+ * 1. Stage updates in memory via `updateVersion()`
10
+ * 2. Persist all updates via `commit()`
11
+ *
12
+ * Uses {@link VersionUpdateStrategy} for build system-specific operations.
13
+ * Validates modules against {@link ModuleRegistry}.
14
+ */
15
+ export declare class VersionManager {
16
+ private readonly hierarchyManager;
17
+ private readonly strategy;
18
+ /** Pending version updates awaiting commit (module ID → version string). */
19
+ private readonly pendingUpdates;
20
+ /**
21
+ * Creates a new VersionManager.
22
+ *
23
+ * @param hierarchyManager - Module registry for validation
24
+ * @param strategy - Build system-specific strategy for writing updates
25
+ */
26
+ constructor(hierarchyManager: ModuleRegistry, strategy: VersionUpdateStrategy);
27
+ /**
28
+ * Stages a version update for a module without persisting to files.
29
+ *
30
+ * @param moduleId - Module identifier (e.g., `':'`, `':core'`)
31
+ * @param newVersion - New version as SemVer object or string
32
+ * @throws {Error} If module ID doesn't exist in registry
33
+ */
34
+ updateVersion(moduleId: string, newVersion: SemVer | string): void;
35
+ /**
36
+ * Commits all pending version updates to build files in a single batch operation.
37
+ *
38
+ * @returns Promise that resolves when all updates are written
39
+ * @throws {Error} If file operations fail (specific errors depend on strategy)
40
+ */
41
+ commit(): Promise<void>;
42
+ /**
43
+ * Returns a copy of all pending updates that haven't been committed.
44
+ *
45
+ * @returns Map of module ID to version string
46
+ */
47
+ getPendingUpdates(): Map<string, string>;
48
+ /**
49
+ * Checks whether there are any pending updates awaiting commit.
50
+ *
51
+ * @returns `true` if updates are staged, `false` otherwise
52
+ */
53
+ hasPendingUpdates(): boolean;
54
+ /**
55
+ * Clears all pending updates without committing them.
56
+ *
57
+ * @remarks
58
+ * Use with caution - this operation cannot be undone.
59
+ */
60
+ clearPendingUpdates(): void;
61
+ /**
62
+ * Gets the number of pending updates in the queue.
63
+ *
64
+ * @returns The count of pending updates that have not been processed yet.
65
+ */
66
+ getPendingUpdatesCount(): number;
67
+ }
68
+ //# sourceMappingURL=version-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-manager.d.ts","sourceRoot":"","sources":["../../src/services/version-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAGrE;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IAWvB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D;;;;;OAKG;gBAEgB,gBAAgB,EAAE,cAAc,EAChC,QAAQ,EAAE,qBAAqB;IAGlD;;;;;;OAMG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAclE;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAa7B;;;;OAIG;IACH,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIxC;;;;OAIG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;;;;OAKG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;;;OAIG;IACH,sBAAsB,IAAI,MAAM;CAGjC"}
@@ -0,0 +1,94 @@
1
+ import { formatSemVer } from "../semver/index.js";
2
+ /**
3
+ * Manages version updates for modules with staged commits and batch persistence.
4
+ *
5
+ * @remarks
6
+ * Implements a two-phase update strategy:
7
+ * 1. Stage updates in memory via `updateVersion()`
8
+ * 2. Persist all updates via `commit()`
9
+ *
10
+ * Uses {@link VersionUpdateStrategy} for build system-specific operations.
11
+ * Validates modules against {@link ModuleRegistry}.
12
+ */
13
+ export class VersionManager {
14
+ hierarchyManager;
15
+ strategy;
16
+ /** Pending version updates awaiting commit (module ID → version string). */
17
+ pendingUpdates = new Map();
18
+ /**
19
+ * Creates a new VersionManager.
20
+ *
21
+ * @param hierarchyManager - Module registry for validation
22
+ * @param strategy - Build system-specific strategy for writing updates
23
+ */
24
+ constructor(hierarchyManager, strategy) {
25
+ this.hierarchyManager = hierarchyManager;
26
+ this.strategy = strategy;
27
+ }
28
+ /**
29
+ * Stages a version update for a module without persisting to files.
30
+ *
31
+ * @param moduleId - Module identifier (e.g., `':'`, `':core'`)
32
+ * @param newVersion - New version as SemVer object or string
33
+ * @throws {Error} If module ID doesn't exist in registry
34
+ */
35
+ updateVersion(moduleId, newVersion) {
36
+ // Validate module exists in registry
37
+ if (!this.hierarchyManager.hasModule(moduleId)) {
38
+ throw new Error(`Module ${moduleId} not found`);
39
+ }
40
+ // Convert SemVer to string if needed, otherwise use string directly
41
+ const versionString = typeof newVersion === "string" ? newVersion : formatSemVer(newVersion);
42
+ // Store update in pending updates map
43
+ this.pendingUpdates.set(moduleId, versionString);
44
+ }
45
+ /**
46
+ * Commits all pending version updates to build files in a single batch operation.
47
+ *
48
+ * @returns Promise that resolves when all updates are written
49
+ * @throws {Error} If file operations fail (specific errors depend on strategy)
50
+ */
51
+ async commit() {
52
+ // Early return if nothing to commit
53
+ if (this.pendingUpdates.size === 0) {
54
+ return; // Nothing to commit
55
+ }
56
+ // Write all version updates using build system-specific strategy
57
+ await this.strategy.writeVersionUpdates(this.pendingUpdates);
58
+ // Clear the pending updates after successful commit
59
+ this.pendingUpdates.clear();
60
+ }
61
+ /**
62
+ * Returns a copy of all pending updates that haven't been committed.
63
+ *
64
+ * @returns Map of module ID to version string
65
+ */
66
+ getPendingUpdates() {
67
+ return new Map(this.pendingUpdates);
68
+ }
69
+ /**
70
+ * Checks whether there are any pending updates awaiting commit.
71
+ *
72
+ * @returns `true` if updates are staged, `false` otherwise
73
+ */
74
+ hasPendingUpdates() {
75
+ return this.pendingUpdates.size > 0;
76
+ }
77
+ /**
78
+ * Clears all pending updates without committing them.
79
+ *
80
+ * @remarks
81
+ * Use with caution - this operation cannot be undone.
82
+ */
83
+ clearPendingUpdates() {
84
+ this.pendingUpdates.clear();
85
+ }
86
+ /**
87
+ * Gets the number of pending updates in the queue.
88
+ *
89
+ * @returns The count of pending updates that have not been processed yet.
90
+ */
91
+ getPendingUpdatesCount() {
92
+ return this.pendingUpdates.size;
93
+ }
94
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Strategy for writing version updates to build system-specific files.
3
+ *
4
+ * @remarks
5
+ * Implementations handle version persistence for different build systems (Gradle, Maven, npm).
6
+ * Created by {@link ModuleSystemFactory} and used by {@link VersionManager}.
7
+ */
8
+ export interface VersionUpdateStrategy {
9
+ /**
10
+ * Writes version updates for multiple modules to build system configuration files.
11
+ *
12
+ * @param moduleVersions - Map of module ID to new version string
13
+ * @returns Promise that resolves when all updates are written
14
+ * @throws {Error} If build files cannot be found, are not writable, or I/O operations fail
15
+ */
16
+ writeVersionUpdates(moduleVersions: Map<string, string>): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=version-update-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-update-strategy.d.ts","sourceRoot":"","sources":["../../src/services/version-update-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,mBAAmB,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const banner: string;
2
+ //# sourceMappingURL=banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../src/utils/banner.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,EAAE,MAOpB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export const banner = `
2
+ ██╗ ██╗███████╗██████╗ ███████╗███████╗
3
+ ██║ ██║██╔════╝██╔══██╗██╔════╝██╔════╝
4
+ ██║ ██║█████╗ ██████╔╝███████╗█████╗
5
+ ╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║██╔══╝
6
+ ╚████╔╝ ███████╗██║ ██║███████║███████╗
7
+ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝
8
+ `;
@@ -0,0 +1,12 @@
1
+ import { Config } from "../config/index.js";
2
+ import { CommitInfo } from "../git/index.js";
3
+ import { BumpType } from "../semver/index.js";
4
+ /**
5
+ * Calculates the overall semantic version bump type from a collection of commits.
6
+ * Returns the highest bump type: major > minor > patch > none.
7
+ * @param commits - Array of commit information to analyze
8
+ * @param config - Configuration containing commit type mappings
9
+ * @returns The highest BumpType required across all commits
10
+ */
11
+ export declare function calculateBumpFromCommits(commits: CommitInfo[], config: Config): BumpType;
12
+ //# sourceMappingURL=commits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commits.d.ts","sourceRoot":"","sources":["../../src/utils/commits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAe,MAAM,oBAAoB,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,UAAU,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,QAAQ,CAiBV"}
@@ -0,0 +1,24 @@
1
+ import { getBumpTypeForCommit } from "../config/index.js";
2
+ import { maxBumpType } from "../semver/index.js";
3
+ /**
4
+ * Calculates the overall semantic version bump type from a collection of commits.
5
+ * Returns the highest bump type: major > minor > patch > none.
6
+ * @param commits - Array of commit information to analyze
7
+ * @param config - Configuration containing commit type mappings
8
+ * @returns The highest BumpType required across all commits
9
+ */
10
+ export function calculateBumpFromCommits(commits, config) {
11
+ // Collect bump types for all commits
12
+ const bumpTypes = [];
13
+ // Analyze each commit and determine its version impact
14
+ for (const commit of commits) {
15
+ const bumpType = getBumpTypeForCommit(commit.type, commit.breaking, config);
16
+ // Only include commits that require a version bump
17
+ if (bumpType !== "none") {
18
+ bumpTypes.push(bumpType);
19
+ }
20
+ }
21
+ // Return the highest bump type required across all commits
22
+ // If no meaningful commits found, returns 'none'
23
+ return maxBumpType(bumpTypes);
24
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Checks whether a file or directory exists at the specified path.
3
+ * @param path - Absolute or relative path to check
4
+ * @returns True if the path exists and is accessible, false otherwise
5
+ */
6
+ export declare function exists(path: string): Promise<boolean>;
7
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3D"}
@@ -0,0 +1,19 @@
1
+ import { promises as fs } from "fs";
2
+ /**
3
+ * Checks whether a file or directory exists at the specified path.
4
+ * @param path - Absolute or relative path to check
5
+ * @returns True if the path exists and is accessible, false otherwise
6
+ */
7
+ export async function exists(path) {
8
+ try {
9
+ // Attempt to access the path
10
+ // If access succeeds, the path exists and is accessible
11
+ await fs.access(path);
12
+ return true;
13
+ }
14
+ catch {
15
+ // If access fails (any error), consider path as non-existent
16
+ // This includes ENOENT (doesn't exist) and EACCES (no permission)
17
+ return false;
18
+ }
19
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./commits.js";
2
+ export * from "./file.js";
3
+ export * from "./properties.js";
4
+ export * from "./versioning.js";
5
+ export * from "./logger.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from "./commits.js";
2
+ export * from "./file.js";
3
+ export * from "./properties.js";
4
+ export * from "./versioning.js";
5
+ export * from "./logger.js";
@@ -0,0 +1,14 @@
1
+ export interface Logger {
2
+ debug(message: string): void;
3
+ info(message: string): void;
4
+ warning(message: string | Error, context?: Record<string, unknown>): void;
5
+ error(message: string | Error, context?: Record<string, unknown>): void;
6
+ }
7
+ export declare function initLogger(logger: Logger): void;
8
+ /**
9
+ * Convenience proxy so existing call sites can
10
+ * import `logger` and call methods. The proxy delegates
11
+ * to the mutable `_current` at call-time.
12
+ */
13
+ export declare const logger: Logger;
14
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1E,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACzE;AAYD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,QAExC;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,MAOpB,CAAC"}
@@ -0,0 +1,22 @@
1
+ // default no-op
2
+ const noopLogger = {
3
+ debug: (_message) => { },
4
+ info: (_message) => { },
5
+ warning: (_message, _context) => { },
6
+ error: (_message, _context) => { },
7
+ };
8
+ let _current = noopLogger;
9
+ export function initLogger(logger) {
10
+ _current = logger;
11
+ }
12
+ /**
13
+ * Convenience proxy so existing call sites can
14
+ * import `logger` and call methods. The proxy delegates
15
+ * to the mutable `_current` at call-time.
16
+ */
17
+ export const logger = {
18
+ debug: (message) => _current.debug(message),
19
+ info: (message) => _current.info(message),
20
+ warning: (message, context) => _current.warning(message, context),
21
+ error: (message, context) => _current.error(message, context),
22
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Updates or inserts a single property in a Java-style properties file.
3
+ * @param propertiesPath - Path to the properties file
4
+ * @param key - Property key to update or insert
5
+ * @param value - Property value to set
6
+ */
7
+ export declare function upsertProperty(propertiesPath: string, key: string, value: string): Promise<void>;
8
+ /**
9
+ * Updates or inserts multiple properties in a Java-style properties file.
10
+ * Updates existing properties in place, appends new ones to the end.
11
+ * @param propertiesPath - Path to the properties file
12
+ * @param properties - Map of property keys to values
13
+ * @throws {Error} If file operations fail
14
+ */
15
+ export declare function upsertProperties(propertiesPath: string, properties: Map<string, string>): Promise<void>;
16
+ //# sourceMappingURL=properties.d.ts.map