rman 1.3.0 → 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.
- package/README.md +65 -31
- package/builtins/platforms/node/augmentation/rmanrc.augmentation.d.ts +83 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.d.ts +26 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.js +79 -0
- package/builtins/platforms/node/commands/ci.command.d.ts +133 -0
- package/builtins/platforms/node/commands/ci.command.js +60 -0
- package/builtins/platforms/node/commands/clean.command.d.ts +185 -0
- package/builtins/platforms/node/commands/clean.command.js +74 -0
- package/builtins/platforms/node/index.d.ts +8 -0
- package/builtins/platforms/node/index.js +8 -0
- package/builtins/platforms/node/node-config.interface.d.ts +76 -0
- package/builtins/platforms/node/node-config.interface.js +7 -0
- package/builtins/platforms/node/node-manifest.provider.d.ts +68 -0
- package/builtins/platforms/node/node-manifest.provider.js +125 -0
- package/builtins/platforms/node/node.platform.d.ts +53 -0
- package/builtins/platforms/node/node.platform.js +134 -0
- package/builtins/platforms/node/services/ci.service.d.ts +47 -0
- package/builtins/platforms/node/services/ci.service.js +213 -0
- package/builtins/platforms/node/services/clean.service.d.ts +53 -0
- package/builtins/platforms/node/services/clean.service.js +237 -0
- package/builtins/platforms/node/services/publish.service.d.ts +114 -0
- package/builtins/platforms/node/services/publish.service.js +371 -0
- package/builtins/platforms/node/services/version-plan.service.d.ts +44 -0
- package/builtins/platforms/node/services/version-plan.service.js +58 -0
- package/builtins/platforms/node/utils/workspace-range.d.ts +26 -0
- package/builtins/platforms/node/utils/workspace-range.js +28 -0
- package/builtins/presets/index.d.ts +15 -0
- package/builtins/presets/index.js +57 -0
- package/builtins/presets/node.d.ts +16 -0
- package/builtins/presets/node.js +57 -0
- package/{services → builtins/publish-targets/docker}/docker-publish.service.d.ts +52 -31
- package/{services → builtins/publish-targets/docker}/docker-publish.service.js +49 -26
- package/builtins/publish-targets/docker/docker.target.d.ts +54 -0
- package/builtins/publish-targets/docker/docker.target.js +40 -0
- package/builtins/publish-targets/docker/index.d.ts +2 -0
- package/builtins/publish-targets/docker/index.js +2 -0
- package/builtins/publish-targets/npm/index.d.ts +2 -0
- package/builtins/publish-targets/npm/index.js +2 -0
- package/builtins/publish-targets/npm/npm-publish-target.d.ts +73 -0
- package/builtins/publish-targets/npm/npm-publish-target.js +95 -0
- package/builtins/publish-targets/npm/npm-view.d.ts +48 -0
- package/builtins/publish-targets/npm/npm-view.js +71 -0
- package/cli.d.ts +8 -0
- package/cli.js +228 -93
- package/commands/build.command.d.ts +177 -3
- package/commands/build.command.js +20 -10
- package/commands/changelog.command.d.ts +296 -3
- package/commands/changelog.command.js +127 -43
- package/commands/config.command.d.ts +44 -3
- package/commands/config.command.js +53 -24
- package/commands/diff.command.d.ts +37 -3
- package/commands/diff.command.js +25 -16
- package/commands/exec.command.d.ts +193 -3
- package/commands/exec.command.js +60 -58
- package/commands/github-release.command.d.ts +154 -3
- package/commands/github-release.command.js +67 -37
- package/commands/import.command.d.ts +36 -3
- package/commands/import.command.js +28 -20
- package/commands/info.command.d.ts +35 -7
- package/commands/info.command.js +36 -30
- package/commands/lint.command.d.ts +176 -0
- package/commands/lint.command.js +34 -0
- package/commands/list.command.d.ts +163 -3
- package/commands/list.command.js +109 -71
- package/commands/publish.command.d.ts +231 -0
- package/commands/publish.command.js +304 -0
- package/commands/run.command.d.ts +186 -6
- package/commands/run.command.js +26 -72
- package/commands/test.command.d.ts +173 -3
- package/commands/test.command.js +16 -10
- package/commands/version.command.d.ts +330 -3
- package/commands/version.command.js +292 -78
- package/commands.d.ts +32 -0
- package/commands.js +28 -0
- package/constants.js +1 -1
- package/core/application.d.ts +116 -0
- package/core/application.js +160 -0
- package/core/classes/package.d.ts +219 -0
- package/core/classes/package.js +214 -0
- package/core/classes/registry.d.ts +30 -0
- package/core/classes/registry.js +47 -0
- package/core/{repository.d.ts → classes/repository.d.ts} +69 -20
- package/core/{repository.js → classes/repository.js} +195 -75
- package/core/classes/service.d.ts +49 -0
- package/core/classes/service.js +40 -0
- package/core/{version-scheme.d.ts → classes/version-scheme.d.ts} +23 -1
- package/core/{version-scheme.js → classes/version-scheme.js} +29 -1
- package/core/classes/workspace.d.ts +275 -0
- package/core/classes/workspace.js +537 -0
- package/core/command-builder.d.ts +14 -0
- package/core/command-builder.js +94 -0
- package/core/config/config-file-scope.d.ts +107 -0
- package/core/config/config-file-scope.js +226 -0
- package/core/config/config-interpolator.d.ts +164 -0
- package/core/config/config-interpolator.js +577 -0
- package/core/config/config-paths.d.ts +65 -0
- package/core/config/config-paths.js +78 -0
- package/core/config/config-reader.d.ts +192 -0
- package/core/config/config-reader.js +727 -0
- package/core/{merge-config.d.ts → config/merge-config.d.ts} +33 -34
- package/core/config/merge-config.js +260 -0
- package/core/{resolve-target.d.ts → config/resolve-config-target.d.ts} +1 -1
- package/core/{resolve-target.js → config/resolve-config-target.js} +1 -1
- package/core/{custom-command.d.ts → interfaces/custom-command.d.ts} +46 -10
- package/core/{custom-command.js → interfaces/custom-command.js} +44 -17
- package/core/{manifest.d.ts → interfaces/manifest.d.ts} +49 -27
- package/core/interfaces/manifest.js +132 -0
- package/core/interfaces/plugin.d.ts +174 -0
- package/core/interfaces/plugin.js +124 -0
- package/core/interfaces/publish-target.d.ts +136 -0
- package/core/interfaces/publish-target.js +43 -0
- package/core/{run-step.d.ts → interfaces/run-step.d.ts} +4 -4
- package/core/interfaces/run-step.js +1 -0
- package/core/plugin-loader.d.ts +25 -0
- package/core/plugin-loader.js +53 -0
- package/index.d.ts +122 -24
- package/index.js +66 -16
- package/interfaces/config-scope.interface.d.ts +223 -0
- package/interfaces/config-scope.interface.js +1 -0
- package/interfaces/rman-config.interface.d.ts +821 -203
- package/interfaces/rman-config.interface.js +78 -1
- package/package.json +3 -1
- package/services/change-hash.service.d.ts +42 -8
- package/services/change-hash.service.js +92 -13
- package/services/changelog.service.d.ts +91 -52
- package/services/changelog.service.js +460 -74
- package/services/config-service.d.ts +8 -0
- package/services/config-service.js +3 -0
- package/services/exec.service.d.ts +23 -12
- package/services/exec.service.js +14 -9
- package/services/github-release.service.d.ts +45 -34
- package/services/github-release.service.js +15 -12
- package/services/import.service.d.ts +25 -14
- package/services/import.service.js +9 -5
- package/services/list.service.d.ts +67 -13
- package/services/list.service.js +62 -15
- package/services/run.service.d.ts +35 -22
- package/services/run.service.js +316 -233
- package/services/system-info.d.ts +1 -1
- package/services/version-plan.service.d.ts +35 -8
- package/services/version-plan.service.js +96 -36
- package/services/version.service.d.ts +34 -14
- package/services/version.service.js +35 -16
- package/services.d.ts +1 -1
- package/services.js +1 -1
- package/utils/bin-path.d.ts +6 -7
- package/utils/bin-path.js +7 -18
- package/utils/branch-guard.d.ts +30 -1
- package/utils/branch-guard.js +31 -0
- package/utils/color-yaml.d.ts +8 -0
- package/utils/color-yaml.js +86 -0
- package/utils/exec.d.ts +10 -0
- package/utils/exec.js +1 -1
- package/utils/git.d.ts +26 -0
- package/utils/git.js +65 -0
- package/utils/logger.d.ts +2 -2
- package/utils/logger.js +1 -1
- package/utils/package-filter.d.ts +135 -8
- package/utils/package-filter.js +204 -16
- package/utils/printable-config.d.ts +9 -1
- package/utils/printable-config.js +46 -1
- package/utils/progress-panel.d.ts +9 -0
- package/utils/progress-panel.js +23 -1
- package/utils/release-version.d.ts +1 -1
- package/utils/run-bin.d.ts +10 -0
- package/utils/run-bin.js +1 -1
- package/utils/run-options.d.ts +97 -0
- package/utils/run-options.js +81 -0
- package/utils/version-group.d.ts +31 -0
- package/utils/version-group.js +43 -0
- package/utils/version-stamp.d.ts +1 -1
- package/utils/version-stamp.js +1 -1
- package/commands/changed.command.d.ts +0 -3
- package/commands/changed.command.js +0 -29
- package/core/config.d.ts +0 -409
- package/core/config.js +0 -939
- package/core/extends-config.d.ts +0 -27
- package/core/extends-config.js +0 -89
- package/core/manifest.js +0 -150
- package/core/merge-config.js +0 -219
- package/core/package.d.ts +0 -83
- package/core/package.js +0 -106
- package/core/plugin.d.ts +0 -112
- package/core/plugin.js +0 -189
- package/core/workspace.d.ts +0 -68
- package/core/workspace.js +0 -83
- /package/{core/run-step.js → builtins/platforms/node/augmentation/rmanrc.augmentation.js} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **The one service shape.** Everything that does work on a repository is a class extending this,
|
|
3
|
+
* constructed once per `RmanApplication` and reached through `app.getService(name)`.
|
|
4
|
+
*
|
|
5
|
+
* rman's services were `export namespace` blocks, and the split between those and the two classes
|
|
6
|
+
* (`VersionPlanService`, `VersionScheme`) was historical rather than principled: whatever needed to
|
|
7
|
+
* be *extended* became a class, and the rest stayed a namespace. Three consequences, all of them
|
|
8
|
+
* measured in this repository:
|
|
9
|
+
*
|
|
10
|
+
* - **A namespace that needs state can only have global state.** `RunService` is a namespace and
|
|
11
|
+
* acquired three module-level variables - `stepSources` and two "already warned" sets - which is
|
|
12
|
+
* why a warning printed for one repository was suppressed for the next one in the same process.
|
|
13
|
+
* - **A namespace cannot be extended.** The two seams a plugin has to specialize
|
|
14
|
+
* (`NodeVersionPlanService extends VersionPlanService`) are precisely the two that are classes.
|
|
15
|
+
* - **A namespace has to be stubbed by mutating the module**, and CLAUDE.md records that failing:
|
|
16
|
+
* a spec that captured a core function at module scope and restored it put the *un-augmented*
|
|
17
|
+
* version back for the rest of the process and broke a spec two files away. An instance is
|
|
18
|
+
* rebuilt per application, so a stub dies with it.
|
|
19
|
+
*
|
|
20
|
+
* **`repository` is no longer a parameter.** Nearly every service method took it first; it now
|
|
21
|
+
* comes from the application, which is what made the argument redundant in the first place.
|
|
22
|
+
*
|
|
23
|
+
* Pure functions of their arguments stay plain exported functions rather than becoming services -
|
|
24
|
+
* `ConventionalCommitsService.parseSubject('feat: x')` parses a string and will never hold state,
|
|
25
|
+
* and making it `app.getService('conventionalCommits').parseSubject(...)` would be ceremony that
|
|
26
|
+
* also puts an application between a caller and a parser. The line is whether it needs the
|
|
27
|
+
* repository.
|
|
28
|
+
*/
|
|
29
|
+
export class Service {
|
|
30
|
+
app;
|
|
31
|
+
constructor(app) {
|
|
32
|
+
this.app = app;
|
|
33
|
+
}
|
|
34
|
+
get repository() {
|
|
35
|
+
return this.app.repository;
|
|
36
|
+
}
|
|
37
|
+
get logger() {
|
|
38
|
+
return this.app.logger;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -16,7 +16,7 @@ export type ChangeKind = 'fix' | 'feature' | 'breaking';
|
|
|
16
16
|
* "is this version on the registry yet", `"workspace:"` range rewriting all assume versions that
|
|
17
17
|
* can be ordered and incremented. This is the seam for an ecosystem that numbers differently (PEP
|
|
18
18
|
* 440, a date-based scheme, a build counter), and it is a *meaning* seam rather than a storage one:
|
|
19
|
-
* `
|
|
19
|
+
* `Plugin`'s manifest members answers "where is the version written", this answers "what does the next one
|
|
20
20
|
* look like".
|
|
21
21
|
*
|
|
22
22
|
* **`bumpNames` and `bumpFor` are the interesting part.** `fix:` -> patch, `feat:` -> minor,
|
|
@@ -64,6 +64,20 @@ export declare abstract class VersionScheme {
|
|
|
64
64
|
}): string;
|
|
65
65
|
/** Is this version a preview rather than a release? `github-release` reads it. */
|
|
66
66
|
abstract isPrerelease(version: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Which prerelease line this version belongs to - `'beta'` for `2.0.0-beta.1` - or `undefined`
|
|
69
|
+
* when it is not a preview, or is one with no identifier to name (`2.0.0-1`).
|
|
70
|
+
*
|
|
71
|
+
* **The one thing a preview needs beyond "is it one", and it is a *name*, which is why it is
|
|
72
|
+
* here rather than read out of the version with a regex by whoever wants it.** npm's publish
|
|
73
|
+
* target derives its dist-tag from this, so a beta lands on `beta` instead of on `latest`; the
|
|
74
|
+
* identifier is written in the version itself, so that is a reading rather than a guess.
|
|
75
|
+
*
|
|
76
|
+
* Implemented, not abstract, and returning `undefined` by default: a scheme whose previews have
|
|
77
|
+
* no name (or which has no previews at all) is answering honestly, and the caller's job is to
|
|
78
|
+
* say so rather than invent one. `SemverScheme` overrides it.
|
|
79
|
+
*/
|
|
80
|
+
prereleaseId(version: string): string | undefined;
|
|
67
81
|
/**
|
|
68
82
|
* The highest of `versions` - a group's current version is the highest among its members, and a
|
|
69
83
|
* monorepo root's release identity the highest among the groups.
|
|
@@ -111,6 +125,14 @@ export declare class SemverScheme extends VersionScheme {
|
|
|
111
125
|
preid?: string;
|
|
112
126
|
}): string;
|
|
113
127
|
isPrerelease(version: string): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* semver's first prerelease identifier, when it is a word: `2.0.0-beta.1` -> `'beta'`.
|
|
130
|
+
*
|
|
131
|
+
* **`undefined` for a numeric-only prerelease** (`2.0.0-1`, whose identifiers are `[1]`), because
|
|
132
|
+
* there is no name there to use - and a caller turning that into a dist-tag called `1` would be
|
|
133
|
+
* inventing one. Same answer for a release, which has no prerelease at all.
|
|
134
|
+
*/
|
|
135
|
+
prereleaseId(version: string): string | undefined;
|
|
114
136
|
}
|
|
115
137
|
/**
|
|
116
138
|
* The default, and what every package gets unless something says otherwise - so nothing about
|
|
@@ -6,7 +6,7 @@ import semver from 'semver';
|
|
|
6
6
|
* "is this version on the registry yet", `"workspace:"` range rewriting all assume versions that
|
|
7
7
|
* can be ordered and incremented. This is the seam for an ecosystem that numbers differently (PEP
|
|
8
8
|
* 440, a date-based scheme, a build counter), and it is a *meaning* seam rather than a storage one:
|
|
9
|
-
* `
|
|
9
|
+
* `Plugin`'s manifest members answers "where is the version written", this answers "what does the next one
|
|
10
10
|
* look like".
|
|
11
11
|
*
|
|
12
12
|
* **`bumpNames` and `bumpFor` are the interesting part.** `fix:` -> patch, `feat:` -> minor,
|
|
@@ -25,6 +25,23 @@ import semver from 'semver';
|
|
|
25
25
|
* `SemverScheme` to keep semver's numbering and change only one of these.
|
|
26
26
|
*/
|
|
27
27
|
export class VersionScheme {
|
|
28
|
+
/**
|
|
29
|
+
* Which prerelease line this version belongs to - `'beta'` for `2.0.0-beta.1` - or `undefined`
|
|
30
|
+
* when it is not a preview, or is one with no identifier to name (`2.0.0-1`).
|
|
31
|
+
*
|
|
32
|
+
* **The one thing a preview needs beyond "is it one", and it is a *name*, which is why it is
|
|
33
|
+
* here rather than read out of the version with a regex by whoever wants it.** npm's publish
|
|
34
|
+
* target derives its dist-tag from this, so a beta lands on `beta` instead of on `latest`; the
|
|
35
|
+
* identifier is written in the version itself, so that is a reading rather than a guess.
|
|
36
|
+
*
|
|
37
|
+
* Implemented, not abstract, and returning `undefined` by default: a scheme whose previews have
|
|
38
|
+
* no name (or which has no previews at all) is answering honestly, and the caller's job is to
|
|
39
|
+
* say so rather than invent one. `SemverScheme` overrides it.
|
|
40
|
+
*/
|
|
41
|
+
prereleaseId(version) {
|
|
42
|
+
void version;
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
28
45
|
/**
|
|
29
46
|
* The highest of `versions` - a group's current version is the highest among its members, and a
|
|
30
47
|
* monorepo root's release identity the highest among the groups.
|
|
@@ -117,6 +134,17 @@ export class SemverScheme extends VersionScheme {
|
|
|
117
134
|
isPrerelease(version) {
|
|
118
135
|
return !!semver.prerelease(version);
|
|
119
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* semver's first prerelease identifier, when it is a word: `2.0.0-beta.1` -> `'beta'`.
|
|
139
|
+
*
|
|
140
|
+
* **`undefined` for a numeric-only prerelease** (`2.0.0-1`, whose identifiers are `[1]`), because
|
|
141
|
+
* there is no name there to use - and a caller turning that into a dist-tag called `1` would be
|
|
142
|
+
* inventing one. Same answer for a release, which has no prerelease at all.
|
|
143
|
+
*/
|
|
144
|
+
prereleaseId(version) {
|
|
145
|
+
const first = semver.prerelease(version)?.[0];
|
|
146
|
+
return typeof first === 'string' ? first : undefined;
|
|
147
|
+
}
|
|
120
148
|
}
|
|
121
149
|
/**
|
|
122
150
|
* The default, and what every package gets unless something says otherwise - so nothing about
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type { RmanConfig } from '../../interfaces/rman-config.interface.js';
|
|
2
|
+
import type { RmanApplication } from '../application.js';
|
|
3
|
+
import { ConfigReader } from '../config/config-reader.js';
|
|
4
|
+
import { type Platform, type Plugin } from '../interfaces/plugin.js';
|
|
5
|
+
import { Package } from './package.js';
|
|
6
|
+
/**
|
|
7
|
+
* A repository's layout, resolved: which directories hold packages, which technology claims each of
|
|
8
|
+
* them, what each one answers to, and the **raw** config each one ends up with.
|
|
9
|
+
*
|
|
10
|
+
* Built with {@link Workspace.create}, which runs the whole resolution; the constructor is
|
|
11
|
+
* protected, so there is no such thing as a half-built workspace.
|
|
12
|
+
*
|
|
13
|
+
* The configs it produces are **raw** - every `${{ }}` and every value function is still
|
|
14
|
+
* unevaluated. Resolving one needs `pkg`, `repository` and `git`, which belong to the repository
|
|
15
|
+
* rather than to its layout; `ConfigInterpolator` is the step after this.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Workspace {
|
|
18
|
+
protected readonly options: Workspace.Options;
|
|
19
|
+
/** The repository root - where the walk starts and what every directory chain is relative to. */
|
|
20
|
+
readonly rootDir: string;
|
|
21
|
+
/** Every plugin in play, in load order: the ones passed in first, then each level's own. */
|
|
22
|
+
readonly plugins: Plugin[];
|
|
23
|
+
/** Every technology in play, in contribution order - which is what decides who claims a
|
|
24
|
+
* directory, since the first that recognizes it wins. */
|
|
25
|
+
readonly platforms: Platform[];
|
|
26
|
+
/** The root directory's own package. Not one of `packages`, which holds the members. */
|
|
27
|
+
rootPackage: Package;
|
|
28
|
+
/** Every package below the root, depth-first. */
|
|
29
|
+
readonly packages: Package[];
|
|
30
|
+
/** Each directory's own config, read once - see `_readLevel`. */
|
|
31
|
+
private _levels;
|
|
32
|
+
/** The packages whose selector came from a `"name"` declaration rather than from their platform,
|
|
33
|
+
* for the clash message alone. */
|
|
34
|
+
private _declaredSelectors;
|
|
35
|
+
/** Built on first use, unless `options.reader` supplied one. */
|
|
36
|
+
private _configReader?;
|
|
37
|
+
/**
|
|
38
|
+
* Builds a workspace and resolves it: discovery, selectors, and every package's raw config.
|
|
39
|
+
*
|
|
40
|
+
* A subclass inherits this and gets an instance of itself. Its declared return type stays
|
|
41
|
+
* `Workspace`, so a subclass wanting its own declares a one-line `create` that calls this.
|
|
42
|
+
*
|
|
43
|
+
* @param rootDir the repository root
|
|
44
|
+
*/
|
|
45
|
+
static create(rootDir: string, options: Workspace.Options): Promise<Workspace>;
|
|
46
|
+
/** Use {@link Workspace.create}. */
|
|
47
|
+
protected constructor(rootDir: string, options: Workspace.Options);
|
|
48
|
+
/** The package at a directory, root included, or `undefined` for one that holds none. */
|
|
49
|
+
packageAt(dirname: string): Package | undefined;
|
|
50
|
+
/** The whole resolution, in the one order the steps admit. */
|
|
51
|
+
protected _init(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Descends from the root, asking each directory's own technology where its children are, and
|
|
54
|
+
* fills `rootPackage` and `packages`.
|
|
55
|
+
*
|
|
56
|
+
* One step, repeated: read the directory's config (which loads whatever plugins it names and
|
|
57
|
+
* decides its platform), then ask *that* platform's `getWorkspace` for the directories below it
|
|
58
|
+
* holding packages. A directory is visited once, and `options.deep` bounds the descent.
|
|
59
|
+
*/
|
|
60
|
+
protected _discover(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Gives every package the selector it answers to - its `.rmanrc "name"` when it declares one, and
|
|
63
|
+
* what its platform says otherwise.
|
|
64
|
+
*
|
|
65
|
+
* `"[glob]"` and `--scope` match this, never the package's name: a name is an *ecosystem's*
|
|
66
|
+
* promise rather than rman's.
|
|
67
|
+
*/
|
|
68
|
+
protected _resolveSelectors(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Refuses two packages answering to one selector. The root is exempt - a glob never matches it and
|
|
71
|
+
* `"[/]"` needs no name, so it shares an address with nobody.
|
|
72
|
+
*/
|
|
73
|
+
protected _assertUniqueSelectors(): void;
|
|
74
|
+
/** Cascades every package's config into `Package.rawConfig`, now that the selectors are known.
|
|
75
|
+
* Still raw - `Repository` is what interpolates it into `Package.config`. */
|
|
76
|
+
protected _resolveConfigs(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Every directory from the root down to `pkg`, layered into one config.
|
|
79
|
+
*
|
|
80
|
+
* Two layers per level: the level's unmarked keys first, then the `"[selector]"` blocks that
|
|
81
|
+
* speak for this package, in the order they were written - later wins, as `overrides` does in
|
|
82
|
+
* eslint and prettier.
|
|
83
|
+
*
|
|
84
|
+
* @param selector what the blocks are matched against; `undefined` skips them, except `"[/]"` for
|
|
85
|
+
* the root, which is structural and needs no selector.
|
|
86
|
+
*/
|
|
87
|
+
protected _cascade(pkg: Package, selector: string | undefined): Promise<RmanConfig>;
|
|
88
|
+
/** One directory's own config, read once and cached. Plugins the level names are loaded here and
|
|
89
|
+
* accumulated into `plugins`. */
|
|
90
|
+
protected _readLevel(dirname: string): Promise<ConfigReader.ResolveResult>;
|
|
91
|
+
/** Appends a technology unless one already answers to its name. */
|
|
92
|
+
protected _addPlatform(platform: Platform): void;
|
|
93
|
+
/** The reader levels are read with - `options.reader`, or a default one. */
|
|
94
|
+
protected _reader(): ConfigReader;
|
|
95
|
+
/** Root, then every directory down to `targetDir`, inclusive. A target outside the root is the
|
|
96
|
+
* root alone. */
|
|
97
|
+
protected _dirChain(targetDir: string): string[];
|
|
98
|
+
/** A level's own settings - everything that is not a `"[...]"` block. */
|
|
99
|
+
protected _stripSelectors(config: RmanConfig): RmanConfig;
|
|
100
|
+
/**
|
|
101
|
+
* The blocks in `config` that speak for this package, in declaration order.
|
|
102
|
+
*
|
|
103
|
+
* `"[/]"` matches the root and nothing else; a glob matches a package's selector and never the
|
|
104
|
+
* root.
|
|
105
|
+
*/
|
|
106
|
+
protected _matchingSelectors(config: RmanConfig, audience: Workspace.Audience): RmanConfig[];
|
|
107
|
+
/**
|
|
108
|
+
* Whether one selector block speaks for this package.
|
|
109
|
+
*
|
|
110
|
+
* `"[/]"` asks only whether this *is* the root. Everything else matches packages **below** the
|
|
111
|
+
* root and never the root itself, which is addressed structurally or not at all.
|
|
112
|
+
*/
|
|
113
|
+
protected _speaksFor(scope: ConfigReader.ParsedSelector['scope'], test: (value: string) => boolean, audience: Workspace.Audience): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* The platform that claims a directory - the one its config names, or the first loaded platform
|
|
116
|
+
* whose manifest provider recognizes it. `basePlatform` when none does, so a caller needs no
|
|
117
|
+
* guard; a *declared* platform no plugin provides is an error.
|
|
118
|
+
*/
|
|
119
|
+
protected _platformFor(dirname: string, config: RmanConfig): Platform;
|
|
120
|
+
/** A platform named unmarked or under `"[/]"` - both are the directory saying what it is. */
|
|
121
|
+
protected _declaredPlatformName(config: RmanConfig): string | undefined;
|
|
122
|
+
/** Which file a key came from, for an error that can be acted on. */
|
|
123
|
+
protected _originOf(config: RmanConfig, key: string): string;
|
|
124
|
+
/** Where a `Package` is made, and the only place - override it to build a subclass of `Package`
|
|
125
|
+
* and keep the rest of the walk. */
|
|
126
|
+
protected _createPackage(dirname: string, platform: Platform): Package;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* How a repository is laid out, and who decides.
|
|
130
|
+
*
|
|
131
|
+
* A namespace for the same reason `Manifest` is one: it is what a plugin can *augment*
|
|
132
|
+
* (`declare module 'rman' { namespace Workspace { ... } }`), so whatever this seam grows later
|
|
133
|
+
* arrives as a member here rather than as another top-level export. It merges with the class above,
|
|
134
|
+
* so `Workspace.walk` and `Workspace.create` are reached the same way.
|
|
135
|
+
*/
|
|
136
|
+
export declare namespace Workspace {
|
|
137
|
+
/** Who a selector block is being matched against - one package, as the three questions a block
|
|
138
|
+
* can ask about it. */
|
|
139
|
+
interface Audience {
|
|
140
|
+
/** Whether this is the root package, which `"[/]"` asks and every other block refuses. */
|
|
141
|
+
isRoot: boolean;
|
|
142
|
+
/** What a glob matches. `undefined` on the first cascade pass, where the selector is still
|
|
143
|
+
* being worked out - see `_resolveSelectors` - so glob blocks are skipped. */
|
|
144
|
+
selector: string | undefined;
|
|
145
|
+
/** What `"[platform:...]"` matches. `''` for a package no technology claimed. */
|
|
146
|
+
platform: string;
|
|
147
|
+
}
|
|
148
|
+
interface Options {
|
|
149
|
+
/** The application every `Package` is constructed against. */
|
|
150
|
+
app: RmanApplication;
|
|
151
|
+
/** Plugins to start with - typically the built-ins. They come first, so a repository's own
|
|
152
|
+
* additions are appended after them. */
|
|
153
|
+
plugins?: Plugin[];
|
|
154
|
+
/** Technologies to start with - typically a preset's. They come first, so a repository's own
|
|
155
|
+
* additions are appended after them. */
|
|
156
|
+
platforms?: Platform[];
|
|
157
|
+
/**
|
|
158
|
+
* rman's own presets, laid under the **root**'s config. Defaults to {@link DEFAULT_PRESETS}; an
|
|
159
|
+
* empty list is a caller asking for a bare core, with nothing but what it registered itself.
|
|
160
|
+
*/
|
|
161
|
+
presets?: readonly string[];
|
|
162
|
+
/** How far the walk descends before giving up. Defaults to 10. */
|
|
163
|
+
deep?: number;
|
|
164
|
+
/** The reader levels are read with. Supply one to read from somewhere other than the disk. */
|
|
165
|
+
reader?: ConfigReader;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* **Where one directory's own child packages are** - the directories immediately below it that
|
|
169
|
+
* hold a package, as absolute paths. `undefined` for "this is not a directory I recognize".
|
|
170
|
+
*
|
|
171
|
+
* **A provider answers for one directory, not for the repository**, and that is the whole
|
|
172
|
+
* correction. It used to be `(root) => { root, packageDirs }`: asked once, at the top, by the
|
|
173
|
+
* first platform that recognized it - so in a polyglot repository the technology listed first in
|
|
174
|
+
* `plugins` decided which directories were packages *at all*. Measured, and documented as a known
|
|
175
|
+
* limitation for a year: a `Cargo.toml`-only package was simply not found until a provider that
|
|
176
|
+
* looks for both was listed first.
|
|
177
|
+
*
|
|
178
|
+
* Asked per directory, each platform only ever answers about its own packages - which is all a
|
|
179
|
+
* platform knows - and the recursion is the core's (see `walk`). A Cargo workspace nested inside
|
|
180
|
+
* a Node monorepo is then just a node in the tree whose children came from a different platform.
|
|
181
|
+
*
|
|
182
|
+
* **Children, not descendants.** A provider returning the whole subtree would have to know what
|
|
183
|
+
* the platforms below it consider a package; returning one level means it never has to. npm's
|
|
184
|
+
* `workspaces` globs are already one level by construction (`deep: 0`).
|
|
185
|
+
*
|
|
186
|
+
* Still directories rather than `Package` objects, for the reason it always was: discovery runs
|
|
187
|
+
* before any package exists, so a provider returning packages would make discovery the owner of
|
|
188
|
+
* identity too. A path is also unique by construction, where a name is only unique if the
|
|
189
|
+
* ecosystem says so.
|
|
190
|
+
*/
|
|
191
|
+
type Provider = (dir: string) => string[] | undefined;
|
|
192
|
+
/**
|
|
193
|
+
* One directory in the walk's result: which technology claimed it, and what sits below it.
|
|
194
|
+
*
|
|
195
|
+
* A plain tree rather than `Package`s, keeping the line `Provider` draws: `Repository.create`
|
|
196
|
+
* turns this into packages, so identity stays with the manifest provider and discovery stays
|
|
197
|
+
* with this one.
|
|
198
|
+
*/
|
|
199
|
+
interface Node {
|
|
200
|
+
/** Absolute path to the directory. */
|
|
201
|
+
dirname: string;
|
|
202
|
+
/** The technology that claimed it - `basePlatform` when none did, so a reader needs no guard. */
|
|
203
|
+
platform: Platform;
|
|
204
|
+
/** The nodes for the package directories directly below it, in the order the platform gave
|
|
205
|
+
* them. Empty for a leaf. */
|
|
206
|
+
children: Node[];
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* What a directory's `.rmanrc "platform"` resolves to, when it declares one - `undefined` when
|
|
210
|
+
* it says nothing, so the walk falls back to the guess.
|
|
211
|
+
*
|
|
212
|
+
* **A callback rather than config knowledge in here**, which keeps this namespace answering one
|
|
213
|
+
* question. Reading a directory's cascaded config, deciding that a declared name has to be
|
|
214
|
+
* loaded, and refusing one that cannot be, are all the repository's business; where the packages
|
|
215
|
+
* are is this one's. `Repository.create` supplies it - and it is also the seam a spec uses to
|
|
216
|
+
* drive the declaration path without writing a config file.
|
|
217
|
+
*/
|
|
218
|
+
type DeclaredPlatform = (dir: string) => Promise<Platform | undefined>;
|
|
219
|
+
/**
|
|
220
|
+
* **The walk**: descend from `rootDir`, asking each directory's own technology where its children
|
|
221
|
+
* are, and repeating for each answer.
|
|
222
|
+
*
|
|
223
|
+
* One step, applied recursively:
|
|
224
|
+
*
|
|
225
|
+
* 1. take the directory's **declared** platform if it has one, and otherwise the first registered
|
|
226
|
+
* platform whose manifest provider recognizes it (`app.platformFor`, `basePlatform` if none);
|
|
227
|
+
* 2. ask **that** platform's `getWorkspace` for the directories below it holding packages;
|
|
228
|
+
* 3. do the same for each of them.
|
|
229
|
+
*
|
|
230
|
+
* **A declaration wins, and is then held to it.** A platform named for a directory it does not
|
|
231
|
+
* recognize is a statement that is simply untrue, and the failure it would otherwise become is
|
|
232
|
+
* invisible: the manifest reads as nothing, so the package is named after its directory at
|
|
233
|
+
* `0.0.0` and the repository looks like it works. The error names the directory, the platform and
|
|
234
|
+
* the file that platform looked for.
|
|
235
|
+
*
|
|
236
|
+
* The root node always exists - a repository is a package whatever its technology - so this never
|
|
237
|
+
* returns `undefined`. A repository nobody recognizes is a root with no children, which is the
|
|
238
|
+
* single-package answer arrived at rather than guessed.
|
|
239
|
+
*
|
|
240
|
+
* **A directory is visited once.** A provider may legitimately name a directory another one
|
|
241
|
+
* already claimed (two globs overlapping, a symlinked package), and a provider naming an ancestor
|
|
242
|
+
* would otherwise recurse forever. First visit wins, so a package sits where it was first found.
|
|
243
|
+
*
|
|
244
|
+
* `deep` bounds the descent for the same reason `findRoot` bounds its climb: a provider computing
|
|
245
|
+
* paths rather than reading them can produce a chain that never ends, and a guessed depth is
|
|
246
|
+
* better than a hang with nothing printed.
|
|
247
|
+
*/
|
|
248
|
+
function walk(app: RmanApplication, rootDir: string, options?: {
|
|
249
|
+
deep?: number;
|
|
250
|
+
declared?: DeclaredPlatform;
|
|
251
|
+
}): Promise<Node>;
|
|
252
|
+
/** Every node below `node`, depth-first, excluding `node` itself - the flat list `Repository`
|
|
253
|
+
* reports as its packages, since the root is not one of its own members. */
|
|
254
|
+
function flatten(node: Node): Node[];
|
|
255
|
+
/**
|
|
256
|
+
* Where the repository starts, decided **without knowing anything about any ecosystem** - it has
|
|
257
|
+
* to be, because the plugins that do know are named in the config file this walk is looking for.
|
|
258
|
+
*
|
|
259
|
+
* Walking up from `from`, stopping after a directory holding `.git`, the root is:
|
|
260
|
+
*
|
|
261
|
+
* 1. the **outermost** directory in that chain holding an `.rmanrc*` - outermost, because a
|
|
262
|
+
* *package* may have its own `.rmanrc` (that is a supported thing), and from inside such a
|
|
263
|
+
* package the nearest one is the package's, not the repository's;
|
|
264
|
+
* 2. otherwise the `.git` directory itself, the ordinary meaning of "repository root";
|
|
265
|
+
* 3. otherwise `from`, which is all that is left to go on.
|
|
266
|
+
*
|
|
267
|
+
* **What "outermost" costs**, since the two cases genuinely conflict and only one can win: a
|
|
268
|
+
* self-contained project nested inside a larger git repository *and sharing its `.git`* resolves
|
|
269
|
+
* to the outer root, not to itself (measured). That is the same repository by any definition git
|
|
270
|
+
* recognizes, so it is the defensible answer - and a nested project with a `.git` of its own is
|
|
271
|
+
* found correctly, because the walk stops there before the outer `.rmanrc` is ever seen (also
|
|
272
|
+
* measured). A per-package `.rmanrc` is the common case and it is the one served.
|
|
273
|
+
*/
|
|
274
|
+
function findRoot(from: string, deep?: number): string;
|
|
275
|
+
}
|