Skip to content

Migrate fjs/effects/memory, mock, eff, node, and fjs/text/sgr to .f.mjs - #1488

Merged
sergey-shandar merged 7 commits into
mainfrom
claude/convert-f-ts-to-f-mjs-11
Aug 11, 2026
Merged

Migrate fjs/effects/memory, mock, eff, node, and fjs/text/sgr to .f.mjs#1488
sergey-shandar merged 7 commits into
mainfrom
claude/convert-f-ts-to-f-mjs-11

Conversation

@sergey-shandar

@sergey-shandar sergey-shandar commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Five modules migrate from authored TypeScript to JSDoc-typed .f.mjs, per todo/migrate-typescript-to-mjs.md, each splitting its public type-level API into a sibling types.ts:

  • fjs/effects/memory/module.f.tsKey, MemCreate, MemRead, MemWrite, MemOp, and the private MemKeyHash_MemKeyHash. Updates 13 dependents (cas, mcp, protocol/mcp, effects/node and its virtual/memory submodules), and fixes two markdown link hrefs (cas/evo/module.f.ts's docstring, cas/evo/README.md) that pointed at the old .f.ts path.
  • fjs/effects/mock/module.f.tsMemOperationMap, RunInstance. Updates 4 dependents.
  • fjs/effects/eff/module.f.ts — the Eff<O,T,P> type. Updates 4 dependents plus 3 doc references.
  • fjs/effects/node/module.f.ts (566 lines) — the Node.js effect operations module: filesystem, networking, exec, console, sandbox, test registration, and NodeOp/NodeProgram. Updates 26 dependents across the repo, plus a batch of stale module.f.ts doc references (including several with stale line-number citations that now split across module.f.mjs and types.ts).
  • fjs/text/sgr/module.f.tsStdout, WriteText, CsiConsole. Updates the emergent_testing dependent and stale line-number citations across three todo docs.

All five proof.f.ts files stay TypeScript for now (their remaining runtime dependencies: effects/proof.f.ts, effects/node/virtual/module.f.ts — both still unmigrated).

Test plan

  • npx tsc --noEmit clean
  • node ./fjs/module.ts t — 2356/2356 pass

claude added 2 commits August 11, 2026 06:50
Leaf module. Updates 13 dependents across cas, mcp, protocol/mcp, and
effects/node to import runtime values from .f.mjs and types from
types.ts separately, and fixes two markdown link hrefs.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
functionalscript d6cf1b1 Commit Preview URL

Branch Preview URL
Aug 11 2026, 01:32 PM

claude added 3 commits August 11, 2026 06:54
Leaf module with no proof.f.ts of its own. Updates 4 dependents
(effects/node/virtual, effects/memory, protocol/mcp, emergent_testing)
to import runtime values from .f.mjs and types from types.ts
separately.
proof.f.ts stays TypeScript for now: it has a runtime dependency on
../proof.f.ts (fjs/effects/proof.f.ts), still unmigrated. Updates 4
dependents (protocol/mcp, cas, cas/evo, emergent_testing) and 3 doc
references.
…into types.ts

The Node.js effect operations module: filesystem, networking, exec,
console, sandbox, test registration, and the NodeOp/NodeProgram types.
Nearly the entire public surface moves to types.ts unchanged (real
TypeScript); runtime combinators become JSDoc-typed .mjs, using
@template/@PARAM on writeFromStream and both where an inline @type
can't expose its generics to the body, and an any-cast on both's
all(a, b) call to carry over the original's unchecked `as` widening.

Updates 26 dependents across the repo (djs, text/sgr, cli, dev, ci,
media/type, cas, mcp, protocol/mcp, emergent_testing, website, and
effects' own submodules) to import runtime values from .f.mjs and
types from types.ts separately, plus a batch of stale module.f.ts doc
references (including three with stale line-number citations that now
split across module.f.mjs and types.ts). proof.f.ts stays TypeScript
for now.

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 91bd993. Four modules — effects/memory, effects/mock, effects/eff, effects/node. All four are equivalent to main's compiled output, npx tsc is clean, 2356 pass / 0 fail, links are 144/144 with none added and 0 label-target mismatches, and the CHANGELOG covers all four. One thing to fix.

Two apparent differences turned out to be artifacts of comparing against compiled output, and both are worth naming because they are the good outcome:

  • effects/node looks like it changes (lenV & 0b111n) to (lenV & 7n). It doesn't — main's source at line 216 already reads 0b111n, and TypeScript's emitter is what normalizes it to 7n. The branch preserves the binary spelling, so the "low three bits" intent of the mask survives.
  • effects/memory's asBase/asNominal declarations gain a named _MemKeyHash where main inlined the raw hash literal "3f114fa6…". That is a readability improvement, not a change: the alias was non-exported on main so the emitter had to inline it, and now that it is exported (correctly _-prefixed) it can be named.

Also noticed read's parameter was quietly fixed from ket to key.

log and error dropped the Console annotation

main:

export const log: Console = writeString('stdout')
export const error: Console = writeString('stderr')

this branch:

/** Writes a line to `stdout`. Replaces the retired `Log` effect. */
export const log = writeString('stdout')

With no annotation the type is inferred from writeString('stdout'), so the emitted declarations expand to (s: string) => Effect<Write, void> instead of naming Console. Console is (s: string) => Effect<Write, void>, so the types are identical and no caller can tell — nothing is weakened.

What makes it worth fixing is the second-order effect: Console is still exported from types.ts, unchanged, and after this change nothing in the emitted surface references it. An exported alias that no declaration mentions reads as dead, and the next person to touch this file has no signal that log/error are meant to be the same shape.

This is the same case as eof losing TerminalRange on #1485. Fix is /** @type {Console} */ above each, plus adding Console to the @import list in module.f.mjs — it isn't currently imported there. I swept the rest of the diff for this shape (an export whose main declaration was a bare alias that still exists as an exported type): these two are the only ones.

Minor — a stale line in the description

proof.f.ts stays TypeScript for now — it has a runtime dependency on ../mock/module.f.ts, still unmigrated.

mock is migrated by the third commit of this same PR, so at this head every runtime import in effects/memory/proof.f.ts is already .f.mjs. Leaving the proof as .f.ts is fine either way — §2 says renaming an implementation never requires renaming its proof — so this is only the stated reason having gone stale mid-PR, not a problem with the outcome. (eff/proof.f.ts genuinely is still blocked, on ../proof.f.ts.)


No correctness objection; happy to approve once the two @type {Console} annotations are back.

claude added 2 commits August 11, 2026 13:28
…node

Without the annotation, log/error's declaration emit expanded to the
inline (s: string) => Effect<Write, void> shape instead of naming the
still-exported Console alias, leaving it referenced by nothing.
proof.f.ts stays TypeScript for now: it has a runtime dependency on
effects/node/virtual/module.f.ts, still unmigrated. Updates the
emergent_testing dependent and stale line-number citations across
three todo docs.

@o2alexanderfedin o2alexanderfedin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Re-reviewed at d6cf1b1. The Console annotation is back and fjs/text/sgr joins as a fifth module. CI green.

The fix works

log and error emit as Console again, matching main:

export declare const log: Console;
export declare const error: Console;

They no longer appear in my declaration diff against main at all.

One note, and I checked before raising it so it stays a note rather than a request. The fix uses an inline cast — /** @type {Console} */ (writeString('stdout')) — where the declaration-annotation form would also work:

/**
 * Writes a line to `stdout`. Replaces the retired `Log` effect.
 * @type {Console}
 */
export const log = writeString('stdout')

I assumed the cast would be the weaker of the two and tested it: substituting a deliberately wrong value (writeString instead of writeString('stdout')) produces exactly one error under both forms. So there is no safety difference here, and the emitted declaration is identical either way. The only argument for the annotation is consistency with the "annotated const over inline cast" change made on #1486 — genuinely minor, and not worth a commit on its own.

fjs/text/sgr verified

  • Token-identical to main's compiled output.
  • csi and sgr change only by the End_End / Csi_Csi prefix renames; both were non-exported on main, so nothing public was renamed.
  • csiWrite's signature differs only in the parameter name ({ std } destructuring became options) — same type.
  • proof.f.ts correctly stays TypeScript: it imports effects/node/virtual/module.f.ts, still unmigrated.

Whole-PR state at this head

  • npx tsc clean; 2356 pass / 0 fail.
  • Five modules; four token-identical, and effects/node differs only by the 0b111n7n normalization TypeScript's emitter applies — main's source already spells it 0b111n and this branch preserves it.
  • Public API: 0 removed, 0 non-_ additions. The changed signatures are all prefix renames plus two parameter-name differences.
  • No any as a type in any emitted declaration.
  • Links 144/144 with none added, 0 label/target mismatches.
  • CHANGELOG covers all five.

Still stale, from last round

The summary's line about fjs/effects/memory:

proof.f.ts stays TypeScript for now — it has a runtime dependency on ../mock/module.f.ts, still unmigrated.

mock migrated in this same PR, so every runtime import in that proof is .f.mjs now. Leaving the proof as .f.ts is fine — §2 never requires moving it — so this is only the stated reason, not the outcome. Worth a touch-up before merge since the summary is what describes this in history.

@sergey-shandar sergey-shandar changed the title Migrate fjs/effects/memory to .f.mjs Migrate fjs/effects/memory, mock, eff, node, and fjs/text/sgr to .f.mjs Aug 11, 2026
@sergey-shandar
sergey-shandar added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 3305d79 Aug 11, 2026
19 checks passed
@sergey-shandar
sergey-shandar deleted the claude/convert-f-ts-to-f-mjs-11 branch August 11, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants