rman 1.2.5 → 2.0.0-beta.2

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 (153) hide show
  1. package/README.md +63 -19
  2. package/cli.d.ts +5 -0
  3. package/cli.js +214 -88
  4. package/commands/build.command.d.ts +177 -3
  5. package/commands/build.command.js +20 -10
  6. package/commands/changed.command.d.ts +80 -3
  7. package/commands/changed.command.js +19 -12
  8. package/commands/changelog.command.d.ts +192 -3
  9. package/commands/changelog.command.js +87 -43
  10. package/commands/config.command.d.ts +44 -3
  11. package/commands/config.command.js +30 -19
  12. package/commands/diff.command.d.ts +37 -3
  13. package/commands/diff.command.js +25 -16
  14. package/commands/exec.command.d.ts +193 -3
  15. package/commands/exec.command.js +60 -58
  16. package/commands/github-release.command.d.ts +154 -3
  17. package/commands/github-release.command.js +67 -37
  18. package/commands/import.command.d.ts +36 -3
  19. package/commands/import.command.js +28 -20
  20. package/commands/info.command.d.ts +35 -7
  21. package/commands/info.command.js +36 -30
  22. package/commands/list.command.d.ts +163 -3
  23. package/commands/list.command.js +109 -71
  24. package/commands/publish.command.d.ts +231 -0
  25. package/commands/publish.command.js +304 -0
  26. package/commands/run.command.d.ts +186 -6
  27. package/commands/run.command.js +26 -72
  28. package/commands/test.command.d.ts +173 -3
  29. package/commands/test.command.js +16 -10
  30. package/commands/version.command.d.ts +317 -3
  31. package/commands/version.command.js +149 -69
  32. package/commands.d.ts +32 -0
  33. package/commands.js +28 -0
  34. package/constants.js +1 -1
  35. package/core/application.d.ts +116 -0
  36. package/core/application.js +143 -0
  37. package/core/command-builder.d.ts +14 -0
  38. package/core/command-builder.js +78 -0
  39. package/core/config.d.ts +180 -50
  40. package/core/config.js +332 -153
  41. package/core/core-services.d.ts +14 -0
  42. package/core/core-services.js +30 -0
  43. package/core/core-targets.d.ts +14 -0
  44. package/core/core-targets.js +16 -0
  45. package/core/custom-command.d.ts +42 -6
  46. package/core/custom-command.js +44 -17
  47. package/core/extends-config.d.ts +13 -5
  48. package/core/extends-config.js +52 -12
  49. package/core/load-config-module.d.ts +28 -0
  50. package/core/load-config-module.js +42 -0
  51. package/core/manifest.d.ts +47 -25
  52. package/core/manifest.js +51 -69
  53. package/core/merge-config.d.ts +33 -34
  54. package/core/merge-config.js +138 -93
  55. package/core/package.d.ts +145 -17
  56. package/core/package.js +128 -36
  57. package/core/plugin-loader.d.ts +65 -0
  58. package/core/plugin-loader.js +234 -0
  59. package/core/plugin.d.ts +135 -90
  60. package/core/plugin.js +70 -173
  61. package/core/publish-target.d.ts +124 -0
  62. package/core/publish-target.js +30 -0
  63. package/core/registry.d.ts +30 -0
  64. package/core/registry.js +47 -0
  65. package/core/repository.d.ts +72 -9
  66. package/core/repository.js +293 -43
  67. package/core/resolve-target.d.ts +1 -1
  68. package/core/resolve-target.js +1 -1
  69. package/core/service.d.ts +49 -0
  70. package/core/service.js +40 -0
  71. package/core/version-scheme.d.ts +23 -1
  72. package/core/version-scheme.js +29 -1
  73. package/core/workspace.d.ts +84 -33
  74. package/core/workspace.js +63 -22
  75. package/index.d.ts +111 -14
  76. package/index.js +85 -9
  77. package/interfaces/rman-config.interface.d.ts +739 -212
  78. package/interfaces/rman-config.interface.js +61 -1
  79. package/package.json +2 -1
  80. package/plugins/builtins.d.ts +44 -0
  81. package/plugins/builtins.js +33 -0
  82. package/plugins/detect.d.ts +78 -0
  83. package/plugins/detect.js +70 -0
  84. package/plugins/node/augmentation/rman.augmentation.d.ts +84 -0
  85. package/plugins/node/augmentation/rman.augmentation.js +1 -0
  86. package/plugins/node/augmentation/system-info.augmentation.d.ts +26 -0
  87. package/plugins/node/augmentation/system-info.augmentation.js +79 -0
  88. package/plugins/node/commands/ci.command.d.ts +131 -0
  89. package/plugins/node/commands/ci.command.js +59 -0
  90. package/plugins/node/commands/clean.command.d.ts +183 -0
  91. package/plugins/node/commands/clean.command.js +73 -0
  92. package/plugins/node/index.d.ts +29 -0
  93. package/plugins/node/index.js +40 -0
  94. package/plugins/node/node-config.interface.d.ts +77 -0
  95. package/plugins/node/node-config.interface.js +7 -0
  96. package/plugins/node/node-manifest.provider.d.ts +68 -0
  97. package/plugins/node/node-manifest.provider.js +125 -0
  98. package/plugins/node/node.platform.d.ts +53 -0
  99. package/plugins/node/node.platform.js +134 -0
  100. package/plugins/node/npm-publish-target.d.ts +73 -0
  101. package/plugins/node/npm-publish-target.js +96 -0
  102. package/plugins/node/services/ci.service.d.ts +47 -0
  103. package/plugins/node/services/ci.service.js +213 -0
  104. package/plugins/node/services/clean.service.d.ts +53 -0
  105. package/plugins/node/services/clean.service.js +237 -0
  106. package/plugins/node/services/publish.service.d.ts +114 -0
  107. package/plugins/node/services/publish.service.js +371 -0
  108. package/plugins/node/services/version-plan.service.d.ts +44 -0
  109. package/plugins/node/services/version-plan.service.js +58 -0
  110. package/plugins/node/utils/npm-view.d.ts +48 -0
  111. package/plugins/node/utils/npm-view.js +71 -0
  112. package/plugins/node/utils/workspace-range.d.ts +26 -0
  113. package/plugins/node/utils/workspace-range.js +28 -0
  114. package/services/change-hash.service.d.ts +2 -2
  115. package/services/change-hash.service.js +2 -2
  116. package/services/changelog.service.d.ts +62 -51
  117. package/services/changelog.service.js +14 -11
  118. package/services/docker-publish.service.d.ts +50 -29
  119. package/services/docker-publish.service.js +43 -20
  120. package/services/exec.service.d.ts +23 -12
  121. package/services/exec.service.js +14 -9
  122. package/services/github-release.service.d.ts +44 -33
  123. package/services/github-release.service.js +13 -10
  124. package/services/import.service.d.ts +25 -14
  125. package/services/import.service.js +9 -5
  126. package/services/list.service.d.ts +62 -10
  127. package/services/list.service.js +62 -15
  128. package/services/run.service.d.ts +22 -13
  129. package/services/run.service.js +262 -223
  130. package/services/version-plan.service.d.ts +27 -4
  131. package/services/version-plan.service.js +42 -15
  132. package/services/version.service.d.ts +31 -11
  133. package/services/version.service.js +29 -13
  134. package/targets/docker.target.d.ts +53 -0
  135. package/targets/docker.target.js +40 -0
  136. package/utils/bin-path.d.ts +6 -7
  137. package/utils/bin-path.js +7 -18
  138. package/utils/branch-guard.d.ts +29 -0
  139. package/utils/branch-guard.js +31 -0
  140. package/utils/exec.d.ts +10 -0
  141. package/utils/exec.js +1 -1
  142. package/utils/logger.d.ts +1 -1
  143. package/utils/logger.js +1 -1
  144. package/utils/package-filter.d.ts +127 -7
  145. package/utils/package-filter.js +197 -16
  146. package/utils/printable-config.d.ts +1 -1
  147. package/utils/printable-config.js +1 -1
  148. package/utils/run-bin.d.ts +10 -0
  149. package/utils/run-bin.js +1 -1
  150. package/utils/run-options.d.ts +97 -0
  151. package/utils/run-options.js +81 -0
  152. package/utils/version-stamp.d.ts +1 -1
  153. package/utils/version-stamp.js +1 -1
@@ -0,0 +1,53 @@
1
+ import type { Repository } from '../../../core/repository.js';
2
+ import type { LogLevel } from '../../../utils/logger.js';
3
+ import type { PackageFilterOptions } from '../../../utils/package-filter.js';
4
+ export declare namespace CleanService {
5
+ interface Options extends PackageFilterOptions {
6
+ /** Show the live progress panel. Default true; auto-disabled when stdout isn't a TTY. */
7
+ progress?: boolean;
8
+ /** Report what would be removed without actually removing anything. Default false. */
9
+ dryRun?: boolean;
10
+ /** Clean the whole repository even when the current directory is inside a single package
11
+ * (which otherwise scopes cleaning to just that package - see `Repository.currentPackage`).
12
+ * Has no effect when already at the repository root, or outside any known package. */
13
+ fromRoot?: boolean;
14
+ /** Verbosity of the classic per-item log (only applies when the live panel is off). Falls back
15
+ * to the root's `.rmanrc logLevel`, then 'info' - see `resolveRootLogLevel`. */
16
+ logLevel?: LogLevel;
17
+ }
18
+ /**
19
+ * `clean`: removes build output across every package (root included) - the replacement for
20
+ * `ts-cleanup`, plus whatever else `.rmanrc clean.include`/`clean.exclude` says to remove.
21
+ *
22
+ * **The `node` built-in's rather than always present, because what it knows how to delete is not
23
+ * repository-shaped knowledge but TypeScript-shaped**: a compiled `.js`/`.js.map`/`.d.ts` beside
24
+ * its `.ts` source, a `*.tsbuildinfo`, and a `node_modules` to skip while looking. A Cargo or Go
25
+ * repository has `cargo clean` and `go clean` and nothing here would fire for it, so a core
26
+ * `clean` was a command that only appeared to be general.
27
+ *
28
+ * The `clean.include`/`clean.exclude` globs move with it, and that is the one cost worth naming:
29
+ * they are ecosystem-neutral, so a repository wanting only those now has to name this plugin (or
30
+ * write the two `rm` lines as a `run` script). Keeping a stub `clean` in core for them would mean
31
+ * two commands with one name and a precedence rule between them - worse than the honest move.
32
+ *
33
+ * For every package not opted out via its own (cascaded) `clean.skip: true`:
34
+ * - deletes compiled `.js`/`.js.map`/`.d.ts` files under its `src`/`test` (see `cleanTsArtifacts`);
35
+ * - deletes any `*.tsbuildinfo` incremental-build cache file anywhere in it;
36
+ * - deletes anything matching its own (cascaded) `clean.include` glob(s), minus `clean.exclude`.
37
+ *
38
+ * `include`/`exclude` are resolved relative to *that* package's own directory - a root-level
39
+ * `.rmanrc` pattern like `packages/*\/build` is naturally evaluated from the repository root
40
+ * (spanning every package in one pass), while a package's own override in its own `.rmanrc`
41
+ * (e.g. `include: ./cache`) only ever reaches that one package, since a package normally
42
+ * overrides rather than merges with the root's value for the same key.
43
+ *
44
+ * Never touches `node_modules` - that's `ci`'s job, not this one.
45
+ *
46
+ * Run from inside a single package's own directory, it only cleans that package unless
47
+ * `options.fromRoot` says otherwise (see `Repository.currentPackage`).
48
+ *
49
+ * Uses the same live progress panel as `run`/`build` (see `../utils/progress-panel.ts`) - unlike
50
+ * `ci`, cleaning genuinely is independent per-package work, so the final per-package tally stays.
51
+ */
52
+ function clean(repository: Repository, options?: Options): Promise<void>;
53
+ }
@@ -0,0 +1,237 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import colors from 'ansi-colors';
4
+ import fg from 'fast-glob';
5
+ import { Logger, resolveRootLogLevel } from '../../../utils/logger.js';
6
+ import { filterPackages } from '../../../utils/package-filter.js';
7
+ import { ProgressPanel } from '../../../utils/progress-panel.js';
8
+ export var CleanService;
9
+ (function (CleanService) {
10
+ /**
11
+ * `clean`: removes build output across every package (root included) - the replacement for
12
+ * `ts-cleanup`, plus whatever else `.rmanrc clean.include`/`clean.exclude` says to remove.
13
+ *
14
+ * **The `node` built-in's rather than always present, because what it knows how to delete is not
15
+ * repository-shaped knowledge but TypeScript-shaped**: a compiled `.js`/`.js.map`/`.d.ts` beside
16
+ * its `.ts` source, a `*.tsbuildinfo`, and a `node_modules` to skip while looking. A Cargo or Go
17
+ * repository has `cargo clean` and `go clean` and nothing here would fire for it, so a core
18
+ * `clean` was a command that only appeared to be general.
19
+ *
20
+ * The `clean.include`/`clean.exclude` globs move with it, and that is the one cost worth naming:
21
+ * they are ecosystem-neutral, so a repository wanting only those now has to name this plugin (or
22
+ * write the two `rm` lines as a `run` script). Keeping a stub `clean` in core for them would mean
23
+ * two commands with one name and a precedence rule between them - worse than the honest move.
24
+ *
25
+ * For every package not opted out via its own (cascaded) `clean.skip: true`:
26
+ * - deletes compiled `.js`/`.js.map`/`.d.ts` files under its `src`/`test` (see `cleanTsArtifacts`);
27
+ * - deletes any `*.tsbuildinfo` incremental-build cache file anywhere in it;
28
+ * - deletes anything matching its own (cascaded) `clean.include` glob(s), minus `clean.exclude`.
29
+ *
30
+ * `include`/`exclude` are resolved relative to *that* package's own directory - a root-level
31
+ * `.rmanrc` pattern like `packages/*\/build` is naturally evaluated from the repository root
32
+ * (spanning every package in one pass), while a package's own override in its own `.rmanrc`
33
+ * (e.g. `include: ./cache`) only ever reaches that one package, since a package normally
34
+ * overrides rather than merges with the root's value for the same key.
35
+ *
36
+ * Never touches `node_modules` - that's `ci`'s job, not this one.
37
+ *
38
+ * Run from inside a single package's own directory, it only cleans that package unless
39
+ * `options.fromRoot` says otherwise (see `Repository.currentPackage`).
40
+ *
41
+ * Uses the same live progress panel as `run`/`build` (see `../utils/progress-panel.ts`) - unlike
42
+ * `ci`, cleaning genuinely is independent per-package work, so the final per-package tally stays.
43
+ */
44
+ async function clean(repository, options = {}) {
45
+ /** Standing inside a single package's own directory scopes cleaning to just that package
46
+ * (root's own artifacts included) unless `--from-root` asks for the whole repository anyway - a
47
+ * no-op when already at the root, or outside any known package. */
48
+ const cwdScope = options.fromRoot ? undefined : repository.currentPackage;
49
+ const packages = repository.getPackages().filter(p => p !== repository.rootPackage);
50
+ const allTargets = cwdScope ? [cwdScope] : [repository.rootPackage, ...packages];
51
+ const targets = filterPackages(allTargets, options).filter(pkg => !cleanConfig(pkg).skip);
52
+ const dryRun = options.dryRun ?? false;
53
+ const progress = options.progress ?? true;
54
+ const logger = new Logger(options.logLevel ?? resolveRootLogLevel(repository));
55
+ const panel = new ProgressPanel(dryRun ? 'CLEAN (dry-run)' : 'CLEAN', !!process.stdout.isTTY && progress);
56
+ panel.start();
57
+ let failed = false;
58
+ try {
59
+ const results = await Promise.allSettled(targets.map(pkg => {
60
+ const label = pkg === repository.rootPackage ? 'root' : pkg.name;
61
+ return cleanPackage(pkg, panel.addItem(label), panel.enabled, dryRun, logger);
62
+ }));
63
+ if (results.some(r => r.status === 'rejected'))
64
+ failed = true;
65
+ }
66
+ finally {
67
+ panel.stop();
68
+ }
69
+ panel.printSummary();
70
+ if (failed) {
71
+ const err = new Error('"clean" failed');
72
+ err.logged = true;
73
+ throw err;
74
+ }
75
+ }
76
+ CleanService.clean = clean;
77
+ })(CleanService || (CleanService = {}));
78
+ /** Directories a package's TypeScript output gets cleaned from, mirroring `ts-cleanup -s src`
79
+ * and `-s test` (the only way it was ever actually invoked in this project's own scripts). */
80
+ const TS_SOURCE_DIRS = ['src', 'test'];
81
+ /** A package's (cascaded) `.rmanrc clean.include`/`clean.exclude`/`clean.skip` - a package that
82
+ * declares its own `clean` block replaces the root's entirely for itself (same as any other
83
+ * rman config key), rather than combining with it. `include`/`exclude` accept a single glob
84
+ * string or an array of them. */
85
+ function cleanConfig(pkg) {
86
+ const cfg = pkg.config?.clean;
87
+ const normalize = (v) => {
88
+ if (Array.isArray(v))
89
+ return v.map(String);
90
+ return typeof v === 'string' && v ? [v] : [];
91
+ };
92
+ return { include: normalize(cfg?.include), exclude: normalize(cfg?.exclude), skip: cfg?.skip === true };
93
+ }
94
+ /** Deletes `file`, unless `dryRun` - either way the caller treats it as removed for reporting. */
95
+ async function remove(file, dryRun) {
96
+ if (!dryRun)
97
+ await fs.promises.rm(file, { force: true });
98
+ }
99
+ /** Removes now-empty directories under `dir`, deepest first (so a parent left empty once its
100
+ * only child is removed gets caught in the same pass). Also removes `dir` itself once empty
101
+ * when `includeSelf` is set - used when `dir` is itself something the user asked to delete
102
+ * (e.g. an `include: build` match), as opposed to a source root like `src`/`test` that should
103
+ * stay even if everything inside it was cleaned out. No-op in dry-run mode: nothing was actually
104
+ * deleted, so there's nothing that could have been left empty. */
105
+ function pruneEmptyDirs(dir, includeSelf, dryRun) {
106
+ if (dryRun || !fs.existsSync(dir))
107
+ return;
108
+ const entries = fg.sync('**', { cwd: dir, onlyDirectories: true, dot: true });
109
+ entries.sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
110
+ for (const rel of entries) {
111
+ const abs = path.join(dir, rel);
112
+ if (fs.existsSync(abs) && fs.readdirSync(abs).length === 0)
113
+ fs.rmdirSync(abs);
114
+ }
115
+ if (includeSelf && fs.readdirSync(dir).length === 0)
116
+ fs.rmdirSync(dir);
117
+ }
118
+ /**
119
+ * Deletes every path matched by `include` (minus `exclude`) under `dirname` - files and
120
+ * directories alike, gulp-`src()`-style. Returns what was actually removed (or, in dry-run mode,
121
+ * what *would* be), relative to `dirname`, so the caller only logs what really happened.
122
+ *
123
+ * `exclude` protects at two levels: a pattern matching a whole `include` result directly (e.g.
124
+ * `packages/pkg1/*` against a matched `packages/pkg1/build` directory) drops that result before
125
+ * anything under it is touched; a finer pattern (e.g. `build/*.json`) instead protects just the
126
+ * matching files *inside* an otherwise-deleted directory, leaving the rest of it gone and the
127
+ * protected files (and their now non-empty parent) in place.
128
+ */
129
+ async function cleanGlobs(dirname, include, exclude, dryRun) {
130
+ if (!include.length)
131
+ return [];
132
+ const matches = await fg(include, { cwd: dirname, ignore: exclude, onlyFiles: false, dot: true, absolute: true });
133
+ const protectedFiles = exclude.length
134
+ ? new Set(await fg(exclude, { cwd: dirname, onlyFiles: true, dot: true, absolute: true }))
135
+ : new Set();
136
+ const removed = [];
137
+ for (const m of matches) {
138
+ const stat = await fs.promises.stat(m).catch(() => undefined);
139
+ if (!stat)
140
+ continue;
141
+ if (stat.isDirectory()) {
142
+ const filesInside = await fg('**', { cwd: m, onlyFiles: true, dot: true, absolute: true });
143
+ for (const f of filesInside) {
144
+ if (protectedFiles.has(f))
145
+ continue;
146
+ await remove(f, dryRun);
147
+ removed.push(path.relative(dirname, f));
148
+ }
149
+ pruneEmptyDirs(m, true, dryRun);
150
+ }
151
+ else if (!protectedFiles.has(m)) {
152
+ await remove(m, dryRun);
153
+ removed.push(path.relative(dirname, m));
154
+ }
155
+ }
156
+ return removed;
157
+ }
158
+ /**
159
+ * Removes compiled TypeScript output (`.js`, `.js.map`, `.d.ts`) sitting next to its `.ts`
160
+ * source under `src`/`test` - the same job `ts-cleanup -s <dir> --all` did (the only mode this
161
+ * project ever actually used it in). A `.d.ts` with no matching `.ts`/`.tsx` is left alone - it's
162
+ * presumably a hand-written declaration file, not build output. Prunes directories left empty
163
+ * afterward.
164
+ */
165
+ async function cleanTsArtifacts(dirname, dryRun) {
166
+ const removed = [];
167
+ for (const sub of TS_SOURCE_DIRS) {
168
+ const dir = path.join(dirname, sub);
169
+ if (!fs.existsSync(dir))
170
+ continue;
171
+ const files = await fg('**/*.{js,js.map,d.ts}', { cwd: dir, onlyFiles: true, dot: true, absolute: true });
172
+ for (const f of files) {
173
+ if (f.endsWith('.d.ts')) {
174
+ const base = f.slice(0, -'.d.ts'.length);
175
+ if (!fs.existsSync(base + '.ts') && !fs.existsSync(base + '.tsx'))
176
+ continue;
177
+ }
178
+ await remove(f, dryRun);
179
+ removed.push(path.relative(dirname, f));
180
+ }
181
+ pruneEmptyDirs(dir, false, dryRun);
182
+ }
183
+ return removed;
184
+ }
185
+ /**
186
+ * Removes TypeScript's incremental-build cache files (`*.tsbuildinfo`) anywhere under `dirname` -
187
+ * `tsc --build`/`composite`/`incremental` output that `ts-cleanup` never touched, but which can
188
+ * leave a project in a stale state if a clean rebuild is expected to start from nothing. Skips
189
+ * `node_modules` (dependencies may ship their own, irrelevant to this package's own build).
190
+ */
191
+ async function cleanTsBuildInfo(dirname, dryRun) {
192
+ const files = await fg('**/*.tsbuildinfo', {
193
+ cwd: dirname,
194
+ ignore: ['**/node_modules/**'],
195
+ onlyFiles: true,
196
+ dot: true,
197
+ absolute: true,
198
+ });
199
+ for (const f of files)
200
+ await remove(f, dryRun);
201
+ return files.map(f => path.relative(dirname, f));
202
+ }
203
+ async function cleanPackage(pkg, item, panelEnabled, dryRun, logger) {
204
+ item.status = 'running';
205
+ item.startedAt = Date.now();
206
+ try {
207
+ item.currentStep = 'ts';
208
+ const tsRemoved = await cleanTsArtifacts(pkg.dirname, dryRun);
209
+ const buildInfoRemoved = await cleanTsBuildInfo(pkg.dirname, dryRun);
210
+ item.currentStep = 'glob';
211
+ const { include, exclude } = cleanConfig(pkg);
212
+ const globRemoved = await cleanGlobs(pkg.dirname, include, exclude, dryRun);
213
+ const removed = [...tsRemoved, ...buildInfoRemoved, ...globRemoved];
214
+ const verb = dryRun ? 'would rm' : 'rm';
215
+ if (panelEnabled) {
216
+ item.lastLine = removed.length
217
+ ? `${dryRun ? 'would remove' : 'removed'} ${removed.length} item(s)`
218
+ : 'already clean';
219
+ }
220
+ else if (removed.length) {
221
+ for (const r of removed)
222
+ logger.info(colors.yellow(verb), colors.cyan(item.name), r);
223
+ }
224
+ else {
225
+ logger.info(colors.gray('clean'), colors.cyan(item.name));
226
+ }
227
+ item.status = 'success';
228
+ }
229
+ catch (e) {
230
+ item.status = 'failed';
231
+ item.log.push(e?.message ?? String(e));
232
+ throw e;
233
+ }
234
+ finally {
235
+ item.finishedAt = Date.now();
236
+ }
237
+ }
@@ -0,0 +1,114 @@
1
+ import type { Package } from '../../../core/package.js';
2
+ import type { Repository } from '../../../core/repository.js';
3
+ import type { PackageFilterOptions } from '../../../utils/package-filter.js';
4
+ import { type NpmPackageView } from '../utils/npm-view.js';
5
+ import { CiService } from './ci.service.js';
6
+ export declare namespace PublishService {
7
+ /** Injectable registry lookup - mainly for tests, so they don't depend on network access or a
8
+ * real published package. */
9
+ interface Deps {
10
+ npmViewPackage?: (name: string, cwd: string) => Promise<NpmPackageView | undefined>;
11
+ }
12
+ interface Options extends PackageFilterOptions {
13
+ /** A package with uncommitted local changes is excluded (status `'skip'`) instead of aborting
14
+ * the whole plan (status `'error'`) - same as `version`'s own option. Default false. */
15
+ ignoreDirty?: boolean;
16
+ /** Registry to check against (and, in `applyPlan`, publish to) - `.npmrc`'s own configured
17
+ * registry is used when omitted. */
18
+ registry?: string;
19
+ /** Path to a custom `.npmrc`, for both the registry check and the actual publish. */
20
+ userconfig?: string;
21
+ /**
22
+ * `npm publish --tag <tag>` - the dist-tag to publish under, overriding what the version
23
+ * itself implies.
24
+ *
25
+ * **Usually unnecessary**: a prerelease is published under its own identifier (`2.0.0-beta.1`
26
+ * -> `beta`) and a release under npm's `latest`, neither needing to be asked for. Pass this to
27
+ * send a release somewhere other than `latest`, or a prerelease to a tag that is not its
28
+ * identifier (`next` for every preview, say). See `distTagFor`.
29
+ *
30
+ * **A plan option rather than an apply-only one**, because the tag is decided in the plan: it
31
+ * is printed beside each package and recorded as `Entry.distTag`, so `--dry-run` and the JSON
32
+ * a release pipeline gates on both show where a version is going.
33
+ */
34
+ tag?: string;
35
+ }
36
+ interface ApplyOptions extends Options {
37
+ packageManager?: CiService.PackageManager;
38
+ /** `npm publish --access <access>` - required by the registry for a *new* scoped package. */
39
+ access?: 'public' | 'restricted';
40
+ /** `npm publish --otp <otp>` - a 2FA one-time password, for registries that require it. */
41
+ otp?: string;
42
+ /** Subdirectory to publish from, relative to the package's own directory - only consulted when
43
+ * the package doesn't already declare its own `package.json` `publishConfig.directory` (npm's
44
+ * native mechanism for this, which always wins when present). */
45
+ contents?: string;
46
+ }
47
+ /** One package's outcome in a publish plan - see `getPlan`. */
48
+ interface Entry {
49
+ package: Package;
50
+ version: string;
51
+ status: 'publish' | 'skip' | 'up-to-date' | 'error';
52
+ /** What the registry's **`latest` dist-tag** points at, if anything - only set once a registry
53
+ * check actually ran. Reported rather than compared: whether *this* version is published is a
54
+ * different question, and `getPlan` answers it from the published `versions`. */
55
+ registryVersion?: string;
56
+ /**
57
+ * The dist-tag this entry will publish under - `--tag` when given, otherwise the version's own
58
+ * prerelease identifier (`2.0.0-beta.1` -> `beta`), and `undefined` for an ordinary release,
59
+ * which npm puts on `latest`.
60
+ *
61
+ * **Decided in the plan and read back by `applyPlan`, rather than recomputed there.** The plan
62
+ * is what a reader confirms and what a pipeline gates on, so the tag has to be part of what it
63
+ * says; recomputing at publish time would let the two disagree about where a package is going.
64
+ */
65
+ distTag?: string;
66
+ /** `PublishTarget.Entry`'s own field - what the core's `publish` prints beside the package
67
+ * name. Carries the dist-tag, so where a version is going is visible in the plan and in
68
+ * `--dry-run --json` without the core knowing anything about npm. */
69
+ detail?: string;
70
+ reason?: string;
71
+ }
72
+ /**
73
+ * Computes what `publish` *would* do, across every non-private package (topological order,
74
+ * dependencies before dependents) - never touches the registry to publish anything, just
75
+ * queries it to decide, so it's safe to call any time, including as the plan a bare `rman
76
+ * publish` shows before asking for confirmation.
77
+ *
78
+ * A `private: true` package is always `'skip'`ped outright. Each remaining package's **dist-tag**
79
+ * is settled next (`distTagFor`): usually derived from the version itself, `'error'` in the two
80
+ * cases with nothing to derive - that one is about the invocation rather than the package, so it
81
+ * is answered before anything touches the network. A package with uncommitted local changes is
82
+ * `'error'` too (aborts the whole plan) unless `options.ignoreDirty` downgrades it to `'skip'`
83
+ * instead - same rule `version` uses, since publishing untracked local edits is worse than a bad
84
+ * commit.
85
+ *
86
+ * Otherwise the registry decides, via one `npmViewPackage` per remaining package (run
87
+ * concurrently): **the local version being among the published `versions`** is `'up-to-date'`,
88
+ * anything else - including never having been published at all - is `'publish'`. Deliberately not
89
+ * a comparison against `latest`, which answers a different question and disagrees with this one
90
+ * the moment a prerelease ships under its own dist-tag; see `npmViewPackage`.
91
+ *
92
+ * Deliberately decoupled from `version`: this only ever looks at what's *currently* on disk and
93
+ * on the registry, never at whether `version` was just run - so it works equally well right
94
+ * after a version bump, or standing alone in a release pipeline that bumped days earlier.
95
+ *
96
+ * A monorepo's root package is never a candidate at all - `repository.getPackages()` already
97
+ * excludes it for a real monorepo (it only doubles as "the" package in a single-package repo,
98
+ * where it's a normal candidate like any other).
99
+ */
100
+ function getPlan(repository: Repository, options?: Options, deps?: Deps): Promise<Entry[]>;
101
+ /**
102
+ * Publishes every `'publish'` entry in `plan`, topological order (already `plan`'s own order -
103
+ * see `getPlan`), via the configured `packageManager`'s own `publish` command. Sequential, not
104
+ * concurrent: unlike `run`/`build`, a package genuinely needs its own dependencies to have
105
+ * landed on the registry first, and publishing is rare enough (once per release) that the
106
+ * simplicity is worth more than the parallelism `run` gets from `power-tasks`.
107
+ *
108
+ * If a package fails, every other still-pending entry depending on it (transitively) is marked
109
+ * `'error'` too and never attempted - publishing a package whose own new dependency range points
110
+ * at a version that never actually reached the registry would hand consumers a broken install.
111
+ * A package's own failure doesn't stop unrelated packages elsewhere in the plan, though.
112
+ */
113
+ function applyPlan(repository: Repository, plan: Entry[], options?: ApplyOptions): Promise<Entry[]>;
114
+ }