xray16 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/package.json +38 -0
- package/plugins/built_at_info.ts +18 -0
- package/plugins/from_cast_utils.ts +34 -0
- package/plugins/global_declarations_transform.ts +24 -0
- package/plugins/inject_filename.ts +22 -0
- package/plugins/strip_lua_logger.ts +73 -0
- package/plugins/transform_luabind_class/plugin.ts +51 -0
- package/plugins/transform_luabind_class/transformation/class_declaration.ts +226 -0
- package/plugins/transform_luabind_class/transformation/constants.ts +4 -0
- package/plugins/transform_luabind_class/transformation/decorators.ts +16 -0
- package/plugins/transform_luabind_class/transformation/errors.ts +31 -0
- package/plugins/transform_luabind_class/transformation/index.ts +5 -0
- package/plugins/transform_luabind_class/transformation/members/accessors.ts +48 -0
- package/plugins/transform_luabind_class/transformation/members/constructor.ts +107 -0
- package/plugins/transform_luabind_class/transformation/members/fields.ts +53 -0
- package/plugins/transform_luabind_class/transformation/members/method.ts +70 -0
- package/plugins/transform_luabind_class/transformation/new.ts +14 -0
- package/plugins/transform_luabind_class/transformation/setup.ts +128 -0
- package/plugins/transform_luabind_class/transformation/super.ts +92 -0
- package/plugins/transform_luabind_class/transformation/utils.ts +90 -0
- package/plugins/utils/diagnostics.ts +24 -0
- package/src/index.d.ts +63 -0
- package/src/xr_constant.d.ts +976 -0
- package/src/xr_core.d.ts +347 -0
- package/src/xr_global.d.ts +613 -0
- package/src/xr_lib/xr_fs.d.ts +333 -0
- package/src/xr_lib/xr_math.d.ts +165 -0
- package/src/xr_lib/xr_utils.d.ts +407 -0
- package/src/xr_luabind.d.ts +34 -0
- package/src/xr_map/xr_map.d.ts +42 -0
- package/src/xr_object/xr_action.d.ts +482 -0
- package/src/xr_object/xr_alife.d.ts +206 -0
- package/src/xr_object/xr_anomaly.d.ts +50 -0
- package/src/xr_object/xr_artefact.d.ts +98 -0
- package/src/xr_object/xr_client_object.d.ts +1255 -0
- package/src/xr_object/xr_creature.d.ts +157 -0
- package/src/xr_object/xr_dialog.d.ts +34 -0
- package/src/xr_object/xr_item.d.ts +239 -0
- package/src/xr_object/xr_level.d.ts +166 -0
- package/src/xr_object/xr_physic.d.ts +119 -0
- package/src/xr_object/xr_quest.d.ts +47 -0
- package/src/xr_object/xr_server_object.d.ts +686 -0
- package/src/xr_online/xr_multiplayer.d.ts +299 -0
- package/src/xr_sound/xr_sound.d.ts +153 -0
- package/src/xr_type/xr_enums.d.ts +17 -0
- package/src/xr_type/xr_type.d.ts +70 -0
- package/src/xr_ui/README.md +277 -0
- package/src/xr_ui/demo/CServerList.png +0 -0
- package/src/xr_ui/demo/CUI3tButton.png +0 -0
- package/src/xr_ui/demo/CUICheckButton.png +0 -0
- package/src/xr_ui/demo/CUIComboBox.png +0 -0
- package/src/xr_ui/demo/CUICustomEdit.png +0 -0
- package/src/xr_ui/demo/CUIStatic.png +0 -0
- package/src/xr_ui/demo/CUITrackBar.png +0 -0
- package/src/xr_ui/xr_ui_core.d.ts +185 -0
- package/src/xr_ui/xr_ui_interface.d.ts +666 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 stalker-xrts
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# [📡 XRay-16 engine typescript definitions](https://github.com/xray-forge/xray-16-types)
|
|
2
|
+
|
|
3
|
+
[](https://github.com/xray-forge/xray-16-types/actions/workflows/build_and_test.yml)
|
|
4
|
+
|
|
5
|
+
X-Ray16 engine bindings documentation and types. <br/>
|
|
6
|
+
For usage with [TypeScriptToLua](https://typescripttolua.github.io/docs/getting-started).
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
Module contains xray engine globals typedefs for typescript. <br/>
|
|
10
|
+
By default x-ray export many bindings that can be used from lua scripts, but without game API documentation.
|
|
11
|
+
|
|
12
|
+
To check more details / correct typing you always can reference X-Ray source code.
|
|
13
|
+
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
## 🗻 Docs
|
|
17
|
+
|
|
18
|
+
Types documentation can be checked [here](https://xray-forge.github.io/xray-16-types/modules.html).
|
|
19
|
+
|
|
20
|
+
## 🧱 Usage
|
|
21
|
+
|
|
22
|
+
Types are used with [xrf template](https://github.com/xray-forge/stalker-xrf-template) and can be referenced as an example.
|
|
23
|
+
|
|
24
|
+
## 🎮 Updating types
|
|
25
|
+
|
|
26
|
+
For easier navigation over codebase and typing following rules are applied:
|
|
27
|
+
|
|
28
|
+
- Type declaration should have \@source docblock with matching c++ counterpart signature
|
|
29
|
+
- Variable and class namings follow c++ conventions for easier binding and matching engine codebase
|
|
30
|
+
- XRay types should be prefixed with IXR or TXR if they do not have runtime representation
|
|
31
|
+
|
|
32
|
+
## 📦Extending C++ classes and overriding virtual methods
|
|
33
|
+
|
|
34
|
+
### Lua
|
|
35
|
+
|
|
36
|
+
<p>
|
|
37
|
+
C++ classes can be extended in Lua code with 'class' keyword.
|
|
38
|
+
Class declaration registers table as userdata and adds constructor/destructor metamethods. <br/>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
### Typescript
|
|
42
|
+
|
|
43
|
+
<p>
|
|
44
|
+
In TS codebase '@LuabindClass' decorator can be used to modify transformation and enable virtual calls. <br/>
|
|
45
|
+
Separate transformer is needed to build luabind classes instead of table-based classes.
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
## 🧱 Getting up-to-date LUA bindings
|
|
49
|
+
|
|
50
|
+
- Run game engine with `-dump_bindings` flag
|
|
51
|
+
- Check userdata folder _(where game saves are stored)_ `scriptbindings_*.txt` files
|
|
52
|
+
|
|
53
|
+
## 🧲 References
|
|
54
|
+
|
|
55
|
+
- X-Ray C++ source code
|
|
56
|
+
- LuaBind sources and docs
|
|
57
|
+
- LuaJit sources and docs
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xray16",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "Neloreck",
|
|
5
|
+
"repository": "https://github.com/stalker-xrts/xray-16-types",
|
|
6
|
+
"private": false,
|
|
7
|
+
"main": "src/index.d.ts",
|
|
8
|
+
"types": "src/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"typedoc": "typedoc",
|
|
12
|
+
"format": "prettier --write \"**/*.(js|ts|tsx|md)\" && eslint . --ext .ts,.tsx,.js --fix",
|
|
13
|
+
"lint": "eslint . --ext .ts,.tsx,.js"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"typescript-to-lua": "^1.16.3"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "20.3.1",
|
|
20
|
+
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
|
21
|
+
"@typescript-eslint/parser": "^5.54.0",
|
|
22
|
+
"@typescript-to-lua/language-extensions": "1.0.0",
|
|
23
|
+
"eslint": "^8.35.0",
|
|
24
|
+
"eslint-config-standard-with-typescript": "^34.0.0",
|
|
25
|
+
"eslint-plugin-import": "^2.27.5",
|
|
26
|
+
"eslint-plugin-jest": "^27.2.1",
|
|
27
|
+
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
28
|
+
"prettier": "^3.0.1",
|
|
29
|
+
"typedoc": "^0.24.8",
|
|
30
|
+
"typescript": "^5.1.6"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"plugins/**/*",
|
|
34
|
+
"src/**/*",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Program } from "typescript";
|
|
2
|
+
import { Plugin, CompilerOptions, EmitFile, EmitHost } from "typescript-to-lua";
|
|
3
|
+
|
|
4
|
+
const comment: string = `-- Generated by xrf util at: ${new Date().toString()}\n\n`;
|
|
5
|
+
|
|
6
|
+
const plugin: Plugin = {
|
|
7
|
+
beforeEmit(program: Program, options: CompilerOptions, emitHost: EmitHost, result: Array<EmitFile>) {
|
|
8
|
+
void program;
|
|
9
|
+
void options;
|
|
10
|
+
void emitHost;
|
|
11
|
+
|
|
12
|
+
for (const file of result) {
|
|
13
|
+
file.code = comment + file.code;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default plugin;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isIdentifier, SyntaxKind } from "typescript";
|
|
2
|
+
import { Plugin } from "typescript-to-lua";
|
|
3
|
+
import { createErrorDiagnosticFactory } from "./utils/diagnostics";
|
|
4
|
+
|
|
5
|
+
const FROM_CAST_METHODS: Array<string> = ["$fromObject", "$fromArray", "$fromLuaArray", "$fromLuaTable"];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Push generic error to notify about usage issue.
|
|
9
|
+
*/
|
|
10
|
+
const createInvalidFunctionCallError = createErrorDiagnosticFactory((name?: string) => {
|
|
11
|
+
return `Invalid transformer call, expected function to have exactly 1 argument.`;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Plugin for transformation of casting methods.
|
|
16
|
+
* Simplifies TS/Lua testing and interoperation.
|
|
17
|
+
*/
|
|
18
|
+
const plugin: Plugin = {
|
|
19
|
+
visitors: {
|
|
20
|
+
[SyntaxKind.CallExpression]: (node, context) => {
|
|
21
|
+
if (isIdentifier(node.expression) && FROM_CAST_METHODS.includes(node.expression.text)) {
|
|
22
|
+
if (node.arguments.length !== 1) {
|
|
23
|
+
context.diagnostics.push(createInvalidFunctionCallError(node));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return context.transformExpression(node.arguments[0]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return context.superTransformExpression(node);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default plugin;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SyntaxKind } from "typescript";
|
|
2
|
+
import { Plugin } from "typescript-to-lua";
|
|
3
|
+
|
|
4
|
+
const XRF_GLOBALS: Array<string> = ["xray16"];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Plugin that removes imports from 'global' libraries like engine typedefs.
|
|
8
|
+
*/
|
|
9
|
+
const plugin: Plugin = {
|
|
10
|
+
visitors: {
|
|
11
|
+
[SyntaxKind.ImportDeclaration]: (node, context) => {
|
|
12
|
+
const module: string = node.moduleSpecifier.getText().slice(1, -1);
|
|
13
|
+
const shouldNotBeTransformed: boolean = XRF_GLOBALS.includes(module);
|
|
14
|
+
|
|
15
|
+
if (shouldNotBeTransformed) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return context.superTransformStatements(node);
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default plugin;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { SyntaxKind } from "typescript";
|
|
3
|
+
import { createStringLiteral, Plugin } from "typescript-to-lua";
|
|
4
|
+
|
|
5
|
+
const FILENAME_IDENTIFIER: string = "$filename";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Plugin that injects FILE_NAME in compile-time.
|
|
9
|
+
*/
|
|
10
|
+
const plugin: Plugin = {
|
|
11
|
+
visitors: {
|
|
12
|
+
[SyntaxKind.Identifier]: (node, context) => {
|
|
13
|
+
if (node.text === FILENAME_IDENTIFIER) {
|
|
14
|
+
return createStringLiteral(path.parse(context.sourceFile.fileName).name);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return context.superTransformExpression(node);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default plugin;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallExpression,
|
|
3
|
+
factory,
|
|
4
|
+
Identifier,
|
|
5
|
+
PropertyAccessExpression,
|
|
6
|
+
SyntaxKind,
|
|
7
|
+
Type,
|
|
8
|
+
TypeChecker,
|
|
9
|
+
VariableDeclaration,
|
|
10
|
+
VariableDeclarationList,
|
|
11
|
+
} from "typescript";
|
|
12
|
+
import { Plugin } from "typescript-to-lua";
|
|
13
|
+
|
|
14
|
+
const LUA_LOGGER_STRIP_TARGET: string = "LuaLogger";
|
|
15
|
+
const IS_LUA_LOGGER_DISABLED: boolean = process.argv.includes("--no-lua-logs");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Plugin that removes all LuaLogger instance creations and calls when possible.
|
|
19
|
+
*/
|
|
20
|
+
const plugin: Plugin = {
|
|
21
|
+
visitors: {
|
|
22
|
+
[SyntaxKind.VariableStatement]: (statement, context) => {
|
|
23
|
+
if (IS_LUA_LOGGER_DISABLED) {
|
|
24
|
+
let elementsCount: number = 0;
|
|
25
|
+
const list = statement.declarationList as VariableDeclarationList;
|
|
26
|
+
const nodes: Array<VariableDeclaration> = [];
|
|
27
|
+
|
|
28
|
+
list.forEachChild((it: VariableDeclaration) => {
|
|
29
|
+
const checker: TypeChecker = context.program.getTypeChecker();
|
|
30
|
+
const typeSymbol: Type = checker.getTypeAtLocation(it);
|
|
31
|
+
|
|
32
|
+
if (typeSymbol.symbol?.name === LUA_LOGGER_STRIP_TARGET) {
|
|
33
|
+
// nothing
|
|
34
|
+
} else {
|
|
35
|
+
nodes.push(it);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
elementsCount += 1;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (nodes.length === 0) {
|
|
42
|
+
return undefined;
|
|
43
|
+
} else if (nodes.length !== elementsCount) {
|
|
44
|
+
return context.superTransformStatements(
|
|
45
|
+
factory.createVariableStatement(statement.modifiers, factory.updateVariableDeclarationList(list, nodes))
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return context.superTransformStatements(statement);
|
|
51
|
+
},
|
|
52
|
+
[SyntaxKind.ExpressionStatement]: (statement, context) => {
|
|
53
|
+
if (IS_LUA_LOGGER_DISABLED && statement.expression?.kind === SyntaxKind.CallExpression) {
|
|
54
|
+
const expression: CallExpression = statement.expression as CallExpression;
|
|
55
|
+
const propertyAccess: PropertyAccessExpression = expression.expression as PropertyAccessExpression;
|
|
56
|
+
|
|
57
|
+
if (propertyAccess.expression?.kind === SyntaxKind.Identifier) {
|
|
58
|
+
const checker: TypeChecker = context.program.getTypeChecker();
|
|
59
|
+
const identifier: Identifier = propertyAccess.expression as Identifier;
|
|
60
|
+
const typeSymbol: Type = checker.getTypeAtLocation(identifier);
|
|
61
|
+
|
|
62
|
+
if (typeSymbol.symbol?.name === LUA_LOGGER_STRIP_TARGET) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return context.superTransformStatements(statement);
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default plugin;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
transformLuabindClassDeclaration,
|
|
3
|
+
transformNewCallExpression,
|
|
4
|
+
isLuabindClassSuperCall,
|
|
5
|
+
transformClassSuperMethodExpression,
|
|
6
|
+
transformLuabindConstructorSuperCall,
|
|
7
|
+
ITransformationContext,
|
|
8
|
+
isLuabindClassType,
|
|
9
|
+
isLuabindDecoratedClass,
|
|
10
|
+
isLuabindClassSuperMethodCall,
|
|
11
|
+
} from "./transformation";
|
|
12
|
+
import { CallExpression, NewExpression, SuperExpression, SyntaxKind } from "typescript";
|
|
13
|
+
import { Plugin } from "typescript-to-lua";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Plugin that transform TS classes marked with decorator to luabind class declaration.
|
|
17
|
+
*/
|
|
18
|
+
const plugin: Plugin = {
|
|
19
|
+
visitors: {
|
|
20
|
+
[SyntaxKind.CallExpression]: (expression: CallExpression, context: ITransformationContext) => {
|
|
21
|
+
if (isLuabindClassSuperCall(expression, context)) {
|
|
22
|
+
return transformLuabindConstructorSuperCall(expression, context);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return context.superTransformExpression(expression);
|
|
26
|
+
},
|
|
27
|
+
[SyntaxKind.ClassDeclaration]: (declaration, context: ITransformationContext) => {
|
|
28
|
+
if (isLuabindDecoratedClass(declaration)) {
|
|
29
|
+
return transformLuabindClassDeclaration(declaration, context);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return context.superTransformStatements(declaration);
|
|
33
|
+
},
|
|
34
|
+
[SyntaxKind.NewExpression]: (expression: NewExpression, context: ITransformationContext) => {
|
|
35
|
+
if (isLuabindClassType(expression, context)) {
|
|
36
|
+
return transformNewCallExpression(expression, context);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return context.superTransformExpression(expression);
|
|
40
|
+
},
|
|
41
|
+
[SyntaxKind.SuperKeyword]: (expression: SuperExpression, context: ITransformationContext) => {
|
|
42
|
+
if (isLuabindClassSuperMethodCall(expression, context)) {
|
|
43
|
+
return transformClassSuperMethodExpression(expression, context);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return context.superTransformExpression(expression);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default plugin;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { LUABIND_CONSTRUCTOR_METHOD } from "./constants";
|
|
2
|
+
import { checkLuabindClassDecoratorExpression } from "./decorators";
|
|
3
|
+
import { unsupportedStaticMethod } from "./errors";
|
|
4
|
+
import { transformAccessorDeclarations } from "./members/accessors";
|
|
5
|
+
import { createConstructorName, transformConstructorDeclaration } from "./members/constructor";
|
|
6
|
+
import { verifyPropertyDecoratingExpression, transformClassInstanceFields } from "./members/fields";
|
|
7
|
+
import { verifyMethodDecoratingExpression, transformMethodDeclaration } from "./members/method";
|
|
8
|
+
import { createClassSetup } from "./setup";
|
|
9
|
+
import { getExtendedNode, getExtendedType, isStaticNode, markTypeAsLuabind } from "./utils";
|
|
10
|
+
import {
|
|
11
|
+
canHaveDecorators,
|
|
12
|
+
ClassLikeDeclaration,
|
|
13
|
+
ConstructorDeclaration,
|
|
14
|
+
ExpressionWithTypeArguments,
|
|
15
|
+
factory,
|
|
16
|
+
getDecorators,
|
|
17
|
+
isAccessor,
|
|
18
|
+
isConstructorDeclaration,
|
|
19
|
+
isMethodDeclaration,
|
|
20
|
+
isPropertyDeclaration,
|
|
21
|
+
} from "typescript";
|
|
22
|
+
import * as tstl from "typescript-to-lua";
|
|
23
|
+
import { LuaTarget, TransformationContext } from "typescript-to-lua";
|
|
24
|
+
import {
|
|
25
|
+
createDefaultExportExpression,
|
|
26
|
+
createExportedIdentifier,
|
|
27
|
+
hasDefaultExportModifier,
|
|
28
|
+
hasExportModifier,
|
|
29
|
+
} from "typescript-to-lua/dist/transformation/utils/export";
|
|
30
|
+
import { createSelfIdentifier } from "typescript-to-lua/dist/transformation/utils/lua-ast";
|
|
31
|
+
import { transformInPrecedingStatementScope } from "typescript-to-lua/dist/transformation/utils/preceding-statements";
|
|
32
|
+
import { createSafeName, isUnsafeName } from "typescript-to-lua/dist/transformation/utils/safe-names";
|
|
33
|
+
import { transformIdentifier } from "typescript-to-lua/dist/transformation/visitors/identifier";
|
|
34
|
+
|
|
35
|
+
export interface ITransformationContext extends TransformationContext {
|
|
36
|
+
classSuperInfos: Array<ClassSuperInfo>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const transformLuabindClassDeclaration = (declaration, context: TransformationContext) => {
|
|
40
|
+
// If declaration is a default export, transform to export variable assignment instead
|
|
41
|
+
if (hasDefaultExportModifier(declaration)) {
|
|
42
|
+
// Class declaration including assignment to ____exports.default are in preceding statements
|
|
43
|
+
const { precedingStatements } = transformInPrecedingStatementScope(context, () => {
|
|
44
|
+
transformClassAsExpression(declaration, context as ITransformationContext);
|
|
45
|
+
return [];
|
|
46
|
+
});
|
|
47
|
+
return precedingStatements;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { statements } = transformClassLikeDeclaration(declaration, context as ITransformationContext);
|
|
51
|
+
return statements;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function transformClassAsExpression(
|
|
55
|
+
expression: ClassLikeDeclaration,
|
|
56
|
+
context: ITransformationContext
|
|
57
|
+
): tstl.Expression {
|
|
58
|
+
const { statements, name } = transformClassLikeDeclaration(expression, context);
|
|
59
|
+
context.addPrecedingStatements(statements);
|
|
60
|
+
return name;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** @internal */
|
|
64
|
+
export interface ClassSuperInfo {
|
|
65
|
+
className: tstl.Identifier;
|
|
66
|
+
classDeclaration: ClassLikeDeclaration;
|
|
67
|
+
extendedTypeNode?: ExpressionWithTypeArguments;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function transformClassLikeDeclaration(
|
|
71
|
+
classDeclaration: ClassLikeDeclaration,
|
|
72
|
+
context: ITransformationContext,
|
|
73
|
+
nameOverride?: tstl.Identifier
|
|
74
|
+
): { statements: tstl.Statement[]; name: tstl.Identifier } {
|
|
75
|
+
let className: tstl.Identifier;
|
|
76
|
+
|
|
77
|
+
if (nameOverride !== undefined) {
|
|
78
|
+
className = nameOverride;
|
|
79
|
+
} else if (classDeclaration.name !== undefined) {
|
|
80
|
+
className = transformIdentifier(context, classDeclaration.name);
|
|
81
|
+
} else {
|
|
82
|
+
className = tstl.createIdentifier(context.createTempName("class"), classDeclaration);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
markTypeAsLuabind(classDeclaration, context);
|
|
86
|
+
|
|
87
|
+
// Get type that is extended
|
|
88
|
+
const extendedTypeNode = getExtendedNode(classDeclaration);
|
|
89
|
+
const extendedType = getExtendedType(context, classDeclaration);
|
|
90
|
+
|
|
91
|
+
context.classSuperInfos.push({ className, classDeclaration: classDeclaration, extendedTypeNode });
|
|
92
|
+
|
|
93
|
+
// Get all properties with value
|
|
94
|
+
const properties = classDeclaration.members.filter(isPropertyDeclaration).filter((member) => member.initializer);
|
|
95
|
+
|
|
96
|
+
// Divide properties into static and non-static
|
|
97
|
+
const instanceFields = properties.filter((prop) => !isStaticNode(prop));
|
|
98
|
+
|
|
99
|
+
const result: tstl.Statement[] = [];
|
|
100
|
+
|
|
101
|
+
let localClassName: tstl.Identifier;
|
|
102
|
+
if (isUnsafeName(className.text, context.options)) {
|
|
103
|
+
localClassName = tstl.createIdentifier(
|
|
104
|
+
createSafeName(className.text),
|
|
105
|
+
undefined,
|
|
106
|
+
className.symbolId,
|
|
107
|
+
className.text
|
|
108
|
+
);
|
|
109
|
+
tstl.setNodePosition(localClassName, className);
|
|
110
|
+
} else {
|
|
111
|
+
localClassName = className;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
result.push(...createClassSetup(context, classDeclaration, className, localClassName));
|
|
115
|
+
|
|
116
|
+
// Find first constructor with body
|
|
117
|
+
const constructor = classDeclaration.members.find(
|
|
118
|
+
(n): n is ConstructorDeclaration => isConstructorDeclaration(n) && n.body !== undefined
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (constructor) {
|
|
122
|
+
// Add constructor plus initialization of instance fields
|
|
123
|
+
const constructorResult = transformConstructorDeclaration(
|
|
124
|
+
context,
|
|
125
|
+
constructor,
|
|
126
|
+
localClassName,
|
|
127
|
+
instanceFields,
|
|
128
|
+
classDeclaration
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (constructorResult) result.push(constructorResult);
|
|
132
|
+
} else if (!extendedType) {
|
|
133
|
+
// Generate a constructor if none was defined in a base class
|
|
134
|
+
const constructorResult = transformConstructorDeclaration(
|
|
135
|
+
context,
|
|
136
|
+
factory.createConstructorDeclaration([], [], factory.createBlock([], true)),
|
|
137
|
+
localClassName,
|
|
138
|
+
instanceFields,
|
|
139
|
+
classDeclaration
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
if (constructorResult) result.push(constructorResult);
|
|
143
|
+
} else {
|
|
144
|
+
// Generate a constructor if none was defined in a class with instance fields that need initialization
|
|
145
|
+
// localClassName.__init = function(self, ...)
|
|
146
|
+
// baseClassName.__init(self, ...) // or unpack(arg) for Lua 5.0
|
|
147
|
+
// ...
|
|
148
|
+
// Also luabind always needs definition of call expression to use table as class.
|
|
149
|
+
const constructorBody = transformClassInstanceFields(context, instanceFields);
|
|
150
|
+
const argsExpression =
|
|
151
|
+
context.luaTarget === LuaTarget.Lua50
|
|
152
|
+
? tstl.createCallExpression(tstl.createIdentifier("unpack"), [tstl.createArgLiteral()])
|
|
153
|
+
: tstl.createDotsLiteral();
|
|
154
|
+
const superCall = tstl.createExpressionStatement(
|
|
155
|
+
tstl.createCallExpression(
|
|
156
|
+
tstl.createTableIndexExpression(
|
|
157
|
+
context.transformExpression(factory.createSuper()),
|
|
158
|
+
tstl.createStringLiteral(LUABIND_CONSTRUCTOR_METHOD)
|
|
159
|
+
),
|
|
160
|
+
[createSelfIdentifier(), argsExpression]
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
constructorBody.unshift(superCall);
|
|
164
|
+
const constructorFunction = tstl.createFunctionExpression(
|
|
165
|
+
tstl.createBlock(constructorBody),
|
|
166
|
+
[createSelfIdentifier()],
|
|
167
|
+
tstl.createDotsLiteral(),
|
|
168
|
+
tstl.NodeFlags.Declaration
|
|
169
|
+
);
|
|
170
|
+
result.push(
|
|
171
|
+
tstl.createAssignmentStatement(createConstructorName(localClassName), constructorFunction, classDeclaration)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Transform accessors
|
|
176
|
+
for (const member of classDeclaration.members) {
|
|
177
|
+
if (!isAccessor(member)) continue;
|
|
178
|
+
const accessors = context.resolver.getAllAccessorDeclarations(member);
|
|
179
|
+
if (accessors.firstAccessor !== member) continue;
|
|
180
|
+
|
|
181
|
+
const accessorsResult = transformAccessorDeclarations(context, accessors, localClassName);
|
|
182
|
+
if (accessorsResult) {
|
|
183
|
+
result.push(accessorsResult);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const decorationStatements: tstl.Statement[] = [];
|
|
188
|
+
|
|
189
|
+
for (const member of classDeclaration.members) {
|
|
190
|
+
if (isAccessor(member)) {
|
|
191
|
+
verifyPropertyDecoratingExpression(context, member);
|
|
192
|
+
} else if (isMethodDeclaration(member)) {
|
|
193
|
+
const statement = transformMethodDeclaration(context, member, localClassName);
|
|
194
|
+
if (statement) result.push(statement);
|
|
195
|
+
if (member.body) {
|
|
196
|
+
verifyMethodDecoratingExpression(context, member);
|
|
197
|
+
}
|
|
198
|
+
} else if (isPropertyDeclaration(member)) {
|
|
199
|
+
if (isStaticNode(member)) {
|
|
200
|
+
context.diagnostics.push(unsupportedStaticMethod(member));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
verifyPropertyDecoratingExpression(context, member);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
result.push(...decorationStatements);
|
|
208
|
+
|
|
209
|
+
// Decorate the class
|
|
210
|
+
if (canHaveDecorators(classDeclaration) && getDecorators(classDeclaration)) {
|
|
211
|
+
getDecorators(classDeclaration)?.forEach((d) => checkLuabindClassDecoratorExpression(context, d));
|
|
212
|
+
|
|
213
|
+
if (hasExportModifier(classDeclaration)) {
|
|
214
|
+
const exportExpression = hasDefaultExportModifier(classDeclaration)
|
|
215
|
+
? createDefaultExportExpression(classDeclaration)
|
|
216
|
+
: createExportedIdentifier(context, className);
|
|
217
|
+
|
|
218
|
+
const classAssignment = tstl.createAssignmentStatement(exportExpression, localClassName);
|
|
219
|
+
result.push(classAssignment);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
context.classSuperInfos.pop();
|
|
224
|
+
|
|
225
|
+
return { statements: result, name: className };
|
|
226
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { unsupportedClassDecorator } from "./errors";
|
|
2
|
+
import { LUABIND_DECORATOR } from "./constants";
|
|
3
|
+
import { CallExpression, Decorator, Identifier } from "typescript";
|
|
4
|
+
import { TransformationContext } from "typescript-to-lua";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transform decorator call expressions for luabind class.
|
|
8
|
+
*/
|
|
9
|
+
export function checkLuabindClassDecoratorExpression(context: TransformationContext, decorator: Decorator) {
|
|
10
|
+
const expression = decorator.expression;
|
|
11
|
+
|
|
12
|
+
// Do not transform luabind decorator.
|
|
13
|
+
if (((expression as CallExpression).expression as Identifier).text !== LUABIND_DECORATOR) {
|
|
14
|
+
context.diagnostics.push(unsupportedClassDecorator(expression));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createErrorDiagnosticFactory } from "../../utils/diagnostics";
|
|
2
|
+
|
|
3
|
+
export const unsupportedStaticMethod = createErrorDiagnosticFactory((name?: string) => {
|
|
4
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
5
|
+
return `Unable transform static properties for luabind classes${nameReference}.`;
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const unsupportedClassDecorator = createErrorDiagnosticFactory((name?: string) => {
|
|
9
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
10
|
+
return `Unable transform class decorators for luabind classes${nameReference}.`;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const unsupportedPropertyDecorator = createErrorDiagnosticFactory((name?: string) => {
|
|
14
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
15
|
+
return `Unable transform property decorator for luabind classes${nameReference}.`;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const unsupportedParameterDecorator = createErrorDiagnosticFactory((name?: string) => {
|
|
19
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
20
|
+
return `Unable transform parameter decorator for luabind classes${nameReference}.`;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const unsupportedMethodDecorator = createErrorDiagnosticFactory((name?: string) => {
|
|
24
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
25
|
+
return `Unable transform method decorator for luabind classes${nameReference}.`;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const unsupportedStaticAccessor = createErrorDiagnosticFactory((name?: string) => {
|
|
29
|
+
const nameReference = name ? ` '${name}'` : "";
|
|
30
|
+
return `Unable transform static accessors for luabind classes${nameReference}.`;
|
|
31
|
+
});
|