@savvy-web/silk-effects 0.2.2 → 0.4.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/README.md +120 -60
- package/index.d.ts +425 -241
- package/index.js +638 -204
- package/package.json +4 -4
- package/tsdoc-metadata.json +1 -1
package/README.md
CHANGED
|
@@ -1,122 +1,172 @@
|
|
|
1
1
|
# @savvy-web/silk-effects
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@savvy-web/silk-effects)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
Shared [Effect](https://effect.website/) library providing Silk Suite conventions for publishability detection, versioning strategy, tag formatting, managed file sections, config discovery, Biome schema synchronization
|
|
6
|
+
Shared [Effect](https://effect.website/) library providing Silk Suite conventions for publishability detection, versioning strategy, tag formatting, managed file sections, config discovery, Biome schema synchronization and CLI tool resolution. Platform-agnostic — consumers provide their own runtime layer (`NodeContext`, `BunContext`, etc.).
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
-
|
|
10
|
+
- Detect a package's publish targets from its `package.json` `publishConfig`, with multi-registry support and a changeset-ignore-aware override for `workspaces-effect`'s `PublishabilityDetector`
|
|
11
|
+
- Read changeset config through a typed accessor service that reports silk vs vanilla mode, ignore patterns and fixed groups
|
|
11
12
|
- Manage tool-owned sections in user-editable files without clobbering surrounding content
|
|
12
13
|
- Discover and resolve CLI tools globally or locally with version enforcement and caching
|
|
13
14
|
- Detect versioning strategy and format git tags from changeset configuration
|
|
14
15
|
- Locate config files and keep Biome schema URLs in sync across workspaces
|
|
15
16
|
|
|
16
|
-
##
|
|
17
|
+
## Install
|
|
17
18
|
|
|
18
19
|
```bash
|
|
20
|
+
npm install @savvy-web/silk-effects effect @effect/platform @effect/platform-node
|
|
21
|
+
# or
|
|
19
22
|
pnpm add @savvy-web/silk-effects effect @effect/platform @effect/platform-node
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
`effect`
|
|
25
|
+
`effect` and `@effect/platform` are peer dependencies. Install a platform package (`@effect/platform-node`, `@effect/platform-bun`) matching your runtime.
|
|
23
26
|
|
|
24
|
-
## Quick
|
|
27
|
+
## Quick start
|
|
25
28
|
|
|
26
29
|
All exports come from the package root:
|
|
27
30
|
|
|
28
31
|
```typescript
|
|
29
32
|
import {
|
|
30
|
-
|
|
33
|
+
SilkPublishability,
|
|
31
34
|
ManagedSection, ManagedSectionLive, SectionDefinition,
|
|
32
35
|
ToolDiscovery, ToolDiscoveryLive, ToolDefinition,
|
|
33
36
|
} from "@savvy-web/silk-effects";
|
|
34
37
|
```
|
|
35
38
|
|
|
39
|
+
`SilkPublishability.detect` is a pure static — no layers, no Effect runtime. Pass a package name and the raw `package.json` and get back the publish targets the silk rules resolve:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { SilkPublishability } from "@savvy-web/silk-effects";
|
|
43
|
+
|
|
44
|
+
const targets = SilkPublishability.detect("@my-org/my-package", {
|
|
45
|
+
private: true,
|
|
46
|
+
publishConfig: { access: "public", targets: ["npm", "github"] },
|
|
47
|
+
});
|
|
48
|
+
// => [PublishTarget { name: "@my-org/my-package", registry: "https://registry.npmjs.org/", ... },
|
|
49
|
+
// PublishTarget { name: "@my-org/my-package", registry: "https://npm.pkg.github.com/", ... }]
|
|
50
|
+
```
|
|
51
|
+
|
|
36
52
|
## Services
|
|
37
53
|
|
|
38
|
-
The
|
|
54
|
+
The services are grouped by which platform layers they require.
|
|
39
55
|
|
|
40
56
|
---
|
|
41
57
|
|
|
42
|
-
### No
|
|
58
|
+
### No platform layer required
|
|
43
59
|
|
|
44
|
-
These services are pure logic
|
|
60
|
+
These services are pure logic — no filesystem or shell access needed.
|
|
45
61
|
|
|
46
|
-
####
|
|
62
|
+
#### SilkPublishability
|
|
47
63
|
|
|
48
|
-
|
|
64
|
+
Apply silk publishability rules to a raw `package.json` and resolve its publish targets. Targets are `PublishTarget` records from `workspaces-effect` with `name`, `registry`, `directory`, `access` and `provenance` fields. The static `detect`, `expandShorthand` and `resolveTargetAccess` helpers are pure; `resolveTargets` and `listPublishable` are Effects that read from disk (see below).
|
|
65
|
+
|
|
66
|
+
In silk mode `private: true` is the norm on workspace `package.json` files. Publishability is derived from `publishConfig`, with the `private` flag consulted only as a last-resort default.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { SilkPublishability } from "@savvy-web/silk-effects";
|
|
70
|
+
|
|
71
|
+
// Targets-first: one PublishTarget per surviving publishConfig.targets entry
|
|
72
|
+
const targets = SilkPublishability.detect("@my-org/pkg", {
|
|
73
|
+
private: true,
|
|
74
|
+
publishConfig: { access: "public", targets: ["npm", "github"] },
|
|
75
|
+
});
|
|
76
|
+
// => [PublishTarget { registry: "https://registry.npmjs.org/", access: "public", ... },
|
|
77
|
+
// PublishTarget { registry: "https://npm.pkg.github.com/", access: "public", ... }]
|
|
78
|
+
|
|
79
|
+
// Not publishable -> empty array
|
|
80
|
+
const none = SilkPublishability.detect("@my-org/internal", { private: true });
|
|
81
|
+
// => []
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
See [Publishability](./docs/publishability.md) for the full rule order and the disk-reading helpers.
|
|
85
|
+
|
|
86
|
+
#### TagStrategy
|
|
87
|
+
|
|
88
|
+
Determine git-tag naming strategy and format tag strings. Strategy is `"single"` (one publishable package, tags like `1.2.3`) or `"scoped"` (multiple packages, tags like `@scope/pkg@1.2.3`). Tag format follows strict SemVer 2.0.0 with no `v` prefix.
|
|
49
89
|
|
|
50
90
|
```typescript
|
|
51
91
|
import { Effect } from "effect";
|
|
52
|
-
import {
|
|
92
|
+
import { TagStrategy, TagStrategyLive } from "@savvy-web/silk-effects";
|
|
53
93
|
|
|
54
|
-
const
|
|
94
|
+
const tag = await Effect.runPromise(
|
|
55
95
|
Effect.gen(function* () {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
const ts = yield* TagStrategy;
|
|
97
|
+
const strategy = yield* ts.determine(versioningResult);
|
|
98
|
+
return yield* ts.formatTag("@savvy-web/silk-effects", "1.0.0", strategy);
|
|
99
|
+
}).pipe(Effect.provide(TagStrategyLive)),
|
|
59
100
|
);
|
|
60
|
-
// =>
|
|
101
|
+
// => "@savvy-web/silk-effects@1.0.0"
|
|
61
102
|
```
|
|
62
103
|
|
|
63
|
-
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### FileSystem layer required
|
|
107
|
+
|
|
108
|
+
These services read or write files. Provide a platform layer such as `NodeContext.layer` or `BunContext.layer`.
|
|
109
|
+
|
|
110
|
+
#### SilkPublishabilityDetectorLive and PublishabilityDetectorAdaptiveLive
|
|
64
111
|
|
|
65
|
-
|
|
112
|
+
`SilkPublishability.detect` is also exposed through `workspaces-effect`'s `PublishabilityDetector` Tag so consumers can swap silk rules into any program that already yields the detector. Two layers override the Tag:
|
|
66
113
|
|
|
67
|
-
|
|
114
|
+
- `SilkPublishabilityDetectorLive` — applies silk rules unconditionally. Requires `FileSystem`.
|
|
115
|
+
- `PublishabilityDetectorAdaptiveLive` — ignore-aware. Changeset-`ignore`d packages resolve to `[]`, then it dispatches by changeset mode (`none` → `[]`, `silk` → silk rules, `vanilla` → the `workspaces-effect` default). Requires `FileSystem` and `ChangesetConfig`.
|
|
68
116
|
|
|
69
117
|
```typescript
|
|
70
118
|
import { Effect } from "effect";
|
|
71
|
-
import {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} from "@savvy-web/silk-effects";
|
|
119
|
+
import { NodeContext } from "@effect/platform-node";
|
|
120
|
+
import { PublishabilityDetector } from "workspaces-effect";
|
|
121
|
+
import { SilkPublishabilityDetectorLive } from "@savvy-web/silk-effects";
|
|
75
122
|
|
|
76
123
|
const targets = await Effect.runPromise(
|
|
77
124
|
Effect.gen(function* () {
|
|
78
|
-
const
|
|
79
|
-
return yield*
|
|
125
|
+
const detector = yield* PublishabilityDetector;
|
|
126
|
+
return yield* detector.detect(pkg, root);
|
|
80
127
|
}).pipe(
|
|
81
|
-
Effect.provide(
|
|
82
|
-
Effect.provide(
|
|
128
|
+
Effect.provide(SilkPublishabilityDetectorLive),
|
|
129
|
+
Effect.provide(NodeContext.layer),
|
|
83
130
|
),
|
|
84
131
|
);
|
|
132
|
+
// => ReadonlyArray<PublishTarget>
|
|
85
133
|
```
|
|
86
134
|
|
|
87
|
-
|
|
135
|
+
See [Publishability](./docs/publishability.md) for the adaptive layer and the `ChangesetConfig` service.
|
|
88
136
|
|
|
89
|
-
|
|
137
|
+
#### ChangesetConfig
|
|
138
|
+
|
|
139
|
+
Typed accessor over a workspace root's `.changeset/config.json`, reading through `ChangesetConfigReader` with a per-root cache. Every accessor is total — a missing or unreadable config collapses to `mode: "none"` and empty defaults. Methods: `mode`, `versionPrivate`, `ignorePatterns`, `isIgnored`, `fixed`, plus a static `ChangesetConfig.matches(name, pattern)`.
|
|
90
140
|
|
|
91
141
|
```typescript
|
|
92
142
|
import { Effect } from "effect";
|
|
93
|
-
import {
|
|
143
|
+
import { NodeContext } from "@effect/platform-node";
|
|
144
|
+
import {
|
|
145
|
+
ChangesetConfig, ChangesetConfigLive, ChangesetConfigReaderLive,
|
|
146
|
+
} from "@savvy-web/silk-effects";
|
|
94
147
|
|
|
95
|
-
const
|
|
148
|
+
const mode = await Effect.runPromise(
|
|
96
149
|
Effect.gen(function* () {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
150
|
+
const config = yield* ChangesetConfig;
|
|
151
|
+
return yield* config.mode(process.cwd());
|
|
152
|
+
}).pipe(
|
|
153
|
+
Effect.provide(ChangesetConfigLive),
|
|
154
|
+
Effect.provide(ChangesetConfigReaderLive),
|
|
155
|
+
Effect.provide(NodeContext.layer),
|
|
156
|
+
),
|
|
101
157
|
);
|
|
102
|
-
// => "
|
|
158
|
+
// => "silk" | "vanilla" | "none"
|
|
103
159
|
```
|
|
104
160
|
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
### FileSystem Layer Required
|
|
108
|
-
|
|
109
|
-
These services read or write files. Provide a platform layer such as `NodeContext.layer` or `BunContext.layer`.
|
|
110
|
-
|
|
111
161
|
#### ManagedSection
|
|
112
162
|
|
|
113
163
|
Manage tool-owned delimited sections inside user-editable files. Sections are bounded by markers like `# --- BEGIN TOOL MANAGED SECTION ---` / `# --- END ... ---`. User content outside the markers is never touched.
|
|
114
164
|
|
|
115
|
-
|
|
165
|
+
`SectionDefinition` is a value object representing section identity (tool name + comment style). It creates `SectionBlock` instances that hold the actual content. Definitions support typed content factories via `generate()` and `generateEffect()`.
|
|
116
166
|
|
|
117
|
-
|
|
167
|
+
`SectionBlock` represents the content between markers. It supports `diff()`, `prepend()` and `append()` operations and uses normalized content for equality comparison.
|
|
118
168
|
|
|
119
|
-
Methods: `read`, `write`, `sync`, `check`, `isManaged`
|
|
169
|
+
Methods: `read`, `write`, `sync`, `check`, `isManaged` — all support dual API (data-first and data-last) for pipe composition.
|
|
120
170
|
|
|
121
171
|
```typescript
|
|
122
172
|
import { Effect } from "effect";
|
|
@@ -159,7 +209,7 @@ Use `ShellSectionDefinition` when the comment style is always `#` and should not
|
|
|
159
209
|
|
|
160
210
|
#### VersioningStrategy
|
|
161
211
|
|
|
162
|
-
Classify the versioning strategy from changeset configuration. Outputs `"single"` (0-1 publishable packages), `"fixed-group"` (all packages in one fixed group)
|
|
212
|
+
Classify the versioning strategy from changeset configuration. Outputs `"single"` (0-1 publishable packages), `"fixed-group"` (all packages in one fixed group) or `"independent"` (multiple packages, not in a single group). Falls back gracefully if config is missing.
|
|
163
213
|
|
|
164
214
|
```typescript
|
|
165
215
|
import { Effect } from "effect";
|
|
@@ -184,7 +234,7 @@ const result = await Effect.runPromise(
|
|
|
184
234
|
|
|
185
235
|
#### ChangesetConfigReader
|
|
186
236
|
|
|
187
|
-
Read and decode `.changeset/config.json`. Auto-detects whether the project uses `@savvy-web/changesets` (returning `
|
|
237
|
+
Read and decode `.changeset/config.json`. Auto-detects whether the project uses `@savvy-web/changesets` (returning `SilkChangesetConfigFile` with `_isSilk: true`) or standard changesets (returning `ChangesetConfigFile`).
|
|
188
238
|
|
|
189
239
|
```typescript
|
|
190
240
|
import { Effect } from "effect";
|
|
@@ -202,6 +252,7 @@ const config = await Effect.runPromise(
|
|
|
202
252
|
Effect.provide(NodeContext.layer),
|
|
203
253
|
),
|
|
204
254
|
);
|
|
255
|
+
// => ChangesetConfigFile | SilkChangesetConfigFile
|
|
205
256
|
```
|
|
206
257
|
|
|
207
258
|
#### ConfigDiscovery
|
|
@@ -217,12 +268,12 @@ const result = await Effect.runPromise(
|
|
|
217
268
|
Effect.gen(function* () {
|
|
218
269
|
const cd = yield* ConfigDiscovery;
|
|
219
270
|
return yield* cd.find("biome.jsonc");
|
|
220
|
-
// => { path: "/project/biome.jsonc", source: "root" } | null
|
|
221
271
|
}).pipe(
|
|
222
272
|
Effect.provide(ConfigDiscoveryLive),
|
|
223
273
|
Effect.provide(NodeContext.layer),
|
|
224
274
|
),
|
|
225
275
|
);
|
|
276
|
+
// => { path: "/project/biome.jsonc", source: "root" } | null
|
|
226
277
|
```
|
|
227
278
|
|
|
228
279
|
#### BiomeSchemaSync
|
|
@@ -234,29 +285,29 @@ import { Effect } from "effect";
|
|
|
234
285
|
import { NodeContext } from "@effect/platform-node";
|
|
235
286
|
import { BiomeSchemaSync, BiomeSchemaSyncLive } from "@savvy-web/silk-effects";
|
|
236
287
|
|
|
237
|
-
await Effect.runPromise(
|
|
288
|
+
const result = await Effect.runPromise(
|
|
238
289
|
Effect.gen(function* () {
|
|
239
290
|
const bss = yield* BiomeSchemaSync;
|
|
240
|
-
|
|
241
|
-
// => { updated: true, skipped: false, current: "2.0.0" }
|
|
291
|
+
return yield* bss.sync("2.0.0");
|
|
242
292
|
}).pipe(
|
|
243
293
|
Effect.provide(BiomeSchemaSyncLive),
|
|
244
294
|
Effect.provide(NodeContext.layer),
|
|
245
295
|
),
|
|
246
296
|
);
|
|
297
|
+
// => { updated: true, skipped: false, current: "2.0.0" }
|
|
247
298
|
```
|
|
248
299
|
|
|
249
300
|
---
|
|
250
301
|
|
|
251
|
-
### FileSystem + CommandExecutor
|
|
302
|
+
### FileSystem + CommandExecutor layer required
|
|
252
303
|
|
|
253
304
|
#### ToolDiscovery
|
|
254
305
|
|
|
255
|
-
Locate CLI tools globally (PATH) or locally (via package manager), extract versions, enforce constraints
|
|
306
|
+
Locate CLI tools globally (PATH) or locally (via package manager), extract versions, enforce constraints and cache results.
|
|
256
307
|
|
|
257
|
-
|
|
308
|
+
`ToolDefinition` configures how a tool is resolved: `VersionExtractor` (Flag, Json or None), `ResolutionPolicy` (Report, PreferLocal, PreferGlobal, RequireMatch) and `SourceRequirement` (Any, OnlyLocal, OnlyGlobal, Both). Equality is based on tool name only.
|
|
258
309
|
|
|
259
|
-
|
|
310
|
+
`ResolvedTool` is the result of resolution. It carries the tool's name, source (`"global"` or `"local"`), version and package manager. Its `exec()` and `dlx()` methods return a `ToolCommand` — a wrapper around `@effect/platform` `Command` with instance-method ergonomics (`string()`, `lines()`, `exitCode()`, `stream()`).
|
|
260
311
|
|
|
261
312
|
```typescript
|
|
262
313
|
import { Effect } from "effect";
|
|
@@ -295,8 +346,17 @@ const biome = yield* td.require(
|
|
|
295
346
|
|
|
296
347
|
## Documentation
|
|
297
348
|
|
|
298
|
-
|
|
349
|
+
- [Overview](./docs/overview.md) — what the library is, its design philosophy and platform-layer model
|
|
350
|
+
- [Publishability](./docs/publishability.md) — silk publishability rules, the detector overrides and the ChangesetConfig service
|
|
351
|
+
- [Changeset config](./docs/changeset-config.md) — reading and decoding `.changeset/config.json`
|
|
352
|
+
- [Platform layers](./docs/platform-layers.md) — composing layers and providing platform dependencies
|
|
353
|
+
- [Managed sections](./docs/managed-section.md) — tool-owned regions in user-editable files
|
|
354
|
+
- [Tool discovery](./docs/tool-discovery.md) — locating and resolving CLI tools
|
|
355
|
+
- [Versioning strategy](./docs/versioning-strategy.md) — classifying workspace versioning
|
|
356
|
+
- [Config discovery](./docs/config-discovery.md) — priority-based config file search
|
|
357
|
+
- [Biome sync](./docs/biome-sync.md) — keeping Biome `$schema` URLs current
|
|
358
|
+
- [Tag strategy](./docs/tag-strategy.md) — git tag naming and formatting
|
|
299
359
|
|
|
300
360
|
## License
|
|
301
361
|
|
|
302
|
-
[MIT](
|
|
362
|
+
[MIT](LICENSE)
|