rolldown-pnpm-config 2.0.1 → 2.0.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.
@@ -1,7 +1,7 @@
1
1
  import { bareVersion } from "../../semver-util.js";
2
2
  import { WorkingDirectory } from "../cwd.js";
3
+ import { RegistryResolver } from "../resolve.js";
3
4
  import { evaluatePluginConfig } from "../evaluate.js";
4
- import { printDoc } from "../render/print.js";
5
5
  import { failureDoc, warningDoc } from "../render/report.js";
6
6
  import { discoverCatalogEntries } from "../discover.js";
7
7
  import { filterEntriesByCatalog, findConfigFiles, pickConfigCandidate } from "../select-file.js";
@@ -13,13 +13,12 @@ import { buildGroupModel, computeGroupPeers } from "../interop-live.js";
13
13
  import { derivePeerRange } from "../peer-range.js";
14
14
  import { defaultPick, planEntry } from "../plan.js";
15
15
  import { parsePnpmGate, readConfigReleaseAge } from "../release-age.js";
16
- import { RegistryResolver, RegistryResolverLive } from "../resolve.js";
17
16
  import { applyEdits } from "../rewrite.js";
18
17
  import { summaryDoc } from "../summary.js";
19
18
  import { validateEdits } from "../validate.js";
20
19
  import { buildWalkItems } from "../walk-plan.js";
21
20
  import { findWorkspaceRoot, makeWorkspaceResolver } from "../workspace-resolve.js";
22
- import { Console, Data, Effect, Option, Result, Runtime } from "effect";
21
+ import { Clock, Console, Data, Effect, Option, Result, Runtime } from "effect";
23
22
  import { readFileSync, writeFileSync } from "node:fs";
24
23
  import { dirname } from "node:path";
25
24
  import { CliDoc, CliExit, CliInteractive, CliMessage, Doc } from "@effected/cli";
@@ -208,7 +207,7 @@ function runUpgrade(opts) {
208
207
  return Effect.gen(function* () {
209
208
  const { source, entries, skipped } = yield* readCatalogSource(opts.file);
210
209
  const gate = yield* computeGate(source, opts.file, opts.resolver);
211
- const versionsByPkg = yield* resolveGatedVersions(entries, opts.resolver, gate, Date.now(), opts.onProgress, opts.workspaceResolver);
210
+ const versionsByPkg = yield* resolveGatedVersions(entries, opts.resolver, gate, yield* Clock.currentTimeMillis, opts.onProgress, opts.workspaceResolver);
212
211
  if (versionsByPkg.unresolved.length > 0) return yield* Effect.fail(new UpgradeError({ message: unresolvedMessage(versionsByPkg.unresolved) }));
213
212
  const edits = [];
214
213
  const interopEdits = [];
@@ -388,7 +387,7 @@ function runUpgradePreview(opts) {
388
387
  return Effect.gen(function* () {
389
388
  const { source, entries } = yield* readCatalogSource(opts.file);
390
389
  const gate = yield* computeGate(source, opts.file, opts.resolver);
391
- const versions = yield* resolveGatedVersions(entries, opts.resolver, gate, Date.now(), void 0, opts.workspaceResolver);
390
+ const versions = yield* resolveGatedVersions(entries, opts.resolver, gate, yield* Clock.currentTimeMillis, void 0, opts.workspaceResolver);
392
391
  const items = yield* buildWalkItems(entries, versions.gated).pipe(Effect.mapError((e) => new UpgradeError({ message: e.message })));
393
392
  return {
394
393
  doc: summaryDoc(projectDecisions(items, opts.full)),
@@ -415,7 +414,7 @@ function checkOutcome(changed) {
415
414
  exitCode: 1,
416
415
  doc: [
417
416
  Doc.line(`Catalog drift detected in ${changed.length} package(s):`),
418
- Doc.lines(changed.map((c) => ` ${c.name} (${c.source})`)),
417
+ Doc.lines(changed.map((c) => ` ${c.name} (${c.source})`), { wrap: false }),
419
418
  Doc.line([
420
419
  "Run ",
421
420
  Doc.code("rolldown-pnpm-config upgrade --yes"),
@@ -546,7 +545,7 @@ function resolveTargetFile(fileOpt) {
546
545
  }
547
546
  /** Print the unresolved-packages warning to stderr, when there is one. */
548
547
  function warnUnresolved(unresolved) {
549
- return unresolved.length > 0 ? printDoc(warningDoc(unresolvedMessage(unresolved)), { stream: "stderr" }) : Effect.void;
548
+ return unresolved.length > 0 ? Doc.print(warningDoc(unresolvedMessage(unresolved)), { stream: "stderr" }) : Effect.void;
550
549
  }
551
550
  /**
552
551
  * Resolve every entry's versions, then — for interop catalogs — pre-fetch the
@@ -558,7 +557,7 @@ function warnUnresolved(unresolved) {
558
557
  */
559
558
  function resolveForWalk(entries, resolver, gate, workspaceResolver, report) {
560
559
  return Effect.gen(function* () {
561
- const versions = yield* resolveGatedVersions(entries, resolver, gate, Date.now(), resolveProgress(report), workspaceResolver);
560
+ const versions = yield* resolveGatedVersions(entries, resolver, gate, yield* Clock.currentTimeMillis, resolveProgress(report), workspaceResolver);
562
561
  const items = yield* buildWalkItems(entries, versions.gated).pipe(Effect.mapError((e) => new UpgradeError({ message: e.message })));
563
562
  const interopByCatalog = /* @__PURE__ */ new Map();
564
563
  for (const e of entries) {
@@ -659,7 +658,7 @@ const upgradeCommand = Command.make("upgrade", {
659
658
  }));
660
659
  }
661
660
  const outcome = checkOutcome(result.success.changed);
662
- yield* printDoc(outcome.doc);
661
+ yield* Doc.print(outcome.doc);
663
662
  return yield* CliExit.set(outcome.exitCode);
664
663
  }
665
664
  if (json) {
@@ -677,7 +676,7 @@ const upgradeCommand = Command.make("upgrade", {
677
676
  full,
678
677
  workspaceResolver
679
678
  });
680
- yield* printDoc(doc);
679
+ yield* Doc.print(doc);
681
680
  return yield* warnUnresolved(unresolved);
682
681
  }
683
682
  if (yes) {
@@ -691,7 +690,7 @@ const upgradeCommand = Command.make("upgrade", {
691
690
  yield* dryRun ? CliMessage.info(`Dry run — no changes written. ${result.updated} package(s) would be updated; skipped ${result.skipped.length}.`) : CliMessage.success(`Updated ${result.updated} package(s); skipped ${result.skipped.length}.`);
692
691
  if (result.conflicts.length > 0) {
693
692
  const lines = result.conflicts.map((c) => ` ${c.pkg} (kept ${c.ceiling}) blocked by ${c.blockedBy}`);
694
- yield* printDoc(warningDoc(["Interop conflicts (left at your pick):", ...lines].join("\n")), { stream: "stderr" });
693
+ yield* Doc.print(warningDoc(["Interop conflicts (left at your pick):", ...lines].join("\n")), { stream: "stderr" });
695
694
  }
696
695
  return;
697
696
  }
@@ -699,10 +698,10 @@ const upgradeCommand = Command.make("upgrade", {
699
698
  const entries = filterEntriesByCatalog(discovered, Option.getOrUndefined(catalog));
700
699
  const gate = yield* computeGate(source, file, resolver);
701
700
  if (!(yield* CliInteractive)) {
702
- const versions = yield* resolveGatedVersions(entries, resolver, gate, Date.now(), void 0, workspaceResolver);
701
+ const versions = yield* resolveGatedVersions(entries, resolver, gate, yield* Clock.currentTimeMillis, void 0, workspaceResolver);
703
702
  const items = yield* buildWalkItems(entries, versions.gated).pipe(Effect.mapError((e) => new UpgradeError({ message: e.message })));
704
703
  const note = dryRun ? "(dry run — nothing written)" : "(not interactive — run with --yes to apply, or in a terminal to choose)";
705
- yield* printDoc([
704
+ yield* Doc.print([
706
705
  ...summaryDoc(projectDecisions(items, full)),
707
706
  Doc.line(""),
708
707
  Doc.line(Doc.text(note, "muted"))
@@ -714,12 +713,14 @@ const upgradeCommand = Command.make("upgrade", {
714
713
  yield* warnUnresolved(versions.unresolved);
715
714
  return yield* CliMessage.info(nothingToUpgradeMessage(0));
716
715
  }
717
- const decisions = yield* CliUi.run(walkScreen({
716
+ const picked = yield* CliUi.run(walkScreen({
718
717
  items,
719
718
  dryRun,
720
719
  unresolved: versions.unresolved,
721
720
  interopModels
722
- }));
721
+ })).pipe(Effect.map(Option.some), Effect.catchTag("Cancelled", (cancel) => cancel.reason === "escape" ? Effect.succeed(Option.none()) : Effect.fail(cancel)));
722
+ if (Option.isNone(picked)) return yield* CliMessage.info("cancelled; nothing written");
723
+ const decisions = picked.value;
723
724
  const nonInteropDecisions = decisions.filter((d) => d.item.entry.strategy !== "interop");
724
725
  const interopEdits = [];
725
726
  const allConflicts = [];
@@ -755,12 +756,12 @@ const upgradeCommand = Command.make("upgrade", {
755
756
  const planned = buildEdits(nonInteropDecisions);
756
757
  const { accepted, rejected } = yield* validateEdits(planned, versions.raw);
757
758
  const acceptedPkgs = new Set(accepted.map((e) => e.pkg));
758
- yield* printDoc(summaryDoc(decisions, { conflicts: allConflicts }, rejected));
759
+ yield* Doc.print(summaryDoc(decisions, { conflicts: allConflicts }, rejected));
759
760
  if (!dryRun) yield* applyInteropAndDecisions(file, source, accepted, interopEdits);
760
761
  const changed = countChangedDecisions(nonInteropDecisions.filter((d) => acceptedPkgs.has(d.item.entry.pkg))) + interopChanged;
761
762
  yield* dryRun ? CliMessage.info(`Dry run — no changes written. ${changed} change(s) would be applied.`) : CliMessage.success(`Applied ${changed} change(s).`);
762
763
  yield* warnUnresolved(versions.unresolved);
763
- }).pipe(Effect.provide(RegistryResolverLive))).pipe(Command.withDescription("Upgrade catalog versions in a config file"));
764
+ })).pipe(Command.withDescription("Upgrade catalog versions in a config file"));
764
765
 
765
766
  //#endregion
766
767
  export { CHECK_FAILED_LABEL, CheckFailedError, UpgradeError, UpgradeUsageError, applyInteropAndDecisions, checkJsonOutcome, checkOutcome, computeGate, countChangedDecisions, nothingToUpgradeMessage, projectDecisions, readCatalogSource, resolveGatedVersions, resolveProgress, resolveTargetFile, runUpgrade, runUpgradePreview, unresolvedMessage, upgradeCommand, upgradeJsonOutcome, validateJsonMode };
package/cli/main.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { WorkingDirectory } from "./cwd.js";
2
+ import { RegistryResolverLive } from "./resolve.js";
2
3
  import { rootCommand } from "./root.js";
3
4
  import { CLI_VERSION } from "./version.js";
4
5
  import { Effect } from "effect";
@@ -11,6 +12,10 @@ import { CliAudience, CliRuntime } from "@effected/cli";
11
12
  * the working directory, argv for the build-time log format, and stderr's
12
13
  * terminal state are read here and passed down as plain values.
13
14
  *
15
+ * The registry resolver (`pnpm view`, spawned through the platform) is
16
+ * provided here, at the edge, so a test drives the same command tree against
17
+ * a stub resolver.
18
+ *
14
19
  * `CliRuntime.main` builds the audience, terminal and theme from `env`,
15
20
  * decides whether the run may prompt, reports every failure on stderr for the
16
21
  * run's audience, and maps the exit code (usage 64, cancel 130, otherwise 1).
@@ -18,7 +23,7 @@ import { CliAudience, CliRuntime } from "@effected/cli";
18
23
  * @internal
19
24
  */
20
25
  function main() {
21
- const program = CliAudience.run(rootCommand, { version: CLI_VERSION }).pipe(Effect.provideService(WorkingDirectory, process.cwd()));
26
+ const program = CliAudience.run(rootCommand, { version: CLI_VERSION }).pipe(Effect.provideService(WorkingDirectory, process.cwd()), Effect.provide(RegistryResolverLive));
22
27
  NodeRuntime.runMain(CliRuntime.main(program, {
23
28
  platform: NodeServices.layer,
24
29
  helpOnUsageError: "stderr",
@@ -3,7 +3,7 @@ import { Doc } from "@effected/cli";
3
3
 
4
4
  //#region src/cli/render/legend.ts
5
5
  function swatches(entries) {
6
- return Doc.line([Doc.text(" Legend: "), ...entries.map(([label, t], i) => tone(`■ ${label}${i < entries.length - 1 ? " " : ""}`, t))]);
6
+ return Doc.line([Doc.text(" Legend: "), ...entries.map(([label, t], i) => tone(`■ ${label}${i < entries.length - 1 ? " " : ""}`, t))], { wrap: false });
7
7
  }
8
8
  /**
9
9
  * The colour legend for the config diff (the `preview` command and
@@ -15,24 +15,11 @@ const coloured = Effect.gen(function* () {
15
15
  return (yield* Audience).kind === "human" && theme.color !== "none";
16
16
  });
17
17
  /**
18
- * Print a document with no width limit, for every audience. Diffs, summaries
19
- * and package lists are line-oriented data: a hard wrap at a person's width (80
20
- * when output is piped) would split a row away from its gutter and break a
21
- * grep. A terminal still soft-wraps a long line when it shows it.
22
- *
23
- * @internal
24
- */
25
- function printDoc(doc, options = {}) {
26
- return Doc.print(doc, {
27
- ...options,
28
- width: Number.POSITIVE_INFINITY
29
- });
30
- }
31
- /**
32
18
  * Print a diff-shaped view to stdout: an optional heading line, the legend
33
- * when the output is coloured, then the view. The audience picks the
34
- * renderer (ANSI for a person, plain for an agent, the GitHub log under
35
- * Actions).
19
+ * when the output is coloured, then the view's rows, each kept whole on one
20
+ * line whatever the width (the heading may wrap at a person's terminal). The
21
+ * audience picks the renderer (ANSI for a person, plain for an agent, the
22
+ * GitHub log under Actions).
36
23
  *
37
24
  * @internal
38
25
  */
@@ -41,10 +28,10 @@ function printView(view, options = {}) {
41
28
  const doc = [];
42
29
  if (options.heading !== void 0) doc.push(Doc.line(options.heading), Doc.line(""));
43
30
  if (options.legend !== void 0 && (yield* coloured)) doc.push(options.legend, Doc.line(""));
44
- doc.push(view);
45
- yield* printDoc(doc);
31
+ doc.push(Doc.lines(view.lines, { wrap: false }));
32
+ yield* Doc.print(doc);
46
33
  });
47
34
  }
48
35
 
49
36
  //#endregion
50
- export { coloured, printDoc, printView };
37
+ export { coloured, printView };
package/cli/summary.js CHANGED
@@ -46,8 +46,8 @@ function summaryDoc(decisions, interop, rejected) {
46
46
  }
47
47
  lines.push(row(" ", 0, [tone(`${toUpdate} to update · ${major} major · ${resync} resync · ${materialize} new peer · ${upToDate} up to date`, "unchanged")]));
48
48
  if (interop) for (const c of interop.conflicts) lines.push(row("⚠", 0, [tone(`${c.pkg} (kept ${c.ceiling}) blocked by ${c.blockedBy}`, "warn")]));
49
- const blocks = [Doc.lines(lines)];
50
- if (rejected && rejected.length > 0) blocks.push(Doc.line(""), Doc.lines([row("⚠", 0, [tone("Rejected (no published version satisfies these):", "warn")]), ...rejected.map((r) => row("⚠", 1, [tone(`${r.pkg} ${r.kind} ${r.value} — ${r.reason}`, "warn")]))]));
49
+ const blocks = [Doc.lines(lines, { wrap: false })];
50
+ if (rejected && rejected.length > 0) blocks.push(Doc.line(""), Doc.lines([row("⚠", 0, [tone("Rejected (no published version satisfies these):", "warn")]), ...rejected.map((r) => row("⚠", 1, [tone(`${r.pkg} ${r.kind} ${r.value} — ${r.reason}`, "warn")]))], { wrap: false }));
51
51
  return blocks;
52
52
  }
53
53
 
@@ -75,7 +75,7 @@ function makePreviewScreen(views) {
75
75
  renderRow: (row, highlighted) => /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, { children: highlighted ? /* @__PURE__ */ jsx(Styled, {
76
76
  token: "accent",
77
77
  children: "›"
78
- }) : " " }), /* @__PURE__ */ jsx(DocView, { doc: Doc.line(row._tag === "Item" ? lines[Number(row.key)] ?? [] : []) })] })
78
+ }) : " " }), /* @__PURE__ */ jsx(DocView, { doc: Doc.line(row._tag === "Item" ? lines[Number(row.key)] ?? [] : [], { truncate: true }) })] })
79
79
  }),
80
80
  /* @__PURE__ */ jsx(KeyHelp, { tables: [
81
81
  Viewport.keys,
@@ -1,4 +1,3 @@
1
- import { initialProgress, reduceProgress } from "./progress.js";
2
1
  import { Status } from "@effected/cli";
3
2
  import { Styled, useGlyphs, useTheme } from "@effected/cli/ui";
4
3
  import { Text } from "ink";
@@ -25,23 +24,19 @@ function Progress({ state, frame }) {
25
24
  ] });
26
25
  }
27
26
  /**
28
- * The resolve-progress live view, minus its events: one spinner line naming
29
- * the phase and its count, committed as a check-marked line carrying the
30
- * phase's finished label when it ends.
31
- * Shared by the command and its test so the two never drift.
27
+ * The resolve-progress view: one spinner line naming the phase and its count,
28
+ * committed as a check-marked line carrying the phase's finished label when it
29
+ * ends. Loaded only when a run draws it (`CliUi.lazyView` in `screens.ts`), so
30
+ * this module — and React with it — stays off every run that never draws.
32
31
  *
33
32
  * @internal
34
33
  */
35
- const progressView = {
36
- initial: initialProgress,
37
- reduce: reduceProgress,
38
- render: (state, frame) => /* @__PURE__ */ jsx(Progress, {
34
+ function progressView(state, frame) {
35
+ return /* @__PURE__ */ jsx(Progress, {
39
36
  state,
40
37
  frame
41
- }),
42
- isStart: (event) => event._tag === "Phase",
43
- isTerminal: (event) => event._tag === "Finished"
44
- };
38
+ });
39
+ }
45
40
 
46
41
  //#endregion
47
- export { progressView };
42
+ export { progressView as default };
package/cli/ui/screens.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { initialProgress, reduceProgress } from "./progress.js";
1
2
  import { Effect, PubSub } from "effect";
2
- import { CliInteractive } from "@effected/cli";
3
3
  import { CliUi } from "@effected/cli/ui";
4
4
 
5
5
  //#region src/cli/ui/screens.ts
@@ -12,29 +12,41 @@ function previewScreen(views) {
12
12
  return CliUi.lazy(async () => ({ default: (await import("./preview-screen.js")).makePreviewScreen(views) }));
13
13
  }
14
14
  /**
15
- * Run `body` with a progress reporter. In an interactive run the reports
16
- * drive a live spinner view that redraws in place; otherwise the reporter is a
17
- * no-op and nothing is drawn or loaded, so piped and CI output stay clean. The
18
- * view is closed — its last frame committed — before this returns, so a
19
- * screen mounted next never waits on it.
15
+ * The resolve-progress live view, minus its events: one spinner line per
16
+ * phase, committed as a check-marked line when the phase finishes. A run that
17
+ * cannot draw (a pipe, CI, an agent) prints nothing: `final` is the empty
18
+ * document, so stdout carries only the command's own output, and neither the
19
+ * view's module nor Ink nor React is loaded.
20
+ *
21
+ * @internal
22
+ */
23
+ const progressOptions = {
24
+ initial: initialProgress,
25
+ reduce: reduceProgress,
26
+ render: CliUi.lazyView(() => import("./progress-view.js")),
27
+ final: () => [],
28
+ isStart: (event) => event._tag === "Phase",
29
+ isTerminal: (event) => event._tag === "Finished"
30
+ };
31
+ /**
32
+ * Run `body` with a progress reporter whose reports drive the live view. In an
33
+ * interactive run it redraws in place; otherwise it draws and prints nothing
34
+ * (see {@link progressOptions}). The view is closed — its last frame committed
35
+ * — before this returns, so a screen mounted next never waits on it.
20
36
  *
21
37
  * @internal
22
38
  */
23
39
  function withProgress(body) {
24
- return Effect.gen(function* () {
25
- if (!(yield* CliInteractive)) return yield* body(() => Effect.void);
26
- const { progressView } = yield* Effect.promise(() => import("./progress-view.js"));
27
- return yield* Effect.scoped(Effect.gen(function* () {
28
- const pubsub = yield* PubSub.unbounded();
29
- const events = yield* PubSub.subscribe(pubsub);
30
- const view = yield* CliUi.live({
31
- ...progressView,
32
- events
33
- });
34
- return yield* body((event) => PubSub.publish(pubsub, event).pipe(Effect.asVoid)).pipe(Effect.ensuring(view.close));
35
- }));
36
- });
40
+ return Effect.scoped(Effect.gen(function* () {
41
+ const pubsub = yield* PubSub.unbounded();
42
+ const events = yield* PubSub.subscribe(pubsub);
43
+ const view = yield* CliUi.live({
44
+ ...progressOptions,
45
+ events
46
+ });
47
+ return yield* body((event) => PubSub.publish(pubsub, event).pipe(Effect.asVoid)).pipe(Effect.ensuring(view.close));
48
+ }));
37
49
  }
38
50
 
39
51
  //#endregion
40
- export { previewScreen, walkScreen, withProgress };
52
+ export { previewScreen, progressOptions, walkScreen, withProgress };
package/cli/version.js CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @internal
8
8
  */
9
- const CLI_VERSION = "2.0.1";
9
+ const CLI_VERSION = "2.0.2";
10
10
 
11
11
  //#endregion
12
12
  export { CLI_VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rolldown-pnpm-config",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "private": false,
5
5
  "description": "A dogfooding example of our plugin",
6
6
  "repository": {
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@effect/platform-node": "^4.0.2",
39
- "@effected/cli": "^0.14.0",
39
+ "@effected/cli": "^0.15.0",
40
40
  "@effected/env": "^0.1.0",
41
41
  "@effected/glob": "^0.10.0",
42
42
  "@effected/npm": "^0.20.0",
@@ -45,7 +45,7 @@
45
45
  "@effected/workspaces": "^0.32.0",
46
46
  "@effected/yaml": "^0.19.1",
47
47
  "effect": "^4.0.2",
48
- "ink": "^7.1.1",
48
+ "ink": "^8.0.0",
49
49
  "oxc-parser": "^0.153.0",
50
50
  "react": "^19.3.0"
51
51
  },