@savvy-web/silk-effects 5.9.0 → 5.9.2

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.
@@ -338,13 +338,10 @@ function applyEffect(root, dryRun, changelogModules, inspector, fs) {
338
338
  version: fresh
339
339
  } : p;
340
340
  });
341
- versionFileUpdates = yield* Effect.try({
342
- try: () => scopes.length > 0 ? VersionFiles.processResolvedVersionFiles(scopes, dryRun) : [],
343
- catch: (e) => new ReleasePlanError({
344
- phase: "apply",
345
- reason: errMsg(e)
346
- })
347
- });
341
+ versionFileUpdates = scopes.length > 0 ? yield* VersionFiles.processResolvedVersionFiles(scopes, dryRun).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.mapError((e) => new ReleasePlanError({
342
+ phase: "apply",
343
+ reason: errMsg(e)
344
+ }))) : [];
348
345
  }
349
346
  return {
350
347
  dryRun,
@@ -1,7 +1,7 @@
1
+ import { VersionFileError } from "../errors.js";
1
2
  import { LegacyVersionFilesSchema } from "../schemas/version-files.js";
2
3
  import { jsonPathGet, jsonPathResolve, parseJsonPath } from "./jsonpath.js";
3
- import { Effect, Path, Schema } from "effect";
4
- import { readFileSync, writeFileSync } from "node:fs";
4
+ import { Effect, FileSystem, Path, Schema } from "effect";
5
5
  import { join, relative, resolve } from "node:path";
6
6
  import { GlobPatternOptions } from "@effected/glob";
7
7
  import { compileAndExpand } from "@effected/walker";
@@ -102,34 +102,32 @@ var VersionFiles = class VersionFiles {
102
102
  * @returns Array of workspace packages with versions
103
103
  */
104
104
  static discoverVersions(cwd, packages) {
105
- const resolvedCwd = resolve(cwd);
106
- const results = [];
107
- const seen = /* @__PURE__ */ new Set();
108
- for (const pkg of packages) {
109
- if (seen.has(pkg.path) || !pkg.version) continue;
110
- seen.add(pkg.path);
111
- results.push({
112
- name: pkg.name,
113
- path: pkg.path,
114
- version: pkg.version
115
- });
116
- }
117
- if (!seen.has(resolvedCwd)) {
118
- const version = readPackageVersion(resolvedCwd);
119
- if (version) {
120
- let rootName = "root";
121
- try {
122
- const pkg = JSON.parse(readFileSync(join(resolvedCwd, "package.json"), "utf-8"));
123
- if (pkg.name) rootName = pkg.name;
124
- } catch {}
105
+ return Effect.gen(function* () {
106
+ const resolvedCwd = resolve(cwd);
107
+ const results = [];
108
+ const seen = /* @__PURE__ */ new Set();
109
+ for (const pkg of packages) {
110
+ if (seen.has(pkg.path) || !pkg.version) continue;
111
+ seen.add(pkg.path);
125
112
  results.push({
126
- name: rootName,
127
- path: resolvedCwd,
128
- version
113
+ name: pkg.name,
114
+ path: pkg.path,
115
+ version: pkg.version
129
116
  });
130
117
  }
131
- }
132
- return results;
118
+ if (!seen.has(resolvedCwd)) {
119
+ const version = yield* readPackageVersion(resolvedCwd);
120
+ if (version) {
121
+ const rootName = yield* readPackageName(resolvedCwd);
122
+ results.push({
123
+ name: rootName,
124
+ path: resolvedCwd,
125
+ version
126
+ });
127
+ }
128
+ }
129
+ return results;
130
+ });
133
131
  }
134
132
  /**
135
133
  * Determine which workspace version applies to a given file path
@@ -224,16 +222,19 @@ var VersionFiles = class VersionFiles {
224
222
  * @see {@link VersionFiles.applyVersionEdit} for the per-path edit
225
223
  */
226
224
  static updateFile(filePath, jsonPaths, version) {
227
- const original = readFileSync(filePath, "utf-8");
228
- const { content, previousValues, totalChanged } = VersionFiles.computeUpdate(original, jsonPaths, version);
229
- if (totalChanged === 0) return;
230
- writeFileSync(filePath, content, "utf-8");
231
- return {
232
- filePath,
233
- jsonPaths,
234
- version,
235
- previousValues
236
- };
225
+ return Effect.gen(function* () {
226
+ const fs = yield* FileSystem.FileSystem;
227
+ const original = yield* fs.readFileString(filePath);
228
+ const { content, previousValues, totalChanged } = VersionFiles.computeUpdate(original, jsonPaths, version);
229
+ if (totalChanged === 0) return;
230
+ yield* fs.writeFileString(filePath, content);
231
+ return {
232
+ filePath,
233
+ jsonPaths,
234
+ version,
235
+ previousValues
236
+ };
237
+ });
237
238
  }
238
239
  /**
239
240
  * Compute the full update for a document without touching the filesystem:
@@ -330,30 +331,15 @@ var VersionFiles = class VersionFiles {
330
331
  */
331
332
  static processVersionFiles(cwd, configs, dryRun = false, packages = []) {
332
333
  return Effect.gen(function* () {
333
- const workspaces = VersionFiles.discoverVersions(cwd, packages);
334
+ const workspaces = yield* VersionFiles.discoverVersions(cwd, packages);
334
335
  const rootVersion = workspaces.find((ws) => ws.path === resolve(cwd))?.version ?? "0.0.0";
335
336
  const resolved = yield* VersionFiles.resolveGlobs(configs, cwd);
336
337
  const updates = [];
337
338
  for (const [filePath, config] of resolved) {
338
339
  const jsonPaths = config.paths ?? ["$.version"];
339
340
  const version = config.package ? workspaces.find((ws) => ws.name === config.package)?.version ?? rootVersion : VersionFiles.resolveVersion(filePath, workspaces, rootVersion);
340
- try {
341
- if (dryRun) {
342
- const content = readFileSync(filePath, "utf-8");
343
- const { previousValues, totalChanged } = VersionFiles.computeUpdate(content, jsonPaths, version);
344
- if (totalChanged > 0) updates.push({
345
- filePath,
346
- jsonPaths,
347
- version,
348
- previousValues
349
- });
350
- } else {
351
- const result = VersionFiles.updateFile(filePath, jsonPaths, version);
352
- if (result) updates.push(result);
353
- }
354
- } catch (error) {
355
- throw new Error(`Failed to update ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
356
- }
341
+ const result = yield* VersionFiles.applyOne(filePath, jsonPaths, version, dryRun).pipe(Effect.orDie);
342
+ if (result) updates.push(result);
357
343
  }
358
344
  return updates;
359
345
  });
@@ -380,28 +366,61 @@ var VersionFiles = class VersionFiles {
380
366
  * @internal
381
367
  */
382
368
  static processResolvedVersionFiles(scopes, dryRun = false) {
383
- const updates = [];
384
- for (const scope of scopes) for (const vf of scope.versionFiles) {
385
- const jsonPaths = vf.paths.length > 0 ? vf.paths : ["$.version"];
386
- for (const filePath of vf.matchedFiles) try {
387
- if (dryRun) {
388
- const content = readFileSync(filePath, "utf-8");
389
- const { previousValues, totalChanged } = VersionFiles.computeUpdate(content, jsonPaths, scope.version);
390
- if (totalChanged > 0) updates.push({
391
- filePath,
392
- jsonPaths,
393
- version: scope.version,
394
- previousValues
395
- });
396
- } else {
397
- const result = VersionFiles.updateFile(filePath, jsonPaths, scope.version);
369
+ return Effect.gen(function* () {
370
+ const updates = [];
371
+ for (const scope of scopes) for (const vf of scope.versionFiles) {
372
+ const jsonPaths = vf.paths.length > 0 ? vf.paths : ["$.version"];
373
+ for (const filePath of vf.matchedFiles) {
374
+ const result = yield* VersionFiles.applyOne(filePath, jsonPaths, scope.version, dryRun);
398
375
  if (result) updates.push(result);
399
376
  }
400
- } catch (error) {
401
- throw new Error(`Failed to update ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
402
377
  }
378
+ return updates;
379
+ });
380
+ }
381
+ /**
382
+ * Apply one version file's update, shared by both process entry points.
383
+ *
384
+ * @remarks
385
+ * Fails TYPED with `VersionFileError`, carrying the offending `filePath`. The two callers then
386
+ * choose their own posture, which is not the same and must not be unified:
387
+ * {@link VersionFiles.processVersionFiles} (legacy) turns it into a DEFECT,
388
+ * matching the synchronous throw it had under `node:fs`, while
389
+ * {@link VersionFiles.processResolvedVersionFiles} leaves it typed because
390
+ * `ReleasePlanner.apply` converts it to a `ReleasePlanError` — a defect there
391
+ * would bypass the inspector's catch and crash `apply()`.
392
+ *
393
+ * @internal
394
+ */
395
+ static applyOne(filePath, jsonPaths, version, dryRun) {
396
+ return Effect.gen(function* () {
397
+ if (dryRun) {
398
+ const content = yield* (yield* FileSystem.FileSystem).readFileString(filePath);
399
+ const { previousValues, totalChanged } = VersionFiles.computeUpdate(content, jsonPaths, version);
400
+ return totalChanged > 0 ? {
401
+ filePath,
402
+ jsonPaths,
403
+ version,
404
+ previousValues
405
+ } : void 0;
406
+ }
407
+ return yield* VersionFiles.updateFile(filePath, jsonPaths, version);
408
+ }).pipe(Effect.mapError((error) => new VersionFileError({
409
+ filePath,
410
+ reason: VersionFiles.describeFailure(error)
411
+ })), Effect.catchDefect((defect) => Effect.fail(new VersionFileError({
412
+ filePath,
413
+ reason: VersionFiles.describeFailure(defect)
414
+ }))));
415
+ }
416
+ /** Render a `PlatformError` the way the old `node:fs` catch rendered an `Error`. */
417
+ static describeFailure(error) {
418
+ if (typeof error === "object" && error !== null) {
419
+ const e = error;
420
+ if (typeof e.message === "string") return e.message;
421
+ if (typeof e.reason === "string") return e.reason;
403
422
  }
404
- return updates;
423
+ return String(error);
405
424
  }
406
425
  };
407
426
  /**
@@ -450,12 +469,32 @@ function expandGlob(source, cwd) {
450
469
  *
451
470
  * @internal
452
471
  */
472
+ /**
473
+ * Read the `name` field from a `package.json` in the given directory, falling
474
+ * back to `"root"` when it is absent, unreadable, or malformed.
475
+ *
476
+ * @param dir - Absolute path to the directory containing `package.json`
477
+ * @returns The package name, or `"root"`
478
+ *
479
+ * @internal
480
+ */
481
+ function readPackageName(dir) {
482
+ return Effect.gen(function* () {
483
+ const raw = yield* (yield* FileSystem.FileSystem).readFileString(join(dir, "package.json"));
484
+ return yield* Effect.try({
485
+ try: () => JSON.parse(raw).name,
486
+ catch: (e) => e
487
+ });
488
+ }).pipe(Effect.map((name) => name ?? "root"), Effect.orElseSucceed(() => "root"));
489
+ }
453
490
  function readPackageVersion(dir) {
454
- try {
455
- return JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")).version;
456
- } catch {
457
- return;
458
- }
491
+ return Effect.gen(function* () {
492
+ const raw = yield* (yield* FileSystem.FileSystem).readFileString(join(dir, "package.json"));
493
+ return yield* Effect.try({
494
+ try: () => JSON.parse(raw).version,
495
+ catch: (e) => e
496
+ });
497
+ }).pipe(Effect.orElseSucceed(() => void 0));
459
498
  }
460
499
 
461
500
  //#endregion
package/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { ChildProcessSpawner } from "effect/unstable/process";
4
4
  import { PackageManagerDetector, PublishConfig, PublishTarget, PublishabilityDetector, VersioningStrategy, WorkspaceDiscovery, WorkspaceDiscoveryFailure, WorkspacePackage, WorkspaceSnapshotAtFailure, WorkspaceSnapshotWorktreeFailure, WorkspaceSnapshots, WorkspaceStateSnapshot, WorkspacesOptions } from "@effected/workspaces";
5
5
  import { Git } from "@effected/git";
6
6
  import { GlobExpansionError } from "@effected/walker";
7
+ import * as PlatformError from "effect/PlatformError";
7
8
  import { YamlFormattingOptions } from "@effected/yaml";
8
9
  import { Section, SectionId } from "@effected/templates";
9
10
  import { ToolDiscovery } from "@effected/commands";
@@ -4808,7 +4809,7 @@ declare class VersionFiles {
4808
4809
  name: string;
4809
4810
  version: string;
4810
4811
  path: string;
4811
- }>): WorkspaceVersion[];
4812
+ }>): Effect.Effect<WorkspaceVersion[], never, FileSystem.FileSystem>;
4812
4813
  /**
4813
4814
  * Determine which workspace version applies to a given file path
4814
4815
  * using longest-prefix matching.
@@ -4883,7 +4884,7 @@ declare class VersionFiles {
4883
4884
  * @see {@link jsonPathResolve} for concrete-path enumeration
4884
4885
  * @see {@link VersionFiles.applyVersionEdit} for the per-path edit
4885
4886
  */
4886
- static updateFile(filePath: string, jsonPaths: readonly string[], version: string): VersionFileUpdate | undefined;
4887
+ static updateFile(filePath: string, jsonPaths: readonly string[], version: string): Effect.Effect<VersionFileUpdate | undefined, PlatformError.PlatformError, FileSystem.FileSystem>;
4887
4888
  /**
4888
4889
  * Compute the full update for a document without touching the filesystem:
4889
4890
  * the edited content, the previous values at every matched path, and how
@@ -4965,7 +4966,24 @@ declare class VersionFiles {
4965
4966
  *
4966
4967
  * @internal
4967
4968
  */
4968
- static processResolvedVersionFiles(scopes: ReadonlyArray<ResolvedPackageScope>, dryRun?: boolean): VersionFileUpdate[];
4969
+ static processResolvedVersionFiles(scopes: ReadonlyArray<ResolvedPackageScope>, dryRun?: boolean): Effect.Effect<VersionFileUpdate[], VersionFileError, FileSystem.FileSystem>;
4970
+ /**
4971
+ * Apply one version file's update, shared by both process entry points.
4972
+ *
4973
+ * @remarks
4974
+ * Fails TYPED with `VersionFileError`, carrying the offending `filePath`. The two callers then
4975
+ * choose their own posture, which is not the same and must not be unified:
4976
+ * {@link VersionFiles.processVersionFiles} (legacy) turns it into a DEFECT,
4977
+ * matching the synchronous throw it had under `node:fs`, while
4978
+ * {@link VersionFiles.processResolvedVersionFiles} leaves it typed because
4979
+ * `ReleasePlanner.apply` converts it to a `ReleasePlanError` — a defect there
4980
+ * would bypass the inspector's catch and crash `apply()`.
4981
+ *
4982
+ * @internal
4983
+ */
4984
+ private static applyOne;
4985
+ /** Render a `PlatformError` the way the old `node:fs` catch rendered an `Error`. */
4986
+ private static describeFailure;
4969
4987
  }
4970
4988
  //#endregion
4971
4989
  //#region ../../node_modules/.pnpm/micromark-util-types@2.0.2/node_modules/micromark-util-types/index.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk-effects",
3
- "version": "5.9.0",
3
+ "version": "5.9.2",
4
4
  "private": false,
5
5
  "description": "Shared Effect library for Silk Suite conventions",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
@@ -33,15 +33,15 @@
33
33
  "@changesets/config": "^4.0.0",
34
34
  "@changesets/get-github-info": "^1.0.0",
35
35
  "@changesets/get-release-plan": "^5.0.0",
36
- "@effected/commands": "^0.4.0",
37
- "@effected/git": "^0.8.0",
38
- "@effected/glob": "^0.3.0",
39
- "@effected/jsonc": "^0.6.0",
40
- "@effected/package-json": "^0.9.0",
41
- "@effected/templates": "^0.2.0",
42
- "@effected/walker": "^0.4.0",
43
- "@effected/workspaces": "^0.13.0",
44
- "@effected/yaml": "^0.8.0",
36
+ "@effected/commands": "^0.5.0",
37
+ "@effected/git": "^0.9.0",
38
+ "@effected/glob": "^0.4.0",
39
+ "@effected/jsonc": "^0.7.0",
40
+ "@effected/package-json": "^0.10.0",
41
+ "@effected/templates": "^0.3.0",
42
+ "@effected/walker": "^0.5.0",
43
+ "@effected/workspaces": "^0.14.0",
44
+ "@effected/yaml": "^0.10.0",
45
45
  "@manypkg/get-packages": "^3.1.0",
46
46
  "mdast-util-heading-range": "^4.0.0",
47
47
  "mdast-util-to-string": "^4.0.0",
@@ -54,6 +54,6 @@
54
54
  "unist-util-visit": "^5.1.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "effect": "4.0.0-beta.107"
57
+ "effect": "4.0.0-rc.109"
58
58
  }
59
59
  }