@effected/workspaces 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CatalogAssemblyError.js +43 -0
- package/ChangeDetector.js +154 -0
- package/ConfigDependencyHooks.js +153 -0
- package/DependencyGraph.js +241 -0
- package/LICENSE +21 -0
- package/LockfileReader.js +118 -0
- package/PackageManagerName.js +248 -0
- package/Publishability.js +73 -0
- package/README.md +165 -0
- package/WorkspaceCatalogs.js +392 -0
- package/WorkspaceDiscovery.js +338 -0
- package/WorkspacePackage.js +247 -0
- package/WorkspaceRoot.js +90 -0
- package/WorkspaceSnapshots.js +0 -0
- package/WorkspaceStateSnapshot.js +165 -0
- package/Workspaces.js +113 -0
- package/WorkspacesSync.js +205 -0
- package/index.d.ts +1559 -0
- package/index.js +17 -0
- package/internal/catalogs.js +70 -0
- package/internal/enumerate.js +75 -0
- package/internal/limits.js +20 -0
- package/internal/patterns.js +62 -0
- package/internal/traverse.js +94 -0
- package/package.json +61 -0
- package/tsdoc-metadata.json +11 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,1559 @@
|
|
|
1
|
+
import { Context, Effect, FileSystem, Layer, Option, Path, Schema } from "effect";
|
|
2
|
+
import { Git, GitCommandError, NotARepositoryError, UnknownRefError } from "@effected/git";
|
|
3
|
+
import { CatalogResolver, WorkspaceResolver } from "@effected/npm";
|
|
4
|
+
import { GlobPattern } from "@effected/glob";
|
|
5
|
+
import { Lockfile, LockfileFramingError, LockfileIntegrity, LockfileParseError, ResolvedPackage, WorkspaceManifest } from "@effected/lockfiles";
|
|
6
|
+
import { Package } from "@effected/package-json";
|
|
7
|
+
import { ChildProcessSpawner } from "effect/unstable/process";
|
|
8
|
+
//#region src/CatalogAssemblyError.d.ts
|
|
9
|
+
declare const CatalogAssemblyError_base: Schema.Class<CatalogAssemblyError, Schema.TaggedStruct<"CatalogAssemblyError", {
|
|
10
|
+
/**
|
|
11
|
+
* Which input failed: `manifest` for a file-level or top-level shape problem,
|
|
12
|
+
* `catalog` for a malformed catalog block or the double-default duplication,
|
|
13
|
+
* `hooks` for a config-dependency `pnpmfile.cjs` load or replay failure.
|
|
14
|
+
*/
|
|
15
|
+
readonly source: Schema.Literals<readonly ["manifest", "catalog", "hooks"]>;
|
|
16
|
+
/** The file, the catalog name, or the config dependency name. */
|
|
17
|
+
readonly path: Schema.String;
|
|
18
|
+
/** The originating failure. */
|
|
19
|
+
readonly cause: Schema.Defect;
|
|
20
|
+
}>, import("effect/Cause").YieldableError>;
|
|
21
|
+
/**
|
|
22
|
+
* Raised when a workspace's catalogs cannot be assembled — a `pnpm-workspace.yaml`
|
|
23
|
+
* that is unreadable or not valid YAML, a root `package.json` `workspaces` field
|
|
24
|
+
* whose shape or catalog blocks are malformed in a way pnpm itself rejects
|
|
25
|
+
* (including the default catalog declared twice), or a config dependency whose
|
|
26
|
+
* `pnpmfile.cjs` cannot be loaded or replayed.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* A *missing* `pnpm-workspace.yaml`, an *absent* `workspaces` field, or one
|
|
30
|
+
* explicitly `null` is not an error: there is simply nothing to misread, so
|
|
31
|
+
* assembly yields the empty set. The reader is otherwise **hard-fail by design** —
|
|
32
|
+
* a silently-empty catalog read is the "every dependency looks newly added" bug,
|
|
33
|
+
* because catalog output is load-bearing for snapshot diffing.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
declare class CatalogAssemblyError extends CatalogAssemblyError_base {
|
|
38
|
+
/** Renders the failing source into a one-line message. */
|
|
39
|
+
get message(): string;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/WorkspacePackage.d.ts
|
|
43
|
+
declare const PublishConfig_base: Schema.Class<PublishConfig, Schema.Struct<{
|
|
44
|
+
/** Scoped-package visibility. Its presence overrides `private`. */
|
|
45
|
+
readonly access: Schema.optionalKey<Schema.Literals<readonly ["public", "restricted"]>>;
|
|
46
|
+
/** The registry to publish to. */
|
|
47
|
+
readonly registry: Schema.optionalKey<Schema.String>;
|
|
48
|
+
/** A subdirectory to publish instead of the package root. */
|
|
49
|
+
readonly directory: Schema.optionalKey<Schema.String>;
|
|
50
|
+
/** The dist-tag to publish under. */
|
|
51
|
+
readonly tag: Schema.optionalKey<Schema.String>;
|
|
52
|
+
}>, {}>;
|
|
53
|
+
/**
|
|
54
|
+
* The `publishConfig` fields workspace tooling reads.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* Deliberately narrow. `@effected/package-json` models `publishConfig` as an
|
|
58
|
+
* open `Record<string, unknown>` for round-trip fidelity, which preserves every
|
|
59
|
+
* key but types none of them; this is the typed projection of the four that
|
|
60
|
+
* decide *where and whether* a package publishes. Unknown keys are ignored, not
|
|
61
|
+
* rejected.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
declare class PublishConfig extends PublishConfig_base {}
|
|
66
|
+
/**
|
|
67
|
+
* The result of comparing two {@link WorkspacePackage} dependency snapshots.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* Comparison runs across all four dependency kinds combined, so a dependency
|
|
71
|
+
* that moves between kinds at the same version does not appear in the diff.
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
interface DependencyDiff {
|
|
76
|
+
/** Present in the receiver, absent from the other. */
|
|
77
|
+
readonly added: Record<string, string>;
|
|
78
|
+
/** Present in the other, absent from the receiver. */
|
|
79
|
+
readonly removed: Record<string, string>;
|
|
80
|
+
/** Present in both at different specifiers. */
|
|
81
|
+
readonly changed: Record<string, {
|
|
82
|
+
readonly from: string;
|
|
83
|
+
readonly to: string;
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
declare const WorkspaceManifestError_base: Schema.Class<WorkspaceManifestError, Schema.TaggedStruct<"WorkspaceManifestError", {
|
|
87
|
+
/** Absolute path to the `package.json` that failed. */
|
|
88
|
+
readonly packageJsonPath: Schema.String;
|
|
89
|
+
/** Whether the file could not be read, or read but not decoded. */
|
|
90
|
+
readonly kind: Schema.Literals<readonly ["read", "decode"]>;
|
|
91
|
+
/** The originating failure, preserved rather than flattened to a string. */
|
|
92
|
+
readonly cause: Schema.Defect;
|
|
93
|
+
}>, import("effect/Cause").YieldableError>;
|
|
94
|
+
/**
|
|
95
|
+
* Raised when a workspace member's `package.json` cannot be read or decoded
|
|
96
|
+
* into the strict `@effected/package-json` `Package` model.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* Discovery itself never raises this — it uses the tolerant projection. Only
|
|
100
|
+
* `WorkspacePackage.manifest` does, so opting into the strict model is an
|
|
101
|
+
* explicit, individually recoverable step.
|
|
102
|
+
*
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
declare class WorkspaceManifestError extends WorkspaceManifestError_base {
|
|
106
|
+
/** Renders the path and failure kind into a one-line message. */
|
|
107
|
+
get message(): string;
|
|
108
|
+
}
|
|
109
|
+
declare const WorkspacePackage_base: Schema.Class<WorkspacePackage, Schema.Struct<{
|
|
110
|
+
/** The package name. */
|
|
111
|
+
readonly name: Schema.NonEmptyString;
|
|
112
|
+
/** The raw `version` string — deliberately not semver-validated. */
|
|
113
|
+
readonly version: Schema.String;
|
|
114
|
+
/** Absolute path to the package directory. */
|
|
115
|
+
readonly path: Schema.NonEmptyString;
|
|
116
|
+
/** Absolute path to the package's `package.json`. */
|
|
117
|
+
readonly packageJsonPath: Schema.NonEmptyString;
|
|
118
|
+
/** POSIX path relative to the workspace root; `"."` for the root package. */
|
|
119
|
+
readonly relativePath: Schema.String;
|
|
120
|
+
/** Whether the package is marked private. */
|
|
121
|
+
readonly private: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
|
|
122
|
+
/** Production dependencies. */
|
|
123
|
+
readonly dependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
124
|
+
/** Development dependencies. */
|
|
125
|
+
readonly devDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
126
|
+
/** Peer dependencies. */
|
|
127
|
+
readonly peerDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
128
|
+
/** Optional dependencies. */
|
|
129
|
+
readonly optionalDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
130
|
+
/** The `publishConfig` block, when present. */
|
|
131
|
+
readonly publishConfig: Schema.optionalKey<typeof PublishConfig>;
|
|
132
|
+
}>, {}>;
|
|
133
|
+
/**
|
|
134
|
+
* A single package inside a workspace: the discovery-relevant slice of its
|
|
135
|
+
* `package.json` plus its filesystem location.
|
|
136
|
+
*
|
|
137
|
+
* @remarks
|
|
138
|
+
* Produced by `WorkspaceDiscovery` for every directory the `packages:` patterns
|
|
139
|
+
* enumerate. The root package is always present with `relativePath` `"."`.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { WorkspacePackage } from "@effected/workspaces";
|
|
144
|
+
*
|
|
145
|
+
* const pkg = WorkspacePackage.make({
|
|
146
|
+
* name: "@my-org/utils",
|
|
147
|
+
* version: "1.0.0",
|
|
148
|
+
* path: "/repo/packages/utils",
|
|
149
|
+
* packageJsonPath: "/repo/packages/utils/package.json",
|
|
150
|
+
* relativePath: "packages/utils",
|
|
151
|
+
* });
|
|
152
|
+
*
|
|
153
|
+
* pkg.isRootWorkspace; // false
|
|
154
|
+
* pkg.unscopedName; // "utils"
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
declare class WorkspacePackage extends WorkspacePackage_base {
|
|
160
|
+
/** Whether this is the workspace root package. */
|
|
161
|
+
get isRootWorkspace(): boolean;
|
|
162
|
+
/** Whether the package is publishable in principle (not marked private). */
|
|
163
|
+
get isPublic(): boolean;
|
|
164
|
+
/** The npm scope (`@org`), or `Option.none()` for an unscoped name. */
|
|
165
|
+
get scope(): Option.Option<string>;
|
|
166
|
+
/** The name with any scope stripped. */
|
|
167
|
+
get unscopedName(): string;
|
|
168
|
+
/**
|
|
169
|
+
* Every dependency, merged across the four kinds.
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* Precedence on a name declared in several kinds runs
|
|
173
|
+
* `dependencies` \> `devDependencies` \> `peerDependencies` \>
|
|
174
|
+
* `optionalDependencies`.
|
|
175
|
+
*/
|
|
176
|
+
get allDependencies(): Record<string, string>;
|
|
177
|
+
/** Whether `name` is a production dependency. */
|
|
178
|
+
hasDependency(name: string): boolean;
|
|
179
|
+
/** Whether `name` is a development dependency. */
|
|
180
|
+
hasDevDependency(name: string): boolean;
|
|
181
|
+
/** Whether `name` is a peer dependency. */
|
|
182
|
+
hasPeerDependency(name: string): boolean;
|
|
183
|
+
/** Whether `name` is an optional dependency. */
|
|
184
|
+
hasOptionalDependency(name: string): boolean;
|
|
185
|
+
/** Whether `name` appears in any of the four dependency kinds. */
|
|
186
|
+
hasAnyDependencyOn(name: string): boolean;
|
|
187
|
+
/** The declared specifier for `name`, searched across all four kinds. */
|
|
188
|
+
dependencyVersion(name: string): Option.Option<string>;
|
|
189
|
+
/**
|
|
190
|
+
* Whether any dependency name matches `pattern` — the `minimatch` runtime
|
|
191
|
+
* dependency's one call site, now over `@effected/glob`'s vendored engine.
|
|
192
|
+
*
|
|
193
|
+
* @remarks
|
|
194
|
+
* A `GlobPattern` is total and free to test. A `string` is compiled on every
|
|
195
|
+
* call and an **uncompilable** literal throws: a glob written into a call
|
|
196
|
+
* site is developer wiring, not untrusted input, so it belongs in the defect
|
|
197
|
+
* channel rather than widening the typed channel every caller must branch
|
|
198
|
+
* on. Compile once with `GlobPattern.compile` and pass the result when
|
|
199
|
+
* testing many packages.
|
|
200
|
+
*
|
|
201
|
+
* @param pattern - A compiled pattern, or a source string to compile.
|
|
202
|
+
*/
|
|
203
|
+
matchesDependency(pattern: GlobPattern | string): boolean;
|
|
204
|
+
/** Compare this package's dependencies against `other`'s. */
|
|
205
|
+
dependencyDiff(other: WorkspacePackage): DependencyDiff;
|
|
206
|
+
/**
|
|
207
|
+
* Project to `@effected/lockfiles`' `WorkspaceManifest` — the input shape of
|
|
208
|
+
* `LockfileIntegrity.compare`. Total.
|
|
209
|
+
*/
|
|
210
|
+
toWorkspaceManifest(): WorkspaceManifest;
|
|
211
|
+
/**
|
|
212
|
+
* Read and decode this package's `package.json` into the strict
|
|
213
|
+
* `@effected/package-json` `Package` model — the bridge from the
|
|
214
|
+
* tolerant discovery projection to the fully typed manifest.
|
|
215
|
+
*/
|
|
216
|
+
static readonly manifest: (self: WorkspacePackage) => Effect.Effect<Package, WorkspaceManifestError, FileSystem.FileSystem>;
|
|
217
|
+
/** Instance form of `WorkspacePackage.manifest`. */
|
|
218
|
+
manifest(): Effect.Effect<Package, WorkspaceManifestError, FileSystem.FileSystem>;
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/WorkspaceRoot.d.ts
|
|
222
|
+
/**
|
|
223
|
+
* The marker filenames {@link WorkspaceRoot} probes for, in priority order.
|
|
224
|
+
*
|
|
225
|
+
* @public
|
|
226
|
+
*/
|
|
227
|
+
declare const WORKSPACE_MARKERS: ReadonlyArray<string>;
|
|
228
|
+
declare const WorkspaceRootNotFoundError_base: Schema.Class<WorkspaceRootNotFoundError, Schema.TaggedStruct<"WorkspaceRootNotFoundError", {
|
|
229
|
+
/** The directory the ascent started from. */
|
|
230
|
+
readonly searchPath: Schema.String;
|
|
231
|
+
/** The marker filenames probed at each ancestor. */
|
|
232
|
+
readonly markers: Schema.$Array<Schema.String>;
|
|
233
|
+
}>, import("effect/Cause").YieldableError>;
|
|
234
|
+
/**
|
|
235
|
+
* Raised when no workspace root can be found by ascending from a directory.
|
|
236
|
+
*
|
|
237
|
+
* @remarks
|
|
238
|
+
* `markers` records what was probed, so the failure names the contract rather
|
|
239
|
+
* than paraphrasing it in prose.
|
|
240
|
+
*
|
|
241
|
+
* @public
|
|
242
|
+
*/
|
|
243
|
+
declare class WorkspaceRootNotFoundError extends WorkspaceRootNotFoundError_base {
|
|
244
|
+
/** Renders the search path and probed markers into a one-line message. */
|
|
245
|
+
get message(): string;
|
|
246
|
+
}
|
|
247
|
+
declare const WorkspaceRoot_base: Context.ServiceClass<WorkspaceRoot, "@effected/workspaces/WorkspaceRoot", {
|
|
248
|
+
/**
|
|
249
|
+
* The nearest workspace root at or above `cwd`.
|
|
250
|
+
*
|
|
251
|
+
* @param cwd - The directory to start the ascent from; resolved to an
|
|
252
|
+
* absolute path first.
|
|
253
|
+
*/
|
|
254
|
+
readonly find: (cwd: string) => Effect.Effect<string, WorkspaceRootNotFoundError>;
|
|
255
|
+
}>;
|
|
256
|
+
/**
|
|
257
|
+
* Locates the workspace root by ascending from a starting directory.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* import { WorkspaceRoot } from "@effected/workspaces";
|
|
262
|
+
* import { Effect } from "effect";
|
|
263
|
+
*
|
|
264
|
+
* const program = Effect.gen(function* () {
|
|
265
|
+
* const root = yield* WorkspaceRoot;
|
|
266
|
+
* return yield* root.find("/repo/packages/utils/src");
|
|
267
|
+
* });
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* @public
|
|
271
|
+
*/
|
|
272
|
+
declare class WorkspaceRoot extends WorkspaceRoot_base {
|
|
273
|
+
/** Builds the service over core `FileSystem` and `Path`. */
|
|
274
|
+
static readonly make: Effect.Effect<{
|
|
275
|
+
readonly find: (cwd: string) => Effect.Effect<string, WorkspaceRootNotFoundError>;
|
|
276
|
+
}, never, FileSystem.FileSystem | Path.Path>;
|
|
277
|
+
/** The live layer. */
|
|
278
|
+
static readonly layer: Layer.Layer<WorkspaceRoot, never, FileSystem.FileSystem | Path.Path>;
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/WorkspaceDiscovery.d.ts
|
|
282
|
+
declare const WorkspaceDiscoveryError_base: Schema.Class<WorkspaceDiscoveryError, Schema.TaggedStruct<"WorkspaceDiscoveryError", {
|
|
283
|
+
/** The workspace root discovery was running against. */
|
|
284
|
+
readonly root: Schema.String;
|
|
285
|
+
/** The file that failed. */
|
|
286
|
+
readonly path: Schema.String;
|
|
287
|
+
/** What went wrong with it. */
|
|
288
|
+
readonly kind: Schema.Literals<readonly ["read", "invalidJson", "invalidShape", "invalidYaml", "missingName", "missingVersion"]>;
|
|
289
|
+
/** The originating failure, if there was one. */
|
|
290
|
+
readonly cause: Schema.Defect;
|
|
291
|
+
}>, import("effect/Cause").YieldableError>;
|
|
292
|
+
/**
|
|
293
|
+
* Raised when a workspace member's `package.json` cannot be read, parsed, or
|
|
294
|
+
* used — it is missing, malformed, or lacks a `name` or `version`.
|
|
295
|
+
*
|
|
296
|
+
* @remarks
|
|
297
|
+
* `kind` is the discriminant a caller branches on; `cause` preserves the
|
|
298
|
+
* originating failure rather than flattening it into a sentence.
|
|
299
|
+
*
|
|
300
|
+
* @public
|
|
301
|
+
*/
|
|
302
|
+
declare class WorkspaceDiscoveryError extends WorkspaceDiscoveryError_base {
|
|
303
|
+
/** Renders the failing file and kind into a one-line message. */
|
|
304
|
+
get message(): string;
|
|
305
|
+
}
|
|
306
|
+
declare const WorkspacePatternError_base: Schema.Class<WorkspacePatternError, Schema.TaggedStruct<"WorkspacePatternError", {
|
|
307
|
+
/** The workspace root the patterns were expanded against. */
|
|
308
|
+
readonly root: Schema.String;
|
|
309
|
+
/** The offending pattern, verbatim. */
|
|
310
|
+
readonly pattern: Schema.String;
|
|
311
|
+
/** Why it could not be enumerated. */
|
|
312
|
+
readonly kind: Schema.Literals<readonly ["missingBaseDir", "uncompilable", "depthExceeded", "budgetExceeded", "unreadableDirectory"]>;
|
|
313
|
+
/** A short, structured detail — the missing directory, or the bound exceeded. */
|
|
314
|
+
readonly detail: Schema.String;
|
|
315
|
+
}>, import("effect/Cause").YieldableError>;
|
|
316
|
+
/**
|
|
317
|
+
* Raised when a `packages:` pattern cannot be enumerated: its base directory is
|
|
318
|
+
* absent (usually a typo), the descent exceeded its depth cap, or the visit
|
|
319
|
+
* budget was exhausted.
|
|
320
|
+
*
|
|
321
|
+
* @public
|
|
322
|
+
*/
|
|
323
|
+
declare class WorkspacePatternError extends WorkspacePatternError_base {
|
|
324
|
+
/** Renders the pattern and failure kind into a one-line message. */
|
|
325
|
+
get message(): string;
|
|
326
|
+
}
|
|
327
|
+
declare const PackageNotFoundError_base: Schema.Class<PackageNotFoundError, Schema.TaggedStruct<"PackageNotFoundError", {
|
|
328
|
+
/** The name that was requested. */
|
|
329
|
+
readonly name: Schema.String;
|
|
330
|
+
/** Every workspace package name that does exist. */
|
|
331
|
+
readonly available: Schema.$Array<Schema.String>;
|
|
332
|
+
}>, import("effect/Cause").YieldableError>;
|
|
333
|
+
/**
|
|
334
|
+
* Raised when a workspace package is requested by a name no member carries.
|
|
335
|
+
*
|
|
336
|
+
* @remarks
|
|
337
|
+
* `available` lists every known member, which is what makes the error
|
|
338
|
+
* actionable — a typo is obvious next to the list it missed.
|
|
339
|
+
*
|
|
340
|
+
* @public
|
|
341
|
+
*/
|
|
342
|
+
declare class PackageNotFoundError extends PackageNotFoundError_base {
|
|
343
|
+
/** Renders the requested name into a one-line message. */
|
|
344
|
+
get message(): string;
|
|
345
|
+
}
|
|
346
|
+
declare const WorkspaceInfo_base: Schema.Class<WorkspaceInfo, Schema.Struct<{
|
|
347
|
+
/** Absolute path to the workspace root. */
|
|
348
|
+
readonly root: Schema.String;
|
|
349
|
+
/** The `packages:` patterns, verbatim. */
|
|
350
|
+
readonly patterns: Schema.$Array<Schema.String>;
|
|
351
|
+
}>, {}>;
|
|
352
|
+
/**
|
|
353
|
+
* Top-level facts about a workspace: where it is, what manages it, and the
|
|
354
|
+
* patterns that define its membership.
|
|
355
|
+
*
|
|
356
|
+
* @public
|
|
357
|
+
*/
|
|
358
|
+
declare class WorkspaceInfo extends WorkspaceInfo_base {}
|
|
359
|
+
/**
|
|
360
|
+
* Every failure `WorkspaceDiscovery.getPackage` can surface: the discovery
|
|
361
|
+
* failures plus a name that matches no member.
|
|
362
|
+
*
|
|
363
|
+
* @public
|
|
364
|
+
*/
|
|
365
|
+
type WorkspaceLookupFailure = WorkspaceRootNotFoundError | WorkspaceDiscoveryError | WorkspacePatternError | PackageNotFoundError;
|
|
366
|
+
/**
|
|
367
|
+
* The error channel of the discovery methods that do not look a package up by
|
|
368
|
+
* name — everything except `getPackage`.
|
|
369
|
+
*
|
|
370
|
+
* @public
|
|
371
|
+
*/
|
|
372
|
+
type WorkspaceDiscoveryFailure = Exclude<WorkspaceLookupFailure, PackageNotFoundError>;
|
|
373
|
+
/**
|
|
374
|
+
* Options for the {@link WorkspaceDiscovery} layer.
|
|
375
|
+
*
|
|
376
|
+
* @public
|
|
377
|
+
*/
|
|
378
|
+
interface WorkspaceDiscoveryOptions {
|
|
379
|
+
/**
|
|
380
|
+
* The directory the workspace root is resolved from.
|
|
381
|
+
*
|
|
382
|
+
* @defaultValue `process.cwd()`, read lazily on first use — so a
|
|
383
|
+
* `process.chdir` between providing the layer and the first call is
|
|
384
|
+
* honoured.
|
|
385
|
+
*/
|
|
386
|
+
readonly cwd?: string;
|
|
387
|
+
/** Descent cap for segment-crossing patterns. Defaults to 32. */
|
|
388
|
+
readonly maxDepth?: number;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* The {@link WorkspaceDiscovery} service shape.
|
|
392
|
+
*
|
|
393
|
+
* @public
|
|
394
|
+
*/
|
|
395
|
+
interface WorkspaceDiscoveryShape {
|
|
396
|
+
/** Facts about the resolved workspace. */
|
|
397
|
+
readonly info: () => Effect.Effect<WorkspaceInfo, WorkspaceDiscoveryFailure>;
|
|
398
|
+
/** Every workspace package, root first, then the rest sorted by relative path. */
|
|
399
|
+
readonly listPackages: () => Effect.Effect<ReadonlyArray<WorkspacePackage>, WorkspaceDiscoveryFailure>;
|
|
400
|
+
/** The discovered packages keyed by their root-relative importer path. */
|
|
401
|
+
readonly importerMap: () => Effect.Effect<ReadonlyMap<string, WorkspacePackage>, WorkspaceDiscoveryFailure>;
|
|
402
|
+
/** A single package by name. */
|
|
403
|
+
readonly getPackage: (name: string) => Effect.Effect<WorkspacePackage, WorkspaceLookupFailure>;
|
|
404
|
+
/** The package owning an absolute file path, by longest-prefix match. */
|
|
405
|
+
readonly resolveFile: (filePath: string) => Effect.Effect<Option.Option<WorkspacePackage>, WorkspaceDiscoveryFailure>;
|
|
406
|
+
/** The distinct packages owning any of `filePaths`. */
|
|
407
|
+
readonly resolveFiles: (filePaths: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<WorkspacePackage>, WorkspaceDiscoveryFailure>;
|
|
408
|
+
/** Drop the memoized discovery so the next call re-reads the filesystem. */
|
|
409
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
410
|
+
}
|
|
411
|
+
declare const WorkspaceDiscovery_base: Context.ServiceClass<WorkspaceDiscovery, "@effected/workspaces/WorkspaceDiscovery", WorkspaceDiscoveryShape>;
|
|
412
|
+
/**
|
|
413
|
+
* Discovers the packages of a workspace.
|
|
414
|
+
*
|
|
415
|
+
* @remarks
|
|
416
|
+
* Layer construction is O(1): the root walk, pattern read, enumeration and
|
|
417
|
+
* per-package decode all happen on the first method call and are memoized for
|
|
418
|
+
* the lifetime of the layer. A Vitest reporter that builds the layer per call
|
|
419
|
+
* site and never queries it pays nothing.
|
|
420
|
+
*
|
|
421
|
+
* The memo is **success-only**. `Effect.cached` memoizes the first `Exit`,
|
|
422
|
+
* *including an interrupt* — an init interrupted by an unrelated timeout would
|
|
423
|
+
* otherwise brick the layer permanently with a cause outside its declared error
|
|
424
|
+
* channel. A failure or interrupt is therefore retried on the next call, which
|
|
425
|
+
* is a deliberate behaviour change from the v3 library.
|
|
426
|
+
*
|
|
427
|
+
* @example
|
|
428
|
+
* ```ts
|
|
429
|
+
* import { WorkspaceDiscovery } from "@effected/workspaces";
|
|
430
|
+
* import { Effect } from "effect";
|
|
431
|
+
*
|
|
432
|
+
* const program = Effect.gen(function* () {
|
|
433
|
+
* const discovery = yield* WorkspaceDiscovery;
|
|
434
|
+
* const packages = yield* discovery.listPackages();
|
|
435
|
+
* return packages.map((p) => p.name);
|
|
436
|
+
* });
|
|
437
|
+
* ```
|
|
438
|
+
*
|
|
439
|
+
* @public
|
|
440
|
+
*/
|
|
441
|
+
declare class WorkspaceDiscovery extends WorkspaceDiscovery_base {
|
|
442
|
+
/**
|
|
443
|
+
* Builds the service. Root resolution is one explicit concern: `cwd` is an
|
|
444
|
+
* option here, never an ambient `process.cwd()` read inside a method.
|
|
445
|
+
*/
|
|
446
|
+
static readonly make: (options?: WorkspaceDiscoveryOptions) => Effect.Effect<WorkspaceDiscoveryShape, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
|
|
447
|
+
/**
|
|
448
|
+
* The live layer.
|
|
449
|
+
*
|
|
450
|
+
* @remarks
|
|
451
|
+
* A parameterized layer factory mints a **fresh reference per call**, and
|
|
452
|
+
* layers memoize by reference — bind the result to a `const` and reuse it
|
|
453
|
+
* rather than calling `layer(...)` at each composition site.
|
|
454
|
+
*/
|
|
455
|
+
static readonly layer: (options?: WorkspaceDiscoveryOptions) => Layer.Layer<WorkspaceDiscovery, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
|
|
456
|
+
/**
|
|
457
|
+
* The real implementation of `@effected/npm`'s `WorkspaceResolver` contract
|
|
458
|
+
* — the one `@effected/package-json` declares but cannot fill.
|
|
459
|
+
*
|
|
460
|
+
* @remarks
|
|
461
|
+
* `versionOf` returns `Option.none()` for a name that is not a workspace
|
|
462
|
+
* member, per the contract's convention; the `DependencyResolutionError`
|
|
463
|
+
* channel is reserved for a failure of the resolution *mechanism* (an
|
|
464
|
+
* unfindable root, an unreadable manifest), never an ordinary miss.
|
|
465
|
+
*
|
|
466
|
+
* @example
|
|
467
|
+
* ```ts
|
|
468
|
+
* import { Package } from "@effected/package-json";
|
|
469
|
+
* import { WorkspaceDiscovery } from "@effected/workspaces";
|
|
470
|
+
* import { Layer } from "effect";
|
|
471
|
+
*
|
|
472
|
+
* const resolvers = WorkspaceDiscovery.workspaceResolver.pipe(
|
|
473
|
+
* Layer.provide(WorkspaceDiscovery.layer()),
|
|
474
|
+
* );
|
|
475
|
+
* // `Package.resolve` now resolves `workspace:*` for real.
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
static readonly workspaceResolver: Layer.Layer<WorkspaceResolver, never, WorkspaceDiscovery>;
|
|
479
|
+
}
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region src/ChangeDetector.d.ts
|
|
482
|
+
declare const ChangeDetectionOptions_base: Schema.Class<ChangeDetectionOptions, Schema.Struct<{
|
|
483
|
+
/**
|
|
484
|
+
* The ref to compare against.
|
|
485
|
+
*
|
|
486
|
+
* @defaultValue `"HEAD~1"`
|
|
487
|
+
*/
|
|
488
|
+
readonly base: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.String, never>>;
|
|
489
|
+
/**
|
|
490
|
+
* The ref to compare to.
|
|
491
|
+
*
|
|
492
|
+
* @defaultValue `"HEAD"`
|
|
493
|
+
*/
|
|
494
|
+
readonly head: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.String, never>>;
|
|
495
|
+
/**
|
|
496
|
+
* Whether to include staged, unstaged and untracked working-tree changes on
|
|
497
|
+
* top of the committed range.
|
|
498
|
+
*
|
|
499
|
+
* @defaultValue `false`
|
|
500
|
+
*/
|
|
501
|
+
readonly includeUncommitted: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
|
|
502
|
+
}>, {}>;
|
|
503
|
+
/**
|
|
504
|
+
* Which git refs to compare, and whether to fold in the working tree.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```ts
|
|
508
|
+
* import { ChangeDetectionOptions } from "@effected/workspaces";
|
|
509
|
+
*
|
|
510
|
+
* ChangeDetectionOptions.make({}); // HEAD~1...HEAD
|
|
511
|
+
* ChangeDetectionOptions.make({ base: "origin/main" }); // against a branch
|
|
512
|
+
* ```
|
|
513
|
+
*
|
|
514
|
+
* @public
|
|
515
|
+
*/
|
|
516
|
+
declare class ChangeDetectionOptions extends ChangeDetectionOptions_base {}
|
|
517
|
+
declare const ChangeDetectionError_base: Schema.Class<ChangeDetectionError, Schema.TaggedStruct<"ChangeDetectionError", {
|
|
518
|
+
/** The operation that could not run. */
|
|
519
|
+
readonly operation: Schema.String;
|
|
520
|
+
/** The originating failure. */
|
|
521
|
+
readonly cause: Schema.Defect;
|
|
522
|
+
}>, import("effect/Cause").YieldableError>;
|
|
523
|
+
/**
|
|
524
|
+
* Raised when change detection cannot proceed for a reason that is not one of
|
|
525
|
+
* git's own typed failures — the wrapper for "detection has no ground to stand
|
|
526
|
+
* on".
|
|
527
|
+
*
|
|
528
|
+
* @remarks
|
|
529
|
+
* A git command that merely *fails* surfaces as one of `@effected/git`'s typed
|
|
530
|
+
* errors ({@link ChangeDetectionFailure} carries `GitCommandError`,
|
|
531
|
+
* `NotARepositoryError` and `UnknownRefError`) rather than being flattened into
|
|
532
|
+
* this wrapper — a caller branches on git's taxonomy directly.
|
|
533
|
+
*
|
|
534
|
+
* @public
|
|
535
|
+
*/
|
|
536
|
+
declare class ChangeDetectionError extends ChangeDetectionError_base {
|
|
537
|
+
/** Renders the failed operation into a one-line message. */
|
|
538
|
+
get message(): string;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Every failure the change-detection methods can surface.
|
|
542
|
+
*
|
|
543
|
+
* @remarks
|
|
544
|
+
* `@effected/git`'s typed errors surface directly alongside
|
|
545
|
+
* {@link ChangeDetectionError} and the discovery failures — a git command that
|
|
546
|
+
* fails is reported as git classified it (`NotARepositoryError` for a
|
|
547
|
+
* non-repository, `UnknownRefError` for a bad ref, `GitCommandError`
|
|
548
|
+
* otherwise), not re-wrapped.
|
|
549
|
+
*
|
|
550
|
+
* @public
|
|
551
|
+
*/
|
|
552
|
+
type ChangeDetectionFailure = ChangeDetectionError | GitCommandError | NotARepositoryError | UnknownRefError | WorkspaceDiscoveryFailure;
|
|
553
|
+
/**
|
|
554
|
+
* The {@link ChangeDetector} service shape.
|
|
555
|
+
*
|
|
556
|
+
* @public
|
|
557
|
+
*/
|
|
558
|
+
interface ChangeDetectorShape {
|
|
559
|
+
/** The file paths (workspace-root-relative, as git reports them) changed in the range. */
|
|
560
|
+
readonly changedFiles: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<string>, ChangeDetectionFailure>;
|
|
561
|
+
/** The workspace packages owning those files. */
|
|
562
|
+
readonly changedPackages: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<WorkspacePackage>, ChangeDetectionFailure>;
|
|
563
|
+
/** Those packages plus every workspace package that transitively depends on one. */
|
|
564
|
+
readonly affectedPackages: (options?: ChangeDetectionOptions) => Effect.Effect<ReadonlyArray<WorkspacePackage>, ChangeDetectionFailure>;
|
|
565
|
+
}
|
|
566
|
+
declare const ChangeDetector_base: Context.ServiceClass<ChangeDetector, "@effected/workspaces/ChangeDetector", ChangeDetectorShape>;
|
|
567
|
+
/**
|
|
568
|
+
* Detects which workspace packages a git range touches.
|
|
569
|
+
*
|
|
570
|
+
* @remarks
|
|
571
|
+
* Three depths on one service, cheapest first — raw file paths, the packages
|
|
572
|
+
* owning them, and the transitive blast radius through the dependency graph.
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* ```ts
|
|
576
|
+
* import { ChangeDetectionOptions, ChangeDetector } from "@effected/workspaces";
|
|
577
|
+
* import { Effect } from "effect";
|
|
578
|
+
*
|
|
579
|
+
* const program = Effect.gen(function* () {
|
|
580
|
+
* const detector = yield* ChangeDetector;
|
|
581
|
+
* const affected = yield* detector.affectedPackages(
|
|
582
|
+
* ChangeDetectionOptions.make({ base: "origin/main" }),
|
|
583
|
+
* );
|
|
584
|
+
* return affected.map((pkg) => pkg.name);
|
|
585
|
+
* });
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* @public
|
|
589
|
+
*/
|
|
590
|
+
declare class ChangeDetector extends ChangeDetector_base {
|
|
591
|
+
/** Builds the service over `Git` and {@link WorkspaceDiscovery}. */
|
|
592
|
+
static readonly make: Effect.Effect<ChangeDetectorShape, never, Git | WorkspaceDiscovery>;
|
|
593
|
+
/** The live layer. */
|
|
594
|
+
static readonly layer: Layer.Layer<ChangeDetector, never, Git | WorkspaceDiscovery>;
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region src/ConfigDependencyHooks.d.ts
|
|
598
|
+
/**
|
|
599
|
+
* The {@link ConfigDependencyHooks} service shape.
|
|
600
|
+
*
|
|
601
|
+
* @remarks
|
|
602
|
+
* `inject` is given the workspace root, the manifest's `configDependencies`
|
|
603
|
+
* (name → version+integrity), and the inline-catalog seed as a plain
|
|
604
|
+
* `catalog name → dependency name → range` record, and produces the catalogs the
|
|
605
|
+
* replayed hooks yield. The default (no-op) implementation returns the seed
|
|
606
|
+
* unchanged and loads nothing.
|
|
607
|
+
*
|
|
608
|
+
* @public
|
|
609
|
+
*/
|
|
610
|
+
interface ConfigDependencyHooksShape {
|
|
611
|
+
/**
|
|
612
|
+
* Replay each config dependency's `updateConfig` hook over `seed`, in
|
|
613
|
+
* declaration order, and return the resulting catalogs.
|
|
614
|
+
*
|
|
615
|
+
* @param root - The workspace root; config dependencies resolve under
|
|
616
|
+
* `<root>/node_modules/.pnpm-config/<name>`.
|
|
617
|
+
* @param configDependencies - The `configDependencies` map (name →
|
|
618
|
+
* version+integrity) declared in `pnpm-workspace.yaml`.
|
|
619
|
+
* @param seed - The inline catalogs, as `catalog name → dependency → range`.
|
|
620
|
+
*/
|
|
621
|
+
readonly inject: (root: string, configDependencies: Readonly<Record<string, string>>, seed: Readonly<Record<string, Readonly<Record<string, string>>>>) => Effect.Effect<Readonly<Record<string, Readonly<Record<string, string>>>>, CatalogAssemblyError>;
|
|
622
|
+
}
|
|
623
|
+
declare const ConfigDependencyHooks_base: Context.ServiceClass<ConfigDependencyHooks, "@effected/workspaces/ConfigDependencyHooks", ConfigDependencyHooksShape>;
|
|
624
|
+
/**
|
|
625
|
+
* Replays a workspace's `configDependencies` `updateConfig` hooks over the inline
|
|
626
|
+
* catalogs — the opt-in seam that lets hook-injected catalogs participate in
|
|
627
|
+
* assembly.
|
|
628
|
+
*
|
|
629
|
+
* @remarks
|
|
630
|
+
* A contract-only service: it declares the shape and ships two layers, never a
|
|
631
|
+
* baked-in default. {@link ConfigDependencyHooks.layerNoop} executes no
|
|
632
|
+
* config-dependency code (it returns the seed untouched) and is what the default
|
|
633
|
+
* {@link WorkspaceCatalogs} layer wires; {@link ConfigDependencyHooks.layerLive}
|
|
634
|
+
* dynamically imports each `pnpmfile.cjs` and replays it, and is wired only by the
|
|
635
|
+
* explicit `WorkspaceCatalogs.layerWithConfigDependencies` opt-in.
|
|
636
|
+
*
|
|
637
|
+
* @public
|
|
638
|
+
*/
|
|
639
|
+
declare class ConfigDependencyHooks extends ConfigDependencyHooks_base {
|
|
640
|
+
/**
|
|
641
|
+
* The no-op layer: `inject` returns the seed unchanged and never touches a
|
|
642
|
+
* config dependency. The default {@link WorkspaceCatalogs} layer wires this, so
|
|
643
|
+
* the default catalog path provably executes no config-dependency code.
|
|
644
|
+
*/
|
|
645
|
+
static readonly layerNoop: Layer.Layer<ConfigDependencyHooks>;
|
|
646
|
+
/**
|
|
647
|
+
* The live layer: dynamically imports each config dependency's `pnpmfile.cjs`
|
|
648
|
+
* (in process, no subprocess) and replays its `updateConfig` hook over the
|
|
649
|
+
* seed, in declaration order. A dependency without a `pnpmfile.cjs` contributes
|
|
650
|
+
* nothing; a dependency whose file fails to load or replay fails typed with a
|
|
651
|
+
* `hooks`-source {@link CatalogAssemblyError}, never a silent skip.
|
|
652
|
+
*
|
|
653
|
+
* @remarks
|
|
654
|
+
* Node-coupled by design — the `node:fs` / `node:path` / `node:url` imports are
|
|
655
|
+
* the sanctioned Node-only overlay, matching the other seams here. Only ever
|
|
656
|
+
* wired by `WorkspaceCatalogs.layerWithConfigDependencies`.
|
|
657
|
+
*/
|
|
658
|
+
static readonly layerLive: Layer.Layer<ConfigDependencyHooks>;
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/DependencyGraph.d.ts
|
|
662
|
+
declare const CyclicDependencyError_base: Schema.Class<CyclicDependencyError, Schema.TaggedStruct<"CyclicDependencyError", {
|
|
663
|
+
/** The packages participating in the cycle. */
|
|
664
|
+
readonly cycle: Schema.$Array<Schema.String>;
|
|
665
|
+
}>, import("effect/Cause").YieldableError>;
|
|
666
|
+
/**
|
|
667
|
+
* Raised when the workspace dependency graph cannot be topologically ordered
|
|
668
|
+
* because it contains a cycle.
|
|
669
|
+
*
|
|
670
|
+
* @remarks
|
|
671
|
+
* `cycle` lists every package still carrying unsatisfied dependencies when
|
|
672
|
+
* Kahn's algorithm stalls — the strongly-connected residue, sorted. It is the
|
|
673
|
+
* set to break, not necessarily a single ordered loop.
|
|
674
|
+
*
|
|
675
|
+
* @public
|
|
676
|
+
*/
|
|
677
|
+
declare class CyclicDependencyError extends CyclicDependencyError_base {
|
|
678
|
+
/** Renders the cycle members into a one-line message. */
|
|
679
|
+
get message(): string;
|
|
680
|
+
}
|
|
681
|
+
declare const DependencyGraph_base: Schema.Class<DependencyGraph, Schema.Struct<{
|
|
682
|
+
/** The workspace packages the graph is drawn over. */
|
|
683
|
+
readonly packages: Schema.$Array<typeof WorkspacePackage>;
|
|
684
|
+
}>, {}>;
|
|
685
|
+
/**
|
|
686
|
+
* The directed graph of dependencies **between workspace packages**. External
|
|
687
|
+
* npm dependencies are not nodes.
|
|
688
|
+
*
|
|
689
|
+
* @remarks
|
|
690
|
+
* A pure value over the discovered package list, with the edge indexes built
|
|
691
|
+
* lazily into `#private` fields the schema never encodes. Edges are drawn from
|
|
692
|
+
* `dependencies`, `devDependencies`, `peerDependencies` and
|
|
693
|
+
* `optionalDependencies`; a self-edge is dropped.
|
|
694
|
+
*
|
|
695
|
+
* Total accessors never fail; the four fallible operations are `Effect.fn`
|
|
696
|
+
* boundaries.
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```ts
|
|
700
|
+
* import { DependencyGraph, WorkspaceDiscovery } from "@effected/workspaces";
|
|
701
|
+
* import { Effect } from "effect";
|
|
702
|
+
*
|
|
703
|
+
* const program = Effect.gen(function* () {
|
|
704
|
+
* const discovery = yield* WorkspaceDiscovery;
|
|
705
|
+
* const graph = DependencyGraph.make({ packages: yield* discovery.listPackages() });
|
|
706
|
+
* return yield* graph.levels();
|
|
707
|
+
* });
|
|
708
|
+
* ```
|
|
709
|
+
*
|
|
710
|
+
* @public
|
|
711
|
+
*/
|
|
712
|
+
declare class DependencyGraph extends DependencyGraph_base {
|
|
713
|
+
#private;
|
|
714
|
+
/** Every workspace package name, sorted. Total. */
|
|
715
|
+
get names(): ReadonlyArray<string>;
|
|
716
|
+
/** The adjacency map: name → the names it depends on. Total. */
|
|
717
|
+
get adjacency(): ReadonlyMap<string, ReadonlySet<string>>;
|
|
718
|
+
/**
|
|
719
|
+
* Whether the graph contains a cycle. Total.
|
|
720
|
+
*
|
|
721
|
+
* @remarks
|
|
722
|
+
* An explicit-stack DFS with an on-stack set — never recursive, so a long
|
|
723
|
+
* dependency chain cannot overflow.
|
|
724
|
+
*/
|
|
725
|
+
get hasCycle(): boolean;
|
|
726
|
+
/** The workspace packages `name` depends on, sorted. */
|
|
727
|
+
readonly dependenciesOf: (name: string) => Effect.Effect<readonly string[], PackageNotFoundError, never>;
|
|
728
|
+
/** The workspace packages that depend on `name`, sorted. */
|
|
729
|
+
readonly dependentsOf: (name: string) => Effect.Effect<readonly string[], PackageNotFoundError, never>;
|
|
730
|
+
/**
|
|
731
|
+
* `name` plus every package that transitively depends on it — the blast
|
|
732
|
+
* radius of a change. Sorted; includes `name` itself.
|
|
733
|
+
*/
|
|
734
|
+
readonly affectedBy: (names: readonly string[]) => Effect.Effect<readonly string[], never, never>;
|
|
735
|
+
/**
|
|
736
|
+
* Packages grouped into parallel build levels: level 0 depends on nothing in
|
|
737
|
+
* the workspace, level *n* depends only on levels below it.
|
|
738
|
+
*
|
|
739
|
+
* @remarks
|
|
740
|
+
* Kahn's algorithm over the reverse-edge index — linear, where v3's rescanned
|
|
741
|
+
* the whole adjacency map per processed node. Each level is sorted
|
|
742
|
+
* lexicographically, so the output is deterministic.
|
|
743
|
+
*/
|
|
744
|
+
readonly levels: () => Effect.Effect<readonly (readonly string[])[], CyclicDependencyError, never>;
|
|
745
|
+
/** The flattened topological order — `levels()` concatenated. */
|
|
746
|
+
readonly sort: () => Effect.Effect<readonly string[], CyclicDependencyError, never>;
|
|
747
|
+
/**
|
|
748
|
+
* A topological order over `names` plus their transitive workspace
|
|
749
|
+
* dependencies — the build order for a subset.
|
|
750
|
+
*/
|
|
751
|
+
readonly sortSubset: (names: readonly string[]) => Effect.Effect<readonly string[], CyclicDependencyError | PackageNotFoundError, never>;
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region src/PackageManagerName.d.ts
|
|
755
|
+
/**
|
|
756
|
+
* The four package managers this package understands.
|
|
757
|
+
*
|
|
758
|
+
* @public
|
|
759
|
+
*/
|
|
760
|
+
declare const PackageManagerName: Schema.Literals<readonly ["npm", "pnpm", "yarn", "bun"]>;
|
|
761
|
+
/**
|
|
762
|
+
* The decoded type of {@link (PackageManagerName:variable)}: `"npm" | "pnpm" | "yarn" | "bun"`.
|
|
763
|
+
*
|
|
764
|
+
* @public
|
|
765
|
+
*/
|
|
766
|
+
type PackageManagerName = typeof PackageManagerName.Type;
|
|
767
|
+
declare const DetectedPackageManager_base: Schema.Class<DetectedPackageManager, Schema.Struct<{
|
|
768
|
+
/** The detected manager. */
|
|
769
|
+
readonly name: Schema.Literals<readonly ["npm", "pnpm", "yarn", "bun"]>;
|
|
770
|
+
/** Its version, when a manifest field agrees on the manager and carries one. */
|
|
771
|
+
readonly version: Schema.Option<Schema.String>;
|
|
772
|
+
/** The JavaScript runtime the manager implies. */
|
|
773
|
+
readonly runtime: Schema.Literals<readonly ["node", "bun"]>;
|
|
774
|
+
}>, {}>;
|
|
775
|
+
/**
|
|
776
|
+
* The outcome of package-manager detection at a workspace root.
|
|
777
|
+
*
|
|
778
|
+
* @remarks
|
|
779
|
+
* `version` is `Option.none()` unless a manifest field naming the *same* manager
|
|
780
|
+
* that was detected also carries a version — a `packageManager: "yarn@4"` in a
|
|
781
|
+
* pnpm workspace tells us nothing about pnpm's version, so it is not reported as
|
|
782
|
+
* one. The two fields consulted are the corepack top-level `packageManager` and
|
|
783
|
+
* `devEngines.packageManager`; see {@link PackageManagerDetector} for the
|
|
784
|
+
* precedence between them.
|
|
785
|
+
*
|
|
786
|
+
* @public
|
|
787
|
+
*/
|
|
788
|
+
declare class DetectedPackageManager extends DetectedPackageManager_base {}
|
|
789
|
+
declare const PackageManagerDetectionError_base: Schema.Class<PackageManagerDetectionError, Schema.TaggedStruct<"PackageManagerDetectionError", {
|
|
790
|
+
/** The workspace root that was probed. */
|
|
791
|
+
readonly root: Schema.String;
|
|
792
|
+
/** The marker files probed, in the order they were probed. */
|
|
793
|
+
readonly checked: Schema.$Array<Schema.String>;
|
|
794
|
+
}>, import("effect/Cause").YieldableError>;
|
|
795
|
+
/**
|
|
796
|
+
* Raised when a directory carries no lockfile and no workspace configuration,
|
|
797
|
+
* so no package manager can be attributed to it.
|
|
798
|
+
*
|
|
799
|
+
* @public
|
|
800
|
+
*/
|
|
801
|
+
declare class PackageManagerDetectionError extends PackageManagerDetectionError_base {
|
|
802
|
+
/** Renders the root and probed markers into a one-line message. */
|
|
803
|
+
get message(): string;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Every failure {@link PackageManagerDetector} can surface: no manager could be
|
|
807
|
+
* attributed to the root, or the root's `package.json` exists but cannot be read
|
|
808
|
+
* or parsed.
|
|
809
|
+
*
|
|
810
|
+
* @public
|
|
811
|
+
*/
|
|
812
|
+
type PackageManagerDetectionFailure = PackageManagerDetectionError | WorkspaceManifestError;
|
|
813
|
+
declare const PackageManagerDetector_base: Context.ServiceClass<PackageManagerDetector, "@effected/workspaces/PackageManagerDetector", {
|
|
814
|
+
/** Detect the package manager at a workspace root. */
|
|
815
|
+
readonly detect: (root: string) => Effect.Effect<DetectedPackageManager, PackageManagerDetectionFailure>;
|
|
816
|
+
}>;
|
|
817
|
+
/**
|
|
818
|
+
* Detects which package manager owns a workspace root.
|
|
819
|
+
*
|
|
820
|
+
* @remarks
|
|
821
|
+
* **Lockfile evidence is the primary signal** — it is what says which manager
|
|
822
|
+
* actually ran. Priority, first match wins: a `pnpm-workspace.yaml` means pnpm;
|
|
823
|
+
* a bun lockfile *plus* a manifest field naming bun means bun; a `yarn.lock`
|
|
824
|
+
* *plus* a manifest field naming yarn means yarn; a root `package.json` with a
|
|
825
|
+
* `workspaces` field falls back to npm.
|
|
826
|
+
*
|
|
827
|
+
* The manifest conjunction is deliberate: a stray `yarn.lock` in an npm repo is
|
|
828
|
+
* common, and only a declared manager name disambiguates it.
|
|
829
|
+
*
|
|
830
|
+
* **Two manifest fields declare a manager, and they are not interchangeable.**
|
|
831
|
+
* Corepack reads both, and this is the rule that falls out of how it treats
|
|
832
|
+
* them:
|
|
833
|
+
*
|
|
834
|
+
* - `devEngines.packageManager.name` is authoritative for the **name**.
|
|
835
|
+
* Corepack *errors* when a top-level `packageManager` disagrees with it (per
|
|
836
|
+
* `devEngines.packageManager.onFail`), so where both are present and disagree,
|
|
837
|
+
* `devEngines` is the one to believe. When `devEngines` names a manager, the
|
|
838
|
+
* top-level field's name is not consulted as a disambiguator at all.
|
|
839
|
+
* - The top-level `packageManager` is authoritative for the exact **version**:
|
|
840
|
+
* it is the field that carries the integrity hash. Where both name the same
|
|
841
|
+
* manager, its version wins; where it is absent, `devEngines.packageManager.version`
|
|
842
|
+
* supplies the version instead.
|
|
843
|
+
*
|
|
844
|
+
* A version is reported **only when the field it came from names the manager
|
|
845
|
+
* that was actually detected**. A `packageManager: "yarn@4"` in a pnpm workspace
|
|
846
|
+
* says nothing about pnpm's version, so no version is reported — and the same
|
|
847
|
+
* discipline applies to `devEngines`.
|
|
848
|
+
*
|
|
849
|
+
* Malformed manifest *hints* are ignored rather than fatal, matching corepack: a
|
|
850
|
+
* non-object or array `devEngines.packageManager`, a `name` containing `@`, or a
|
|
851
|
+
* version that is not an exact version cannot turn a detectable workspace into a
|
|
852
|
+
* detection failure. A manifest that exists but cannot be **read or parsed** is a
|
|
853
|
+
* different thing entirely and fails with a `WorkspaceManifestError` — a corrupt
|
|
854
|
+
* root manifest is a real problem, not a missing hint.
|
|
855
|
+
*
|
|
856
|
+
* @public
|
|
857
|
+
*/
|
|
858
|
+
declare class PackageManagerDetector extends PackageManagerDetector_base {
|
|
859
|
+
/** Builds the service over core `FileSystem` and `Path`. */
|
|
860
|
+
static readonly make: Effect.Effect<{
|
|
861
|
+
readonly detect: (root: string) => Effect.Effect<DetectedPackageManager, PackageManagerDetectionFailure>;
|
|
862
|
+
}, never, FileSystem.FileSystem | Path.Path>;
|
|
863
|
+
/** The live layer. */
|
|
864
|
+
static readonly layer: Layer.Layer<PackageManagerDetector, never, FileSystem.FileSystem | Path.Path>;
|
|
865
|
+
}
|
|
866
|
+
//#endregion
|
|
867
|
+
//#region src/LockfileReader.d.ts
|
|
868
|
+
declare const LockfileReadError_base: Schema.Class<LockfileReadError, Schema.TaggedStruct<"LockfileReadError", {
|
|
869
|
+
/** Absolute path to the lockfile that could not be read. */
|
|
870
|
+
readonly lockfilePath: Schema.String;
|
|
871
|
+
/** The format the detected package manager implies. */
|
|
872
|
+
readonly format: Schema.Literals<readonly ["bun", "npm", "pnpm", "yarn"]>;
|
|
873
|
+
/** The originating failure. */
|
|
874
|
+
readonly cause: Schema.Defect;
|
|
875
|
+
}>, import("effect/Cause").YieldableError>;
|
|
876
|
+
/**
|
|
877
|
+
* Raised when the workspace's lockfile cannot be read off disk.
|
|
878
|
+
*
|
|
879
|
+
* @remarks
|
|
880
|
+
* Parse failures are `@effected/lockfiles`' `LockfileParseError`, not this —
|
|
881
|
+
* this is strictly the IO half.
|
|
882
|
+
*
|
|
883
|
+
* @public
|
|
884
|
+
*/
|
|
885
|
+
declare class LockfileReadError extends LockfileReadError_base {
|
|
886
|
+
/** Renders the unreadable path into a one-line message. */
|
|
887
|
+
get message(): string;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Every failure the lockfile methods can surface — the exported init-error
|
|
891
|
+
* union the review named best-in-class DX.
|
|
892
|
+
*
|
|
893
|
+
* @remarks
|
|
894
|
+
* Layer construction does no IO, so every member surfaces from the *methods*
|
|
895
|
+
* rather than from `Layer.build`: the root cannot be found, no package manager
|
|
896
|
+
* can be attributed to it (or its manifest is corrupt), its lockfile cannot be
|
|
897
|
+
* read, the lockfile is malformed, or the lockfile's YAML stream carries no
|
|
898
|
+
* lockfile document.
|
|
899
|
+
*
|
|
900
|
+
* @public
|
|
901
|
+
*/
|
|
902
|
+
type LockfileReadFailure = WorkspaceRootNotFoundError | PackageManagerDetectionFailure | LockfileReadError | LockfileParseError | LockfileFramingError;
|
|
903
|
+
/**
|
|
904
|
+
* The {@link LockfileReader} service shape.
|
|
905
|
+
*
|
|
906
|
+
* @public
|
|
907
|
+
*/
|
|
908
|
+
interface LockfileReaderShape {
|
|
909
|
+
/** The parsed lockfile, with pnpm importer paths already resolved to real names. */
|
|
910
|
+
readonly read: () => Effect.Effect<Lockfile, LockfileReadFailure>;
|
|
911
|
+
/**
|
|
912
|
+
* The lockfile's record of a package, when it records one.
|
|
913
|
+
*
|
|
914
|
+
* @remarks
|
|
915
|
+
* A name can resolve at **several versions** in one lockfile (two members
|
|
916
|
+
* depending on different majors of the same package). This returns the
|
|
917
|
+
* **first** entry in lockfile order and does not attempt to rank them — there
|
|
918
|
+
* is no single "the" version to return, and picking the highest semver would
|
|
919
|
+
* imply a resolution decision this reader is not entitled to make. Callers
|
|
920
|
+
* that must see every resolution should read `lockfile.packagesNamed(name)`
|
|
921
|
+
* off `read()` directly.
|
|
922
|
+
*/
|
|
923
|
+
readonly resolvedVersion: (packageName: string) => Effect.Effect<Option.Option<ResolvedPackage>, LockfileReadFailure>;
|
|
924
|
+
/**
|
|
925
|
+
* Whether the lockfile agrees with the workspace manifests on disk — the
|
|
926
|
+
* pure `LockfileIntegrity.compare`, fed the manifests this package reads.
|
|
927
|
+
*/
|
|
928
|
+
readonly integrity: () => Effect.Effect<LockfileIntegrity, LockfileReadFailure | WorkspaceDiscoveryFailure>;
|
|
929
|
+
/** Drop the memoized read so the next call re-reads the lockfile. */
|
|
930
|
+
readonly refresh: () => Effect.Effect<void>;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Options for the {@link LockfileReader} layer.
|
|
934
|
+
*
|
|
935
|
+
* @public
|
|
936
|
+
*/
|
|
937
|
+
interface LockfileReaderOptions {
|
|
938
|
+
/**
|
|
939
|
+
* The directory the workspace root is resolved from.
|
|
940
|
+
*
|
|
941
|
+
* @defaultValue `process.cwd()`, read lazily on first use.
|
|
942
|
+
*/
|
|
943
|
+
readonly cwd?: string;
|
|
944
|
+
}
|
|
945
|
+
declare const LockfileReader_base: Context.ServiceClass<LockfileReader, "@effected/workspaces/LockfileReader", LockfileReaderShape>;
|
|
946
|
+
/**
|
|
947
|
+
* Reads and parses the workspace's lockfile.
|
|
948
|
+
*
|
|
949
|
+
* @remarks
|
|
950
|
+
* Layer construction is O(1). The root walk, package-manager detection, file
|
|
951
|
+
* read, parse and pnpm name resolution all happen on the first method call and
|
|
952
|
+
* are memoized success-only for the lifetime of the layer.
|
|
953
|
+
*
|
|
954
|
+
* @example
|
|
955
|
+
* ```ts
|
|
956
|
+
* import { LockfileReader } from "@effected/workspaces";
|
|
957
|
+
* import { Effect } from "effect";
|
|
958
|
+
*
|
|
959
|
+
* const program = Effect.gen(function* () {
|
|
960
|
+
* const reader = yield* LockfileReader;
|
|
961
|
+
* const lockfile = yield* reader.read();
|
|
962
|
+
* return lockfile.packages.length;
|
|
963
|
+
* });
|
|
964
|
+
* ```
|
|
965
|
+
*
|
|
966
|
+
* @public
|
|
967
|
+
*/
|
|
968
|
+
declare class LockfileReader extends LockfileReader_base {
|
|
969
|
+
/** Builds the service. */
|
|
970
|
+
static readonly make: (options?: LockfileReaderOptions) => Effect.Effect<LockfileReaderShape, never, WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
|
|
971
|
+
/**
|
|
972
|
+
* The live layer.
|
|
973
|
+
*
|
|
974
|
+
* @remarks
|
|
975
|
+
* Parameterized, so it mints a fresh reference per call — bind it to a
|
|
976
|
+
* `const` and reuse it.
|
|
977
|
+
*/
|
|
978
|
+
static readonly layer: (options?: LockfileReaderOptions) => Layer.Layer<LockfileReader, never, WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
|
|
979
|
+
}
|
|
980
|
+
//#endregion
|
|
981
|
+
//#region src/Publishability.d.ts
|
|
982
|
+
declare const PublishTarget_base: Schema.Class<PublishTarget, Schema.Struct<{
|
|
983
|
+
/** The package name being published. */
|
|
984
|
+
readonly name: Schema.NonEmptyString;
|
|
985
|
+
/** The registry URL. */
|
|
986
|
+
readonly registry: Schema.NonEmptyString;
|
|
987
|
+
/** The directory to publish, relative to the package root; `"."` for the root itself. */
|
|
988
|
+
readonly directory: Schema.String;
|
|
989
|
+
/** Scoped-package visibility. */
|
|
990
|
+
readonly access: Schema.Literals<readonly ["public", "restricted"]>;
|
|
991
|
+
/** Whether to publish with a provenance attestation. */
|
|
992
|
+
readonly provenance: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.Boolean, never>>;
|
|
993
|
+
}>, {}>;
|
|
994
|
+
/**
|
|
995
|
+
* A resolved publish destination for a workspace package.
|
|
996
|
+
*
|
|
997
|
+
* @public
|
|
998
|
+
*/
|
|
999
|
+
declare class PublishTarget extends PublishTarget_base {}
|
|
1000
|
+
declare const PublishabilityDetector_base: Context.ServiceClass<PublishabilityDetector, "@effected/workspaces/PublishabilityDetector", {
|
|
1001
|
+
/** The publish targets for a package; empty means it does not publish. */
|
|
1002
|
+
readonly detect: (pkg: WorkspacePackage) => Effect.Effect<ReadonlyArray<PublishTarget>>;
|
|
1003
|
+
}>;
|
|
1004
|
+
/**
|
|
1005
|
+
* Decides whether a workspace package publishes, and to where.
|
|
1006
|
+
*
|
|
1007
|
+
* @remarks
|
|
1008
|
+
* The default layer implements standard npm semantics: a `private` package with
|
|
1009
|
+
* no `publishConfig.access` publishes nowhere; an explicit
|
|
1010
|
+
* `publishConfig.access` overrides `private`; anything else publishes to the
|
|
1011
|
+
* public registry with defaults.
|
|
1012
|
+
*
|
|
1013
|
+
* Those are *npm's* semantics, not necessarily yours. Swap the layer:
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* ```ts
|
|
1017
|
+
* import { PublishabilityDetector, PublishTarget } from "@effected/workspaces";
|
|
1018
|
+
* import { Effect, Layer } from "effect";
|
|
1019
|
+
*
|
|
1020
|
+
* const internalOnly = Layer.succeed(PublishabilityDetector, {
|
|
1021
|
+
* detect: (pkg) =>
|
|
1022
|
+
* Effect.succeed(
|
|
1023
|
+
* pkg.name.startsWith("@acme/")
|
|
1024
|
+
* ? [PublishTarget.make({
|
|
1025
|
+
* name: pkg.name,
|
|
1026
|
+
* registry: "https://npm.acme.internal/",
|
|
1027
|
+
* directory: ".",
|
|
1028
|
+
* access: "restricted",
|
|
1029
|
+
* })]
|
|
1030
|
+
* : [],
|
|
1031
|
+
* ),
|
|
1032
|
+
* });
|
|
1033
|
+
* ```
|
|
1034
|
+
*
|
|
1035
|
+
* @public
|
|
1036
|
+
*/
|
|
1037
|
+
declare class PublishabilityDetector extends PublishabilityDetector_base {
|
|
1038
|
+
/** Standard npm publishing semantics. Pure — no filesystem, no platform services. */
|
|
1039
|
+
static readonly layer: Layer.Layer<PublishabilityDetector>;
|
|
1040
|
+
}
|
|
1041
|
+
//#endregion
|
|
1042
|
+
//#region src/WorkspaceCatalogs.d.ts
|
|
1043
|
+
declare const CatalogSet_base: Schema.Class<CatalogSet, Schema.Struct<{
|
|
1044
|
+
/** Catalog name → dependency name → version range. */
|
|
1045
|
+
readonly entries: Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.String>>;
|
|
1046
|
+
}>, {}>;
|
|
1047
|
+
/**
|
|
1048
|
+
* An immutable, fully-normalized catalog collection — the one catalog
|
|
1049
|
+
* resolution semantic in the package.
|
|
1050
|
+
*
|
|
1051
|
+
* @remarks
|
|
1052
|
+
* `entries` is catalog name → dependency → range, with pnpm's unnamed
|
|
1053
|
+
* top-level `catalog:` block normalized under the key `"default"`. Lockfile
|
|
1054
|
+
* catalog entries, which pnpm records as `{ specifier, version }`, are
|
|
1055
|
+
* normalized to their `specifier` — the declared range, which is what a catalog
|
|
1056
|
+
* resolves to.
|
|
1057
|
+
*
|
|
1058
|
+
* @public
|
|
1059
|
+
*/
|
|
1060
|
+
declare class CatalogSet extends CatalogSet_base {
|
|
1061
|
+
/** The empty set — a workspace with no catalogs. */
|
|
1062
|
+
static empty(): CatalogSet;
|
|
1063
|
+
/** Wrap a pnpm `Catalogs` map, dropping unusable entries. */
|
|
1064
|
+
static fromCatalogs(catalogs: unknown): CatalogSet;
|
|
1065
|
+
/**
|
|
1066
|
+
* The `catalog:` and `catalogs:` blocks of a `pnpm-workspace.yaml` document.
|
|
1067
|
+
*
|
|
1068
|
+
* @param text - The raw YAML text.
|
|
1069
|
+
*/
|
|
1070
|
+
static readonly fromWorkspaceYaml: (text: string) => Effect.Effect<CatalogSet, CatalogAssemblyError, never>;
|
|
1071
|
+
/**
|
|
1072
|
+
* The `catalogs:` section of a pnpm lockfile, whose entries are either a bare
|
|
1073
|
+
* range or a `{ specifier, version }` pair.
|
|
1074
|
+
*/
|
|
1075
|
+
static fromLockfileCatalogs(raw: unknown): CatalogSet;
|
|
1076
|
+
/**
|
|
1077
|
+
* The catalog set a parsed lockfile records, PM-aware.
|
|
1078
|
+
*
|
|
1079
|
+
* @remarks
|
|
1080
|
+
* Both pnpm and bun record catalogs in the lockfile, in different shapes:
|
|
1081
|
+
* pnpm under `extension.catalogs`, bun under `extension.catalog` /
|
|
1082
|
+
* `extension.catalogs`. Assembly reads whichever the parsed lockfile carries
|
|
1083
|
+
* rather than assuming the pnpm extension. A lockfile with no extension, or a
|
|
1084
|
+
* pnpm one with no catalogs, yields the empty set.
|
|
1085
|
+
*
|
|
1086
|
+
* @param lockfile - A parsed lockfile from `@effected/lockfiles`.
|
|
1087
|
+
*/
|
|
1088
|
+
static fromLockfile(lockfile: Lockfile): CatalogSet;
|
|
1089
|
+
/**
|
|
1090
|
+
* A catalog set from bun's `{ catalog, catalogs }` blocks — used for the
|
|
1091
|
+
* `bun.lock` extension and for the root `package.json` `workspaces` block. The
|
|
1092
|
+
* unnamed default catalog normalizes under `"default"`. Tolerant: unusable
|
|
1093
|
+
* values are dropped, never fatal.
|
|
1094
|
+
*
|
|
1095
|
+
* @param blocks - The `catalog` (default) and `catalogs` (named) blocks.
|
|
1096
|
+
*/
|
|
1097
|
+
static fromBunBlocks(blocks: {
|
|
1098
|
+
readonly catalog?: unknown;
|
|
1099
|
+
readonly catalogs?: unknown;
|
|
1100
|
+
}): CatalogSet;
|
|
1101
|
+
/**
|
|
1102
|
+
* The `catalog` / `catalogs` blocks of a root `package.json` `workspaces` field
|
|
1103
|
+
* — bun's package.json analogue of pnpm's `pnpm-workspace.yaml` blocks.
|
|
1104
|
+
*
|
|
1105
|
+
* @remarks
|
|
1106
|
+
* **Hard-fail by design**, preserving the semantics catalog output is
|
|
1107
|
+
* load-bearing for: a present-but-malformed `workspaces` shape (a number, a
|
|
1108
|
+
* string, an object with a malformed `packages` / `catalog` / `catalogs`), or
|
|
1109
|
+
* the default catalog declared twice — once as `workspaces.catalog` and again
|
|
1110
|
+
* as `workspaces.catalogs.default` — fails with {@link CatalogAssemblyError}
|
|
1111
|
+
* naming what was wrong. An absent `workspaces` field, one explicitly `null`,
|
|
1112
|
+
* or the plain array form (npm/yarn patterns, which carry no catalogs) yields
|
|
1113
|
+
* the empty set. Presence is checked structurally, so an explicitly-declared
|
|
1114
|
+
* empty `catalog: {}` still counts as a declaration.
|
|
1115
|
+
*
|
|
1116
|
+
* @param text - The raw root `package.json` text.
|
|
1117
|
+
*/
|
|
1118
|
+
static readonly fromManifestWorkspaces: (text: string) => Effect.Effect<CatalogSet, CatalogAssemblyError, never>;
|
|
1119
|
+
/** Merge sets. Later sets win per dependency within a catalog. */
|
|
1120
|
+
static merge(...sets: ReadonlyArray<CatalogSet>): CatalogSet;
|
|
1121
|
+
/** Whether any catalog declares anything. */
|
|
1122
|
+
get isEmpty(): boolean;
|
|
1123
|
+
/**
|
|
1124
|
+
* The range a `catalog:` specifier resolves to.
|
|
1125
|
+
*
|
|
1126
|
+
* @remarks
|
|
1127
|
+
* Total: an unmatched dependency, an unknown catalog name, or a non-catalog
|
|
1128
|
+
* specifier all yield `Option.none()`. A *malformed* catalog — one pnpm
|
|
1129
|
+
* itself rejects — also yields `Option.none()` here; the fallible surface is
|
|
1130
|
+
* {@link WorkspaceCatalogs}, which fails typed on assembly instead.
|
|
1131
|
+
*
|
|
1132
|
+
* @param dependency - The package name being resolved.
|
|
1133
|
+
* @param specifier - The declared specifier, e.g. `catalog:` or `catalog:build`.
|
|
1134
|
+
*/
|
|
1135
|
+
resolveSpecifier(dependency: string, specifier: string): Option.Option<string>;
|
|
1136
|
+
/**
|
|
1137
|
+
* The range `dependency` carries in a named catalog, or in the default
|
|
1138
|
+
* catalog when `catalog` is `Option.none()`.
|
|
1139
|
+
*
|
|
1140
|
+
* @remarks
|
|
1141
|
+
* The shape `@effected/npm`'s `CatalogResolver` contract asks for.
|
|
1142
|
+
*/
|
|
1143
|
+
rangeOf(dependency: string, catalog: Option.Option<string>): Option.Option<string>;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Every failure catalog assembly can surface.
|
|
1147
|
+
*
|
|
1148
|
+
* @public
|
|
1149
|
+
*/
|
|
1150
|
+
type CatalogAssemblyFailure = CatalogAssemblyError | WorkspaceRootNotFoundError;
|
|
1151
|
+
/**
|
|
1152
|
+
* The {@link WorkspaceCatalogs} service shape.
|
|
1153
|
+
*
|
|
1154
|
+
* @public
|
|
1155
|
+
*/
|
|
1156
|
+
interface WorkspaceCatalogsShape {
|
|
1157
|
+
/** The assembled catalog set for the workspace. Memoized after the first call. */
|
|
1158
|
+
readonly set: () => Effect.Effect<CatalogSet, CatalogAssemblyFailure>;
|
|
1159
|
+
/** Resolve one `catalog:` specifier; `Option.none()` when it names nothing. */
|
|
1160
|
+
readonly resolveSpecifier: (dependency: string, specifier: string) => Effect.Effect<Option.Option<string>, CatalogAssemblyFailure>;
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Options for the {@link WorkspaceCatalogs} layer.
|
|
1164
|
+
*
|
|
1165
|
+
* @public
|
|
1166
|
+
*/
|
|
1167
|
+
interface WorkspaceCatalogsOptions {
|
|
1168
|
+
/**
|
|
1169
|
+
* The directory the workspace root is resolved from.
|
|
1170
|
+
*
|
|
1171
|
+
* @defaultValue `process.cwd()`, read lazily on first use.
|
|
1172
|
+
*/
|
|
1173
|
+
readonly cwd?: string;
|
|
1174
|
+
}
|
|
1175
|
+
declare const WorkspaceCatalogs_base: Context.ServiceClass<WorkspaceCatalogs, "@effected/workspaces/WorkspaceCatalogs", WorkspaceCatalogsShape>;
|
|
1176
|
+
/**
|
|
1177
|
+
* Assembles a workspace's catalogs, package-manager-aware.
|
|
1178
|
+
*
|
|
1179
|
+
* @remarks
|
|
1180
|
+
* The inline source is picked by **file presence**, the same rule
|
|
1181
|
+
* `internal/patterns.ts` uses for globs: a `pnpm-workspace.yaml` selects the pnpm
|
|
1182
|
+
* path (its `catalog:` / `catalogs:` blocks); its absence selects the root
|
|
1183
|
+
* `package.json` `workspaces.catalog` / `workspaces.catalogs` (bun's analogue).
|
|
1184
|
+
* The lockfile source is PM-aware too — whichever extension the parsed lockfile
|
|
1185
|
+
* carries (pnpm or bun) contributes its recorded catalogs.
|
|
1186
|
+
*
|
|
1187
|
+
* Precedence, lowest first: catalogs recorded in the lockfile, then the inline
|
|
1188
|
+
* declaration, then — only under {@link WorkspaceCatalogs.layerWithConfigDependencies}
|
|
1189
|
+
* — the config-dependency `pnpmfile.cjs` hooks, each layer winning per dependency
|
|
1190
|
+
* within a catalog. An unreadable or absent lockfile degrades to no lockfile
|
|
1191
|
+
* catalogs rather than failing (the inline declaration is the source of truth, the
|
|
1192
|
+
* lockfile a record of what was installed); a malformed inline source **fails
|
|
1193
|
+
* typed** with {@link CatalogAssemblyError}, because a silently-empty catalog read
|
|
1194
|
+
* is the "every dependency looks newly added" bug.
|
|
1195
|
+
*
|
|
1196
|
+
* Assembly is deferred to the first call and memoized success-only, matching
|
|
1197
|
+
* {@link WorkspaceDiscovery}.
|
|
1198
|
+
*
|
|
1199
|
+
* @public
|
|
1200
|
+
*/
|
|
1201
|
+
declare class WorkspaceCatalogs extends WorkspaceCatalogs_base {
|
|
1202
|
+
/** Builds the service. */
|
|
1203
|
+
static readonly make: (options?: WorkspaceCatalogsOptions) => Effect.Effect<WorkspaceCatalogsShape, never, WorkspaceRoot | LockfileReader | ConfigDependencyHooks | FileSystem.FileSystem | Path.Path>;
|
|
1204
|
+
/**
|
|
1205
|
+
* The live layer — the default, which **never executes config-dependency
|
|
1206
|
+
* code**: it wires {@link ConfigDependencyHooks.layerNoop}, whose hooks return
|
|
1207
|
+
* the inline-catalog seed untouched.
|
|
1208
|
+
*
|
|
1209
|
+
* @remarks
|
|
1210
|
+
* Parameterized, so it mints a fresh reference per call — bind it to a
|
|
1211
|
+
* `const` and reuse it, or layer memoization does not apply.
|
|
1212
|
+
*/
|
|
1213
|
+
static readonly layer: (options?: WorkspaceCatalogsOptions) => Layer.Layer<WorkspaceCatalogs, never, WorkspaceRoot | LockfileReader | FileSystem.FileSystem | Path.Path>;
|
|
1214
|
+
/**
|
|
1215
|
+
* The opt-in live layer that **does** replay config-dependency `pnpmfile.cjs`
|
|
1216
|
+
* hooks: it wires {@link ConfigDependencyHooks.layerLive}, which dynamically
|
|
1217
|
+
* imports and runs each config dependency's `updateConfig` in process.
|
|
1218
|
+
*
|
|
1219
|
+
* @remarks
|
|
1220
|
+
* Same output and requirement set as {@link WorkspaceCatalogs.layer} — the only
|
|
1221
|
+
* difference is that config-dependency code is executed. Use it deliberately;
|
|
1222
|
+
* the default catalog path stays free of any config-dependency execution.
|
|
1223
|
+
* Parameterized, so bind it to a `const` and reuse it.
|
|
1224
|
+
*/
|
|
1225
|
+
static readonly layerWithConfigDependencies: (options?: WorkspaceCatalogsOptions) => Layer.Layer<WorkspaceCatalogs, never, WorkspaceRoot | LockfileReader | FileSystem.FileSystem | Path.Path>;
|
|
1226
|
+
/**
|
|
1227
|
+
* The real implementation of `@effected/npm`'s `CatalogResolver` contract —
|
|
1228
|
+
* the one `@effected/package-json` declares but cannot fill.
|
|
1229
|
+
*
|
|
1230
|
+
* @remarks
|
|
1231
|
+
* `rangeOf` returns `Option.none()` for a dependency no catalog declares, per
|
|
1232
|
+
* the contract's convention; `DependencyResolutionError` is reserved for a
|
|
1233
|
+
* failure of the resolution *mechanism* — an unfindable workspace root, an
|
|
1234
|
+
* unreadable or malformed `pnpm-workspace.yaml`.
|
|
1235
|
+
*/
|
|
1236
|
+
static readonly catalogResolver: Layer.Layer<CatalogResolver, never, WorkspaceCatalogs>;
|
|
1237
|
+
}
|
|
1238
|
+
//#endregion
|
|
1239
|
+
//#region src/WorkspaceStateSnapshot.d.ts
|
|
1240
|
+
declare const PackageStateSnapshot_base: Schema.Class<PackageStateSnapshot, Schema.Struct<{
|
|
1241
|
+
/** The package name. */
|
|
1242
|
+
readonly name: Schema.NonEmptyString;
|
|
1243
|
+
/** The raw `version` string, as recorded at the captured moment. */
|
|
1244
|
+
readonly version: Schema.String;
|
|
1245
|
+
/** POSIX path relative to the workspace root; `"."` for the root package. */
|
|
1246
|
+
readonly relativePath: Schema.String;
|
|
1247
|
+
/** Production dependencies. */
|
|
1248
|
+
readonly dependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
1249
|
+
/** Development dependencies. */
|
|
1250
|
+
readonly devDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
1251
|
+
/** Peer dependencies. */
|
|
1252
|
+
readonly peerDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
1253
|
+
/** Optional dependencies. */
|
|
1254
|
+
readonly optionalDependencies: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.String>, never>>;
|
|
1255
|
+
}>, {}>;
|
|
1256
|
+
/**
|
|
1257
|
+
* One workspace member as captured in a {@link WorkspaceStateSnapshot} — the
|
|
1258
|
+
* serializable slice a snapshot diff reads: identity, version, location, and the
|
|
1259
|
+
* four dependency records.
|
|
1260
|
+
*
|
|
1261
|
+
* @remarks
|
|
1262
|
+
* Deliberately narrower than {@link WorkspacePackage}: a snapshot is a value to
|
|
1263
|
+
* store and diff, not a located member to act on, so it carries no absolute
|
|
1264
|
+
* paths, `publishConfig`, or `private` flag. The four records are keyed by the
|
|
1265
|
+
* standard manifest field names, which are exactly `@effected/npm`'s
|
|
1266
|
+
* `DependencyField` values.
|
|
1267
|
+
*
|
|
1268
|
+
* @public
|
|
1269
|
+
*/
|
|
1270
|
+
declare class PackageStateSnapshot extends PackageStateSnapshot_base {
|
|
1271
|
+
/**
|
|
1272
|
+
* Every dependency, merged across the four kinds.
|
|
1273
|
+
*
|
|
1274
|
+
* @remarks
|
|
1275
|
+
* Precedence on a name declared in several kinds runs
|
|
1276
|
+
* `dependencies` \> `devDependencies` \> `peerDependencies` \>
|
|
1277
|
+
* `optionalDependencies`.
|
|
1278
|
+
*/
|
|
1279
|
+
get allDependencies(): Record<string, string>;
|
|
1280
|
+
}
|
|
1281
|
+
declare const WorkspaceStateSnapshot_base: Schema.Class<WorkspaceStateSnapshot, Schema.Struct<{
|
|
1282
|
+
/** Every workspace package captured at this moment. */
|
|
1283
|
+
readonly packages: Schema.$Array<typeof PackageStateSnapshot>;
|
|
1284
|
+
/** The catalog set assembled at this moment. */
|
|
1285
|
+
readonly catalogs: typeof CatalogSet;
|
|
1286
|
+
}>, {}>;
|
|
1287
|
+
/**
|
|
1288
|
+
* The state of a whole workspace at one moment — its packages and its assembled
|
|
1289
|
+
* catalog set — as a serializable value.
|
|
1290
|
+
*
|
|
1291
|
+
* @remarks
|
|
1292
|
+
* Produced by `WorkspaceSnapshots.at` (a git ref, read with no checkout)
|
|
1293
|
+
* or `WorkspaceSnapshots.worktree` (the live tree). The lookup and
|
|
1294
|
+
* resolution surfaces (`versions`, `package`, `resolve`, the resolver layers)
|
|
1295
|
+
* are backed by `#private` indexes built lazily on first use and never encoded —
|
|
1296
|
+
* the `DependencyGraph` edge-index precedent.
|
|
1297
|
+
*
|
|
1298
|
+
* `resolve` and the resolver layers answer specifiers against THIS snapshot's
|
|
1299
|
+
* own captured state, so a consumer can ask "what did `catalog:` /
|
|
1300
|
+
* `workspace:*` mean as of that ref". An unmatched specifier is always
|
|
1301
|
+
* `Option.none()`, never an error.
|
|
1302
|
+
*
|
|
1303
|
+
* @example
|
|
1304
|
+
* ```ts
|
|
1305
|
+
* import { WorkspaceSnapshots } from "@effected/workspaces";
|
|
1306
|
+
* import { Effect } from "effect";
|
|
1307
|
+
*
|
|
1308
|
+
* const program = Effect.gen(function* () {
|
|
1309
|
+
* const snapshots = yield* WorkspaceSnapshots;
|
|
1310
|
+
* const before = yield* snapshots.at("origin/main");
|
|
1311
|
+
* return before.resolve("effect", "catalog:");
|
|
1312
|
+
* });
|
|
1313
|
+
* ```
|
|
1314
|
+
*
|
|
1315
|
+
* @public
|
|
1316
|
+
*/
|
|
1317
|
+
declare class WorkspaceStateSnapshot extends WorkspaceStateSnapshot_base {
|
|
1318
|
+
#private;
|
|
1319
|
+
/** Every captured package's name → version. Total; O(1) after the first call. */
|
|
1320
|
+
get versions(): ReadonlyMap<string, string>;
|
|
1321
|
+
/** A single captured package by name, or `Option.none()`. Total. */
|
|
1322
|
+
package(name: string): Option.Option<PackageStateSnapshot>;
|
|
1323
|
+
/**
|
|
1324
|
+
* The concrete range or version a specifier resolved to AS OF this snapshot.
|
|
1325
|
+
*
|
|
1326
|
+
* @remarks
|
|
1327
|
+
* The specifier is classified through `@effected/npm`'s
|
|
1328
|
+
* `DependencySpecifier.FromString` — never by prefix-sniffing.
|
|
1329
|
+
* A `workspace:` specifier resolves to the captured version of `dependency`; a
|
|
1330
|
+
* `catalog:` specifier resolves against the captured catalog set. Every other
|
|
1331
|
+
* form — a plain range, a dist-tag, a `file:`/git/url specifier, or an
|
|
1332
|
+
* unparseable string — is `Option.none()`, because there is no indirection to
|
|
1333
|
+
* resolve. Total.
|
|
1334
|
+
*
|
|
1335
|
+
* @param dependency - The dependency's package name (what `workspace:` /
|
|
1336
|
+
* `catalog:` resolve for).
|
|
1337
|
+
* @param specifier - The raw specifier string.
|
|
1338
|
+
*/
|
|
1339
|
+
resolve(dependency: string, specifier: string): Option.Option<string>;
|
|
1340
|
+
/**
|
|
1341
|
+
* A `CatalogResolver` layer implementing `@effected/npm`'s contract against
|
|
1342
|
+
* THIS snapshot's catalog set — so code written to the contract resolves
|
|
1343
|
+
* `catalog:` specifiers as of this ref. Built once per instance and cached, so
|
|
1344
|
+
* it memoizes by reference.
|
|
1345
|
+
*/
|
|
1346
|
+
get catalogResolver(): Layer.Layer<CatalogResolver>;
|
|
1347
|
+
/**
|
|
1348
|
+
* A `WorkspaceResolver` layer implementing `@effected/npm`'s contract against
|
|
1349
|
+
* THIS snapshot's captured versions — so code written to the contract resolves
|
|
1350
|
+
* `workspace:` specifiers as of this ref. Built once per instance and cached.
|
|
1351
|
+
*/
|
|
1352
|
+
get workspaceResolver(): Layer.Layer<WorkspaceResolver>;
|
|
1353
|
+
/** Both snapshot-scoped resolver layers merged. Built once per instance and cached. */
|
|
1354
|
+
get resolvers(): Layer.Layer<CatalogResolver | WorkspaceResolver>;
|
|
1355
|
+
}
|
|
1356
|
+
//#endregion
|
|
1357
|
+
//#region src/WorkspaceSnapshots.d.ts
|
|
1358
|
+
/**
|
|
1359
|
+
* Every failure `WorkspaceSnapshots.at` can surface: git's own typed
|
|
1360
|
+
* errors, a catalog-assembly failure from the inline config source at the ref,
|
|
1361
|
+
* or an unfindable workspace root.
|
|
1362
|
+
*
|
|
1363
|
+
* @remarks
|
|
1364
|
+
* Narrow by design. `at` reads through git and never enumerates the live
|
|
1365
|
+
* filesystem, so no `WorkspaceDiscoveryError` / `WorkspacePatternError` appears —
|
|
1366
|
+
* and a malformed *lockfile* at the ref degrades to no catalogs (a lockfile is a
|
|
1367
|
+
* record, not a source of truth), so only the inline source raises
|
|
1368
|
+
* {@link CatalogAssemblyError}.
|
|
1369
|
+
*
|
|
1370
|
+
* @public
|
|
1371
|
+
*/
|
|
1372
|
+
type WorkspaceSnapshotAtFailure = GitCommandError | NotARepositoryError | UnknownRefError | CatalogAssemblyError | WorkspaceRootNotFoundError;
|
|
1373
|
+
/**
|
|
1374
|
+
* Every failure `WorkspaceSnapshots.worktree` can surface: the discovery
|
|
1375
|
+
* failures plus a catalog-assembly failure.
|
|
1376
|
+
*
|
|
1377
|
+
* @remarks
|
|
1378
|
+
* `worktree` never invokes git — it reads the live tree over
|
|
1379
|
+
* {@link WorkspaceDiscovery} and {@link WorkspaceCatalogs} — so no git error is
|
|
1380
|
+
* reachable.
|
|
1381
|
+
*
|
|
1382
|
+
* @public
|
|
1383
|
+
*/
|
|
1384
|
+
type WorkspaceSnapshotWorktreeFailure = WorkspaceDiscoveryFailure | CatalogAssemblyError;
|
|
1385
|
+
/**
|
|
1386
|
+
* Options for the {@link WorkspaceSnapshots} layer.
|
|
1387
|
+
*
|
|
1388
|
+
* @public
|
|
1389
|
+
*/
|
|
1390
|
+
interface WorkspaceSnapshotsOptions {
|
|
1391
|
+
/**
|
|
1392
|
+
* The directory `at(ref)` resolves the workspace root from.
|
|
1393
|
+
*
|
|
1394
|
+
* @defaultValue `process.cwd()`, read lazily on first use inside
|
|
1395
|
+
* `Effect.suspend`, so a `process.chdir` between providing the layer and the
|
|
1396
|
+
* first call is honoured.
|
|
1397
|
+
*/
|
|
1398
|
+
readonly cwd?: string;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* The {@link WorkspaceSnapshots} service shape.
|
|
1402
|
+
*
|
|
1403
|
+
* @public
|
|
1404
|
+
*/
|
|
1405
|
+
interface WorkspaceSnapshotsShape {
|
|
1406
|
+
/** The workspace state at a git ref, read with no checkout. Cached per `(root, ref)`. */
|
|
1407
|
+
readonly at: (ref: string) => Effect.Effect<WorkspaceStateSnapshot, WorkspaceSnapshotAtFailure>;
|
|
1408
|
+
/** The live workspace state, over discovery and catalog assembly. Uncached. */
|
|
1409
|
+
readonly worktree: () => Effect.Effect<WorkspaceStateSnapshot, WorkspaceSnapshotWorktreeFailure>;
|
|
1410
|
+
}
|
|
1411
|
+
declare const WorkspaceSnapshots_base: Context.ServiceClass<WorkspaceSnapshots, "@effected/workspaces/WorkspaceSnapshots", WorkspaceSnapshotsShape>;
|
|
1412
|
+
/**
|
|
1413
|
+
* Reads workspace state at a git ref with no checkout, and the live worktree.
|
|
1414
|
+
*
|
|
1415
|
+
* @remarks
|
|
1416
|
+
* `at(ref)` is cached per `(resolved root, ref)` via
|
|
1417
|
+
* `Effect.cachedInvalidateWithTTL` at `Duration.infinity`, invalidated on any
|
|
1418
|
+
* non-success exit — never bare `Effect.cached`, which would memoize an
|
|
1419
|
+
* interrupt. A failed `at(ref)` init is therefore retried on the next call, not
|
|
1420
|
+
* memoized.
|
|
1421
|
+
*
|
|
1422
|
+
* @example
|
|
1423
|
+
* ```ts
|
|
1424
|
+
* import { WorkspaceSnapshots } from "@effected/workspaces";
|
|
1425
|
+
* import { Effect } from "effect";
|
|
1426
|
+
*
|
|
1427
|
+
* const program = Effect.gen(function* () {
|
|
1428
|
+
* const snapshots = yield* WorkspaceSnapshots;
|
|
1429
|
+
* const before = yield* snapshots.at("origin/main");
|
|
1430
|
+
* const after = yield* snapshots.worktree();
|
|
1431
|
+
* return { before: before.versions, after: after.versions };
|
|
1432
|
+
* });
|
|
1433
|
+
* ```
|
|
1434
|
+
*
|
|
1435
|
+
* @public
|
|
1436
|
+
*/
|
|
1437
|
+
declare class WorkspaceSnapshots extends WorkspaceSnapshots_base {
|
|
1438
|
+
/** Builds the service over `Git`, {@link WorkspaceRoot}, {@link WorkspaceDiscovery} and {@link WorkspaceCatalogs}. */
|
|
1439
|
+
static readonly make: (options?: WorkspaceSnapshotsOptions) => Effect.Effect<WorkspaceSnapshotsShape, never, Git | WorkspaceRoot | WorkspaceDiscovery | WorkspaceCatalogs>;
|
|
1440
|
+
/**
|
|
1441
|
+
* The live layer.
|
|
1442
|
+
*
|
|
1443
|
+
* @remarks
|
|
1444
|
+
* Parameterized, so it mints a fresh reference per call — bind it to a
|
|
1445
|
+
* `const` and reuse it, or layer memoization does not apply.
|
|
1446
|
+
*/
|
|
1447
|
+
static readonly layer: (options?: WorkspaceSnapshotsOptions) => Layer.Layer<WorkspaceSnapshots, never, Git | WorkspaceRoot | WorkspaceDiscovery | WorkspaceCatalogs>;
|
|
1448
|
+
}
|
|
1449
|
+
//#endregion
|
|
1450
|
+
//#region src/Workspaces.d.ts
|
|
1451
|
+
/**
|
|
1452
|
+
* Options shared by the composite layers.
|
|
1453
|
+
*
|
|
1454
|
+
* @public
|
|
1455
|
+
*/
|
|
1456
|
+
interface WorkspacesOptions {
|
|
1457
|
+
/**
|
|
1458
|
+
* The directory every root-consuming service resolves the workspace root
|
|
1459
|
+
* from — one explicit concern, applied uniformly.
|
|
1460
|
+
*
|
|
1461
|
+
* @defaultValue `process.cwd()`, read lazily on first use.
|
|
1462
|
+
*/
|
|
1463
|
+
readonly cwd?: string;
|
|
1464
|
+
/** Descent cap for segment-crossing `packages:` patterns. Defaults to 32. */
|
|
1465
|
+
readonly maxDepth?: number;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Every service the git-free composite layer provides.
|
|
1469
|
+
*
|
|
1470
|
+
* @public
|
|
1471
|
+
*/
|
|
1472
|
+
type WorkspacesServices = WorkspaceRoot | PackageManagerDetector | WorkspaceDiscovery | LockfileReader | WorkspaceCatalogs | PublishabilityDetector;
|
|
1473
|
+
/**
|
|
1474
|
+
* The composite layers.
|
|
1475
|
+
*
|
|
1476
|
+
* @public
|
|
1477
|
+
*/
|
|
1478
|
+
declare const Workspaces: {
|
|
1479
|
+
readonly layer: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices, never, FileSystem.FileSystem | Path.Path>;
|
|
1480
|
+
readonly layerWithConfigDependencies: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices, never, FileSystem.FileSystem | Path.Path>;
|
|
1481
|
+
readonly layerWithGit: (options?: WorkspacesOptions) => Layer.Layer<WorkspacesServices | ChangeDetector | WorkspaceSnapshots | Git, never, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
|
|
1482
|
+
readonly resolvers: Layer.Layer<CatalogResolver | WorkspaceResolver, never, WorkspaceCatalogs | WorkspaceDiscovery>;
|
|
1483
|
+
};
|
|
1484
|
+
//#endregion
|
|
1485
|
+
//#region src/WorkspacesSync.d.ts
|
|
1486
|
+
/**
|
|
1487
|
+
* The nearest workspace root at or above `cwd`, or `null`.
|
|
1488
|
+
*
|
|
1489
|
+
* @remarks
|
|
1490
|
+
* **Synchronous and Node-only.** The Effect surface is `WorkspaceRoot`; reach
|
|
1491
|
+
* for this one only where you genuinely cannot run an Effect — a Vitest config
|
|
1492
|
+
* being the motivating case.
|
|
1493
|
+
*
|
|
1494
|
+
* Markers match the async service exactly: a `pnpm-workspace.yaml`, or a
|
|
1495
|
+
* `package.json` carrying a `workspaces` field.
|
|
1496
|
+
*
|
|
1497
|
+
* @param cwd - Where to start the ascent. Defaults to `process.cwd()`.
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```ts
|
|
1501
|
+
* import { findWorkspaceRootSync } from "@effected/workspaces";
|
|
1502
|
+
*
|
|
1503
|
+
* const root = findWorkspaceRootSync();
|
|
1504
|
+
* ```
|
|
1505
|
+
*
|
|
1506
|
+
* @public
|
|
1507
|
+
*/
|
|
1508
|
+
declare const findWorkspaceRootSync: (cwd?: string) => string | null;
|
|
1509
|
+
/**
|
|
1510
|
+
* Options for {@link getWorkspacePackagesSync}.
|
|
1511
|
+
*
|
|
1512
|
+
* @public
|
|
1513
|
+
*/
|
|
1514
|
+
interface GetWorkspacePackagesSyncOptions {
|
|
1515
|
+
/**
|
|
1516
|
+
* Descent cap below a wildcard's enumeration prefix, mirroring
|
|
1517
|
+
* `WorkspaceDiscovery.layer({ maxDepth })`.
|
|
1518
|
+
*
|
|
1519
|
+
* @defaultValue 32
|
|
1520
|
+
*/
|
|
1521
|
+
readonly maxDepth?: number;
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Every workspace package under `root`, root package first.
|
|
1525
|
+
*
|
|
1526
|
+
* @remarks
|
|
1527
|
+
* **Synchronous and Node-only.** The Effect surface is `WorkspaceDiscovery`.
|
|
1528
|
+
*
|
|
1529
|
+
* Pattern semantics are not merely "shared" with the Effect enumerator — both
|
|
1530
|
+
* drive the **same traversal state machine** (`internal/traverse.ts`), so the
|
|
1531
|
+
* dequeue order, the depth rule, the visit budget and the prune list cannot
|
|
1532
|
+
* drift apart. A `packages/**` finds exactly the same packages here as there,
|
|
1533
|
+
* including at the depth boundary.
|
|
1534
|
+
*
|
|
1535
|
+
* The one deliberate difference is what happens at a bound: the Effect surface
|
|
1536
|
+
* fails typed (`depthExceeded` / `budgetExceeded`), while this one is **total**
|
|
1537
|
+
* and truncates. An unenumerable pattern or an unreadable manifest is skipped,
|
|
1538
|
+
* not raised — a function with no error channel should not pretend to have one,
|
|
1539
|
+
* and a Vitest config has nowhere to put a failure. Totality covers *data*, not
|
|
1540
|
+
* caller mistakes: a `maxDepth` that is not a positive integer throws, matching
|
|
1541
|
+
* the enumerator's defect.
|
|
1542
|
+
*
|
|
1543
|
+
* @param root - The workspace root, from {@link findWorkspaceRootSync}.
|
|
1544
|
+
* @param options - Traversal bounds; see {@link GetWorkspacePackagesSyncOptions}.
|
|
1545
|
+
*
|
|
1546
|
+
* @example
|
|
1547
|
+
* ```ts
|
|
1548
|
+
* import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
|
|
1549
|
+
*
|
|
1550
|
+
* const root = findWorkspaceRootSync();
|
|
1551
|
+
* const packages = root === null ? [] : getWorkspacePackagesSync(root);
|
|
1552
|
+
* ```
|
|
1553
|
+
*
|
|
1554
|
+
* @public
|
|
1555
|
+
*/
|
|
1556
|
+
declare const getWorkspacePackagesSync: (root: string, options?: GetWorkspacePackagesSyncOptions) => ReadonlyArray<WorkspacePackage>;
|
|
1557
|
+
//#endregion
|
|
1558
|
+
export { CatalogAssemblyError, type CatalogAssemblyFailure, CatalogSet, ChangeDetectionError, type ChangeDetectionFailure, ChangeDetectionOptions, ChangeDetector, type ChangeDetectorShape, ConfigDependencyHooks, type ConfigDependencyHooksShape, CyclicDependencyError, type DependencyDiff, DependencyGraph, DetectedPackageManager, type GetWorkspacePackagesSyncOptions, LockfileReadError, type LockfileReadFailure, LockfileReader, type LockfileReaderOptions, type LockfileReaderShape, PackageManagerDetectionError, type PackageManagerDetectionFailure, PackageManagerDetector, PackageManagerName, PackageNotFoundError, PackageStateSnapshot, PublishConfig, PublishTarget, PublishabilityDetector, WORKSPACE_MARKERS, WorkspaceCatalogs, type WorkspaceCatalogsOptions, type WorkspaceCatalogsShape, WorkspaceDiscovery, WorkspaceDiscoveryError, type WorkspaceDiscoveryFailure, type WorkspaceDiscoveryOptions, type WorkspaceDiscoveryShape, WorkspaceInfo, type WorkspaceLookupFailure, WorkspaceManifestError, WorkspacePackage, WorkspacePatternError, WorkspaceRoot, WorkspaceRootNotFoundError, type WorkspaceSnapshotAtFailure, type WorkspaceSnapshotWorktreeFailure, WorkspaceSnapshots, type WorkspaceSnapshotsOptions, type WorkspaceSnapshotsShape, WorkspaceStateSnapshot, Workspaces, type WorkspacesOptions, type WorkspacesServices, findWorkspaceRootSync, getWorkspacePackagesSync };
|
|
1559
|
+
//# sourceMappingURL=index.d.ts.map
|