Repository navigation
🐛 fix: a class named as .NET names one of its types is a module the page imports - #891
Merged
Merged
Conversation
… a page names it The emitter keeps a list of names it takes for .NET's own, which map to JavaScript or to the runtime: Type, Uri, Console, Convert, Math, Regex and the rest. It dropped the import of any name on it before it asked whether the build writes a module of that name. A library's static class Type reached the page as Type.family(), with no import and no module of Type: the build said nothing, and the browser met a name nothing defined. The list now yields to IsAppModule, in the component's imports and in a class module's, and so does the rule that takes a name ending in Exception for .NET's: an exception class the app declares is a module of its own (#611). Six names of the list, each as a library's class a page calls, and the app's own class named Type: each is a module the page imports.
A page that builds a library's own exception wrote new OrderException('x').code with no import and
no module of it, since a name ending in Exception was taken for .NET's. The case fails on main's
emitter and passes with the fix before it.
The control of the list's rule: a page that calls System.Math, in a solution where no class is called Math, imports nothing for it and no module of that name is written. It passes on main's emitter and with the fix.
…uild writes A new capability, module-imports, with one requirement: a module imports each type it names that the build writes a module for, whatever the type is called, and a name .NET keeps for its own is left alone only where nothing of the app carries it. The ledger records #888.
… app's The first form of this fix asked whether the build writes a module of the name, and for the app's own types that question is asked by the name alone. An app that declares a class Math and calls System.Math from another file had that other file import the app's Math, which hides JavaScript's own inside the module, so Math.max was undefined there. Found in review, before any release. NamesAppType asks the module's own symbols: a name of the list is the app's where an identifier of the module binds to a type declared in source. A type of a referenced project was known by symbol already. The case holds both: a file that calls the solution's Math imports it, and a file that calls System.Math imports nothing of that name, with the class declared by the app and by a library. It fails on the first form for the app's class, and on main's emitter for both.
…ule's own code means it The requirement of module-imports asked whether the build writes a module of the name, and now says a name .NET keeps for its own is the app's where the module's own code names a type of the app by it, with a class Math beside a file that calls System.Math as a scenario.
A file that names a solution's Math and System.Math writes both under one name: measured, and left to #890. The design and the ledger say so.
There was a problem hiding this comment.
🟡 Changes recommended
Tipos introduzidos apenas durante o lowering ainda podem perder o import e causar nomes indefinidos em runtime.
1 open finding
What changed in this PR
Corrige imports de módulos cujos nomes coincidem com tipos .NET.
Changes:
- Usa símbolos para distinguir tipos da aplicação de tipos .NET.
- Adiciona onze casos de regressão.
- Registra o comportamento em OpenSpec e no ledger.
| File | Description |
|---|---|
TypeScriptEmitter.cs |
Ajusta a resolução de imports. |
AClassNamedLikeADotNetTypeTests.cs |
Adiciona testes de regressão. |
openspec/specs/module-imports/spec.md |
Define o contrato de imports. |
tasks.md |
Registra as tarefas concluídas. |
specs/module-imports/spec.md |
Arquiva o delta da especificação. |
proposal.md |
Documenta motivação e escopo. |
design.md |
Registra decisões e limitações. |
.openspec.yaml |
Configura a mudança arquivada. |
docs/LEDGER.md |
Registra a correção no histórico. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
An extension method declared in the app's own class Math, called as 2.Twice(), is written Math.twice(2): the name is in the module and nowhere in its source, so no identifier could be asked what it means, and the import was still dropped. The conversion introduces such a name for a type of the app by that type's symbol (UsedAppTypes), and NamesAppType now takes it for named. The case holds the class declared by the app and by a library. The app's fails without this.
A scenario of module-imports: a page that calls 2.Twice(), an extension the solution's Math declares, imports Math though its source names none. The design says where the name comes from.
…e it means it A class that is no component is written by another path of the emitter, with its own list of imports, and no case went through it. Three plain classes the page calls: one calls the solution's Math, one an extension that Math declares, one System.Math. With that path's condition put back as main has it, the case fails for the class declared by the app and by a library.
Main gained #879. Nothing conflicted: its entry is the chronology's last, and this branch's is not.
This was referenced Oct 13, 2026
Closed
edgarmesquita
added a commit
that referenced
this pull request
Oct 13, 2026
) #891 and #893 merged 39 seconds apart, #891 first, and the branch of #893 had not taken main in after it. Main held the entry of #888 in the chronology while docs/ledger/folded.json recorded the chronology without it, and LedgerTests failed on main: 189 entries where the last fold left 188. The entry is a file under docs/ledger/ now, as every event since the rule is, which puts the chronology back to the record byte for byte. The record is untouched (#894). Co-authored-by: Edgar Mesquita <edgar@equantic.tech>
7 of 8 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.


Closes #888
What
A class the app or a project it references declares under a name .NET uses for one of its own types is imported where a page names it.
static class Typereached the page asType.family(), with no import and no module ofType. The build said nothing, and the browser met a name nothing defined.Uri,Console,Convert,MathandRegex, for the app's own class of such a name, and for an exception class a library declares.For a developer who uses the SDK: a class may be called what .NET calls one of its own.
Why
The emitter keeps a list of names it takes for .NET's, which map to JavaScript or to the runtime. It dropped the import of any name on that list before it asked whether the build writes a module of that name. The rule that takes a name ending in
Exceptionfor .NET's did the same.Both rules now ask the module's own symbols: a name of the list is the app's where an identifier of the module binds to a type declared in source. The list stays for every other use of the name.
The first form of the fix asked only whether the build writes a module of that name. My review of it found that an app with its own
Maththen made a file that callsSystem.Mathimport the app's, which hides JavaScript's own inside that module. A type of a referenced project was already known by symbol, so only the app's own classes met it.Found while testing #887, where the test library's class was called
Typeand its module never appeared.Left for its own change: a file that names both a class of the solution and .NET's type of the same name has one binding for the two (#890). Before this change that file failed on the other call.
OpenSpec
openspec/changes/archive/2026-10-13-a-class-named-as-dotnet-names-one-is-imported, archived. It adds a capability,module-imports, with one requirement: a module imports every type the build writes that it names, whatever the type is called.Proof
AClassNamedLikeADotNetTypeTests: six names of the list as a library's class a page calls, the app's own class namedType, a library's exception class, a solution'sMathbeside a file that callsSystem.Math(declared by the app, and by a library), an extension declared in a class namedMathand called as2.Twice()(by the app, and by a library), three plain classes that are no component (one calls the solution'sMath, one its extension, oneSystem.Math), and a page that callsSystem.Mathwith no class of that name anywhere.Mathcase fails, and with the final form all fifteen pass.Mathand its source does not, so no identifier could be asked. It failed for the app's class before the change that answers it.eQuantic.UI.Compiler.Tests2148 passed andeQuantic.UI.Conformance.Tests5988 passed with 49 skipped, with main at cc32748 merged in.eQuantic.UI.Web.Tests1046 of 1047:WikiVocabularyTestsfails on the wiki's new German, Spanish and French pages, which 🐛 fix: the wiki's guards read every language a page is written in #886 fixes../scripts/check-openspec.shvalidates 58 items.MathandSystem.Mathis measured and filed as A file that names both a class of the solution and .NET's type of the same name calls one of them wrong #890, and a partial class split over two files is left with its reason.Checklist
dotnet teston the affected test projects: Compiler, Web and Conformance. No TypeScript changed./scripts/check-openspec.shpasses, and the change is archiveddotnet build samples/DefaultUIDashboard: builds with no warningdocs/LEDGER.mdline, citing the issue