Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/static_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ jobs:

- name: Spell checks via codespell
if: github.event_name == 'pull_request' && env.CHANGED_FILES != ''
uses: codespell-project/actions-codespell@v1
uses: codespell-project/actions-codespell@v2
with:
skip: "./bin,./thirdparty,*.desktop,*.gen.*,*.po,*.pot,*.rc,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./core/input/gamecontrollerdb.txt,./core/string/locales.h,./editor/project_converter_3_to_4.cpp,./misc/scripts/codespell.sh,./platform/android/java/lib/src/com,./platform/web/node_modules,./platform/web/package-lock.json"
ignore_words_list: "curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai"
ignore_words_list: "breaked,checkin,curvelinear,doubleclick,expct,findn,gird,hel,inout,labelin,lod,mis,nd,numer,ot,pointin,requestor,te,textin,thirdparty,vai"
path: ${{ env.CHANGED_FILES }}
1 change: 1 addition & 0 deletions SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,5 @@ env_module.Append(CPPPATH=["#modules/javascript"])
env_module.add_source_files(env.modules_sources, sources)

if env.editor_build:
env_module.add_source_files(env.modules_sources, "editor/workarounds/*.cpp")
env_module.add_source_files(env.modules_sources, "editor/*.cpp")
214 changes: 114 additions & 100 deletions editor/editor_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,82 @@ static String apply_pattern(const String &p_pattern, const Dictionary &p_values)
return ret;
}

static String format_enum_name(const String &enum_name) {
if (enum_name.begins_with("Variant.")) {
return enum_name.replace(".", "");
}
return enum_name;
}

void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) {
_export_typescript_declare_file("");
String file_content = "// Tool generated file DO NOT modify manually\n"
"// Add this script as first autoload to your project to bind enumerations for release build of godot engine\n"
"\n"
"if (!godot.DEBUG_ENABLED) {\n"
"\tfunction bind(cls, enumerations) {\n"
"\t\tif (cls) Object.defineProperties(cls, enumerations);\n"
"\t};\n"
"\n"
"${enumerations}"
"}\n"
"export default class extends godot.Node {};\n";

String enumerations = "";
for (const auto &cls : class_enumerations) {
const ClassEnumerations &enumeration = cls.value;
const String &name = cls.key;
String class_name = name;
if (class_name != "godot") {
class_name = "godot." + class_name;
}
String class_enums = "";
uint32_t idx = 0;
for (const auto &E : enumeration) {
String enum_items_text = "{";
const Vector<const DocData::ConstantDoc *> &consts = E.value;
for (int i = 0; i < consts.size(); ++i) {
const DocData::ConstantDoc *c = consts[i];
enum_items_text += c->name + ": " + c->value;
if (i < consts.size() - 1) {
enum_items_text += ", ";
}
}
enum_items_text += " }";
Dictionary new_dict;
new_dict["name"] = format_enum_name(E.key);
new_dict["values"] = enum_items_text;
class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", new_dict);
if (idx < enumeration.size() - 1) {
class_enums += ", ";
} else {
class_enums += "\n\t";
}
idx++;
}
static String class_template = "\tbind(${class}, {${enumerations}});\n";
Dictionary class_dict;
class_dict["class"] = class_name;
class_dict["enumerations"] = class_enums;
enumerations += apply_pattern(class_template, class_dict);
}
Dictionary enum_dict;
enum_dict["enumerations"] = enumerations;
file_content = apply_pattern(file_content, enum_dict);

dump_to_file(p_path, file_content);
}

void JavaScriptPlugin::_generate_typescript_project() {
_export_typescript_declare_file("res://godot.d.ts");
dump_to_file("res://tsconfig.json", TSCONFIG_CONTENT);
dump_to_file("res://decorators.ts", TS_DECORATORS_CONTENT);
dump_to_file("res://package.json", PACKAGE_JSON_CONTENT);
}

// The following functions are used to generate a godot.d.ts file out of the docs folder from godot
#pragma region TS declare file

static String format_doc_text(const String &p_bbcode, const String &p_indent = "\t") {
String markdown = p_bbcode.strip_edges();

Expand Down Expand Up @@ -222,16 +298,15 @@ static String format_property_name(const String &p_ident) {
return p_ident;
}

static String format_enum_name(const String &enum_name) {
if (enum_name.begins_with("Variant.")) {
return enum_name.replace(".", "");
}
return enum_name;
}

static String get_type_name(const String &p_type) {
if (p_type.is_empty())
if (p_type.is_empty() || p_type == "void")
return "void";

if (p_type.ends_with("[]")) {
String base_type = p_type.substr(0, p_type.length() - 2);
return "Array<" + get_type_name(base_type) + ">";
}

if (p_type == "int" || p_type == "float")
return "number";
if (p_type == "bool")
Expand All @@ -242,8 +317,10 @@ static String get_type_name(const String &p_type) {
return "any[]";
if (p_type == "Dictionary")
return "object";
if (p_type == "Variant")
if (p_type == "Variant" || p_type.contains("*"))
return "any";
if (p_type == "StringName")
return "StringName | string";
return p_type;
}

Expand Down Expand Up @@ -276,6 +353,11 @@ String _export_method(const DocData::MethodDoc &p_method, bool is_function = fal
}
} else {
default_value += arg.default_value;
// we don't want to have pointers or addresses in TS
default_value = default_value
.replace("&", "")
.replace("*", "")
.replace("**", "");
}
}

Expand Down Expand Up @@ -316,17 +398,23 @@ String _export_method(const DocData::MethodDoc &p_method, bool is_function = fal
return apply_pattern(method_template, dict);
}

String _export_class(const DocData::ClassDoc &class_doc) {
/* This function generates all classes for godot.d.ts based on DocData::ClassDoc */
String _export_class(const DocData::ClassDoc &class_doc,
Dictionary missing_constructors,
Dictionary missing_enums,
Array ignore_methods) {
String class_template = "\n"
"\t/** ${brief_description}\n"
"\t ${description} */\n"
"${TS_IGNORE}"
"\tclass ${name}${extends}${inherits} {\n"
"${missingConstructors}"
"${properties}"
"${methods}"
"${extrals}"
"\t}\n"
"\tnamespace ${name} {\n"
"${missingEnums}"
"${signals}"
"${enumerations}"
"${constants}"
Expand All @@ -345,6 +433,9 @@ String _export_class(const DocData::ClassDoc &class_doc) {
dict["description"] = description;
}

dict["missingConstructors"] = missing_constructors.get(class_doc.name, "");
dict["missingEnums"] = missing_enums.get(class_doc.name, "");

HashSet<String> ignore_members;
if (removed_members.has(class_doc.name)) {
ignore_members = removed_members[class_doc.name];
Expand Down Expand Up @@ -439,15 +530,15 @@ String _export_class(const DocData::ClassDoc &class_doc) {
new_dict["static"] = Engine::get_singleton()->has_singleton(class_doc.name) ? "static " : "";
properties += apply_pattern(prop_str, new_dict);

if (!prop_doc.getter.is_empty()) {
if (!prop_doc.getter.is_empty() && !ignore_methods.has(prop_doc.getter)) {
DocData::MethodDoc md;
md.name = prop_doc.getter;
md.return_type = get_type_name(prop_doc.type);
md.description = String("Getter of `") + prop_doc.name + "` property";
method_list.push_back(md);
}

if (!prop_doc.setter.is_empty()) {
if (!prop_doc.setter.is_empty() && !ignore_methods.has(prop_doc.setter)) {
DocData::MethodDoc md;
md.name = prop_doc.setter;
DocData::ArgumentDoc arg;
Expand Down Expand Up @@ -566,27 +657,6 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
ignored_classes.insert("Variant");
ignored_classes.insert("Array");
ignored_classes.insert("Dictionary");
#if 1
ignored_classes.insert("Vector2");
ignored_classes.insert("Vector3");
ignored_classes.insert("Color");
ignored_classes.insert("Rect2");
ignored_classes.insert("RID");
ignored_classes.insert("NodePath");
ignored_classes.insert("Transform2D");
ignored_classes.insert("Transform3D");
ignored_classes.insert("Basis");
ignored_classes.insert("Quaternion");
ignored_classes.insert("Plane");
ignored_classes.insert("AABB");
ignored_classes.insert("PackedByteArray");
ignored_classes.insert("PackedInt32Array");
ignored_classes.insert("PackedFloat32Array");
ignored_classes.insert("PackedStringArray");
ignored_classes.insert("PackedVector2Array");
ignored_classes.insert("PackedVector3Array");
ignored_classes.insert("PackedColorArray");
#endif
ignored_classes.insert("Semaphore");
ignored_classes.insert("Thread");
ignored_classes.insert("Mutex");
Expand All @@ -601,7 +671,11 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
if (ignored_classes.has(class_doc.name)) {
continue;
}
class_doc.name = get_type_name(class_doc.name);

if (class_doc.name != "StringName" && class_doc.name != "NodePath") {
class_doc.name = get_type_name(class_doc.name);
}

if (class_doc.name.begins_with("@")) {
HashMap<String, Vector<const DocData::ConstantDoc *>> enumerations;
if (class_doc.name == "@GlobalScope" || class_doc.name == "@GDScript") {
Expand Down Expand Up @@ -666,7 +740,11 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
}
continue;
}
classes += _export_class(class_doc);
classes += _export_class(
class_doc,
DECLARATION_CONSTRUCTORS,
DECLARATION_ENUMS,
IGNORE_METHODS);
}
dict["classes"] = classes;
dict["constants"] = constants;
Expand All @@ -681,70 +759,6 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
}
}

void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) {
_export_typescript_declare_file("");
String file_content = "// Tool generated file DO NOT modify manually\n"
"// Add this script as first autoload to your project to bind enumerations for release build of godot engine\n"
"\n"
"if (!godot.DEBUG_ENABLED) {\n"
"\tfunction bind(cls, enumerations) {\n"
"\t\tif (cls) Object.defineProperties(cls, enumerations);\n"
"\t};\n"
"\n"
"${enumerations}"
"}\n"
"export default class extends godot.Node {};\n";

String enumerations = "";
for (const auto &cls : class_enumerations) {
const ClassEnumerations &enumeration = cls.value;
const String &name = cls.key;
String class_name = name;
if (class_name != "godot") {
class_name = "godot." + class_name;
}
String class_enums = "";
uint32_t idx = 0;
for (const auto &E : enumeration) {
String enum_items_text = "{";
const Vector<const DocData::ConstantDoc *> &consts = E.value;
for (int i = 0; i < consts.size(); ++i) {
const DocData::ConstantDoc *c = consts[i];
enum_items_text += c->name + ": " + c->value;
if (i < consts.size() - 1) {
enum_items_text += ", ";
}
}
enum_items_text += " }";
Dictionary new_dict;
new_dict["name"] = format_enum_name(E.key);
new_dict["values"] = enum_items_text;
class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", new_dict);
if (idx < enumeration.size() - 1) {
class_enums += ", ";
} else {
class_enums += "\n\t";
}
idx++;
}
static String class_template = "\tbind(${class}, {${enumerations}});\n";
Dictionary class_dict;
class_dict["class"] = class_name;
class_dict["enumerations"] = class_enums;
enumerations += apply_pattern(class_template, class_dict);
}
Dictionary enum_dict;
enum_dict["enumerations"] = enumerations;
file_content = apply_pattern(file_content, enum_dict);

dump_to_file(p_path, file_content);
}

void JavaScriptPlugin::_generate_typescript_project() {
_export_typescript_declare_file("res://godot.d.ts");
dump_to_file("res://tsconfig.json", TSCONFIG_CONTENT);
dump_to_file("res://decorators.ts", TS_DECORATORS_CONTENT);
dump_to_file("res://package.json", PACKAGE_JSON_CONTENT);
}
#pragma endregion TS declare file

#endif // TOOLS_ENABLED
6 changes: 6 additions & 0 deletions editor/editor_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,17 @@ class JavaScriptPlugin : public EditorPlugin {
const Dictionary *modified_api;

protected:
/* Strings will be generated by ./SCsub from misc directory */
static String BUILTIN_DECLARATION_TEXT;
static String TSCONFIG_CONTENT;
static String TS_DECORATORS_CONTENT;
static String PACKAGE_JSON_CONTENT;

/* Missing declarations, ignoring*/
static Dictionary DECLARATION_CONSTRUCTORS;
static Dictionary DECLARATION_ENUMS;
static Array IGNORE_METHODS;

static void _bind_methods();

void _notification(int p_what);
Expand Down
43 changes: 43 additions & 0 deletions editor/workarounds/ignore-methods.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**************************************************************************/
/* ignore-methods.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

/* All types are generated in editor_tools, but constructors are missing we need to add them manually. */

#include "../editor_tools.h"

Array create_ignore_methods() {
Array array = Array();
array.push_back("get_flag");
array.push_back("set_flag");
array.push_back("set_play_area_mode");
return array;
}

Array JavaScriptPlugin::IGNORE_METHODS = create_ignore_methods();
Loading