rolldown-pnpm-config 2.2.0 → 2.2.1

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.
@@ -14,10 +14,10 @@ import { printView } from "../render/print.js";
14
14
  import { failureDoc } from "../render/report.js";
15
15
  import { findConfigFiles, pickConfigCandidate } from "../select-file.js";
16
16
  import { overlayWorkspace } from "../workspace-overlay.js";
17
- import { Data, Effect, Option, Predicate } from "effect";
17
+ import { Data, Effect, FileSystem, Option, Predicate } from "effect";
18
18
  import { dirname, relative } from "node:path";
19
19
  import { CliDoc, CliMessage } from "@effected/cli";
20
- import { existsSync, writeFileSync } from "node:fs";
20
+ import { existsSync } from "node:fs";
21
21
  import { Argument, Command, Flag } from "effect/cli";
22
22
 
23
23
  // src/cli/commands/export.ts
@@ -90,10 +90,7 @@ function runExport(opts) {
90
90
  diff,
91
91
  report
92
92
  };
93
- yield* Effect.try({
94
- try: () => writeFileSync(path, rendered, "utf8"),
95
- catch: () => new ExportError({ message: `Cannot write ${path}` })
96
- });
93
+ yield* (yield* FileSystem.FileSystem).writeFileString(path, rendered).pipe(Effect.mapError(() => new ExportError({ message: `Cannot write ${path}` })));
97
94
  return {
98
95
  path,
99
96
  rendered,
@@ -18,10 +18,9 @@ import { summaryDoc } from "../summary.js";
18
18
  import { validateEdits } from "../validate.js";
19
19
  import { buildWalkItems } from "../walk-plan.js";
20
20
  import { findWorkspaceRoot, makeWorkspaceResolver } from "../workspace-resolve.js";
21
- import { Clock, Data, Effect, Option, Result } from "effect";
21
+ import { Clock, Data, Effect, FileSystem, Option, Result } from "effect";
22
22
  import { dirname } from "node:path";
23
23
  import { CliDoc, CliExit, CliFormat, CliInteractive, CliMessage, Doc, Fmt } from "@effected/cli";
24
- import { readFileSync, writeFileSync } from "node:fs";
25
24
  import { Argument, Command, Flag } from "effect/cli";
26
25
  import { CliUi } from "@effected/cli/ui";
27
26
  import { ReleaseAgeGate } from "@effected/npm";
@@ -71,13 +70,14 @@ var CheckFailedError = class extends Data.TaggedError("CheckFailedError") {
71
70
  return failureDoc(`${CHECK_FAILED_LABEL}\n${indent(this.message)}`);
72
71
  }
73
72
  };
73
+ /** Write the rewritten config source back to `file`. */
74
+ function writeSource(file, next) {
75
+ return Effect.flatMap(FileSystem.FileSystem, (fs) => fs.writeFileString(file, next).pipe(Effect.mapError(() => new UpgradeError({ message: `Cannot write ${file}` }))));
76
+ }
74
77
  /** Read a config file and statically discover its catalog entries. @internal */
75
78
  function readCatalogSource(file) {
76
79
  return Effect.gen(function* () {
77
- const source = yield* Effect.try({
78
- try: () => readFileSync(file, "utf8"),
79
- catch: () => new UpgradeError({ message: `Cannot read ${file}` })
80
- });
80
+ const source = yield* (yield* FileSystem.FileSystem).readFileString(file).pipe(Effect.mapError(() => new UpgradeError({ message: `Cannot read ${file}` })));
81
81
  const { entries, skipped } = yield* Effect.try({
82
82
  try: () => discoverCatalogEntries(source, file),
83
83
  catch: (e) => new UpgradeError({ message: Fmt.describe(e) })
@@ -165,16 +165,15 @@ function resolveGatedVersions(entries, resolver, gate, now, onProgress, workspac
165
165
  * @internal
166
166
  */
167
167
  function resolveProgress(report) {
168
- const noun = (n) => `${n} package${n === 1 ? "" : "s"}`;
169
168
  const finished = (total) => report({
170
169
  _tag: "Finished",
171
- label: `Resolved ${noun(total)}`
170
+ label: `Resolved ${Fmt.plural(total, "package")}`
172
171
  });
173
172
  return (resolved, total) => {
174
173
  if (resolved === 0) {
175
174
  const begin = report({
176
175
  _tag: "Phase",
177
- label: `Resolving ${noun(total)}`,
176
+ label: `Resolving ${Fmt.plural(total, "package")}`,
178
177
  total
179
178
  });
180
179
  return total === 0 ? Effect.andThen(begin, finished(total)) : begin;
@@ -283,10 +282,7 @@ function runUpgrade(opts) {
283
282
  const allEdits = [...accepted, ...interopEdits];
284
283
  if (allEdits.length > 0 && !opts.dryRun) {
285
284
  const next = applyEdits(source, allEdits);
286
- yield* Effect.try({
287
- try: () => writeFileSync(opts.file, next, "utf8"),
288
- catch: () => new UpgradeError({ message: `Cannot write ${opts.file}` })
289
- });
285
+ yield* writeSource(opts.file, next);
290
286
  }
291
287
  return {
292
288
  updated: changedSpans.size,
@@ -316,11 +312,7 @@ function applyInteropAndDecisions(file, source, nonInteropEdits, interopEdits) {
316
312
  return Effect.gen(function* () {
317
313
  const edits = [...nonInteropEdits, ...interopEdits];
318
314
  if (edits.length === 0) return;
319
- const next = applyEdits(source, edits);
320
- yield* Effect.try({
321
- try: () => writeFileSync(file, next, "utf8"),
322
- catch: () => new UpgradeError({ message: `Cannot write ${file}` })
323
- });
315
+ yield* writeSource(file, applyEdits(source, edits));
324
316
  });
325
317
  }
326
318
  /**
package/cli/diff/build.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Predicate } from "effect";
1
+ import { Order, Predicate } from "effect";
2
2
 
3
3
  // src/cli/diff/build.ts
4
4
  const isObject = Predicate.isObject;
@@ -49,7 +49,7 @@ function diffArray(key, path, before, after, tag) {
49
49
  const here = [...path, key];
50
50
  const b = new Set(before.map(String));
51
51
  const a = new Set(after.map(String));
52
- const children = [.../* @__PURE__ */ new Set([...b, ...a])].sort((x, y) => x.localeCompare(y)).map((el) => {
52
+ const children = [.../* @__PURE__ */ new Set([...b, ...a])].sort(Order.String).map((el) => {
53
53
  const inB = b.has(el);
54
54
  const inA = a.has(el);
55
55
  const kind = inB && inA ? "unchanged" : inA ? "added" : "removed";
@@ -73,7 +73,7 @@ function diffArray(key, path, before, after, tag) {
73
73
  function diffValue(key, path, before, after, tag) {
74
74
  const here = [...path, key];
75
75
  if (isObject(before) && isObject(after)) {
76
- const children = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort((x, y) => x.localeCompare(y)).map((k) => {
76
+ const children = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort(Order.String).map((k) => {
77
77
  if (!(k in before)) return uniform(k, here, after[k], "added");
78
78
  if (!(k in after)) return uniform(k, here, before[k], "removed");
79
79
  return diffValue(k, here, before[k], after[k]);
@@ -104,7 +104,7 @@ function diffValue(key, path, before, after, tag) {
104
104
  * @internal
105
105
  */
106
106
  function buildDiff(before, after, meta) {
107
- const children = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort((x, y) => x.localeCompare(y)).map((k) => {
107
+ const children = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].sort(Order.String).map((k) => {
108
108
  const tag = meta.localKeys.has(k) ? "local" : meta.managedKeys.has(k) ? void 0 : "unmanaged";
109
109
  if (!(k in before)) return uniform(k, [], after[k], "added", tag);
110
110
  if (!(k in after)) return uniform(k, [], before[k], "removed", tag);
@@ -1,5 +1,5 @@
1
1
  import { bareVersion, parseRange, parseVersion } from "../semver-util.js";
2
- import "./interop.js";
2
+ import { lowestVersion } from "./interop.js";
3
3
  import { Effect } from "effect";
4
4
 
5
5
  // src/cli/interop-live.ts
@@ -28,19 +28,7 @@ function computeGroupPeers(model, selected) {
28
28
  for (const m of model.members) {
29
29
  const v = selected.get(m);
30
30
  if (v === void 0) continue;
31
- const declared = declaredFloors.get(m);
32
- if (declared?.length) {
33
- let minStr = declared[0];
34
- let minSv = model.ver.get(minStr) ?? null;
35
- for (const f of declared.slice(1)) {
36
- const sv = model.ver.get(f) ?? null;
37
- if (sv && (minSv === null || sv.compare(minSv) < 0)) {
38
- minSv = sv;
39
- minStr = f;
40
- }
41
- }
42
- peer.set(m, `^${minStr}`);
43
- } else peer.set(m, `^${v}`);
31
+ peer.set(m, `^${lowestVersion(declaredFloors.get(m) ?? []) ?? v}`);
44
32
  }
45
33
  const conflict = /* @__PURE__ */ new Map();
46
34
  for (const m of model.members) {
package/cli/interop.js CHANGED
@@ -50,7 +50,13 @@ function deriveFloors(resolved, fetchPeer) {
50
50
  return out;
51
51
  });
52
52
  }
53
- /** The lowest parseable version string in `list`, or null when none parses. */
53
+ /**
54
+ * The lowest parseable version string in `list`, or null when none parses.
55
+ * Shared by the `--yes` resolver and the interactive table so both write the
56
+ * same peer floor.
57
+ *
58
+ * @internal
59
+ */
54
60
  function lowestVersion(list) {
55
61
  let best = null;
56
62
  for (const f of list) {
@@ -223,4 +229,4 @@ function buildInteropEdits(entries, result) {
223
229
  return edits;
224
230
  }
225
231
 
226
- export { buildInteropEdits, deriveFloors, interopEntryChanged, makePeerFetcher, resolveGroup, runInterop };
232
+ export { buildInteropEdits, deriveFloors, interopEntryChanged, lowestVersion, makePeerFetcher, resolveGroup, runInterop };
@@ -1,8 +1,7 @@
1
1
  import { parseWorkspace } from "./workspace-file.js";
2
2
  import { evaluatePluginConfig } from "./evaluate.js";
3
- import { Effect, Predicate } from "effect";
3
+ import { Effect, FileSystem, Predicate } from "effect";
4
4
  import { Fmt } from "@effected/cli";
5
- import { existsSync, readFileSync } from "node:fs";
6
5
 
7
6
  // src/cli/load-config.ts
8
7
  /**
@@ -11,22 +10,26 @@ import { existsSync, readFileSync } from "node:fs";
11
10
  * parse the workspace file when present. `mkError` wraps each failure
12
11
  * message in the command's own error type.
13
12
  *
13
+ * IO goes through the platform `FileSystem`. Only a workspace file that is
14
+ * NOT FOUND reads as absent (`fs.exists` maps `NotFound` to `false`); an
15
+ * existence check that fails for any other reason (EACCES, ENOTDIR, EIO) is a
16
+ * `Cannot read or parse` failure, never a silent "create it fresh".
17
+ *
14
18
  * @internal
15
19
  */
16
20
  function loadConfigAndWorkspace(opts, mkError) {
17
21
  return Effect.gen(function* () {
18
- const configSource = yield* Effect.try({
19
- try: () => readFileSync(opts.configFile, "utf8"),
20
- catch: () => mkError(`Cannot read ${opts.configFile}`)
21
- });
22
+ const fs = yield* FileSystem.FileSystem;
23
+ const configSource = yield* fs.readFileString(opts.configFile).pipe(Effect.mapError(() => mkError(`Cannot read ${opts.configFile}`)));
22
24
  const { config, errors } = evaluatePluginConfig(configSource, opts.configFile);
23
25
  if (config === null) return yield* Effect.fail(mkError(`No PnpmConfigPlugin call found in ${opts.configFile}`));
24
26
  if (errors.length > 0) return yield* Effect.fail(mkError(`Non-literal config values: ${errors.join("; ")}`));
25
27
  const path = opts.workspacePath;
26
- const parsed = existsSync(path) ? yield* Effect.try({
27
- try: () => parseWorkspace(readFileSync(path, "utf8")),
28
- catch: (e) => mkError(`Cannot read or parse ${path}: ${Fmt.causeMessage(e) ?? Fmt.describe(e)}`)
29
- }) : {};
28
+ const cannotRead = (e) => mkError(`Cannot read or parse ${path}: ${Fmt.errorText(e)}`);
29
+ const parsed = (yield* fs.exists(path).pipe(Effect.mapError(cannotRead))) ? yield* fs.readFileString(path).pipe(Effect.mapError(cannotRead), Effect.flatMap((text) => Effect.try({
30
+ try: () => parseWorkspace(text),
31
+ catch: cannotRead
32
+ }))) : {};
30
33
  return {
31
34
  config,
32
35
  localCfg: Predicate.isObject(config.local) ? config.local : void 0,
@@ -1,4 +1,4 @@
1
- import { Predicate } from "effect";
1
+ import { Array as Array$1, Predicate } from "effect";
2
2
 
3
3
  // src/cli/local-merge.ts
4
4
  /** Default protocols whose existing-file override entries are preserved. @internal */
@@ -30,9 +30,7 @@ function combine(managed, value, strategy) {
30
30
  if (Array.isArray(managed) || Array.isArray(value)) {
31
31
  const m = Array.isArray(managed) ? managed : [];
32
32
  const v = Array.isArray(value) ? value : [];
33
- if (strategy === "union") return [.../* @__PURE__ */ new Set([...m, ...v])];
34
- const drop = new Set(v.map((x) => JSON.stringify(x)));
35
- return m.filter((x) => !drop.has(JSON.stringify(x)));
33
+ return strategy === "union" ? Array$1.dedupe(Array$1.appendAll(m, v)) : Array$1.difference(m, v);
36
34
  }
37
35
  const m = Predicate.isObject(managed) ? managed : {};
38
36
  const v = Predicate.isObject(value) ? value : {};
package/cli/resolve.js CHANGED
@@ -86,7 +86,7 @@ const RegistryResolverLive = Layer.effect(RegistryResolver, Effect.gen(function*
86
86
  "--json"
87
87
  ])).pipe(Effect.map(stripPnpmNotices), Effect.mapError((e) => new ResolveError({
88
88
  pkg,
89
- message: Fmt.causeMessage(e) ?? Fmt.describe(e)
89
+ message: Fmt.errorText(e)
90
90
  })));
91
91
  return {
92
92
  versions: (pkg) => pnpmView(pkg, pkg, "versions").pipe(Effect.flatMap((out) => parseVersions(pkg, out))),
@@ -1,10 +1,9 @@
1
1
  import { discoverCatalogEntries } from "./discover.js";
2
- import { Effect, Result } from "effect";
2
+ import { Effect, FileSystem, Result } from "effect";
3
3
  import { join } from "node:path";
4
4
  import { GlobPattern, GlobPatternOptions } from "@effected/glob";
5
5
  import { descendSync } from "@effected/walker";
6
6
  import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
7
- import { readFileSync } from "node:fs";
8
7
 
9
8
  // src/cli/select-file.ts
10
9
  /** Top-level `.ts` FILES of a directory, no dotfiles, sorted. */
@@ -20,7 +19,8 @@ const TS_FILES = Result.getOrThrow(GlobPattern.compileResult("*.ts", GlobPattern
20
19
  * @internal
21
20
  */
22
21
  function findConfigFiles(dir) {
23
- return Effect.sync(() => {
22
+ return Effect.gen(function* () {
23
+ const fs = yield* FileSystem.FileSystem;
24
24
  const names = Result.getOrElse(descendSync(TS_FILES, {
25
25
  cwd: dir,
26
26
  ...nodeWalkerSyncOps
@@ -29,11 +29,7 @@ function findConfigFiles(dir) {
29
29
  for (const name of names) {
30
30
  if (name.endsWith(".d.ts")) continue;
31
31
  const path = join(dir, name);
32
- try {
33
- const source = readFileSync(path, "utf8");
34
- const { entries } = discoverCatalogEntries(source, path);
35
- if (entries.length > 0) matches.push(path);
36
- } catch {}
32
+ if (yield* fs.readFileString(path).pipe(Effect.flatMap((source) => Effect.try(() => discoverCatalogEntries(source, path).entries.length > 0)), Effect.orElseSucceed(() => false))) matches.push(path);
37
33
  }
38
34
  return matches;
39
35
  });
@@ -1,6 +1,7 @@
1
1
  import { canonicalize } from "./workspace-file.js";
2
2
  import { row, tone } from "./render/tone.js";
3
3
  import { scalarText } from "./diff/render.js";
4
+ import { Predicate } from "effect";
4
5
  import { Doc } from "@effected/cli";
5
6
 
6
7
  // src/cli/simulated-view.ts
@@ -42,7 +43,7 @@ function annotation(entry) {
42
43
  /** Flatten one key/value into YAML-shaped plain lines; `ann` annotates the head. */
43
44
  function flatten(key, value, depth, ann) {
44
45
  if (Array.isArray(value)) return [row(" ", depth, [tone(`${key}:`, "plain"), ...ann]), ...value.map((el) => row(" ", depth + 1, [tone(`- ${scalarText(el)}`, "plain")]))];
45
- if (value !== null && typeof value === "object") return [row(" ", depth, [tone(`${key}:`, "plain"), ...ann]), ...Object.entries(value).flatMap(([k, v]) => flatten(k, v, depth + 1, []))];
46
+ if (Predicate.isObject(value)) return [row(" ", depth, [tone(`${key}:`, "plain"), ...ann]), ...Object.entries(value).flatMap(([k, v]) => flatten(k, v, depth + 1, []))];
46
47
  return [row(" ", depth, [tone(`${key}: ${scalarText(value)}`, "plain"), ...ann])];
47
48
  }
48
49
  /**
package/cli/version.js CHANGED
@@ -6,6 +6,6 @@
6
6
  *
7
7
  * @internal
8
8
  */
9
- const CLI_VERSION = "2.2.0";
9
+ const CLI_VERSION = "2.2.1";
10
10
 
11
11
  export { CLI_VERSION };
@@ -1,6 +1,6 @@
1
- import { Result } from "effect";
2
- import { dirname, join } from "node:path";
3
- import { existsSync } from "node:fs";
1
+ import { Order, Predicate, Result } from "effect";
2
+ import { locateWorkspaceRootSync } from "@effected/workspaces";
3
+ import { nodeSyncOps } from "@effected/workspaces/node-sync";
4
4
  import { Yaml, YamlStringifyOptions } from "@effected/yaml";
5
5
 
6
6
  // src/cli/workspace-file.ts
@@ -23,31 +23,28 @@ function allPrimitive(arr) {
23
23
  function canonicalize(value) {
24
24
  if (Array.isArray(value)) {
25
25
  const mapped = value.map(canonicalize);
26
- return allPrimitive(mapped) ? [...mapped].sort((a, b) => String(a).localeCompare(String(b))) : mapped;
26
+ return allPrimitive(mapped) ? [...mapped].sort((a, b) => Order.String(String(a), String(b))) : mapped;
27
27
  }
28
- if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, canonicalize(v)]));
28
+ if (Predicate.isObject(value)) return Object.fromEntries(Object.entries(value).sort(([a], [b]) => Order.String(a, b)).map(([k, v]) => [k, canonicalize(v)]));
29
29
  return value;
30
30
  }
31
31
  /**
32
32
  * Walk up from `startDir` to the nearest directory containing a
33
- * pnpm-workspace.yaml; returns the file path or null.
33
+ * pnpm-workspace.yaml; returns the file path or null. A `package.json`
34
+ * `workspaces` field is not a marker here: this tool targets pnpm only.
34
35
  *
35
36
  * @internal
36
37
  */
37
38
  function findWorkspaceFile(startDir) {
38
- let dir = startDir;
39
- for (;;) {
40
- const candidate = join(dir, FILENAME);
41
- if (existsSync(candidate)) return candidate;
42
- const parent = dirname(dir);
43
- if (parent === dir) return null;
44
- dir = parent;
45
- }
39
+ return locateWorkspaceRootSync(startDir, {
40
+ ...nodeSyncOps,
41
+ markers: [FILENAME]
42
+ })?.path ?? null;
46
43
  }
47
44
  /** Parse pnpm-workspace.yaml source; empty/whitespace yields an empty object. @internal */
48
45
  function parseWorkspace(source) {
49
46
  const parsed = Result.getOrThrow(Yaml.parseResult(source));
50
- return parsed && typeof parsed === "object" ? parsed : {};
47
+ return Predicate.isObject(parsed) ? parsed : {};
51
48
  }
52
49
  /** Render a workspace object: deterministic key sort + yaml.stringify. @internal */
53
50
  function renderWorkspace(obj) {
@@ -1,13 +1,12 @@
1
1
  import { parseVersion } from "../semver-util.js";
2
- import { findWorkspaceFile } from "./workspace-file.js";
3
2
  import { ResolveError } from "./resolve.js";
4
3
  import { Effect, Layer, Result } from "effect";
5
- import { dirname, join, resolve } from "node:path";
4
+ import { join, resolve } from "node:path";
6
5
  import { GlobPattern, GlobPatternOptions } from "@effected/glob";
7
6
  import { descendSync } from "@effected/walker";
8
7
  import { nodeWalkerSyncOps } from "@effected/walker/node-sync";
9
8
  import { readFileSync } from "node:fs";
10
- import { getWorkspacePackagesSync } from "@effected/workspaces";
9
+ import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
11
10
  import { nodeSyncOps } from "@effected/workspaces/node-sync";
12
11
 
13
12
  // src/cli/workspace-resolve.ts
@@ -159,8 +158,10 @@ function makeWorkspaceResolver(rootDir) {
159
158
  * @internal
160
159
  */
161
160
  function findWorkspaceRoot(startDir) {
162
- const file = findWorkspaceFile(resolve(startDir));
163
- return file === null ? resolve(startDir) : dirname(file);
161
+ return findWorkspaceRootSync(startDir, {
162
+ ...nodeSyncOps,
163
+ markers: ["pnpm-workspace.yaml"]
164
+ }) ?? resolve(startDir);
164
165
  }
165
166
 
166
167
  export { findWorkspaceRoot, makeWorkspaceResolver, readManifests, readWorkspaceVersions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-pnpm-config",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "private": false,
5
5
  "description": "A dogfooding example of our plugin",
6
6
  "repository": {
@@ -35,16 +35,16 @@
35
35
  "rolldown-pnpm-config": "bin/rolldown-pnpm-config.js"
36
36
  },
37
37
  "dependencies": {
38
- "@effect/platform-node": "^4.0.6",
39
- "@effected/cli": "^0.23.0",
40
- "@effected/env": "^0.6.0",
41
- "@effected/glob": "^0.15.0",
42
- "@effected/npm": "^0.27.1",
43
- "@effected/semver": "^0.18.0",
44
- "@effected/walker": "^0.21.0",
45
- "@effected/workspaces": "^0.39.1",
46
- "@effected/yaml": "^0.25.1",
47
- "effect": "^4.0.6",
38
+ "@effect/platform-node": "^4.0.7",
39
+ "@effected/cli": "^0.24.0",
40
+ "@effected/env": "^0.7.0",
41
+ "@effected/glob": "^0.16.0",
42
+ "@effected/npm": "^0.28.0",
43
+ "@effected/semver": "^0.19.0",
44
+ "@effected/walker": "^0.22.0",
45
+ "@effected/workspaces": "^0.40.0",
46
+ "@effected/yaml": "^0.26.0",
47
+ "effect": "^4.0.7",
48
48
  "ink": "^8.0.0",
49
49
  "oxc-parser": "^0.156.0",
50
50
  "react": "^19.3.1"
@@ -1,5 +1,6 @@
1
1
  import { rangeOf } from "../catalogs.js";
2
2
  import { bareVersion } from "../semver-util.js";
3
+ import { Predicate } from "effect";
3
4
 
4
5
  // src/plugin/allowed-versions.ts
5
6
  /** An exact version: no range operator, no wildcard — `X.Y.Z` with an optional prerelease. */
@@ -43,7 +44,7 @@ function deriveAllowedVersions(catalogs, directives) {
43
44
  * @internal
44
45
  */
45
46
  function resolvePeerDependencyRules(value, catalogs) {
46
- if (value === null || typeof value !== "object" || !("allowedVersionsFromCatalogs" in value)) return value;
47
+ if (!Predicate.isObject(value) || !("allowedVersionsFromCatalogs" in value)) return value;
47
48
  const { allowedVersionsFromCatalogs, ...rest } = value;
48
49
  const merged = {
49
50
  ...deriveAllowedVersions(catalogs, allowedVersionsFromCatalogs),
package/plugin/freeze.js CHANGED
@@ -3,7 +3,7 @@ import { DESCRIPTORS, deriveSchemas } from "../descriptors/index.js";
3
3
  import { FIELD_REGISTRY } from "../registry.js";
4
4
  import { resolvePeerDependencyRules } from "./allowed-versions.js";
5
5
  import { resolveOverrides } from "./overrides-from-catalogs.js";
6
- import { Data, Effect, Schema } from "effect";
6
+ import { Data, Effect, Predicate, Schema } from "effect";
7
7
  import { Fmt } from "@effected/cli";
8
8
 
9
9
  // src/plugin/freeze.ts
@@ -33,7 +33,7 @@ const WRAPPED_KEYS = /* @__PURE__ */ new Set([
33
33
  * @internal
34
34
  */
35
35
  function isWrappedField(input) {
36
- if (input === null || typeof input !== "object") return false;
36
+ if (!Predicate.isObject(input)) return false;
37
37
  const keys = Object.keys(input);
38
38
  return keys.includes("value") && keys.every((k) => WRAPPED_KEYS.has(k));
39
39
  }
@@ -1,5 +1,6 @@
1
1
  import { rangeOf } from "../catalogs.js";
2
2
  import { bareVersion } from "../semver-util.js";
3
+ import { Predicate } from "effect";
3
4
 
4
5
  // src/plugin/overrides-from-catalogs.ts
5
6
  /** A plain release version: `X.Y.Z`, no prerelease, no build metadata. */
@@ -58,7 +59,7 @@ function deriveOverrides(catalogs, directives) {
58
59
  function resolveOverrides(authored, directives, catalogs) {
59
60
  if (directives === void 0) return authored;
60
61
  const derived = deriveOverrides(catalogs, directives);
61
- const manual = authored !== null && typeof authored === "object" ? authored : {};
62
+ const manual = Predicate.isObject(authored) ? authored : {};
62
63
  return {
63
64
  ...derived,
64
65
  ...manual
@@ -1,8 +1,10 @@
1
+ import { Order, Predicate } from "effect";
2
+
1
3
  // src/plugin/serialize.ts
2
4
  /** Recursively sort object keys for deterministic output; arrays keep order. */
3
5
  function sortKeys(value) {
4
6
  if (Array.isArray(value)) return value.map(sortKeys);
5
- if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, sortKeys(v)]));
7
+ if (Predicate.isObject(value)) return Object.fromEntries(Object.entries(value).sort(([a], [b]) => Order.String(a, b)).map(([k, v]) => [k, sortKeys(v)]));
6
8
  return value;
7
9
  }
8
10
  /** Source for the `catalogs` virtual module: a sorted Map literal (plain-JS branch). */
@@ -1,9 +1,11 @@
1
1
  // src/runtime/strategies/arrays.ts
2
+ /** Code-unit order: locale-independent, so the render is the same on every machine. */
3
+ const byCodeUnit = (a, b) => a < b ? -1 : a > b ? 1 : 0;
2
4
  /** Union `managed` with `local` (when present), deduped and sorted for a stable render. @internal */
3
5
  function unionSort(managed, local) {
4
6
  const set = new Set(managed);
5
7
  for (const item of local ?? []) set.add(item);
6
- return [...set].sort((a, b) => a.localeCompare(b));
8
+ return [...set].sort(byCodeUnit);
7
9
  }
8
10
  /**
9
11
  * Union + sort string arrays; child entries are added to the managed set. Quiet.
@@ -24,7 +26,7 @@ const arrayRecordUnion = (base, local) => {
24
26
  const child = local ?? {};
25
27
  const keys = /* @__PURE__ */ new Set([...Object.keys(managed), ...Object.keys(child)]);
26
28
  const result = {};
27
- for (const key of [...keys].sort((a, b) => a.localeCompare(b))) {
29
+ for (const key of [...keys].sort(byCodeUnit)) {
28
30
  const merged = unionSort(managed[key] ?? [], child[key]);
29
31
  if (merged.length > 0) result[key] = merged;
30
32
  }
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.59.4"
8
+ "packageVersion": "7.60.0"
9
9
  }
10
10
  ]
11
11
  }