Skip to content

SupportedFeatures pt BR

Edgar Mesquita edited this page Aug 23, 2026 · 2 revisions

Matriz de recursos C# suportados

🌐 Esta página em: English · Português

Este documento traz uma lista abrangente dos recursos de C#, APIs .NET e padrões suportados pelo compilador do eQuantic.UI.

Legenda

Suporte completo: transpila para um comportamento JavaScript equivalente.

⚠️ Suporte parcial: funciona com ressalvas ou diferenças pequenas.

Sem suporte: lógica fundamentalmente incompatível (ex.: I/O bloqueante, ponteiros unsafe).


🏗️ Recursos centrais da linguagem

Recurso Status Notas
Classes e structs Transpilados para classes ES6.
Interfaces Usadas na checagem de tipos do TypeScript (apagadas em runtime).
Enums Atravessam como o nome em camelCase (MainAlign.Start'start'). .ToString() e interpolação dão o nome do membro C# ("Start"), o mesmo texto que o servidor imprime. Desde 0.2.0-preview.15.
Genéricos Totalmente suportados (apagados em runtime).
Extension methods Resolvidos pelo Semantic Model e transpilados para chamadas diretas.
Async / await Mapeiam para async / await e Promise.
Expressões lambda Mapeiam para arrow functions () => {}.
Pattern matching Padrões is, padrões de propriedade, padrões recursivos.
Interpolação de string Mapeia para template literals `${var}`.
Null-coalescing ?? e ??= mapeados para os equivalentes JS.
Inicializadores de objeto new Obj { Prop = 1 }.
field (C# 14) Propriedades guardadas: o gêmeo ganha um slot $name (um nome que nenhum campo C# pode ter), um getter e o corpo do próprio acessor.
Acessores init Emitidos como setter JS, porque um corpo de init é onde um tipo declara a invariante dele, e descartá-lo perderia a checagem no cliente.
Inicializadores de coleção new List<int> { 1, 2 } mapeia para [1, 2].
Desconstrução var (a, b) = tuple mapeia para [a, b] = tuple.
Funções locais Transpiladas para funções internas.
Records (with) Mapeia para spread de objeto { ...src, prop: val }.
typeof Mapeia para o literal de string com o nome do tipo.
Chamadas base Mapeiam para a palavra-chave super.
cast e as Mapeiam para passagem/truncamento em JS.
sizeof Mapeia para os tamanhos dos primitivos C#.
Métodos anônimos delegate(...) { ... } mapeia para arrow functions.
params Um parâmetro REST (...xs). As duas formas de chamada do C# funcionam: argumentos expandidos e um array passado inteiro, que é espalhado. Desde 0.2.0-preview.15.
stackalloc Mapeia para typed arrays (ex.: Int32Array).
yield return Mapeia para generator functions do JS (function*).
lock ⚠️ Transpilado para um bloco sem efeito (JS é single-threaded).

🔄 Suporte a LINQ

O compilador inclui estratégias especializadas para quase todos os métodos LINQ.

Lógica Métodos Status
Filtragem Where, OfType
Projeção Select, SelectMany, Cast
Particionamento Skip, Take, SkipWhile, TakeWhile
Ordenação OrderBy, OrderByDescending, ThenBy, Reverse
Agregação Count, Sum, Min, Max, Average, Aggregate
Quantificadores Any, All, Contains
Conjuntos Distinct, DistinctBy, Union, Intersect, Except, Concat
Elementos First, FirstOrDefault, Single, Last, ElementAt
Utilitários SequenceEqual, DefaultIfEmpty
Conversão ToList, ToArray, ToDictionary, ToHashSet
Agrupamento/Join GroupBy, Join, Zip

📦 Tipos .NET (BCL)

Mapeamos os tipos .NET comuns para os equivalentes em JavaScript.

Primitivos

Tipo .NET Equivalente JavaScript
string String
int, double, float Number
bool Boolean
object Object
dynamic any

System.String

  • Join, Format
  • IsNullOrEmpty, IsNullOrWhiteSpace
  • Split, Replace, Substring, Trim
  • ToLower, ToUpper, StartsWith, EndsWith

System.DateTime, TimeSpan, DateOnly, TimeOnly e DateTimeOffset

Os tipos temporais são respaldados por tipos compatíveis com precisão de tick (ticks de 100 ns, calendário gregoriano proléptico, não o mapeamento com perda de new Date() / milissegundos numéricos). Construtores, componentes, Add*, aritmética (-TimeSpan), comparações e o .ToString() invariante batem todos com o .NET; os valores atravessam o fio do SSR como strings ISO-8601 / "c" e são hidratados de volta no tipo compatível. Veja a tabela Cobertura e conformidade da BCL .NET abaixo para o detalhe por tipo.

System.Collections.Generic

  • List<T> → Array [] do JavaScript
  • Dictionary<TKey, TValue> → objeto simples {} para chaves string/número/enum; $eq.collections.valueMap para chaves de record/struct/tupla (chaves de igualdade estrutural, então duas chaves iguais por valor colidem como no .NET).
  • HashSet<T>Set do JavaScript.
  • ContainsKey / TryGetValue perguntam pela chave própria do objeto, então um dicionário nunca responde por "constructor", "toString" ou qualquer outra coisa em Object.prototype. Desde 0.2.0-preview.15.
  • Queue<T>, Stack<T>, LinkedList<T>, SortedSet<T>, SortedDictionary<K,V>, SortedList<K,V> → coleções compatíveis do runtime, sob $eq.collections.*.

System.Threading.Tasks

  • Task, Task<T>Promise.
  • Task.Delay → wrapper de setTimeout.
  • Task.WhenAll, Task.WhenAny.
  • ⚠️ Task.Run executa na thread principal (microtask), NÃO numa thread de fundo.

Outros utilitários

  • Console.WriteLineconsole.log.
  • Math.* (Min, Max, Abs, Round, etc.) → Math.*.
  • Guid (NewGuid, Empty, Parse) → crypto.randomUUID().
  • RegexRegExp do JavaScript.

🌐 Pacotes do ecossistema

eQuantic.UI.Lucide / Heroicons / RadixIcons / TablerIcons / Phosphor / SimpleIcons / BootstrapIcons / Iconoir / ...

Propósito: conjuntos de ícones abrangentes. Contêm:

  • Lógica de resolução de SVG
  • Componentes de ícone especializados
  • Implementação de IIconProvider
Pacote Propósito Status
eQuantic.UI.Charts (Apex/ChartJS) Visualização de alta performance.
eQuantic.UI.Lottie Animações de alta performance.
eQuantic.UI.Image Otimizada (Lazy/Blur/Priority).
eQuantic.UI.Tailwind Integração de estilo padrão.

🧩 Padrões do framework

Padrão Interface Descrição Status
Gestão de metadados IHandleMetadata Tags de SEO e elementos do head.
Gestão de assets IRequireAssets Injeção dinâmica de script/estilo.
Server Actions [ServerAction] RPC seguro do cliente para o servidor.
Componentes compostos N/A Padrões de subcomponentes semânticos.

⚠️ Limitações e ressalvas

  1. Código bloqueante:

    • .Wait() e .Result em Tasks NÃO são suportados. Você tem que usar await. Bloquear a thread principal congela a interface do browser.
  2. Reflexão:

    • System.Reflection é largamente sem suporte.
    • typeof(T).Name e nameof(...) são constantes suportadas.
  3. Sistema de arquivos:

    • System.IO (File, Directory) não é estritamente proibido, mas vai falhar em tempo de execução no browser.
    • Use Server Actions para lidar com operações de arquivo.
  4. Números:

    • int/double/float mapeiam para números do JS. A divisão inteira trunca (Math.trunc) e o Math.Round usa arredondamento bancário (MidpointRounding.ToEven) pelo helper compatível round.
    • decimal é exato de ponta a ponta: compilado para o tipo compatível Decimal do runtime (mantissa BigInt + escala), então 0.1m + 0.2m == 0.3m é true. Decimais também atravessam o fio como strings JSON (EqJson) e são hidratados de volta em Decimal no cliente (o padrão Decimal do campo guia uma coerção que preserva o tipo, veja hydrate-value.ts), então os decimais vindos do servidor mantêm todos os 28 dígitos em vez de arredondar por um double.
    • long/ulong agora são exatos: compilados para BigInt do JS pelo helper compatível long. 9007199254740993L + 1L é 9007199254740994 (um número JS comum arredondaria para …992). Literais viram BigInt (5L5n); operandos de aritmética/comparação são embrulhados em long() (que coage number/stringbigint) para que expressões mistas nunca lancem. No fio, inteiros de 64 bits atravessam como strings JSON (Server Actions + estado do SSR, via EqJson) para que valores além de 2^53 sobrevivam à ida e volta. Outros sufixos de tipo numérico (1.5f, 100u) são removidos.
  5. Segurança entre threads:

    • Como o JS é single-threaded, instruções lock são compiladas para fora (ignoradas).
    • Thread.Sleep não é suportado (use Task.Delay).

🧪 Cobertura e conformidade da BCL .NET

A fidelidade da transpilação é imposta por um arnês de conformidade (tests/eQuantic.UI.Conformance.Tests): cada caso roda a mesma expressão C# de dois jeitos, transpilada para JS (executada pelo Bun embarcado) e avaliada diretamente em .NET (Roslyn scripting), e afirma resultados idênticos. Mais de 460 casos estão verdes.

(Mais recente: dicionários com chave de record via $eq.collections.valueMap.) Isso cobre tanto expressões quanto blocos de instruções (controle de fluxo: if/for/foreach/while/switch/ try-catch-finally/funções locais; o bloco roda numa IIFE e o valor retornado é comparado).

Toda construção resolve por um de três mecanismos (veja docs/DOTNET-COVERAGE-PROGRAM.md):

  1. Estratégia nativa: JS idiomático quando o runtime tem um equivalente.

  2. Helper compatível com .NET no runtime: semântica .NET fiel onde o JS não tem nenhuma. O transpilador emite esses sob um único namespace $eq (organizado por domínio), trazido com um import por módulo, import { $eq } from "@equantic/runtime" (resolvido pelo import map da página), em vez de N imports soltos de helpers, e $eq.* nunca pode colidir com um identificador do usuário no escopo gerado:

    • $eq.num: dec (Decimal exato), long (Int64 via BigInt)
    • $eq.math: round (arredondamento bancário)
    • $eq.text: format (formatação de número/string), stringBuilder
    • $eq.time: dateTime, timeSpan, dateOnly, timeOnly, dateTimeOffset
    • $eq.enums: parse (nome de membro de enum)
    • $eq.collections: queue (FIFO), stack (LIFO), valueMap (dicionário com chave estrutural), linkedList, sortedSet/sortedDictionary/sortedList (ordenados por chave)
    • $eq.nullable: arith, cmp (operadores Nullable<T> elevados: aritmética que propaga nulo, relacional falso em nulo)
    • $eq.equals: igualdade estrutural (por valor) para records/structs/tuplas (dá suporte a ==, .Equals, Contains, Distinct)
    • $eq.css: styleBuilder, classBuilder, joinClasses, whenClass (o subsistema de estilo)
  3. Falhar no que não é suportado: uma construção sem representação possível em JS agora levanta um erro de build (com um código EQ estável) em vez de ser emitida verbatim em silêncio. Duas camadas:

    • UnsupportedConstructStrategy (EQ2001): intrínsecos de referência tipada (__makeref, __refvalue, __reftype), tipos ponteiro, ponteiros de função.
    • goto/goto case/goto default (EQ2002): sem equivalente em JS; reestruture com laços/condicionais. (Blocos unsafe/fixed/lock desembrulham para o corpo deles, sendo o lock um no-op single-threaded, e um rótulo solto cai para a instrução interna dele.)
    • Fronteira cliente/servidor do SemanticValidator (EQ21xx): chamadas a System.IO, System.Net.Http, System.Net.Sockets, EF Core / System.Data, threading do SO (Thread/Monitor/Mutex), Process, InteropServices (P/Invoke), Reflection.Emit a partir de um componente cliente. (System.Threading.Tasks não é proibido: async mapeia para Promise.) A correção é mover a chamada para um [ServerAction].

    Qualquer outra construção que não bata em nenhuma estratégia é erro (EQ1001 para expressão, EQ1002 para statement, EQ1003 para o resto) e nada é emitido por ela. Antes passava verbatim com um aviso, o que dava uma build que sucedia e uma página que quebrava — recusar o que não consegue representar é justamente o ponto. Os diagnósticos saem na forma canônica do MSBuild, então falham o dotnet build e a IDE linka. A lista completa está em Diagnósticos.

Área Status Notas
Aritmética / bitwise / comparação a divisão inteira trunca; %, deslocamentos, `&
Math.* Truncatetrunc, Ceilingceil, Round bancário pelo helper round
decimal exato via Decimal (literais + + - * / == != < > <= >=)
Constantes numéricas int.MaxValue, double.Epsilon, … → literais
Parsing / Convert.* int/double.Parse, bool.Parse, Convert.ToInt32/ToDouble/ToString/ToBoolean/…
Strings Substring/IndexOf/Replace/Split/Pad/Trim(char)/Concat/Format/Join/IsNullOrEmpty/IsNullOrWhiteSpace; Equals/StartsWith/EndsWith/Contains/IndexOf cientes de StringComparison (Ordinal + IgnoreCase). Ordenação sensível à cultura (CompareTo) está fora de escopo.
char.* ToUpper/ToLower/IsDigit/IsLetter/IsWhiteSpace/… (cientes de Unicode)
StringBuilder tipo compatível: Append(incl. bool→"True"/"False")/AppendLine("\n")/Insert/Remove/Replace/Clear/Length/ToString
LINQ Where/Select/SelectMany/Where-Select(indexado)/OrderBy/Distinct(By)/GroupBy/ToDictionary/ToLookup/Zip/Chunk/MinBy/MaxBy/Take(While)/Skip(While)/Aggregate/Sum/Min/Max/Average/Count/Any/All/First/Last/Concat/Reverse/Join/GroupJoin/ThenBy/ThenByDescending (Join/GroupJoin = hash join que preserva a ordem sobre chaves primitivas; OrderBy+ThenBy = uma única ordenação composta estável, com a fonte copiada). O IGrouping vindo de GroupBy/ToLookup é usável como sequência (iterar, g.Select/g.Sum/g.Count()) e expõe g.Key; o indexador [key] de ILookup não é modelado.
Coleções List, Dictionary, HashSet (incl. inicializadores e .Count); compatíveis de Queue/Stack/LinkedList; família ordenada SortedSet/SortedDictionary/SortedList (enumeração ordenada por chave). Dicionários com chave de record/struct/tupla vão para $eq.collections.valueMap (chaves estruturais: construção, get/set em d[k], ContainsKey/Add/Remove/Clear/TryGetValue/GetValueOrDefault, Keys/Values/Count, foreach); dicionários com chave string/número/enum mantêm a forma de objeto simples. O indexador ILookup[key] devolve o grupo (ou vazio para uma chave ausente).
enum string com o nome do membro (igualdade/switch/ternário)
long/ulong exato via BigInt (helper long); literais 5L5n, no fio como string JSON
DateTime tipo compatível DateTime com precisão de tick: construtores, componentes, Add*, -TimeSpan, comparações, .ToString()/format; fio ISO-8601 + hidratação
TimeSpan tipo compatível TimeSpan com precisão de tick: From*, construtores, componentes/totais, + -, comparações, .ToString() "c" do .NET; fio "c" + hidratação
DateOnly / TimeOnly tipos compatíveis (.NET 6+): construtores, componentes, Add*(+ volta do TimeOnly), comparações, .ToString() invariante (MM/dd/yyyy / HH:mm); fio ISO + hidratação
DateTimeOffset tipo compatível com precisão de tick (hora de parede + deslocamento, comparado pelo instante): construtores, componentes, Offset/UtcDateTime/LocalDateTime, ToOffset, Add*, From/ToUnixTime*, - TimeSpan, comparações por instante, .ToString() invariante (MM/dd/yyyy HH:mm:ss zzz); fio ISO+offset + hidratação
record / struct / tupla de valor Semântica de valor. Records/structs são objetos simples (o posicional new Point(1,2){x,y}, inicializadores de objeto mesclam), tuplas são arrays com acesso a elemento por posição (t.Item1) e por nome declarado ((int X, int Y).X) → índice. ==/!=, .Equals, Contains, Distinct comparam estruturalmente via $eq.equals; o with copia e substitui. A desconstrução var (a, b) = … funciona para tuplas (destructuring de array, com buracos de descarte) e records (destructuring de objeto pela ordem do Deconstruct). Records são emitidos como classes JS nomeadas, carregando os métodos de instância do usuário + um equals estrutural, um with que preserva o protótipo, e o toString do .NET; a semântica de valor não muda. O pipeline de build descobre records por varredura e emite cada um como módulo próprio; componentes que referenciam um record o importam automaticamente (reativo, sem lista fixa). Os valores do SSR são re-hidratados de volta na classe do record no cliente (recursivamente, restaurando records aninhados e membros compatíveis), então métodos/instanceof sobrevivem. Cobre records posicionais e de corpo e structs simples (a construção por inicializador de objeto mapeia para o construtor pela ordem dos membros, com padrões por membro), mais herança de record (extends + super) e records genéricos (argumentos de tipo apagados). Dicionários com chave de record (Dictionary<RecordKey, V>) vão para $eq.collections.valueMap, para que chaves iguais por valor colidam como no .NET.
Nullable<T> (T?) HasValue/Value, GetValueOrDefault() (padrão ciente do tipo: 0/false/$eq.num.dec(0)/membro zero do enum/…) e GetValueOrDefault(fallback), ??; operadores elevados via $eq.nullable.*: a aritmética propaga null, o relacional (< > <= >=) é falso quando qualquer lado é nulo (não uma coerção numérica). O GetValueOrDefault() sem argumento em DateTime?/Guid?/struct devolve null, então use a forma com fallback ali.
Guid Guid.NewGuid()crypto.randomUUID(), Guid.Empty, Guid.Parse; fio como string

Clone this wiki locally