@effected/workspaces 0.2.1 → 0.3.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/Publishability.js +31 -0
- package/README.md +2 -0
- package/WorkspacePackage.js +10 -3
- package/index.d.ts +60 -6
- package/node-sync.d.ts +116 -0
- package/node-sync.js +67 -0
- package/package.json +10 -6
package/Publishability.js
CHANGED
|
@@ -51,6 +51,37 @@ var PublishTarget = class extends Schema.Class("PublishTarget")({
|
|
|
51
51
|
* });
|
|
52
52
|
* ```
|
|
53
53
|
*
|
|
54
|
+
* @example
|
|
55
|
+
* The shape's error channel is `never` — **degrade or die**. An override
|
|
56
|
+
* backed by something fallible (a policy service, a registry probe) folds its
|
|
57
|
+
* failure structurally over `{ readonly message: string }` — matching every
|
|
58
|
+
* `Error`, every Effect schema error class, and anything else carrying a
|
|
59
|
+
* message — and either degrades to a safe answer or dies:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { PublishabilityDetector, PublishTarget } from "@effected/workspaces";
|
|
63
|
+
* import { Effect, Layer } from "effect";
|
|
64
|
+
*
|
|
65
|
+
* declare const lookupPolicy: (
|
|
66
|
+
* name: string,
|
|
67
|
+
* ) => Effect.Effect<ReadonlyArray<PublishTarget>, { readonly message: string }>;
|
|
68
|
+
*
|
|
69
|
+
* const fromPolicyService = Layer.succeed(PublishabilityDetector, {
|
|
70
|
+
* detect: (pkg) =>
|
|
71
|
+
* lookupPolicy(pkg.name).pipe(
|
|
72
|
+
* Effect.catch((error) =>
|
|
73
|
+
* Effect.die(new Error(`publishability policy lookup failed for ${pkg.name}: ${error.message}`)),
|
|
74
|
+
* ),
|
|
75
|
+
* ),
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* A lookup failure that should *not* abort the run degrades instead —
|
|
80
|
+
* `Effect.catch(() => Effect.succeed([]))` reads as "unknown means
|
|
81
|
+
* unpublishable" — but pick one deliberately; silently swallowing the failure
|
|
82
|
+
* into a wrong "publishes to npm" answer is the one option the contract
|
|
83
|
+
* forbids.
|
|
84
|
+
*
|
|
54
85
|
* @public
|
|
55
86
|
*/
|
|
56
87
|
var PublishabilityDetector = class PublishabilityDetector extends Context.Service()("@effected/workspaces/PublishabilityDetector") {
|
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ pnpm add @effected/workspaces effect
|
|
|
39
39
|
|
|
40
40
|
Requires Node.js >=24.11.0. `effect` v4 is a peer dependency. You provide a `FileSystem` and `Path` implementation at the edge — `@effect/platform-node` or `@effect/platform-bun`.
|
|
41
41
|
|
|
42
|
+
All `@effected/*` packages are ESM-only: the exports maps publish only `import` conditions, so `require()` — including tools that resolve in CJS mode — fails with Node's `ERR_PACKAGE_PATH_NOT_EXPORTED` rather than loading a CJS build that does not exist. Import from an ES module.
|
|
43
|
+
|
|
42
44
|
pnpm's catalog semantics come from pnpm's own `@pnpm/catalogs.*` packages, which install as regular dependencies. Reimplementing them would mean owning a moving spec with no oracle, so they are used directly and confined to a single internal module.
|
|
43
45
|
|
|
44
46
|
## Quick start
|
package/WorkspacePackage.js
CHANGED
|
@@ -12,9 +12,9 @@ const EMPTY_MANIFEST = Object.freeze(Object.create(null));
|
|
|
12
12
|
* @remarks
|
|
13
13
|
* Deliberately narrow. `@effected/package-json` models `publishConfig` as an
|
|
14
14
|
* open `Record<string, unknown>` for round-trip fidelity, which preserves every
|
|
15
|
-
* key but types none of them; this is the typed projection of the
|
|
16
|
-
* decide *where and
|
|
17
|
-
* rejected.
|
|
15
|
+
* key but types none of them; this is the typed projection of the handful that
|
|
16
|
+
* decide *where, whether and as what* a package publishes. Unknown keys are
|
|
17
|
+
* ignored, not rejected.
|
|
18
18
|
*
|
|
19
19
|
* @public
|
|
20
20
|
*/
|
|
@@ -25,6 +25,13 @@ var PublishConfig = class extends Schema.Class("PublishConfig")({
|
|
|
25
25
|
registry: Schema.optionalKey(Schema.String),
|
|
26
26
|
/** A subdirectory to publish instead of the package root. */
|
|
27
27
|
directory: Schema.optionalKey(Schema.String),
|
|
28
|
+
/**
|
|
29
|
+
* Whether workspace links point into `directory` during local development —
|
|
30
|
+
* pnpm symlinks the publish directory instead of the package root, so
|
|
31
|
+
* siblings resolve the built artifact they would install from the registry.
|
|
32
|
+
* Meaningful only alongside `directory`.
|
|
33
|
+
*/
|
|
34
|
+
linkDirectory: Schema.optionalKey(Schema.Boolean),
|
|
28
35
|
/** The dist-tag to publish under. */
|
|
29
36
|
tag: Schema.optionalKey(Schema.String)
|
|
30
37
|
}) {};
|
package/index.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ declare const PublishConfig_base: Schema.Class<PublishConfig, Schema.Struct<{
|
|
|
13
13
|
readonly registry: Schema.optionalKey<Schema.String>;
|
|
14
14
|
/** A subdirectory to publish instead of the package root. */
|
|
15
15
|
readonly directory: Schema.optionalKey<Schema.String>;
|
|
16
|
+
/**
|
|
17
|
+
* Whether workspace links point into `directory` during local development —
|
|
18
|
+
* pnpm symlinks the publish directory instead of the package root, so
|
|
19
|
+
* siblings resolve the built artifact they would install from the registry.
|
|
20
|
+
* Meaningful only alongside `directory`.
|
|
21
|
+
*/
|
|
22
|
+
readonly linkDirectory: Schema.optionalKey<Schema.Boolean>;
|
|
16
23
|
/** The dist-tag to publish under. */
|
|
17
24
|
readonly tag: Schema.optionalKey<Schema.String>;
|
|
18
25
|
}>, {}>;
|
|
@@ -22,9 +29,9 @@ declare const PublishConfig_base: Schema.Class<PublishConfig, Schema.Struct<{
|
|
|
22
29
|
* @remarks
|
|
23
30
|
* Deliberately narrow. `@effected/package-json` models `publishConfig` as an
|
|
24
31
|
* open `Record<string, unknown>` for round-trip fidelity, which preserves every
|
|
25
|
-
* key but types none of them; this is the typed projection of the
|
|
26
|
-
* decide *where and
|
|
27
|
-
* rejected.
|
|
32
|
+
* key but types none of them; this is the typed projection of the handful that
|
|
33
|
+
* decide *where, whether and as what* a package publishes. Unknown keys are
|
|
34
|
+
* ignored, not rejected.
|
|
28
35
|
*
|
|
29
36
|
* @public
|
|
30
37
|
*/
|
|
@@ -977,10 +984,26 @@ declare const PublishTarget_base: Schema.Class<PublishTarget, Schema.Struct<{
|
|
|
977
984
|
* @public
|
|
978
985
|
*/
|
|
979
986
|
declare class PublishTarget extends PublishTarget_base {}
|
|
980
|
-
|
|
987
|
+
/**
|
|
988
|
+
* The {@link PublishabilityDetector} service shape.
|
|
989
|
+
*
|
|
990
|
+
* @remarks
|
|
991
|
+
* The error channel is deliberately `never`: every consumer of the service —
|
|
992
|
+
* a release planner iterating a whole workspace — treats "does this publish"
|
|
993
|
+
* as a total question, so an overriding layer whose lookup can fail must
|
|
994
|
+
* **degrade or die**. Fold a recoverable failure into a safe answer (usually
|
|
995
|
+
* the empty target list), or `Effect.orDie` it into the defect channel; it
|
|
996
|
+
* cannot widen the channel the contract declares. See
|
|
997
|
+
* {@link PublishabilityDetector} for the adapter an overriding consumer
|
|
998
|
+
* writes.
|
|
999
|
+
*
|
|
1000
|
+
* @public
|
|
1001
|
+
*/
|
|
1002
|
+
interface PublishabilityDetectorShape {
|
|
981
1003
|
/** The publish targets for a package; empty means it does not publish. */
|
|
982
1004
|
readonly detect: (pkg: WorkspacePackage) => Effect.Effect<ReadonlyArray<PublishTarget>>;
|
|
983
|
-
}
|
|
1005
|
+
}
|
|
1006
|
+
declare const PublishabilityDetector_base: Context.ServiceClass<PublishabilityDetector, "@effected/workspaces/PublishabilityDetector", PublishabilityDetectorShape>;
|
|
984
1007
|
/**
|
|
985
1008
|
* Decides whether a workspace package publishes, and to where.
|
|
986
1009
|
*
|
|
@@ -1012,6 +1035,37 @@ declare const PublishabilityDetector_base: Context.ServiceClass<PublishabilityDe
|
|
|
1012
1035
|
* });
|
|
1013
1036
|
* ```
|
|
1014
1037
|
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* The shape's error channel is `never` — **degrade or die**. An override
|
|
1040
|
+
* backed by something fallible (a policy service, a registry probe) folds its
|
|
1041
|
+
* failure structurally over `{ readonly message: string }` — matching every
|
|
1042
|
+
* `Error`, every Effect schema error class, and anything else carrying a
|
|
1043
|
+
* message — and either degrades to a safe answer or dies:
|
|
1044
|
+
*
|
|
1045
|
+
* ```ts
|
|
1046
|
+
* import { PublishabilityDetector, PublishTarget } from "@effected/workspaces";
|
|
1047
|
+
* import { Effect, Layer } from "effect";
|
|
1048
|
+
*
|
|
1049
|
+
* declare const lookupPolicy: (
|
|
1050
|
+
* name: string,
|
|
1051
|
+
* ) => Effect.Effect<ReadonlyArray<PublishTarget>, { readonly message: string }>;
|
|
1052
|
+
*
|
|
1053
|
+
* const fromPolicyService = Layer.succeed(PublishabilityDetector, {
|
|
1054
|
+
* detect: (pkg) =>
|
|
1055
|
+
* lookupPolicy(pkg.name).pipe(
|
|
1056
|
+
* Effect.catch((error) =>
|
|
1057
|
+
* Effect.die(new Error(`publishability policy lookup failed for ${pkg.name}: ${error.message}`)),
|
|
1058
|
+
* ),
|
|
1059
|
+
* ),
|
|
1060
|
+
* });
|
|
1061
|
+
* ```
|
|
1062
|
+
*
|
|
1063
|
+
* A lookup failure that should *not* abort the run degrades instead —
|
|
1064
|
+
* `Effect.catch(() => Effect.succeed([]))` reads as "unknown means
|
|
1065
|
+
* unpublishable" — but pick one deliberately; silently swallowing the failure
|
|
1066
|
+
* into a wrong "publishes to npm" answer is the one option the contract
|
|
1067
|
+
* forbids.
|
|
1068
|
+
*
|
|
1015
1069
|
* @public
|
|
1016
1070
|
*/
|
|
1017
1071
|
declare class PublishabilityDetector extends PublishabilityDetector_base {
|
|
@@ -1668,5 +1722,5 @@ interface GetWorkspacePackagesSyncOptions extends WorkspacesSyncOptions {
|
|
|
1668
1722
|
*/
|
|
1669
1723
|
declare const getWorkspacePackagesSync: (root: string, options: GetWorkspacePackagesSyncOptions) => ReadonlyArray<WorkspacePackage>;
|
|
1670
1724
|
//#endregion
|
|
1671
|
-
export { type CatalogAssemblyFailure, CatalogSet, ChangeDetectionError, type ChangeDetectionFailure, ChangeDetectionOptions, ChangeDetector, type ChangeDetectorShape, ConfigDependencyHooks, type ConfigDependencyHooksShape, CyclicDependencyError, type DependencyDiff, DependencyGraph, DetectedPackageManager, type FindWorkspaceRootSyncOptions, type GetWorkspacePackagesSyncOptions, LockfileReadError, type LockfileReadFailure, LockfileReader, type LockfileReaderOptions, type LockfileReaderShape, PackageManagerDetectionError, type PackageManagerDetectionFailure, PackageManagerDetector, PackageManagerName, PackageNotFoundError, PackageStateSnapshot, PublishConfig, PublishTarget, PublishabilityDetector, type SyncFileSystem, type SyncPath, 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, type WorkspacesSyncOptions, findWorkspaceRootSync, getWorkspacePackagesSync };
|
|
1725
|
+
export { type CatalogAssemblyFailure, CatalogSet, ChangeDetectionError, type ChangeDetectionFailure, ChangeDetectionOptions, ChangeDetector, type ChangeDetectorShape, ConfigDependencyHooks, type ConfigDependencyHooksShape, CyclicDependencyError, type DependencyDiff, DependencyGraph, DetectedPackageManager, type FindWorkspaceRootSyncOptions, type GetWorkspacePackagesSyncOptions, LockfileReadError, type LockfileReadFailure, LockfileReader, type LockfileReaderOptions, type LockfileReaderShape, PackageManagerDetectionError, type PackageManagerDetectionFailure, PackageManagerDetector, PackageManagerName, PackageNotFoundError, PackageStateSnapshot, PublishConfig, PublishTarget, PublishabilityDetector, type PublishabilityDetectorShape, type SyncFileSystem, type SyncPath, 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, type WorkspacesSyncOptions, findWorkspaceRootSync, getWorkspacePackagesSync };
|
|
1672
1726
|
//# sourceMappingURL=index.d.ts.map
|
package/node-sync.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import "@effected/glob";
|
|
2
|
+
import "@effected/lockfiles";
|
|
3
|
+
import "@effected/package-json";
|
|
4
|
+
import "effect";
|
|
5
|
+
//#region src/WorkspacesSync.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The synchronous file operations the sync entry points need, supplied by the
|
|
8
|
+
* consumer. Node's built-ins satisfy it directly:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
12
|
+
*
|
|
13
|
+
* const fileSystem: SyncFileSystem = {
|
|
14
|
+
* exists: existsSync,
|
|
15
|
+
* readFile: (p) => readFileSync(p, "utf8"),
|
|
16
|
+
* readDirectory: (p) => readdirSync(p),
|
|
17
|
+
* isDirectory: (p) => statSync(p).isDirectory(),
|
|
18
|
+
* };
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* `exists` must return a boolean and not throw (Node's `existsSync` never
|
|
22
|
+
* does). The other three may throw — `statSync` on a missing path, a
|
|
23
|
+
* permission error mid-read — and every throw is absorbed into the documented
|
|
24
|
+
* degraded-skip semantics: a throwing `readFile` reads as an unusable
|
|
25
|
+
* manifest, a throwing `readDirectory` as an unreadable directory, a throwing
|
|
26
|
+
* `isDirectory` as "not a directory". Nothing propagates.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
interface SyncFileSystem {
|
|
31
|
+
/** Whether a file or directory exists at `path`. Must not throw. */
|
|
32
|
+
readonly exists: (path: string) => boolean;
|
|
33
|
+
/** Read the file at `path` as text. May throw; a throw degrades to a skip. */
|
|
34
|
+
readonly readFile: (path: string) => string;
|
|
35
|
+
/** The entry names inside the directory at `path`. May throw; a throw skips the directory. */
|
|
36
|
+
readonly readDirectory: (path: string) => ReadonlyArray<string>;
|
|
37
|
+
/** Whether `path` is a directory. May throw; a throw reads as `false`. */
|
|
38
|
+
readonly isDirectory: (path: string) => boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The synchronous path operations the sync entry points need, supplied by the
|
|
42
|
+
* consumer. Deliberately a structural subset of `node:path`, so the built-in
|
|
43
|
+
* module (and its `win32` / `posix` variants, or a Bun / Deno equivalent)
|
|
44
|
+
* satisfies it verbatim:
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* import * as path from "node:path";
|
|
48
|
+
*
|
|
49
|
+
* const options: WorkspacesSyncOptions = {
|
|
50
|
+
* fileSystem: { exists: existsSync, readFile: (p) => readFileSync(p, "utf8"), readDirectory: (p) => readdirSync(p), isDirectory: (p) => statSync(p).isDirectory() },
|
|
51
|
+
* path, // node:path IS a SyncPath
|
|
52
|
+
* };
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* These operations shape only the ABSOLUTE paths handed back to the consumer
|
|
56
|
+
* (and to its own `fileSystem`); workspace-relative pattern matching is POSIX
|
|
57
|
+
* by the `packages:` contract and never routes through here. Windows
|
|
58
|
+
* correctness comes from supplying a win32-appropriate implementation, not
|
|
59
|
+
* from anything in this module.
|
|
60
|
+
*
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
interface SyncPath {
|
|
64
|
+
/** Join segments with the implementation's separator (like `path.join`). */
|
|
65
|
+
readonly join: (...segments: ReadonlyArray<string>) => string;
|
|
66
|
+
/** The directory portion of `p` (like `path.dirname`). */
|
|
67
|
+
readonly dirname: (p: string) => string;
|
|
68
|
+
/** Resolve segments to an absolute path (rightmost-wins, like `path.resolve`). */
|
|
69
|
+
readonly resolve: (...segments: ReadonlyArray<string>) => string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The consumer-supplied operations backing one sync call: the file operations
|
|
73
|
+
* and the path implementation. Both are required — this package never imports
|
|
74
|
+
* `node:*` and never assumes posix, so the platform binding is entirely the
|
|
75
|
+
* caller's.
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
79
|
+
interface WorkspacesSyncOptions {
|
|
80
|
+
/** The synchronous file operations (Node: `existsSync` / `readFileSync` / `readdirSync` / `statSync`). */
|
|
81
|
+
readonly fileSystem: SyncFileSystem;
|
|
82
|
+
/** The synchronous path implementation (Node: the `node:path` module itself). */
|
|
83
|
+
readonly path: SyncPath;
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/node-sync.d.ts
|
|
87
|
+
/**
|
|
88
|
+
* `SyncFileSystem` over `node:fs`.
|
|
89
|
+
*
|
|
90
|
+
* @remarks
|
|
91
|
+
* `existsSync` never throws, satisfying `exists`'s must-not-throw contract;
|
|
92
|
+
* the other three may throw and every throw lands in the sync entry points'
|
|
93
|
+
* documented degraded-skip semantics.
|
|
94
|
+
*
|
|
95
|
+
* @public
|
|
96
|
+
*/
|
|
97
|
+
declare const nodeFileSystem: SyncFileSystem;
|
|
98
|
+
/**
|
|
99
|
+
* `SyncPath` as the running platform's `node:path` — win32 semantics on
|
|
100
|
+
* Windows, posix elsewhere. Pass `node:path/win32` or `node:path/posix`
|
|
101
|
+
* yourself to pin a dialect.
|
|
102
|
+
*
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
declare const nodePath: SyncPath;
|
|
106
|
+
/**
|
|
107
|
+
* The complete Node-bound options bag for `findWorkspaceRootSync` and
|
|
108
|
+
* `getWorkspacePackagesSync` — {@link nodeFileSystem} plus {@link nodePath}.
|
|
109
|
+
* Spread it to add the per-call extras: `{ ...nodeSyncOps, cwd }`.
|
|
110
|
+
*
|
|
111
|
+
* @public
|
|
112
|
+
*/
|
|
113
|
+
declare const nodeSyncOps: WorkspacesSyncOptions;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { type SyncFileSystem, type SyncPath, type WorkspacesSyncOptions, nodeFileSystem, nodePath, nodeSyncOps };
|
|
116
|
+
//# sourceMappingURL=node-sync.d.ts.map
|
package/node-sync.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
//#region src/node-sync.ts
|
|
5
|
+
/**
|
|
6
|
+
* The Node.js binding for the sync entry points — ready-made `SyncFileSystem`
|
|
7
|
+
* and `SyncPath` operations over `node:fs` / `node:path`, so adopting
|
|
8
|
+
* `findWorkspaceRootSync` / `getWorkspacePackagesSync` is one import instead
|
|
9
|
+
* of four hand-wired one-liners.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately a **separate subpath** (`@effected/workspaces/node-sync`), not
|
|
12
|
+
* part of the main entry: the main entry imports nothing platform-shaped, and
|
|
13
|
+
* re-exporting these from it would drag `node:*` imports into every consumer —
|
|
14
|
+
* including the ones supplying their own operations (a win32-explicit `path`,
|
|
15
|
+
* a Bun or Deno binding, a test fake). Import this module only where Node's
|
|
16
|
+
* built-ins are the platform you mean; `nodePath` is the running platform's
|
|
17
|
+
* `node:path`, so on Windows the paths handed back are win32 paths.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
|
|
22
|
+
* import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
23
|
+
*
|
|
24
|
+
* const root = findWorkspaceRootSync(nodeSyncOps);
|
|
25
|
+
* const packages = root === null ? [] : getWorkspacePackagesSync(root, nodeSyncOps);
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @packageDocumentation
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* `SyncFileSystem` over `node:fs`.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* `existsSync` never throws, satisfying `exists`'s must-not-throw contract;
|
|
35
|
+
* the other three may throw and every throw lands in the sync entry points'
|
|
36
|
+
* documented degraded-skip semantics.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
const nodeFileSystem = {
|
|
41
|
+
exists: existsSync,
|
|
42
|
+
readFile: (p) => readFileSync(p, "utf8"),
|
|
43
|
+
readDirectory: (p) => readdirSync(p),
|
|
44
|
+
isDirectory: (p) => statSync(p).isDirectory()
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* `SyncPath` as the running platform's `node:path` — win32 semantics on
|
|
48
|
+
* Windows, posix elsewhere. Pass `node:path/win32` or `node:path/posix`
|
|
49
|
+
* yourself to pin a dialect.
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
const nodePath = path;
|
|
54
|
+
/**
|
|
55
|
+
* The complete Node-bound options bag for `findWorkspaceRootSync` and
|
|
56
|
+
* `getWorkspacePackagesSync` — {@link nodeFileSystem} plus {@link nodePath}.
|
|
57
|
+
* Spread it to add the per-call extras: `{ ...nodeSyncOps, cwd }`.
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
const nodeSyncOps = {
|
|
62
|
+
fileSystem: nodeFileSystem,
|
|
63
|
+
path: nodePath
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { nodeFileSystem, nodePath, nodeSyncOps };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/workspaces",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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": [
|
|
@@ -37,16 +37,20 @@
|
|
|
37
37
|
"types": "./index.d.ts",
|
|
38
38
|
"import": "./index.js"
|
|
39
39
|
},
|
|
40
|
+
"./node-sync": {
|
|
41
|
+
"types": "./node-sync.d.ts",
|
|
42
|
+
"import": "./node-sync.js"
|
|
43
|
+
},
|
|
40
44
|
"./package.json": "./package.json"
|
|
41
45
|
},
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@effected/git": "0.
|
|
47
|
+
"@effected/git": "0.3.0",
|
|
44
48
|
"@effected/glob": "0.1.0",
|
|
45
|
-
"@effected/lockfiles": "0.1.
|
|
49
|
+
"@effected/lockfiles": "0.1.2",
|
|
46
50
|
"@effected/npm": "0.2.0",
|
|
47
|
-
"@effected/package-json": "0.
|
|
48
|
-
"@effected/walker": "0.
|
|
49
|
-
"@effected/yaml": "0.
|
|
51
|
+
"@effected/package-json": "0.3.0",
|
|
52
|
+
"@effected/walker": "0.2.0",
|
|
53
|
+
"@effected/yaml": "0.2.0",
|
|
50
54
|
"@pnpm/catalogs.config": "^1100.0.0",
|
|
51
55
|
"@pnpm/catalogs.protocol-parser": "^1100.0.0",
|
|
52
56
|
"@pnpm/catalogs.resolver": "^1100.0.0",
|