@savvy-web/silk-effects 4.2.6 → 5.0.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 +73 -192
- package/changesets/api/changelog.js +1 -2
- package/changesets/changelog/index.js +8 -10
- package/changesets/errors.js +0 -1
- package/changesets/index.js +1 -4
- package/changesets/services/changelog.js +1 -1
- package/changesets/services/github.js +1 -1
- package/changesets/utils/dependency-table.js +1 -1
- package/index.d.ts +95 -1398
- package/index.js +1 -20
- package/lint/cli/sections.js +9 -8
- package/package.json +5 -3
- package/schemas/SavvySections.js +26 -9
- package/schemas/VersioningSchemas.js +1 -32
- package/schemas/WorkspaceAnalysisSchemas.js +4 -5
- package/services/SilkPublishability.js +1 -1
- package/services/SilkWorkspaceAnalyzer.js +13 -16
- package/turbo/services/TurboInspector.js +11 -11
- package/changesets/services/markdown.js +0 -93
- package/errors/SectionParseError.js +0 -17
- package/errors/SectionValidationError.js +0 -17
- package/errors/SectionWriteError.js +0 -17
- package/errors/TagFormatError.js +0 -21
- package/errors/ToolNotFoundError.js +0 -12
- package/errors/ToolResolutionError.js +0 -12
- package/errors/ToolVersionMismatchError.js +0 -12
- package/errors/VersioningDetectionError.js +0 -21
- package/schemas/CommentStyle.js +0 -17
- package/schemas/ResolvedTool.js +0 -99
- package/schemas/SectionBlock.js +0 -71
- package/schemas/SectionDefinition.js +0 -123
- package/schemas/SectionResults.js +0 -21
- package/schemas/TagStrategySchemas.js +0 -19
- package/schemas/ToolDefinition.js +0 -40
- package/schemas/ToolResults.js +0 -28
- package/services/ManagedSection.js +0 -289
- package/services/TagStrategy.js +0 -56
- package/services/ToolDiscovery.js +0 -232
- package/services/VersioningStrategy.js +0 -69
- package/utils/ToolCommand.js +0 -67
package/README.md
CHANGED
|
@@ -3,27 +3,28 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@savvy-web/silk-effects)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
Shared [Effect](https://effect.website/) library providing Silk Suite conventions for publishability detection,
|
|
6
|
+
Shared [Effect](https://effect.website/) library providing Silk Suite conventions for publishability detection, changeset config access, release planning, config discovery, Biome schema synchronization and read-only Turborepo inspection. Platform-agnostic — consumers provide their own platform layer (`NodeServices.layer` from `@effect/platform-node`, or the equivalent for their runtime).
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- Detect a package's publish targets from its `package.json` `publishConfig`, with multi-registry support and a changeset-ignore-aware override for
|
|
10
|
+
- Detect a package's publish targets from its `package.json` `publishConfig`, with multi-registry support and a changeset-ignore-aware override for `@effected/workspaces`'s `PublishabilityDetector`
|
|
11
11
|
- Read changeset config through a typed accessor service that reports silk vs vanilla mode, ignore patterns and fixed groups
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- Locate config files and keep Biome schema URLs in sync across workspaces
|
|
12
|
+
- Plan, preview and apply a release over the genuine changesets engine, lint changeset files against the section-aware Silk rules and regenerate pure dependency changesets from a branch diff
|
|
13
|
+
- Supply the Silk commitlint config, its prompt and formatter, and the `silk/body-no-markdown` rule
|
|
14
|
+
- Run the lint-staged handlers and the `savvy lint fmt` formatters from a single implementation so the hook and the CLI cannot drift
|
|
16
15
|
- Inspect a Turborepo read-only — diagnose per-package cache hits, derive the task graph and compute affected packages, all over `turbo --dry`
|
|
16
|
+
- Manage the vendored reference repos declared in `.repos/config.json`, including submodule sync, pinning and drift reporting
|
|
17
|
+
- Locate config files and keep Biome schema URLs in sync across workspaces
|
|
17
18
|
|
|
18
19
|
## Install
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
|
-
npm install @savvy-web/silk-effects effect @effect/platform
|
|
22
|
+
npm install @savvy-web/silk-effects effect @effect/platform-node
|
|
22
23
|
# or
|
|
23
|
-
pnpm add @savvy-web/silk-effects effect @effect/platform
|
|
24
|
+
pnpm add @savvy-web/silk-effects effect @effect/platform-node
|
|
24
25
|
```
|
|
25
26
|
|
|
26
|
-
`effect`
|
|
27
|
+
`effect` is a peer dependency. Install the platform package matching your runtime — `@effect/platform-node` for Node.js — to satisfy the `FileSystem` and process services the file-reading services need.
|
|
27
28
|
|
|
28
29
|
## Quick start
|
|
29
30
|
|
|
@@ -32,8 +33,8 @@ All exports come from the package root:
|
|
|
32
33
|
```typescript
|
|
33
34
|
import {
|
|
34
35
|
SilkPublishability,
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
ChangesetConfig, ChangesetConfigLive,
|
|
37
|
+
Changesets, Lint, Turbo,
|
|
37
38
|
} from "@savvy-web/silk-effects";
|
|
38
39
|
```
|
|
39
40
|
|
|
@@ -66,7 +67,7 @@ These services are pure logic — no filesystem or shell access needed.
|
|
|
66
67
|
|
|
67
68
|
#### SilkPublishability
|
|
68
69
|
|
|
69
|
-
Apply silk publishability rules to a raw `package.json` and the bundler's resolved target binding, and resolve the publish targets. Targets are `PublishTarget` records from
|
|
70
|
+
Apply silk publishability rules to a raw `package.json` and the bundler's resolved target binding, and resolve the publish targets. Targets are `PublishTarget` records from `@effected/workspaces` with `name`, `registry`, `directory`, `access` and `provenance` fields. The static `detect` helper is pure; `resolveTargets` and `listPublishable` are Effects that read from disk (see below), and `readTargetsBinding` reads the binding `detect` consumes.
|
|
70
71
|
|
|
71
72
|
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. Publish targets are declared as the bundler's keyed `publishConfig.targets` map; the legacy array form is no longer supported.
|
|
72
73
|
|
|
@@ -90,43 +91,39 @@ const none = SilkPublishability.detect("@my-org/internal", { private: true }, nu
|
|
|
90
91
|
// => []
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
See [Publishability](./docs/publishability.md) for the full rule order and the disk-reading helpers.
|
|
94
|
+
See [Publishability](./docs/03-publishability.md) for the full rule order and the disk-reading helpers.
|
|
94
95
|
|
|
95
|
-
####
|
|
96
|
+
#### Tags and versioning classification
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
Git-tag naming and versioning classification live upstream in `@effected/workspaces` as pure value classes — `ReleaseTag`, `TrackingTag`, `classifyTag` and `VersioningStrategy` — so there is no service, no layer and no error channel.
|
|
98
99
|
|
|
99
100
|
```typescript
|
|
100
|
-
import {
|
|
101
|
-
import { TagStrategy, TagStrategyLive } from "@savvy-web/silk-effects";
|
|
101
|
+
import { VersioningStrategy } from "@effected/workspaces";
|
|
102
102
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const strategy = yield* ts.determine(versioningResult);
|
|
107
|
-
return yield* ts.formatTag("@savvy-web/silk-effects", "1.0.0", strategy);
|
|
108
|
-
}).pipe(Effect.provide(TagStrategyLive)),
|
|
109
|
-
);
|
|
110
|
-
// => "@savvy-web/silk-effects@1.0.0"
|
|
103
|
+
const strategy = VersioningStrategy.classify({ packages: publishablePackages, fixedGroups });
|
|
104
|
+
const tags = strategy.tagsFor([{ name: "@savvy-web/silk-effects", version: "1.0.0" }]);
|
|
105
|
+
// => [ReleaseTag { value: "@savvy-web/silk-effects@1.0.0" }]
|
|
111
106
|
```
|
|
112
107
|
|
|
108
|
+
`WorkspaceAnalysis.versioning` and `WorkspaceAnalysis.tagStrategy` carry those kit types directly.
|
|
109
|
+
|
|
113
110
|
---
|
|
114
111
|
|
|
115
112
|
### FileSystem layer required
|
|
116
113
|
|
|
117
|
-
These services read or write files. Provide
|
|
114
|
+
These services read or write files. Provide the platform layer for your runtime, such as `NodeServices.layer`.
|
|
118
115
|
|
|
119
116
|
#### SilkPublishabilityDetectorLive and PublishabilityDetectorAdaptiveLive
|
|
120
117
|
|
|
121
|
-
`SilkPublishability.detect` is also exposed through
|
|
118
|
+
`SilkPublishability.detect` is also exposed through `@effected/workspaces`'s `PublishabilityDetector` Tag so consumers can swap silk rules into any program that already yields the detector. Two layers override the Tag:
|
|
122
119
|
|
|
123
120
|
- `SilkPublishabilityDetectorLive` — applies silk rules unconditionally. Requires `FileSystem`.
|
|
124
|
-
- `PublishabilityDetectorAdaptiveLive` — ignore-aware. Changeset-`ignore`d packages resolve to `[]`, then it dispatches by changeset mode (`none` → `[]`, `silk` → silk rules, `vanilla` → the
|
|
121
|
+
- `PublishabilityDetectorAdaptiveLive` — ignore-aware. Changeset-`ignore`d packages resolve to `[]`, then it dispatches by changeset mode (`none` → `[]`, `silk` → silk rules, `vanilla` → the `@effected/workspaces` default). Requires `FileSystem` and `ChangesetConfig`.
|
|
125
122
|
|
|
126
123
|
```typescript
|
|
127
124
|
import { Effect } from "effect";
|
|
128
|
-
import {
|
|
129
|
-
import { PublishabilityDetector } from "workspaces
|
|
125
|
+
import { NodeServices } from "@effect/platform-node";
|
|
126
|
+
import { PublishabilityDetector } from "@effected/workspaces";
|
|
130
127
|
import { SilkPublishabilityDetectorLive } from "@savvy-web/silk-effects";
|
|
131
128
|
|
|
132
129
|
const targets = await Effect.runPromise(
|
|
@@ -135,13 +132,13 @@ const targets = await Effect.runPromise(
|
|
|
135
132
|
return yield* detector.detect(pkg, root);
|
|
136
133
|
}).pipe(
|
|
137
134
|
Effect.provide(SilkPublishabilityDetectorLive),
|
|
138
|
-
Effect.provide(
|
|
135
|
+
Effect.provide(NodeServices.layer),
|
|
139
136
|
),
|
|
140
137
|
);
|
|
141
138
|
// => ReadonlyArray<PublishTarget>
|
|
142
139
|
```
|
|
143
140
|
|
|
144
|
-
See [Publishability](./docs/publishability.md) for the adaptive layer and the `ChangesetConfig` service.
|
|
141
|
+
See [Publishability](./docs/03-publishability.md) for the adaptive layer and the `ChangesetConfig` service.
|
|
145
142
|
|
|
146
143
|
#### ChangesetConfig
|
|
147
144
|
|
|
@@ -149,7 +146,7 @@ Typed accessor over a workspace root's `.changeset/config.json`, reading through
|
|
|
149
146
|
|
|
150
147
|
```typescript
|
|
151
148
|
import { Effect } from "effect";
|
|
152
|
-
import {
|
|
149
|
+
import { NodeServices } from "@effect/platform-node";
|
|
153
150
|
import {
|
|
154
151
|
ChangesetConfig, ChangesetConfigLive, ChangesetConfigReaderLive,
|
|
155
152
|
} from "@savvy-web/silk-effects";
|
|
@@ -161,128 +158,48 @@ const mode = await Effect.runPromise(
|
|
|
161
158
|
}).pipe(
|
|
162
159
|
Effect.provide(ChangesetConfigLive),
|
|
163
160
|
Effect.provide(ChangesetConfigReaderLive),
|
|
164
|
-
Effect.provide(
|
|
161
|
+
Effect.provide(NodeServices.layer),
|
|
165
162
|
),
|
|
166
163
|
);
|
|
167
164
|
// => "silk" | "vanilla" | "none"
|
|
168
165
|
```
|
|
169
166
|
|
|
170
|
-
####
|
|
171
|
-
|
|
172
|
-
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.
|
|
173
|
-
|
|
174
|
-
`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()`.
|
|
175
|
-
|
|
176
|
-
`SectionBlock` represents the content between markers. It supports `diff()`, `prepend()` and `append()` operations and uses normalized content for equality comparison.
|
|
177
|
-
|
|
178
|
-
Methods: `read`, `write`, `sync`, `syncMany`, `check`, `remove`, `isManaged` — all support dual API (data-first and data-last) for pipe composition. `sync` manages one section; `syncMany` manages several ordered sections in one file; `remove` deletes a section including its markers.
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
import { Effect } from "effect";
|
|
182
|
-
import { NodeContext } from "@effect/platform-node";
|
|
183
|
-
import {
|
|
184
|
-
ManagedSection, ManagedSectionLive, SectionDefinition,
|
|
185
|
-
} from "@savvy-web/silk-effects";
|
|
186
|
-
|
|
187
|
-
// Define section identity
|
|
188
|
-
const def = SectionDefinition.make({ toolName: "LINT-STAGED" });
|
|
189
|
-
|
|
190
|
-
// Create a content block from the definition
|
|
191
|
-
const block = def.block("\nnpx lint-staged\n");
|
|
192
|
-
|
|
193
|
-
await Effect.runPromise(
|
|
194
|
-
Effect.gen(function* () {
|
|
195
|
-
const ms = yield* ManagedSection;
|
|
196
|
-
|
|
197
|
-
// Sync: creates the section if missing, updates if changed, no-op if identical
|
|
198
|
-
const result = yield* ms.sync(".husky/pre-commit", block);
|
|
199
|
-
// => SyncResult: Created | Updated | Unchanged
|
|
200
|
-
|
|
201
|
-
// Check: compare file content against expected block
|
|
202
|
-
const check = yield* ms.check(".husky/pre-commit", block);
|
|
203
|
-
// => CheckResult: Found | NotFound
|
|
204
|
-
|
|
205
|
-
// Remove: delete the section and its markers, collapsing the leftover blank line
|
|
206
|
-
const removed = yield* ms.remove(".husky/pre-commit", def);
|
|
207
|
-
// => true if a section was removed, false if none was present
|
|
208
|
-
}).pipe(
|
|
209
|
-
Effect.provide(ManagedSectionLive),
|
|
210
|
-
Effect.provide(NodeContext.layer),
|
|
211
|
-
),
|
|
212
|
-
);
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
`SectionDefinition` also supports `//` comment style for JavaScript/TypeScript files:
|
|
167
|
+
#### Husky hook sections
|
|
216
168
|
|
|
217
|
-
|
|
218
|
-
const jsDef = SectionDefinition.make({ toolName: "MY-TOOL", commentStyle: "//" });
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Use `ShellSectionDefinition` when the comment style is always `#` and should not be configurable.
|
|
222
|
-
|
|
223
|
-
`syncMany` keeps several sections in one file in their declared relative order. It updates existing sections in place, inserts a missing section next to its declared sibling, normalizes order when sections drift out of order and preserves user content and unrelated tool sections. It returns one `SyncResult` per input block in input order and is idempotent.
|
|
224
|
-
|
|
225
|
-
The `SavvySections` exports compose ordered managed sections per husky hook file. A base section defines shared shell, then each consumer layers its own one-line tool section on top:
|
|
169
|
+
The Silk husky hooks are data. `SavvySections` supplies the section identities and the shell that goes inside them, and [`@effected/templates`](https://www.npmjs.com/package/@effected/templates)' `ManagedSection` service does the reading and writing, so user content outside the `# --- BEGIN ... ---` markers is never touched.
|
|
226
170
|
|
|
227
|
-
- `SavvyBaseSection` is
|
|
228
|
-
- `SavvyHooksSection` (
|
|
229
|
-
- `savvyToolSection(toolName, command)` builds a consumer's one-line tool section whose content is exactly `in_ci || pm_exec <command>` — the command is appended verbatim, so shell tokens like `$ROOT` and `$1` survive into the output. A `savvy-base` section must
|
|
171
|
+
- `SavvyBaseSection` is the shared preamble's identity (key `SAVVY-BASE`); pair it with `savvyBasePreamble()`, which defines `ROOT`, the `in_ci` predicate, `PM` via package-manager detection and `pm_exec`.
|
|
172
|
+
- `SavvyHooksSection` (key `SAVVY-HOOKS`) pairs with `savvyHooksHygiene()`, a self-guarded repo-hygiene block that runs outside CI.
|
|
173
|
+
- `savvyToolSection(toolName, command)` builds a consumer's one-line tool section whose content is exactly `in_ci || pm_exec <command>` — the command is appended verbatim, so shell tokens like `$ROOT` and `$1` survive into the output. A `savvy-base` section must come first in the same hook file, so pass both to `syncAll` in that order.
|
|
230
174
|
|
|
231
175
|
```typescript
|
|
232
176
|
import { Effect } from "effect";
|
|
233
|
-
import {
|
|
234
|
-
import {
|
|
235
|
-
|
|
236
|
-
SavvyBaseSection, savvyBasePreamble, savvyToolSection,
|
|
237
|
-
} from "@savvy-web/silk-effects";
|
|
177
|
+
import { NodeServices } from "@effect/platform-node";
|
|
178
|
+
import { ManagedSection } from "@effected/templates";
|
|
179
|
+
import { SavvyBaseSection, savvyBasePreamble, savvyToolSection } from "@savvy-web/silk-effects";
|
|
238
180
|
|
|
239
181
|
await Effect.runPromise(
|
|
240
182
|
Effect.gen(function* () {
|
|
241
183
|
const ms = yield* ManagedSection;
|
|
242
|
-
const results = yield* ms.
|
|
243
|
-
SavvyBaseSection.
|
|
184
|
+
const results = yield* ms.syncAll(".husky/commit-msg", [
|
|
185
|
+
SavvyBaseSection.section(savvyBasePreamble()),
|
|
244
186
|
savvyToolSection("savvy-commit", 'commitlint --config "$ROOT/lib/configs/commitlint.config.ts" --edit "$1"'),
|
|
245
187
|
]);
|
|
246
|
-
// =>
|
|
188
|
+
// => one sync result per input section, in declared order
|
|
247
189
|
}).pipe(
|
|
248
|
-
Effect.provide(
|
|
249
|
-
Effect.provide(
|
|
190
|
+
Effect.provide(ManagedSection.layer),
|
|
191
|
+
Effect.provide(NodeServices.layer),
|
|
250
192
|
),
|
|
251
193
|
);
|
|
252
194
|
```
|
|
253
195
|
|
|
254
|
-
#### VersioningStrategy
|
|
255
|
-
|
|
256
|
-
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.
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
import { Effect } from "effect";
|
|
260
|
-
import { NodeContext } from "@effect/platform-node";
|
|
261
|
-
import {
|
|
262
|
-
VersioningStrategy, VersioningStrategyLive,
|
|
263
|
-
ChangesetConfigReaderLive,
|
|
264
|
-
} from "@savvy-web/silk-effects";
|
|
265
|
-
|
|
266
|
-
const result = await Effect.runPromise(
|
|
267
|
-
Effect.gen(function* () {
|
|
268
|
-
const vs = yield* VersioningStrategy;
|
|
269
|
-
return yield* vs.detect(publishablePackages, process.cwd());
|
|
270
|
-
}).pipe(
|
|
271
|
-
Effect.provide(VersioningStrategyLive),
|
|
272
|
-
Effect.provide(ChangesetConfigReaderLive),
|
|
273
|
-
Effect.provide(NodeContext.layer),
|
|
274
|
-
),
|
|
275
|
-
);
|
|
276
|
-
// => { strategy: "single" | "fixed-group" | "independent", ... }
|
|
277
|
-
```
|
|
278
|
-
|
|
279
196
|
#### ChangesetConfigReader
|
|
280
197
|
|
|
281
198
|
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`).
|
|
282
199
|
|
|
283
200
|
```typescript
|
|
284
201
|
import { Effect } from "effect";
|
|
285
|
-
import {
|
|
202
|
+
import { NodeServices } from "@effect/platform-node";
|
|
286
203
|
import {
|
|
287
204
|
ChangesetConfigReader, ChangesetConfigReaderLive,
|
|
288
205
|
} from "@savvy-web/silk-effects";
|
|
@@ -293,7 +210,7 @@ const config = await Effect.runPromise(
|
|
|
293
210
|
return yield* reader.read(process.cwd());
|
|
294
211
|
}).pipe(
|
|
295
212
|
Effect.provide(ChangesetConfigReaderLive),
|
|
296
|
-
Effect.provide(
|
|
213
|
+
Effect.provide(NodeServices.layer),
|
|
297
214
|
),
|
|
298
215
|
);
|
|
299
216
|
// => ChangesetConfigFile | SilkChangesetConfigFile
|
|
@@ -305,7 +222,7 @@ Locate config files using a priority-based search convention. Checks `lib/config
|
|
|
305
222
|
|
|
306
223
|
```typescript
|
|
307
224
|
import { Effect } from "effect";
|
|
308
|
-
import {
|
|
225
|
+
import { NodeServices } from "@effect/platform-node";
|
|
309
226
|
import { ConfigDiscovery, ConfigDiscoveryLive } from "@savvy-web/silk-effects";
|
|
310
227
|
|
|
311
228
|
const result = await Effect.runPromise(
|
|
@@ -314,7 +231,7 @@ const result = await Effect.runPromise(
|
|
|
314
231
|
return yield* cd.find("biome.jsonc");
|
|
315
232
|
}).pipe(
|
|
316
233
|
Effect.provide(ConfigDiscoveryLive),
|
|
317
|
-
Effect.provide(
|
|
234
|
+
Effect.provide(NodeServices.layer),
|
|
318
235
|
),
|
|
319
236
|
);
|
|
320
237
|
// => { path: "/project/biome.jsonc", source: "root" } | null
|
|
@@ -326,7 +243,7 @@ Keep Biome config `$schema` URLs current. Locates `biome.json` or `biome.jsonc`,
|
|
|
326
243
|
|
|
327
244
|
```typescript
|
|
328
245
|
import { Effect } from "effect";
|
|
329
|
-
import {
|
|
246
|
+
import { NodeServices } from "@effect/platform-node";
|
|
330
247
|
import { BiomeSchemaSync, BiomeSchemaSyncLive } from "@savvy-web/silk-effects";
|
|
331
248
|
|
|
332
249
|
const result = await Effect.runPromise(
|
|
@@ -335,7 +252,7 @@ const result = await Effect.runPromise(
|
|
|
335
252
|
return yield* bss.sync("2.0.0");
|
|
336
253
|
}).pipe(
|
|
337
254
|
Effect.provide(BiomeSchemaSyncLive),
|
|
338
|
-
Effect.provide(
|
|
255
|
+
Effect.provide(NodeServices.layer),
|
|
339
256
|
),
|
|
340
257
|
);
|
|
341
258
|
// => { updated: true, skipped: false, current: "2.0.0" }
|
|
@@ -343,59 +260,27 @@ const result = await Effect.runPromise(
|
|
|
343
260
|
|
|
344
261
|
---
|
|
345
262
|
|
|
346
|
-
### FileSystem +
|
|
347
|
-
|
|
348
|
-
#### ToolDiscovery
|
|
349
|
-
|
|
350
|
-
Locate CLI tools globally (PATH) or locally (via package manager), extract versions, enforce constraints and cache results.
|
|
263
|
+
### FileSystem + process layer required
|
|
351
264
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
`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()`).
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
import { Effect } from "effect";
|
|
358
|
-
import { NodeContext } from "@effect/platform-node";
|
|
359
|
-
import {
|
|
360
|
-
ToolDiscovery, ToolDiscoveryLive, ToolDefinition,
|
|
361
|
-
} from "@savvy-web/silk-effects";
|
|
362
|
-
|
|
363
|
-
const output = await Effect.runPromise(
|
|
364
|
-
Effect.gen(function* () {
|
|
365
|
-
const td = yield* ToolDiscovery;
|
|
366
|
-
|
|
367
|
-
// Resolve a tool (results are cached by name)
|
|
368
|
-
const biome = yield* td.resolve(ToolDefinition.make({ name: "biome" }));
|
|
369
|
-
|
|
370
|
-
// Check availability without throwing
|
|
371
|
-
const hasBiome = yield* td.isAvailable(ToolDefinition.make({ name: "biome" }));
|
|
265
|
+
#### TurboInspector
|
|
372
266
|
|
|
373
|
-
|
|
374
|
-
return yield* biome.exec("check", ".").string();
|
|
375
|
-
}).pipe(
|
|
376
|
-
Effect.provide(ToolDiscoveryLive),
|
|
377
|
-
Effect.provide(NodeContext.layer),
|
|
378
|
-
),
|
|
379
|
-
);
|
|
380
|
-
```
|
|
267
|
+
Read-only Turborepo inspection. Every method shells out to `turbo` with `--dry=json`, so no task ever runs. `diagnoseCache(task, cwd)` reports a per-package cache HIT/MISS breakdown for a task, `taskGraph(cwd, task?)` derives the task graph and its critical path and `affected(cwd, base?)` lists the packages affected relative to `base` (default `main`). It resolves the `turbo` binary through `ToolDiscovery` from [`@effected/commands`](https://www.npmjs.com/package/@effected/commands) and fails with a tagged error when `turbo` is missing or the directory is not a Turborepo. The service tag and its layer are exported under the `Turbo` namespace.
|
|
381
268
|
|
|
382
|
-
|
|
269
|
+
`Turbo.TurboInspectorLive` requires `ToolDiscovery`, `Git` from [`@effected/git`](https://www.npmjs.com/package/@effected/git), `FileSystem` and the platform process spawner. Wire `ToolDiscovery` to the workspace with `Workspaces.localExecLayer()`, which teaches it the argv prefix that runs a project-local binary:
|
|
383
270
|
|
|
384
271
|
```typescript
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
272
|
+
import { Effect, Layer } from "effect";
|
|
273
|
+
import { NodeServices } from "@effect/platform-node";
|
|
274
|
+
import { ToolDiscovery } from "@effected/commands";
|
|
275
|
+
import { Git } from "@effected/git";
|
|
276
|
+
import { PackageManagerDetector, WorkspaceRoot, Workspaces } from "@effected/workspaces";
|
|
277
|
+
import { Turbo } from "@savvy-web/silk-effects";
|
|
278
|
+
|
|
279
|
+
const WorkspaceLive = Layer.mergeAll(WorkspaceRoot.layer, PackageManagerDetector.layer);
|
|
280
|
+
const ToolsLive = ToolDiscovery.layer.pipe(
|
|
281
|
+
Layer.provide(Workspaces.localExecLayer()),
|
|
282
|
+
Layer.provide(WorkspaceLive),
|
|
388
283
|
);
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
#### TurboInspector
|
|
392
|
-
|
|
393
|
-
Read-only Turborepo inspection. Every method shells out to `turbo` with `--dry=json`, so no task ever runs. `diagnoseCache(task, cwd)` reports a per-package cache HIT/MISS breakdown for a task, `taskGraph(cwd, task?)` derives the task graph and its critical path and `affected(cwd, base?)` lists the packages affected relative to `base` (default `main`). It resolves the `turbo` binary through `ToolDiscovery` and fails with a tagged error when `turbo` is missing or the directory is not a Turborepo. The service tag and its layer are exported under the `Turbo` namespace.
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
import { Effect } from "effect";
|
|
397
|
-
import { NodeContext } from "@effect/platform-node";
|
|
398
|
-
import { Turbo, ToolDiscoveryLive } from "@savvy-web/silk-effects";
|
|
399
284
|
|
|
400
285
|
const diagnosis = await Effect.runPromise(
|
|
401
286
|
Effect.gen(function* () {
|
|
@@ -403,8 +288,8 @@ const diagnosis = await Effect.runPromise(
|
|
|
403
288
|
return yield* turbo.diagnoseCache("build:dev", process.cwd());
|
|
404
289
|
}).pipe(
|
|
405
290
|
Effect.provide(Turbo.TurboInspectorLive),
|
|
406
|
-
Effect.provide(
|
|
407
|
-
Effect.provide(
|
|
291
|
+
Effect.provide(Layer.mergeAll(ToolsLive, Git.layer)),
|
|
292
|
+
Effect.provide(NodeServices.layer),
|
|
408
293
|
),
|
|
409
294
|
);
|
|
410
295
|
// => CacheDiagnosis: per-package HIT/MISS breakdown for the task
|
|
@@ -412,16 +297,12 @@ const diagnosis = await Effect.runPromise(
|
|
|
412
297
|
|
|
413
298
|
## Documentation
|
|
414
299
|
|
|
415
|
-
- [Overview](./docs/overview.md) — what the library is, its design philosophy and platform-layer model
|
|
416
|
-
- [
|
|
417
|
-
- [
|
|
418
|
-
- [
|
|
419
|
-
- [
|
|
420
|
-
- [
|
|
421
|
-
- [Versioning strategy](./docs/versioning-strategy.md) — classifying workspace versioning
|
|
422
|
-
- [Config discovery](./docs/config-discovery.md) — priority-based config file search
|
|
423
|
-
- [Biome sync](./docs/biome-sync.md) — keeping Biome `$schema` URLs current
|
|
424
|
-
- [Tag strategy](./docs/tag-strategy.md) — git tag naming and formatting
|
|
300
|
+
- [Overview](./docs/01-overview.md) — what the library is, its design philosophy and platform-layer model
|
|
301
|
+
- [Platform layers](./docs/02-platform-layers.md) — composing layers and providing platform dependencies
|
|
302
|
+
- [Publishability](./docs/03-publishability.md) — silk publishability rules, the detector overrides and the ChangesetConfig service
|
|
303
|
+
- [Changeset config](./docs/04-changeset-config.md) — reading and decoding `.changeset/config.json`
|
|
304
|
+
- [Config discovery](./docs/05-config-discovery.md) — priority-based config file search
|
|
305
|
+
- [Biome sync](./docs/06-biome-sync.md) — keeping Biome `$schema` URLs current
|
|
425
306
|
|
|
426
307
|
## License
|
|
427
308
|
|
|
@@ -15,8 +15,7 @@ import changelogFunctions from "../changelog/index.js";
|
|
|
15
15
|
* Delegates to the Changesets-compatible `getReleaseLine` and
|
|
16
16
|
* `getDependencyReleaseLine` functions. Internally, these use the
|
|
17
17
|
* {@link ChangelogService} Effect service layer, which coordinates
|
|
18
|
-
* the {@link GitHubService} (for commit/PR metadata)
|
|
19
|
-
* {@link MarkdownService} (for AST manipulation) to produce
|
|
18
|
+
* the {@link GitHubService} (for commit/PR metadata) to produce
|
|
20
19
|
* structured changelog entries.
|
|
21
20
|
*
|
|
22
21
|
* @remarks
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { validateChangesetOptions } from "../schemas/options.js";
|
|
2
2
|
import { GitHubLive } from "../services/github.js";
|
|
3
|
-
import { MarkdownLive } from "../services/markdown.js";
|
|
4
3
|
import { getDependencyReleaseLine } from "./getDependencyReleaseLine.js";
|
|
5
4
|
import { getReleaseLine } from "./getReleaseLine.js";
|
|
6
|
-
import { Effect
|
|
5
|
+
import { Effect } from "effect";
|
|
7
6
|
|
|
8
7
|
//#region src/changesets/changelog/index.ts
|
|
9
8
|
/**
|
|
@@ -17,8 +16,7 @@ import { Effect, Layer } from "effect";
|
|
|
17
16
|
* @remarks
|
|
18
17
|
* The module composes two Effect programs — {@link getReleaseLine} and
|
|
19
18
|
* {@link getDependencyReleaseLine} — and runs each through
|
|
20
|
-
* `Effect.runPromise` with
|
|
21
|
-
* metadata) and {@link MarkdownLive} (for mdast parsing). Options are
|
|
19
|
+
* `Effect.runPromise` with {@link GitHubLive} (for commit metadata). Options are
|
|
22
20
|
* validated at the boundary via `validateChangesetOptions` before being
|
|
23
21
|
* passed to the formatters.
|
|
24
22
|
*
|
|
@@ -58,16 +56,16 @@ import { Effect, Layer } from "effect";
|
|
|
58
56
|
* @see {@link getDependencyReleaseLine} in `./getDependencyReleaseLine.ts` for dependency table formatting
|
|
59
57
|
*/
|
|
60
58
|
/**
|
|
61
|
-
*
|
|
59
|
+
* The layer providing every service the formatters need.
|
|
62
60
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* `
|
|
61
|
+
* {@link GitHubLive} satisfies the requirements of both `getReleaseLine` and
|
|
62
|
+
* `getDependencyReleaseLine`, which each need only `GitHubService`. Markdown
|
|
63
|
+
* parsing is not a layer: the formatters call the remark pipeline's
|
|
64
|
+
* `parseMarkdown` / `stringifyMarkdown` functions directly.
|
|
67
65
|
*
|
|
68
66
|
* @internal
|
|
69
67
|
*/
|
|
70
|
-
const MainLayer =
|
|
68
|
+
const MainLayer = GitHubLive;
|
|
71
69
|
/**
|
|
72
70
|
* Changesets API `ChangelogFunctions` implementation.
|
|
73
71
|
*
|
package/changesets/errors.js
CHANGED
package/changesets/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import { JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema
|
|
|
5
5
|
import { GlobSchema, PackageScopeSchema, PackagesRecordSchema } from "./schemas/package-scope.js";
|
|
6
6
|
import { ChangesetOptionsSchema, RepoSchema } from "./schemas/options.js";
|
|
7
7
|
import { GitHubLive, GitHubService, makeGitHubTest } from "./services/github.js";
|
|
8
|
-
import { MarkdownLive, MarkdownService } from "./services/markdown.js";
|
|
9
8
|
import { NonEmptyString, PositiveInteger } from "./schemas/primitives.js";
|
|
10
9
|
import { DependencyActionSchema, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, VERSION_RE, VersionOrEmptySchema } from "./schemas/dependency-table.js";
|
|
11
10
|
import { serializeDependencyTableToMarkdown } from "./utils/dependency-table.js";
|
|
@@ -108,9 +107,7 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
|
|
|
108
107
|
MaintenanceNotePlugin: () => MaintenanceNotePlugin,
|
|
109
108
|
MaintenanceReasonSchema: () => MaintenanceReasonSchema,
|
|
110
109
|
MaintenanceTriggerSchema: () => MaintenanceTriggerSchema,
|
|
111
|
-
MarkdownLive: () => MarkdownLive,
|
|
112
110
|
MarkdownParseError: () => MarkdownParseError,
|
|
113
|
-
MarkdownService: () => MarkdownService,
|
|
114
111
|
MarkdownlintContentStructureRule: () => ContentStructureRule$1,
|
|
115
112
|
MarkdownlintDependencyTableFormatRule: () => DependencyTableFormatRule$1,
|
|
116
113
|
MarkdownlintHeadingHierarchyRule: () => HeadingHierarchyRule$1,
|
|
@@ -162,4 +159,4 @@ var changesets_exports = /* @__PURE__ */ __exportAll({
|
|
|
162
159
|
});
|
|
163
160
|
|
|
164
161
|
//#endregion
|
|
165
|
-
export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerLive, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetOptionsSchema, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, ClassificationReasonSchema, ClassificationSchema, CommitHashSchema, ConfigInspector, ConfigInspectorLive, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, DependencyTypeSchema, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, DepsRegenLive, FileStatusSchema, GitError, GitHubApiError, GitHubInfoSchema, GitHubLive, GitHubService, GlobSchema, HeadingHierarchyRule, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, MaintenanceNotePlugin, MaintenanceReasonSchema, MaintenanceTriggerSchema,
|
|
162
|
+
export { AggregateDependencyTablesPlugin, AppliedReleaseEntrySchema, AppliedReleaseSchema, BranchAnalysisSchema, BranchAnalyzer, BranchAnalyzerLive, BranchFileEntrySchema, BumpTypeSchema, Categories, Changelog, ChangelogService, ChangelogTransformer, ChangesetIOError, ChangesetLinter, ChangesetOptionsSchema, ChangesetPreviewSchema, ChangesetSchema, ChangesetSummarySchema, ChangesetValidationError, ClassificationReasonSchema, ClassificationSchema, CommitHashSchema, ConfigInspector, ConfigInspectorLive, ConfigurationError, ContentStructureRule, ContributorFootnotesPlugin, DeduplicateItemsPlugin, DependencyActionSchema, DependencyTable, DependencyTableFormatRule, DependencyTableRowSchema, DependencyTableSchema, DependencyTableTypeSchema, DependencyTypeSchema, DependencyUpdateSchema, DepsRegen, DepsRegenDefault, DepsRegenLive, FileStatusSchema, GitError, GitHubApiError, GitHubInfoSchema, GitHubLive, GitHubService, GlobSchema, HeadingHierarchyRule, InspectedConfigSchema, IssueLinkRefsPlugin, IssueNumberSchema, JsonPathSchema, LegacyVersionFileConfigSchema, LegacyVersionFilesSchema, MaintenanceNotePlugin, MaintenanceReasonSchema, MaintenanceTriggerSchema, MarkdownParseError, ContentStructureRule$1 as MarkdownlintContentStructureRule, DependencyTableFormatRule$1 as MarkdownlintDependencyTableFormatRule, HeadingHierarchyRule$1 as MarkdownlintHeadingHierarchyRule, RequiredSectionsRule$1 as MarkdownlintRequiredSectionsRule, UncategorizedContentRule$1 as MarkdownlintUncategorizedContentRule, MergeSectionsPlugin, NonEmptyString, NormalizeFormatPlugin, PackageScopeSchema, PackagesRecordSchema, PendingChangesetSchema, PositiveInteger, PreviewReleaseSchema, ReleasePlanError, ReleasePlanner, ReleasePlannerLive, ReorderSectionsPlugin, RepoSchema, RequiredSectionsRule, ResolvedPackageScopeSchema, ResolvedVersionFileSchema, SectionCategorySchema, SilkChangesetPreset, SilkChangesetTransformPreset, SilkChangesetsRules, UncategorizedContentRule, UrlOrMarkdownLinkSchema, UsernameSchema, VERSION_RE, VersionFileConfigSchema, VersionFileError, VersionFileUpdateRecordSchema, VersionFiles, VersionFilesSchema, VersionOrEmptySchema, VersionTypeSchema, changelogFunctions, changesets_exports, computeWorkspaceDependencyDiffs, deriveMaintenanceReason, gitMergeBase, isPureDependencyChangeset, listPublishablePackageNames, makeBranchAnalyzerTest, makeConfigInspectorTest, makeDepsRegenDefault, makeGitHubTest, makeReleasePlannerTest, serializeDependencyTableToMarkdown };
|
|
@@ -18,7 +18,7 @@ import { Context } from "effect";
|
|
|
18
18
|
* ```typescript
|
|
19
19
|
* import { Effect } from "effect";
|
|
20
20
|
* import type { ChangesetOptions } from "\@savvy-web/changesets";
|
|
21
|
-
* import { ChangelogService, GitHubLive
|
|
21
|
+
* import { ChangelogService, GitHubLive } from "\@savvy-web/changesets";
|
|
22
22
|
*
|
|
23
23
|
* const program = Effect.gen(function* () {
|
|
24
24
|
* const changelog = yield* ChangelogService;
|
|
@@ -92,7 +92,7 @@ var GitHubService = class extends Context.Service()("GitHubService") {};
|
|
|
92
92
|
* @remarks
|
|
93
93
|
* This layer is used by the `\@savvy-web/changesets/changelog` entry point
|
|
94
94
|
* to resolve commit hashes into PR numbers and author attribution. It is
|
|
95
|
-
*
|
|
95
|
+
* used by the changelog formatter's
|
|
96
96
|
* `MainLayer`.
|
|
97
97
|
*
|
|
98
98
|
* @example
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { literalText, stringifyMarkdown } from "./remark-pipeline.js";
|
|
2
1
|
import { DependencyTableRowSchema } from "../schemas/dependency-table.js";
|
|
2
|
+
import { literalText, stringifyMarkdown } from "./remark-pipeline.js";
|
|
3
3
|
import { Schema } from "effect";
|
|
4
4
|
import { toString } from "mdast-util-to-string";
|
|
5
5
|
|