v3.1.3
Cocoar.JsEval v3.1.3
Cocoar.JsEval.TsDefinition now emits valid TypeScript — and stops shipping a 10-year-old standard library.
This release is a pure fix-up of Cocoar.JsEval.TsDefinition. No API additions, no changes to any other package. Three latent renderer bugs silently produced .d.ts output that the TypeScript compiler refuses — so anyone piping GetTsDefinitions() into Monaco's worker, ts.createProgram, or an IDE language service has been running with partially broken IntelliSense and never knew.
The failure 3.1.2 and earlier users were hitting
A probe of the full default module set's output (ran ts.createSourceFile over every non-lib. file produced by GetTsDefinitions()):
Before 3.1.3:
AngleSharp.d.ts 10 parse diagnostics
Cocoar.d.ts 93 parse diagnostics
Dapper.d.ts 46 parse diagnostics
SqlKata.d.ts 91 parse diagnostics
System.d.ts 465 parse diagnostics
→ 5 of 9 files unusable to any real TypeScript consumer
The errors were invisible at the C# side — the renderer returned strings, nobody ever fed them through a TS parser to verify — but any consumer who did got a silently-degraded IntelliSense experience, missing completions for every affected type. This release lands those files clean:
After 3.1.3:
→ 9 of 9 files parse with zero diagnostics
What 3.1.3 does
Three independent renderer bugs, all fixed:
-
Task<T>/ValueTask<T>emitted the generic argument twice.NormalizeTypeNamebaked<T>into the returned string;BuildTypeStringappended it again fromTypeDefinition.GenericArguments. Result:Promise<T><T>— a parse error. The fix brings the handling in line with every other generic type:NormalizeTypeNamereturns the bare wrapper ("Promise"), and the caller owns generic-arg composition once. -
ref Tparameters and return types leaked the .NET ByRef suffix&into the TS output. Properties likeCurrent: T&onSpan<T>.Enumeratortripped TypeScript's intersection operator (which needs a right-hand operand). The existing ByRef check usedType.FullName.EndsWith('&'), butFullNameisnullfor generic type parameters — soref Ton a method return silently slipped through. Now usesType.IsByRef || Type.IsPointerwithGetElementType()to unwrap — the spec-correct path. -
Name-colliding types were declared twice in the same namespace.
TypeDefinition.FromTypehas an internalFriendlyName-based cache; distinctTypeinputs that collapse to the same friendly name return the sameTypeDefinitionreference. The renderer was adding that reference tonamespace.Typeson every encounter —System.d.tsalone emitted 40+ duplicate declarations (Type,Attribute,AdjustmentRule,RuntimeTypeHandle, …). Dedup'd on add.
Also in 3.1.3: lib.es5.d.ts / lib.es2015.core.d.ts stop shipping
Those were vendored copies of a very old TypeScript standard library (predating TS 4.x — the Microsoft copyright header in the file dates to the original 1.x-era bundle), historically shipped as a convenience for Monaco integrations. Two problems:
- Stale. A decade behind current TypeScript. Anyone using them as their Monaco source would be missing every post-ES5-core addition.
- Shadowing risk. Monaco's own TypeScript language service loads its own version-matched libs internally. Stacking ours on top could override fresher types — exactly the wrong default.
Neither this package nor any other Cocoar.JsEval.* package reads these files; they were pass-through resources. Dropping them removes ~4,940 lines of dead weight from the binary.
global.d.ts (hand-written, declares JsEval-specific globals — fetch, NewObject, exit, require) is unchanged and still ships.
Compatibility
Breaking for consumers who were reading lib.es5.d.ts / lib.es2015.core.d.ts directly from GetTsDefinitions(). If your code does:
var defs = tsDefService.GetTsDefinitions();
var lib5 = defs["lib.es5.d.ts"]; // ← KeyNotFoundException in 3.1.3…you have two supported migration paths:
Path A — trust Monaco's own libs (recommended). Monaco ships a version-matched set automatically. Don't inject anything from us.
Path B — embed fresh ES libs from the upcoming Cocoar.JsEval.TypeScript.V8 package. That package exposes EmbeddedResources.LibFiles — a 97-file, TS 6.0.2, ES-only set with no DOM surface. Usable even if you don't use the V8 transpiler itself:
using Cocoar.JsEval.TypeScript.V8.Internal; // (coming in 3.2.0)
foreach (var (name, content) in EmbeddedResources.LibFiles)
monacoEditor.LanguageService.AddExtraLib(content, $"ts:filename/{name}");NormalizeTypeName contract change (direct callers only). For Task<T> / ValueTask<T> the method now returns "Promise" instead of "Promise<T>" — the caller is expected to append the generic args from TypeDefinition.GenericArguments. Non-generic Task / ValueTask still return "Promise<void>" (unchanged; that comes from TypeMappings, not GenericTypeMappings). Consumers who use the bundled TypeScriptRenderer see no change — the final rendered .d.ts output for Task<string> is still Promise<string>, just composed once instead of twice.
Tests
Three new regression tests in JsEval.Tests.Engine/TsDefinitionTests.cs lock in the fixes:
Render_TaskOfT_DoesNotProduceDoubleGenerics— assertsPromise<string>is present and><(double-generics marker) is absentRender_RefReturn_DoesNotLeakAmpersand— asserts no&;or&>sequences anywhere in the output (uses aRefReturningSampletype withref intmethods)GetTsDefinitions_DoesNotShipLibFiles— assertslib.es5.d.ts/lib.es2015.core.d.tsare absent from the output
The three pre-existing Task*_MapsToPromise* tests were updated to reflect the new NormalizeTypeName contract ("Promise" instead of "Promise<string>"); end-to-end rendering is verified via the new regression tests that exercise the full BuildTypeString path.
Full suite: 306 tests green (Engine 140, Linq 119, TypeScript 29, Modules 18 — Fetch excluded as usual since it needs network).
Packages
| Package | Changed in 3.1.3 |
|---|---|
Cocoar.JsEval.TsDefinition |
✅ three renderer fixes + stop shipping stale lib files |
Cocoar.JsEval |
no change |
Cocoar.JsEval.Engine |
no change |
Cocoar.JsEval.Linq |
no change |
Cocoar.JsEval.TypeScript |
no change |
| All modules | no change |