@effected/workspaces 0.28.0 → 0.29.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/LockfileReader.js +5 -1
- package/PeerCheck.js +449 -36
- package/README.md +20 -5
- package/WorkspaceDiscovery.js +2 -1
- package/WorkspaceSnapshots.js +3 -3
- package/WorkspaceStateSnapshot.js +47 -30
- package/WorkspacesSync.js +11 -1
- package/index.d.ts +904 -742
- package/package.json +4 -4
package/WorkspaceDiscovery.js
CHANGED
|
@@ -548,7 +548,8 @@ var WorkspaceDiscovery = class WorkspaceDiscovery extends Context.Service()("@ef
|
|
|
548
548
|
const version = index.get(packageName);
|
|
549
549
|
return version === void 0 ? Effect.fail(new DependencyResolutionError({
|
|
550
550
|
specifier,
|
|
551
|
-
|
|
551
|
+
reason: "no-version",
|
|
552
|
+
cause: void 0
|
|
552
553
|
})) : Effect.succeed(Option.some(version));
|
|
553
554
|
}));
|
|
554
555
|
} };
|
package/WorkspaceSnapshots.js
CHANGED
|
@@ -52,10 +52,10 @@ const snapshotOf = (content, relativePath) => {
|
|
|
52
52
|
const parsed = parseJsonObject(content.value);
|
|
53
53
|
const name = parsed.name;
|
|
54
54
|
if (typeof name !== "string" || name.length === 0) return Option.none();
|
|
55
|
-
const version =
|
|
55
|
+
const version = parsed.version;
|
|
56
56
|
return Option.some(PackageStateSnapshot.make({
|
|
57
57
|
name,
|
|
58
|
-
version,
|
|
58
|
+
...typeof version === "string" && version !== "" ? { version } : {},
|
|
59
59
|
relativePath,
|
|
60
60
|
...isStringRecord(parsed.dependencies) ? { dependencies: parsed.dependencies } : {},
|
|
61
61
|
...isStringRecord(parsed.devDependencies) ? { devDependencies: parsed.devDependencies } : {},
|
|
@@ -233,7 +233,7 @@ var WorkspaceSnapshots = class WorkspaceSnapshots extends Context.Service()("@ef
|
|
|
233
233
|
const hookReplays = yield* catalogsService.hookReplays();
|
|
234
234
|
const snapshotPackages = packages.map((pkg) => PackageStateSnapshot.make({
|
|
235
235
|
name: pkg.name,
|
|
236
|
-
version: pkg.version
|
|
236
|
+
...pkg.version === void 0 ? {} : { version: pkg.version },
|
|
237
237
|
relativePath: pkg.relativePath,
|
|
238
238
|
dependencies: pkg.dependencies,
|
|
239
239
|
devDependencies: pkg.devDependencies,
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
import { unanimousVersionOf } from "./internal/importerVersions.js";
|
|
2
2
|
import { CatalogSet } from "./WorkspaceCatalogs.js";
|
|
3
|
-
import { Effect, Exit, Layer, Option, Schema } from "effect";
|
|
3
|
+
import { Effect, Exit, Layer, Option, Schema, SchemaTransformation } from "effect";
|
|
4
4
|
import { CatalogResolver, DependencyResolutionError, DependencySpecifier, WorkspaceResolver } from "@effected/npm";
|
|
5
5
|
|
|
6
6
|
//#region src/WorkspaceStateSnapshot.ts
|
|
7
7
|
const EMPTY = Object.freeze(Object.create(null));
|
|
8
8
|
const DependencyMap = Schema.Record(Schema.String, Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed(EMPTY)), Schema.withConstructorDefault(Effect.succeed(EMPTY)));
|
|
9
9
|
/**
|
|
10
|
+
* A snapshot's `version` field: absent when the manifest declared none, and
|
|
11
|
+
* never `""`.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* The Type side is a `NonEmptyString`, so `make` rejects `""` outright. The
|
|
15
|
+
* encoded side stays a plain optional string for one reason only: snapshots
|
|
16
|
+
* serialized while `""` was the "declared no version" sentinel must still
|
|
17
|
+
* decode, and they decode to the absent key they always meant — so an old
|
|
18
|
+
* stored value and a fresh capture of the same manifest compare equal.
|
|
19
|
+
*/
|
|
20
|
+
const SnapshotVersion = Schema.optionalKey(Schema.String).pipe(Schema.decodeTo(Schema.optionalKey(Schema.NonEmptyString), SchemaTransformation.transformOptional({
|
|
21
|
+
decode: (encoded) => Option.filter(encoded, (version) => version !== ""),
|
|
22
|
+
encode: (version) => version
|
|
23
|
+
})));
|
|
24
|
+
/**
|
|
10
25
|
* One workspace member as captured in a {@link WorkspaceStateSnapshot} — the
|
|
11
26
|
* serializable slice a snapshot diff reads: identity, version, location, and the
|
|
12
27
|
* four dependency records.
|
|
@@ -24,23 +39,24 @@ var PackageStateSnapshot = class extends Schema.Class("PackageStateSnapshot")({
|
|
|
24
39
|
/** The package name. */
|
|
25
40
|
name: Schema.NonEmptyString,
|
|
26
41
|
/**
|
|
27
|
-
* The raw `version` string, as recorded at the captured moment —
|
|
42
|
+
* The raw `version` string, as recorded at the captured moment — absent for
|
|
28
43
|
* a manifest that declared none.
|
|
29
44
|
*
|
|
30
45
|
* @remarks
|
|
31
|
-
* `WorkspacePackage.version` is
|
|
32
|
-
* ordinary pnpm shape
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* {@link WorkspaceStateSnapshot.
|
|
40
|
-
*
|
|
41
|
-
* `
|
|
46
|
+
* Optional exactly as `WorkspacePackage.version` is: a version-less member is
|
|
47
|
+
* an ordinary pnpm shape. Both capture paths — `WorkspaceSnapshots.at(ref)`
|
|
48
|
+
* and `WorkspaceSnapshots.worktree()` — omit the key for such a member, so
|
|
49
|
+
* the two sides of a diff agree without a placeholder. Never `""`: `make`
|
|
50
|
+
* rejects it, and a snapshot serialized when `""` was the "no version"
|
|
51
|
+
* sentinel decodes to the absent key.
|
|
52
|
+
*
|
|
53
|
+
* A version-less member is still a member: it appears in `packages` and
|
|
54
|
+
* answers {@link WorkspaceStateSnapshot.package}, but is absent from
|
|
55
|
+
* {@link WorkspaceStateSnapshot.versions}, resolves a `workspace:` specifier
|
|
56
|
+
* to `Option.none()`, and fails its snapshot-bound `WorkspaceResolver`'s
|
|
57
|
+
* `versionOf` typed.
|
|
42
58
|
*/
|
|
43
|
-
version:
|
|
59
|
+
version: SnapshotVersion,
|
|
44
60
|
/** POSIX path relative to the workspace root; `"."` for the root package. */
|
|
45
61
|
relativePath: Schema.String,
|
|
46
62
|
/** Production dependencies. */
|
|
@@ -166,7 +182,11 @@ var WorkspaceStateSnapshot = class WorkspaceStateSnapshot extends Schema.Class("
|
|
|
166
182
|
#workspaceResolver;
|
|
167
183
|
#resolvers;
|
|
168
184
|
#versions() {
|
|
169
|
-
if (this.#versionIndex === void 0)
|
|
185
|
+
if (this.#versionIndex === void 0) {
|
|
186
|
+
const index = /* @__PURE__ */ new Map();
|
|
187
|
+
for (const pkg of this.packages) if (pkg.version !== void 0) index.set(pkg.name, pkg.version);
|
|
188
|
+
this.#versionIndex = index;
|
|
189
|
+
}
|
|
170
190
|
return this.#versionIndex;
|
|
171
191
|
}
|
|
172
192
|
#packages() {
|
|
@@ -174,15 +194,13 @@ var WorkspaceStateSnapshot = class WorkspaceStateSnapshot extends Schema.Class("
|
|
|
174
194
|
return this.#packageIndex;
|
|
175
195
|
}
|
|
176
196
|
/**
|
|
177
|
-
* Every captured package's name → version
|
|
197
|
+
* Every captured package's name → version, for the packages that declared
|
|
198
|
+
* one. Total; O(1) after the first call.
|
|
178
199
|
*
|
|
179
200
|
* @remarks
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* "has a usable version". A caller reading a version out of this map owes
|
|
184
|
-
* the `""` check itself; {@link WorkspaceStateSnapshot.resolve} already
|
|
185
|
-
* makes it.
|
|
201
|
+
* A member whose manifest declared no version is **absent** from this map,
|
|
202
|
+
* so every value is a real version and presence answers "has a version",
|
|
203
|
+
* not membership — ask {@link WorkspaceStateSnapshot.package} for that.
|
|
186
204
|
*/
|
|
187
205
|
get versions() {
|
|
188
206
|
return this.#versions();
|
|
@@ -268,10 +286,7 @@ var WorkspaceStateSnapshot = class WorkspaceStateSnapshot extends Schema.Class("
|
|
|
268
286
|
const fromCatalogs = this.#catalogRange(dependency, classified.name);
|
|
269
287
|
return Option.isSome(fromCatalogs) ? fromCatalogs : onUnresolvedCatalog();
|
|
270
288
|
}
|
|
271
|
-
case "workspace":
|
|
272
|
-
const version = this.#versions().get(dependency);
|
|
273
|
-
return version === void 0 || version === "" ? Option.none() : Option.some(version);
|
|
274
|
-
}
|
|
289
|
+
case "workspace": return Option.fromUndefinedOr(this.#versions().get(dependency));
|
|
275
290
|
default: return Option.none();
|
|
276
291
|
}
|
|
277
292
|
}
|
|
@@ -422,11 +437,13 @@ var WorkspaceStateSnapshot = class WorkspaceStateSnapshot extends Schema.Class("
|
|
|
422
437
|
*/
|
|
423
438
|
get workspaceResolver() {
|
|
424
439
|
if (this.#workspaceResolver === void 0) this.#workspaceResolver = Layer.succeed(WorkspaceResolver, { versionOf: (packageName) => {
|
|
425
|
-
const
|
|
426
|
-
if (
|
|
427
|
-
|
|
440
|
+
const member = this.#packages().get(packageName);
|
|
441
|
+
if (member === void 0) return Effect.succeed(Option.none());
|
|
442
|
+
const version = member.version;
|
|
443
|
+
if (version === void 0) return Effect.fail(new DependencyResolutionError({
|
|
428
444
|
specifier: `workspace:${packageName}`,
|
|
429
|
-
|
|
445
|
+
reason: "no-version",
|
|
446
|
+
cause: void 0
|
|
430
447
|
}));
|
|
431
448
|
return Effect.succeed(Option.some(version));
|
|
432
449
|
} });
|
package/WorkspacesSync.js
CHANGED
|
@@ -120,9 +120,17 @@ const isPackage = (options, dir) => options.fileSystem.exists(options.path.join(
|
|
|
120
120
|
* Markers match the async service exactly: a `pnpm-workspace.yaml`, or a
|
|
121
121
|
* `package.json` carrying a `workspaces` field.
|
|
122
122
|
*
|
|
123
|
+
* The ascent is unbounded unless `options.stopAt` names a ceiling
|
|
124
|
+
* ({@link FindWorkspaceRootSyncOptions.stopAt}), with the Effect surface's
|
|
125
|
+
* semantics: inclusive, resolved at lookup time. Where `WorkspaceRoot.find`
|
|
126
|
+
* fails `WorkspaceRootNotFoundError` carrying the resolved ceiling, this
|
|
127
|
+
* returns `null` — the facade is total and has no error channel, and the
|
|
128
|
+
* caller already holds the ceiling it passed.
|
|
129
|
+
*
|
|
123
130
|
* @param cwd - Where to start the ascent (typically `process.cwd()`),
|
|
124
131
|
* matching the Effect layers' `{ cwd }` option.
|
|
125
|
-
* @param options - The consumer-supplied file and path operations
|
|
132
|
+
* @param options - The consumer-supplied file and path operations, plus an
|
|
133
|
+
* optional `stopAt` ceiling.
|
|
126
134
|
*
|
|
127
135
|
* @example
|
|
128
136
|
* ```ts
|
|
@@ -146,10 +154,12 @@ const isPackage = (options, dir) => options.fileSystem.exists(options.path.join(
|
|
|
146
154
|
const findWorkspaceRootSync = (cwd, options) => {
|
|
147
155
|
const { fileSystem, path } = options;
|
|
148
156
|
let current = path.resolve(cwd);
|
|
157
|
+
const ceiling = options.stopAt === void 0 ? void 0 : path.resolve(options.stopAt);
|
|
149
158
|
for (let depth = 0; depth < 32 * 8; depth++) {
|
|
150
159
|
if (fileSystem.exists(path.join(current, "pnpm-workspace.yaml"))) return current;
|
|
151
160
|
const manifest = readJson(fileSystem, path.join(current, "package.json"));
|
|
152
161
|
if (manifest?.workspaces !== void 0 && manifest.workspaces !== null) return current;
|
|
162
|
+
if (ceiling !== void 0 && current === ceiling) return null;
|
|
153
163
|
const parent = path.dirname(current);
|
|
154
164
|
if (parent === current) return null;
|
|
155
165
|
current = parent;
|