Перейти к содержимому

Рекомендуемые сообщения

 

 

 

 

512px-TypeScript_Logo_(Blue).svg.png

 

 

 

 

Вместо вступления:

Я не считаю C-подобный синтаксис лучше синтаксиса lua и не буду заставлять вас переписывать все ваши программы на TypeScript! Я просто хочу поделится с вами альтернативой и рассказать про ее преимущества и недостатки.

 

# Что такое TypeScript?

TypeScript — язык программирования, представленный Microsoft в 2012 году и позиционируемый как средство разработки веб-приложений. Он создан для расширения JavaScript и он компилируется в JavaScript, но также существует инструмент для преобразования TypeScript кода в Lua. Вам может показаться, что этот транслятор крайне ограничен, но, поверьте мне, его возможности впечатляют.

 

# Почему его стоит попробовать?

Я сначала продемонстрирую некоторые возможности TypeScript графически, а потом подробно расскажу про установку и настройку необходимых инструментов. Я покажу вам далеко не все возможности TypeScript, а только самые основные и интересные.

Из-за большого размера контент каждого раздела будет скрыт под спойлер.

 

1. Статический анализ

Скрытый текст

Системы типов JavaScript и Lua во многом похожи, и потому они имеют некоторые общие проблемы, которые может решить TypeScript.

 

1.1 Проверка типов

Если функция или метод явно требует среди аргументов число, TypeScript не допустит что-то отличное от числа.

image.png.d5fc0b4b741592cf190d3a77c124c785.png

 

Lua тоже сообщит об этом, но только после запуска скрипта.

image.png.21ad2183b440c8b07a9b118bf2b45e19.png

 

1.2 Проверка существования полей и методов

Если вы попытаетесь обратится к несуществующему полю или методу, TypeScript сообщит вам об этом и даже поможет исправить, если вы, например, опечатались.

image.png.e6cf4d71e5b073e5d2595257259c12fa.png

 

В Lua мы узнаем об этом только после запуска скрипта.

image.png.610e5cdb29c1d11ea667e1c0587ecb49.png

 

2. Автодополнение

Скрытый текст

Благодаря статической типизации, редактор кода может подсказывать методы и поля объекта.

image.png.f2bb10226d369c05b792b6e659dfee3f.png

 

Или показать параметры, которые принимает метод.

image.png.e05fe44e605ca1ca6b43ba5ae2aa6ea8.png

 

Или текст документации.

image.png

 

3. ООП

Скрытый текст

3.1 Классы


class Player {
    username: string;

    constructor(username: string) {
        this.username = username;
    }

    greet() {
        print("Привет, " + this.username + "!");
    }
}

let alex = new Player("alex");
alex.greet(); // Привет, Alex!

 

Сгенерированный lua код

Скрытый текст


--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
Player = {}
Player.name = "Player"
Player.__index = Player
Player.prototype = {}
Player.prototype.__index = Player.prototype
Player.prototype.constructor = Player
function Player.new(...)
    local self = setmetatable({}, Player.prototype)
    self:____constructor(...)
    return self
end
function Player.prototype.____constructor(self, username)
    self.username = username
end
function Player.prototype.greet(self)
    print("Привет, " .. tostring(self.username) .. "!")
end
local alex = Player.new("alex")
alex:greet()

 

 

3.2 Модификаторы доступа

image.png

 

3.3 Наследование


class Player {
    username: string;

    constructor(username: string) {
        this.username = username;
    }
}

class Alex extends Player {
    constructor() {
        super("Alex");
    }
}

let alex = new Alex();
print(alex.username); // Alex

 

Сгенерированный lua код

Скрытый текст


--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
Player = {}
Player.name = "Player"
Player.__index = Player
Player.prototype = {}
Player.prototype.__index = Player.prototype
Player.prototype.constructor = Player
function Player.new(...)
    local self = setmetatable({}, Player.prototype)
    self:____constructor(...)
    return self
end
function Player.prototype.____constructor(self, username)
    self.username = username
end
Alex = {}
Alex.name = "Alex"
Alex.__index = Alex
Alex.prototype = {}
Alex.prototype.__index = Alex.prototype
Alex.prototype.constructor = Alex
Alex.____super = Player
setmetatable(Alex, Alex.____super)
setmetatable(Alex.prototype, Alex.____super.prototype)
function Alex.new(...)
    local self = setmetatable({}, Alex.prototype)
    self:____constructor(...)
    return self
end
function Alex.prototype.____constructor(self)
    Player.prototype.____constructor(self, "Alex")
end
local alex = Alex.new()
print(alex.username)

 

 

 

4. Стандартная библиотека и возможности языка

Скрытый текст

Многие методы стандартных типов TypeScript (такие как массивы и строки) также могут быть транслированы в lua.

 

4.1 Получение всех четных чисел массива, возведение в квадрат и соединение в строку через запятую


const items = [1, 2, 3, 4, 5];

items.push(6);

const result = items
    .filter(x => x % 2 == 0)
    .map(x => x ** 2)
    .join(", ");

print(result); // 4, 16, 36

 

Сгенерированный lua код

Скрытый текст


--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
-- Lua Library inline imports
function __TS__ArrayPush(arr, ...)
    local items = ({...})
    for ____, item in ipairs(items) do
        arr[#arr + 1] = item
    end
    return #arr
end

function __TS__ArrayFilter(arr, callbackfn)
    local result = {}
    do
        local i = 0
        while i < #arr do
            if callbackfn(_G, arr[i + 1], i, arr) then
                result[#result + 1] = arr[i + 1]
            end
            i = i + 1
        end
    end
    return result
end

function __TS__ArrayMap(arr, callbackfn)
    local newArray = {}
    do
        local i = 0
        while i < #arr do
            newArray[i + 1] = callbackfn(_G, arr[i + 1], i, arr)
            i = i + 1
        end
    end
    return newArray
end

local items = {
    1,
    2,
    3,
    4,
    5,
}
__TS__ArrayPush(items, 6)
local result = table.concat(__TS__ArrayMap(__TS__ArrayFilter(items, function(____, x) return x % 2 == 0 end), function(____, x) return x ^ 2 end), ", ")
print(result)

 

 

4.2 Модули


// main.ts
import { myFunction } from "./myLibrary";

myFunction();

// myLibrary.ts
export function myFunction() {
    print("Hi from myLibrary");
}

Сгенерированный lua код

Скрытый текст


-- main.lua
--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
local ____exports = {}
local ____myLibrary = require("myLibrary")
local myFunction = ____myLibrary.myFunction
myFunction(nil)
return ____exports

-- myLibrary.lua
--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
local ____exports = {}
function ____exports.myFunction(self)
    print("Hi from myLibrary")
end
return ____exports

 

 

4.3 Форматирование строк


const text = `2 + 2 = ${2 + 2}`;
print(text); // 2 + 2 = 4

Сгенерированный lua код


--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
local text = "2 + 2 = " .. tostring(2 + 2)
print(text)

 

# Как это работает?

Конечно же все не так просто. Компилятор просто так не узнает типы методов и полей объектов, с которыми мы будем работать. Для того, чтобы описать наше окружение необходимо написать так называемые файлы декларации или тайпинги. Хочу сразу вас обрадовать - это не ваша задача. Существует репозиторий с такими декларациями, в котором, на данный момент, существуют типы для большинства API и компонентов OpenOS и библиотеки GUI.

От вас требуется только установить все необходимые инструменты и правильно их настроить.

 

# Установка

Редактор кода

Вы можете использовать любой редактор кода с поддержкой TypeScript. Я рекомендую VSCode, который поддерживает его из коробки.

 

NodeJS

Он необходим нам для установки необходимых пакетов (он поставляется с пакетным менеджером npm) и для запуска транспилера. Вы можете скачать последнюю стабильную версию с официального сайта.

 

Использование плагина для VSCode (рекомендуется):

Скрытый текст

Вы можете установить плагин OpenComputersTS. В нем есть две команды:

  • OC-TS: Init - Создание нового проекта в пустой папке.
  • OC-TS: Mount - Подключение дисков из сохранений minecraft или эмулятора OCEmu в папку dist.

Для открытия окна с командами используйте сочетание Ctrl + Shift + P.

 

ici-RMCx-RWf.gif

 

Создание проекта вручную:

Скрытый текст

После установки NodeJS у вас должны появится команды npm  и node.

  1. Создайте новую папку для своего первого проекта
  2. Переключитесь в нее, используя терминал и все дальнешие действия выполняйте в ней
  3. Создайте npm пакет: npm init. После выполнения этой команды в папке появится файл package.json
  4. Добавьте в объект "scripts" в package.json строку "build": "tstl",
  5. Установите транспилер npm install --dev typescript-to-lua. После установки первого пакета у вас появится папка node_modules
  6. Установите тайпинги npm install --dev @opct/openos
  7. Создайте папку src для исходных файлов
  8. Создайте файл tsconfig.json со следующим содержимым:

{
    "compilerOptions": {
        "target": "esnext",
        "outDir": "dist",
        "module": "commonjs",
        "lib": ["esnext"],
        "strict": true,
        "moduleResolution": "node",
        "rootDir": "src",
        "types": ["lua-types/jit", "@opct/openos"]
    },
    "tstl": {
        "luaTarget": "JIT"
    }
}

Теперь вы можете размещать в src исходный код, например, main.ts со следующим содержимым:


import * as component from "component";
import { front } from "sides";

component.redstone.setOutput(front, 1);

 

Как запустить сгенерированный код в OpenComputers?

Самый удобный способ для доставки полученного кода - символическая ссылка. Вы можете заменить каталог dist ссылкой на папку диска.


# Создание ссылки через терминал
# linux / macos
ln -s /path/to/disk/home dist

# windows (cmd)
mklink /j dist C:\path\to\disk\home

Диски располагаются в папке .minecraft\saves\{сохранение}\opencomputers. Вам также необходимо отключить параметр filesystem.bufferChanges в файле .minecraft\config\opencomputers\settings.conf

После этого вы сможете запускать сгенерированный код прямо в игре.

 

Для компиляции используйте команду npm run build. Сгенерированные lua файлы появятся в папке dist.

 

# Что дальше?

Дальше, если вас действительно заинтересовал TypeScript, вы можете подробнее ознакомиться с языком и транспилером. Ссылки на документацию я оставлю ниже. Прошу также отписаться в тему по поводу гайда, инструментов, тайпингов и вообще высказать ваше мнение. Гайд достаточно сырой и его необходимо будет доработать, надеюсь на вашу помощь. Кроме того, я постараюсь ответить на все ваши вопросы и помочь с решением проблем, возникших при установке, настройке и использовании.

 

# Ссылки

 

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Morkoffka сказал:

После установки NodeJS у вас должны появится команды npm  и node.

  1. Создайте новую папку для своего первого проекта
  2. Переключитесь в нее, используя терминал и все дальнешие действия выполняйте в ней
  3. Создайте npm пакет: npm init. После выполнения этой команды в папке появится файл package.json
  4. Добавьте в объект "scripts" в package.json строку "build": "tstl",
  5. Установите транспилер npm install --dev typescript-to-lua. После установки первого пакета у вас появится папка node_modules
  6. Установите тайпинги npm install --dev @opct/openos
  7. Создайте папку src для исходных файлов
  8. Создайте файл tsconfig.json со следующим содержимым:

А есть плагин для VSCode, чтобы сетапать воркспейс нажатием одной кнопки?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

На тайпскрипте я, конечно, не писал, но пробовал MoonScript. Это такой язык, который транспилируется в Lua. У него тоже есть классы, сахара всякие. Но я на нём больше писать не хочу.

Выхлопной код получается страшный. Что не сильно способствует дебагу. А ещё он неоптимален. В том числе по размеру получающегося скрипта, и минификатор не сильно помогает.

Здесь, видимо, всё то же. Так что для опенкомпов будет проще всё же писать на Lua.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, Fingercomp сказал:

На тайпскрипте я, конечно, не писал, но пробовал MoonScript. Это такой язык, который транспилируется в Lua. У него тоже есть классы, сахара всякие. Но я на нём больше писать не хочу.

Выхлопной код получается страшный. Что не сильно способствует дебагу. А ещё он неоптимален. В том числе по размеру получающегося скрипта, и минификатор не сильно помогает.

Здесь, видимо, всё то же. Так что для опенкомпов будет проще всё же писать на Lua.

Тут оптимизатор нужен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
12 часа назад, hohserg сказал:

А есть плагин для VSCode, чтобы сетапать воркспейс нажатием одной кнопки?

Хорошая идея, я об этом даже не подумал. Можно также добавить в этот плагин автоматический поиск дисков (папки .minecraft\saves\xxx\opencomputers) и их подключение. Я займусь его написанием, не думаю что это слишком сложно.

 

11 час назад, Fingercomp сказал:

На тайпскрипте я, конечно, не писал, но пробовал MoonScript. Это такой язык, который транспилируется в Lua. У него тоже есть классы, сахара всякие. Но я на нём больше писать не хочу.

Выхлопной код получается страшный. Что не сильно способствует дебагу. А ещё он неоптимален. В том числе по размеру получающегося скрипта, и минификатор не сильно помогает.

Здесь, видимо, всё то же. Так что для опенкомпов будет проще всё же писать на Lua.

Я видел MoonScript в соседней теме. Он конечно хорош, учитывая что был создан специально для lua, но разве в нем есть статический анализ? Это хоть и не спасает от ошибок в рантайме, но позволяет уберечь программиста от отладки очень глупых ошибок и опечаток и обнаружить их еще до компиляции (или во время нее). Что касается отладки - действительно, код не сильно читаем. Я пока не знаю, насколько это возможно, но хотелось бы иметь отладчик. Технически, транспилер поддерживает карты кода, что позволяет сопоставить исходный typescript и сгенерированный lua код. Я пока не нашел полноценного lua отладчика для opencomputers, но думаю что он есть. В крайнем случае можно использовать библиотеку debug.

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

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, Morkoffka сказал:

Осталось лишь найти транспорт между игрой и VSCode, чтобы доставлять отладочные данные и можно будет написать отладчик как плагин для VSCode

А какие отладочные данные требуются?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, hohserg сказал:

А какие отладочные данные требуются?

Самые простые: уведомление VSCode об ошибке или брейкпоинте и передача строки, в которой произошла остановка. Если произошла ошибка, можно показать ее текст в редакторе.

Сложнее: передача состояния переменных из области видимости того места, где произошла остановка. Это уже более полезная информация, которая позволит не использовать print для отладки. Добавить стек вызовов и это уже можно будет назвать полноценным отладчиком.

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

21 час назад, hohserg сказал:

А есть плагин для VSCode, чтобы сетапать воркспейс нажатием одной кнопки?

Небольшая демонстрация.

Скрытый текст

ici-RMCx-RWf.gif

 

Надо исправить некоторые недочеты и добавить поддержку Linux.

Потом буду разбираться как загрузить его в каталог расширений и обновлю гайд.

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 часа назад, Morkoffka сказал:

Добавить стек вызовов

Стэк вызовов уже есть, его можно получать так: ```ok,err = xpcall(code, debug.traceback, args...)```. Однако, это будет стэк вызовов Lua-кода и нужно как-то получить соответствие TypeScript-коду

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
3 минуты назад, hohserg сказал:

нужно как-то получить соответствие TypeScript-коду

Да, все так. Я надеюсь, что с этим разберутся карты кода.

Кстати, есть идея касательно транспорта. Можно использовать интернет карту. Она же может совершать запросы к localhostу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может конечно. В этом случае плагин ide должен разместить локально свой сервис, к которому программа в игре будет обращаться в случае ошибки

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, hohserg сказал:

Может конечно. В этом случае плагин ide должен разместить локально свой сервис, к которому программа в игре будет обращаться в случае ошибки

Да, так и планировалось. При запуске отладчика плагин будет встраивать в запускаемый файл кусок кода, который устанавливает обработчики ошибок и подключается к серверу. Я правда не знаю какой протокол для этого использовать: можно http, а можно tcp или вебсокеты (если в opencomputers они есть). Тогда можно будет отправлять данные в оба направления, например, чтобы уведомить программу продолжить работу после остановки на брейкпоинте или перезапустится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@hohserg Я обновил гайд и залил плагин в каталог.

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Попробовал. OC-TS: Mount че-то не работает - ввожу команду и ничего не происходит. Как выбрать назначение ссылки для dist?

~~~

Может, я че-то не так делаю? Раньше не юзал VSCode

Изменено пользователем hohserg

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
10 часов назад, hohserg сказал:

Попробовал. OC-TS: Mount че-то не работает - ввожу команду и ничего не происходит. Как выбрать назначение ссылки для dist?

~~~ 

Может, я че-то не так делаю? Раньше не юзал VSCode

Я нашел ошибку (и даже не одну). Я использовал неправильный оператор (return вместо continue), и поэтому он выходит из команды, если хотя бы одно сохранение не содержит папку opencomputers. У меня было только одно сохранение, поэтому я сразу не нашел этот баг.

Я исправил его и опубликовал новую версию.

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

image.png.a1a48cbdfae11eb0db05691d259e7801.png

Сохранения у мя лежат в %AppData%\opencomputers\saves\, а не в %AppData%\.minecraft\saves\

Можно вынести это в конфигурацию куда-нить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, hohserg сказал:

image.png.a1a48cbdfae11eb0db05691d259e7801.png

Сохранения у мя лежат в %AppData%\opencomputers\saves\, а не в %AppData%\.minecraft\saves\

Можно вынести это в конфигурацию куда-нить?

Да, можно сделать опцию. Так и сделаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
36 минут назад, hohserg сказал:

image.png.a1a48cbdfae11eb0db05691d259e7801.png

Сохранения у мя лежат в %AppData%\opencomputers\saves\, а не в %AppData%\.minecraft\saves\

Можно вынести это в конфигурацию куда-нить?

Добавил. Открыть настройки можно сочетанием Ctrl + ,

image.png.fac6e1e5ac23bc4266aa7cabc06385c4.png

 

Относительные пути будут разрешены относительно домашней папки (в винде C:\Users\username). Абсолютные модифицированы не будут.

Изменено пользователем Morkoffka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Запускаю таску watch, транслированный файл появляется(чекнул через проводник), но в VSCode не отображается, таска watch не завершается 

image.png.c1821530cee3f59fa9c62f8cb5e9dabf.png

 

image.png.c50dc763166e3e003efa41785b2fea91.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...