rman 2.0.0-beta.2 → 2.0.0-beta.3

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 (164) hide show
  1. package/README.md +2 -12
  2. package/{plugins/node/augmentation/rman.augmentation.d.ts → builtins/platforms/node/augmentation/rmanrc.augmentation.d.ts} +4 -5
  3. package/{plugins → builtins/platforms}/node/augmentation/system-info.augmentation.js +1 -1
  4. package/{plugins → builtins/platforms}/node/commands/ci.command.d.ts +5 -3
  5. package/{plugins → builtins/platforms}/node/commands/ci.command.js +6 -5
  6. package/{plugins → builtins/platforms}/node/commands/clean.command.d.ts +6 -4
  7. package/{plugins → builtins/platforms}/node/commands/clean.command.js +6 -5
  8. package/builtins/platforms/node/index.d.ts +8 -0
  9. package/builtins/platforms/node/index.js +8 -0
  10. package/{plugins → builtins/platforms}/node/node-config.interface.d.ts +1 -2
  11. package/{plugins → builtins/platforms}/node/node-manifest.provider.d.ts +3 -3
  12. package/{plugins → builtins/platforms}/node/node-manifest.provider.js +3 -3
  13. package/{plugins → builtins/platforms}/node/node.platform.d.ts +3 -3
  14. package/{plugins → builtins/platforms}/node/services/ci.service.d.ts +3 -3
  15. package/{plugins → builtins/platforms}/node/services/ci.service.js +4 -4
  16. package/{plugins → builtins/platforms}/node/services/clean.service.d.ts +3 -3
  17. package/{plugins → builtins/platforms}/node/services/clean.service.js +3 -3
  18. package/{plugins → builtins/platforms}/node/services/publish.service.d.ts +4 -4
  19. package/{plugins → builtins/platforms}/node/services/publish.service.js +5 -5
  20. package/{plugins → builtins/platforms}/node/services/version-plan.service.d.ts +3 -3
  21. package/{plugins → builtins/platforms}/node/services/version-plan.service.js +2 -2
  22. package/builtins/presets/index.d.ts +15 -0
  23. package/builtins/presets/index.js +57 -0
  24. package/builtins/presets/node.d.ts +16 -0
  25. package/builtins/presets/node.js +57 -0
  26. package/{services → builtins/publish-targets/docker}/docker-publish.service.d.ts +6 -6
  27. package/{services → builtins/publish-targets/docker}/docker-publish.service.js +9 -9
  28. package/{targets → builtins/publish-targets/docker}/docker.target.d.ts +6 -5
  29. package/{targets → builtins/publish-targets/docker}/docker.target.js +1 -1
  30. package/builtins/publish-targets/docker/index.d.ts +2 -0
  31. package/builtins/publish-targets/docker/index.js +2 -0
  32. package/builtins/publish-targets/npm/index.d.ts +2 -0
  33. package/builtins/publish-targets/npm/index.js +2 -0
  34. package/{plugins/node → builtins/publish-targets/npm}/npm-publish-target.d.ts +4 -4
  35. package/{plugins/node → builtins/publish-targets/npm}/npm-publish-target.js +4 -5
  36. package/cli.d.ts +3 -0
  37. package/cli.js +16 -7
  38. package/commands/changelog.command.d.ts +106 -2
  39. package/commands/changelog.command.js +40 -0
  40. package/commands/config.command.js +23 -5
  41. package/commands/lint.command.d.ts +176 -0
  42. package/commands/lint.command.js +34 -0
  43. package/commands/list.command.js +1 -1
  44. package/commands/publish.command.d.ts +1 -1
  45. package/commands/publish.command.js +1 -1
  46. package/commands/run.command.js +1 -1
  47. package/commands/version.command.d.ts +16 -3
  48. package/commands/version.command.js +143 -9
  49. package/commands.d.ts +1 -1
  50. package/commands.js +1 -1
  51. package/constants.js +1 -1
  52. package/core/application.d.ts +10 -10
  53. package/core/application.js +28 -11
  54. package/core/{package.d.ts → classes/package.d.ts} +12 -4
  55. package/core/{package.js → classes/package.js} +17 -1
  56. package/core/{repository.d.ts → classes/repository.d.ts} +22 -36
  57. package/core/{repository.js → classes/repository.js} +112 -241
  58. package/core/{service.d.ts → classes/service.d.ts} +2 -2
  59. package/core/classes/workspace.d.ts +275 -0
  60. package/core/classes/workspace.js +537 -0
  61. package/core/command-builder.js +17 -1
  62. package/core/config/config-file-scope.d.ts +107 -0
  63. package/core/config/config-file-scope.js +226 -0
  64. package/core/config/config-interpolator.d.ts +164 -0
  65. package/core/config/config-interpolator.js +577 -0
  66. package/core/config/config-paths.d.ts +65 -0
  67. package/core/config/config-paths.js +78 -0
  68. package/core/config/config-reader.d.ts +192 -0
  69. package/core/config/config-reader.js +727 -0
  70. package/core/{merge-config.js → config/merge-config.js} +4 -8
  71. package/core/{custom-command.d.ts → interfaces/custom-command.d.ts} +5 -5
  72. package/core/{manifest.d.ts → interfaces/manifest.d.ts} +3 -3
  73. package/core/{manifest.js → interfaces/manifest.js} +2 -2
  74. package/core/{plugin.d.ts → interfaces/plugin.d.ts} +44 -27
  75. package/core/{plugin.js → interfaces/plugin.js} +48 -10
  76. package/core/{publish-target.d.ts → interfaces/publish-target.d.ts} +24 -12
  77. package/core/{publish-target.js → interfaces/publish-target.js} +16 -3
  78. package/core/{run-step.d.ts → interfaces/run-step.d.ts} +4 -4
  79. package/core/plugin-loader.d.ts +11 -51
  80. package/core/plugin-loader.js +21 -202
  81. package/index.d.ts +29 -28
  82. package/index.js +20 -46
  83. package/interfaces/config-scope.interface.d.ts +223 -0
  84. package/interfaces/config-scope.interface.js +1 -0
  85. package/interfaces/rman-config.interface.d.ts +100 -5
  86. package/interfaces/rman-config.interface.js +17 -0
  87. package/package.json +2 -1
  88. package/services/change-hash.service.d.ts +40 -6
  89. package/services/change-hash.service.js +90 -11
  90. package/services/changelog.service.d.ts +31 -3
  91. package/services/changelog.service.js +448 -65
  92. package/services/config-service.d.ts +8 -0
  93. package/services/config-service.js +3 -0
  94. package/services/exec.service.d.ts +2 -2
  95. package/services/exec.service.js +1 -1
  96. package/services/github-release.service.d.ts +3 -3
  97. package/services/github-release.service.js +3 -3
  98. package/services/import.service.d.ts +2 -2
  99. package/services/import.service.js +1 -1
  100. package/services/list.service.d.ts +9 -7
  101. package/services/list.service.js +2 -2
  102. package/services/run.service.d.ts +15 -11
  103. package/services/run.service.js +62 -18
  104. package/services/system-info.d.ts +1 -1
  105. package/services/version-plan.service.d.ts +8 -4
  106. package/services/version-plan.service.js +54 -21
  107. package/services/version.service.d.ts +5 -5
  108. package/services/version.service.js +7 -4
  109. package/services.d.ts +1 -1
  110. package/services.js +1 -1
  111. package/utils/branch-guard.d.ts +1 -1
  112. package/utils/color-yaml.d.ts +8 -0
  113. package/utils/color-yaml.js +86 -0
  114. package/utils/git.d.ts +26 -0
  115. package/utils/git.js +65 -0
  116. package/utils/logger.d.ts +1 -1
  117. package/utils/package-filter.d.ts +8 -1
  118. package/utils/package-filter.js +7 -0
  119. package/utils/printable-config.d.ts +8 -0
  120. package/utils/printable-config.js +45 -0
  121. package/utils/progress-panel.d.ts +9 -0
  122. package/utils/progress-panel.js +23 -1
  123. package/utils/release-version.d.ts +1 -1
  124. package/utils/run-options.js +1 -1
  125. package/utils/version-group.d.ts +31 -0
  126. package/utils/version-group.js +43 -0
  127. package/commands/changed.command.d.ts +0 -80
  128. package/commands/changed.command.js +0 -36
  129. package/core/config.d.ts +0 -530
  130. package/core/config.js +0 -1123
  131. package/core/core-services.d.ts +0 -14
  132. package/core/core-services.js +0 -30
  133. package/core/core-targets.d.ts +0 -14
  134. package/core/core-targets.js +0 -16
  135. package/core/extends-config.d.ts +0 -35
  136. package/core/extends-config.js +0 -129
  137. package/core/load-config-module.d.ts +0 -28
  138. package/core/load-config-module.js +0 -42
  139. package/core/workspace.d.ts +0 -119
  140. package/core/workspace.js +0 -124
  141. package/plugins/builtins.d.ts +0 -44
  142. package/plugins/builtins.js +0 -33
  143. package/plugins/detect.d.ts +0 -78
  144. package/plugins/detect.js +0 -70
  145. package/plugins/node/index.d.ts +0 -29
  146. package/plugins/node/index.js +0 -40
  147. /package/{core/run-step.js → builtins/platforms/node/augmentation/rmanrc.augmentation.js} +0 -0
  148. /package/{plugins → builtins/platforms}/node/augmentation/system-info.augmentation.d.ts +0 -0
  149. /package/{plugins → builtins/platforms}/node/node-config.interface.js +0 -0
  150. /package/{plugins → builtins/platforms}/node/node.platform.js +0 -0
  151. /package/{plugins → builtins/platforms}/node/utils/workspace-range.d.ts +0 -0
  152. /package/{plugins → builtins/platforms}/node/utils/workspace-range.js +0 -0
  153. /package/{plugins/node/utils → builtins/publish-targets/npm}/npm-view.d.ts +0 -0
  154. /package/{plugins/node/utils → builtins/publish-targets/npm}/npm-view.js +0 -0
  155. /package/core/{registry.d.ts → classes/registry.d.ts} +0 -0
  156. /package/core/{registry.js → classes/registry.js} +0 -0
  157. /package/core/{service.js → classes/service.js} +0 -0
  158. /package/core/{version-scheme.d.ts → classes/version-scheme.d.ts} +0 -0
  159. /package/core/{version-scheme.js → classes/version-scheme.js} +0 -0
  160. /package/core/{merge-config.d.ts → config/merge-config.d.ts} +0 -0
  161. /package/core/{resolve-target.d.ts → config/resolve-config-target.d.ts} +0 -0
  162. /package/core/{resolve-target.js → config/resolve-config-target.js} +0 -0
  163. /package/core/{custom-command.js → interfaces/custom-command.js} +0 -0
  164. /package/{plugins/node/augmentation/rman.augmentation.js → core/interfaces/run-step.js} +0 -0
@@ -42,6 +42,14 @@ const config = {
42
42
  type: 'boolean',
43
43
  conflicts: 'interactive',
44
44
  },
45
+ json: {
46
+ target: 'cli',
47
+ alias: 'j',
48
+ describe: 'Print the plan as JSON and write nothing - the machine-readable form of --show, and what ' +
49
+ 'the removed "changed" command was for.',
50
+ type: 'boolean',
51
+ conflicts: ['interactive', 'yes'],
52
+ },
45
53
  ignoreDirty: {
46
54
  target: 'cli',
47
55
  cliName: 'ignore-dirty',
@@ -165,6 +173,38 @@ const versionCommand = registerCommand(app => {
165
173
  ignoreDirty: args.ignoreDirty,
166
174
  preid: args.preid,
167
175
  });
176
+ /**
177
+ * **The machine-readable plan, and the whole of it.** This replaced `rman changed`, which
178
+ * was `getPlan` filtered to `status === 'bump'` - and that one-line filter produced two
179
+ * silent wrongs at once, measured together on a dirty tree: the entry it returned was the
180
+ * repository **root** (`buildRootEntry` reports `'bump'`, and the fact that it is
181
+ * informational lived only in `reason`), while `pkg-a`, the package that had actually
182
+ * changed, was dropped because a package with uncommitted changes is `'error'`. A CI script
183
+ * reading that array saw one name to release and it was the one name that must never be
184
+ * published.
185
+ *
186
+ * So nothing is filtered here. Every entry carries its own `status`, and `isRoot` is stated
187
+ * rather than left to be inferred from `group === "root"` - a consumer selects what it wants
188
+ * and can see what it is leaving out. Printed **before** the table and before the
189
+ * dirty-package throw, so stdout holds one JSON document and nothing else.
190
+ *
191
+ * **Exit 0 either way, deliberately.** `--show` exits 1 on a dirty package because a person
192
+ * needs stopping; here the same fact is in the data, and overloading the exit code would
193
+ * make a pipeline bail before it could read the very rows that explain why.
194
+ */
195
+ if (args.json) {
196
+ console.log(JSON.stringify(plan.map(e => ({
197
+ name: e.package.name,
198
+ selector: e.package.selector,
199
+ isRoot: e.package.isRoot,
200
+ group: e.group,
201
+ status: e.status,
202
+ from: e.from,
203
+ to: e.to,
204
+ reason: e.reason,
205
+ })), undefined, 2));
206
+ return;
207
+ }
168
208
  printPlan(plan);
169
209
  const errors = plan.filter(e => e.status === 'error');
170
210
  if (errors.length) {
@@ -236,18 +276,112 @@ function printApplied(result) {
236
276
  }
237
277
  function printPlan(entries) {
238
278
  const table = new EasyTable();
239
- for (const e of entries) {
240
- table.cell('Status', statusLabel(e.status));
241
- table.cell('Package', colors.cyan(e.package.name));
242
- table.cell('Group', colors.gray(`(${e.group})`));
243
- table.cell('From', e.from);
244
- table.cell('', e.status === 'bump' ? '->' : '');
245
- table.cell('To', e.status === 'bump' ? colors.yellow(e.to) : '');
246
- table.cell('Reason', e.status === 'error' ? colors.red(e.reason ?? '') : colors.gray(e.reason ?? ''));
247
- table.newRow();
279
+ let first = true;
280
+ for (const { members, shared } of planBlocks(entries)) {
281
+ if (!first)
282
+ table.pushDelimeter(PLAN_COLUMNS);
283
+ first = false;
284
+ for (const e of members)
285
+ printPlanRow(table, e, shared);
248
286
  }
249
287
  console.log(table.toString().trim());
250
288
  }
289
+ /**
290
+ * The plan, split into the blocks a delimiter is drawn between: the **repository root** first, then
291
+ * every shared version line with its members together, then the packages that share a line with
292
+ * nobody.
293
+ *
294
+ * `getPlan` returns entries in *package* order, which is the order the workspace found them in -
295
+ * so two members of one group are adjacent only by luck. That matters more than it looks: a group
296
+ * releases as one version line, so "these four numbers move together" is the single fact the table
297
+ * exists to convey, and scattering the members leaves the `Group` column as the only thing saying
298
+ * so. Read top to bottom instead, each block now *is* a release.
299
+ *
300
+ * **The root is first, and it is the one row that is not a release.** Its number is the
301
+ * repository's identity - what the GitHub Release is named after, and on a calendar version a
302
+ * number no package shares - so it is the heading the rest of the table sits under rather than a
303
+ * footnote to it. `buildRootEntry` appends it, which is why it is pulled out by hand here; leaving
304
+ * it where the plan put it made it the last singleton, indistinguishable from a package that
305
+ * happens to be grouped with no one.
306
+ *
307
+ * **Solo packages are one block, not one block each.** `group: false` makes every package its own
308
+ * group of one, so a delimiter per group would draw a line between every row in exactly the
309
+ * repository that has nothing to group - noise standing in for structure. They share a block
310
+ * because what they have in common is real: none of them is tied to anyone else.
311
+ *
312
+ * `shared` travels with each block because it is also what decides whether the `Group` column is
313
+ * written at all - see `printPlanRow`. One partition, asked once, answering both questions; working
314
+ * it out again at the cell would be a second rule that could disagree with the blocks beside it.
315
+ */
316
+ function planBlocks(entries) {
317
+ /**
318
+ * `package.isRoot` is by **directory**, which is the only reliable test - `Repository extends
319
+ * Package` while holding a separate `rootPackage` instance for the same directory, so an identity
320
+ * check answers `false` for one of the two objects that are both the root.
321
+ *
322
+ * In a single-package repository that one package *is* the root and `getPlan` pushes no root
323
+ * entry of its own, so it lands here and prints alone - one row, and no delimiter to draw.
324
+ */
325
+ const root = entries.filter(e => e.package.isRoot);
326
+ const members = entries.filter(e => !e.package.isRoot);
327
+ const byGroup = new Map();
328
+ for (const e of members) {
329
+ const group = byGroup.get(e.groupKey);
330
+ if (group)
331
+ group.push(e);
332
+ else
333
+ byGroup.set(e.groupKey, [e]);
334
+ }
335
+ const shared = [];
336
+ const solo = [];
337
+ for (const group of byGroup.values()) {
338
+ if (group.length > 1)
339
+ shared.push({ members: group, shared: true });
340
+ else
341
+ solo.push(group[0]);
342
+ }
343
+ return [
344
+ ...(root.length ? [{ members: root, shared: false }] : []),
345
+ ...shared,
346
+ ...(solo.length ? [{ members: solo, shared: false }] : []),
347
+ ];
348
+ }
349
+ /** `buildRootEntry`'s display label. Named here because `printPlanRow` has to recognize the one
350
+ * singleton whose group is worth printing, and a bare `'root'` in a condition reads as a guess. */
351
+ const ROOT_GROUP = 'root';
352
+ /** The column names in the order `printPlanRow` writes them - `pushDelimeter` has to be handed the
353
+ * same set, or the dashes appear under a column that does not exist yet. */
354
+ const PLAN_COLUMNS = ['Status', 'Package', 'Group', 'From', '', 'To', 'Reason'];
355
+ function printPlanRow(table, e, shared) {
356
+ table.cell('Status', statusLabel(e.status));
357
+ table.cell('Package', colors.cyan(e.package.name));
358
+ /**
359
+ * **Blank for a package that shares its version line with nobody.** `resolveGroupKey` gives an
360
+ * ungrouped package a group of one named after the package, so the cell printed the Package
361
+ * column again, one column to the right - a word that looks like information and carries none.
362
+ * Worse, it made `(default)` and `(@panates/tsconfig)` read as the same *kind* of answer when one
363
+ * names a line four packages move along and the other names nothing at all.
364
+ *
365
+ * The root keeps its label: `root` is not its package name but what the row *is*, and it is the
366
+ * only thing on the line saying that the number below is the repository's identity rather than a
367
+ * release. So the test is `shared`, plus that one entry - not "does this string repeat the name",
368
+ * which would blank a genuine group that happened to be called after one of its members.
369
+ */
370
+ table.cell('Group', shared || e.group === ROOT_GROUP ? colors.gray(`(${e.group})`) : '');
371
+ table.cell('From', e.from);
372
+ /**
373
+ * Gated on `to`, not on `status === 'bump'`, which is what kept the column blank on the one
374
+ * command whose whole job is to fill it: a dirty package aborts the run, and "you cannot
375
+ * release this" is only half of what the reader came for - the other half is which version it
376
+ * would have got. `getPlan` sets `to` on exactly the entries that earned one, so asking whether
377
+ * there is a version to show is the honest test. Dimmed rather than yellow when the entry is
378
+ * not a bump, because that number is a hypothetical and nothing is going to write it.
379
+ */
380
+ table.cell('', e.to ? '->' : '');
381
+ table.cell('To', e.to ? (e.status === 'bump' ? colors.yellow(e.to) : colors.gray(e.to)) : '');
382
+ table.cell('Reason', e.status === 'error' ? colors.red(e.reason ?? '') : colors.gray(e.reason ?? ''));
383
+ table.newRow();
384
+ }
251
385
  function statusLabel(status) {
252
386
  switch (status) {
253
387
  case 'bump':
package/commands.d.ts CHANGED
@@ -13,7 +13,6 @@
13
13
  * being hand-written centrally, in what is now `rman-config.interface.ts`).
14
14
  */
15
15
  import './commands/build.command.js';
16
- import './commands/changed.command.js';
17
16
  import './commands/changelog.command.js';
18
17
  import './commands/config.command.js';
19
18
  import './commands/diff.command.js';
@@ -21,6 +20,7 @@ import './commands/exec.command.js';
21
20
  import './commands/github-release.command.js';
22
21
  import './commands/import.command.js';
23
22
  import './commands/info.command.js';
23
+ import './commands/lint.command.js';
24
24
  import './commands/list.command.js';
25
25
  import './commands/publish.command.js';
26
26
  import './commands/run.command.js';
package/commands.js CHANGED
@@ -13,7 +13,6 @@
13
13
  * being hand-written centrally, in what is now `rman-config.interface.ts`).
14
14
  */
15
15
  import './commands/build.command.js';
16
- import './commands/changed.command.js';
17
16
  import './commands/changelog.command.js';
18
17
  import './commands/config.command.js';
19
18
  import './commands/diff.command.js';
@@ -21,6 +20,7 @@ import './commands/exec.command.js';
21
20
  import './commands/github-release.command.js';
22
21
  import './commands/import.command.js';
23
22
  import './commands/info.command.js';
23
+ import './commands/lint.command.js';
24
24
  import './commands/list.command.js';
25
25
  import './commands/publish.command.js';
26
26
  import './commands/run.command.js';
package/constants.js CHANGED
@@ -1 +1 @@
1
- export const version = '2.0.0-beta.2';
1
+ export const version = '2.0.0-beta.3';
@@ -1,10 +1,10 @@
1
1
  import type { VersionPlanService } from '../services/version-plan.service.js';
2
2
  import { Logger, type LogLevel } from '../utils/logger.js';
3
- import { type Platform, type Plugin } from './plugin.js';
4
- import type { PublishTarget } from './publish-target.js';
5
- import { Registry } from './registry.js';
6
- import type { Repository } from './repository.js';
7
- import type { ServiceFactory, ServiceMap } from './service.js';
3
+ import { Registry } from './classes/registry.js';
4
+ import type { Repository } from './classes/repository.js';
5
+ import type { ServiceFactory, ServiceMap } from './classes/service.js';
6
+ import { type Platform, type Plugin } from './interfaces/plugin.js';
7
+ import type { PublishTarget } from './interfaces/publish-target.js';
8
8
  /**
9
9
  * **One rman invocation, and everything it holds.** Created before anything else, handed to every
10
10
  * plugin's `init`, and the owner of every registry and service that used to be a module-level
@@ -62,6 +62,11 @@ export declare class RmanApplication {
62
62
  */
63
63
  versionPlanner?: VersionPlanService;
64
64
  readonly logger: Logger;
65
+ /** `info` until `--log-level` or `.rmanrc "logLevel"` is resolved - which cannot happen here,
66
+ * since reading the config is itself work the application does. */
67
+ constructor(options?: {
68
+ logLevel?: LogLevel;
69
+ });
65
70
  /** Which platform claims a directory - the first whose manifest provider recognizes it, because
66
71
  * before a package is read there is nothing else to go on. `basePlatform` when none does, so the
67
72
  * caller needs no guard. */
@@ -76,11 +81,6 @@ export declare class RmanApplication {
76
81
  * made a real mistake, and `undefined` would let it write a check that silently does nothing.
77
82
  */
78
83
  get repository(): Repository;
79
- /** `info` until `--log-level` or `.rmanrc "logLevel"` is resolved - which cannot happen here,
80
- * since reading the config is itself work the application does. */
81
- constructor(options?: {
82
- logLevel?: LogLevel;
83
- });
84
84
  /**
85
85
  * The single instance of a service, built on first use.
86
86
  *
@@ -1,8 +1,15 @@
1
+ import { DockerPublishService, dockerPublishTarget } from '../builtins/publish-targets/docker/index.js';
2
+ import { ChangelogService } from '../services/changelog.service.js';
3
+ import { ConfigService } from '../services/config-service.js';
4
+ import { ExecService } from '../services/exec.service.js';
5
+ import { GithubReleaseService } from '../services/github-release.service.js';
6
+ import { ImportService } from '../services/import.service.js';
7
+ import { ListService } from '../services/list.service.js';
8
+ import { RunService } from '../services/run.service.js';
9
+ import { VersionService } from '../services/version.service.js';
1
10
  import { Logger } from '../utils/logger.js';
2
- import { registerCoreServices } from './core-services.js';
3
- import { registerCoreTargets } from './core-targets.js';
4
- import { basePlatform } from './plugin.js';
5
- import { Registry } from './registry.js';
11
+ import { Registry } from './classes/registry.js';
12
+ import { basePlatform } from './interfaces/plugin.js';
6
13
  /**
7
14
  * **One rman invocation, and everything it holds.** Created before anything else, handed to every
8
15
  * plugin's `init`, and the owner of every registry and service that used to be a module-level
@@ -60,6 +67,23 @@ export class RmanApplication {
60
67
  */
61
68
  versionPlanner;
62
69
  logger;
70
+ /** `info` until `--log-level` or `.rmanrc "logLevel"` is resolved - which cannot happen here,
71
+ * since reading the config is itself work the application does. */
72
+ constructor(options) {
73
+ this.logger = new Logger(options?.logLevel ?? 'info');
74
+ // Register core services.
75
+ this.setService('config', a => new ConfigService(a));
76
+ this.setService('changelog', a => new ChangelogService(a));
77
+ this.setService('dockerPublish', a => new DockerPublishService(a));
78
+ this.setService('githubRelease', a => new GithubReleaseService(a));
79
+ this.setService('exec', a => new ExecService(a));
80
+ this.setService('import', a => new ImportService(a));
81
+ this.setService('list', a => new ListService(a));
82
+ this.setService('run', a => new RunService(a));
83
+ this.setService('version', a => new VersionService(a));
84
+ // Register core targets.
85
+ this.publishTargets.add(dockerPublishTarget);
86
+ }
63
87
  /** Which platform claims a directory - the first whose manifest provider recognizes it, because
64
88
  * before a package is read there is nothing else to go on. `basePlatform` when none does, so the
65
89
  * caller needs no guard. */
@@ -82,13 +106,6 @@ export class RmanApplication {
82
106
  }
83
107
  return this._repository;
84
108
  }
85
- /** `info` until `--log-level` or `.rmanrc "logLevel"` is resolved - which cannot happen here,
86
- * since reading the config is itself work the application does. */
87
- constructor(options) {
88
- this.logger = new Logger(options?.logLevel ?? 'info');
89
- registerCoreServices(this);
90
- registerCoreTargets(this);
91
- }
92
109
  /**
93
110
  * The single instance of a service, built on first use.
94
111
  *
@@ -1,7 +1,7 @@
1
- import type { RmanApplication } from './application.js';
2
- import type { ResolvedConfig } from './config.js';
3
- import { Manifest } from './manifest.js';
4
- import type { Platform } from './plugin.js';
1
+ import type { ResolvedConfig, RmanConfig } from '../../interfaces/rman-config.interface.js';
2
+ import type { RmanApplication } from '../application.js';
3
+ import { Manifest } from '../interfaces/manifest.js';
4
+ import type { Platform } from '../interfaces/plugin.js';
5
5
  import type { Repository } from './repository.js';
6
6
  import { type VersionScheme } from './version-scheme.js';
7
7
  export declare class Package {
@@ -35,6 +35,14 @@ export declare class Package {
35
35
  * there is no second type to keep in step - see `Resolved`.
36
36
  */
37
37
  config: ResolvedConfig;
38
+ /**
39
+ * The same config **before** interpolation - every `${{ ... }}` and every value function still as
40
+ * the author wrote it.
41
+ *
42
+ * `Workspace` produces this when it cascades the directory chain; `Repository` evaluates it into
43
+ * {@link config}. Read `config` unless you specifically want the unevaluated text.
44
+ */
45
+ rawConfig: RmanConfig;
38
46
  /**
39
47
  * The repository this package belongs to - so anything holding a package can reach the whole
40
48
  * picture (its siblings, the root's config, git) without being handed it separately.
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { Manifest } from './manifest.js';
2
+ import { Manifest } from '../interfaces/manifest.js';
3
3
  import { semverScheme } from './version-scheme.js';
4
4
  export class Package {
5
5
  dirname;
@@ -32,6 +32,22 @@ export class Package {
32
32
  * there is no second type to keep in step - see `Resolved`.
33
33
  */
34
34
  config = {};
35
+ /**
36
+ * The same config **before** interpolation - every `${{ ... }}` and every value function still as
37
+ * the author wrote it.
38
+ *
39
+ * `Workspace` produces this when it cascades the directory chain; `Repository` evaluates it into
40
+ * {@link config}. Read `config` unless you specifically want the unevaluated text.
41
+ */
42
+ /* A second field rather than a stage of the first, because the two have different *types*:
43
+ * `config` is a `ResolvedConfig` by contract and is read in a hundred places, so putting a raw
44
+ * config there for the window between the cascade and the bake would make the type say something
45
+ * untrue everywhere.
46
+ *
47
+ * There was a `rawConfig` once before and it was removed as a duplicate - `version` kept one to
48
+ * re-read its own hooks, which `DEFERRED_PATHS` made unnecessary. This is not that: it is the
49
+ * handoff between two steps that genuinely produce different things. */
50
+ rawConfig = {};
35
51
  /**
36
52
  * The packages whose directories sit directly inside this one - **the tree edge**, in the order
37
53
  * the platform that claimed this directory gave them.
@@ -1,9 +1,7 @@
1
- import type { RmanConfig } from '../interfaces/rman-config.interface.js';
2
- import { type DetectedBuiltin } from '../plugins/detect.js';
3
- import { RmanApplication } from './application.js';
4
- import { type ConfigScope, type GitScope, type PackageScope, type RepositoryScope } from './config.js';
1
+ import { type ConfigScope, type GitScope, type PackageScope, type RepositoryScope } from '../../interfaces/config-scope.interface.js';
2
+ import { RmanApplication } from '../application.js';
3
+ import type { Platform } from '../interfaces/plugin.js';
5
4
  import { Package } from './package.js';
6
- import type { Platform } from './plugin.js';
7
5
  import { Workspace } from './workspace.js';
8
6
  export declare class Repository extends Package {
9
7
  readonly dirname: string;
@@ -14,8 +12,6 @@ export declare class Repository extends Package {
14
12
  * really was. Used by `currentPackage` to scope commands to "the package I'm standing in". */
15
13
  readonly cwd: string;
16
14
  readonly rootPackage: Package;
17
- /** See the `defineProperty` in the constructor - what detection supplied, when it did. */
18
- readonly detectedBuiltin?: DetectedBuiltin;
19
15
  /** Commands the repository's plugins contributed, loaded during `create` because the workspace
20
16
  * providers they bring are needed before any package can be found. `cli.ts` registers them. */
21
17
  /**
@@ -33,14 +29,15 @@ export declare class Repository extends Package {
33
29
  * and because reading it is a subprocess: a deep walk of a package must not spawn one. */
34
30
  private _git?;
35
31
  /**
36
- * Files `${{ read(...) }}` has parsed, shared by every package's scope and keyed by the identity
37
- * of the bytes - see `readStructuredFile`.
32
+ * What `${{ file... }}` and `${{ read(...) }}` answer from, for every package.
38
33
  *
39
- * **On the repository rather than per scope, and that is the whole point of it**: `configScope`
40
- * is built once per package, so a cache living there would re-read a repository-level file once
41
- * for every package that mentions it.
34
+ * **One per repository rather than one per scope, and that is the whole point of it**:
35
+ * `configScope` is built once per package, so a parse cache living there would re-read a
36
+ * repository-level file once for every package that mentions it. The cache inside is keyed by the
37
+ * identity of the bytes (`mtimeNs:size`), because rman writes JSON while it runs - `version`
38
+ * rewrites every bumped manifest and then re-interpolates its deferred hooks.
42
39
  */
43
- private readonly _readCache;
40
+ private readonly _files;
44
41
  /**
45
42
  * The application this repository belongs to - its services, its technologies, its logger.
46
43
  *
@@ -139,24 +136,9 @@ export declare class Repository extends Package {
139
136
  */
140
137
  protected _linkPackages(tree: Workspace.Node, nodes: Workspace.Node[], packages: Package[]): void;
141
138
  /**
142
- * Gives every package the selector a `"[glob]"` block and `--scope` match it by, and refuses two
143
- * packages that would answer to the same one.
144
- *
145
- * **Its own step, before any config is resolved by a selector**, which is the ordering that makes
146
- * the rest work: `_resolveConfigs` asks `resolveConfig` for each package *by selector*, so an
147
- * address assigned afterwards would be applied to nothing.
148
- *
149
- * **`name` comes from the unmarked cascade only** - the same read `platform` gets, from the same
150
- * cache, for the same reason. A `"[glob]"` block cannot set it (`assertSelectorBlocks` refuses
151
- * one) because the glob matches the very thing the block would be setting.
152
- *
153
- * **Uniqueness is checked, and the cascade is the mistake it usually catches.** `name` cascades
154
- * like every unmarked key, so one declaration above two packages gives both the same address -
155
- * and the failure would otherwise be silent in the worst way: the config reaches both and
156
- * `getPackage` returns whichever came first. The message names both directories, and says the
157
- * cascade out loud when the two got it from one declaration.
139
+ * Bakes every package's config: the raw one the workspace cascaded, with every `${{ }}` and value
140
+ * function resolved against that package's scope.
158
141
  */
159
- protected _assignSelectors(rootDir: string, cache: Map<string, RmanConfig>): Promise<void>;
160
142
  protected _resolveConfigs(): Promise<void>;
161
143
  protected _topoSortPackages(packages: Package[]): void;
162
144
  protected _packageScope(pkg: Package, targetVersion?: string): PackageScope;
@@ -196,18 +178,22 @@ export declare class Repository extends Package {
196
178
  * 3. **Ask the providers** for the layout. None recognizing it means a repository that is itself
197
179
  * the one package.
198
180
  *
199
- * **A repository whose `.rmanrc` names no plugin has no packages beyond itself**, and that is the
181
+ * **A repository no technology recognizes has no packages beyond itself**, and that is the
200
182
  * boundary working rather than failing: `workspaces` in a `package.json` is npm's idea, so it
201
- * takes `plugins: ['node']` - or detection reading the directory as a Node one - for it to be
202
- * read as a workspace at all.
183
+ * takes a platform that reads one for the directory to be a workspace at all. rman's own presets
184
+ * are laid under every root (see `DEFAULT_PRESETS`), so a plain Node repository needs no config
185
+ * file to say so; anything else arrives through `extends` or `platforms`.
203
186
  */
204
187
  static create(root?: string, options?: {
205
188
  deep?: number;
206
189
  app?: RmanApplication;
190
+ presets?: readonly string[];
207
191
  }): Promise<Repository>;
208
- /** Finishes constructing `repo` with the async work a constructor can't do itself - resolving
209
- * `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` config (which may need a dynamic `import()`)
210
- * before the dependency graph is built from it. */
192
+ /**
193
+ * Takes the workspace's packages as this repository's own - the back-references a `Package` needs
194
+ * and the parent/child edges the walk established.
195
+ */
196
+ protected _adopt(workspace: Workspace): void;
211
197
  private static _init;
212
198
  }
213
199
  export declare namespace Repository {