Skip to content

Migrate fjs/bnf/data to .f.mjs - #1487

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

Migrate fjs/bnf/data to .f.mjs#1487
sergey-shandar merged 6 commits into
mainfrom
claude/convert-f-ts-to-f-mjs-10

Conversation

@sergey-shandar

Copy link
Copy Markdown
Contributor

Summary

  • Migrates fjs/bnf/data/module.f.ts from authored TypeScript to JSDoc-typed .f.mjs, per todo/migrate-typescript-to-mjs.md.
  • Splits the public type-level API (TerminalRange, Sequence, Variant, Rule, RuleSet, EmptyTag) into a sibling types.ts.
  • proof.f.ts stays TypeScript for now — it has a runtime dependency on ../testlib.f.ts and ../../media/json/module.f.ts, both still unmigrated.
  • Updates the two dependents (fjs/bnf/descent, fjs/bnf/ll1 — module + proof each) to import runtime values from .f.mjs and types from types.ts separately.
  • Fixes stale module.f.ts references (paths and, where cited, line numbers) across fjs/bnf/data's todo/ docs.

Test plan

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

Generated by Claude Code

claude added 2 commits August 11, 2026 05:46
proof.f.ts stays TypeScript for now: it has a runtime dependency on
testlib.f.ts and media/json/module.f.ts, both still unmigrated. Updates
descent/ll1 dependents and the stale line references across bnf/data's
todo docs.
@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 28199f7 Commit Preview URL

Branch Preview URL
Aug 11 2026, 06:21 AM

claude added 4 commits August 11, 2026 05:56
proof.f.ts stays TypeScript for now: it has a runtime dependency on
testlib.f.ts, still unmigrated. Updates the stale module.f.ts
reference in the ll1 stack-recursion todo doc.
proof.f.ts stays TypeScript for now: it has a runtime dependency on
testlib.f.ts, still unmigrated. Updates the djs/tokenizer dependent
and stale module.f.ts references in bnf/ll1 and bnf's todo docs.
…types.ts

The core effect system module: Operation, Effect, Pure, Cont, Do,
History, OperationMap, MatchResult, ToAsyncOperationMap, Param, Return,
F, Func move to types.ts unchanged (real TypeScript, variance
annotations intact); the runtime combinators (pure, step, mapStep,
historyStep, history, do_, foldStep, forEachStep, okStep, runPure,
match) become JSDoc-typed .mjs, using @template/@PARAM on multi-step
curried functions where an inline @type can't expose its generics to
the function body.

Updates all 30+ dependents across the repo (cas, ci, cli, dev, djs,
emergent_testing, mcp, media/type, protocol/mcp, text/sgr, website,
and effects' own submodules) to import runtime values from .f.mjs and
types from types.ts separately. proof.f.ts stays TypeScript for now.
No proof.f.ts existed for this module (AGENTS.md's coverage gap is
pre-existing, not introduced here). Updates 8 dependents across cas,
mcp, media/type, and effects/node to import runtime values from
.f.mjs and types from types.ts separately.

@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. Reviewed at 28199f7 against main (03126e4). Five modules — bnf/data, bnf/ll1, bnf/descent, effects, effects/list — plus ~45 dependents updated.

Two modules genuinely restructure, and both check out

bnf/data, bnf/descent, and effects/list are equivalent to main's compiled output. The other two each carry one real code change, both the same idiom: JSDoc has no call-site type-argument syntax, so an inline argument gets extracted into a named const that can be annotated.

// ll1:  rangeMap<DispatchResult>({…})   ->
/** @type {Properties<_DispatchResult>} */
const dispatchProps = {}
const dispatchOp = rangeMap(dispatchProps)

// effects:  fold<T, Effect<O|Q, S>>(item => acc => step(acc, f(item)))   ->
/** @type {Fold<T, Effect<O | Q, S>>} */
const op = item => acc => step(acc, f(item))
return step(items, fold(op)(pure(init)))

I enumerated every normalized difference in each module to confirm these are the only ones — one hunk in ll1, one in effects — then checked behaviour rather than arguing from the shape. effects is the core combinator module, so it got a direct comparison against main:

foldStep sum 1..5    main: [15]   pr: [15]
foldStep empty list  main: [42]   pr: [42]      (init passes through)
forEachStep          main: [null] pr: [null]
okStep ok / error    main: [42] [["error","boom"]]
                     pr  : [42] [["error","boom"]]

Both okStep branches, the empty-list edge, and the folding path all match. For ll1 I leaned on the repo's own coverage instead — my ad-hoc parser harness was calling the API wrong (it failed identically against main, so it was my mistake, not a finding), and the three migrated modules' proofs contribute 164 passing cases, with another 222 across effects.

effects/list shows up as differing only because my normalizer rewrites '.f.js' in single quotes and that file uses double quotes — the sole difference is the import specifier, and empty/nonEmpty produce identical results.

Everything else

  • npx tsc clean; 2356 pass / 0 fail.
  • Public API: 0 removed, 0 non-_ additions. All 10 new types are _-prefixed. The 3 changed types and 3 changed const signatures are entirely those renames (AstRule_AstRule, DispatchRule_DispatchRule, DispatchMap_DispatchMap) plus one effects/module.f.tseffects/types.ts import path. I confirmed all three renamed types were non-exported on main, so nothing public was renamed.
  • No any as a type in any emitted declaration.
  • Markdown links: 144 broken on main, 144 here, none added, 0 label/target mismatches. No bare .f.ts code-span references to migrated files either — the shape that slipped through on #1486.
  • All four new types.ts files keep the @module header through emit.
  • CHANGELOG entries for all five, including the explicit "proof.f.ts stays TypeScript for now" note.

The proof.f.ts decision is right and I verified the reason. All three bnf proofs import runtime values from ../testlib.f.ts, and data's also from media/json/module.f.ts — both still .f.ts on disk, so §2 does not yet permit proof.f.mjs. Stating that in the PR body and the CHANGELOG rather than leaving a reviewer to work it out is the right call.

CI still finishing on 28199f7; verified locally at that commit.

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28199f733e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread fjs/effects/module.f.mjs
Comment on lines +370 to +373
* @template {O} O1
* @template T
* @param {Effect<O1, T>} e
* @returns {MatchResult<O1, T, R>}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Declare the returned match function's type parameters

For any published TypeScript consumer importing this module with the default skipLibCheck: false, declaration emission leaves these nested @template tags as comments rather than emitting an inner generic binder: the resulting .d.mts references undeclared O1 and T and fails with four TS2304 errors. Preserve the previous signature <O1 extends O, T>(e: Effect<O1, T>) => MatchResult<O1, T, R> in valid emitted syntax.

AGENTS.md reference: AGENTS.md:L525-L529

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Checked this directly against the actual declaration emit (npx tsc --noEmit false --declaration --emitDeclarationOnly --outDir <scratch>). match's emitted .d.mts is:

export declare const match: <O extends Operation, R>(map: OperationMap<O, R>) => <O1 extends O, T>(
/**
 * @template {O} O1
 * @template T
 * @param {Effect<O1, T>} e
 * @returns {MatchResult<O1, T, R>}
 */
e: Effect<O1, T>) => MatchResult<O1, T, R>;

O1 and T are declared, in <O1 extends O, T>(...) — the JSDoc block just lands as a positional comment ahead of the e parameter, which is legal TS syntax (a comment can appear anywhere whitespace can, including inside a parameter list). This is the same "noisy but not broken" per-arrow-JSDoc emit pattern already flagged as pre-existing on 14 other declarations in an earlier review round on this PR (the option example) — not new breakage.

I verified two ways:

  1. Compiled the exact emitted snippet standalone (tsc --noEmit on a .d.ts reproducing it, with a matching Operation/Effect/MatchResult/OperationMap) — clean, no errors, in particular no TS2304.
  2. Wrote a small consumer importing match from the real emitted module.f.d.mts and calling it — it type-checks and dispatches correctly; the only diagnostic I hit was an unrelated R inference note from my test's loosely-typed map, not anything about O1/T being undeclared.

No TS2304 anywhere in either check. I don't see the four errors described — happy to look again with a concrete repro if you have one, but as written this looks like a false positive.


Generated by Claude Code

@sergey-shandar

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 28199f733e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sergey-shandar
sergey-shandar added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 60a71f1 Aug 11, 2026
19 checks passed
@sergey-shandar
sergey-shandar deleted the claude/convert-f-ts-to-f-mjs-10 branch August 11, 2026 06:45
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