diff --git a/docs/advanced/writing-declarations.md b/docs/advanced/writing-declarations.md index 360d1cd3..6d6d90ba 100644 --- a/docs/advanced/writing-declarations.md +++ b/docs/advanced/writing-declarations.md @@ -2,19 +2,19 @@ title: Writing Declarations --- -The real power of the transpiler is unlocked when combining it with declarations for your target environment. Declarations tell TypeScript which Lua API is available in your target context. +The best way to use TypeScript is to provide it with information about the format/types of the external functions and variables that you will be using (specific to your environment). This allows the compiler to check your code for mistakes when compiling, instead of having to run the code to find issues. To give TypeScript this information, you will need to provide it with type declarations. You can write these declarations yourself or, if available, install an existing type declarations package for your environment from npm. -If you need tips or help writing declarations, feel free to [join our Discord](https://discord.gg/BWAq58Y). +For more information about installing existing type definition packages, see the [getting started page](getting-started.md#type-declarations). -## About Declaration Files +This page has more information about how to write your own type declarations. This can be tricky, so if you need help, feel free to [join our Discord server](https://discord.gg/BWAq58Y). -Declaration files end with the extension _.d.ts_. These contain pure ambient code. +## About Declaration Files -For TypeScriptToLua, these files should contain information that describes the target Lua environment. +Declaration files end with the extension `.d.ts` (which stands for "declaration TypeScript file"). Declaration files are different from normal `.ts` files in that they must only contain _ambient_ code. In the context of TypeScript, _ambient_ refers to code that only exists at compile-time and is not emitted into the program output. -This means functions, modules, variables and other members of the target Lua environment are primarily described in these files. +In other words, anything you put into a `.d.ts` file will inform the TypeScript compiler about what the format of something is. And it will never appear in the generated `.lua` file(s). -They don't contain code that you would execute. Similar to how you'd write an interface in some other languages. TypeScriptToLua doesn't output any information from these files either. +For TypeScriptToLua, these files should contain information that describes the target Lua environment. This means functions, modules, variables and other members of the target Lua environment are primarily described in these files. :::note You can write ambient declarations inside _.ts_ files as well. @@ -38,7 +38,7 @@ declare const _VERSION: number; /** * Receives any number of arguments, and prints their values to stdout, using the - * tostring function to convert them to strings. print is not intended for + * `tostring` function to convert them to strings. print is not intended for * formatted output, but only as a quick way to show a value, typically for * debugging. For formatted output, use string.format. * @param args Arguments to print @@ -120,7 +120,7 @@ This allows users to modify `this` inside a function and expect behaviour simila But obviously Lua does not have a `self` parameter for every function, so one of the three options must happen to tell TypeScriptToLua there is no "contextual parameter" (`self`): -1. Use `this: void` as the first parameter of the function / method. This formally describes to TypeScript to not allow `this` to be modified inside this function. (you could also use the [noImplicitThis](../configuration.md#custom-options) option to disallow `this` to be modified if `this` is of an `any` type). +1. Use `this: void` as the first parameter of the function / method. This formally describes to TypeScript to not allow `this` to be modified inside this function. (you could also use the [noImplicitThis](configuration.md#custom-options) option to disallow `this` to be modified if `this` is of an `any` type). 2. Use `@noSelf` in the comments of the declaration's owner (the namespace, module, object, etc). 3. Use `@noSelfInFile` at the beginning of the file in a comment to make sure every function defined in this file does not use a "contextual parameter". @@ -172,7 +172,7 @@ Here are some commonly used TSDoc tags used in comments: | `@param ` | Defines a parameter. e.g. A parameter for a function | | `@return ` | Describes the return value of a function / method | -TypeScriptToLua takes this further. Some "tags" change how the transpiler translates certain pieces of code. These are referred to as [annotations](compiler-annotations.md). +TypeScriptToLua takes this further. Some "tags" change how the transpiler translates certain pieces of code. These are referred to as [annotations](advanced/compiler-annotations.md). As an example, `@tupleReturn` marks a function as something which returns multiple values instead of its array. @@ -197,7 +197,7 @@ let [c, d] = array(); // local c, d = unpack(array()) ``` -See [Compiler Annotations](compiler-annotations.md) page for more information. +See [Compiler Annotations](advanced/compiler-annotations.md) page for more information. ## Environmental Declarations @@ -223,7 +223,7 @@ We recommend reading about Mapped and Conditional types. These things can be use ## Declaration Merging -https://www.typescriptlang.org/docs/handbook/declaration-merging.html +Declaration merging is a feature of TypeScript that allows you to combine new declarations with ones that already exist. For more information, see [the TypeScript documentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html). Some examples of declaration merging have been shown in the above examples. @@ -532,7 +532,7 @@ const v3 = (v1 * 4) as Vector; const d = v3.dot(v2); ``` -The second option was added in version [0.38.0](https://github.com/TypeScriptToLua/TypeScriptToLua/blob/master/CHANGELOG.md#0380). You can now use [language extensions](https://typescripttolua.github.io/docs/advanced/language-extensions) that allow declaring special functions which will transpile to operators. This will be completely type safe if the operators are declared correctly. See [Operator Map Types](language-extensions.md#operator-map-types) for more information. +The second option was added in version [0.38.0](https://github.com/TypeScriptToLua/TypeScriptToLua/blob/master/CHANGELOG.md#0380). You can now use [language extensions](https://typescripttolua.github.io/docs/advanced/language-extensions) that allow declaring special functions which will transpile to operators. This will be completely type safe if the operators are declared correctly. See [Operator Map Types](advanced/language-extensions.md#operator-map-types) for more information. ### Import and export @@ -555,7 +555,7 @@ declare module "mymodule" { } ``` -## NPM Publishing +## npm Publishing It is possible to publish a list of declarations for other users to easily download via [npm](https://www.npmjs.com/). diff --git a/docs/caveats.md b/docs/caveats.md index 09e9f3a2..1deebd53 100644 --- a/docs/caveats.md +++ b/docs/caveats.md @@ -2,6 +2,10 @@ title: Caveats --- +Luckily, for most use-cases, you can write modern, idiomatic TypeScript, and TSTL will produce transpiled Lua that will work flawlessly. In other words, you probably will not have to worry about the idiomatic quirks of Lua or the internal decisions that TSTL makes when converting code. + +With that said, TSTL does have some "gotchas" that you might run into. This page covers some of those edge-cases. + ## Feature support | Feature | Lua 5.0 | Lua 5.1 | Lua 5.2 | Lua 5.3 | LuaJIT | @@ -17,7 +21,7 @@ title: Caveats ## Differences from JavaScript -This project aims for both compilation results to have the same behavior as much as possible, but not at all costs. Since TypeScript is based on JavaScript it also inherited some of the quirks in JavaScript that are not present in Lua. This is where behavior between Lua and JavaScript compilation targets diverge. TypeScriptToLua aims to keep identical behavior as long as **sane** TypeScript is used: if JavaScript-specific quirks are used behavior might differ. +This project aims for both compilation results to have the same behavior as much as possible, but not at all costs. Since TypeScript is based on JavaScript, it also inherited some of the quirks in JavaScript that are not present in Lua. This is where behavior between Lua and JavaScript compilation targets diverge. TypeScriptToLua aims to keep identical behavior as long as **sane** TypeScript is used: if JavaScript-specific quirks are used, behavior might differ. Below are some of the cases where resulting Lua intentionally behaves different from compiled JS. @@ -39,49 +43,82 @@ JavaScript and Lua differ in what they evaluate to true/false. TypeScriptToLua a | `0` | `false` | ⚠️`true` | | (Everything else) | `true` | `true` | +We recommend that you use the [`strict-boolean-expression`](https://typescript-eslint.io/rules/strict-boolean-expressions/) ESLint rule in your TSTL projects, which will force you to be explicit and prevent this class of bug entirely. + ### [Loose equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using) TypeScriptToLua makes no difference between `==` and `===` when compiling to Lua, treating all comparisons as strict (`===`). +We recommend that you use the [`eqeqeq`](https://eslint.org/docs/latest/rules/eqeqeq) ESLint rule, which will force you to be explicit and prevent this class of bug entirely. + +### `undefined` and `null` + +`nil` is the Lua equivalent for `undefined`, so TSTL converts `undefined` to `nil`. However, there is no Lua equivlanet for `null`, so TSTL converts `null` to `nil` as well. + +This means that TSTL programs with `null` will have different behavior than JavaScript/TypeScript programs. For example: + +```ts +const foo = { + someProp1: 123, + someProp2: null, + someProp3: undefined, +}; +``` + +If we iterated over `foo` in a TSTL program, we would _only_ get `someProp1`, instead of both `someProp1` and `someProp2` like we would in a JavaScript/TypeScript program. + +In general, we recommend keeping `null` out of your TSTL codebases in favor of `undefined`. Not only will this represent the transpiled Lua code better, but [it is more idiomatic in TypeScript to prefer `undefined` over `null` when both would accomplish the same thing](https://basarat.gitbook.io/typescript/recap/null-undefined). + ### Array Length -`Array.prototype.length` is translated to Lua's `#` operator. Due to the way lists are implemented in Lua there can be differences between JavaScript's `list.length` and Lua's `#list`. The transpiler does not do anything to remedy these differences, so when working with lists, the transpiled Lua will use the standard Lua conventions. Generally speaking, the situation where these differences occur happen when adding/removing items to a list in a hacky way, or when setting list items to `undefined`/`null`. +`Array.prototype.length` is translated to Lua's `#` operator. Due to the way arrays are implemented in Lua, there can be differences between JavaScript's `myArray.length` and Lua's `#myArray`. The transpiler does not do anything to remedy these differences. Thus, when working with arrays, the transpiled Lua will use the standard Lua conventions. Generally speaking, the situation where these differences occur happen when adding/removing items to an array in a hacky way, or when setting array items to `undefined` / `null`. -**Examples:** +For example: -**Safe (no difference):** +#### Safe (no difference) ```ts -const myList = [1, 2, 3]; -myList.push(4); -myList.pop(); -myList.splice(1, 1); -// myList.length == 2 +const myArray = [1, 2, 3]; +myArray.push(4); +myArray.pop(); +myArray.splice(1, 1); +// myArray.length == 2 ``` -**Differences might occur:** +#### Differences might occur ```ts -const myList = [1, 2, 3]; -myList[1] = undefined; -// myList.length == 1 (3 in JavaScript) +const myArray = [1, 2, 3]; +myArray[1] = undefined; +// myArray.length == 1 (which would be 3 in JavaScript) ``` ```ts -const myList = [1, 2, 3]; -myList[4] = 5; -// myList.length == 3 (5 in JavaScript) +const myArray = [1, 2, 3]; +myArray[4] = 5; +// myArray.length == 3 (which would be 5 in JavaScript) ``` ### Key Iteration Order Even though iterating over object keys with `for ... in` does not guarantee order in either JavaScript or Lua. Therefore, the iteration order in JavaScript is likely different from the order in Lua. -**Note:** If a specific order is required, it is better to use ordered collections like lists instead. +**Note:** If a specific order is required, it is better to use ordered collections like arrays instead. ### Iterating an array with `for ... in` -Not allowed. +Not allowed. Use a `for of` loop instead to iterate over an array. + +### Sorting + +A sorting algorithm is [said to be stable](https://stackoverflow.com/questions/1517793/what-is-stability-in-sorting-algorithms-and-why-is-it-important) if two objects with equal keys appear in the same order in sorted output as they appear in the input array to be sorted. + +- Sorting is part of the JavaScript standard library via the `Array.sort` method. It is guaraunteed to be [stable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort). +- Sorting is also part of the Lua standard library via the `table.sort` method. It is **not** guaraunteed to be [stable](https://www.lua.org/manual/5.3/manual.html#pdf-table.sort). + +TypeScriptToLua relies on the Lua standard library for sorting. In other words, it transpiles `[1, 2, 3].sort();` to `table.sort({1, 2, 3})`. So beware that your sorts will no longer be stable! + +If you need stable sorting, you have to manually use a custom sorting function. For some examples of this, see the [sorting helper functions from `isaacscript-common`](https://github.com/IsaacScript/isaacscript/blob/main/packages/isaacscript-common/src/functions/sort.ts). ### Local Variable Limit diff --git a/docs/external-code.md b/docs/external-code.md new file mode 100644 index 00000000..c2080535 --- /dev/null +++ b/docs/external-code.md @@ -0,0 +1,133 @@ +--- +title: External Code +--- + +In your `tstl` project, you might want to import some existing Lua code. Or, you might want to import a library from [npm](https://www.npmjs.com/). This page describes how to use external code. + +:::note +This page is about importing code that **actually executes something**. In a `tstl` project, it is common to depend on external library that provide type declarations. Type declaration libraries only provide types: they do not contribute any code to your actual program output. Thus, they work a little differently from what is discussed on this page. For information on how type declarations work, see the [type declarations page](advanced/writing-declarations.md). +::: + +## Adding Lua files to your project sources + +The most straightforward way to add Lua code is to put the Lua file directly next to your TypeScript files. Next, you add [a declaration file](advanced/writing-declarations.md) with the same name. Then, you can import the Lua code in your TypeScript. + +For example, a project might look like this: + +```text +project/ +├── main.ts +├── someLua.lua +├── someLua.d.ts +└── tsconfig.json +``` + +```ts title=main.ts +import { foo, bar } from "./someLua"; + +foo(); +bar(); +``` + +```lua title=someLua.lua +local someLua = {} + +function someLua:foo() + print("hello") +end + +function someLua:bar() + print("world") +end + +return someLua +``` + +```ts title=someLua.d.ts +export function foo(): void; +export function bar(): void; +``` + +## Importing a Lua module that only exports an array + +Building on the previous section, you might want also want to import a Lua file that exports an array. For example, something like: + +```lua title=things.lua +return { + { + foo = 123, + bar = 456, + }, + { + foo = 789, + bar = 987, + }, +} +``` + +Writing a definitions file for this is tricky, since the Lua file has no named imports and no default export. Here, you have to use `export =` syntax, like so: + +```ts title=things.d.ts +interface Thing { + foo: number; + bar: number; +} + +declare const things: Thing[]; +export = things; +``` + +Then, in your TypeScript code, you can import it like: + +```ts title=main.ts +import * as things from "./module"; + +print(things[0].foo); // Prints "123" +``` + +For more information about this export syntax, see [the official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require). + +## Importing Lua packages from npm + +`tstl` supports module resolution for libraries, which means you can _use_ and _create_ npm packages containing `.lua` files. (Most packages on npm contain JavaScript files, but npm allows you to create packages with whatever kinds of files you want.) + +### Using Lua packages + +To use a Lua package, install it via npm and use it in the same way that you would in a normal TypeScript project. In other words: + +```sh +# If you use npm: +npm install foo --save + +# If you use yarn: +yarn add foo + +# If you use pnpm: +pnpm add foo +``` + +And then use it in your code: + +```ts +import { someFunction } from "foo"; + +someFunction(); +``` + +Since the npm package was presumably made for `tstl` users, it will almost certainly include `.d.ts` files alongside the `.lua` files, which is necessary for `tstl` to import the Lua files properly. If there are no `.d.ts` files, you can try [creating some for the package yourself](advanced/writing-declarations.md). + +### Creating Lua packages + +For more information on creating a Lua package yourself, see [the page on publishing modules](publishing-modules.md). + +## Importing JavaScript or TypeScript packages from npm + +**Importing JavaScript or TypeScript packages from npm will not work.** This means that it is impossible to use common JavaScript/TypeScript libraries like [Underscore.js](https://underscorejs.org/) and so on. + +(It is not possible for `tstl` to work with a generic npm package because most TypeScript libraries only publish the compiled JavaScript to npm. And `tstl` can't convert JavaScript to Lua because it needs the type information to create correct code. For example, `tstl` needs to be able to distinguish between arrays and objects in order to write the correct index.) + +As a workaround, you can copy paste TypeScript code from a package repository directly into your project. (That way, it will be compiled by `tstl` alongside your normal code.) + +Alternatively, you could fork an existing package and re-publish it as Lua files (instead of JavaScript) so that it can be directly consumed by other `tstl` projects. However, doing this kind of thing will only work for really basic packages, since you would have to also fork all of the dependencies and convert those to Lua as well. + +Obviously, `tstl` programs will not have access to any of the Node.js standard libraries or APIs (like e.g. `import path from "path";`), so make sure that any code that you integrate into your project is not Node-specific. diff --git a/docs/external-lua-code.md b/docs/external-lua-code.md deleted file mode 100644 index ceea3757..00000000 --- a/docs/external-lua-code.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: External Lua Code ---- - -As of `0.40.0`, tstl supports module resolution for libraries, which means you can _use_ and _create_ npm packages containing `.lua` files. You can also include Lua source files directly into your source code. - -## Adding Lua files to your project sources - -You can simply add a Lua file as part of your project sources if you add [a declaration file](./advanced/writing-declarations.md) with the same name. You can then simply import the Lua code in your TypeScript. - -Your project should look like: - -``` -project/ -├── main.ts -├── someLua.lua -├── someLua.d.ts -└── tsconfig.json -``` - -```ts title=main.ts -import { foo, bar } from "./someLua"; - -foo(); -bar(); -``` - -```lua title=someLua.lua -local someLua = {} - -function someLua:foo() - print("hello") -end - -function someLua:bar() - print("world") -end - -return someLua -``` - -```ts title=someLua.d.ts -export function foo(): void; -export function bar(): void; -``` - -## Importing a Lua module that only exports an array - -Building on the previous section, you might want also want to import a Lua file that only exports an array. For example, something like: - -```lua title=things.lua -return { - { - foo = 123, - bar = 456, - }, - { - foo = 789, - bar = 987, - }, -} -``` - -Writing a definitions file for this is tricky, since the Lua file has no named imports and no default export. Here, you have to use `export =` syntax, like so: - -```ts title=things.d.ts -interface Thing { - foo: number; - bar: number; -} - -declare const things: Thing[]; -export = things; -``` - -Then, in your TypeScript code, you can import it like: - -```ts title=main.ts -import * as things from "./module"; - -print(things[0].foo); // Prints "123" -``` - -For more information about this export syntax, see [the official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require). - -## Using NPM packages - -To use a Lua package, install it via npm and use it as you would for any regular npm package in TypeScript. If the package does not include its own `.d.ts` declaration files, you can create your own by adding a `.d.ts` [declaration file](./advanced/writing-declarations.md) to your source files. - -:::note -Including TS or JS files from npm packages is currently NOT supported. -::: diff --git a/docs/getting-started.md b/docs/getting-started.md index 87334e50..ed6df8a2 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,32 +2,44 @@ title: Getting Started --- -This is a quick introduction into project setup and our CLI. For a TypeScript quick start please read: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html +This page will help you set up a new TypeScript project that will be converted to Lua with TypeScriptToLua. + +Note that we assume that you are already familiar with how TypeScript works. If you have never coded a project in TypeScript before, or you need a refresher, first read the [official TypeScript tutorial](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html). ## Installation -TypeScriptToLua is built using [Node.js](https://nodejs.org/) and distributed via [npm](https://www.npmjs.com/). To install it, you need to create a `package.json` file in the root of your project, containing at least `{}`. Then you can use this command to add the latest version of TypeScriptToLua to your project: +TypeScriptToLua is built using [Node.js](https://nodejs.org/) and distributed via [npm](https://www.npmjs.com/). To install it, you need to create a `package.json` file in the root of your project, containing at least `{}`. Then, you can add the latest version of TypeScriptToLua to your project: ```bash -npm install -D typescript-to-lua +# If you use npm: +npm install --save-dev typescript-to-lua + +# If you use yarn: +yarn add --dev typescript-to-lua + +# If you use pnpm: +pnpm add --save-dev typescript-to-lua ``` +(If you don't know the difference between the package managers, choose `npm`.) + :::note -Installing `tstl` locally is recommended to keep your build reproducible and prevent version conflicts between projects. However, it is also possible to install it globally with `npm install --global typescript-to-lua` or run it without install using `npx typescript-to-lua`. +Installing `tstl` locally is recommended to keep your build reproducible and prevent version conflicts between projects. However, it is also possible to install it globally with `npm install --global typescript-to-lua`. ::: ## Project setup -TypeScriptToLua shares the configuration format with vanilla TypeScript. This file is called `tsconfig.json` and should be located in your project's root. +TypeScriptToLua is configured using a `tsconfig.json` file. (This is the same file used to configure vanilla TypeScript.) It should be located in your project's root. -Basic recommended configuration: +### Basic Configuration ```json title=tsconfig.json { + "$schema": "https://raw.githubusercontent.com/TypeScriptToLua/TypeScriptToLua/master/tsconfig-schema.json", "compilerOptions": { - "target": "esnext", - "lib": ["esnext"], - "moduleResolution": "node", + "target": "ESNext", + "lib": ["ESNext"], + "moduleResolution": "Node", "types": [], "strict": true }, @@ -37,13 +49,48 @@ Basic recommended configuration: } ``` -Check out [Configuration](configuration.md) page for more information. +If your target Lua environment is not [LuaJIT](https://luajit.org/), make sure to change the value of `luaTarget`. Valid values are `JIT`, `5.3`, `5.2`, `5.1`, `5.0`, and `universal`. + +:::note +You can find out the version of your Lua environment by running: `print(_VERSION)` +::: + +Check out [configuration page](configuration.md) for more information. + +### Strictest Configuration + +If you want the TypeScript compiler to be as strict as possible, then you need to enable some additional flags. Handily, we can extend from [the "strictest" TypeScript community config](https://github.com/tsconfig/bases/blob/main/bases/strictest.json) to abstract this away by adding this to top of the `tsconfig.json` file: + +```json + // We extend the strictest base config: + // https://github.com/tsconfig/bases/blob/main/bases/strictest.json + "extends": "@tsconfig/strictest/tsconfig.json", +``` ## Building your project -Our command line interface is called `tstl` and it works almost exactly as TypeScript's `tsc`. +Our command line interface is called `tstl` and it works almost exactly the same as TypeScript's `tsc`. -Since `tstl` is installed locally to your project, you cannot run it as a bare command in your terminal, so it's recommended to use it with [npm scripts](https://docs.npmjs.com/misc/scripts). +Since `tstl` is installed locally to your project, you cannot run it as a bare command in your terminal. Instead, use: + +```bash +# If you use npm: +npx tstl + +# If you use yarn (yarn also uses npx): +npx tstl + +# If you use pnpm: +pnpm exec tstl +``` + +:::note +The binary is installed to `node_modules/.bin/tstl`, so you can also run it directly from that path if needed. (But this is not recommended.) +::: + +### npm scripts + +You can also run `tstl` as an [npm script](https://docs.npmjs.com/misc/scripts). Using npm scripts for this sort of thing is idiomatic in JavaScript/TypeScript projects. This is accomplished by adding a `scripts` field to the `package.json` file: ```json title=package.json { @@ -58,6 +105,8 @@ Since `tstl` is installed locally to your project, you cannot run it as a bare c } ``` +Then, you can run the script like this: + ```bash # Build npm run build @@ -66,21 +115,34 @@ npm run build npm run dev ``` -:::note -For testing purposes you also can run `tstl` directly from your terminal with `node_modules/.bin/tstl` or `npx tstl`. -::: +## Type Declarations + +The best way to use TypeScript is to provide it with information about the format/types of the external functions and variables that you will be using (specific to your environment). This allows the compiler to check your code for mistakes when compiling, instead of having to run the code to find issues. To give TypeScript this information, you will need to provide it with type declarations. You can write these declarations yourself or, if available, install an existing type declarations package for your environment from npm. + +For instructions on how to install type declaration packages, see the readme file for the individual package in question. In short, you need to install the package from npm, and then add the `types` field to the `compilerOptions` in the `tsconfig.json` file. -## Declarations +### Type Declaration Packages - Official -The real power of this transpiler is usage together with good declarations for the Lua API provided. Some examples of Lua interface declarations can be found here: +We provide an official type declaration package for [the Lua standard library](https://github.com/TypeScriptToLua/lua-types). + +These declarations do not come with `tstl` by default because most of the time, you should not be using the Lua standard library directly. In other words, you can just write idiomatic TypeScript and `tstl` will convert things properly. (For example, it converts `Math.round` to `math.round`.) However, if you want to do some low-level Lua stuff and work with the Lua standard library, then you will need to install these type declarations so that the TypeScript compiler can understand what you are doing. + +### Type Declaration Packages - Unofficial + +Type declarations exist for some common Lua environments: + +- [Defold Game Engine](https://github.com/ts-defold/types) +- [LÖVE 2D Game Engine](https://github.com/hazzard993/love-typescript-definitions) + +Additionally, type declarations exist for some games: -- [Lua Standard Library](https://github.com/TypeScriptToLua/lua-types) -- [Dota 2 Custom Games](https://github.com/ModDota/API/tree/master/declarations/server) ([template](https://github.com/ModDota/TypeScriptAddonTemplate)) -- [Defold Game Engine Scripting](https://github.com/ts-defold/types) -- [LÖVE 2D Game Development](https://github.com/hazzard993/love-typescript-definitions) -- [World of Warcraft - Addon Development](https://github.com/wartoshika/wow-declarations) -- [World of Warcraft Classic - Addon Development](https://github.com/wartoshika/wow-classic-declarations) -- [Typed Factorio](https://github.com/GlassBricks/typed-factorio) - [The Binding of Isaac: Rebirth](https://isaacscript.github.io) -- [Retro Gadget](https://github.com/DarkMio/retro-gadgets-typedefs) ([template](https://github.com/DarkMio/retro-gadgets-template)) +- [ComputerCraft (Minecraft)](https://github.com/MCJack123/cc-tstl-template) +- [Dota 2](https://github.com/ModDota/API/tree/master/declarations/server) ([template](https://github.com/ModDota/TypeScriptAddonTemplate)) +- [Factorio](https://github.com/GlassBricks/typed-factorio) - [Garry's Mod](https://github.com/lolleko/gmod-typescript) +- [Retro Gadget](https://github.com/DarkMio/retro-gadgets-typedefs) ([template](https://github.com/DarkMio/retro-gadgets-template)) +- [World of Warcraft](https://github.com/wartoshika/wow-declarations) +- [World of Warcraft Classic](https://github.com/wartoshika/wow-classic-declarations) + +(If you have created type declarations for a new game, you can click on the "Edit this page" link below to add it to the list.) diff --git a/docs/publishing-modules.md b/docs/publishing-modules.md index 807f314e..3d4e8e53 100644 --- a/docs/publishing-modules.md +++ b/docs/publishing-modules.md @@ -2,16 +2,21 @@ title: Publishing Modules --- -As of `0.40.0`, tstl supports module resolution for libraries, which means you can _use_ and _create_ npm packages containing `.lua` files. You can also include Lua source files directly into your source code. +There are two kinds of `tstl` libraries published on npm: -- You cannot import `.ts` and `.tsx` source files -- You must use `"buildMode": "library"` -- It is recommended you use `"declaration": true` -- You cannot use `"luaBundle"` in packages intended to be included as dependency in another project +- **Type declaration libraries** - Provides only _ambient_ types. In other words, these libraries do not contain any code which can be executed. +- **Lua libraries** - Provides Lua code that can be imported and executed by `tstl` projects. + +This page describes how to create a Lua package and publish it to npm. + +## Basic Limitations + +- `tstl` cannot import `.ts` and `.tsx` source files from a `node_modules` library. +- `tstl` Lua libraries can not be bundled with the `luaBundle` compiler flag. (The end-users consuming the library will decide whether they want the final product to use `luaBundle` or not.) ## Project Configuration -Your `tsconfig.json` file must at least specify the following... +Your `tsconfig.json` file must include the following fields: ```json title=tsconfig.json { @@ -24,65 +29,51 @@ Your `tsconfig.json` file must at least specify the following... } ``` -And your `package.json` file should specify the `types` property. You should also specify the `main` property if your module contains runnable Lua code. +Your `package.json` file should include the following fields: ```json title=package.json { - "main": "./dist/index", // points to ./dist/index.lua - "types": "./dist/index" // points to ./dist/index.d.ts -} -``` - -These must be **relative** paths within your module **without** the file's extension. - -> These are set to `"index"` by default so if you _really_ don't want to specify these you can keep an `index.d.ts` and `index.lua` file at the top level of your package. - -## Publishing - -Within your `package.json` you can specify the `files` field to mark what files to publish. + // An array containing the files that will be published to npm. (See more information below.) + "files": [ + "dist/**/*.lua", // Only specify this if your library is a Lua library. + "dist/**/*.d.ts" + ], -This is useful if you don't want to publish your source code. + "types": "./dist/index.d.ts", -```json title=package.json -{ - "files": [ - "dist/**/*.lua", // publish all Lua files in /dist/ - "dist/**/*.d.ts" // publish all declaration files in /dist/ - ] + // Only specify "main" if your library is a Lua library. + // (Do NOT include the file extension here, or things will not work properly.) + "main": "./dist/index" } ``` -You can use `npm publish --dry-run` to see what files would be published without publishing your package. - -- Some files will always be published e.g. `package.json`, `README.md`. -- Modules specified in `"devDependencies"` will not be available to the module at runtime. -- The `tsconfig.json` file does nothing for users of your module. - -And when you're happy, your `package.json` has a `name`, `version`, `description`, and you are logged into NPM on your machine... you can run `npm publish` to publish your module. +:::note +There are many other fields that should be in a proper `package.json` file, such as `name`, `author`, `version`, and so on. Use `npm init` to generate a new `package.json` with some basic fields, if necessary. +::: -## Using the Module +## Publishing -Assuming the module is available on NPM, users of your module can download it like so. +Note that: -```bash -npm install -# OR -yarn add -``` +- Regardless of the contents of the `files` field, some files will always be published, like `package.json` and `README.md`. +- Modules specified in `"devDependencies"` will not be available to the module at runtime. +- There is no need to publish the `tsconfig.json` file, as it will do nothing for the users of your module. -Now they can start using it. +When you are ready to publish: -```ts title=example.ts -import { func } from ""; +- Use `npm login` to cache your npm credentials. +- Use `npm publish --dry-run` to see what files would be published without actually uploading anything. +- Use `npm publish` to actually upload it. -func(); -``` +## Using the Module -TypeScriptToLua will handle the module resolution from here. +See [the page on using Lua packages](external-code.md#using-lua-packages). ## Example projects -For example projects using external Lua, you can look at the projects used in the TypeScriptToLua tests: +For an example of a Lua package published to npm, see [`isaacscript-common`](https://github.com/IsaacScript/isaacscript/tree/main/packages/isaacscript-common). + +You can also reference the projects used in the TypeScriptToLua tests: ### [A project using Lua from node_modules packages](https://github.com/TypeScriptToLua/TypeScriptToLua/tree/master/test/transpile/module-resolution/project-with-node-modules) diff --git a/docusaurus.config.js b/docusaurus.config.js index 006e31fb..23b3a0ec 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -53,7 +53,7 @@ module.exports = { }, { label: "Advanced", - to: "docs/advanced/writing-declarations", + to: "docs/advanced/compiler-annotations", }, ], }, diff --git a/package.json b/package.json index b10d8b02..40036c1b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "scripts": { "start": "docusaurus start", "build": "docusaurus build", + "serve": "docusaurus serve", "lint": "npm run lint:prettier", "lint:prettier": "prettier --check .", "fix:prettier": "prettier --write .", diff --git a/sidebars.json b/sidebars.json index 21559104..34a32cbc 100644 --- a/sidebars.json +++ b/sidebars.json @@ -1,17 +1,29 @@ { "docs": [ - "getting-started", - "configuration", - "caveats", - "the-self-parameter", - "external-lua-code", - "publishing-modules", - "editor-support", - "advanced/writing-declarations", - "advanced/compiler-annotations", - "advanced/language-extensions", - "json-modules", - "jsx", + { + "type": "category", + "label": "Basic", + "items": [ + "getting-started", + "configuration", + "caveats", + "the-self-parameter", + "external-code", + "publishing-modules", + "editor-support" + ] + }, + { + "type": "category", + "label": "Advanced", + "items": [ + "advanced/writing-declarations", + "advanced/compiler-annotations", + "advanced/language-extensions", + "json-modules", + "jsx" + ] + }, { "type": "category", "label": "API", diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 503f997a..2c4ca428 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -140,7 +140,7 @@ export default function Home() {

Getting started

- Getting started with TSTL is easy, simply install typescript-to-lua from npm: + Getting started with TSTL is easy. Simply install "typescript-to-lua" from npm:

$ npm install -D typescript typescript-to-lua

@@ -149,7 +149,7 @@ export default function Home() { $ npx tstl

For more information, see{" "} - tstl Getting Started documentation. + the getting started page.