fix: add --src-root for subdirectory-aware package.json paths (#50)#52
Merged
fix: add --src-root for subdirectory-aware package.json paths (#50)#52
Conversation
Create Metano-packages.slnx with only publishable src/ projects and point dotnet-releaser at it. Samples have AfterBuild targets that run the compiler via `dotnet run`, causing file-lock conflicts under parallel builds. Also specify Metano.slnx explicitly in the CI build step since two .slnx files now exist in the root. Part of #50
There was a problem hiding this comment.
Pull request overview
Adds a --src-root / MetanoSrcRoot option so package.json imports/exports generation becomes aware of TypeScript source roots when the transpiler output targets a subdirectory (e.g., src/domain/), and updates release/build plumbing plus tests/spec-related artifacts.
Changes:
- Add
--src-rootplumbing (CLI + MSBuild) and compute an output prefix to correctly prefixdistpaths and export subpaths for subdirectory outputs. - Update
PackageJsonWriterbehavior to (a) mergeimportswhile preserving user-defined entries and cleaning stale managed keys, and (b) fully replaceexportson regeneration. - Add new tests covering subdirectory prefixing and merge/stale-cleanup behavior; adjust release build to use a packages-only solution.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Metano.Tests/EmitPackageTests.cs | Adds tests for imports merge/stale cleanup and subdirectory-aware exports/imports prefix behavior. |
| src/Metano.Compiler.TypeScript/PackageJsonWriter.cs | Implements srcRoot/prefix computation and updates merge/replace strategy for imports/exports. |
| src/Metano.Compiler.TypeScript/Commands.cs | Adds --src-root CLI parameter and wires it into PackageJsonWriter. |
| src/Metano.Build/buildTransitive/Metano.Build.targets | Adds MetanoSrcRoot property passthrough to CLI args. |
| src/Metano.Build/build/Metano.Build.targets | Adds MetanoSrcRoot property passthrough to CLI args. |
| js/sample-todo-service/package.json | Updates generated imports to remove the # alias entry. |
| dotnet-releaser.toml | Switches release build to Metano-packages.slnx to avoid building samples. |
| Metano-packages.slnx | Introduces packages-only solution file for release builds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e0ca805 to
fc39364
Compare
Normalize srcRoot by trimming trailing slashes so "src/" behaves like "src". Handle "--src-root ." as package root (full srcRelative becomes the output prefix). Avoid using NormalizePath on srcRoot since it strips leading ".." segments.
danfma
added a commit
that referenced
this pull request
Apr 15, 2026
) Closes task #51 — the first of three gaps that block UseIrBodiesWhenCovered from going default-on. C#'s `decimal` surfaces as the decimal.js Decimal class at runtime, which needs method-call dispatch (`a.plus(b)`, `.times`, `.div`, `.mod`, `.eq`, `.lt`, …) instead of the raw TS `+` / `*` / `/` operators. The legacy OperatorHandler detects both operands as System_Decimal via the SemanticModel and rewrites the call accordingly (TryMapDecimalBinary). The IR path used to emit raw IrBinary- Expressions and the TS bridge had no way to recover the type info to rewrite at lowering time. IrExpressionExtractor.ExtractBinary now runs the same detection: when both sides are Decimal and the operator maps to a decimal.js method, it normalizes the expression to an IrCallExpression (`IrMemberAccess(left, method)`, [right]). Inequality (`!=`) wraps the call in `IrUnaryExpression(LogicalNot, …)` to preserve the `!eq` convention. The rest of the binary-op path stays untouched so non-Decimal operands continue to use IrBinaryExpression — no behavior change for any other type. Regenerating SampleOperatorOverloading under UseIrBodiesWhenCovered = true confirms the fix: `this.cents / 100m` now lowers through `this.cents.div(100)` instead of raw `/`, and `amount * 100m` through `amount.times(100)`. Three decimal-adjacent gaps remain and block the flag flip: 1. Decimal literals (`100m`) don't wrap as `new Decimal("100")`. 2. `decimal → BigInt` conversions skip the `.round().toFixed(0)` chain legacy emits. 3. `Math.Round(decimal)` doesn't dispatch to `.round()`. Each is a separate extractor-side rewrite captured as task #52. Flag goes back to false at the end of this commit so production samples keep their canonical output. 522/522 .NET tests; all bun suites still green; every sample (regenerated with the flag off) shows zero diff. Part of #56
danfma
added a commit
that referenced
this pull request
Apr 15, 2026
…goes default-on (#56) Closes task #52 and flips UseIrBodiesWhenCovered default to true with zero diff across every regenerated sample (SampleTodo, SampleIssueTracker, SampleTodo.Service, SampleOperatorOverloading, and SampleCounter). Three extractor-side rewrites, all in IrExpressionExtractor, each mirroring a piece of the legacy ExpressionTransformer / LiteralHandler / InvocationHandler that used to run only via Roslyn symbols: 1. Numeric literals in a Decimal / BigInteger context. A new ClassifyNumericInContext consults SemanticModel.GetTypeInfo (lit).ConvertedType. When the inferred type is `decimal`, the literal is emitted as IrLiteral(text, Decimal) so the bridge wraps it as `new Decimal("…")`; for BigInteger contexts IrLiteral(text, BigInteger) produces the native `n` suffix (`150n`). Covers both explicit `100m` literals and implicit conversions in mixed-type arithmetic. 2. Numeric casts that change representation. ExtractCast takes over CastExpressionSyntax handling and produces the four shapes the legacy emits: `(decimal)bigInt` → `new Decimal(val.toString ())`, `(BigInteger)decimal` → `BigInt(val.toFixed(0))`, `(int|long|...)decimal` → `val.toNumber()`, and `(BigInteger) int|long|decimal` → `BigInt(val)`. Uses IrTypeReference("BigInt") for the global builtin so the TS bridge's camelCase pass doesn't rewrite it to `bigInt`. 3. `Math.Round/Floor/Ceiling/Abs` on a decimal argument. A new TryRewriteMathDecimalCall detects `System.Math.Round(decimal)` style calls and rewrites them to the receiver's instance method (`amount.round()`), matching decimal.js semantics. Multi-argument overloads fall through to the normal BCL mapping path. Bridge support: - IrToTsExpressionBridge.MapLiteral now emits `new Decimal("val")` for Decimal kind and `valn` for BigInteger kind; IntN literals keep the plain number form. - MapNewTarget special-cases IrPrimitiveTypeRef(Decimal) so synthesized `new Decimal(...)` expressions (produced by ExtractCast) reach the decimal.js constructor even though the type mapper flattens decimal to `number` for signatures. Validation: every TS sample plus SampleCounter.dart regenerates byte-identical to the legacy output with the flag on. 522/522 .NET tests; bun suites all green (18 + 65 + 19). Follow-up: the flip to true is local to this commit — the refactor's wrap-up will decide whether to land default-on as part of the legacy-retirement series or keep the seam as an opt-in for another round. Part of #56
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
--src-rootCLI parameter (MetanoSrcRootMSBuild property) to specify the TypeScript source root relative to the package rootsrc/domain/), the output prefix (domain) is applied to dist paths and export subpaths#custom/*), with stale managed keys (#,#/*) cleaned up automatically--src-rootis an ancestor of the output path — emit MS0007 warning on mismatchMetano-packages.slnxto avoid file-lock conflictsExample
With
MetanoOutputDir = src/domain/:Before (wrong):
After (correct):
Test plan
Metano-packages.slnxbuilds successfullyCloses #50