Мы рады объявить о нашем новом выпуске Retyped и о том, что мы добавили поддержку более 1200 новых библиотек привязки. Это доводит общее количество библиотек привязки, которые могут использоваться в проектах Bridge.NET, до 3600+.

«Retyped теперь поддерживает использование более 3600 библиотек JavaScript в проектах C # в сочетании с Bridge.NET».

Факты о повторном вводе

  1. 1500+ коммитов в основной репозиторий исходного кода Retyped
  2. Ретипированное решение включает 14 проектов и 25000 LOC (VS Code Metrics)
  3. Более 2000 модульных тестов охватывают логику синтаксического анализа и перевода.
  4. Retyped читает NPM, ОпределенноTyped и исходные репозитории для сбора файлов декларации TypeScript для каждой библиотеки.
  5. Retyped содержит 25000 файлов d.ts, принадлежащих более 4000 библиотекам
  6. Для созданных решений C # требуется 100 ГБ дискового пространства.
  7. Полная перекомпиляция занимает 2 часа (4 потока на Core i7)
  8. 3600+ перепечатанных пакетов теперь доступны на NuGet
  9. Общее количество скачиваний всех Retyped пакетов теперь превышает 1,0 миллиона.
  10. Самые популярные пакеты - Retyped.jquery и Retyped.node.

Развитие Retyped очень увлекательно для нашей команды, и мы продолжаем постепенно улучшать Retyped каждый день.

Что нового в Retyped 1.5

Этот выпуск включает исправления и улучшения примерно для 100 проблем, а важные новые функции описаны ниже.

Поддержка NPM

С момента своего создания Retyped использовал только ОпределенноТипед в качестве единственного источника файлов объявлений. Retyped new правильно управляет сотнями пакетов, опубликованных только в NPM или в отдельных репозиториях GitHub.

Помимо чтения исходных файлов .d.ts, Retyped также отслеживает метаданные для каждой библиотеки, включая автора (авторов), номер версии и описание. См. Пример decimal.js.

Многие библиотеки больше не публикуют свои официальные файлы .d.ts в DefinentyTyped, поэтому, чтобы обеспечить включение только самых последних выпусков библиотек, Retyped найдет официальное расположение источника и будет читать оттуда.

Виртуальные члены

Все члены класса (кроме членов ObjectLiteral) теперь объявляются с модификатором virtual, который обеспечивает более чистый метод переопределения. Просто сравните следующие примеры кода.

Старый синтаксис

Https://deck.net/70b444440f3bdd37ee238ea64c29f915

public class MyConsole : SpecialConsole
{
    [Name("Print")] // <-- overrides the external base member
    public void Print(string msg)
    {
        Console.WriteLine(msg);
    }
}
[External]
public class SpecialConsole
{
    public extern void Print(string msg);
}

Новый синтаксис

Https://deck.net/fb15de62219f27a9379f07c84d143214

public class MyConsole : SpecialConsole
{
    public override void Print(string msg)
    {
        Console.WriteLine(msg);
    }
}
[External]
public class SpecialConsole
{
    public virtual extern void Print(string msg);
}

Выражения в объявлениях Enum

Retyped теперь может генерировать правильный C # для библиотек, объявляющих элементы перечисления с использованием выражений.

enum Permission 
{
    Nobody = 0,
    Owner = 1,
    Officer = 2,
    Member = 4,
    Moderator = 8,
    AllMembers = Owner | Officer | Member | Moderator
}

Типы делегатов и наследование

Есть два способа объявить тип делегата в TypeScript:

Площадка для TypeScript

type ToStringDelegate1 = (n: number) => string;
interface ToStringDelegate2 {
    (n: number): string;
}

Ранее Retyped создавал объявление делегата для ToStringDelegate1 и объявление интерфейса для ToStringDelegate2. Теперь оба типа будут испускаться одинаково:

public delegate string ToStringDelegate1(double n);
public delegate string ToStringDelegate2(double n);

Объявление интерфейса не будет свернуто до простого типа делегата, если оно содержит дополнительные члены или если оно является производным от другого делегата.

В этом случае могут быть сгенерированы некоторые вспомогательные члены (если возможно): конструктор, принимающий аргумент типа делегата и набор неявных операторов - все это поможет с инициализацией и приведением типов.

Типы фиксированных конструкторов

Типы конструкторов напоминают типы функций с основным отличием, они предполагают использование ключевого слова new.

Чтобы гарантировать это, Retyped генерирует класс, содержащий конструктор, позволяющий инициализировать тип конструктора с помощью LINQ Expression. Выражение указывает на конкретный конструктор некоторого типа. Еще один полезный член - метод Invoke, который вызывает предоставленный конструктор и создает экземпляр типа.

TypeScript

class A { /* .. */ }
let aCtorType: new () => A;
aCtorType = A;
let a = new aCtorType();

C#

Https://deck.net/5fbcef09355da563d9b754561179d657

public class Program
{
    public static void Main()
    {
        ACtorFn aCtorType;
        aCtorType = new ACtorFn(() => new A());
        var a = aCtorType.Invoke();
    }
}

Заявления по умолчанию для импорта / экспорта

Ранее Retyped имел некоторые пробелы в обработке заявлений по умолчанию для экспорта.

Теперь такие операторы полностью поддерживаются как в логике синтаксического анализа, так и в логике разрешения типов. Итак, учитывая следующий код TypeScript:

declare module "test" {
    namespace NS {
        class A {
        }
    }
    export default NS.A;
}

... будет создан следующий C #:

[Retyped.Scope]
[Bridge.GlobalMethods]
[Retyped.ExportedAs("NS.A", IsExportDefault = true)]
[Bridge.Module(Bridge.ModuleType.UMD, false, Name = "test")]
public static class test
{
    [Retyped.Scope]
    public static class NS
    {
        [Bridge.Name("default")]
        [Retyped.ExportedAs("test.NS.A")]
        public class A : Retyped.IObject
        {
        }
    }
}

Внешние модули

Было несколько улучшений, посвященных модулям окружения. К ним относятся предотвращение конфликтов имен, расширение, разрешение типов и поддержка различных методов импорта и экспорта, включая псевдонимы. Например, в TypeScript одна сущность может быть импортирована с использованием нескольких разных стилей операторов.

import * as lib from ".."
let a: lib.A;
import { A } from ".."
let a: A;
import A from ".."
let a: A;
import { A as B } from ".."
let a: B;

Все вышеперечисленное теперь работает как в обычных, так и в эмбиентных модулях.

Общие ограничения

Это самая важная и в то же время сложная для обсуждения тема. Мы пытались исправить проблемы, связанные с общими ограничениями, но они возвращались в виде все более сложных сценариев.

Мы пришли к выводу, что ограничения TypeScript просто не могут быть обработаны с помощью системы ограничений C #. Это заставило нас задуматься о реализации нашего собственного механизма ограничения типов. Мы предложили реализовать новый атрибут [Where], позволяющий применять гибкие правила ограничений. Например, ограничение типов Union или Псевдонимов типов.

В настоящее время ведется дополнительная работа над реализацией атрибута [Where], и мы будем признательны за ваш отзыв. Подробнее см. Мост Проблема № 3452.

Тестирование разрешения типа

Как упоминалось выше, у нас есть более 2000 модульных тестов, которые помогают нам проверить качество и согласованность сгенерированного кода C # для Retyped во всех более чем 3600 поддерживаемых библиотеках. Управление таким большим количеством проектов с помощью связанного набора модульных тестов - непростая задача, требующая высокого уровня автоматизации.

Эта тема заслуживает отдельного сообщения в блоге, но на данный момент у нас есть интеграционные тесты, охватывающие весь жизненный цикл Retyped, включая loading libs -> parsing -> emitting C# -> generating solutions -> resolving all dependencies -> full recompilation -> generating NuGet packages -> publishing to NuGet.

Перепечатанные демо

Сайт Retyped Demos в настоящее время содержит 15 демонстрационных проектов, и в ближайшее время будут добавлены новые. Исходный код всех демонстраций доступен на GitHub.

Создание многих повторных демонстраций включало простой перенос исходного примера с JavaScript на C #. В большинстве случаев нам удавалось просто скопировать / вставить код JavaScript непосредственно в проект C #, а затем выполнить несколько тривиальных корректировок, таких как преобразование сигнатур функций JavaScript в объявления методов C #.

Благодаря соглашению об именах Retyped, большая часть использования JavaScript API не требует настроек, таких как изменение регистра с camelCase на PascalCase. Эта основная функция Retyped экономит огромное количество времени, снижает количество точек отказа и обеспечивает совместимость с исходной библиотекой.

Мы пытаемся создать демонстрационные проекты с исходным кодом C #, который точно соответствует первоначальному замыслу авторов, включая как функциональность, так и стиль синтаксиса.

При использовании Retyped и Bridge удивительно стираются границы между разными технологиями и языками.

Повторное управление версиями

Схема управления версиями пакетов Retyped вызвала несколько вопросов, поэтому давайте обрисуем некоторые из наших начальных требований и окончательный подход.

Требования:

  1. Повторно набранные пакеты можно рассматривать как привязки Bridge.NET, что делает их зависимыми от Bridge.Core, который предоставляет информацию о требуемой версии Bridge.
  2. Нам нужно было отслеживать, какая версия компилятора Retyped использовалась для создания пакета.
  3. Файлы деклараций тесно связаны с версией TypeScript, для которой они созданы. Это еще одна информация, которую необходимо идентифицировать.
  4. У каждой библиотеки есть своя собственная версия, поэтому она также должна быть отражена в пакете Retyped.
  5. Процесс сборки полностью автоматизирован, поэтому требовалось указать временную метку даты компиляции.

Подход:

  • Базовый пакет был создан и добавлен как зависимость к каждому повторному пакету. Пакет назывался Retyped.Core, он содержит специфичные для Retyped типы, такие как атрибуты. Пакет Retyped.Core зависит от Bridge.Core - вместе они предоставляют информацию о версиях компилятора Retyped и Bridge.NET соответственно.
  • Повторно типизированные пакеты, такие как Retyped.es5 или Retyped.dom, построены на основе базовых библиотек TypeScript, поэтому они могут представлять версию TypeScript.
  • Пакет Retyped, созданный для библиотеки, получает версию этой библиотеки.
  • Все упомянутые выше пакеты получают версию patch , представляющую количество дней, прошедших с 1 января 2000 года (калькулятор).

В качестве примера возьмем пакет Retyped.node и некоторые его зависимости:

  • Retyped.node 9.6.6685 = NodeJS 9.6
  • Retyped.dom 2.8.6685 = TypeScript 2.8
  • Retyped.Core 1.5.6685 = Retyped 1.5
  • Bridge.Core 17.0.0 = Bridge 17.0
  • * .6685 = дата выпуска была 6685 дней после 2000–01–01 = 2018–04–20

Надеюсь, что эта информация поможет вам лучше ориентироваться между версиями и выпусками пакетов Retyped.

Повторно напечатанная дорожная карта

Этот выпуск является важной вехой для Retyped. Прошло много времени с тех пор, как мы запустили такое массовое обновление, синхронизирующее с последними объявлениями.

Впрочем, впереди еще дорога. Имеются планы по реализации таких функций, как ночные инкрементные сборки и автономные пакеты со всеми необходимыми файлами JavaScript для каждого встроенного пакета.

Ретипованный и мост Премиум

Знаете ли вы, что Bridge.NET - это бесплатное программное обеспечение с открытым исходным кодом, поддерживаемое сообществом? Мы финансируем разработку Bridge и Retyped, предоставляя дополнительные плагины Premium и ускоренную службу поддержки Premium. Пожалуйста, ознакомьтесь с опциями Bridge Pro и Enterprise Premium.

Спасибо за интерес к Retyped и Bridge.NET!