@effected/workspaces 0.30.4 → 0.32.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/DependencyGraph.js +17 -7
- package/DuplicateCheck.js +8 -7
- package/LayerPolicy.js +1 -1
- package/LockfileReader.js +4 -1
- package/PackageManagerName.js +3 -4
- package/PackedInstall.js +135 -15
- package/PeerCheck.js +6 -2
- package/Publishability.js +10 -14
- package/README.md +4 -4
- package/ReleaseTag.js +6 -5
- package/SourceBoundary.js +1 -1
- package/VersioningStrategy.js +14 -4
- package/WorkspaceCatalogs.js +3 -4
- package/WorkspaceDiscovery.js +7 -7
- package/WorkspacePackage.js +16 -12
- package/WorkspaceRoot.js +4 -6
- package/WorkspaceSnapshots.js +4 -1
- package/WorkspaceStateSnapshot.js +10 -16
- package/Workspaces.js +13 -17
- package/WorkspacesSync.js +1 -3
- package/index.d.ts +152 -146
- package/internal/importerVersions.js +1 -1
- package/node-sync.d.ts +2 -0
- package/package.json +12 -12
- package/testing.d.ts +179 -47
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Strip pnpm's peer-disambiguation suffix from a recorded importer version.
|
|
4
4
|
*
|
|
5
5
|
* pnpm records an importer version as the resolved version followed by the peer
|
|
6
|
-
* context it was resolved under — `4.0.0
|
|
6
|
+
* context it was resolved under — `4.0.0(effect@4.0.0)(ioredis@5.11.1(supports-color@8.1.1))`.
|
|
7
7
|
* `@effected/lockfiles` stores that string verbatim (its `packages:` key parser
|
|
8
8
|
* strips the suffix; the importer entries deliberately keep it), so the raw
|
|
9
9
|
* value must never reach a consumer's dependency table — it would render the
|
package/node-sync.d.ts
CHANGED
|
@@ -92,7 +92,9 @@ interface SyncDirectoryEntry {
|
|
|
92
92
|
* satisfies it verbatim:
|
|
93
93
|
*
|
|
94
94
|
* ```ts
|
|
95
|
+
* import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
95
96
|
* import * as path from "node:path";
|
|
97
|
+
* import type { WorkspacesSyncOptions } from "@effected/workspaces";
|
|
96
98
|
*
|
|
97
99
|
* const options: WorkspacesSyncOptions = {
|
|
98
100
|
* fileSystem: { exists: existsSync, readFile: (p) => readFileSync(p, "utf8"), readDirectory: (p) => readdirSync(p), isDirectory: (p) => statSync(p).isDirectory() },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/workspaces",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Monorepo workspace tooling as Effect services — root discovery, package enumeration, the dependency graph, package-manager detection, pnpm catalog resolution, lockfile IO and git-based change detection.",
|
|
6
6
|
"keywords": [
|
|
@@ -51,23 +51,23 @@
|
|
|
51
51
|
"./package.json": "./package.json"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@effected/commands": "^0.
|
|
55
|
-
"@effected/git": "^0.
|
|
56
|
-
"@effected/glob": "^0.
|
|
57
|
-
"@effected/jsonc": "^0.
|
|
58
|
-
"@effected/lockfiles": "^0.
|
|
59
|
-
"@effected/npm": "^0.
|
|
60
|
-
"@effected/package-json": "^0.
|
|
61
|
-
"@effected/semver": "^0.
|
|
62
|
-
"@effected/walker": "^0.
|
|
63
|
-
"@effected/yaml": "^0.
|
|
54
|
+
"@effected/commands": "^0.11.0",
|
|
55
|
+
"@effected/git": "^0.20.0",
|
|
56
|
+
"@effected/glob": "^0.10.0",
|
|
57
|
+
"@effected/jsonc": "^0.15.1",
|
|
58
|
+
"@effected/lockfiles": "^0.15.0",
|
|
59
|
+
"@effected/npm": "^0.20.0",
|
|
60
|
+
"@effected/package-json": "^0.20.0",
|
|
61
|
+
"@effected/semver": "^0.11.0",
|
|
62
|
+
"@effected/walker": "^0.15.0",
|
|
63
|
+
"@effected/yaml": "^0.19.1",
|
|
64
64
|
"@pnpm/catalogs.config": "^1100.0.5",
|
|
65
65
|
"@pnpm/catalogs.protocol-parser": "^1100.0.0",
|
|
66
66
|
"@pnpm/catalogs.resolver": "^1100.0.0",
|
|
67
67
|
"@pnpm/catalogs.types": "^1100.0.0"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"effect": "4.0.0
|
|
70
|
+
"effect": "^4.0.0"
|
|
71
71
|
},
|
|
72
72
|
"engines": {
|
|
73
73
|
"node": ">=24.11.0"
|
package/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DependencyField, WorkspaceResolver } from "@effected/npm";
|
|
2
|
-
import { Context, Duration, Effect, FileSystem, Layer, Option, Path, Schema } from "effect";
|
|
2
|
+
import { Context, Duration, Effect, FileSystem, Layer, Option, Path, PlatformError, Schema, Stream } from "effect";
|
|
3
3
|
import { GlobPattern } from "@effected/glob";
|
|
4
4
|
import { WorkspaceManifest } from "@effected/lockfiles";
|
|
5
5
|
import { Package } from "@effected/package-json";
|
|
@@ -57,7 +57,7 @@ declare const LayerPolicy_base: Schema.Class<LayerPolicy, Schema.Struct<{
|
|
|
57
57
|
* message names every such key. A typo on an optional key would otherwise be
|
|
58
58
|
* silently dropped: `requiredEdge` would remove the non-vacuity guard and
|
|
59
59
|
* leave the report green. `$schema` is always accepted. A file that carries
|
|
60
|
-
* keys of its own, such as
|
|
60
|
+
* keys of its own, such as a `harness` block, passes them in `allowKeys`.
|
|
61
61
|
*
|
|
62
62
|
* @example
|
|
63
63
|
* ```ts
|
|
@@ -136,7 +136,7 @@ interface DependencyDiff {
|
|
|
136
136
|
readonly added: Record<string, string>;
|
|
137
137
|
/** Present in the other, absent from the receiver. */
|
|
138
138
|
readonly removed: Record<string, string>;
|
|
139
|
-
/** Present in both at different specifiers. */
|
|
139
|
+
/** Present in both at different specifiers: `from` is the other package's, `to` the receiver's. */
|
|
140
140
|
readonly changed: Record<string, {
|
|
141
141
|
readonly from: string;
|
|
142
142
|
readonly to: string;
|
|
@@ -196,13 +196,9 @@ declare const WorkspacePackage_base: Schema.Class<WorkspacePackage, Schema.Struc
|
|
|
196
196
|
* Absolute path to the workspace root this package was discovered under.
|
|
197
197
|
*
|
|
198
198
|
* @remarks
|
|
199
|
-
* Carried, not derived
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* root arithmetic (counting `relativePath` segments and re-ascending that
|
|
203
|
-
* many `..`). That reconstruction is exact only while `path` and
|
|
204
|
-
* `relativePath` agree, and it re-derives something the kit never had to
|
|
205
|
-
* lose.
|
|
199
|
+
* Carried, not derived: `WorkspaceDiscovery` resolves the root before
|
|
200
|
+
* enumerating, so every package arrives with it and consumers need no
|
|
201
|
+
* per-package root arithmetic over `relativePath`.
|
|
206
202
|
*
|
|
207
203
|
* For the root package this equals `path`, and `relativePath` is `"."`.
|
|
208
204
|
*/
|
|
@@ -229,8 +225,7 @@ declare const WorkspacePackage_base: Schema.Class<WorkspacePackage, Schema.Struc
|
|
|
229
225
|
* validated beyond being a record. For the strict typed model use
|
|
230
226
|
* `manifest()`, which deliberately **re-reads** the file — a point-in-time
|
|
231
227
|
* refresh this captured record cannot provide. Defaults to `{}` for
|
|
232
|
-
*
|
|
233
|
-
* field.
|
|
228
|
+
* values constructed or decoded without the field.
|
|
234
229
|
*/
|
|
235
230
|
readonly manifestRecord: Schema.withConstructorDefault<Schema.withDecodingDefaultKey<Schema.$Record<Schema.String, Schema.Unknown>, never>>;
|
|
236
231
|
}>, {}>;
|
|
@@ -293,8 +288,8 @@ export declare class WorkspacePackage extends WorkspacePackage_base {
|
|
|
293
288
|
/** The declared specifier for `name`, searched across all four kinds. */
|
|
294
289
|
dependencyVersion(name: string): Option.Option<string>;
|
|
295
290
|
/**
|
|
296
|
-
* Whether any dependency name
|
|
297
|
-
*
|
|
291
|
+
* Whether any dependency name (across all four kinds) matches the glob
|
|
292
|
+
* `pattern`, using `@effected/glob`.
|
|
298
293
|
*
|
|
299
294
|
* @remarks
|
|
300
295
|
* A `GlobPattern` is total and free to test. A `string` is compiled on every
|
|
@@ -307,7 +302,12 @@ export declare class WorkspacePackage extends WorkspacePackage_base {
|
|
|
307
302
|
* @param pattern - A compiled pattern, or a source string to compile.
|
|
308
303
|
*/
|
|
309
304
|
matchesDependency(pattern: GlobPattern | string): boolean;
|
|
310
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* Compare this package's dependencies against `other`'s, treating `other` as
|
|
307
|
+
* the baseline: what this package added, removed or re-specified.
|
|
308
|
+
*
|
|
309
|
+
* @param other - The package to compare against.
|
|
310
|
+
*/
|
|
311
311
|
dependencyDiff(other: WorkspacePackage): DependencyDiff;
|
|
312
312
|
/**
|
|
313
313
|
* Project to `@effected/lockfiles`' `WorkspaceManifest` — the input shape of
|
|
@@ -318,6 +318,10 @@ export declare class WorkspacePackage extends WorkspacePackage_base {
|
|
|
318
318
|
* Read and decode this package's `package.json` into the strict
|
|
319
319
|
* `@effected/package-json` `Package` model — the bridge from the
|
|
320
320
|
* tolerant discovery projection to the fully typed manifest.
|
|
321
|
+
*
|
|
322
|
+
* @remarks
|
|
323
|
+
* Fails with {@link WorkspaceManifestError} (`kind: "read"` or `"decode"`) and
|
|
324
|
+
* requires core `FileSystem`.
|
|
321
325
|
*/
|
|
322
326
|
static readonly manifest: (self: WorkspacePackage) => Effect.Effect<Package, WorkspaceManifestError, FileSystem.FileSystem>;
|
|
323
327
|
/** Instance form of `WorkspacePackage.manifest`. */
|
|
@@ -462,12 +466,10 @@ export declare class WorkspaceRoot extends WorkspaceRoot_base {
|
|
|
462
466
|
* A test double resolving every `find` to `root`, with no filesystem.
|
|
463
467
|
*
|
|
464
468
|
* @remarks
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
* call pass under test and fail against the live service, which is the
|
|
470
|
-
* failure mode the option exists to catch. A `root` above the ceiling fails
|
|
469
|
+
* Stands in for a hand-written `Layer.succeed` over a `find` that ignores its
|
|
470
|
+
* arguments. Unlike that, this double **honours `stopAt`**: a `find` that
|
|
471
|
+
* ignores the ceiling makes a bounded call pass under test and fail against
|
|
472
|
+
* the live service, which is the failure mode the option exists to catch. A `root` above the ceiling fails
|
|
471
473
|
* here exactly as it would live, with the same
|
|
472
474
|
* {@link WorkspaceRootNotFoundError}.
|
|
473
475
|
*
|
|
@@ -541,7 +543,7 @@ declare const WorkspaceDiscoveryError_base: Schema.Class<WorkspaceDiscoveryError
|
|
|
541
543
|
* A manifest with no `version` is NOT a failure: pnpm accepts a version-less
|
|
542
544
|
* private package and a private monorepo root without one is the ordinary
|
|
543
545
|
* shape, so the member is discovered with `WorkspacePackage.version` absent.
|
|
544
|
-
*
|
|
546
|
+
* Only ABSENCE is tolerated: a
|
|
545
547
|
* `version` that is present but not a string — or present and `""`, which pnpm
|
|
546
548
|
* never wrote and which would resolve `workspace:^` to a bare `"^"` — is the
|
|
547
549
|
* manifest's shape being wrong and reports `invalidShape`.
|
|
@@ -650,11 +652,10 @@ interface WorkspaceDiscoveryOptions {
|
|
|
650
652
|
* `importerMap`, `getPackage`, `resolveFile`, `resolveFiles`). The per-call
|
|
651
653
|
* `infoIn`, `listPackagesIn` and `refreshIn` resolve from an arbitrary
|
|
652
654
|
* directory the caller names, which a single layer-level ceiling cannot
|
|
653
|
-
* sensibly bound, so they ascend unbounded
|
|
655
|
+
* sensibly bound, so they ascend unbounded.
|
|
654
656
|
*
|
|
655
657
|
* `LockfileReader`, `WorkspaceCatalogs` and `WorkspaceSnapshots` each
|
|
656
|
-
* take the same option; give them the same
|
|
657
|
-
* value when wiring by hand, or let a `Workspaces.*` composite forward one
|
|
658
|
+
* take the same option; give them the same value when wiring by hand, or let a `Workspaces.*` composite forward one
|
|
658
659
|
* `stopAt` to all of them, so no service adopts a root another refused.
|
|
659
660
|
*
|
|
660
661
|
* @defaultValue no ceiling — the ascent runs to the filesystem root.
|
|
@@ -751,11 +752,9 @@ declare const WorkspaceDiscovery_base: Context.ServiceClass<WorkspaceDiscovery,
|
|
|
751
752
|
* the lifetime of the layer. A Vitest reporter that builds the layer per call
|
|
752
753
|
* site and never queries it pays nothing.
|
|
753
754
|
*
|
|
754
|
-
* The memo is **success-only
|
|
755
|
-
*
|
|
756
|
-
*
|
|
757
|
-
* channel. A failure or interrupt is therefore retried on the next call, which
|
|
758
|
-
* is a deliberate behaviour change from the v3 library.
|
|
755
|
+
* The memo is **success-only**: a failure or interrupt is not cached, so an
|
|
756
|
+
* init interrupted by an unrelated timeout cannot brick the layer, and the next
|
|
757
|
+
* call retries.
|
|
759
758
|
*
|
|
760
759
|
* @example
|
|
761
760
|
* ```ts
|
|
@@ -778,12 +777,14 @@ export declare class WorkspaceDiscovery extends WorkspaceDiscovery_base {
|
|
|
778
777
|
*/
|
|
779
778
|
static readonly make: (options?: WorkspaceDiscoveryOptions) => Effect.Effect<WorkspaceDiscoveryShape, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
|
|
780
779
|
/**
|
|
781
|
-
* The live layer.
|
|
780
|
+
* The live layer, discovering the workspace from `options.cwd`.
|
|
782
781
|
*
|
|
783
782
|
* @remarks
|
|
784
783
|
* A parameterized layer factory mints a **fresh reference per call**, and
|
|
785
784
|
* layers memoize by reference — bind the result to a `const` and reuse it
|
|
786
785
|
* rather than calling `layer(...)` at each composition site.
|
|
786
|
+
*
|
|
787
|
+
* @param options - Root resolution and enumeration bounds.
|
|
787
788
|
*/
|
|
788
789
|
static readonly layer: (options?: WorkspaceDiscoveryOptions) => Layer.Layer<WorkspaceDiscovery, never, WorkspaceRoot | FileSystem.FileSystem | Path.Path>;
|
|
789
790
|
/**
|
|
@@ -894,12 +895,12 @@ export declare class WorkspaceDiscovery extends WorkspaceDiscovery_base {
|
|
|
894
895
|
* @remarks
|
|
895
896
|
* `{ directory }` runs `npm pack` in that subdirectory of each package, whose
|
|
896
897
|
* manifest must already be publish-ready. The default,
|
|
897
|
-
* `{ directory: "dist/prod/npm/pkg" }`, is
|
|
898
|
+
* `{ directory: "dist/prod/npm/pkg" }`, is `@savvy-web/bundler`'s prod npm
|
|
898
899
|
* output: the same file list a release publishes.
|
|
899
900
|
*
|
|
900
901
|
* `"source"` runs `pnpm pack` in the package directory: pnpm honours
|
|
901
902
|
* `publishConfig.directory` and rewrites `workspace:` and `catalog:`
|
|
902
|
-
* specifiers. Two costs. Under
|
|
903
|
+
* specifiers. Two costs. Under `@savvy-web/bundler`, `publishConfig.directory`
|
|
903
904
|
* names the DEV build, so source mode proves the dev artifact, not the
|
|
904
905
|
* published one. And pnpm can rewrite a `workspace:` specifier only in a
|
|
905
906
|
* workspace that has been `pnpm install`ed: in a never-installed one the pack
|
|
@@ -937,10 +938,10 @@ interface PackedInstallClosureOptions {
|
|
|
937
938
|
* `.tgz`, with or without a `file:` prefix.
|
|
938
939
|
*
|
|
939
940
|
* @remarks
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
943
|
-
* publish-ready (for
|
|
941
|
+
* For a closure member that imports a surface of a dependency existing
|
|
942
|
+
* only in a sibling checkout's unreleased build, which the registry's copy
|
|
943
|
+
* lacks. A directory is `npm pack`ed, so it must be
|
|
944
|
+
* publish-ready (for a package built by `@savvy-web/bundler`, its
|
|
944
945
|
* `dist/prod/npm/pkg`); a `.tgz` is used as it is. Either way the packed
|
|
945
946
|
* manifest must be named as its key, carry no specifier only a workspace
|
|
946
947
|
* could resolve, and it joins `PackedInstallResult.tarballs`. Each
|
|
@@ -957,9 +958,9 @@ interface PackedInstallClosureOptions {
|
|
|
957
958
|
readonly overrides?: Readonly<Record<string, string>> | undefined;
|
|
958
959
|
/**
|
|
959
960
|
* Also read the workspace root's `pnpm-workspace.yaml` and take every
|
|
960
|
-
* `overrides:` entry of the
|
|
961
|
-
*
|
|
962
|
-
*
|
|
961
|
+
* `overrides:` entry of the link shape `"@scope/name": "file:<dir>"` as if
|
|
962
|
+
* passed through `overrides`: the linked sibling builds the workspace itself
|
|
963
|
+
* installs. Entries that are not `file:`, or
|
|
963
964
|
* whose key carries a selector (`a>b`, `a@1`), are left out. A root with
|
|
964
965
|
* no readable `pnpm-workspace.yaml`, or one that is not YAML, fails
|
|
965
966
|
* `InvalidOverride`.
|
|
@@ -1029,7 +1030,12 @@ interface PackedInstallOptions extends PackedInstallClosureOptions {
|
|
|
1029
1030
|
* `false`, so sharing is an explicit choice.
|
|
1030
1031
|
*/
|
|
1031
1032
|
readonly allowSharedBins?: boolean | undefined;
|
|
1032
|
-
/**
|
|
1033
|
+
/**
|
|
1034
|
+
* The environment for every spawn: pass `process.env` from the test file, the edge that supplies the host
|
|
1035
|
+
* environment. It is taken whole because the parent manager's context is stripped by prefix (`npm_*`,
|
|
1036
|
+
* `pnpm_config_*`, `yarn_*`), which `Config`, reading keys by name, cannot enumerate; read single keys such as
|
|
1037
|
+
* `CI` through `Config`.
|
|
1038
|
+
*/
|
|
1033
1039
|
readonly env: Readonly<Record<string, string | undefined>>;
|
|
1034
1040
|
/**
|
|
1035
1041
|
* Extra consumer dependencies, name to range or `file:` tarball spec.
|
|
@@ -1106,6 +1112,22 @@ interface BinCommandOptions {
|
|
|
1106
1112
|
interface RunBinOptions extends BinCommandOptions {
|
|
1107
1113
|
/** Ceiling on the run. Defaults to one minute. Expiry fails `BinFailed` with a message naming the bin and this duration. */
|
|
1108
1114
|
readonly timeout?: Duration.Input | undefined;
|
|
1115
|
+
/**
|
|
1116
|
+
* What to write to the bin's stdin, which is then closed: a string (UTF-8
|
|
1117
|
+
* encoded), bytes, or a byte stream for input that must arrive in pieces,
|
|
1118
|
+
* such as a framed LSP session.
|
|
1119
|
+
*
|
|
1120
|
+
* @remarks
|
|
1121
|
+
* Omitted or `""`, the bin's stdin is the null device: it reads end of
|
|
1122
|
+
* input immediately, never an open pipe, so a bin that reads stdin exits
|
|
1123
|
+
* instead of hanging until the ceiling. Empty bytes and an empty stream
|
|
1124
|
+
* are sent as given: the bin sees an ended, empty input. A bin that answers
|
|
1125
|
+
* only after the input is complete is driven by this option; one that must
|
|
1126
|
+
* be interleaved with its output is driven through
|
|
1127
|
+
* {@link InstalledConsumer.command} or {@link InstalledConsumer.carrierCommand},
|
|
1128
|
+
* which leave stdin open.
|
|
1129
|
+
*/
|
|
1130
|
+
readonly stdin?: string | Uint8Array | Stream.Stream<Uint8Array, PlatformError.PlatformError> | undefined;
|
|
1109
1131
|
}
|
|
1110
1132
|
/**
|
|
1111
1133
|
* Which installed package a `node_modules/.bin` symlink resolves into.
|
|
@@ -1208,7 +1230,9 @@ export declare class InstalledConsumer extends InstalledConsumer_base {
|
|
|
1208
1230
|
* Run the installed bin `name` to completion and collect what it wrote.
|
|
1209
1231
|
*
|
|
1210
1232
|
* @remarks
|
|
1211
|
-
* Spawns {@link InstalledConsumer.command} with stdin
|
|
1233
|
+
* Spawns {@link InstalledConsumer.command} with `options.stdin` as its
|
|
1234
|
+
* input (the null device when omitted, so a bin never waits on an open
|
|
1235
|
+
* pipe): the bin
|
|
1212
1236
|
* from the consumer's directory, under the install's scrubbed environment
|
|
1213
1237
|
* with `options.env` layered over it after the scrub, and nothing
|
|
1214
1238
|
* inherited beyond that. A
|
|
@@ -1220,7 +1244,7 @@ export declare class InstalledConsumer extends InstalledConsumer_base {
|
|
|
1220
1244
|
*
|
|
1221
1245
|
* @param name - The bin, as named in `node_modules/.bin`.
|
|
1222
1246
|
* @param args - Its arguments.
|
|
1223
|
-
* @param options - Extra environment, working directory and
|
|
1247
|
+
* @param options - Extra environment, working directory, ceiling and stdin.
|
|
1224
1248
|
*/
|
|
1225
1249
|
runBin(name: string, args?: ReadonlyArray<string>, options?: RunBinOptions): Effect.Effect<CommandOutput, PackedInstallError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
1226
1250
|
/**
|
|
@@ -1260,7 +1284,8 @@ export declare class InstalledConsumer extends InstalledConsumer_base {
|
|
|
1260
1284
|
* the `node_modules/.bin` slot.
|
|
1261
1285
|
*
|
|
1262
1286
|
* @remarks
|
|
1263
|
-
* Spawns {@link InstalledConsumer.carrierCommand} with stdin
|
|
1287
|
+
* Spawns {@link InstalledConsumer.carrierCommand} with `options.stdin` as
|
|
1288
|
+
* its input (the null device when omitted), and
|
|
1264
1289
|
* reports as {@link InstalledConsumer.runBin} does: a non-zero exit is a
|
|
1265
1290
|
* result, and a bin that cannot spawn or outlives `options.timeout` (one
|
|
1266
1291
|
* minute by default) fails `BinFailed`. Use it beside `runBin` under
|
|
@@ -1271,7 +1296,7 @@ export declare class InstalledConsumer extends InstalledConsumer_base {
|
|
|
1271
1296
|
*
|
|
1272
1297
|
* @param name - The bin, as the carrier's `bin` map names it.
|
|
1273
1298
|
* @param args - Its arguments.
|
|
1274
|
-
* @param options - Extra environment, working directory and
|
|
1299
|
+
* @param options - Extra environment, working directory, ceiling and stdin.
|
|
1275
1300
|
*/
|
|
1276
1301
|
runCarrierBin(name: string, args?: ReadonlyArray<string>, options?: RunBinOptions): Effect.Effect<CommandOutput, PackedInstallError, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
|
|
1277
1302
|
}
|
|
@@ -1322,6 +1347,43 @@ interface PackedInstallBudget {
|
|
|
1322
1347
|
*/
|
|
1323
1348
|
readonly perConsumer?: Duration.Input | undefined;
|
|
1324
1349
|
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Options for {@link PackedInstall.preflight}: the run's closure and pack
|
|
1352
|
+
* source, so the check answers for exactly the run those options describe.
|
|
1353
|
+
*
|
|
1354
|
+
* @public
|
|
1355
|
+
*/
|
|
1356
|
+
interface PackedInstallPreflightOptions extends PackedInstallClosureOptions {
|
|
1357
|
+
/** The carrier, as the run's `carrier`. */
|
|
1358
|
+
readonly carrier: string;
|
|
1359
|
+
/** Where the run packs from; defaults as the run's does, to `{ directory: "dist/prod/npm/pkg" }`. */
|
|
1360
|
+
readonly packFrom?: PackSource | undefined;
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Whether the pack source a run needs is on disk.
|
|
1364
|
+
*
|
|
1365
|
+
* @public
|
|
1366
|
+
*/
|
|
1367
|
+
interface PackedInstallPreflight {
|
|
1368
|
+
/** `true` when every package the run packs has its pack source in place. */
|
|
1369
|
+
readonly ready: boolean;
|
|
1370
|
+
/** The absolute `package.json` paths that do not exist, in pack order; empty exactly when `ready`. */
|
|
1371
|
+
readonly missing: ReadonlyArray<string>;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* What a test suite should do about a {@link PackedInstallPreflight}.
|
|
1375
|
+
*
|
|
1376
|
+
* @public
|
|
1377
|
+
*/
|
|
1378
|
+
interface PackedInstallGate {
|
|
1379
|
+
/**
|
|
1380
|
+
* `"run"` when the pack source is there; `"skip"` when it is missing and
|
|
1381
|
+
* the run is not under CI; `"fail"` when it is missing under CI.
|
|
1382
|
+
*/
|
|
1383
|
+
readonly action: "run" | "skip" | "fail";
|
|
1384
|
+
/** Why, naming the missing paths and the build to run. Empty when `action` is `"run"`. */
|
|
1385
|
+
readonly message: string;
|
|
1386
|
+
}
|
|
1325
1387
|
/**
|
|
1326
1388
|
* Prove a carrier's bins reach a consumer that is not part of the workspace,
|
|
1327
1389
|
* once per available package manager.
|
|
@@ -1489,6 +1551,76 @@ export declare class PackedInstall {
|
|
|
1489
1551
|
static readonly timeoutBudgetFor: (options: PackedInstallOptions, extra?: {
|
|
1490
1552
|
readonly perConsumer?: Duration.Input | undefined;
|
|
1491
1553
|
}) => Effect.Effect<Duration.Duration, PackedInstallError, WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
|
|
1554
|
+
/**
|
|
1555
|
+
* Whether the pack source {@link PackedInstall.run} would read is on disk,
|
|
1556
|
+
* before any package manager is spawned.
|
|
1557
|
+
*
|
|
1558
|
+
* @remarks
|
|
1559
|
+
* Plans the closure as the run does (`PackedInstall.closure`'s planner) and
|
|
1560
|
+
* checks the `package.json` of each closure package under `packFrom`
|
|
1561
|
+
* (default `{ directory: "dist/prod/npm/pkg" }`), the same file whose
|
|
1562
|
+
* absence makes the run fail `PackSourceMissing`. Under `packFrom: "source"`
|
|
1563
|
+
* the packer builds nothing of its own, so nothing is checked and the
|
|
1564
|
+
* result is ready. A package a bundler's dev build produced is no
|
|
1565
|
+
* substitute: the prod output exists only after the prod build, which a
|
|
1566
|
+
* test job's usual `build:dev` pre-step does not run. Pair it with
|
|
1567
|
+
* {@link PackedInstall.gate} to skip locally and fail under CI.
|
|
1568
|
+
*
|
|
1569
|
+
* Fails as `closure` does, plus `Io` when a path cannot be inspected.
|
|
1570
|
+
*
|
|
1571
|
+
* @example
|
|
1572
|
+
* ```ts
|
|
1573
|
+
* import { NodeServices } from "@effect/platform-node";
|
|
1574
|
+
* import { Workspaces } from "@effected/workspaces";
|
|
1575
|
+
* import { PackedInstall } from "@effected/workspaces/testing";
|
|
1576
|
+
* import { Effect, Layer } from "effect";
|
|
1577
|
+
*
|
|
1578
|
+
* const Live = Workspaces.layer({ cwd: "/repo" }).pipe(Layer.provideMerge(NodeServices.layer));
|
|
1579
|
+
* const preflight = await Effect.runPromise(
|
|
1580
|
+
* PackedInstall.preflight({ carrier: "my-tool", closure: "auto" }).pipe(Effect.provide(Live)),
|
|
1581
|
+
* );
|
|
1582
|
+
* console.log(preflight.ready, preflight.missing);
|
|
1583
|
+
* ```
|
|
1584
|
+
*
|
|
1585
|
+
* @param options - The run's carrier, closure, overrides and pack source.
|
|
1586
|
+
*/
|
|
1587
|
+
static readonly preflight: (options: PackedInstallPreflightOptions) => Effect.Effect<PackedInstallPreflight, PackedInstallError, WorkspaceDiscovery | FileSystem.FileSystem | Path.Path>;
|
|
1588
|
+
/**
|
|
1589
|
+
* Turns a {@link PackedInstallPreflight} into the suite's decision: run,
|
|
1590
|
+
* skip locally, or fail under CI.
|
|
1591
|
+
*
|
|
1592
|
+
* @remarks
|
|
1593
|
+
* `CI` is read through `Config`, so the ambient `ConfigProvider` decides —
|
|
1594
|
+
* the process environment at a test file's top level, and whatever a test
|
|
1595
|
+
* provides in a test; nothing here reads `process`. `CI` counts as set when
|
|
1596
|
+
* it is present and not `""`, `"0"` or `"false"` (case-insensitive), and an
|
|
1597
|
+
* unreadable `CI` counts as unset. Ready is always `"run"`;
|
|
1598
|
+
* missing is `"skip"` off CI and `"fail"` on it, so a CI job that never ran
|
|
1599
|
+
* the prod build cannot pass by silently skipping the proof. The message
|
|
1600
|
+
* names every missing path. The test job must run the prod build
|
|
1601
|
+
* (`build:prod` for a `@savvy-web/bundler` package) before the packed-install
|
|
1602
|
+
* tests: a dev build leaves `dist/prod` absent.
|
|
1603
|
+
*
|
|
1604
|
+
* @example
|
|
1605
|
+
* ```ts
|
|
1606
|
+
* import { assert, describe, it } from "@effect/vitest";
|
|
1607
|
+
* import { PackedInstall } from "@effected/workspaces/testing";
|
|
1608
|
+
* import { Effect } from "effect";
|
|
1609
|
+
*
|
|
1610
|
+
* declare const preflight: { readonly ready: boolean; readonly missing: ReadonlyArray<string> };
|
|
1611
|
+
* const gate = Effect.runSync(PackedInstall.gate(preflight));
|
|
1612
|
+
*
|
|
1613
|
+
* describe.runIf(gate.action === "run")("packed install", () => {
|
|
1614
|
+
* it("installs", () => {});
|
|
1615
|
+
* });
|
|
1616
|
+
* describe.runIf(gate.action === "fail")("packed install prod build", () => {
|
|
1617
|
+
* it("exists", () => assert.fail(gate.message));
|
|
1618
|
+
* });
|
|
1619
|
+
* ```
|
|
1620
|
+
*
|
|
1621
|
+
* @param preflight - What {@link PackedInstall.preflight} answered.
|
|
1622
|
+
*/
|
|
1623
|
+
static readonly gate: (preflight: PackedInstallPreflight) => Effect.Effect<PackedInstallGate>;
|
|
1492
1624
|
/** Pack, then install under every available manager. */
|
|
1493
1625
|
static readonly run: (options: PackedInstallOptions) => Effect.Effect<PackedInstallResult, PackedInstallError, ChildProcessSpawner.ChildProcessSpawner | FileSystem.FileSystem | Path.Path | import("effect/Scope").Scope | WorkspaceDiscovery>;
|
|
1494
1626
|
}
|
|
@@ -1761,7 +1893,7 @@ export declare class SourceBoundary {
|
|
|
1761
1893
|
static readonly scan: (options: ScanOptions) => Effect.Effect<SourceScan, import("@effected/glob").GlobPatternError | import("effect/PlatformError").PlatformError, FileSystem.FileSystem | Path.Path>;
|
|
1762
1894
|
/** The shipped positive- and negative-control snippets, at least one of each per rule kind. */
|
|
1763
1895
|
static readonly fixtures: ReadonlyArray<BoundaryFixture>;
|
|
1764
|
-
/** The names of shipped fixtures the scanner
|
|
1896
|
+
/** The names of shipped fixtures the scanner gets wrong; `[]` means it still flags and spares what it must. */
|
|
1765
1897
|
static readonly verifyFixtures: () => ReadonlyArray<string>;
|
|
1766
1898
|
}
|
|
1767
1899
|
//#endregion
|
|
@@ -1860,5 +1992,5 @@ export declare class WorkspaceLayering {
|
|
|
1860
1992
|
static readonly checkWorkspace: (policy: LayerPolicy) => Effect.Effect<LayeringReport, WorkspaceDiscoveryFailure, WorkspaceDiscovery>;
|
|
1861
1993
|
}
|
|
1862
1994
|
//#endregion
|
|
1863
|
-
export type { BinCommandOptions, BinProvenance, BoundaryFixture, BoundaryRule, DependencyDiff, FindWorkspaceRootOptions, LayeringGraph, OffenceRule, PackSource, PackedInstallBudget, PackedInstallClosureOptions, PackedInstallOptions, ReferenceOptions, RunBinOptions, ScanOptions, WorkspaceDiscoveryFailure, WorkspaceDiscoveryOptions, WorkspaceDiscoveryShape, WorkspaceLookupFailure, WorkspaceRootShape };
|
|
1995
|
+
export type { BinCommandOptions, BinProvenance, BoundaryFixture, BoundaryRule, DependencyDiff, FindWorkspaceRootOptions, LayeringGraph, OffenceRule, PackSource, PackedInstallBudget, PackedInstallClosureOptions, PackedInstallGate, PackedInstallOptions, PackedInstallPreflight, PackedInstallPreflightOptions, ReferenceOptions, RunBinOptions, ScanOptions, WorkspaceDiscoveryFailure, WorkspaceDiscoveryOptions, WorkspaceDiscoveryShape, WorkspaceLookupFailure, WorkspaceRootShape };
|
|
1864
1996
|
//# sourceMappingURL=testing.d.ts.map
|