@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,110 @@
1
+ /**
2
+ * Auto-generation of changesets for dependency updates during publishing.
3
+ *
4
+ * Creates changesets when packages need to republish due to updated dependencies.
5
+ * For parsing existing changesets, see `changeset_reader.ts`.
6
+ */
7
+ import { writeFile, mkdir } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ import { existsSync } from 'node:fs';
10
+ import { strip_version_prefix } from './version_utils.js';
11
+ /**
12
+ * Creates a changeset file for dependency updates.
13
+ * Returns the path to the created changeset file.
14
+ */
15
+ export const create_changeset_for_dependency_updates = async (repo, updates, options = {}) => {
16
+ const { log } = options;
17
+ const changesets_dir = join(repo.repo_dir, '.changeset');
18
+ // Ensure .changeset directory exists
19
+ if (!existsSync(changesets_dir)) {
20
+ await mkdir(changesets_dir, { recursive: true });
21
+ }
22
+ // Generate a unique filename
23
+ const timestamp = Date.now();
24
+ const random = Math.random().toString(36).substring(2, 8);
25
+ const filename = `dependency-update-${timestamp}-${random}.md`;
26
+ const filepath = join(changesets_dir, filename);
27
+ // Determine the required bump type based on updates
28
+ const required_bump = calculate_required_bump(repo, updates);
29
+ // Generate changeset content
30
+ const content = generate_changeset_content(repo.library.name, updates, required_bump);
31
+ // Write the changeset file
32
+ await writeFile(filepath, content, 'utf8');
33
+ log?.info(` Created changeset: ${filename}`);
34
+ return filepath;
35
+ };
36
+ const calculate_required_bump = (repo, updates) => {
37
+ const current_version = repo.library.package_json.version || '0.0.0';
38
+ const [major] = current_version.split('.').map(Number);
39
+ const is_pre_1_0 = major === 0;
40
+ // Check if any dependency had breaking changes
41
+ const has_breaking = updates.some((u) => u.breaking);
42
+ if (has_breaking) {
43
+ // Breaking changes propagate
44
+ // Pre-1.0: use minor for breaking changes
45
+ // 1.0+: use major for breaking changes
46
+ return is_pre_1_0 ? 'minor' : 'major';
47
+ }
48
+ // For non-breaking dependency updates, always use patch
49
+ return 'patch';
50
+ };
51
+ /**
52
+ * Generates markdown changeset content for dependency updates.
53
+ *
54
+ * Creates properly formatted changeset with YAML frontmatter, summary,
55
+ * and categorized list of breaking vs regular updates. Output format
56
+ * matches changesets CLI for consistency.
57
+ *
58
+ * @param package_name package receiving the dependency updates
59
+ * @param updates list of dependency changes with version info
60
+ * @param bump_type required bump type (calculated from breaking changes)
61
+ * @returns markdown content ready to write to .changeset/*.md file
62
+ */
63
+ export const generate_changeset_content = (package_name, updates, bump_type) => {
64
+ // Group updates by type
65
+ const breaking_updates = updates.filter((u) => u.breaking);
66
+ const regular_updates = updates.filter((u) => !u.breaking);
67
+ let message = 'Update dependencies';
68
+ if (breaking_updates.length > 0) {
69
+ message = 'Update dependencies (BREAKING CHANGES)';
70
+ }
71
+ const lines = ['---', `"${package_name}": ${bump_type}`, '---', '', message, ''];
72
+ if (breaking_updates.length > 0) {
73
+ lines.push('Breaking dependency changes:');
74
+ for (const update of breaking_updates) {
75
+ lines.push(`- ${update.package_name}: ${update.from_version} → ${update.to_version} (${update.bump_type})`);
76
+ }
77
+ lines.push('');
78
+ }
79
+ if (regular_updates.length > 0) {
80
+ if (breaking_updates.length > 0) {
81
+ lines.push('Other dependency updates:');
82
+ }
83
+ else {
84
+ lines.push('Updated dependencies:');
85
+ }
86
+ for (const update of regular_updates) {
87
+ lines.push(`- ${update.package_name}: ${update.from_version} → ${update.to_version} (${update.bump_type})`);
88
+ }
89
+ lines.push('');
90
+ }
91
+ return lines.join('\n');
92
+ };
93
+ export const create_dependency_updates = (dependencies, published_versions) => {
94
+ const updates = [];
95
+ for (const [dep_name, current_version] of dependencies) {
96
+ const published = published_versions.get(dep_name);
97
+ if (published) {
98
+ // Strip version prefix (^, ~, etc)
99
+ const clean_current = strip_version_prefix(current_version);
100
+ updates.push({
101
+ package_name: dep_name,
102
+ from_version: clean_current,
103
+ to_version: published.new_version,
104
+ bump_type: published.bump_type,
105
+ breaking: published.breaking,
106
+ });
107
+ }
108
+ }
109
+ return updates;
110
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Changeset parsing and version prediction from `.changeset/*.md` files.
3
+ *
4
+ * Reads changesets to determine which packages need publishing and their version bumps.
5
+ * For auto-generating changesets during publishing, see `changeset_generator.ts`.
6
+ */
7
+ import type { Logger } from '@fuzdev/fuz_util/log.js';
8
+ import type { LocalRepo } from './local_repo.js';
9
+ import type { BumpType } from './semver.js';
10
+ export interface ChangesetInfo {
11
+ filename: string;
12
+ packages: Array<{
13
+ name: string;
14
+ bump_type: BumpType;
15
+ }>;
16
+ summary: string;
17
+ }
18
+ /**
19
+ * Parses changeset content string from markdown format.
20
+ *
21
+ * Pure function for testability - no file I/O, just string parsing.
22
+ * Extracts package names, bump types, and summary from YAML frontmatter format.
23
+ * Returns null if format is invalid or no packages found.
24
+ *
25
+ * Expected format:
26
+ * ---
27
+ * "package-name": patch
28
+ * "@scope/package": minor
29
+ * ---
30
+ *
31
+ * Summary of changes
32
+ *
33
+ * @param content changeset markdown with YAML frontmatter
34
+ * @param filename optional filename for error reporting context
35
+ * @returns parsed changeset info or null if invalid format
36
+ */
37
+ export declare const parse_changeset_content: (content: string, filename?: string) => ChangesetInfo | null;
38
+ export declare const parse_changeset_file: (filepath: string, log?: Logger) => Promise<ChangesetInfo | null>;
39
+ export declare const read_changesets: (repo: LocalRepo, log?: Logger) => Promise<Array<ChangesetInfo>>;
40
+ /**
41
+ * Determines the bump type for a package from its changesets.
42
+ *
43
+ * When multiple changesets exist for the same package, returns the highest
44
+ * bump type (major > minor > patch) to ensure the most significant change
45
+ * is reflected in the version bump.
46
+ *
47
+ * @returns the highest bump type, or null if package has no changesets
48
+ */
49
+ export declare const determine_bump_from_changesets: (changesets: Array<ChangesetInfo>, package_name: string) => BumpType | null;
50
+ /**
51
+ * Checks if a repo has any changeset files (excluding README.md).
52
+ *
53
+ * Used by preflight checks and publishing workflow to determine which packages
54
+ * need to be published. Returns false if .changeset directory doesn't exist
55
+ * or contains only README.md.
56
+ *
57
+ * @returns true if repo has unpublished changesets
58
+ */
59
+ export declare const has_changesets: (repo: LocalRepo) => Promise<boolean>;
60
+ /**
61
+ * Predicts the next version by analyzing all changesets in a repo.
62
+ *
63
+ * Reads all changesets, determines the highest bump type for the package,
64
+ * and calculates the next version. Returns null if no changesets found.
65
+ *
66
+ * Critical for dry-run mode accuracy - allows simulating publishes without
67
+ * actually running `gro publish` which consumes changesets.
68
+ *
69
+ * @returns predicted version and bump type, or null if no changesets
70
+ */
71
+ export declare const predict_next_version: (repo: LocalRepo, log?: Logger) => Promise<{
72
+ version: string;
73
+ bump_type: BumpType;
74
+ } | null>;
75
+ //# sourceMappingURL=changeset_reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeset_reader.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/changeset_reader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAG1C,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAA;KAAC,CAAC,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,uBAAuB,GACnC,SAAS,MAAM,EACf,iBAAyB,KACvB,aAAa,GAAG,IAmClB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,UAAU,MAAM,EAChB,MAAM,MAAM,KACV,OAAO,CAAC,aAAa,GAAG,IAAI,CAgB9B,CAAC;AAEF,eAAO,MAAM,eAAe,GAC3B,MAAM,SAAS,EACf,MAAM,MAAM,KACV,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAsB9B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GAC1C,YAAY,KAAK,CAAC,aAAa,CAAC,EAChC,cAAc,MAAM,KAClB,QAAQ,GAAG,IAcb,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,OAAO,CAarE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,MAAM,MAAM,KACV,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,QAAQ,CAAA;CAAC,GAAG,IAAI,CAsBvD,CAAC"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Changeset parsing and version prediction from `.changeset/*.md` files.
3
+ *
4
+ * Reads changesets to determine which packages need publishing and their version bumps.
5
+ * For auto-generating changesets during publishing, see `changeset_generator.ts`.
6
+ */
7
+ import { existsSync } from 'node:fs';
8
+ import { readdir, readFile } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { compare_bump_types, calculate_next_version } from './version_utils.js';
11
+ /**
12
+ * Parses changeset content string from markdown format.
13
+ *
14
+ * Pure function for testability - no file I/O, just string parsing.
15
+ * Extracts package names, bump types, and summary from YAML frontmatter format.
16
+ * Returns null if format is invalid or no packages found.
17
+ *
18
+ * Expected format:
19
+ * ---
20
+ * "package-name": patch
21
+ * "@scope/package": minor
22
+ * ---
23
+ *
24
+ * Summary of changes
25
+ *
26
+ * @param content changeset markdown with YAML frontmatter
27
+ * @param filename optional filename for error reporting context
28
+ * @returns parsed changeset info or null if invalid format
29
+ */
30
+ export const parse_changeset_content = (content, filename = 'changeset.md') => {
31
+ // Match frontmatter between --- markers
32
+ const frontmatter_match = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)/.exec(content);
33
+ if (!frontmatter_match) {
34
+ return null;
35
+ }
36
+ const frontmatter = frontmatter_match[1];
37
+ const summary = frontmatter_match[2].trim();
38
+ // Parse package entries
39
+ const packages = [];
40
+ // Match lines like: "package-name": patch
41
+ // or: '@scope/package': minor
42
+ // Allow leading whitespace
43
+ const package_regex = /^\s*["']([^"']+)["']\s*:\s*(major|minor|patch)\s*$/gm;
44
+ let match;
45
+ while ((match = package_regex.exec(frontmatter)) !== null) {
46
+ packages.push({
47
+ name: match[1],
48
+ bump_type: match[2],
49
+ });
50
+ }
51
+ if (packages.length === 0) {
52
+ return null;
53
+ }
54
+ return {
55
+ filename,
56
+ packages,
57
+ summary,
58
+ };
59
+ };
60
+ export const parse_changeset_file = async (filepath, log) => {
61
+ try {
62
+ const content = await readFile(filepath, 'utf8');
63
+ const filename = filepath.split('/').pop() || '';
64
+ const result = parse_changeset_content(content, filename);
65
+ if (!result) {
66
+ log?.warn(` Invalid changeset format in ${filepath}`);
67
+ }
68
+ return result;
69
+ }
70
+ catch (error) {
71
+ log?.error(` Failed to parse changeset ${filepath}: ${error}`);
72
+ return null;
73
+ }
74
+ };
75
+ export const read_changesets = async (repo, log) => {
76
+ const changesets_dir = join(repo.repo_dir, '.changeset');
77
+ try {
78
+ const files = await readdir(changesets_dir);
79
+ const changeset_files = files.filter((f) => f.endsWith('.md') && f !== 'README.md');
80
+ const changesets = [];
81
+ for (const file of changeset_files) {
82
+ const filepath = join(changesets_dir, file);
83
+ const changeset = await parse_changeset_file(filepath, log); // eslint-disable-line no-await-in-loop
84
+ if (changeset) {
85
+ changesets.push(changeset);
86
+ }
87
+ }
88
+ return changesets;
89
+ }
90
+ catch (_error) {
91
+ // No .changeset directory or error reading
92
+ return [];
93
+ }
94
+ };
95
+ /**
96
+ * Determines the bump type for a package from its changesets.
97
+ *
98
+ * When multiple changesets exist for the same package, returns the highest
99
+ * bump type (major > minor > patch) to ensure the most significant change
100
+ * is reflected in the version bump.
101
+ *
102
+ * @returns the highest bump type, or null if package has no changesets
103
+ */
104
+ export const determine_bump_from_changesets = (changesets, package_name) => {
105
+ let highest_bump = null;
106
+ for (const changeset of changesets) {
107
+ for (const pkg of changeset.packages) {
108
+ if (pkg.name === package_name) {
109
+ if (!highest_bump || compare_bump_types(pkg.bump_type, highest_bump) > 0) {
110
+ highest_bump = pkg.bump_type;
111
+ }
112
+ }
113
+ }
114
+ }
115
+ return highest_bump;
116
+ };
117
+ /**
118
+ * Checks if a repo has any changeset files (excluding README.md).
119
+ *
120
+ * Used by preflight checks and publishing workflow to determine which packages
121
+ * need to be published. Returns false if .changeset directory doesn't exist
122
+ * or contains only README.md.
123
+ *
124
+ * @returns true if repo has unpublished changesets
125
+ */
126
+ export const has_changesets = async (repo) => {
127
+ const changesets_dir = join(repo.repo_dir, '.changeset');
128
+ if (!existsSync(changesets_dir)) {
129
+ return false;
130
+ }
131
+ try {
132
+ const files = await readdir(changesets_dir);
133
+ // Look for markdown files that aren't the README
134
+ return files.some((file) => file.endsWith('.md') && file !== 'README.md');
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ };
140
+ /**
141
+ * Predicts the next version by analyzing all changesets in a repo.
142
+ *
143
+ * Reads all changesets, determines the highest bump type for the package,
144
+ * and calculates the next version. Returns null if no changesets found.
145
+ *
146
+ * Critical for dry-run mode accuracy - allows simulating publishes without
147
+ * actually running `gro publish` which consumes changesets.
148
+ *
149
+ * @returns predicted version and bump type, or null if no changesets
150
+ */
151
+ export const predict_next_version = async (repo, log) => {
152
+ const changesets = await read_changesets(repo, log);
153
+ if (changesets.length === 0) {
154
+ return null;
155
+ }
156
+ const bump_type = determine_bump_from_changesets(changesets, repo.library.name);
157
+ if (!bump_type) {
158
+ return null;
159
+ }
160
+ const current_version = repo.library.package_json.version || '0.0.0';
161
+ const next_version = calculate_next_version(current_version, bump_type);
162
+ log?.debug(` Predicted ${repo.library.name}: ${current_version} → ${next_version} (${bump_type})`);
163
+ return {
164
+ version: next_version,
165
+ bump_type,
166
+ };
167
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Maximum number of iterations for fixed-point iteration during publishing.
3
+ * Used in both plan generation and actual publishing to resolve transitive dependency cascades.
4
+ *
5
+ * In practice, most repos converge in 2-3 iterations.
6
+ * Deep dependency chains may require more iterations.
7
+ */
8
+ export declare const MAX_ITERATIONS = 10;
9
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Maximum number of iterations for fixed-point iteration during publishing.
3
+ * Used in both plan generation and actual publishing to resolve transitive dependency cascades.
4
+ *
5
+ * In practice, most repos converge in 2-3 iterations.
6
+ * Deep dependency chains may require more iterations.
7
+ */
8
+ export const MAX_ITERATIONS = 10;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Dependency graph data structure and algorithms for multi-repo publishing.
3
+ *
4
+ * Provides `DependencyGraph` class with topological sort and cycle detection.
5
+ * For validation workflow and publishing order computation, see `graph_validation.ts`.
6
+ */
7
+ import type { LocalRepo } from './local_repo.js';
8
+ export declare const DEPENDENCY_TYPE: {
9
+ readonly PROD: "prod";
10
+ readonly PEER: "peer";
11
+ readonly DEV: "dev";
12
+ };
13
+ export type DependencyType = (typeof DEPENDENCY_TYPE)[keyof typeof DEPENDENCY_TYPE];
14
+ export interface DependencySpec {
15
+ type: DependencyType;
16
+ version: string;
17
+ resolved?: string;
18
+ }
19
+ export interface DependencyGraphJson {
20
+ nodes: Array<{
21
+ name: string;
22
+ version: string;
23
+ dependencies: Array<{
24
+ name: string;
25
+ spec: DependencySpec;
26
+ }>;
27
+ dependents: Array<string>;
28
+ publishable: boolean;
29
+ }>;
30
+ edges: Array<{
31
+ from: string;
32
+ to: string;
33
+ }>;
34
+ }
35
+ export interface DependencyNode {
36
+ name: string;
37
+ version: string;
38
+ repo?: LocalRepo;
39
+ dependencies: Map<string, DependencySpec>;
40
+ dependents: Set<string>;
41
+ publishable: boolean;
42
+ }
43
+ export declare class DependencyGraph {
44
+ nodes: Map<string, DependencyNode>;
45
+ edges: Map<string, Set<string>>;
46
+ constructor();
47
+ init_from_repos(repos: Array<LocalRepo>): void;
48
+ get_node(name: string): DependencyNode | undefined;
49
+ get_dependents(name: string): Set<string>;
50
+ get_dependencies(name: string): Map<string, DependencySpec>;
51
+ /**
52
+ * Computes topological sort order for dependency graph.
53
+ *
54
+ * Uses Kahn's algorithm with alphabetical ordering within tiers for
55
+ * deterministic results. Throws if cycles detected.
56
+ *
57
+ * @param exclude_dev if true, excludes dev dependencies to break cycles.
58
+ * Publishing uses exclude_dev=true to handle circular dev deps.
59
+ * @returns array of package names in dependency order (dependencies before dependents)
60
+ * @throws {Error} if circular dependencies detected in included dependency types
61
+ */
62
+ topological_sort(exclude_dev?: boolean): Array<string>;
63
+ detect_cycles(): Array<Array<string>>;
64
+ /**
65
+ * Detects circular dependencies, categorized by severity.
66
+ *
67
+ * Production/peer cycles prevent publishing (impossible to order packages).
68
+ * Dev cycles are normal (test utils, shared configs) and safely ignored.
69
+ *
70
+ * Uses DFS traversal with recursion stack to identify back edges.
71
+ * Deduplicates cycles using sorted cycle keys.
72
+ *
73
+ * @returns object with production_cycles (errors) and dev_cycles (info)
74
+ */
75
+ detect_cycles_by_type(): {
76
+ production_cycles: Array<Array<string>>;
77
+ dev_cycles: Array<Array<string>>;
78
+ };
79
+ toJSON(): DependencyGraphJson;
80
+ }
81
+ /**
82
+ * Builder for creating and analyzing dependency graphs.
83
+ */
84
+ export declare class DependencyGraphBuilder {
85
+ /**
86
+ * Constructs dependency graph from local repos.
87
+ *
88
+ * Two-pass algorithm: first creates nodes, then builds edges (dependents).
89
+ * Prioritizes prod/peer deps over dev deps when same package appears in
90
+ * multiple dependency types (stronger constraint wins).
91
+ *
92
+ * @returns fully initialized dependency graph with all nodes and edges
93
+ */
94
+ build_from_repos(repos: Array<LocalRepo>): DependencyGraph;
95
+ /**
96
+ * Computes publishing order using topological sort with dev deps excluded.
97
+ *
98
+ * Excludes dev dependencies to break circular dev dependency cycles while
99
+ * preserving production/peer dependency ordering. This allows patterns like
100
+ * shared test utilities that depend on each other for development.
101
+ *
102
+ * @returns package names in safe publishing order (dependencies before dependents)
103
+ * @throws {Error} if production/peer cycles detected (cannot be resolved by exclusion)
104
+ */
105
+ compute_publishing_order(graph: DependencyGraph): Array<string>;
106
+ analyze(graph: DependencyGraph): {
107
+ production_cycles: Array<Array<string>>;
108
+ dev_cycles: Array<Array<string>>;
109
+ wildcard_deps: Array<{
110
+ pkg: string;
111
+ dep: string;
112
+ version: string;
113
+ }>;
114
+ missing_peers: Array<{
115
+ pkg: string;
116
+ dep: string;
117
+ }>;
118
+ };
119
+ }
120
+ //# sourceMappingURL=dependency_graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency_graph.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/dependency_graph.ts"],"names":[],"mappings":"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"}