fix: draft() can't resolve TypeScript helper functions defined in logic/logic.ts (#147)#150
Open
mttrbrts wants to merge 1 commit into
Open
fix: draft() can't resolve TypeScript helper functions defined in logic/logic.ts (#147)#150mttrbrts wants to merge 1 commit into
mttrbrts wants to merge 1 commit into
Conversation
…ic/logic.ts (#147) TemplateArchiveProcessor.draft() compiled inline formulas (`{{% expr %}}`) with a TypeScript context that did not include the template's user code from `logic/logic.ts`. Helper functions like `monthlyPaymentFormula(...)` therefore produced `Cannot find name 'monthlyPaymentFormula'` (TS2304). trigger() and init() already loaded logic/logic.ts via the TypeScriptToJavaScriptCompiler. This change: - Extracts that compilation into a shared `compileUserLogic` helper (src/UserLogic.ts) which returns the compiled JS along with the top-level identifiers it declares. - Adds `declare const <name>: any;` stubs to the formula compile context for each of those identifiers, so user helpers resolve at compile time. - Splices the stripped logic.ts JS into the formula function body at runtime, so the same identifiers are real values at evaluation time. - Refactors trigger() and init() to use the new shared helper, so draft() and trigger()/init() now use the same logic-loading path. Adds a fixture (test/archives/formula-uses-logic-helper) and a unit test that confirms draft() can call helpers from logic/logic.ts. Signed-off-by: Claude <noreply@anthropic.com>
Coverage Report for CI Build 25955964043Coverage increased (+0.6%) to 64.788%Details
Uncovered Changes
Coverage Regressions2 previously-covered lines in 1 file lost coverage.
Coverage Stats
💛 - Coveralls |
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes issue #147 by ensuring draft() compiles inline formula expressions with awareness of helper symbols declared in a template’s logic/logic.ts, and makes those helpers available at runtime during formula evaluation.
Changes:
- Extract user-logic compilation into a shared helper (
compileUserLogic) and reuse it fromdraft(),trigger(), andinit(). - Extend the TypeScript compilation context for inline formulas to include ambient declarations for user-logic top-level identifiers.
- Thread a stripped “user logic prelude” into the formula evaluator so helpers exist at evaluation time, and add a regression test fixture + unit test.
Reviewed changes
Copilot reviewed 17 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/TemplateArchiveProcessor.test.ts | Adds a regression test that drafts a template whose formula calls a helper from logic/logic.ts. |
| test/archives/formula-uses-logic-helper/text/grammar.tem.md | New fixture grammar containing a formula that calls calc(...). |
| test/archives/formula-uses-logic-helper/request.json | New fixture request payload. |
| test/archives/formula-uses-logic-helper/README.md | New fixture README/sample text. |
| test/archives/formula-uses-logic-helper/package.json | Declares the fixture as a TypeScript-runtime template. |
| test/archives/formula-uses-logic-helper/model/model.cto | New fixture model defining template/request/response/state. |
| test/archives/formula-uses-logic-helper/model/@models.accordproject.org.time@0.3.0.cto | Vendored model dependency for offline tests. |
| test/archives/formula-uses-logic-helper/model/@models.accordproject.org.accordproject.runtime@0.2.0.cto | Vendored model dependency for offline tests. |
| test/archives/formula-uses-logic-helper/model/@models.accordproject.org.accordproject.contract@0.2.0.cto | Vendored model dependency for offline tests. |
| test/archives/formula-uses-logic-helper/logic/README.md | New fixture logic README. |
| test/archives/formula-uses-logic-helper/logic/logic.ts | New fixture logic with helper calc used by the grammar formula. |
| test/archives/formula-uses-logic-helper/logic/generated/org.accordproject.time@0.3.0.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/org.accordproject.runtime@0.2.0.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/org.accordproject.contract@0.2.0.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/io.clause.latedeliveryandpenalty@0.1.0.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/concerto@1.0.0.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/concerto.ts | Generated TS types for the fixture. |
| test/archives/formula-uses-logic-helper/logic/generated/concerto.decorator@1.0.0.ts | Generated TS types for the fixture. |
| src/UserLogic.ts | Introduces shared compilation helper + module-syntax stripping + symbol extraction. |
| src/TypeScriptToJavaScriptCompiler.ts | Extends compiler construction to accept user-logic symbol stubs for formula compilation. |
| src/TypeScriptCompilationContext.ts | Emits declare const <name>: any; stubs for user-logic symbols to make formulas type-check. |
| src/TemplateMarkToJavaScriptCompiler.ts | Threads user-logic symbols into the TS→JS compilation pipeline for TemplateMark code nodes. |
| src/TemplateMarkInterpreter.ts | Threads compiled user-logic prelude into runtime formula evaluation. |
| src/TemplateArchiveProcessor.ts | Refactors logic compilation into compileLogic() and wires it into draft()/trigger()/init(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+102
to
+105
| const logicFile = tsFiles.find(f => f.getIdentifier() === 'logic/logic.ts') ?? tsFiles[0]; | ||
| if (!logicFile) { | ||
| return undefined; | ||
| } |
Comment on lines
+122
to
125
| const userLogic = await this.compileLogic(); | ||
| if (!userLogic) { | ||
| throw new Error('Only TypeScript is supported at this time'); | ||
| } |
Comment on lines
+150
to
153
| const userLogic = await this.compileLogic(); | ||
| if (!userLogic) { | ||
| throw new Error('Only TypeScript is supported at this time'); | ||
| } |
Comment on lines
100
to
108
| // chop the function header and closing | ||
| const expression = fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')); | ||
| if (expression.trim().length === 0) { | ||
| throw new Error('Empty expression'); | ||
| } | ||
| const codeWithPrelude = userLogicPrelude ? `${userLogicPrelude}\n${expression}` : expression; | ||
| try { | ||
| const request = { code: expression, argumentNames: functionArgNames, arguments: functionArgValues }; | ||
| const request = { code: codeWithPrelude, argumentNames: functionArgNames, arguments: functionArgValues }; | ||
| if (options?.childProcessJavaScriptEvaluation) { |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #147.
TemplateArchiveProcessor.draft()was compiling each inline formula(
{{% expr %}}) with a TypeScript context that did not includethe template's user code from
logic/logic.ts. As a result, helperfunctions like
monthlyPaymentFormula(...)producedCannot find name 'monthlyPaymentFormula'(TS2304) and drafting failedon otherwise valid templates (repro: cicero-template-library PR #484
src/fixed-interests).trigger()andinit()were already loadinglogic/logic.tsviaTypeScriptToJavaScriptCompiler. They just didn't share that work withdraft().Fix
compileUserLogic(src/UserLogic.ts). It returns the compiled JSalong with the top-level identifiers (
function,class,const/let/var) it declares and a copy of that JS withimport/exportsyntax stripped so it can be spliced into anew Functionbody.
TypeScriptCompilationContextnow emitsdeclare const <name>: any;for each declared identifier, so user helpers type-check inside
formula expressions.
TemplateMarkInterpreteraccepts aCompiledUserLogicand threadsthe runtime prelude through to the JS formula evaluator, so the same
identifiers are real values at evaluation time.
TemplateArchiveProcessor:draft()now callscompileLogic()and passes the result into theinterpreter.
trigger()andinit()were refactored to call the samecompileLogic()helper, so all three code paths now load logic viathe same path.
Repro / test
Added
test/archives/formula-uses-logic-helper: a minimal templatefixture whose grammar contains
{{% return calc(penaltyPercentage); %}}where
calcis a helper function declared inlogic/logic.ts.The new test in
test/TemplateArchiveProcessor.test.ts:mainwithTS2304: Cannot find name 'calc'.calc(10.5) === 26.25).Test plan
should draft a templatestill passes (template withlogic.ts but no helper-calling formula).
should trigger a template/should init a templatestill pass after refactor to shared helper.
npx eslint src/ test/— no new errors.blocks
models.accordproject.org, so some unrelated tests faillocally on
maintoo.)Generated by Claude Code