rman 1.0.12 → 1.2.1

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 (102) hide show
  1. package/README.md +90 -70
  2. package/cli.js +226 -14
  3. package/commands/build.command.js +1 -0
  4. package/commands/changed.command.js +2 -2
  5. package/commands/changelog.command.js +13 -15
  6. package/commands/config.command.js +61 -0
  7. package/commands/diff.command.js +9 -4
  8. package/commands/exec.command.js +2 -8
  9. package/commands/github-release.command.js +1 -0
  10. package/commands/info.command.d.ts +9 -0
  11. package/commands/info.command.js +12 -2
  12. package/commands/run.command.js +5 -8
  13. package/commands/test.command.js +1 -0
  14. package/commands/version.command.js +53 -14
  15. package/constants.js +1 -1
  16. package/core/config.d.ts +265 -17
  17. package/core/config.js +651 -76
  18. package/core/custom-command.d.ts +133 -0
  19. package/core/custom-command.js +99 -0
  20. package/core/extends-config.d.ts +27 -0
  21. package/core/extends-config.js +89 -0
  22. package/core/manifest.d.ts +222 -0
  23. package/core/manifest.js +150 -0
  24. package/core/merge-config.d.ts +70 -0
  25. package/core/merge-config.js +193 -0
  26. package/core/package.d.ts +73 -7
  27. package/core/package.js +86 -24
  28. package/core/plugin.d.ts +112 -0
  29. package/core/plugin.js +189 -0
  30. package/core/repository.d.ts +91 -1
  31. package/core/repository.js +277 -132
  32. package/core/resolve-target.d.ts +12 -0
  33. package/core/resolve-target.js +33 -0
  34. package/core/run-step.d.ts +75 -0
  35. package/core/run-step.js +1 -0
  36. package/core/version-scheme.d.ts +134 -0
  37. package/core/version-scheme.js +148 -0
  38. package/core/workspace.d.ts +68 -0
  39. package/core/workspace.js +83 -0
  40. package/index.d.ts +55 -8
  41. package/index.js +42 -7
  42. package/interfaces/rman-config.interface.d.ts +222 -46
  43. package/package.json +16 -7
  44. package/services/change-hash.service.d.ts +88 -0
  45. package/services/change-hash.service.js +112 -0
  46. package/services/changelog.service.d.ts +8 -13
  47. package/services/changelog.service.js +12 -11
  48. package/services/conventional-commits.service.d.ts +73 -0
  49. package/services/conventional-commits.service.js +116 -0
  50. package/services/docker-publish.service.js +1 -1
  51. package/services/exec.service.js +1 -1
  52. package/services/github-release.service.d.ts +2 -2
  53. package/services/github-release.service.js +10 -5
  54. package/services/list.service.js +5 -2
  55. package/services/run.service.d.ts +112 -6
  56. package/services/run.service.js +265 -89
  57. package/services/system-info.d.ts +22 -7
  58. package/services/system-info.js +8 -23
  59. package/services/version-plan.service.d.ts +244 -0
  60. package/services/version-plan.service.js +414 -0
  61. package/services/version.service.d.ts +102 -82
  62. package/services/version.service.js +226 -434
  63. package/services.d.ts +5 -3
  64. package/services.js +5 -3
  65. package/utils/bin-path.d.ts +59 -0
  66. package/utils/bin-path.js +82 -0
  67. package/utils/child-tracker.d.ts +16 -0
  68. package/utils/child-tracker.js +30 -0
  69. package/utils/exec.d.ts +13 -2
  70. package/utils/exec.js +17 -17
  71. package/utils/git.d.ts +9 -3
  72. package/utils/git.js +10 -2
  73. package/utils/package-filter.d.ts +33 -2
  74. package/utils/package-filter.js +47 -7
  75. package/utils/printable-config.d.ts +15 -0
  76. package/utils/printable-config.js +42 -0
  77. package/utils/release-version.js +3 -3
  78. package/utils/run-bin.d.ts +46 -0
  79. package/utils/run-bin.js +63 -0
  80. package/utils/version-stamp.d.ts +14 -6
  81. package/utils/version-stamp.js +25 -13
  82. package/commands/ci.command.js +0 -30
  83. package/commands/clean.command.d.ts +0 -3
  84. package/commands/clean.command.js +0 -36
  85. package/commands/publish.command.d.ts +0 -3
  86. package/commands/publish.command.js +0 -225
  87. package/rmanrc.schema.json +0 -392
  88. package/services/ci.service.d.ts +0 -40
  89. package/services/ci.service.js +0 -204
  90. package/services/clean.service.d.ts +0 -42
  91. package/services/clean.service.js +0 -226
  92. package/services/publish.service.d.ts +0 -79
  93. package/services/publish.service.js +0 -273
  94. package/utils/change-hash.d.ts +0 -68
  95. package/utils/change-hash.js +0 -98
  96. package/utils/conventional-commits.d.ts +0 -52
  97. package/utils/conventional-commits.js +0 -90
  98. package/utils/npm-run-path.d.ts +0 -67
  99. package/utils/npm-run-path.js +0 -63
  100. package/utils/workspace-range.d.ts +0 -17
  101. package/utils/workspace-range.js +0 -28
  102. /package/commands/{ci.command.d.ts → config.command.d.ts} +0 -0
@@ -0,0 +1,112 @@
1
+ import type { RmanConfig } from '../interfaces/rman-config.interface.js';
2
+ import { RunService } from '../services/run.service.js';
3
+ import { VersionPlanService } from '../services/version-plan.service.js';
4
+ import { BinPath } from '../utils/bin-path.js';
5
+ import type { CustomCommand, LoadedCommand } from './custom-command.js';
6
+ import { type ManifestProvider } from './manifest.js';
7
+ import { Workspace } from './workspace.js';
8
+ /** The `.rmanrc` key naming plugin packages to load. */
9
+ export declare const PLUGINS_KEY = "plugins";
10
+ /**
11
+ * What a plugin package hands rman.
12
+ *
13
+ * An object rather than a bare array of commands, for the reason `CommandContext` is one: a plugin
14
+ * will eventually contribute more than commands (config defaults, publish targets, a package
15
+ * provider for a non-Node repository), and nothing written against this should have to change when
16
+ * it does.
17
+ */
18
+ export interface RmanPlugin {
19
+ /** For error messages and `--help` grouping. Conventionally the package's own name. */
20
+ name: string;
21
+ commands?: CustomCommand[];
22
+ /**
23
+ * Where `run` can find a package's steps besides its `.rmanrc` - `rman-node` contributes
24
+ * `package.json#scripts` here, with npm's `pre`/`post` lifecycle.
25
+ *
26
+ * Registered in `plugins` declaration order, and only for plugins the repository actually named:
27
+ * what a script resolves to is then a function of the config rather than of what happened to be
28
+ * imported.
29
+ */
30
+ runSteps?: RunService.StepSource;
31
+ /**
32
+ * How this ecosystem's repositories are laid out - `rman-node` reads `workspaces` from the root
33
+ * `package.json` here.
34
+ *
35
+ * Loaded **before any package is known**, since this is what finds them: `Repository.create`
36
+ * reads the root config, loads the plugins it names, and only then asks. A repository naming no
37
+ * plugin therefore has no packages beyond itself.
38
+ */
39
+ workspace?: Workspace.Provider;
40
+ /**
41
+ * Where a package's name and version are written, and how it is numbered - `rman-node`
42
+ * contributes `package.json` here.
43
+ *
44
+ * Registered before any package is constructed, since `Package` reads through it. A repository
45
+ * naming no plugin therefore gets packages named after their own directories at version
46
+ * `0.0.0` - see `readManifest`.
47
+ */
48
+ manifest?: ManifestProvider;
49
+ /**
50
+ * How a release is planned - which packages have changed since their last release and what
51
+ * version each gets. `rman-node` contributes `NodeVersionPlanService` here.
52
+ *
53
+ * **`VersionPlanService` is abstract, so `version`/`changed` do not work without one** (they fail
54
+ * naming this key). Unlike `manifest` and `workspace`, which degrade to honest defaults, a plan is
55
+ * either right or it quietly releases the wrong set of packages - see `VersionPlanService`.
56
+ *
57
+ * Consulted when a command asks, not at load time, so this is declared and nothing else has to
58
+ * happen as the plugin's module is imported.
59
+ */
60
+ versionPlanner?: VersionPlanService;
61
+ /**
62
+ * Where this ecosystem keeps a repository's locally installed executables - `rman-node`
63
+ * contributes npm's `node_modules/.bin`, walked up the directory chain.
64
+ *
65
+ * Prepended to PATH for every `exec`/`runBin` child process, so a command an author wrote runs
66
+ * against the repository's own pinned tools. **Every plugin's entries are used**, not just the
67
+ * first - see `BinPath`.
68
+ */
69
+ binPaths?: BinPath.Provider;
70
+ }
71
+ /**
72
+ * Identity helper for authoring a plugin with full type-checking - the `defineConfig`/
73
+ * `defineCommand` pattern again, for the same reason. Returns `plugin` unchanged.
74
+ *
75
+ * **A plugin package's entry point exports a *config*, not this**, so that a package is an
76
+ * `.rmanrc` like any other and can carry a second plugin later without changing shape:
77
+ *
78
+ * ```js
79
+ * // rman-node's entry point
80
+ * import { defineConfig, definePlugin } from 'rman';
81
+ * import publishCommand from './commands/publish.js';
82
+ *
83
+ * export const nodePlugin = definePlugin({ name: 'rman-node', commands: [publishCommand] });
84
+ * export default defineConfig({ plugins: [nodePlugin] });
85
+ * ```
86
+ *
87
+ * **A module exporting the plugin itself is refused**, with a message saying so. Accepting both
88
+ * would mean telling a plugin from a config at runtime, and `name` is a key either may have - the
89
+ * test would be a guess, and guessing "plugin" registers nothing while reporting success.
90
+ */
91
+ export declare function definePlugin(plugin: RmanPlugin): RmanPlugin;
92
+ /**
93
+ * Loads every plugin the repository's `.rmanrc "plugins"` declares, in declaration order.
94
+ *
95
+ * This is what lets a *package* contribute commands. `.rman/*.mjs` covers one repository's own
96
+ * commands (see `loadCustomCommands`); a plugin covers a whole class of repository - `rman-node`
97
+ * carrying everything that only means something because the repository is a Node one, so rman's
98
+ * core does not have to.
99
+ *
100
+ * An entry is a package name, a path, or a plugin object - and a named package's entry point
101
+ * exports a **config**, whose own `plugins` are then loaded the same way (see `loadInto`).
102
+ *
103
+ * Names resolve relative to the repository root's own `node_modules`, the way `extends` resolves -
104
+ * a plugin is the repository's dependency, not rman's.
105
+ *
106
+ * **A plugin that cannot be loaded throws**, unlike a broken `.rman/*.mjs` file, which is warned
107
+ * about and skipped. The two differ because the consequence does: a skipped local command affects
108
+ * only itself, while a missing plugin silently removes commands the repository is built around -
109
+ * `rman publish` would simply not exist, and "not a known command" sends the reader looking in the
110
+ * wrong place entirely.
111
+ */
112
+ export declare function loadPlugins(rootDir: string, rootConfig: RmanConfig): Promise<LoadedCommand[]>;
package/core/plugin.js ADDED
@@ -0,0 +1,189 @@
1
+ import path from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ import { RunService } from '../services/run.service.js';
4
+ import { VersionPlanService } from '../services/version-plan.service.js';
5
+ import { BinPath } from '../utils/bin-path.js';
6
+ import { Manifest } from './manifest.js';
7
+ import { resolveConfigTarget } from './resolve-target.js';
8
+ import { Workspace } from './workspace.js';
9
+ /** The `.rmanrc` key naming plugin packages to load. */
10
+ export const PLUGINS_KEY = 'plugins';
11
+ /**
12
+ * Identity helper for authoring a plugin with full type-checking - the `defineConfig`/
13
+ * `defineCommand` pattern again, for the same reason. Returns `plugin` unchanged.
14
+ *
15
+ * **A plugin package's entry point exports a *config*, not this**, so that a package is an
16
+ * `.rmanrc` like any other and can carry a second plugin later without changing shape:
17
+ *
18
+ * ```js
19
+ * // rman-node's entry point
20
+ * import { defineConfig, definePlugin } from 'rman';
21
+ * import publishCommand from './commands/publish.js';
22
+ *
23
+ * export const nodePlugin = definePlugin({ name: 'rman-node', commands: [publishCommand] });
24
+ * export default defineConfig({ plugins: [nodePlugin] });
25
+ * ```
26
+ *
27
+ * **A module exporting the plugin itself is refused**, with a message saying so. Accepting both
28
+ * would mean telling a plugin from a config at runtime, and `name` is a key either may have - the
29
+ * test would be a guess, and guessing "plugin" registers nothing while reporting success.
30
+ */
31
+ export function definePlugin(plugin) {
32
+ return plugin;
33
+ }
34
+ /**
35
+ * Loads every plugin the repository's `.rmanrc "plugins"` declares, in declaration order.
36
+ *
37
+ * This is what lets a *package* contribute commands. `.rman/*.mjs` covers one repository's own
38
+ * commands (see `loadCustomCommands`); a plugin covers a whole class of repository - `rman-node`
39
+ * carrying everything that only means something because the repository is a Node one, so rman's
40
+ * core does not have to.
41
+ *
42
+ * An entry is a package name, a path, or a plugin object - and a named package's entry point
43
+ * exports a **config**, whose own `plugins` are then loaded the same way (see `loadInto`).
44
+ *
45
+ * Names resolve relative to the repository root's own `node_modules`, the way `extends` resolves -
46
+ * a plugin is the repository's dependency, not rman's.
47
+ *
48
+ * **A plugin that cannot be loaded throws**, unlike a broken `.rman/*.mjs` file, which is warned
49
+ * about and skipped. The two differ because the consequence does: a skipped local command affects
50
+ * only itself, while a missing plugin silently removes commands the repository is built around -
51
+ * `rman publish` would simply not exist, and "not a known command" sends the reader looking in the
52
+ * wrong place entirely.
53
+ */
54
+ export async function loadPlugins(rootDir, rootConfig) {
55
+ const commands = [];
56
+ /** Resolved against the repository root, where the `.rmanrc` declaring them lives. */
57
+ await loadInto(commands, rootConfig, path.join(rootDir, '.rmanrc'), { files: new Set(), names: new Set() });
58
+ return commands;
59
+ }
60
+ /**
61
+ * One config's `plugins`, in declaration order.
62
+ *
63
+ * Recursive because a plugin package **exports a config**, not a plugin: `rman-node`'s entry point
64
+ * is `export default defineConfig({ plugins: [ ... ] })`, so resolving a name lands on another
65
+ * config whose own `plugins` are the ones to register. That also means a plugin package can name a
66
+ * plugin of its own and it simply works.
67
+ *
68
+ * `from` is the file the entries are resolved against, and it changes as it descends - an entry in
69
+ * `rman-node`'s config resolves through *its* `node_modules`, not the repository's, the same rule
70
+ * `extends` follows.
71
+ *
72
+ * **Only `plugins` is read out of an imported config.** Its other keys are not merged: a config's
73
+ * way into a repository is `extends`, which is the key that says "merge this underneath mine".
74
+ * Reading them here would make a plugin able to configure a repository by being installed.
75
+ */
76
+ async function loadInto(commands, config, from, seen) {
77
+ const declared = config?.[PLUGINS_KEY];
78
+ if (declared === undefined)
79
+ return;
80
+ for (const entry of Array.isArray(declared) ? declared : [declared]) {
81
+ /**
82
+ * The object form: a JS config handing a plugin over directly, and what a plugin package's own
83
+ * config holds. Nothing to resolve or import.
84
+ *
85
+ * An object here **is** a plugin - it is not guessed at. The one thing checked is that it has a
86
+ * `name`, because everything downstream (the registration guard, `--help` grouping, every error
87
+ * message) is keyed by it.
88
+ */
89
+ if (isPlainObject(entry)) {
90
+ if (typeof entry.name !== 'string' || !entry.name) {
91
+ throw new Error(`A plugin object in "${PLUGINS_KEY}" has no "name" - every other message is keyed by it.`);
92
+ }
93
+ register(commands, entry, entry.name, from, seen);
94
+ continue;
95
+ }
96
+ if (typeof entry !== 'string' || !entry.trim()) {
97
+ throw new Error(`"${PLUGINS_KEY}" takes a package name, a path, or a plugin object - not ${JSON.stringify(entry)}`);
98
+ }
99
+ const file = resolveConfigTarget(entry, from, PLUGINS_KEY);
100
+ /** A config naming itself, or two naming each other, would otherwise recurse forever. Keyed by
101
+ * resolved file, so the same package reached by two names is still loaded once. */
102
+ if (seen.files.has(file))
103
+ continue;
104
+ seen.files.add(file);
105
+ const mod = await import(pathToFileURL(file).href);
106
+ const exported = mod?.default ?? mod?.plugin;
107
+ /**
108
+ * **A module exports one thing: an rman config.** Not a plugin, and not either-or.
109
+ *
110
+ * Accepting both meant having to *tell them apart*, and there is no reliable way to - `name` is
111
+ * a key a config may have as well, so the test came down to "a name plus at least one of the
112
+ * things a plugin contributes", which is a guess. Guess wrong in the direction of "plugin" and
113
+ * nothing is registered while the command reports success, which is the worst outcome on offer.
114
+ * One shape, one rule, one error.
115
+ */
116
+ if (!isPlainObject(exported) || exported.plugins === undefined) {
117
+ throw new Error(`Plugin "${entry}" must export an rman config - \`export default defineConfig({ plugins: [ ... ] })\`. ` +
118
+ describeExport(exported));
119
+ }
120
+ await loadInto(commands, exported, file, seen);
121
+ }
122
+ }
123
+ /**
124
+ * Everything a plugin contributes, in one place - so the object and the imported forms cannot drift
125
+ * apart in what they support.
126
+ *
127
+ * **One registration per plugin name.** `plugins` appends at every layer now, so the same plugin
128
+ * arriving twice is an ordinary consequence of `extends` rather than a mistake to report - and
129
+ * registering it twice would define its commands twice, which yargs does not survive. The config
130
+ * merge already drops an identical entry; this catches the rest, including two objects claiming one
131
+ * name and an object that duplicates a named package.
132
+ */
133
+ function register(commands, plugin, label, specifier, seen) {
134
+ if (seen.names.has(plugin.name))
135
+ return;
136
+ seen.names.add(plugin.name);
137
+ if (plugin.runSteps)
138
+ RunService.addStepSource(plugin.runSteps);
139
+ if (plugin.manifest)
140
+ Manifest.addProvider(plugin.manifest);
141
+ if (plugin.workspace)
142
+ Workspace.addProvider(plugin.workspace);
143
+ if (plugin.binPaths)
144
+ BinPath.addProvider(plugin.binPaths);
145
+ if (plugin.versionPlanner)
146
+ VersionPlanService.setPlanner(plugin.versionPlanner);
147
+ for (const command of plugin.commands ?? []) {
148
+ commands.push(toLoadedCommand(command, label || specifier, specifier));
149
+ }
150
+ }
151
+ /**
152
+ * The second half of the error above - what the module *did* export, so the author can see how far
153
+ * off it was.
154
+ *
155
+ * It recognizes a plugin object only to **say so in a message**. That is the one safe use for this
156
+ * shape test: it decides nothing, so a wrong guess costs a slightly less helpful sentence rather
157
+ * than a plugin that silently does not load.
158
+ */
159
+ function describeExport(exported) {
160
+ if (exported === undefined)
161
+ return 'It has no default export.';
162
+ if (!isPlainObject(exported))
163
+ return `Its default export is a ${typeof exported}.`;
164
+ const looksLikePlugin = PLUGIN_SEAMS.some(seam => exported[seam] !== undefined);
165
+ return looksLikePlugin
166
+ ? `Its default export looks like the plugin itself - put it in a config's "${PLUGINS_KEY}".`
167
+ : `Its default export has no "${PLUGINS_KEY}".`;
168
+ }
169
+ const PLUGIN_SEAMS = ['commands', 'runSteps', 'workspace', 'manifest', 'versionPlanner', 'binPaths'];
170
+ /** A config object, as opposed to an array or anything with its own prototype. */
171
+ function isPlainObject(value) {
172
+ return !!value && typeof value === 'object' && !Array.isArray(value);
173
+ }
174
+ /** A plugin's command, checked the same way a `.rman/*.mjs` one is - the name it answers to comes
175
+ * from its own `command` string, since a plugin has no file name to fall back on. */
176
+ function toLoadedCommand(command, pluginName, specifier) {
177
+ const declared = command?.command?.trim();
178
+ if (!declared) {
179
+ throw new Error(`Plugin "${pluginName}" has a command with no "command" name - it cannot be registered.`);
180
+ }
181
+ if (typeof command.handler !== 'function') {
182
+ throw new Error(`Plugin "${pluginName}" command "${declared}" has no "handler" function.`);
183
+ }
184
+ if (typeof command.describe !== 'string' || !command.describe) {
185
+ throw new Error(`Plugin "${pluginName}" command "${declared}" has no "describe" - \`rman --help\` would have ` +
186
+ `nothing to list it by.`);
187
+ }
188
+ return { ...command, command: declared, name: declared.split(/\s+/)[0], file: specifier };
189
+ }
@@ -1,3 +1,5 @@
1
+ import { type ConfigScope, type GitScope, type PackageScope, type RepositoryScope } from './config.js';
2
+ import type { LoadedCommand } from './custom-command.js';
1
3
  import { Package } from './package.js';
2
4
  export declare class Repository extends Package {
3
5
  readonly dirname: string;
@@ -8,6 +10,32 @@ export declare class Repository extends Package {
8
10
  * really was. Used by `currentPackage` to scope commands to "the package I'm standing in". */
9
11
  readonly cwd: string;
10
12
  readonly rootPackage: Package;
13
+ /** Commands the repository's plugins contributed, loaded during `create` because the workspace
14
+ * providers they bring are needed before any package can be found. `cli.ts` registers them. */
15
+ pluginCommands: LoadedCommand[];
16
+ /**
17
+ * Cached repository scope - see `_repositoryScope`.
18
+ *
19
+ * **Non-enumerable**, and for the same reason `targetVersion` itself is: this cache holds a
20
+ * `PackageScope` per package, each carrying that throwing getter, and it hangs off a `Repository`
21
+ * which every `Package` points back at. Left enumerable, *any* deep walk of a package reached it
22
+ * and threw - measured through a test's own `toEqual` diff, but a `JSON.stringify` or a debugger
23
+ * would do it too, with an error about `version` that has nothing to do with what the caller did.
24
+ * An internal cache has no business being walked anyway.
25
+ */
26
+ private _repoScope?;
27
+ /** Cached `${{ git.* }}` facts - see `_gitScope`. Non-enumerable for the same reason as above,
28
+ * and because reading it is a subprocess: a deep walk of a package must not spawn one. */
29
+ private _git?;
30
+ /**
31
+ * Files `${{ read(...) }}` has parsed, shared by every package's scope and keyed by the identity
32
+ * of the bytes - see `readStructuredFile`.
33
+ *
34
+ * **On the repository rather than per scope, and that is the whole point of it**: `configScope`
35
+ * is built once per package, so a cache living there would re-read a repository-level file once
36
+ * for every package that mentions it.
37
+ */
38
+ private readonly _readCache;
11
39
  protected constructor(dirname: string, monorepo: boolean, packages: Package[],
12
40
  /** The directory `Repository.create()` was actually invoked from - unlike `dirname` (the
13
41
  * resolved repository root, possibly several levels up), this is where the user's shell
@@ -36,6 +64,20 @@ export declare class Repository extends Package {
36
64
  listStatus(options?: {
37
65
  hash?: string;
38
66
  }): Promise<Record<string, Repository.PackageStatus>>;
67
+ /**
68
+ * The scope a `${{ ... }}` expression is evaluated against for `pkg`, optionally with the version
69
+ * a run is about to write bound into it.
70
+ *
71
+ * `version` is the only caller that passes one, and it has to: the config was resolved before its
72
+ * plan existed, so `pkg.targetVersion` had nothing to be. Re-evaluating that raw value against
73
+ * this is how that one binding gets filled in, without every other command paying for it - or
74
+ * seeing a value that means nothing to them.
75
+ */
76
+ configScope(pkg: Package, options?: {
77
+ targetVersion?: string;
78
+ }): ConfigScope;
79
+ /** `${{ git.* }}`, read at most once per repository per process. */
80
+ protected _gitScope(): GitScope;
39
81
  /**
40
82
  * Resolves the effective rman config for the repository root and every package, cascading
41
83
  * root -> intermediate directories -> package directory, so a `.rmanrc` placed anywhere along
@@ -46,8 +88,57 @@ export declare class Repository extends Package {
46
88
  * single-package repository it *is* the one package, so `"[*]"` has to reach it; in a monorepo
47
89
  * nothing under `getPackages()` is the root, so only its own unmarked config applies.
48
90
  */
91
+ /**
92
+ * Gives every package its `repository` and `parent`, before any config is resolved - a config
93
+ * expression or a provider may already want to navigate from a package outwards.
94
+ *
95
+ * A repository's own `repository` is itself, which reads oddly and is the honest answer:
96
+ * `Repository extends Package`, so the repository *is* a package of its own repository.
97
+ */
98
+ protected _linkPackages(): void;
49
99
  protected _resolveConfigs(): Promise<void>;
100
+ protected _topoSortPackages(packages: Package[]): void;
101
+ protected _packageScope(pkg: Package, targetVersion?: string): PackageScope;
102
+ /** Built once and reused: it is the same for every package, and its `git` getter caches too, so a
103
+ * repository whose config never mentions git spawns none. */
104
+ protected _repositoryScope(): RepositoryScope;
105
+ /**
106
+ * One `.rmanrc "dependencies"` entry to a package: its **name** first, then a
107
+ * **repository-relative directory**.
108
+ *
109
+ * The path form is what makes the key usable outside npm. A name identifies a package only where
110
+ * the ecosystem guarantees uniqueness - the same reason `Package.dependencies` holds references
111
+ * and `Workspace.Layout` carries paths - so a repository whose names collide, or whose packages
112
+ * have no names rman can read, states the edge by directory instead.
113
+ *
114
+ * Name first because that is what a Node repository writes and there is no ambiguity in practice:
115
+ * a package name that is also an existing directory path in the same repository does not occur.
116
+ * An entry matching neither is ignored, as an unknown name always was - the graph is a statement
117
+ * about packages that exist.
118
+ */
119
+ protected _resolveDeclaredPackage(entry: string): Package | undefined;
50
120
  protected _updateDependencies(): void;
121
+ /** `git` facts for a `${{ git.* }}` expression. Synchronous on purpose: it backs a lazy
122
+ * getter, and a getter cannot await. Everything is `undefined` outside a git checkout - not an
123
+ * error, just a repository without one. */
124
+ protected _readGitScope(dirname: string): GitScope;
125
+ /**
126
+ * Opens the repository containing `root` (default: the current directory).
127
+ *
128
+ * Three steps, in this order because each needs the one before it:
129
+ *
130
+ * 1. **Find the root** without knowing any ecosystem - see `Workspace.findRoot`. It cannot be
131
+ * otherwise: the plugins that know what a package is are named in the config file this step
132
+ * is looking for.
133
+ * 2. **Load the plugins** the root's config names, which registers their workspace providers
134
+ * (and their commands, handed on via `pluginCommands` - `cli.ts` registers those).
135
+ * 3. **Ask the providers** for the layout. None recognizing it means a repository that is itself
136
+ * the one package.
137
+ *
138
+ * **A repository whose `.rmanrc` names no plugin has no packages beyond itself**, and that is the
139
+ * boundary working rather than failing: `workspaces` in a `package.json` is npm's idea, so it
140
+ * takes `plugins: ['rman-node']` to be read as one.
141
+ */
51
142
  static create(root?: string, options?: {
52
143
  deep?: number;
53
144
  }): Promise<Repository>;
@@ -55,7 +146,6 @@ export declare class Repository extends Package {
55
146
  * `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` config (which may need a dynamic `import()`)
56
147
  * before the dependency graph is built from it. */
57
148
  private static _init;
58
- protected static _resolvePackages(dirname: string, patterns: string[]): Package[];
59
149
  }
60
150
  export declare namespace Repository {
61
151
  type PackageStatus = 'dirty' | 'committed' | 'changed' | 'clean';