Skip to content

docs: auto-complete and codegen #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/documentation/godot-js-scripts/auto-completion-and-codegen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Auto-Completion and Codegen

If you use TypeScript just follow the getting-started and install all [preset files](../getting-started.md#install-preset-files).

By default, the codegen is activated, which will generate new `*.d.ts` files based on you project resources.

Example given `ResourceLoader.load()` will autocomplete like this:

![Resource Loader load auto complete](images/codegen/resource-loader.png)

## .gen.d.ts files

Similarly to scenes, each resource has a generated `.gen.d.ts file` in the `/generated/typings/` subdirectory.

For example, a `hmm.tres` file for a custom Resource whose script looks like:

```ts
export default class LineCardLayout extends CardLayout {
```

will have the following `hmm.tres.gen.d.ts` generated:

```ts
import LineCardLayout from "../../../src/layouts/line-card-layout";
declare module "godot" {
interface ResourceTypes {
"res://scenes/example/hmm.tres": LineCardLayout;
}
}
```

## ResourceLoader.load

Now when you write code to load a resource with a string literal, the type is known:

![ResourceLoader load string literal](images/codegen/resource-loader-string.png)

Built-in resource types are also typed as expected:

![ResourceLoader load typed](images/codegen/resource-loader-typed.png)

Unknown/non-literal resources will fall back to being typed as `Resource`, mimicking the old behavior.

## Scenes

We have special case handling for scenes.

![Scene Typed](images/codegen/scene.png)

In the example above, no explicit types are provided, but the instantiated scene is known to be of type `StandardCard`. This works because `PackedScene` is now `PackedScene<T extends Node = Node>` and the generated contents of `standard-card.tscn.gen.d.ts` are as follows:

```ts
import StandardCard from "../../../src/example/standard-card";
declare module "godot" {
interface ResourceTypes {
"res://scenes/example/standard_card.tscn": PackedScene<StandardCard>;
}
}
```

## Settings

As with scene node codegen, resource codegen can be disabled with editor settings:

![Settings Codegen](images/codegen/settings.png)

## Customization

As with scene node codegen, users can customize the generated type for custom `Resource` by exporting a `codegen` function and handling the codegen request of type `CodeGenType.ScriptResourceTypeDescriptor` e.g.

```ts
export const codegen: CodeGenHandler = (rawRequest) => {
const request = rawRequest.proxy();

switch (request.type) {
case CodeGenType.ScriptResourceTypeDescriptor: {
return GDictionary.create<StringLiteralTypeDescriptor>({
type: DescriptorType.StringLiteral,
value: "FooBar",
});
}
}

return undefined;
};
```

which would lead to the contents of `hmm.tres.gen.d.ts` becoming:

```ts
declare module "godot" {
interface ResourceTypes {
"res://scenes/example/hmm.tres": "FooBar";
}
}
```

_**Note:** This is just for illustrative purposes. It's highly unlikely someone will implement a custom `Resource` that is somehow compliant with the string literal type `"FooBar"`!_
15 changes: 8 additions & 7 deletions docs/documentation/godot-js-scripts/code-in-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
> **NOTE:** Read [Godot Docs](https://docs.godotengine.org/en/stable/tutorials/plugins/running_code_in_the_editor.html#what-is-tool) for more details about `@tool`.


If a GodotJS class is annotated with `tool()`, it'll be instantiated in the editor. Call `Engine.is_editor_hint()` in the script to check if it's running in the editor.
If a GodotJS class is annotated with `@Tool()`, it'll be instantiated in the editor.
Call `Engine.is_editor_hint()` in the script to check if it's running in the editor.
It's also possible to show warnings on a `Node` on `Scene` panel with `_get_configuration_warnings` defined. Here is a simple example:

```ts
import { Engine, PackedStringArray, Sprite2D, Variant } from "godot";
import { export_, tool } from "godot.annotations";
import { Export, Tool } from "godot.annotations";

@tool()
@Tool()
export default class MyEditorSprite extends Sprite2D {

/**
* get/set property for `export` (both must be defined)
*/
@export_(Variant.Type.TYPE_FLOAT)
@Export(Variant.Type.TYPE_FLOAT)
get speed(): number { return this._speed; }
set speed(value: number) {
if (this._speed != value) {
Expand All @@ -29,7 +30,7 @@ export default class MyEditorSprite extends Sprite2D {
/**
* plain field for `export`
*/
@export_(Variant.Type.TYPE_INT)
@Export(Variant.Type.TYPE_INT)
unused_int = 0;

private _clockwise = false;
Expand Down Expand Up @@ -81,9 +82,9 @@ This is available in Godot by extending `EditorScript` in a script. This provide

```ts
import { EditorScript } from "godot";
import { tool } from "godot.annotations";
import { Tool } from "godot.annotations";

@tool()
@Tool()
export default class MyEditorScript1 extends EditorScript {
_run() {
console.log("my editor script run");
Expand Down
34 changes: 17 additions & 17 deletions docs/documentation/godot-js-scripts/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ There are several decorators to help you define properties, signals, and other m

## Signal annotation

You can define signals in your script using the `@signal` annotation:
You can define signals in your script using the `@ExportSignal` annotation:

```ts
import { Node, Signal0, Callable } from "godot";
import { signal } from "godot.annotations";
import { Node, Signal } from "godot";
import { ExportSignal } from "godot.annotations";

export default class MyJSNode extends Node {
@signal()
declare test!: Signal0;
@ExportSignal()
test!: Signal<(param1: string) => void>;
}
```

Expand All @@ -24,9 +24,9 @@ If a GodotJS class is annotated with `tool()`, it'll be instantiated in the edit

```ts
import { Node } from "godot";
import { tool } from "godot.annotations";
import { Tool } from "godot.annotations";

@tool()
@Tool()
export default class MyTool extends Node {
_ready() {
// This code will run in the editor
Expand All @@ -43,9 +43,9 @@ An icon can be used as node icon in the editor scene hierarchy with the annotati

```ts
import { Sprite2D } from "godot";
import { icon } from "godot.annotations";
import { Icon } from "godot.annotations";

@icon("res://icon/affiliate.svg")
@Icon("res://icon/affiliate.svg")
export default class MySprite extends Sprite2D {}
```

Expand All @@ -57,15 +57,15 @@ In `GodotJS`, class member properties/variables can be exported.
This means their value gets saved along with the resource
(such as the scene) they're attached to.
They will also be available for editing in the property editor.
Exporting is done by using the `@export_` annotation.
Exporting is done by using the `@Export` annotation.

```ts
import { export_ } from "godot.annotations";
import { Export } from "godot.annotations";

export default class Shooter extends Sprite2D {
// type must be explicitly provided as the first parameter of @export_
// type must be explicitly provided as the first parameter of @Export
// cuz static type is actually a phantom in typescript
@export_(Variant.Type.TYPE_FLOAT)
@Export(Variant.Type.TYPE_FLOAT)
speed: number = 0;

// ...
Expand All @@ -84,17 +84,17 @@ The retrieval of default value is implemented through `Class Default Object (CDO
### Basic Use

```ts
@export_(Variant.Type.TYPE_STRING)
@Export(Variant.Type.TYPE_STRING)
address: string = "somewhere"; // `:string` can be omitted here

@export_(Variant.Type.TYPE_INT)
@Export(Variant.Type.TYPE_INT)
age: number = 0; // `:number` can be omitted here
```

If there's no default value, `default value` of the give type will be used (`0` in this case).

```ts
@export_(Variant.Type.TYPE_INT)
@Export(Variant.Type.TYPE_INT)
age: number;
```

Expand All @@ -105,7 +105,7 @@ Enum value properties can be exported with the built-in support in the property
> **NOTE:** So far, only `int` is supported as enum value.

```ts
@export_enum(MyColor)
@ExportEnum(MyColor)
color: MyColor = MyColor.White;
```

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/documentation/godot-js-scripts/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ export default class MyJSNode extends Node {
Annotations are used to define properties, signals, and other metadata for Godot objects.
They are similar to decorators in TypeScript and can be used to enhance the functionality of your scripts.
Check out [decorators](decorators.md) for more information.

## Auto-Completion and Codegen

By default, GodotJS wil auto generate some TypeScript files based on you project.
Check out [auto-completion](auto-completion.md) for more information.
2 changes: 1 addition & 1 deletion docs/documentation/godot-js-scripts/npm-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { dayjs } from "./npm.bundle";

export default class Example extends Node {
_ready(): void {
const label: Label = this.get_node("Label") as Label;
const label: Label = this.get_node("Label");

label.text = dayjs().toString();
}
Expand Down
33 changes: 13 additions & 20 deletions docs/documentation/godot-js-scripts/signals.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,25 @@
You can define signals based on the amount of arguments you want to pass:

```ts
import { Node, Signal0, Signal1, Signal2, Callable } from "godot";
import { signal } from "godot.annotations";
import { Node, Signal } from "godot";
import { ExportSignal } from "godot.annotations";

export default class MyJSNode extends Node {
@signal()
declare no_arg!: Signal0;
export default class MyNode extends Node {
@ExportSignal()
declare no_arg!: Signal<() => void>;

@signal()
declare one_arg!: Signal1<number>;
@ExportSignal()
declare one_arg!: Signal<(param1: string) => void>;

@signal()
declare two_args!: Signal2<string, string>;
@ExportSignal()
declare two_args!: Signal<(param1: number, param2: string) => void>;
}
```

> **NOTE:** You must `declare` signal properties.
> This creates an "ambient" declaration, which is a way of telling TypeScript
> that the property exists but not to generate any code to define it.
> Instead `@signal` automatically generates an accessor on your behalf.
> If you omit `declare`, the TypeScript compiler creates an "own property"
> on instances with an `undefined` value, which blocks access to the GodotJS'
> generated accessor method (which exists on the instance's prototype).

## Passing Arguments via Signals

When emitting signals, only Godot-native objects (GArray, GDictionary, and primitives) can be passed as valid arguments. Raw TypeScript/JavaScript objects cannot be used directly.
When emitting signals, only Godot-native objects (GArray, GDictionary, and primitives) can be passed as valid arguments.
Raw TypeScript/JavaScript objects cannot be used directly.

Incorrect Example:

Expand All @@ -46,9 +39,9 @@ data.set("key", "value");
this.some_signal.emit(data); // ✅ Godot dictionary
```

If raw JavaScript objects must be passed, consider converting them into ``GDictionary`` or ``GArray`` before emitting them as arguments.
If raw JavaScript objects must be passed, consider converting them into `GDictionary` or `GArray` before emitting them as arguments.
If you use [godot-ts](https://github.com/godotjs/godot-ts) you can use
the functions ``toGDictionary`` and `fromGDictionary` from ``generated/utils.ts``.
the functions `toGDictionary` and `fromGDictionary` from `generated/utils.ts`.

## Connect and disconnect to a signal programmatically

Expand Down
10 changes: 5 additions & 5 deletions docs/examples/reuse-custom-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ This example shows how to create a custom resource and reuse it with different s
We create a new file `character-attributes.ts` and add this code to it:

```ts title="character-attributes.ts"
import { export_ } from "godot.annotations";
import { Export } from "godot.annotations";
import { Resource, Variant } from "godot";

export default class CharacterAttributes extends Resource {
@export_(Variant.Type.TYPE_INT)
@Export(Variant.Type.TYPE_INT)
health: number = 5;
}
```
Expand All @@ -33,14 +33,14 @@ Create a new file `index.ts` and add this code to it:

```ts title="index.ts"
import { Node, Variant } from "godot";
import { export_ } from "godot.annotations";
import { Export } from "godot.annotations";
import CharacterAttributes from "./character-attributes";

export default class ResourceExample extends Node {
@export_(Variant.Type.TYPE_OBJECT)
@Export(Variant.Type.TYPE_OBJECT)
warriorAttributes: CharacterAttributes | undefined = undefined;

@export_(Variant.Type.TYPE_OBJECT)
@Export(Variant.Type.TYPE_OBJECT)
mageAttributes: CharacterAttributes | undefined = undefined;

_ready(): void {
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Supports JavaScript engines:

## Getting started

Read the [getting-started](documentation/getting-started).
Read the [getting-started](documentation/getting-started.md).

## Features

Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ nav:
- Cyclic Imports: documentation/godot-js-scripts/cyclic-imports.md
- Bindings: documentation/godot-js-scripts/bindings.md
- Running code in editor: documentation/godot-js-scripts/code-in-editor.md
- Auto-Completion and Codegen: documentation/godot-js-scripts/auto-completion-and-codegen.md
- Utilities:
- REPL: documentation/utilities/repl.md
- SourceMaps: documentation/utilities/source-map.md
Expand Down