FE-1516: Accept bare function bodies for kernel, lambda, and dynamics code - #9370
Conversation
… code Transition kernels, lambdas, and differential equations accept a bare function body ending in `return`, with the input object (tokensByPlace / tokens) and `parameters` ambient — like metrics and scenario code. The legacy `export default <Ctor>(...)` module form is still accepted. - HIR: detect the source form (any top-level export marks the module form) and lower bare bodies through the wrapped-body path with synthesized ambient parameters. - LSP: dual-form virtual files pick the module or body wrapper from the current content on every write, so both forms type-check with completions; the body wrapper widens the return type with `| void` so unfinished bodies get the HIR's friendlier missing-return error and empty lambdas stay valid. - Default templates, built-in examples, Storybook nets, the AI assistant guidance, and the user docs now use the bare form; visualizers are unchanged. New test compiles and LSP-checks every built-in example.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Arch docs: user-code.mdx now describes the bare-body form as primary.
- LSP body wrapper: exact return type plus an unreachable
`return undefined as never;` in the suffix instead of `| void`
widening, so type-mismatch messages no longer mention a void the user
never wrote while empty/unfinished bodies still defer to the HIR lint.
- Examples: replace the codemod's `return ({});` with `return {};`.
- Default predicate template no longer suggests `return Infinity;`
(a type error for predicate lambdas).
- Direct table test for detectUserCodeForm; exact parse-error span
assertion; checker test pinning where redeclared-ambient errors land.
- getFileContent includes the suffix, matching what TypeScript checks.
Kernels and lambdas read their tokens as `input` in the bare-body form (dynamics keeps `tokens`). Templates, examples, AI guidance, schema descriptions, and the user guide follow, and the guide gains a "Code surfaces and their variables" table listing what is in scope per surface.
PR SummaryMedium Risk Overview A shared form detector ( Defaults, built-in examples, Storybook nets, AI assistant guidance, entity schema descriptions, and user docs are updated to the bare style. New tests compile all shipped examples through HIR and the full LSP check; existing tests expect bare default kernel templates. Reviewed by Cursor Bugbot for commit 9aedf64. Bugbot is set up for automated code reviews on this repo. Configure here. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9370 +/- ##
==========================================
- Coverage 60.73% 60.50% -0.24%
==========================================
Files 1440 1434 -6
Lines 143477 141340 -2137
Branches 6662 6612 -50
==========================================
- Hits 87145 85519 -1626
+ Misses 55240 54746 -494
+ Partials 1092 1075 -17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🌟 What is the purpose of this PR?
Transition kernels, lambdas, and differential equations can be written as a plain function body ending in
return, the way metrics and scenario code already are. Theexport default TransitionKernel(...)/Lambda(...)/Dynamics(...)module form still works: both forms pass the LSP and lower to the same HIR. Visualizers are unchanged.input,parametersinput,parametersboolean/ firing ratetokens,parametersstate,parametersparameters,scenario,range🔍 What does this change?
hir/user-code-form.ts(new): classifies code as module or bare body. Any top-levelexportstatement means module form. The HIR lowering and the LSP wrapping both call it, so the editor and the compiler always agree on a given source text.hir/lower-typescript.ts: bare bodies lower through the wrapped-body path metrics already use. The code is wrapped in(input, parameters) => { ... }for parsing, spans are shifted back onto the raw text, and the lowered function carries the ambient names as its parameters. The type checker, analyses, and buffer emitters are unchanged.generate-virtual-files.ts,create-language-service-host.ts): each kernel/lambda/dynamics virtual file carries a wrapper per form (VirtualFile.formWrappers), re-picked on every content write, per-keystroke updates included. The body wrapper types the code as a function body with typedinput/tokens/parametersparameters and appends an unreachablereturn undefined as never;to its suffix: an unfinished body is not a TypeScript error (the HIR lint reports "must end with areturnstatement" at the right position), an empty lambda stays valid (the runtime default applies), and type mismatches keep exact messages ("not assignable to type 'boolean'").ai.ts), and the entity-schema descriptions to the bare form.petri-net-extensions.mdgains a "Code surfaces and their variables" section with the table above and now teaches the bare form;useful-patterns.mdsnippets migrated. The arch pagecontent/simulation/user-code.mdxdocuments the form detection.exportis read as a bare body, soconst x = 1;now fails with "The function body must end with areturnstatement" instead of "Expectedexport default <Ctor>(...)".Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
export defaultcode in the editors and need re-capturing.petrinaut-clitest fixtures keep the module form as backwards-compatibility coverage;brunch-agentinbox documents keep it too and still load.🐾 Next steps
🛡 What tests cover this?
hir/user-code-form.test.ts:Form-detection table test
hir/lower-typescript.test.ts:Bare-body lowering for all three surfaces, module/body equivalence, span mapping, missing-return errors
lsp/lib/checker.test.ts:Both forms through the full checker, diagnostic positions, empty lambda, missing return reported by the HIR lint
lsp/lib/create-sdcpn-language-service.test.ts:Completions in both forms and re-wrapping when an edit switches form
examples/examples.test.ts:Every built-in example compiles through the HIR pipeline and passes the full LSP check
❓ How to test this?
return { <Place>: [...] };with no wrapper: completions offerinputandparameters, and diagnostics point into the body.export default TransitionKernel(...)module: it still type-checks.