Skip to content

Commit 72c366d

Browse files
authored
fix: generating declaration file inside editor (#190)
* fix: generating declaration file inside editor * chore: fix typo * fix: issue with StringName for godot.d.ts * chore: fix issues with hard coded classes in godot.d.ts file * chore: update clang format * chore: run clang-format * chore: update static_checks.yml
1 parent 4d10a74 commit 72c366d

File tree

8 files changed

+332
-2111
lines changed

8 files changed

+332
-2111
lines changed

.github/workflows/static_checks.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ jobs:
9696
9797
- name: Spell checks via codespell
9898
if: github.event_name == 'pull_request' && env.CHANGED_FILES != ''
99-
uses: codespell-project/actions-codespell@v1
99+
uses: codespell-project/actions-codespell@v2
100100
with:
101101
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"
102-
ignore_words_list: "curvelinear,doubleclick,expct,findn,gird,hel,inout,lod,nd,numer,ot,te,vai"
102+
ignore_words_list: "breaked,checkin,curvelinear,doubleclick,expct,findn,gird,hel,inout,labelin,lod,mis,nd,numer,ot,pointin,requestor,te,textin,thirdparty,vai"
103103
path: ${{ env.CHANGED_FILES }}

SCsub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,5 @@ env_module.Append(CPPPATH=["#modules/javascript"])
100100
env_module.add_source_files(env.modules_sources, sources)
101101

102102
if env.editor_build:
103+
env_module.add_source_files(env.modules_sources, "editor/workarounds/*.cpp")
103104
env_module.add_source_files(env.modules_sources, "editor/*.cpp")

editor/editor_tools.cpp

Lines changed: 114 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,82 @@ static String apply_pattern(const String &p_pattern, const Dictionary &p_values)
150150
return ret;
151151
}
152152

153+
static String format_enum_name(const String &enum_name) {
154+
if (enum_name.begins_with("Variant.")) {
155+
return enum_name.replace(".", "");
156+
}
157+
return enum_name;
158+
}
159+
160+
void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) {
161+
_export_typescript_declare_file("");
162+
String file_content = "// Tool generated file DO NOT modify manually\n"
163+
"// Add this script as first autoload to your project to bind enumerations for release build of godot engine\n"
164+
"\n"
165+
"if (!godot.DEBUG_ENABLED) {\n"
166+
"\tfunction bind(cls, enumerations) {\n"
167+
"\t\tif (cls) Object.defineProperties(cls, enumerations);\n"
168+
"\t};\n"
169+
"\n"
170+
"${enumerations}"
171+
"}\n"
172+
"export default class extends godot.Node {};\n";
173+
174+
String enumerations = "";
175+
for (const auto &cls : class_enumerations) {
176+
const ClassEnumerations &enumeration = cls.value;
177+
const String &name = cls.key;
178+
String class_name = name;
179+
if (class_name != "godot") {
180+
class_name = "godot." + class_name;
181+
}
182+
String class_enums = "";
183+
uint32_t idx = 0;
184+
for (const auto &E : enumeration) {
185+
String enum_items_text = "{";
186+
const Vector<const DocData::ConstantDoc *> &consts = E.value;
187+
for (int i = 0; i < consts.size(); ++i) {
188+
const DocData::ConstantDoc *c = consts[i];
189+
enum_items_text += c->name + ": " + c->value;
190+
if (i < consts.size() - 1) {
191+
enum_items_text += ", ";
192+
}
193+
}
194+
enum_items_text += " }";
195+
Dictionary new_dict;
196+
new_dict["name"] = format_enum_name(E.key);
197+
new_dict["values"] = enum_items_text;
198+
class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", new_dict);
199+
if (idx < enumeration.size() - 1) {
200+
class_enums += ", ";
201+
} else {
202+
class_enums += "\n\t";
203+
}
204+
idx++;
205+
}
206+
static String class_template = "\tbind(${class}, {${enumerations}});\n";
207+
Dictionary class_dict;
208+
class_dict["class"] = class_name;
209+
class_dict["enumerations"] = class_enums;
210+
enumerations += apply_pattern(class_template, class_dict);
211+
}
212+
Dictionary enum_dict;
213+
enum_dict["enumerations"] = enumerations;
214+
file_content = apply_pattern(file_content, enum_dict);
215+
216+
dump_to_file(p_path, file_content);
217+
}
218+
219+
void JavaScriptPlugin::_generate_typescript_project() {
220+
_export_typescript_declare_file("res://godot.d.ts");
221+
dump_to_file("res://tsconfig.json", TSCONFIG_CONTENT);
222+
dump_to_file("res://decorators.ts", TS_DECORATORS_CONTENT);
223+
dump_to_file("res://package.json", PACKAGE_JSON_CONTENT);
224+
}
225+
226+
// The following functions are used to generate a godot.d.ts file out of the docs folder from godot
227+
#pragma region TS declare file
228+
153229
static String format_doc_text(const String &p_bbcode, const String &p_indent = "\t") {
154230
String markdown = p_bbcode.strip_edges();
155231

@@ -222,16 +298,15 @@ static String format_property_name(const String &p_ident) {
222298
return p_ident;
223299
}
224300

225-
static String format_enum_name(const String &enum_name) {
226-
if (enum_name.begins_with("Variant.")) {
227-
return enum_name.replace(".", "");
228-
}
229-
return enum_name;
230-
}
231-
232301
static String get_type_name(const String &p_type) {
233-
if (p_type.is_empty())
302+
if (p_type.is_empty() || p_type == "void")
234303
return "void";
304+
305+
if (p_type.ends_with("[]")) {
306+
String base_type = p_type.substr(0, p_type.length() - 2);
307+
return "Array<" + get_type_name(base_type) + ">";
308+
}
309+
235310
if (p_type == "int" || p_type == "float")
236311
return "number";
237312
if (p_type == "bool")
@@ -242,8 +317,10 @@ static String get_type_name(const String &p_type) {
242317
return "any[]";
243318
if (p_type == "Dictionary")
244319
return "object";
245-
if (p_type == "Variant")
320+
if (p_type == "Variant" || p_type.contains("*"))
246321
return "any";
322+
if (p_type == "StringName")
323+
return "StringName | string";
247324
return p_type;
248325
}
249326

@@ -276,6 +353,11 @@ String _export_method(const DocData::MethodDoc &p_method, bool is_function = fal
276353
}
277354
} else {
278355
default_value += arg.default_value;
356+
// we don't want to have pointers or addresses in TS
357+
default_value = default_value
358+
.replace("&", "")
359+
.replace("*", "")
360+
.replace("**", "");
279361
}
280362
}
281363

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

319-
String _export_class(const DocData::ClassDoc &class_doc) {
401+
/* This function generates all classes for godot.d.ts based on DocData::ClassDoc */
402+
String _export_class(const DocData::ClassDoc &class_doc,
403+
Dictionary missing_constructors,
404+
Dictionary missing_enums,
405+
Array ignore_methods) {
320406
String class_template = "\n"
321407
"\t/** ${brief_description}\n"
322408
"\t ${description} */\n"
323409
"${TS_IGNORE}"
324410
"\tclass ${name}${extends}${inherits} {\n"
411+
"${missingConstructors}"
325412
"${properties}"
326413
"${methods}"
327414
"${extrals}"
328415
"\t}\n"
329416
"\tnamespace ${name} {\n"
417+
"${missingEnums}"
330418
"${signals}"
331419
"${enumerations}"
332420
"${constants}"
@@ -345,6 +433,9 @@ String _export_class(const DocData::ClassDoc &class_doc) {
345433
dict["description"] = description;
346434
}
347435

436+
dict["missingConstructors"] = missing_constructors.get(class_doc.name, "");
437+
dict["missingEnums"] = missing_enums.get(class_doc.name, "");
438+
348439
HashSet<String> ignore_members;
349440
if (removed_members.has(class_doc.name)) {
350441
ignore_members = removed_members[class_doc.name];
@@ -439,15 +530,15 @@ String _export_class(const DocData::ClassDoc &class_doc) {
439530
new_dict["static"] = Engine::get_singleton()->has_singleton(class_doc.name) ? "static " : "";
440531
properties += apply_pattern(prop_str, new_dict);
441532

442-
if (!prop_doc.getter.is_empty()) {
533+
if (!prop_doc.getter.is_empty() && !ignore_methods.has(prop_doc.getter)) {
443534
DocData::MethodDoc md;
444535
md.name = prop_doc.getter;
445536
md.return_type = get_type_name(prop_doc.type);
446537
md.description = String("Getter of `") + prop_doc.name + "` property";
447538
method_list.push_back(md);
448539
}
449540

450-
if (!prop_doc.setter.is_empty()) {
541+
if (!prop_doc.setter.is_empty() && !ignore_methods.has(prop_doc.setter)) {
451542
DocData::MethodDoc md;
452543
md.name = prop_doc.setter;
453544
DocData::ArgumentDoc arg;
@@ -566,27 +657,6 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
566657
ignored_classes.insert("Variant");
567658
ignored_classes.insert("Array");
568659
ignored_classes.insert("Dictionary");
569-
#if 1
570-
ignored_classes.insert("Vector2");
571-
ignored_classes.insert("Vector3");
572-
ignored_classes.insert("Color");
573-
ignored_classes.insert("Rect2");
574-
ignored_classes.insert("RID");
575-
ignored_classes.insert("NodePath");
576-
ignored_classes.insert("Transform2D");
577-
ignored_classes.insert("Transform3D");
578-
ignored_classes.insert("Basis");
579-
ignored_classes.insert("Quaternion");
580-
ignored_classes.insert("Plane");
581-
ignored_classes.insert("AABB");
582-
ignored_classes.insert("PackedByteArray");
583-
ignored_classes.insert("PackedInt32Array");
584-
ignored_classes.insert("PackedFloat32Array");
585-
ignored_classes.insert("PackedStringArray");
586-
ignored_classes.insert("PackedVector2Array");
587-
ignored_classes.insert("PackedVector3Array");
588-
ignored_classes.insert("PackedColorArray");
589-
#endif
590660
ignored_classes.insert("Semaphore");
591661
ignored_classes.insert("Thread");
592662
ignored_classes.insert("Mutex");
@@ -601,7 +671,11 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
601671
if (ignored_classes.has(class_doc.name)) {
602672
continue;
603673
}
604-
class_doc.name = get_type_name(class_doc.name);
674+
675+
if (class_doc.name != "StringName" && class_doc.name != "NodePath") {
676+
class_doc.name = get_type_name(class_doc.name);
677+
}
678+
605679
if (class_doc.name.begins_with("@")) {
606680
HashMap<String, Vector<const DocData::ConstantDoc *>> enumerations;
607681
if (class_doc.name == "@GlobalScope" || class_doc.name == "@GDScript") {
@@ -666,7 +740,11 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
666740
}
667741
continue;
668742
}
669-
classes += _export_class(class_doc);
743+
classes += _export_class(
744+
class_doc,
745+
DECLARATION_CONSTRUCTORS,
746+
DECLARATION_ENUMS,
747+
IGNORE_METHODS);
670748
}
671749
dict["classes"] = classes;
672750
dict["constants"] = constants;
@@ -681,70 +759,6 @@ void JavaScriptPlugin::_export_typescript_declare_file(const String &p_path) {
681759
}
682760
}
683761

684-
void JavaScriptPlugin::_export_enumeration_binding_file(const String &p_path) {
685-
_export_typescript_declare_file("");
686-
String file_content = "// Tool generated file DO NOT modify manually\n"
687-
"// Add this script as first autoload to your project to bind enumerations for release build of godot engine\n"
688-
"\n"
689-
"if (!godot.DEBUG_ENABLED) {\n"
690-
"\tfunction bind(cls, enumerations) {\n"
691-
"\t\tif (cls) Object.defineProperties(cls, enumerations);\n"
692-
"\t};\n"
693-
"\n"
694-
"${enumerations}"
695-
"}\n"
696-
"export default class extends godot.Node {};\n";
697-
698-
String enumerations = "";
699-
for (const auto &cls : class_enumerations) {
700-
const ClassEnumerations &enumeration = cls.value;
701-
const String &name = cls.key;
702-
String class_name = name;
703-
if (class_name != "godot") {
704-
class_name = "godot." + class_name;
705-
}
706-
String class_enums = "";
707-
uint32_t idx = 0;
708-
for (const auto &E : enumeration) {
709-
String enum_items_text = "{";
710-
const Vector<const DocData::ConstantDoc *> &consts = E.value;
711-
for (int i = 0; i < consts.size(); ++i) {
712-
const DocData::ConstantDoc *c = consts[i];
713-
enum_items_text += c->name + ": " + c->value;
714-
if (i < consts.size() - 1) {
715-
enum_items_text += ", ";
716-
}
717-
}
718-
enum_items_text += " }";
719-
Dictionary new_dict;
720-
new_dict["name"] = format_enum_name(E.key);
721-
new_dict["values"] = enum_items_text;
722-
class_enums += apply_pattern("\n\t\t${name}: { value: ${values} }", new_dict);
723-
if (idx < enumeration.size() - 1) {
724-
class_enums += ", ";
725-
} else {
726-
class_enums += "\n\t";
727-
}
728-
idx++;
729-
}
730-
static String class_template = "\tbind(${class}, {${enumerations}});\n";
731-
Dictionary class_dict;
732-
class_dict["class"] = class_name;
733-
class_dict["enumerations"] = class_enums;
734-
enumerations += apply_pattern(class_template, class_dict);
735-
}
736-
Dictionary enum_dict;
737-
enum_dict["enumerations"] = enumerations;
738-
file_content = apply_pattern(file_content, enum_dict);
739-
740-
dump_to_file(p_path, file_content);
741-
}
742-
743-
void JavaScriptPlugin::_generate_typescript_project() {
744-
_export_typescript_declare_file("res://godot.d.ts");
745-
dump_to_file("res://tsconfig.json", TSCONFIG_CONTENT);
746-
dump_to_file("res://decorators.ts", TS_DECORATORS_CONTENT);
747-
dump_to_file("res://package.json", PACKAGE_JSON_CONTENT);
748-
}
762+
#pragma endregion TS declare file
749763

750764
#endif // TOOLS_ENABLED

editor/editor_tools.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,17 @@ class JavaScriptPlugin : public EditorPlugin {
5151
const Dictionary *modified_api;
5252

5353
protected:
54+
/* Strings will be generated by ./SCsub from misc directory */
5455
static String BUILTIN_DECLARATION_TEXT;
5556
static String TSCONFIG_CONTENT;
5657
static String TS_DECORATORS_CONTENT;
5758
static String PACKAGE_JSON_CONTENT;
5859

60+
/* Missing declarations, ignoring*/
61+
static Dictionary DECLARATION_CONSTRUCTORS;
62+
static Dictionary DECLARATION_ENUMS;
63+
static Array IGNORE_METHODS;
64+
5965
static void _bind_methods();
6066

6167
void _notification(int p_what);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**************************************************************************/
2+
/* ignore-methods.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
/* All types are generated in editor_tools, but constructors are missing we need to add them manually. */
32+
33+
#include "../editor_tools.h"
34+
35+
Array create_ignore_methods() {
36+
Array array = Array();
37+
array.push_back("get_flag");
38+
array.push_back("set_flag");
39+
array.push_back("set_play_area_mode");
40+
return array;
41+
}
42+
43+
Array JavaScriptPlugin::IGNORE_METHODS = create_ignore_methods();

0 commit comments

Comments
 (0)