Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
41 changes: 41 additions & 0 deletions .changeset/silent-clouds-matter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
"@godot-js/editor": major
---

feat: replaced @bind.help/experimental/deprecated with standard JS comments and JSDoc like annotations

Here is an example for more information checkout https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_documentation_comments.html:
````ts
/**
* A brief description of the class's role and functionality.
*
* The description of the script, what it can do,
* and any further detail.
*
* @tutorial https://example.com/tutorial_1
* @tutorial(Tutorial 2) https://example.com/tutorial_2
* @experimental
*/
export default class DocumentationComments extends Node {

/**
* This is a multiline description of the variable v2.
* The type information below will be extracted for the documentation.
*/
v2: number = 0;

/**
* As the following function is documented, even though its name starts with
* an underscore, it will appear in the help window.
*/
_fn(p1: number, p2: string): number {
return 0;
}

/**
* This function is deprecated and should not appear in the help window.
* @deprecated Use [method _fn] instead
*/
_deprecated() {}
}
````
78 changes: 0 additions & 78 deletions bridge/jsb_bridge_module_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,83 +272,6 @@ namespace jsb
impl::Helper::to_string_opt(isolate, evaluator->Get(context, jsb_name(environment, name))));
}

// function set_script_doc(target: GObjectConstructor, property_key: undefined, field: 0 | 1 | 2, message: string): void;
// function set_script_doc(target: GObject, property_key: string, field: 0 | 1 | 2, message: string): void;
void _set_script_doc(const v8::FunctionCallbackInfo<v8::Value>& info)
{
#ifdef TOOLS_ENABLED
constexpr int kTarget = 0; // constructor | prototype
constexpr int kProperty = 1; // undefined | string
constexpr int kField = 2; // int32: 0, 1, 2
constexpr int kMessage = 3; // undefined | string

v8::Isolate* isolate = info.GetIsolate();
v8::HandleScope handle_scope(isolate);
const v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (info.Length() != 4 || !info[kTarget]->IsObject() || !info[kField]->IsNumber())
{
jsb_throw(isolate, "bad param");
return;
}
Environment* environment = Environment::wrap(isolate);
const v8::Local<v8::Object> target = info[kTarget].As<v8::Object>();
const v8::Local<v8::Value> property = info[kProperty].As<v8::Object>();
const ScriptClassDocField::Type doc_item = (ScriptClassDocField::Type) info[kField].As<v8::Int32>()->Value();
const v8::Local<v8::String> message = info[kMessage]->IsString() ? info[kMessage].As<v8::String>() : v8::String::Empty(isolate);
v8::Local<v8::Object> doc;

// always set doc info on `prototype`
if (property->IsUndefined())
{
// doc for class
const v8::Local<v8::Object> prototype = target->Get(context, jsb_name(environment, prototype)).ToLocalChecked().As<v8::Object>();
jsb_check(prototype->IsObject());
if (v8::Local<v8::Value> val; !prototype->Get(context, jsb_symbol(environment, Doc)).ToLocal(&val) || !val->IsObject())
{
doc = v8::Object::New(isolate);
prototype->Set(context, jsb_symbol(environment, Doc), doc).Check();
}
else
{
doc = val.As<v8::Object>();
}
}
else
{
// doc for member
jsb_check(property->IsString() && property.As<v8::String>()->Length() != 0);
v8::Local<v8::Map> member_doc_map;
if (v8::Local<v8::Value> val; !target->Get(context, jsb_symbol(environment, MemberDocMap)).ToLocal(&val) || !val->IsMap())
{
member_doc_map = v8::Map::New(isolate);
target->Set(context, jsb_symbol(environment, MemberDocMap), member_doc_map).Check();
}
else
{
member_doc_map = val.As<v8::Map>();
}

if (v8::Local<v8::Value> val; !member_doc_map->Get(context, property).ToLocal(&val) || !val->IsObject())
{
doc = v8::Object::New(isolate);
jsb_ensure(!member_doc_map->Set(context, property, doc).IsEmpty());
}
else
{
doc = val.As<v8::Object>();
}
}

switch (doc_item)
{
case ScriptClassDocField::Deprecated: doc->Set(context, jsb_name(environment, deprecated), message).Check(); return;
case ScriptClassDocField::Experimental: doc->Set(context, jsb_name(environment, experimental), message).Check(); return;
case ScriptClassDocField::Help: doc->Set(context, jsb_name(environment, help), message).Check(); return;
}
jsb_throw(isolate, "bad param");
#endif
}

// function add_script_property(prototype: GObject, details: ScriptPropertyInfo): void
void _add_script_property(const v8::FunctionCallbackInfo<v8::Value>& info)
{
Expand Down Expand Up @@ -581,7 +504,6 @@ namespace jsb
internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "add_script_tool"), JSB_NEW_FUNCTION(context, _add_script_tool, {})).Check();
internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "add_script_icon"), JSB_NEW_FUNCTION(context, _add_script_icon, {})).Check();
internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "add_script_rpc"), JSB_NEW_FUNCTION(context, _add_script_rpc, {})).Check();
internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "set_script_doc"), JSB_NEW_FUNCTION(context, _set_script_doc, {})).Check();
internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "notify_microtasks_run"), JSB_NEW_FUNCTION(context, _notify_microtasks_run, {})).Check();

internal_obj->Set(context, impl::Helper::new_string_ascii(isolate, "create_script_cached_property_updater"), JSB_NEW_FUNCTION(context, _create_script_cached_property_updater, {})).Check();
Expand Down
73 changes: 2 additions & 71 deletions bridge/jsb_class_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,6 @@

namespace jsb
{
#ifdef TOOLS_ENABLED
void _parse_script_doc(v8::Isolate* isolate, const v8::Local<v8::Context>& context,
const v8::MaybeLocal<v8::Value> holder, ScriptBaseDoc& r_doc)
{
if (v8::Local<v8::Value> tv; holder.IsEmpty() || !holder.ToLocal(&tv) || !tv->IsObject())
{
// invalid
}
else
{
const v8::Local<v8::Object> obj = tv.As<v8::Object>();
Environment* environment = Environment::wrap(isolate);

// (@deprecated)
if (v8::Local<v8::Value> val; obj->Get(context, jsb_name(environment, deprecated)).ToLocal(&val) && val->IsString())
{
r_doc.is_deprecated = true;
r_doc.deprecated_message = impl::Helper::to_string(isolate, val);
}
else
{
r_doc.is_deprecated = false;
}
// (@experimental)
if (v8::Local<v8::Value> val; obj->Get(context, jsb_name(environment, experimental)).ToLocal(&val) && val->IsString())
{
r_doc.is_experimental = true;
r_doc.experimental_message = impl::Helper::to_string(isolate, val);
}
else
{
r_doc.is_experimental = false;
}
// (@help)
if (v8::Local<v8::Value> val; obj->Get(context, jsb_name(environment, help)).ToLocal(&val) && val->IsString())
{
r_doc.brief_description = impl::Helper::to_string(isolate, val);
}
else
{
r_doc.brief_description.clear();
}
}
}
#endif

//NOTE ensure the address of p_class_info being locked during this procedure
void _parse_script_class_iterate(const v8::Local<v8::Context>& p_context, const ScriptClassInfoPtr& p_class_info, const v8::Local<v8::Object>& class_obj)
{
Expand Down Expand Up @@ -80,16 +34,6 @@ namespace jsb

JSB_LOG(VeryVerbose, "godot js class name %s (native: %s)", p_class_info->js_class_name, p_class_info->native_class_name);

#ifdef TOOLS_ENABLED
// class doc
v8::Local<v8::Map> doc_map;
if (v8::Local<v8::Value> val; prototype->Get(p_context, jsb_symbol(environment, MemberDocMap)).ToLocal(&val) && val->IsMap())
{
doc_map = val.As<v8::Map>();
}
_parse_script_doc(isolate, p_context, prototype->Get(p_context, jsb_symbol(environment, Doc)), p_class_info->doc);
#endif

// class rpc config
v8::Local<v8::Map> rpc_config_map;
if (v8::Local<v8::Value> val; prototype->Get(p_context, jsb_symbol(environment, ClassRPCConfig)).ToLocal(&val) && val->IsMap())
Expand Down Expand Up @@ -117,15 +61,8 @@ namespace jsb
v8::Local<v8::Value> prop_val;
if (prop_descriptor.As<v8::Object>()->Get(p_context, jsb_name(environment, value)).ToLocal(&prop_val) && prop_val->IsFunction())
{
//TODO property categories
ScriptMethodInfo method_info = {};
#ifdef TOOLS_ENABLED
if (v8::Local<v8::Value> val; !doc_map.IsEmpty() && doc_map->Get(p_context, prop_name).ToLocal(&val) && val->IsObject())
{
_parse_script_doc(isolate, p_context, val, method_info.doc);
}
#endif // TOOLS_ENABLED
p_class_info->methods.insert((StringName) name_s, method_info);

p_class_info->methods.insert((StringName) name_s, {});

// check rpc config
if (v8::Local<v8::Value> rpc_val;
Expand Down Expand Up @@ -231,12 +168,6 @@ namespace jsb
property_info.cache = cache->BooleanValue(isolate);
}

#ifdef TOOLS_ENABLED
if (v8::Local<v8::Value> val; !doc_map.IsEmpty() && doc_map->Get(p_context, prop_name).ToLocal(&val) && val->IsObject())
{
_parse_script_doc(isolate, p_context, val, property_info.doc);
}
#endif // TOOLS_ENABLED
p_class_info->properties.insert(property_info.name, property_info);
JSB_LOG(VeryVerbose, "... property %s: %s", property_info.name, Variant::get_type_name(property_info.type));
}
Expand Down
29 changes: 0 additions & 29 deletions bridge/jsb_class_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,6 @@ namespace jsb
};
}

#ifdef TOOLS_ENABLED
struct ScriptBaseDoc
{
String brief_description;

String deprecated_message;
String experimental_message;

bool is_deprecated = false;
bool is_experimental = false;

};

struct ScriptClassDoc : ScriptBaseDoc {};
struct ScriptMethodDoc : ScriptBaseDoc {};
struct ScriptPropertyDoc : ScriptBaseDoc {};
#else
struct ScriptClassDoc {};
struct ScriptMethodDoc {};
struct ScriptPropertyDoc {};
#endif

namespace ScriptMethodFlags
{
Expand All @@ -130,9 +109,6 @@ namespace jsb

struct ScriptMethodInfo
{
// only valid with TOOLS_ENABLED
ScriptMethodDoc doc;

ScriptMethodFlags::Type flags = ScriptMethodFlags::None;

// v8::Global<v8::Function> cache_;
Expand All @@ -154,8 +130,6 @@ namespace jsb

String hint_string;

ScriptPropertyDoc doc;

// valid only if _Evaluated flag is set in ScriptClassInfo.flags
Variant default_value;

Expand Down Expand Up @@ -201,9 +175,6 @@ namespace jsb
// script icon path for showing in scene hierarchy
String icon;

// only valid with TOOLS_ENABLED
ScriptClassDoc doc;

Dictionary rpc_config;

HashMap<StringName, ScriptMethodInfo> methods;
Expand Down
83 changes: 1 addition & 82 deletions scripts/jsb.editor/src/jsb.editor.codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1888,88 +1888,7 @@ const annotation_types = {
},
],
},
},
deprecated: {
type: DescriptorType.FunctionLiteral,
parameters: [
{ name: "message", type: { type: DescriptorType.Godot, name: "string" }, optional: true },
],
returns: {
type: DescriptorType.Godot,
name: "Decorator",
arguments: [
{
type: DescriptorType.Union,
types: [
{
type: DescriptorType.Godot,
name: "ClassDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
{
type: DescriptorType.Godot,
name: "ClassValueMemberDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
],
},
],
},
},
experimental: {
type: DescriptorType.FunctionLiteral,
parameters: [
{ name: "message", type: { type: DescriptorType.Godot, name: "string" }, optional: true },
],
returns: {
type: DescriptorType.Godot,
name: "Decorator",
arguments: [
{
type: DescriptorType.Union,
types: [
{
type: DescriptorType.Godot,
name: "ClassDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
{
type: DescriptorType.Godot,
name: "ClassValueMemberDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
],
},
],
},
},
help: {
type: DescriptorType.FunctionLiteral,
parameters: [
{ name: "message", type: { type: DescriptorType.Godot, name: "string" }, optional: true },
],
returns: {
type: DescriptorType.Godot,
name: "Decorator",
arguments: [
{
type: DescriptorType.Union,
types: [
{
type: DescriptorType.Godot,
name: "ClassDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
{
type: DescriptorType.Godot,
name: "ClassValueMemberDecoratorContext",
arguments: [{ type: DescriptorType.Godot, name: "GObjectConstructor" }],
},
],
},
],
},
},
}
},
},
],
Expand Down
Loading
Loading