@fuzdev/fuz_gitops 0.57.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 (190) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/ModulesDetail.svelte +180 -0
  4. package/dist/ModulesDetail.svelte.d.ts +10 -0
  5. package/dist/ModulesDetail.svelte.d.ts.map +1 -0
  6. package/dist/ModulesNav.svelte +43 -0
  7. package/dist/ModulesNav.svelte.d.ts +11 -0
  8. package/dist/ModulesNav.svelte.d.ts.map +1 -0
  9. package/dist/ModulesPage.svelte +50 -0
  10. package/dist/ModulesPage.svelte.d.ts +9 -0
  11. package/dist/ModulesPage.svelte.d.ts.map +1 -0
  12. package/dist/PageFooter.svelte +15 -0
  13. package/dist/PageFooter.svelte.d.ts +19 -0
  14. package/dist/PageFooter.svelte.d.ts.map +1 -0
  15. package/dist/PageHeader.svelte +35 -0
  16. package/dist/PageHeader.svelte.d.ts +19 -0
  17. package/dist/PageHeader.svelte.d.ts.map +1 -0
  18. package/dist/PullRequestsDetail.svelte +53 -0
  19. package/dist/PullRequestsDetail.svelte.d.ts +10 -0
  20. package/dist/PullRequestsDetail.svelte.d.ts.map +1 -0
  21. package/dist/PullRequestsPage.svelte +47 -0
  22. package/dist/PullRequestsPage.svelte.d.ts +11 -0
  23. package/dist/PullRequestsPage.svelte.d.ts.map +1 -0
  24. package/dist/ReposTable.svelte +189 -0
  25. package/dist/ReposTable.svelte.d.ts +9 -0
  26. package/dist/ReposTable.svelte.d.ts.map +1 -0
  27. package/dist/ReposTree.svelte +88 -0
  28. package/dist/ReposTree.svelte.d.ts +11 -0
  29. package/dist/ReposTree.svelte.d.ts.map +1 -0
  30. package/dist/ReposTreeNav.svelte +55 -0
  31. package/dist/ReposTreeNav.svelte.d.ts +11 -0
  32. package/dist/ReposTreeNav.svelte.d.ts.map +1 -0
  33. package/dist/TablePage.svelte +46 -0
  34. package/dist/TablePage.svelte.d.ts +9 -0
  35. package/dist/TablePage.svelte.d.ts.map +1 -0
  36. package/dist/TreeItemPage.svelte +75 -0
  37. package/dist/TreeItemPage.svelte.d.ts +10 -0
  38. package/dist/TreeItemPage.svelte.d.ts.map +1 -0
  39. package/dist/TreePage.svelte +64 -0
  40. package/dist/TreePage.svelte.d.ts +9 -0
  41. package/dist/TreePage.svelte.d.ts.map +1 -0
  42. package/dist/changeset_generator.d.ts +38 -0
  43. package/dist/changeset_generator.d.ts.map +1 -0
  44. package/dist/changeset_generator.js +110 -0
  45. package/dist/changeset_reader.d.ts +75 -0
  46. package/dist/changeset_reader.d.ts.map +1 -0
  47. package/dist/changeset_reader.js +167 -0
  48. package/dist/constants.d.ts +9 -0
  49. package/dist/constants.d.ts.map +1 -0
  50. package/dist/constants.js +8 -0
  51. package/dist/dependency_graph.d.ts +120 -0
  52. package/dist/dependency_graph.d.ts.map +1 -0
  53. package/dist/dependency_graph.js +341 -0
  54. package/dist/dependency_updater.d.ts +46 -0
  55. package/dist/dependency_updater.d.ts.map +1 -0
  56. package/dist/dependency_updater.js +213 -0
  57. package/dist/fetch_repo_data.d.ts +19 -0
  58. package/dist/fetch_repo_data.d.ts.map +1 -0
  59. package/dist/fetch_repo_data.js +49 -0
  60. package/dist/fs_fetch_value_cache.d.ts +24 -0
  61. package/dist/fs_fetch_value_cache.d.ts.map +1 -0
  62. package/dist/fs_fetch_value_cache.js +61 -0
  63. package/dist/git_operations.d.ts +54 -0
  64. package/dist/git_operations.d.ts.map +1 -0
  65. package/dist/git_operations.js +144 -0
  66. package/dist/github.d.ts +91 -0
  67. package/dist/github.d.ts.map +1 -0
  68. package/dist/github.js +94 -0
  69. package/dist/github_helpers.d.ts +10 -0
  70. package/dist/github_helpers.d.ts.map +1 -0
  71. package/dist/github_helpers.js +13 -0
  72. package/dist/gitops_analyze.task.d.ts +17 -0
  73. package/dist/gitops_analyze.task.d.ts.map +1 -0
  74. package/dist/gitops_analyze.task.js +188 -0
  75. package/dist/gitops_config.d.ts +56 -0
  76. package/dist/gitops_config.d.ts.map +1 -0
  77. package/dist/gitops_config.js +63 -0
  78. package/dist/gitops_plan.task.d.ts +28 -0
  79. package/dist/gitops_plan.task.d.ts.map +1 -0
  80. package/dist/gitops_plan.task.js +217 -0
  81. package/dist/gitops_publish.task.d.ts +29 -0
  82. package/dist/gitops_publish.task.d.ts.map +1 -0
  83. package/dist/gitops_publish.task.js +178 -0
  84. package/dist/gitops_sync.task.d.ts +18 -0
  85. package/dist/gitops_sync.task.d.ts.map +1 -0
  86. package/dist/gitops_sync.task.js +95 -0
  87. package/dist/gitops_task_helpers.d.ts +63 -0
  88. package/dist/gitops_task_helpers.d.ts.map +1 -0
  89. package/dist/gitops_task_helpers.js +84 -0
  90. package/dist/gitops_validate.task.d.ts +12 -0
  91. package/dist/gitops_validate.task.d.ts.map +1 -0
  92. package/dist/gitops_validate.task.js +210 -0
  93. package/dist/graph_validation.d.ts +39 -0
  94. package/dist/graph_validation.d.ts.map +1 -0
  95. package/dist/graph_validation.js +79 -0
  96. package/dist/local_repo.d.ts +84 -0
  97. package/dist/local_repo.d.ts.map +1 -0
  98. package/dist/local_repo.js +213 -0
  99. package/dist/log_helpers.d.ts +43 -0
  100. package/dist/log_helpers.d.ts.map +1 -0
  101. package/dist/log_helpers.js +98 -0
  102. package/dist/multi_repo_publisher.d.ts +34 -0
  103. package/dist/multi_repo_publisher.d.ts.map +1 -0
  104. package/dist/multi_repo_publisher.js +364 -0
  105. package/dist/npm_install_helpers.d.ts +23 -0
  106. package/dist/npm_install_helpers.d.ts.map +1 -0
  107. package/dist/npm_install_helpers.js +60 -0
  108. package/dist/npm_registry.d.ts +46 -0
  109. package/dist/npm_registry.d.ts.map +1 -0
  110. package/dist/npm_registry.js +96 -0
  111. package/dist/operations.d.ts +409 -0
  112. package/dist/operations.d.ts.map +1 -0
  113. package/dist/operations.js +34 -0
  114. package/dist/operations_defaults.d.ts +19 -0
  115. package/dist/operations_defaults.d.ts.map +1 -0
  116. package/dist/operations_defaults.js +279 -0
  117. package/dist/output_helpers.d.ts +27 -0
  118. package/dist/output_helpers.d.ts.map +1 -0
  119. package/dist/output_helpers.js +39 -0
  120. package/dist/paths.d.ts +11 -0
  121. package/dist/paths.d.ts.map +1 -0
  122. package/dist/paths.js +10 -0
  123. package/dist/preflight_checks.d.ts +47 -0
  124. package/dist/preflight_checks.d.ts.map +1 -0
  125. package/dist/preflight_checks.js +181 -0
  126. package/dist/publishing_plan.d.ts +100 -0
  127. package/dist/publishing_plan.d.ts.map +1 -0
  128. package/dist/publishing_plan.js +353 -0
  129. package/dist/publishing_plan_helpers.d.ts +30 -0
  130. package/dist/publishing_plan_helpers.d.ts.map +1 -0
  131. package/dist/publishing_plan_helpers.js +112 -0
  132. package/dist/publishing_plan_logging.d.ts +18 -0
  133. package/dist/publishing_plan_logging.d.ts.map +1 -0
  134. package/dist/publishing_plan_logging.js +342 -0
  135. package/dist/repo.svelte.d.ts +52 -0
  136. package/dist/repo.svelte.d.ts.map +1 -0
  137. package/dist/repo.svelte.js +70 -0
  138. package/dist/repo_ops.d.ts +57 -0
  139. package/dist/repo_ops.d.ts.map +1 -0
  140. package/dist/repo_ops.js +167 -0
  141. package/dist/resolved_gitops_config.d.ts +9 -0
  142. package/dist/resolved_gitops_config.d.ts.map +1 -0
  143. package/dist/resolved_gitops_config.js +12 -0
  144. package/dist/semver.d.ts +24 -0
  145. package/dist/semver.d.ts.map +1 -0
  146. package/dist/semver.js +140 -0
  147. package/dist/serialization_types.d.ts +57 -0
  148. package/dist/serialization_types.d.ts.map +1 -0
  149. package/dist/serialization_types.js +40 -0
  150. package/dist/version_utils.d.ts +48 -0
  151. package/dist/version_utils.d.ts.map +1 -0
  152. package/dist/version_utils.js +125 -0
  153. package/package.json +107 -0
  154. package/src/lib/changeset_generator.ts +162 -0
  155. package/src/lib/changeset_reader.ts +218 -0
  156. package/src/lib/constants.ts +8 -0
  157. package/src/lib/dependency_graph.ts +423 -0
  158. package/src/lib/dependency_updater.ts +297 -0
  159. package/src/lib/fetch_repo_data.ts +64 -0
  160. package/src/lib/fs_fetch_value_cache.ts +75 -0
  161. package/src/lib/git_operations.ts +208 -0
  162. package/src/lib/github.ts +128 -0
  163. package/src/lib/github_helpers.ts +31 -0
  164. package/src/lib/gitops_analyze.task.ts +261 -0
  165. package/src/lib/gitops_config.ts +123 -0
  166. package/src/lib/gitops_plan.task.ts +272 -0
  167. package/src/lib/gitops_publish.task.ts +227 -0
  168. package/src/lib/gitops_sync.task.ts +109 -0
  169. package/src/lib/gitops_task_helpers.ts +126 -0
  170. package/src/lib/gitops_validate.task.ts +248 -0
  171. package/src/lib/graph_validation.ts +109 -0
  172. package/src/lib/local_repo.ts +359 -0
  173. package/src/lib/log_helpers.ts +147 -0
  174. package/src/lib/multi_repo_publisher.ts +464 -0
  175. package/src/lib/npm_install_helpers.ts +85 -0
  176. package/src/lib/npm_registry.ts +143 -0
  177. package/src/lib/operations.ts +334 -0
  178. package/src/lib/operations_defaults.ts +335 -0
  179. package/src/lib/output_helpers.ts +64 -0
  180. package/src/lib/paths.ts +11 -0
  181. package/src/lib/preflight_checks.ts +269 -0
  182. package/src/lib/publishing_plan.ts +531 -0
  183. package/src/lib/publishing_plan_helpers.ts +145 -0
  184. package/src/lib/publishing_plan_logging.ts +470 -0
  185. package/src/lib/repo.svelte.ts +95 -0
  186. package/src/lib/repo_ops.ts +213 -0
  187. package/src/lib/resolved_gitops_config.ts +27 -0
  188. package/src/lib/semver.ts +166 -0
  189. package/src/lib/serialization_types.ts +90 -0
  190. package/src/lib/version_utils.ts +150 -0
@@ -0,0 +1,100 @@
1
+ import type { Logger } from '@fuzdev/fuz_util/log.js';
2
+ import type { LocalRepo } from './local_repo.js';
3
+ import type { BumpType } from './semver.js';
4
+ import type { ChangesetOperations } from './operations.js';
5
+ export { log_publishing_plan, type LogPlanOptions } from './publishing_plan_logging.js';
6
+ export interface VersionChange {
7
+ package_name: string;
8
+ from: string;
9
+ to: string;
10
+ bump_type: BumpType;
11
+ breaking: boolean;
12
+ has_changesets: boolean;
13
+ will_generate_changeset?: boolean;
14
+ needs_bump_escalation?: boolean;
15
+ existing_bump?: BumpType;
16
+ required_bump?: BumpType;
17
+ }
18
+ export interface DependencyUpdate {
19
+ dependent_package: string;
20
+ updated_dependency: string;
21
+ current_version: string;
22
+ new_version: string;
23
+ type: 'dependencies' | 'devDependencies' | 'peerDependencies';
24
+ causes_republish: boolean;
25
+ }
26
+ export interface VerboseChangesetDetail {
27
+ package_name: string;
28
+ files: Array<{
29
+ filename: string;
30
+ bump_type: BumpType;
31
+ summary: string;
32
+ }>;
33
+ }
34
+ export interface VerboseIterationPackage {
35
+ name: string;
36
+ changeset_count: number;
37
+ bump_from_changesets: BumpType | null;
38
+ required_bump: BumpType | null;
39
+ triggering_dep: string | null;
40
+ action: 'publish' | 'auto_changeset' | 'escalation' | 'skip';
41
+ version_to: string | null;
42
+ is_breaking: boolean;
43
+ }
44
+ export interface VerboseIteration {
45
+ iteration: number;
46
+ packages: Array<VerboseIterationPackage>;
47
+ new_changes: number;
48
+ }
49
+ export interface VerbosePropagationChain {
50
+ source: string;
51
+ chain: Array<{
52
+ pkg: string;
53
+ dep_type: 'prod' | 'peer';
54
+ action: string;
55
+ }>;
56
+ }
57
+ export interface VerboseGraphSummary {
58
+ package_count: number;
59
+ internal_dep_count: number;
60
+ prod_peer_edges: Array<{
61
+ from: string;
62
+ to: string;
63
+ type: 'prod' | 'peer';
64
+ }>;
65
+ dev_edges: Array<{
66
+ from: string;
67
+ to: string;
68
+ }>;
69
+ prod_cycle_count: number;
70
+ dev_cycle_count: number;
71
+ }
72
+ export interface VerboseData {
73
+ changeset_details: Array<VerboseChangesetDetail>;
74
+ iterations: Array<VerboseIteration>;
75
+ propagation_chains: Array<VerbosePropagationChain>;
76
+ graph_summary: VerboseGraphSummary;
77
+ total_iterations: number;
78
+ }
79
+ export interface PublishingPlan {
80
+ publishing_order: Array<string>;
81
+ version_changes: Array<VersionChange>;
82
+ dependency_updates: Array<DependencyUpdate>;
83
+ breaking_cascades: Map<string, Array<string>>;
84
+ warnings: Array<string>;
85
+ info: Array<string>;
86
+ errors: Array<string>;
87
+ verbose_data?: VerboseData;
88
+ }
89
+ export interface GeneratePlanOptions {
90
+ log?: Logger;
91
+ ops?: ChangesetOperations;
92
+ verbose?: boolean;
93
+ }
94
+ /**
95
+ * Generates a publishing plan showing what would happen during publishing.
96
+ * Shows version changes, dependency updates, and breaking change cascades.
97
+ * Uses fixed-point iteration to resolve transitive cascades.
98
+ */
99
+ export declare const generate_publishing_plan: (repos: Array<LocalRepo>, options?: GeneratePlanOptions) => Promise<PublishingPlan>;
100
+ //# sourceMappingURL=publishing_plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publishing_plan.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,353 @@
1
+ import { styleText as st } from 'node:util';
2
+ import { validate_dependency_graph } from './graph_validation.js';
3
+ import { is_breaking_change, compare_bump_types, calculate_next_version } from './version_utils.js';
4
+ import { default_changeset_operations } from './operations_defaults.js';
5
+ import { MAX_ITERATIONS } from './constants.js';
6
+ import { calculate_dependency_updates, get_required_bump_for_dependencies, } from './publishing_plan_helpers.js';
7
+ // Re-export logging functions
8
+ export { log_publishing_plan } from './publishing_plan_logging.js';
9
+ /**
10
+ * Generates a publishing plan showing what would happen during publishing.
11
+ * Shows version changes, dependency updates, and breaking change cascades.
12
+ * Uses fixed-point iteration to resolve transitive cascades.
13
+ */
14
+ export const generate_publishing_plan = async (repos, options = {}) => {
15
+ const { log, ops = default_changeset_operations, verbose } = options;
16
+ log?.info(st('cyan', 'Generating publishing plan...'));
17
+ const warnings = [];
18
+ const info = []; // Informational status (not warnings)
19
+ const errors = [];
20
+ // Verbose data collection
21
+ const verbose_changeset_details = [];
22
+ const verbose_iterations = [];
23
+ // Build dependency graph and validate
24
+ let publishing_order;
25
+ let production_cycles;
26
+ let dev_cycles;
27
+ let graph = null;
28
+ try {
29
+ const validation = validate_dependency_graph(repos, {
30
+ throw_on_prod_cycles: false, // Collect errors instead of throwing
31
+ log_cycles: false, // We'll handle our own error collection
32
+ log_order: false, // Plan generation doesn't need to log order
33
+ });
34
+ publishing_order = validation.publishing_order;
35
+ production_cycles = validation.production_cycles;
36
+ dev_cycles = validation.dev_cycles;
37
+ graph = validation.graph; // Store for verbose output
38
+ // Add topological sort error if present
39
+ if (validation.sort_error) {
40
+ errors.push(validation.sort_error);
41
+ }
42
+ }
43
+ catch (error) {
44
+ errors.push(`Failed to validate dependency graph: ${error}`);
45
+ return {
46
+ publishing_order: [],
47
+ version_changes: [],
48
+ dependency_updates: [],
49
+ breaking_cascades: new Map(),
50
+ warnings,
51
+ info,
52
+ errors,
53
+ };
54
+ }
55
+ // Collect cycle errors
56
+ if (production_cycles.length > 0) {
57
+ for (const cycle of production_cycles) {
58
+ errors.push(`Production dependency cycle: ${cycle.join(' → ')}`);
59
+ }
60
+ }
61
+ // Dev cycles are shown in gitops_analyze, not repeated here
62
+ if (dev_cycles.length > 0) {
63
+ info.push(`${dev_cycles.length} dev dependency cycle(s) detected (normal, shown in gitops_analyze)`);
64
+ }
65
+ // Initial pass: get all packages with explicit changesets
66
+ const predicted_versions = new Map();
67
+ const breaking_packages = new Set();
68
+ const version_changes = [];
69
+ for (const pkg_name of publishing_order) {
70
+ const repo = repos.find((r) => r.library.name === pkg_name);
71
+ if (!repo)
72
+ continue;
73
+ // Check for changesets
74
+ const has_result = await ops.has_changesets({ repo }); // eslint-disable-line no-await-in-loop
75
+ if (!has_result.ok) {
76
+ errors.push(`Failed to check changesets for ${pkg_name}: ${has_result.message}`);
77
+ continue;
78
+ }
79
+ if (has_result.value) {
80
+ // Predict version from changesets
81
+ const prediction = await ops.predict_next_version({ repo, log }); // eslint-disable-line no-await-in-loop
82
+ if (!prediction) {
83
+ // No changesets found - this shouldn't happen since has_changesets returned true
84
+ continue;
85
+ }
86
+ if (!prediction.ok) {
87
+ errors.push(`Failed to predict version for ${pkg_name}: ${prediction.message}`);
88
+ continue;
89
+ }
90
+ // Capture changeset details for verbose output
91
+ if (verbose) {
92
+ const changesets_result = await ops.read_changesets({ repo, log }); // eslint-disable-line no-await-in-loop
93
+ if (changesets_result.ok) {
94
+ const files = changesets_result.value
95
+ .filter((cs) => cs.packages.some((p) => p.name === pkg_name))
96
+ .map((cs) => {
97
+ const pkg_entry = cs.packages.find((p) => p.name === pkg_name);
98
+ return {
99
+ filename: cs.filename,
100
+ bump_type: pkg_entry?.bump_type || prediction.bump_type,
101
+ summary: cs.summary,
102
+ };
103
+ });
104
+ if (files.length > 0) {
105
+ verbose_changeset_details.push({ package_name: pkg_name, files });
106
+ }
107
+ }
108
+ }
109
+ {
110
+ const old_version = repo.library.package_json.version || '0.0.0';
111
+ const is_breaking = is_breaking_change(old_version, prediction.bump_type);
112
+ predicted_versions.set(pkg_name, prediction.version);
113
+ if (is_breaking) {
114
+ breaking_packages.add(pkg_name);
115
+ }
116
+ version_changes.push({
117
+ package_name: pkg_name,
118
+ from: old_version,
119
+ to: prediction.version,
120
+ bump_type: prediction.bump_type,
121
+ breaking: is_breaking,
122
+ has_changesets: true,
123
+ });
124
+ }
125
+ }
126
+ }
127
+ // Fixed-point iteration to resolve transitive cascades
128
+ // Loop until no new version changes are discovered
129
+ let iteration = 0;
130
+ let changed = true;
131
+ while (changed && iteration < MAX_ITERATIONS) {
132
+ changed = false;
133
+ iteration++;
134
+ // Verbose iteration tracking
135
+ const verbose_iteration_packages = [];
136
+ let verbose_new_changes = 0;
137
+ // Recalculate dependency updates based on current predicted versions
138
+ // (breaking_cascades not needed during iteration, only calculated at the end)
139
+ const { dependency_updates } = calculate_dependency_updates(repos, predicted_versions, breaking_packages);
140
+ // Process packages to check for bump escalation and auto-generated changesets
141
+ for (const repo of repos) {
142
+ const pkg_name = repo.library.name;
143
+ // Get required bump from dependencies
144
+ const required_bump = get_required_bump_for_dependencies(repo, dependency_updates, breaking_packages);
145
+ // Find triggering dependency for verbose output
146
+ let triggering_dep = null;
147
+ if (required_bump) {
148
+ const relevant_updates = dependency_updates.filter((u) => u.dependent_package === pkg_name &&
149
+ (u.type === 'dependencies' || u.type === 'peerDependencies') &&
150
+ breaking_packages.has(u.updated_dependency));
151
+ if (relevant_updates.length > 0) {
152
+ triggering_dep = `${relevant_updates[0].updated_dependency} BREAKING`;
153
+ }
154
+ }
155
+ // Check if already in version_changes (has changesets)
156
+ const existing_entry = version_changes.find((vc) => vc.package_name === pkg_name);
157
+ if (existing_entry) {
158
+ // Package has changesets - check if it needs bump escalation
159
+ if (required_bump && compare_bump_types(required_bump, existing_entry.bump_type) > 0) {
160
+ // Dependencies require a larger bump than existing changesets provide
161
+ const old_version = repo.library.package_json.version || '0.0.0';
162
+ const new_version = calculate_next_version(old_version, required_bump);
163
+ // Only mark as changed if version actually changed
164
+ if (existing_entry.to !== new_version) {
165
+ changed = true;
166
+ verbose_new_changes++;
167
+ // Capture verbose data before updating
168
+ if (verbose) {
169
+ const changeset_detail = verbose_changeset_details.find((d) => d.package_name === pkg_name);
170
+ verbose_iteration_packages.push({
171
+ name: pkg_name,
172
+ changeset_count: changeset_detail?.files.length || 1,
173
+ bump_from_changesets: existing_entry.bump_type,
174
+ required_bump,
175
+ triggering_dep,
176
+ action: 'escalation',
177
+ version_to: new_version,
178
+ is_breaking: is_breaking_change(old_version, required_bump),
179
+ });
180
+ }
181
+ existing_entry.needs_bump_escalation = true;
182
+ existing_entry.existing_bump = existing_entry.bump_type;
183
+ existing_entry.required_bump = required_bump;
184
+ existing_entry.bump_type = required_bump;
185
+ existing_entry.to = new_version;
186
+ existing_entry.breaking = is_breaking_change(old_version, required_bump);
187
+ // Update predicted versions
188
+ predicted_versions.set(pkg_name, new_version);
189
+ if (existing_entry.breaking) {
190
+ breaking_packages.add(pkg_name);
191
+ }
192
+ }
193
+ }
194
+ }
195
+ else if (required_bump) {
196
+ // No existing changesets but needs changeset for dependency updates
197
+ const old_version = repo.library.package_json.version || '0.0.0';
198
+ const new_version = calculate_next_version(old_version, required_bump);
199
+ // Check if this is a new version (not already in version_changes)
200
+ if (!predicted_versions.has(pkg_name)) {
201
+ changed = true;
202
+ verbose_new_changes++;
203
+ const is_breaking = is_breaking_change(old_version, required_bump);
204
+ // Capture verbose data
205
+ if (verbose) {
206
+ verbose_iteration_packages.push({
207
+ name: pkg_name,
208
+ changeset_count: 0,
209
+ bump_from_changesets: null,
210
+ required_bump,
211
+ triggering_dep,
212
+ action: 'auto_changeset',
213
+ version_to: new_version,
214
+ is_breaking,
215
+ });
216
+ }
217
+ if (is_breaking) {
218
+ breaking_packages.add(pkg_name);
219
+ }
220
+ version_changes.push({
221
+ package_name: pkg_name,
222
+ from: old_version,
223
+ to: new_version,
224
+ bump_type: required_bump,
225
+ breaking: is_breaking,
226
+ has_changesets: false,
227
+ will_generate_changeset: true,
228
+ });
229
+ // Update predicted versions
230
+ predicted_versions.set(pkg_name, new_version);
231
+ }
232
+ }
233
+ }
234
+ // Store verbose iteration data
235
+ if (verbose && (verbose_iteration_packages.length > 0 || iteration === 1)) {
236
+ verbose_iterations.push({
237
+ iteration,
238
+ packages: verbose_iteration_packages,
239
+ new_changes: verbose_new_changes,
240
+ });
241
+ }
242
+ }
243
+ // Check if we hit iteration limit without convergence
244
+ if (iteration === MAX_ITERATIONS && changed) {
245
+ // Calculate how many packages still need processing
246
+ const pending_packages = [];
247
+ // Recalculate one more time to see what's pending
248
+ const { dependency_updates: pending_updates } = calculate_dependency_updates(repos, predicted_versions, breaking_packages);
249
+ for (const repo of repos) {
250
+ const pkg_name = repo.library.name;
251
+ const required_bump = get_required_bump_for_dependencies(repo, pending_updates, breaking_packages);
252
+ // Check if this package would need processing
253
+ const existing_entry = version_changes.find((vc) => vc.package_name === pkg_name);
254
+ const needs_escalation = existing_entry &&
255
+ required_bump &&
256
+ compare_bump_types(required_bump, existing_entry.bump_type) > 0;
257
+ const needs_auto_changeset = !existing_entry && required_bump;
258
+ if (needs_escalation || needs_auto_changeset) {
259
+ pending_packages.push(pkg_name);
260
+ }
261
+ }
262
+ // Add warning with diagnostics
263
+ const pending_count = pending_packages.length;
264
+ const estimated_iterations = Math.ceil(pending_count / 2); // Rough estimate
265
+ warnings.push(`Reached maximum iterations (${MAX_ITERATIONS}) without full convergence - ` +
266
+ `${pending_count} package(s) may still need processing: ${pending_packages.join(', ')}. ` +
267
+ `Estimated ${estimated_iterations} more iteration(s) needed.`);
268
+ }
269
+ // Final dependency updates calculation after convergence
270
+ const { dependency_updates, breaking_cascades } = calculate_dependency_updates(repos, predicted_versions, breaking_packages);
271
+ // Identify packages with no changes
272
+ for (const repo of repos) {
273
+ const has_version_change = version_changes.some((vc) => vc.package_name === repo.library.name);
274
+ if (!has_version_change) {
275
+ const has_result = await ops.has_changesets({ repo }); // eslint-disable-line no-await-in-loop
276
+ if (has_result.ok && !has_result.value) {
277
+ info.push(repo.library.name);
278
+ }
279
+ }
280
+ }
281
+ // Build verbose data if requested
282
+ let verbose_data;
283
+ if (verbose) {
284
+ // Build propagation chains from breaking_cascades
285
+ const propagation_chains = [];
286
+ for (const [source, affected] of breaking_cascades) {
287
+ const chain = [];
288
+ for (const pkg of affected) {
289
+ // Determine dep type and action
290
+ const update = dependency_updates.find((u) => u.dependent_package === pkg && u.updated_dependency === source);
291
+ const dep_type = update?.type === 'peerDependencies' ? 'peer' : 'prod';
292
+ const version_change = version_changes.find((vc) => vc.package_name === pkg);
293
+ let action = 'update';
294
+ if (version_change?.will_generate_changeset) {
295
+ action = 'auto-changeset';
296
+ }
297
+ else if (version_change?.needs_bump_escalation) {
298
+ action = 'bump escalation';
299
+ }
300
+ chain.push({ pkg, dep_type, action });
301
+ }
302
+ if (chain.length > 0) {
303
+ propagation_chains.push({ source, chain });
304
+ }
305
+ }
306
+ // Build graph summary
307
+ const prod_peer_edges = [];
308
+ const dev_edges = [];
309
+ let internal_dep_count = 0;
310
+ for (const [pkg_name, node] of graph.nodes) {
311
+ for (const [dep_name, spec] of node.dependencies) {
312
+ // Only count internal dependencies (deps that are also in the graph)
313
+ if (graph.nodes.has(dep_name)) {
314
+ internal_dep_count++;
315
+ if (spec.type === 'dev') {
316
+ dev_edges.push({ from: pkg_name, to: dep_name });
317
+ }
318
+ else {
319
+ prod_peer_edges.push({
320
+ from: pkg_name,
321
+ to: dep_name,
322
+ type: spec.type === 'peer' ? 'peer' : 'prod',
323
+ });
324
+ }
325
+ }
326
+ }
327
+ }
328
+ verbose_data = {
329
+ changeset_details: verbose_changeset_details,
330
+ iterations: verbose_iterations,
331
+ propagation_chains,
332
+ graph_summary: {
333
+ package_count: graph.nodes.size,
334
+ internal_dep_count,
335
+ prod_peer_edges,
336
+ dev_edges,
337
+ prod_cycle_count: production_cycles.length,
338
+ dev_cycle_count: dev_cycles.length,
339
+ },
340
+ total_iterations: iteration,
341
+ };
342
+ }
343
+ return {
344
+ publishing_order,
345
+ version_changes,
346
+ dependency_updates,
347
+ breaking_cascades,
348
+ warnings,
349
+ info,
350
+ errors,
351
+ verbose_data,
352
+ };
353
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Helper functions for publishing plan calculations.
3
+ *
4
+ * Extracted from publishing_plan.ts to reduce file size.
5
+ */
6
+ import type { LocalRepo } from './local_repo.js';
7
+ import type { BumpType } from './semver.js';
8
+ import type { DependencyUpdate } from './publishing_plan.js';
9
+ /**
10
+ * Calculates all dependency updates between packages based on predicted versions.
11
+ *
12
+ * Iterates through all repos, checking prod, peer, and dev dependencies to find
13
+ * which packages will need dependency version bumps after publishing.
14
+ *
15
+ * Also tracks "breaking cascades" - when a breaking change propagates to dependents.
16
+ */
17
+ export declare const calculate_dependency_updates: (repos: Array<LocalRepo>, predicted_versions: Map<string, string>, breaking_packages: Set<string>) => {
18
+ dependency_updates: Array<DependencyUpdate>;
19
+ breaking_cascades: Map<string, Array<string>>;
20
+ };
21
+ /**
22
+ * Determines the required bump type for a package based on its dependency updates.
23
+ *
24
+ * Returns null if no prod/peer dependency updates, otherwise returns the minimum
25
+ * required bump type (major for breaking deps, patch otherwise).
26
+ *
27
+ * Respects pre-1.0 semver conventions (minor for breaking in 0.x).
28
+ */
29
+ export declare const get_required_bump_for_dependencies: (repo: LocalRepo, dependency_updates: Array<DependencyUpdate>, breaking_packages: Set<string>) => BumpType | null;
30
+ //# sourceMappingURL=publishing_plan_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publishing_plan_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B;IACF,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC5C,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;CA2E9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,oBAAoB,KAAK,CAAC,gBAAgB,CAAC,EAC3C,mBAAmB,GAAG,CAAC,MAAM,CAAC,KAC5B,QAAQ,GAAG,IA8Bb,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Helper functions for publishing plan calculations.
3
+ *
4
+ * Extracted from publishing_plan.ts to reduce file size.
5
+ */
6
+ import { needs_update } from './version_utils.js';
7
+ /**
8
+ * Calculates all dependency updates between packages based on predicted versions.
9
+ *
10
+ * Iterates through all repos, checking prod, peer, and dev dependencies to find
11
+ * which packages will need dependency version bumps after publishing.
12
+ *
13
+ * Also tracks "breaking cascades" - when a breaking change propagates to dependents.
14
+ */
15
+ export const calculate_dependency_updates = (repos, predicted_versions, breaking_packages) => {
16
+ const dependency_updates = [];
17
+ const breaking_cascades = new Map();
18
+ for (const repo of repos) {
19
+ // Check prod dependencies
20
+ if (repo.dependencies) {
21
+ for (const [dep_name, current_version] of repo.dependencies) {
22
+ const new_version = predicted_versions.get(dep_name);
23
+ if (new_version && needs_update(current_version, new_version)) {
24
+ dependency_updates.push({
25
+ dependent_package: repo.library.name,
26
+ updated_dependency: dep_name,
27
+ current_version,
28
+ new_version,
29
+ type: 'dependencies',
30
+ causes_republish: true,
31
+ });
32
+ if (breaking_packages.has(dep_name)) {
33
+ const cascades = breaking_cascades.get(dep_name) || [];
34
+ if (!cascades.includes(repo.library.name)) {
35
+ cascades.push(repo.library.name);
36
+ }
37
+ breaking_cascades.set(dep_name, cascades);
38
+ }
39
+ }
40
+ }
41
+ }
42
+ // Check peer dependencies
43
+ if (repo.peer_dependencies) {
44
+ for (const [dep_name, current_version] of repo.peer_dependencies) {
45
+ const new_version = predicted_versions.get(dep_name);
46
+ if (new_version && needs_update(current_version, new_version)) {
47
+ dependency_updates.push({
48
+ dependent_package: repo.library.name,
49
+ updated_dependency: dep_name,
50
+ current_version,
51
+ new_version,
52
+ type: 'peerDependencies',
53
+ causes_republish: true,
54
+ });
55
+ if (breaking_packages.has(dep_name)) {
56
+ const cascades = breaking_cascades.get(dep_name) || [];
57
+ if (!cascades.includes(repo.library.name)) {
58
+ cascades.push(repo.library.name);
59
+ }
60
+ breaking_cascades.set(dep_name, cascades);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ // Check dev dependencies
66
+ if (repo.dev_dependencies) {
67
+ for (const [dep_name, current_version] of repo.dev_dependencies) {
68
+ const new_version = predicted_versions.get(dep_name);
69
+ if (new_version && needs_update(current_version, new_version)) {
70
+ dependency_updates.push({
71
+ dependent_package: repo.library.name,
72
+ updated_dependency: dep_name,
73
+ current_version,
74
+ new_version,
75
+ type: 'devDependencies',
76
+ causes_republish: false,
77
+ });
78
+ }
79
+ }
80
+ }
81
+ }
82
+ return { dependency_updates, breaking_cascades };
83
+ };
84
+ /**
85
+ * Determines the required bump type for a package based on its dependency updates.
86
+ *
87
+ * Returns null if no prod/peer dependency updates, otherwise returns the minimum
88
+ * required bump type (major for breaking deps, patch otherwise).
89
+ *
90
+ * Respects pre-1.0 semver conventions (minor for breaking in 0.x).
91
+ */
92
+ export const get_required_bump_for_dependencies = (repo, dependency_updates, breaking_packages) => {
93
+ // Check if this repo has any prod/peer dependency updates
94
+ const relevant_updates = dependency_updates.filter((update) => update.dependent_package === repo.library.name &&
95
+ (update.type === 'dependencies' || update.type === 'peerDependencies'));
96
+ if (relevant_updates.length === 0) {
97
+ return null;
98
+ }
99
+ // Check if any of these dependencies have breaking changes
100
+ const has_breaking_deps = relevant_updates.some((update) => breaking_packages.has(update.updated_dependency));
101
+ const current_version = repo.library.package_json.version || '0.0.0';
102
+ const [major] = current_version.split('.').map(Number);
103
+ const is_pre_1_0 = major === 0;
104
+ if (has_breaking_deps) {
105
+ // Breaking changes propagate
106
+ // Pre-1.0: use minor for breaking changes
107
+ // 1.0+: use major for breaking changes
108
+ return is_pre_1_0 ? 'minor' : 'major';
109
+ }
110
+ // For non-breaking dependency updates, use patch
111
+ return 'patch';
112
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Logging and formatting functions for publishing plans.
3
+ *
4
+ * Includes both regular plan output and verbose diagnostic sections.
5
+ */
6
+ import type { Logger } from '@fuzdev/fuz_util/log.js';
7
+ import type { PublishingPlan } from './publishing_plan.js';
8
+ export interface LogPlanOptions {
9
+ verbose?: boolean;
10
+ }
11
+ /**
12
+ * Logs a complete publishing plan to the console.
13
+ *
14
+ * Displays errors, publishing order, version changes grouped by scenario,
15
+ * dependency-only updates, warnings, and a summary.
16
+ */
17
+ export declare const log_publishing_plan: (plan: PublishingPlan, log: Logger, options?: LogPlanOptions) => void;
18
+ //# sourceMappingURL=publishing_plan_logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publishing_plan_logging.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan_logging.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EACX,cAAc,EAQd,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AA2GD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,cAAc,EACpB,KAAK,MAAM,EACX,UAAS,cAAmB,KAC1B,IAiKF,CAAC"}