From a8ce317d28a2fd816a487d1a8bf2931ee0384ed7 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Sun, 31 May 2026 07:38:03 +0100 Subject: [PATCH 01/19] Add call action annotation overrides --- custom/Entity.NetworkVar.lua | 9 +++++++++ custom/Entity.NetworkVarElement.lua | 10 ++++++++++ custom/Global.AccessorFunc.lua | 1 + custom/Global.Color.lua | 11 +++++++++++ custom/Global.CreateClientConVar.lua | 13 +++++++++++++ custom/Global.CreateConVar.lua | 1 + custom/Global.DEFINE_BASECLASS.lua | 7 +++++++ custom/Global.DeriveGamemode.lua | 6 ++++++ custom/Panel.Add.lua | 1 + custom/Panel.GetSkin.lua | 6 ++++++ custom/Panel.SetSkin.lua | 8 ++++++++ custom/concommand.Add.lua | 11 +++++++++++ custom/derma.DefineControl.lua | 12 ++++++++++++ custom/derma.DefineSkin.lua | 9 +++++++++ custom/derma.GetDefaultSkin.lua | 6 ++++++ custom/derma.GetNamedSkin.lua | 8 ++++++++ custom/derma.GetSkinTable.lua | 6 ++++++ custom/derma.SkinHook.lua | 10 ++++++++++ custom/hook.Add.lua | 1 + custom/hook.Call.lua | 10 ++++++++++ custom/hook.Run.lua | 9 +++++++++ custom/net.Receive.lua | 7 +++++++ custom/net.Start.lua | 8 ++++++++ custom/timer.Create.lua | 10 ++++++++++ custom/timer.Simple.lua | 8 ++++++++ custom/util.AddNetworkString.lua | 7 +++++++ custom/vgui.Create.lua | 1 + custom/vgui.CreateX.lua | 1 + custom/vgui.Register.lua | 11 +++++++++++ 29 files changed, 208 insertions(+) create mode 100644 custom/Entity.NetworkVar.lua create mode 100644 custom/Entity.NetworkVarElement.lua create mode 100644 custom/Global.Color.lua create mode 100644 custom/Global.CreateClientConVar.lua create mode 100644 custom/Global.DEFINE_BASECLASS.lua create mode 100644 custom/Global.DeriveGamemode.lua create mode 100644 custom/Panel.GetSkin.lua create mode 100644 custom/Panel.SetSkin.lua create mode 100644 custom/concommand.Add.lua create mode 100644 custom/derma.DefineControl.lua create mode 100644 custom/derma.DefineSkin.lua create mode 100644 custom/derma.GetDefaultSkin.lua create mode 100644 custom/derma.GetNamedSkin.lua create mode 100644 custom/derma.GetSkinTable.lua create mode 100644 custom/derma.SkinHook.lua create mode 100644 custom/hook.Call.lua create mode 100644 custom/hook.Run.lua create mode 100644 custom/net.Receive.lua create mode 100644 custom/net.Start.lua create mode 100644 custom/timer.Create.lua create mode 100644 custom/timer.Simple.lua create mode 100644 custom/util.AddNetworkString.lua create mode 100644 custom/vgui.Register.lua diff --git a/custom/Entity.NetworkVar.lua b/custom/Entity.NetworkVar.lua new file mode 100644 index 0000000..891fe3a --- /dev/null +++ b/custom/Entity.NetworkVar.lua @@ -0,0 +1,9 @@ +---Creates a network variable and generated Get/Set accessors for the entity. +---@realm shared +---@source https://wiki.facepunch.com/gmod/Entity:NetworkVar +---@callaction gmod.class kind=network_var type_arg=1 name_arg=3 fallback_name_arg=2 +---@param type string The NetworkVar type. +---@param slot number The NetworkVar slot. +---@param name string Name of the variable, used for generated Get/Set accessors. +---@param extended? table Extra NetworkVar information. +function Entity:NetworkVar(type, slot, name, extended) end diff --git a/custom/Entity.NetworkVarElement.lua b/custom/Entity.NetworkVarElement.lua new file mode 100644 index 0000000..14b039b --- /dev/null +++ b/custom/Entity.NetworkVarElement.lua @@ -0,0 +1,10 @@ +---Creates Get/Set accessors for a vector or angle element NetworkVar. +---@realm shared +---@source https://wiki.facepunch.com/gmod/Entity:NetworkVarElement +---@callaction gmod.class kind=network_var_element type_arg=1 name_arg=4 fallback_name_arg=3 fallback_name_arg2=2 +---@param type string The NetworkVar type. +---@param slot number The NetworkVar slot. +---@param element number The vector or angle element. +---@param name string Name of the variable, used for generated Get/Set accessors. +---@param extended? table Extra NetworkVar information. +function Entity:NetworkVarElement(type, slot, element, name, extended) end diff --git a/custom/Global.AccessorFunc.lua b/custom/Global.AccessorFunc.lua index 3371b5d..18c4d38 100644 --- a/custom/Global.AccessorFunc.lua +++ b/custom/Global.AccessorFunc.lua @@ -4,6 +4,7 @@ ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.AccessorFunc ---@accessorfunc 2 +---@callaction gmod.class kind=accessor_func ---@param tab table The table to add the accessor functions to. ---@param key any The key of the table to be get/set. ---@param name string The name of the functions (will be prefixed with Get and Set). diff --git a/custom/Global.Color.lua b/custom/Global.Color.lua new file mode 100644 index 0000000..5b82b6d --- /dev/null +++ b/custom/Global.Color.lua @@ -0,0 +1,11 @@ +---Creates a new Color. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/Global.Color +---@callaction gmod.color kind=rgba r_arg=1 g_arg=2 b_arg=3 a_arg=4 +---@param r number The red channel, from 0 to 255. +---@param g number The green channel, from 0 to 255. +---@param b number The blue channel, from 0 to 255. +---@param a? number The alpha channel, from 0 to 255. +---@return Color +function _G.Color(r, g, b, a) end diff --git a/custom/Global.CreateClientConVar.lua b/custom/Global.CreateClientConVar.lua new file mode 100644 index 0000000..092ce65 --- /dev/null +++ b/custom/Global.CreateClientConVar.lua @@ -0,0 +1,13 @@ +---Creates a client-side console variable. +---@realm client +---@source https://wiki.facepunch.com/gmod/Global.CreateClientConVar +---@callaction gmod.system kind=create_client_convar name_arg=1 +---@param name string +---@param default string|number +---@param shouldsave? boolean +---@param userinfo? boolean +---@param helptext? string +---@param min? number +---@param max? number +---@return (instance) ConVar +function _G.CreateClientConVar(name, default, shouldsave, userinfo, helptext, min, max) end diff --git a/custom/Global.CreateConVar.lua b/custom/Global.CreateConVar.lua index a8fcfef..100e924 100644 --- a/custom/Global.CreateConVar.lua +++ b/custom/Global.CreateConVar.lua @@ -4,6 +4,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.CreateConVar +---@callaction gmod.system kind=create_convar name_arg=1 ---@param name string ---@param value string|number ---@param flags? FCVAR|number[] diff --git a/custom/Global.DEFINE_BASECLASS.lua b/custom/Global.DEFINE_BASECLASS.lua new file mode 100644 index 0000000..813e9f6 --- /dev/null +++ b/custom/Global.DEFINE_BASECLASS.lua @@ -0,0 +1,7 @@ +---Declares the BaseClass helper for scripted classes. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/Global.DEFINE_BASECLASS +---@callaction gmod.class kind=define_baseclass base_arg=1 +---@param value string Base class name. +function _G.DEFINE_BASECLASS(value) end diff --git a/custom/Global.DeriveGamemode.lua b/custom/Global.DeriveGamemode.lua new file mode 100644 index 0000000..13e53ff --- /dev/null +++ b/custom/Global.DeriveGamemode.lua @@ -0,0 +1,6 @@ +---Derives the current gamemode from another gamemode. +---@realm shared +---@source https://wiki.facepunch.com/gmod/Global.DeriveGamemode +---@callaction gmod.class kind=derive_gamemode base_arg=1 +---@param base string Base gamemode folder name. +function _G.DeriveGamemode(base) end diff --git a/custom/Panel.Add.lua b/custom/Panel.Add.lua index 0e60e0a..7b8894d 100644 --- a/custom/Panel.Add.lua +++ b/custom/Panel.Add.lua @@ -2,6 +2,7 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/Panel:Add +---@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T : Panel ---@overload fun(self: Panel, panelTable: table): Panel # Creates a panel from a PANEL table and parents it to this panel. ---@param object `T`|T The panel to add, or a panel class name to create and add. diff --git a/custom/Panel.GetSkin.lua b/custom/Panel.GetSkin.lua new file mode 100644 index 0000000..51aad8c --- /dev/null +++ b/custom/Panel.GetSkin.lua @@ -0,0 +1,6 @@ +---Returns the table for the derma skin currently being used by this panel object. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/Panel:GetSkin +---@return SKIN # The derma skin table currently being used by this object. +function Panel:GetSkin() end diff --git a/custom/Panel.SetSkin.lua b/custom/Panel.SetSkin.lua new file mode 100644 index 0000000..bc3a769 --- /dev/null +++ b/custom/Panel.SetSkin.lua @@ -0,0 +1,8 @@ +---Sets the derma skin that the panel object will use. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/Panel:SetSkin +---@callaction gmod.derma_skin kind=reference name_arg=1 +---@callaction gmod.derma_skin kind=reference name_arg=2 +---@param skinName string The name of the skin to use. The default derma skin is `Default`. +function Panel:SetSkin(skinName) end diff --git a/custom/concommand.Add.lua b/custom/concommand.Add.lua new file mode 100644 index 0000000..74d23ea --- /dev/null +++ b/custom/concommand.Add.lua @@ -0,0 +1,11 @@ +---Creates a console command that runs the supplied callback. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/concommand.Add +---@callaction gmod.system kind=concommand_add name_arg=1 callback_arg=2 +---@param name string Name of the console command. +---@param callback fun(ply: Player, cmd: string, args: string[], argStr: string) Callback run when the command is executed. +---@param autoComplete? function +---@param helpText? string +---@param flags? FCVAR|number[] +function concommand.Add(name, callback, autoComplete, helpText, flags) end diff --git a/custom/derma.DefineControl.lua b/custom/derma.DefineControl.lua new file mode 100644 index 0000000..3e2d655 --- /dev/null +++ b/custom/derma.DefineControl.lua @@ -0,0 +1,12 @@ +---Defines a new Derma control with an optional base. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.DefineControl +---@callaction gmod.class kind=derma_define_control class_arg=1 table_arg=3 base_arg=4 +---@generic T: Panel +---@param name string Name of the newly created control. +---@param description string Description of the control. +---@param tab T Table containing control methods and properties. +---@param base string Derma control to base the new control off of. +---@return T # A table containing the new control's methods and properties. +function derma.DefineControl(name, description, tab, base) end diff --git a/custom/derma.DefineSkin.lua b/custom/derma.DefineSkin.lua new file mode 100644 index 0000000..f14f50e --- /dev/null +++ b/custom/derma.DefineSkin.lua @@ -0,0 +1,9 @@ +---Defines a new skin so that it is usable by Derma. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.DefineSkin +---@callaction gmod.derma_skin kind=define_skin name_arg=1 table_arg=3 +---@param name string Name of the skin. +---@param description string Description of the skin. +---@param skin SKIN Table containing skin data. +function derma.DefineSkin(name, description, skin) end diff --git a/custom/derma.GetDefaultSkin.lua b/custom/derma.GetDefaultSkin.lua new file mode 100644 index 0000000..c6447d6 --- /dev/null +++ b/custom/derma.GetDefaultSkin.lua @@ -0,0 +1,6 @@ +---Returns the default skin table. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.GetDefaultSkin +---@return SKIN # The default skin table. +function derma.GetDefaultSkin() end diff --git a/custom/derma.GetNamedSkin.lua b/custom/derma.GetNamedSkin.lua new file mode 100644 index 0000000..4c06dd9 --- /dev/null +++ b/custom/derma.GetNamedSkin.lua @@ -0,0 +1,8 @@ +---Returns the skin table of the skin with the supplied name. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.GetNamedSkin +---@callaction gmod.derma_skin kind=reference name_arg=1 +---@param name string Name of skin. +---@return SKIN? # The skin table. +function derma.GetNamedSkin(name) end diff --git a/custom/derma.GetSkinTable.lua b/custom/derma.GetSkinTable.lua new file mode 100644 index 0000000..59b1e92 --- /dev/null +++ b/custom/derma.GetSkinTable.lua @@ -0,0 +1,6 @@ +---Returns a copy of the table containing every Derma skin. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.GetSkinTable +---@return table # Table of every Derma skin. +function derma.GetSkinTable() end diff --git a/custom/derma.SkinHook.lua b/custom/derma.SkinHook.lua new file mode 100644 index 0000000..65900f2 --- /dev/null +++ b/custom/derma.SkinHook.lua @@ -0,0 +1,10 @@ +---Checks if a matching hook function exists in the panel's skin, then calls it. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/derma.SkinHook +---@param type string The type of hook to run, usually `Paint`. +---@param name string The name of the hook or panel to run. Example: `Button`. +---@param panel Panel The panel to call the hook for. +---@param ... any Arguments forwarded to the skin hook. +---@return any # The returned variable from the skin hook. +function derma.SkinHook(type, name, panel, ...) end diff --git a/custom/hook.Add.lua b/custom/hook.Add.lua index 3843590..fdaed93 100644 --- a/custom/hook.Add.lua +++ b/custom/hook.Add.lua @@ -2,6 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/hook.Add +---@callaction gmod.hook kind=add name_arg=1 callback_arg=3 ---@param eventName string The event to hook on to. This can be any GM_Hooks hook, gameevent after using gameevent.Listen, or custom hook run with hook.Call or hook.Run. ---@param identifier any The unique identifier, usually a string. This can be used elsewhere in the code to replace or remove the hook. The identifier **should** be unique so that you do not accidentally override some other mods hook, unless that's what you are trying to do. ---@param func function The function to be called, arguments given to it depend on the identifier used. diff --git a/custom/hook.Call.lua b/custom/hook.Call.lua new file mode 100644 index 0000000..4496fbf --- /dev/null +++ b/custom/hook.Call.lua @@ -0,0 +1,10 @@ +---Calls a hook and returns the first non-nil value returned by hook listeners. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/hook.Call +---@callaction gmod.hook kind=emit name_arg=1 +---@param eventName string The hook event to call. +---@param gamemodeTable? table The gamemode table to call the hook on. +---@param ... any Arguments to pass to the hook. +---@return any +function hook.Call(eventName, gamemodeTable, ...) end diff --git a/custom/hook.Run.lua b/custom/hook.Run.lua new file mode 100644 index 0000000..26d34e6 --- /dev/null +++ b/custom/hook.Run.lua @@ -0,0 +1,9 @@ +---Calls a hook without explicitly passing a gamemode table. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/hook.Run +---@callaction gmod.hook kind=emit name_arg=1 +---@param eventName string The hook event to call. +---@param ... any Arguments to pass to the hook. +---@return any +function hook.Run(eventName, ...) end diff --git a/custom/net.Receive.lua b/custom/net.Receive.lua new file mode 100644 index 0000000..03baa4a --- /dev/null +++ b/custom/net.Receive.lua @@ -0,0 +1,7 @@ +---Registers a callback for a network message. +---@realm shared +---@source https://wiki.facepunch.com/gmod/net.Receive +---@callaction gmod.system kind=net_receive name_arg=1 callback_arg=2 +---@param messageName string The message name to hook to. +---@param callback fun(len: number, ply: Player) The function to be called if the specified message was received. +function net.Receive(messageName, callback) end diff --git a/custom/net.Start.lua b/custom/net.Start.lua new file mode 100644 index 0000000..95992a9 --- /dev/null +++ b/custom/net.Start.lua @@ -0,0 +1,8 @@ +---Begins a new net message. +---@realm shared +---@source https://wiki.facepunch.com/gmod/net.Start +---@callaction gmod.system kind=net_start name_arg=1 +---@param messageName string The name of the message to send. +---@param unreliable? boolean If set to `true`, the message is not guaranteed to reach its destination. +---@return boolean # `true` if the message has been started. +function net.Start(messageName, unreliable) end diff --git a/custom/timer.Create.lua b/custom/timer.Create.lua new file mode 100644 index 0000000..c08ba70 --- /dev/null +++ b/custom/timer.Create.lua @@ -0,0 +1,10 @@ +---Creates a new named timer. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/timer.Create +---@callaction gmod.system kind=timer_create name_arg=1 callback_arg=4 +---@param identifier string Identifier of the timer to create. +---@param delay number The delay interval in seconds. +---@param repetitions number The number of times to repeat the timer. Use `0` for infinite repetitions. +---@param func function Function called when timer has finished the countdown. +function timer.Create(identifier, delay, repetitions, func) end diff --git a/custom/timer.Simple.lua b/custom/timer.Simple.lua new file mode 100644 index 0000000..d759a71 --- /dev/null +++ b/custom/timer.Simple.lua @@ -0,0 +1,8 @@ +---Creates a simple one-shot timer. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/timer.Simple +---@callaction gmod.system kind=timer_simple callback_arg=2 +---@param delay number Delay in seconds. +---@param func function Function called when timer has finished the countdown. +function timer.Simple(delay, func) end diff --git a/custom/util.AddNetworkString.lua b/custom/util.AddNetworkString.lua new file mode 100644 index 0000000..21aa404 --- /dev/null +++ b/custom/util.AddNetworkString.lua @@ -0,0 +1,7 @@ +---Adds the specified string to the network string table. +---@realm server +---@source https://wiki.facepunch.com/gmod/util.AddNetworkString +---@callaction gmod.system kind=net_message_register name_arg=1 +---@param str string Adds the specified string to the string table. +---@return number # The id of the string that was added to the string table. +function util.AddNetworkString(str) end diff --git a/custom/vgui.Create.lua b/custom/vgui.Create.lua index 713d932..8bcb7e5 100644 --- a/custom/vgui.Create.lua +++ b/custom/vgui.Create.lua @@ -3,6 +3,7 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.Create +---@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T: Panel ---@param classname `T` Classname of the panel to create. --- diff --git a/custom/vgui.CreateX.lua b/custom/vgui.CreateX.lua index 3ee13ed..18e8ef3 100644 --- a/custom/vgui.CreateX.lua +++ b/custom/vgui.CreateX.lua @@ -3,6 +3,7 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.CreateX +---@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T : Panel ---@param class `T` Class of the panel to create ---@param parent? Panel If specified, parents created panel to given one diff --git a/custom/vgui.Register.lua b/custom/vgui.Register.lua new file mode 100644 index 0000000..cc64d56 --- /dev/null +++ b/custom/vgui.Register.lua @@ -0,0 +1,11 @@ +---Registers a panel for later creation via vgui.Create. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/vgui.Register +---@callaction gmod.class kind=vgui_register class_arg=1 table_arg=2 base_arg=3 +---@generic T: Panel +---@param classname string Classname of the panel to register. +---@param panelTable T The table containing the panel information. +---@param baseName? string Classname of a panel to inherit functionality from. +---@return T # The given panel table from second argument. +function vgui.Register(classname, panelTable, baseName) end From 6b46a60ff7c53115ea654ef455ec010187446162 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:01:16 +0100 Subject: [PATCH 02/19] Use generic call argument --- custom/Entity.NetworkVar.lua | 3 ++- custom/Entity.NetworkVarElement.lua | 3 ++- custom/Global.AccessorFunc.lua | 1 - custom/Global.Color.lua | 5 ++++- custom/Global.CreateClientConVar.lua | 2 +- custom/Global.CreateConVar.lua | 2 +- custom/Global.DEFINE_BASECLASS.lua | 2 +- custom/Global.DeriveGamemode.lua | 2 +- custom/Panel.Add.lua | 2 +- custom/Panel.SetSkin.lua | 3 +-- custom/concommand.Add.lua | 2 +- custom/derma.DefineControl.lua | 3 ++- custom/derma.DefineSkin.lua | 2 +- custom/derma.GetNamedSkin.lua | 2 +- custom/hook.Add.lua | 2 +- custom/hook.Call.lua | 2 +- custom/hook.Run.lua | 2 +- custom/net.Receive.lua | 2 +- custom/net.Start.lua | 2 +- custom/timer.Create.lua | 2 +- custom/timer.Simple.lua | 1 - custom/util.AddNetworkString.lua | 2 +- custom/vgui.Create.lua | 2 +- custom/vgui.CreateX.lua | 2 +- custom/vgui.Register.lua | 3 ++- 25 files changed, 30 insertions(+), 26 deletions(-) diff --git a/custom/Entity.NetworkVar.lua b/custom/Entity.NetworkVar.lua index 891fe3a..d64f920 100644 --- a/custom/Entity.NetworkVar.lua +++ b/custom/Entity.NetworkVar.lua @@ -1,9 +1,10 @@ ---Creates a network variable and generated Get/Set accessors for the entity. ---@realm shared ---@source https://wiki.facepunch.com/gmod/Entity:NetworkVar ----@callaction gmod.class kind=network_var type_arg=1 name_arg=3 fallback_name_arg=2 +---@[call_arg("gmod.network_var", "type")] ---@param type string The NetworkVar type. ---@param slot number The NetworkVar slot. +---@[call_arg("gmod.network_var", "define")] ---@param name string Name of the variable, used for generated Get/Set accessors. ---@param extended? table Extra NetworkVar information. function Entity:NetworkVar(type, slot, name, extended) end diff --git a/custom/Entity.NetworkVarElement.lua b/custom/Entity.NetworkVarElement.lua index 14b039b..1f65e29 100644 --- a/custom/Entity.NetworkVarElement.lua +++ b/custom/Entity.NetworkVarElement.lua @@ -1,10 +1,11 @@ ---Creates Get/Set accessors for a vector or angle element NetworkVar. ---@realm shared ---@source https://wiki.facepunch.com/gmod/Entity:NetworkVarElement ----@callaction gmod.class kind=network_var_element type_arg=1 name_arg=4 fallback_name_arg=3 fallback_name_arg2=2 +---@[call_arg("gmod.network_var", "type")] ---@param type string The NetworkVar type. ---@param slot number The NetworkVar slot. ---@param element number The vector or angle element. +---@[call_arg("gmod.network_var", "define")] ---@param name string Name of the variable, used for generated Get/Set accessors. ---@param extended? table Extra NetworkVar information. function Entity:NetworkVarElement(type, slot, element, name, extended) end diff --git a/custom/Global.AccessorFunc.lua b/custom/Global.AccessorFunc.lua index 18c4d38..3371b5d 100644 --- a/custom/Global.AccessorFunc.lua +++ b/custom/Global.AccessorFunc.lua @@ -4,7 +4,6 @@ ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.AccessorFunc ---@accessorfunc 2 ----@callaction gmod.class kind=accessor_func ---@param tab table The table to add the accessor functions to. ---@param key any The key of the table to be get/set. ---@param name string The name of the functions (will be prefixed with Get and Set). diff --git a/custom/Global.Color.lua b/custom/Global.Color.lua index 5b82b6d..b82b777 100644 --- a/custom/Global.Color.lua +++ b/custom/Global.Color.lua @@ -2,10 +2,13 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.Color ----@callaction gmod.color kind=rgba r_arg=1 g_arg=2 b_arg=3 a_arg=4 +---@[call_arg("gmod.color", "r")] ---@param r number The red channel, from 0 to 255. +---@[call_arg("gmod.color", "g")] ---@param g number The green channel, from 0 to 255. +---@[call_arg("gmod.color", "b")] ---@param b number The blue channel, from 0 to 255. +---@[call_arg("gmod.color", "a")] ---@param a? number The alpha channel, from 0 to 255. ---@return Color function _G.Color(r, g, b, a) end diff --git a/custom/Global.CreateClientConVar.lua b/custom/Global.CreateClientConVar.lua index 092ce65..f3b2a1f 100644 --- a/custom/Global.CreateClientConVar.lua +++ b/custom/Global.CreateClientConVar.lua @@ -1,7 +1,7 @@ ---Creates a client-side console variable. ---@realm client ---@source https://wiki.facepunch.com/gmod/Global.CreateClientConVar ----@callaction gmod.system kind=create_client_convar name_arg=1 +---@[call_arg("gmod.convar", "define")] ---@param name string ---@param default string|number ---@param shouldsave? boolean diff --git a/custom/Global.CreateConVar.lua b/custom/Global.CreateConVar.lua index 100e924..564a6c9 100644 --- a/custom/Global.CreateConVar.lua +++ b/custom/Global.CreateConVar.lua @@ -4,7 +4,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.CreateConVar ----@callaction gmod.system kind=create_convar name_arg=1 +---@[call_arg("gmod.convar", "define")] ---@param name string ---@param value string|number ---@param flags? FCVAR|number[] diff --git a/custom/Global.DEFINE_BASECLASS.lua b/custom/Global.DEFINE_BASECLASS.lua index 813e9f6..dc51d60 100644 --- a/custom/Global.DEFINE_BASECLASS.lua +++ b/custom/Global.DEFINE_BASECLASS.lua @@ -2,6 +2,6 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.DEFINE_BASECLASS ----@callaction gmod.class kind=define_baseclass base_arg=1 +---@[call_arg("gmod.class_base", "reference")] ---@param value string Base class name. function _G.DEFINE_BASECLASS(value) end diff --git a/custom/Global.DeriveGamemode.lua b/custom/Global.DeriveGamemode.lua index 13e53ff..d3fa3a5 100644 --- a/custom/Global.DeriveGamemode.lua +++ b/custom/Global.DeriveGamemode.lua @@ -1,6 +1,6 @@ ---Derives the current gamemode from another gamemode. ---@realm shared ---@source https://wiki.facepunch.com/gmod/Global.DeriveGamemode ----@callaction gmod.class kind=derive_gamemode base_arg=1 +---@[call_arg("gmod.gamemode", "reference")] ---@param base string Base gamemode folder name. function _G.DeriveGamemode(base) end diff --git a/custom/Panel.Add.lua b/custom/Panel.Add.lua index 7b8894d..d178c22 100644 --- a/custom/Panel.Add.lua +++ b/custom/Panel.Add.lua @@ -2,9 +2,9 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/Panel:Add ----@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T : Panel ---@overload fun(self: Panel, panelTable: table): Panel # Creates a panel from a PANEL table and parents it to this panel. +---@[call_arg("gmod.vgui_panel", "reference")] ---@param object `T`|T The panel to add, or a panel class name to create and add. ---@return (instance) T # The added or created panel function Panel:Add(object) end diff --git a/custom/Panel.SetSkin.lua b/custom/Panel.SetSkin.lua index bc3a769..e156c8b 100644 --- a/custom/Panel.SetSkin.lua +++ b/custom/Panel.SetSkin.lua @@ -2,7 +2,6 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/Panel:SetSkin ----@callaction gmod.derma_skin kind=reference name_arg=1 ----@callaction gmod.derma_skin kind=reference name_arg=2 +---@[call_arg("gmod.derma_skin", "reference")] ---@param skinName string The name of the skin to use. The default derma skin is `Default`. function Panel:SetSkin(skinName) end diff --git a/custom/concommand.Add.lua b/custom/concommand.Add.lua index 74d23ea..23d324c 100644 --- a/custom/concommand.Add.lua +++ b/custom/concommand.Add.lua @@ -2,7 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/concommand.Add ----@callaction gmod.system kind=concommand_add name_arg=1 callback_arg=2 +---@[call_arg("gmod.concommand", "define")] ---@param name string Name of the console command. ---@param callback fun(ply: Player, cmd: string, args: string[], argStr: string) Callback run when the command is executed. ---@param autoComplete? function diff --git a/custom/derma.DefineControl.lua b/custom/derma.DefineControl.lua index 3e2d655..09630ff 100644 --- a/custom/derma.DefineControl.lua +++ b/custom/derma.DefineControl.lua @@ -2,11 +2,12 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/derma.DefineControl ----@callaction gmod.class kind=derma_define_control class_arg=1 table_arg=3 base_arg=4 ---@generic T: Panel +---@[call_arg("gmod.vgui_panel", "define")] ---@param name string Name of the newly created control. ---@param description string Description of the control. ---@param tab T Table containing control methods and properties. +---@[call_arg("gmod.vgui_panel", "base")] ---@param base string Derma control to base the new control off of. ---@return T # A table containing the new control's methods and properties. function derma.DefineControl(name, description, tab, base) end diff --git a/custom/derma.DefineSkin.lua b/custom/derma.DefineSkin.lua index f14f50e..3fd35b3 100644 --- a/custom/derma.DefineSkin.lua +++ b/custom/derma.DefineSkin.lua @@ -2,7 +2,7 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/derma.DefineSkin ----@callaction gmod.derma_skin kind=define_skin name_arg=1 table_arg=3 +---@[call_arg("gmod.derma_skin", "define")] ---@param name string Name of the skin. ---@param description string Description of the skin. ---@param skin SKIN Table containing skin data. diff --git a/custom/derma.GetNamedSkin.lua b/custom/derma.GetNamedSkin.lua index 4c06dd9..c317eb6 100644 --- a/custom/derma.GetNamedSkin.lua +++ b/custom/derma.GetNamedSkin.lua @@ -2,7 +2,7 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/derma.GetNamedSkin ----@callaction gmod.derma_skin kind=reference name_arg=1 +---@[call_arg("gmod.derma_skin", "reference")] ---@param name string Name of skin. ---@return SKIN? # The skin table. function derma.GetNamedSkin(name) end diff --git a/custom/hook.Add.lua b/custom/hook.Add.lua index fdaed93..43d09b8 100644 --- a/custom/hook.Add.lua +++ b/custom/hook.Add.lua @@ -2,7 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/hook.Add ----@callaction gmod.hook kind=add name_arg=1 callback_arg=3 +---@[call_arg("gmod.hook", "add")] ---@param eventName string The event to hook on to. This can be any GM_Hooks hook, gameevent after using gameevent.Listen, or custom hook run with hook.Call or hook.Run. ---@param identifier any The unique identifier, usually a string. This can be used elsewhere in the code to replace or remove the hook. The identifier **should** be unique so that you do not accidentally override some other mods hook, unless that's what you are trying to do. ---@param func function The function to be called, arguments given to it depend on the identifier used. diff --git a/custom/hook.Call.lua b/custom/hook.Call.lua index 4496fbf..21feb95 100644 --- a/custom/hook.Call.lua +++ b/custom/hook.Call.lua @@ -2,7 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/hook.Call ----@callaction gmod.hook kind=emit name_arg=1 +---@[call_arg("gmod.hook", "emit")] ---@param eventName string The hook event to call. ---@param gamemodeTable? table The gamemode table to call the hook on. ---@param ... any Arguments to pass to the hook. diff --git a/custom/hook.Run.lua b/custom/hook.Run.lua index 26d34e6..c0e6c02 100644 --- a/custom/hook.Run.lua +++ b/custom/hook.Run.lua @@ -2,7 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/hook.Run ----@callaction gmod.hook kind=emit name_arg=1 +---@[call_arg("gmod.hook", "emit")] ---@param eventName string The hook event to call. ---@param ... any Arguments to pass to the hook. ---@return any diff --git a/custom/net.Receive.lua b/custom/net.Receive.lua index 03baa4a..226d13e 100644 --- a/custom/net.Receive.lua +++ b/custom/net.Receive.lua @@ -1,7 +1,7 @@ ---Registers a callback for a network message. ---@realm shared ---@source https://wiki.facepunch.com/gmod/net.Receive ----@callaction gmod.system kind=net_receive name_arg=1 callback_arg=2 +---@[call_arg("gmod.net_message", "receive")] ---@param messageName string The message name to hook to. ---@param callback fun(len: number, ply: Player) The function to be called if the specified message was received. function net.Receive(messageName, callback) end diff --git a/custom/net.Start.lua b/custom/net.Start.lua index 95992a9..1bc40b2 100644 --- a/custom/net.Start.lua +++ b/custom/net.Start.lua @@ -1,7 +1,7 @@ ---Begins a new net message. ---@realm shared ---@source https://wiki.facepunch.com/gmod/net.Start ----@callaction gmod.system kind=net_start name_arg=1 +---@[call_arg("gmod.net_message", "start")] ---@param messageName string The name of the message to send. ---@param unreliable? boolean If set to `true`, the message is not guaranteed to reach its destination. ---@return boolean # `true` if the message has been started. diff --git a/custom/timer.Create.lua b/custom/timer.Create.lua index c08ba70..35f45b6 100644 --- a/custom/timer.Create.lua +++ b/custom/timer.Create.lua @@ -2,7 +2,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/timer.Create ----@callaction gmod.system kind=timer_create name_arg=1 callback_arg=4 +---@[call_arg("gmod.timer", "define")] ---@param identifier string Identifier of the timer to create. ---@param delay number The delay interval in seconds. ---@param repetitions number The number of times to repeat the timer. Use `0` for infinite repetitions. diff --git a/custom/timer.Simple.lua b/custom/timer.Simple.lua index d759a71..1e5e03d 100644 --- a/custom/timer.Simple.lua +++ b/custom/timer.Simple.lua @@ -2,7 +2,6 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/timer.Simple ----@callaction gmod.system kind=timer_simple callback_arg=2 ---@param delay number Delay in seconds. ---@param func function Function called when timer has finished the countdown. function timer.Simple(delay, func) end diff --git a/custom/util.AddNetworkString.lua b/custom/util.AddNetworkString.lua index 21aa404..3523c77 100644 --- a/custom/util.AddNetworkString.lua +++ b/custom/util.AddNetworkString.lua @@ -1,7 +1,7 @@ ---Adds the specified string to the network string table. ---@realm server ---@source https://wiki.facepunch.com/gmod/util.AddNetworkString ----@callaction gmod.system kind=net_message_register name_arg=1 +---@[call_arg("gmod.net_message", "define")] ---@param str string Adds the specified string to the string table. ---@return number # The id of the string that was added to the string table. function util.AddNetworkString(str) end diff --git a/custom/vgui.Create.lua b/custom/vgui.Create.lua index 8bcb7e5..3f7d59a 100644 --- a/custom/vgui.Create.lua +++ b/custom/vgui.Create.lua @@ -3,8 +3,8 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.Create ----@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T: Panel +---@[call_arg("gmod.vgui_panel", "reference")] ---@param classname `T` Classname of the panel to create. --- --- Default panel classnames can be found on the VGUI Element List. diff --git a/custom/vgui.CreateX.lua b/custom/vgui.CreateX.lua index 18e8ef3..4cff4a8 100644 --- a/custom/vgui.CreateX.lua +++ b/custom/vgui.CreateX.lua @@ -3,8 +3,8 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.CreateX ----@callaction gmod.vgui_panel kind=reference name_arg=1 ---@generic T : Panel +---@[call_arg("gmod.vgui_panel", "reference")] ---@param class `T` Class of the panel to create ---@param parent? Panel If specified, parents created panel to given one ---@param name? string Name of the created panel diff --git a/custom/vgui.Register.lua b/custom/vgui.Register.lua index cc64d56..19d20b0 100644 --- a/custom/vgui.Register.lua +++ b/custom/vgui.Register.lua @@ -2,10 +2,11 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.Register ----@callaction gmod.class kind=vgui_register class_arg=1 table_arg=2 base_arg=3 ---@generic T: Panel +---@[call_arg("gmod.vgui_panel", "define")] ---@param classname string Classname of the panel to register. ---@param panelTable T The table containing the panel information. +---@[call_arg("gmod.vgui_panel", "base")] ---@param baseName? string Classname of a panel to inherit functionality from. ---@return T # The given panel table from second argument. function vgui.Register(classname, panelTable, baseName) end From 6e30871f5d189764d76ea7f8df434835370f0a09 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Sun, 7 Jun 2026 20:40:33 +0100 Subject: [PATCH 03/19] Annotate system call_arg --- custom/Global.CreateClientConVar.lua | 2 +- custom/Global.CreateConVar.lua | 2 +- custom/concommand.Add.lua | 1 + custom/timer.Create.lua | 1 + custom/timer.Simple.lua | 1 + 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/custom/Global.CreateClientConVar.lua b/custom/Global.CreateClientConVar.lua index f3b2a1f..9fc30df 100644 --- a/custom/Global.CreateClientConVar.lua +++ b/custom/Global.CreateClientConVar.lua @@ -1,7 +1,7 @@ ---Creates a client-side console variable. ---@realm client ---@source https://wiki.facepunch.com/gmod/Global.CreateClientConVar ----@[call_arg("gmod.convar", "define")] +---@[call_arg("gmod.convar", "define_client")] ---@param name string ---@param default string|number ---@param shouldsave? boolean diff --git a/custom/Global.CreateConVar.lua b/custom/Global.CreateConVar.lua index 564a6c9..5416bcc 100644 --- a/custom/Global.CreateConVar.lua +++ b/custom/Global.CreateConVar.lua @@ -4,7 +4,7 @@ ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/Global.CreateConVar ----@[call_arg("gmod.convar", "define")] +---@[call_arg("gmod.convar", "define_server")] ---@param name string ---@param value string|number ---@param flags? FCVAR|number[] diff --git a/custom/concommand.Add.lua b/custom/concommand.Add.lua index 23d324c..19b8169 100644 --- a/custom/concommand.Add.lua +++ b/custom/concommand.Add.lua @@ -4,6 +4,7 @@ ---@source https://wiki.facepunch.com/gmod/concommand.Add ---@[call_arg("gmod.concommand", "define")] ---@param name string Name of the console command. +---@[call_arg("gmod.concommand", "callback")] ---@param callback fun(ply: Player, cmd: string, args: string[], argStr: string) Callback run when the command is executed. ---@param autoComplete? function ---@param helpText? string diff --git a/custom/timer.Create.lua b/custom/timer.Create.lua index 35f45b6..4b3bfa0 100644 --- a/custom/timer.Create.lua +++ b/custom/timer.Create.lua @@ -6,5 +6,6 @@ ---@param identifier string Identifier of the timer to create. ---@param delay number The delay interval in seconds. ---@param repetitions number The number of times to repeat the timer. Use `0` for infinite repetitions. +---@[call_arg("gmod.timer", "callback")] ---@param func function Function called when timer has finished the countdown. function timer.Create(identifier, delay, repetitions, func) end diff --git a/custom/timer.Simple.lua b/custom/timer.Simple.lua index 1e5e03d..c265c14 100644 --- a/custom/timer.Simple.lua +++ b/custom/timer.Simple.lua @@ -3,5 +3,6 @@ ---@realm menu ---@source https://wiki.facepunch.com/gmod/timer.Simple ---@param delay number Delay in seconds. +---@[call_arg("gmod.timer", "simple")] ---@param func function Function called when timer has finished the countdown. function timer.Simple(delay, func) end From 30cf125c130ef30a975ffc81387b767057654c8c Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Sun, 7 Jun 2026 21:55:47 +0100 Subject: [PATCH 04/19] Annotate VGUI call_arg --- custom/derma.DefineControl.lua | 1 + custom/vgui.Register.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/custom/derma.DefineControl.lua b/custom/derma.DefineControl.lua index 09630ff..31ba5cd 100644 --- a/custom/derma.DefineControl.lua +++ b/custom/derma.DefineControl.lua @@ -6,6 +6,7 @@ ---@[call_arg("gmod.vgui_panel", "define")] ---@param name string Name of the newly created control. ---@param description string Description of the control. +---@[call_arg("gmod.vgui_panel", "table")] ---@param tab T Table containing control methods and properties. ---@[call_arg("gmod.vgui_panel", "base")] ---@param base string Derma control to base the new control off of. diff --git a/custom/vgui.Register.lua b/custom/vgui.Register.lua index 19d20b0..859b3f8 100644 --- a/custom/vgui.Register.lua +++ b/custom/vgui.Register.lua @@ -5,6 +5,7 @@ ---@generic T: Panel ---@[call_arg("gmod.vgui_panel", "define")] ---@param classname string Classname of the panel to register. +---@[call_arg("gmod.vgui_panel", "table")] ---@param panelTable T The table containing the panel information. ---@[call_arg("gmod.vgui_panel", "base")] ---@param baseName? string Classname of a panel to inherit functionality from. From bf9cadfecc29055d96620b913578183eef5d01d7 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Mon, 8 Jun 2026 04:24:37 +0100 Subject: [PATCH 05/19] Annotate Derma control and hook call_arg --- custom/derma.DefineControl.lua | 2 +- custom/hook.Call.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/custom/derma.DefineControl.lua b/custom/derma.DefineControl.lua index 31ba5cd..1660641 100644 --- a/custom/derma.DefineControl.lua +++ b/custom/derma.DefineControl.lua @@ -3,7 +3,7 @@ ---@realm menu ---@source https://wiki.facepunch.com/gmod/derma.DefineControl ---@generic T: Panel ----@[call_arg("gmod.vgui_panel", "define")] +---@[call_arg("gmod.vgui_panel", "define_control")] ---@param name string Name of the newly created control. ---@param description string Description of the control. ---@[call_arg("gmod.vgui_panel", "table")] diff --git a/custom/hook.Call.lua b/custom/hook.Call.lua index 21feb95..80a71a7 100644 --- a/custom/hook.Call.lua +++ b/custom/hook.Call.lua @@ -4,6 +4,7 @@ ---@source https://wiki.facepunch.com/gmod/hook.Call ---@[call_arg("gmod.hook", "emit")] ---@param eventName string The hook event to call. +---@[call_arg("gmod.hook", "gamemode_table")] ---@param gamemodeTable? table The gamemode table to call the hook on. ---@param ... any Arguments to pass to the hook. ---@return any From 9bb60475de352592dcafe543991f555e76e203a1 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Mon, 8 Jun 2026 05:33:32 +0100 Subject: [PATCH 06/19] Annotation NetworkVarElement call_arg --- custom/Entity.NetworkVarElement.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/Entity.NetworkVarElement.lua b/custom/Entity.NetworkVarElement.lua index 1f65e29..f4da8fd 100644 --- a/custom/Entity.NetworkVarElement.lua +++ b/custom/Entity.NetworkVarElement.lua @@ -5,7 +5,7 @@ ---@param type string The NetworkVar type. ---@param slot number The NetworkVar slot. ---@param element number The vector or angle element. ----@[call_arg("gmod.network_var", "define")] +---@[call_arg("gmod.network_var", "define_element")] ---@param name string Name of the variable, used for generated Get/Set accessors. ---@param extended? table Extra NetworkVar information. function Entity:NetworkVarElement(type, slot, element, name, extended) end From d3f14bcac007a00f0527caafa60ad21f50a3870a Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Mon, 8 Jun 2026 05:34:15 +0100 Subject: [PATCH 07/19] Stop zip stream after missing input --- src/utils/filesystem.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/utils/filesystem.ts b/src/utils/filesystem.ts index 889b34a..821db35 100644 --- a/src/utils/filesystem.ts +++ b/src/utils/filesystem.ts @@ -62,6 +62,13 @@ export async function zipFiles(outputFile: string, filePaths: string[], trimPath return new Promise(async (resolve, reject) => { const outputDirectory = path.dirname(outputFile); + for (const filePath of filePaths) { + if (!fs.existsSync(filePath)) { + reject(new Error(`File ${filePath} does not exist.`)); + return; + } + } + if (!fs.existsSync(outputDirectory)) fs.mkdirSync(outputDirectory, { recursive: true }); @@ -72,6 +79,10 @@ export async function zipFiles(outputFile: string, filePaths: string[], trimPath resolve(archive); }); + outputStream.on('error', function (err) { + reject(err); + }); + archive.on('error', function (err) { reject(err); }); @@ -79,9 +90,6 @@ export async function zipFiles(outputFile: string, filePaths: string[], trimPath archive.pipe(outputStream); for (const filePath of filePaths) { - if (!fs.existsSync(filePath)) - reject(new Error(`File ${filePath} does not exist.`)); - archive.file(filePath, { name: trimPath ? path.relative(trimPath, filePath) : filePath }); } From ed382e723b507087005042fa1f1be067edd44ed0 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:41:04 +0100 Subject: [PATCH 08/19] Annotate hook callbacks --- custom/hook.Add.lua | 1 + custom/hook.Remove.lua | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 custom/hook.Remove.lua diff --git a/custom/hook.Add.lua b/custom/hook.Add.lua index 43d09b8..9a38735 100644 --- a/custom/hook.Add.lua +++ b/custom/hook.Add.lua @@ -5,5 +5,6 @@ ---@[call_arg("gmod.hook", "add")] ---@param eventName string The event to hook on to. This can be any GM_Hooks hook, gameevent after using gameevent.Listen, or custom hook run with hook.Call or hook.Run. ---@param identifier any The unique identifier, usually a string. This can be used elsewhere in the code to replace or remove the hook. The identifier **should** be unique so that you do not accidentally override some other mods hook, unless that's what you are trying to do. +---@[call_arg("gmod.hook", "callback")] ---@param func function The function to be called, arguments given to it depend on the identifier used. function hook.Add(eventName, identifier, func) end diff --git a/custom/hook.Remove.lua b/custom/hook.Remove.lua new file mode 100644 index 0000000..c888d0f --- /dev/null +++ b/custom/hook.Remove.lua @@ -0,0 +1,8 @@ +---Removes a hook registered with hook.Add. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/hook.Remove +---@[call_arg("gmod.hook", "remove")] +---@param eventName string The hook event name to remove from. +---@param identifier any The unique identifier previously used with hook.Add. +function hook.Remove(eventName, identifier) end From d4db618a349cd938aff5f467a312b6f1211c7c51 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Mon, 8 Jun 2026 18:54:12 +0100 Subject: [PATCH 09/19] Update CI --- .github/workflows/release-gluals.yml | 281 ++++++++++++++++++++------- .github/workflows/release-test.yml | 72 ------- 2 files changed, 214 insertions(+), 139 deletions(-) delete mode 100644 .github/workflows/release-test.yml diff --git a/.github/workflows/release-gluals.yml b/.github/workflows/release-gluals.yml index e5bbabe..689d87c 100644 --- a/.github/workflows/release-gluals.yml +++ b/.github/workflows/release-gluals.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: "22" - - name: Decide what to publish + - name: Decide what to generate id: gate env: EVENT: ${{ github.event_name }} @@ -28,20 +28,21 @@ jobs: run: | set -e - # schedule + manual dispatch always publish everything (wiki content may have changed) + # Scheduled and manual runs need generation because upstream wiki content can change + # without any repository diff. Publishing is still gated later by output comparison. if [ "$EVENT" != "push" ]; then - echo "Reason: event=$EVENT -> publish all" - echo "should_run=true" >> "$GITHUB_OUTPUT" + echo "Reason: event=$EVENT -> generate and compare output" + echo "should_generate=true" >> "$GITHUB_OUTPUT" echo "publish_base=true" >> "$GITHUB_OUTPUT" echo "publish_all_plugins=true" >> "$GITHUB_OUTPUT" exit 0 fi - # push event -> diff against parent. Fail open (publish everything) if we can't. + # Push event -> diff against parent. Fail open (generate everything) if we can't. if [ -z "$BEFORE_SHA" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ] \ || ! git cat-file -e "$BEFORE_SHA" 2>/dev/null; then - echo "No usable base SHA (got '$BEFORE_SHA') -> publish all to be safe" - echo "should_run=true" >> "$GITHUB_OUTPUT" + echo "No usable base SHA (got '$BEFORE_SHA') -> generate all to be safe" + echo "should_generate=true" >> "$GITHUB_OUTPUT" echo "publish_base=true" >> "$GITHUB_OUTPUT" echo "publish_all_plugins=true" >> "$GITHUB_OUTPUT" exit 0 @@ -88,45 +89,36 @@ jobs: PLUGINS_TO_PUBLISH="$CHANGED_PLUGIN_IDS" fi - SHOULD_RUN=false + SHOULD_GENERATE=false if $PUBLISH_BASE || $PUBLISH_ALL_PLUGINS || [ -n "$PLUGINS_TO_PUBLISH" ]; then - SHOULD_RUN=true + SHOULD_GENERATE=true fi - echo "should_run=$SHOULD_RUN" >> "$GITHUB_OUTPUT" + echo "should_generate=$SHOULD_GENERATE" >> "$GITHUB_OUTPUT" echo "publish_base=$PUBLISH_BASE" >> "$GITHUB_OUTPUT" echo "publish_all_plugins=$PUBLISH_ALL_PLUGINS" >> "$GITHUB_OUTPUT" echo "plugins_to_publish=$PLUGINS_TO_PUBLISH" >> "$GITHUB_OUTPUT" { - echo "## release-gluals gate" + echo "## release-gluals generation gate" echo "- event: \`$EVENT\`" - echo "- should_run: \`$SHOULD_RUN\`" + echo "- should_generate: \`$SHOULD_GENERATE\`" echo "- publish_base: \`$PUBLISH_BASE\`" echo "- publish_all_plugins: \`$PUBLISH_ALL_PLUGINS\`" echo "- plugins_to_publish: \`${PLUGINS_TO_PUBLISH:-}\`" } >> "$GITHUB_STEP_SUMMARY" - name: Install dependencies - if: steps.gate.outputs.should_run == 'true' + if: steps.gate.outputs.should_generate == 'true' run: npm ci - name: Set build timestamp id: build_ts - if: steps.gate.outputs.should_run == 'true' + if: steps.gate.outputs.should_generate == 'true' run: echo "value=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT" - name: Scrape wiki - if: steps.gate.outputs.should_run == 'true' + if: steps.gate.outputs.should_generate == 'true' run: npm run scrape-wiki - - name: Stamp metadata with build timestamp - if: steps.gate.outputs.should_run == 'true' - run: | - node -e " - const fs = require('fs'); - const meta = JSON.parse(fs.readFileSync('output/__metadata.json', 'utf8')); - meta.lastUpdate = '${{ steps.build_ts.outputs.value }}'; - fs.writeFileSync('output/__metadata.json', JSON.stringify(meta, null, 2)); - " - name: Regenerate Lua + plugin artifacts metadata - if: steps.gate.outputs.should_run == 'true' + if: steps.gate.outputs.should_generate == 'true' run: | npm run generate-lua -- \ --output ./output \ @@ -142,41 +134,28 @@ jobs: --artifactManifest plugin.json \ --version "${{ steps.build_ts.outputs.value }}" \ --generatedAt "${{ steps.build_ts.outputs.value }}" - - name: Run tests - if: steps.gate.outputs.should_run == 'true' - run: npm test - name: Format the output with StyLua - if: steps.gate.outputs.should_run == 'true' + if: steps.gate.outputs.should_generate == 'true' uses: JohnnyMorganz/stylua-action@v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} version: latest args: --no-editorconfig output/ - - name: Tag latest scrape revision - if: steps.gate.outputs.should_run == 'true' - run: | - build_tag=$(echo "${{ steps.build_ts.outputs.value }}" | sed 's/:/-/g' | sed 's/T/_/' | sed 's/Z//') - tag="$build_tag" - if git rev-parse -q --verify "refs/tags/$tag" >/dev/null 2>&1; then - echo "Tag $tag already exists. Falling back to build run number." - tag="${build_tag}-${GITHUB_RUN_NUMBER}" - fi - git tag "$tag" - git push origin "refs/tags/$tag" - - name: Publish annotations to branch - if: steps.gate.outputs.should_run == 'true' + - name: Prepare release payloads + id: payloads + if: steps.gate.outputs.should_generate == 'true' env: PUBLISH_BASE: ${{ steps.gate.outputs.publish_base }} PUBLISH_ALL_PLUGINS: ${{ steps.gate.outputs.publish_all_plugins }} PLUGINS_TO_PUBLISH: ${{ steps.gate.outputs.plugins_to_publish }} run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" + set -e tmpdir=$(mktemp -d) base_dir="$tmpdir/base" plugin_stage_dir="$tmpdir/plugins" - mkdir -p "$base_dir/plugin" "$plugin_stage_dir" + compare_dir="$tmpdir/compare" + mkdir -p "$base_dir/plugin" "$plugin_stage_dir" "$compare_dir" # Stage base annotation branch payload (core lua + metadata + plugin index only). find output/ -maxdepth 1 -type f -name '*.lua' -exec cp {} "$base_dir/" \; @@ -186,6 +165,188 @@ jobs: cp -R output-plugins/. "$plugin_stage_dir/" fi + normalize_payload() { + local source_dir="$1" + local target_dir="$2" + + mkdir -p "$target_dir" + cp -R "$source_dir/." "$target_dir/" + + node - "$target_dir" <<'NODE' + const fs = require('fs'); + const path = require('path'); + + const root = process.argv[2]; + const rewriteJson = (relativePath, rewrite) => { + const filePath = path.join(root, relativePath); + if (!fs.existsSync(filePath)) return; + const json = JSON.parse(fs.readFileSync(filePath, 'utf8')); + rewrite(json); + fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`, 'utf8'); + }; + + rewriteJson('__metadata.json', (json) => { + json.lastUpdate = '__normalized__'; + }); + + rewriteJson(path.join('plugin', 'index.json'), (json) => { + delete json.generatedAt; + if (Array.isArray(json.plugins)) { + for (const plugin of json.plugins) { + if (plugin.artifact) delete plugin.artifact.version; + } + } + }); + NODE + } + + branch_has_changes() { + local branch_name="$1" + local source_dir="$2" + local existing_dir="$compare_dir/existing-$branch_name" + local normalized_existing="$compare_dir/existing-normalized-$branch_name" + local normalized_source="$compare_dir/source-normalized-$branch_name" + + rm -rf "$existing_dir" "$normalized_existing" "$normalized_source" + mkdir -p "$existing_dir" + + set +e + git ls-remote --exit-code --heads origin "$branch_name" >/dev/null 2>&1 + remote_status=$? + set -e + + if [ "$remote_status" -eq 2 ]; then + echo "Branch '$branch_name' does not exist yet." + return 0 + fi + + if [ "$remote_status" -ne 0 ]; then + echo "Unable to check remote branch '$branch_name'." + exit "$remote_status" + fi + + git fetch --depth=1 origin "refs/heads/$branch_name" >/dev/null + git archive "FETCH_HEAD" | tar -x -C "$existing_dir" + + normalize_payload "$existing_dir" "$normalized_existing" + normalize_payload "$source_dir" "$normalized_source" + + if diff -qr "$normalized_existing" "$normalized_source" >/dev/null; then + return 1 + fi + + return 0 + } + + should_publish_plugin() { + local plugin_id="$1" + + if [ "$PUBLISH_ALL_PLUGINS" = "true" ]; then + return 0 + fi + + for pid in $PLUGINS_TO_PUBLISH; do + if [ "$pid" = "$plugin_id" ]; then + return 0 + fi + done + + return 1 + } + + changed_base=false + changed_plugins="" + + if [ "$PUBLISH_BASE" = "true" ]; then + if branch_has_changes "gluals-annotations" "$base_dir"; then + changed_base=true + else + echo "Base annotations payload matches gluals-annotations." + fi + else + echo "Skipping base annotations comparison (no relevant source changes)." + fi + + for plugin_dir in "$plugin_stage_dir"/*; do + [ -d "$plugin_dir" ] || continue + plugin_id="$(basename "$plugin_dir")" + + if ! should_publish_plugin "$plugin_id"; then + echo "Skipping plugin '$plugin_id' comparison (no related source changes)." + continue + fi + + plugin_branch="gluals-annotations-plugin-${plugin_id}" + if branch_has_changes "$plugin_branch" "$plugin_dir"; then + changed_plugins="$changed_plugins $plugin_id" + else + echo "Plugin '$plugin_id' payload matches $plugin_branch." + fi + done + + changed_plugins=$(echo "$changed_plugins" | xargs || true) + if [ -n "$changed_plugins" ] && [ "$PUBLISH_BASE" = "true" ] && [ "$changed_base" != "true" ]; then + echo "Plugin payload changed; publishing base index so artifact versions stay current." + changed_base=true + fi + + should_publish=false + if [ "$changed_base" = "true" ] || [ -n "$changed_plugins" ]; then + should_publish=true + fi + + echo "tmpdir=$tmpdir" >> "$GITHUB_OUTPUT" + echo "base_dir=$base_dir" >> "$GITHUB_OUTPUT" + echo "plugin_stage_dir=$plugin_stage_dir" >> "$GITHUB_OUTPUT" + echo "should_publish=$should_publish" >> "$GITHUB_OUTPUT" + echo "changed_base=$changed_base" >> "$GITHUB_OUTPUT" + echo "changed_plugins=$changed_plugins" >> "$GITHUB_OUTPUT" + + { + echo "## release-gluals output comparison" + echo "- should_publish: \`$should_publish\`" + echo "- changed_base: \`$changed_base\`" + echo "- changed_plugins: \`${changed_plugins:-}\`" + } >> "$GITHUB_STEP_SUMMARY" + - name: Stop when generated output is unchanged + if: steps.gate.outputs.should_generate == 'true' && steps.payloads.outputs.should_publish != 'true' + run: echo "Generated output matches published branches. Nothing to release." + - name: Run tests + if: steps.payloads.outputs.should_publish == 'true' + run: npm test + - name: Stamp metadata with build timestamp + if: steps.payloads.outputs.should_publish == 'true' + run: | + node -e " + const fs = require('fs'); + const meta = JSON.parse(fs.readFileSync('${{ steps.payloads.outputs.base_dir }}/__metadata.json', 'utf8')); + meta.lastUpdate = '${{ steps.build_ts.outputs.value }}'; + fs.writeFileSync('${{ steps.payloads.outputs.base_dir }}/__metadata.json', JSON.stringify(meta, null, 2) + '\n'); + " + - name: Tag latest scrape revision + if: steps.payloads.outputs.should_publish == 'true' + run: | + build_tag=$(echo "${{ steps.build_ts.outputs.value }}" | sed 's/:/-/g' | sed 's/T/_/' | sed 's/Z//') + tag="$build_tag" + if git rev-parse -q --verify "refs/tags/$tag" >/dev/null 2>&1; then + echo "Tag $tag already exists. Falling back to build run number." + tag="${build_tag}-${GITHUB_RUN_NUMBER}" + fi + git tag "$tag" + git push origin "refs/tags/$tag" + - name: Publish annotations to branch + if: steps.payloads.outputs.should_publish == 'true' + env: + BASE_DIR: ${{ steps.payloads.outputs.base_dir }} + PLUGIN_STAGE_DIR: ${{ steps.payloads.outputs.plugin_stage_dir }} + CHANGED_BASE: ${{ steps.payloads.outputs.changed_base }} + CHANGED_PLUGINS: ${{ steps.payloads.outputs.changed_plugins }} + run: | + set -e + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + publish_branch() { local branch_name="$1" local source_dir="$2" @@ -203,31 +364,17 @@ jobs: now="$(date -u +%Y-%m-%dT%H:%M:%SZ)" - if [ "$PUBLISH_BASE" = "true" ]; then - publish_branch "gluals-annotations" "$base_dir" "Update GLuaLS annotations - $now" + if [ "$CHANGED_BASE" = "true" ]; then + publish_branch "gluals-annotations" "$BASE_DIR" "Update GLuaLS annotations - $now" else - echo "Skipping base annotations branch (no relevant changes)." + echo "Skipping base annotations branch (generated output unchanged)." fi - for plugin_dir in "$plugin_stage_dir"/*; do - [ -d "$plugin_dir" ] || continue - plugin_id="$(basename "$plugin_dir")" - - should_publish=false - if [ "$PUBLISH_ALL_PLUGINS" = "true" ]; then - should_publish=true - else - for pid in $PLUGINS_TO_PUBLISH; do - if [ "$pid" = "$plugin_id" ]; then - should_publish=true - break - fi - done - fi - - if [ "$should_publish" != "true" ]; then - echo "Skipping plugin '$plugin_id' (no related changes)." - continue + for plugin_id in $CHANGED_PLUGINS; do + plugin_dir="$PLUGIN_STAGE_DIR/$plugin_id" + if [ ! -d "$plugin_dir" ]; then + echo "Expected plugin payload directory missing: $plugin_dir" + exit 1 fi plugin_branch="gluals-annotations-plugin-${plugin_id}" diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml deleted file mode 100644 index ee35c7e..0000000 --- a/.github/workflows/release-test.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: release-test -on: - workflow_dispatch: - push: - branches: - #- main - - test-plugin - # Only trigger on changes that actually impact our final output - paths: - - 'src/**' - - 'custom/**' - - '__tests__/**' - - 'package.json' - - 'package-lock.json' - - 'yarn.lock' - - 'jest.config.ts' - - 'tsconfig.json' - -jobs: - release: - permissions: write-all - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-node@v4 - with: - node-version: "22" - - - name: Install dependencies - run: npm ci - - - name: Scrape wiki - run: npm run scrape-wiki - - name: Run tests - run: npm test - - name: Format the output with StyLua - uses: JohnnyMorganz/stylua-action@v2.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: latest - args: --no-editorconfig output/ - - name: Publish annotations to test branch - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Stash only the final .lua files + metadata to a temp dir before switching branches. - # This is necessary because `git rm -rf .` only removes tracked files; output/ is - # gitignored (untracked) so it survives, causing duplicates when git add -A picks it up. - tmpdir=$(mktemp -d) - find output/ -maxdepth 1 -type f -name '*.lua' -exec cp {} "$tmpdir/" \; - cp output/__metadata.json "$tmpdir/" - - # Create orphan branch, then wipe EVERYTHING (tracked + untracked + ignored) - branchName="gluals-annotations-test" - git checkout --orphan "$branchName" - git rm -rf . - git clean -fdx - - # Restore only the final annotation files - cp "$tmpdir/"*.lua . - cp "$tmpdir/__metadata.json" . - git add -A - - # Commit with timestamp and branch reference - commitMsg="Update GLuaLS annotations (test) - $(date -u +%Y-%m-%dT%H:%M:%SZ) - from ${{ github.ref_name }}" - git commit -m "$commitMsg" - - # Force push to publish - git push -f origin "$branchName" From 548ea4dd264f56a6fbfb284172c0d9e9781760c0 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:49:00 +0100 Subject: [PATCH 10/19] Restore override and support call_arg on override --- custom/Entity.NetworkVar.lua | 3 +++ custom/Entity.NetworkVarElement.lua | 5 ++++- custom/Panel.Add.lua | 7 ++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/custom/Entity.NetworkVar.lua b/custom/Entity.NetworkVar.lua index d64f920..cc386a2 100644 --- a/custom/Entity.NetworkVar.lua +++ b/custom/Entity.NetworkVar.lua @@ -1,6 +1,9 @@ ---Creates a network variable and generated Get/Set accessors for the entity. ---@realm shared ---@source https://wiki.facepunch.com/gmod/Entity:NetworkVar +---@[overload_call_arg(0, "gmod.network_var", "type")] +---@[overload_call_arg(1, "gmod.network_var", "define")] +---@overload fun(type: string, name: string, extended?: table) ---@[call_arg("gmod.network_var", "type")] ---@param type string The NetworkVar type. ---@param slot number The NetworkVar slot. diff --git a/custom/Entity.NetworkVarElement.lua b/custom/Entity.NetworkVarElement.lua index f4da8fd..5ec1707 100644 --- a/custom/Entity.NetworkVarElement.lua +++ b/custom/Entity.NetworkVarElement.lua @@ -1,10 +1,13 @@ ---Creates Get/Set accessors for a vector or angle element NetworkVar. ---@realm shared ---@source https://wiki.facepunch.com/gmod/Entity:NetworkVarElement +---@[overload_call_arg(0, "gmod.network_var", "type")] +---@[overload_call_arg(2, "gmod.network_var", "define_element")] +---@overload fun(type: string, element: string, name: string, extended?: table) ---@[call_arg("gmod.network_var", "type")] ---@param type string The NetworkVar type. ---@param slot number The NetworkVar slot. ----@param element number The vector or angle element. +---@param element string The vector or angle element. ---@[call_arg("gmod.network_var", "define_element")] ---@param name string Name of the variable, used for generated Get/Set accessors. ---@param extended? table Extra NetworkVar information. diff --git a/custom/Panel.Add.lua b/custom/Panel.Add.lua index d178c22..d6ecac3 100644 --- a/custom/Panel.Add.lua +++ b/custom/Panel.Add.lua @@ -3,8 +3,9 @@ ---@realm menu ---@source https://wiki.facepunch.com/gmod/Panel:Add ---@generic T : Panel +---@overload fun(self: Panel, panel: Panel): Panel # Parents an existing panel to this panel. ---@overload fun(self: Panel, panelTable: table): Panel # Creates a panel from a PANEL table and parents it to this panel. ---@[call_arg("gmod.vgui_panel", "reference")] ----@param object `T`|T The panel to add, or a panel class name to create and add. ----@return (instance) T # The added or created panel -function Panel:Add(object) end +---@param className `T` The panel class name to create and add. +---@return (instance) T # The created panel. +function Panel:Add(className) end From 47b46579383295f1cde3e2a3fc50d56620842c12 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Wed, 10 Jun 2026 06:11:14 +0100 Subject: [PATCH 11/19] Fix annotation generation not including custom by default --- __tests__/cli-generate-lua.spec.ts | 130 ++++++++++++++++++++++++++++- package.json | 2 +- src/cli-generate-lua.ts | 9 +- 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/__tests__/cli-generate-lua.spec.ts b/__tests__/cli-generate-lua.spec.ts index 9a87f68..c3501b3 100644 --- a/__tests__/cli-generate-lua.spec.ts +++ b/__tests__/cli-generate-lua.spec.ts @@ -19,7 +19,7 @@ describe('cli-generate-lua', () => { try { const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const result = spawnSync( - `${command} run generate-lua -- --output "${outputPath}" --customOverrides ./custom`, + `${command} run generate-lua -- --output "${outputPath}" --custom-overrides ./custom`, [], { cwd: process.cwd(), @@ -69,7 +69,7 @@ describe('cli-generate-lua', () => { try { const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const result = spawnSync( - `${command} run generate-lua -- --output "${outputPath}" --customOverrides ./custom`, + `${command} run generate-lua -- --output "${outputPath}" --custom-overrides ./custom`, [], { cwd: process.cwd(), @@ -94,4 +94,130 @@ describe('cli-generate-lua', () => { fs.rmSync(tmpRoot, { recursive: true, force: true }); } }); + + test('applies custom overrides by default when --custom-overrides is not specified', () => { + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gluals-generate-lua-defaults-')); + const outputPath = path.join(tmpRoot, 'output'); + const vectorDir = path.join(outputPath, 'vector'); + + fs.mkdirSync(vectorDir, { recursive: true }); + fs.writeFileSync( + path.join(vectorDir, 'pages.json'), + JSON.stringify([ + { + type: 'class', + address: 'Vector', + name: 'Vector', + description: 'A 3D vector.', + realm: 'shared', + url: 'https://wiki.facepunch.com/gmod/Vector', + parent: '', + }, + ], null, 2), + 'utf8', + ); + + try { + const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; + const result = spawnSync( + `${command} run generate-lua -- --output "${outputPath}"`, + [], + { + cwd: process.cwd(), + encoding: 'utf8', + shell: true, + }, + ); + + expect(result.status).toBe(0); + const vectorLua = fs.readFileSync(path.join(outputPath, 'vector.lua'), 'utf8'); + // These lines come from custom/class.Vector.lua overrides + expect(vectorLua).toContain('---@field x number'); + expect(vectorLua).toContain('---@field y number'); + expect(vectorLua).toContain('---@field z number'); + expect(vectorLua).toContain('---@operator add(Vector): Vector'); + } finally { + fs.rmSync(tmpRoot, { recursive: true, force: true }); + } + }); + + test('--raw-wiki skips applying custom overrides', () => { + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gluals-generate-lua-rawwiki-')); + const outputPath = path.join(tmpRoot, 'output'); + const vectorDir = path.join(outputPath, 'vector'); + + fs.mkdirSync(vectorDir, { recursive: true }); + fs.writeFileSync( + path.join(vectorDir, 'pages.json'), + JSON.stringify([ + { + type: 'class', + address: 'Vector', + name: 'Vector', + description: 'A 3D vector.', + realm: 'shared', + url: 'https://wiki.facepunch.com/gmod/Vector', + parent: '', + }, + ], null, 2), + 'utf8', + ); + + try { + const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; + const result = spawnSync( + `${command} run generate-lua -- --output "${outputPath}" --raw-wiki`, + [], + { + cwd: process.cwd(), + encoding: 'utf8', + shell: true, + }, + ); + + expect(result.status).toBe(0); + const vectorLua = fs.readFileSync(path.join(outputPath, 'vector.lua'), 'utf8'); + // With --raw-wiki, custom overrides are skipped so @field/@operator from custom/class.Vector.lua should NOT appear + expect(vectorLua).not.toContain('---@field x number'); + expect(vectorLua).not.toContain('---@operator add(Vector): Vector'); + } finally { + fs.rmSync(tmpRoot, { recursive: true, force: true }); + } + }); + + test('--no-wipe-lua preserves existing Lua files', () => { + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gluals-generate-lua-nowipe-')); + const outputPath = path.join(tmpRoot, 'output'); + const vectorDir = path.join(outputPath, 'vector'); + + fs.mkdirSync(vectorDir, { recursive: true }); + fs.writeFileSync( + path.join(vectorDir, 'pages.json'), + JSON.stringify([], null, 2), + 'utf8', + ); + + // Write a sentinel file that should survive when wipe is disabled + const sentinelFile = path.join(outputPath, 'sentinel.lua'); + fs.writeFileSync(sentinelFile, '-- sentinel', 'utf8'); + + try { + const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; + const result = spawnSync( + `${command} run generate-lua -- --output "${outputPath}" --no-wipe-lua --raw-wiki`, + [], + { + cwd: process.cwd(), + encoding: 'utf8', + shell: true, + }, + ); + + expect(result.status).toBe(0); + expect(fs.existsSync(sentinelFile)).toBe(true); + expect(fs.readFileSync(sentinelFile, 'utf8')).toBe('-- sentinel'); + } finally { + fs.rmSync(tmpRoot, { recursive: true, force: true }); + } + }); }); diff --git a/package.json b/package.json index e11cc86..b14eb37 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "wiki-check-changed": "tsx ./src/cli-change-checker.ts", "scrape-wiki": "tsx ./src/cli-scraper.ts --output ./output/ --customOverrides ./custom/ --wipe && npm run generate-all", "generate-lua": "tsx ./src/cli-generate-lua.ts", - "generate-all": "npm run generate-lua -- --output ./output --customOverrides ./custom --wipeLua && npm run generate-plugin-index && npm run generate-plugin-artifacts", + "generate-all": "npm run generate-lua -- --output ./output --custom-overrides ./custom && npm run generate-plugin-index && npm run generate-plugin-artifacts", "generate-plugin-index": "tsx ./src/cli-generate-plugin-index.ts --pluginRoot ./plugin --output ./plugin/index.json", "generate-plugin-artifacts": "tsx ./src/cli-generate-plugin-artifacts.ts --pluginRoot ./plugin --indexOutput ./plugin/index.json --annotationsOutput ./output --pluginBundlesOutput ./output-plugins", "pack-release": "tsx ./src/cli-release-packer.ts --input ./output/ --output ./dist/release/", diff --git a/src/cli-generate-lua.ts b/src/cli-generate-lua.ts index 2eb4eed..a61a78b 100644 --- a/src/cli-generate-lua.ts +++ b/src/cli-generate-lua.ts @@ -53,13 +53,14 @@ async function main() { program .description('Regenerate Lua annotations from existing JSON pages (no wiki scrape)') .option('-o, --output ', 'Output directory containing wiki JSON and Lua files', './output') - .option('-c, --customOverrides [path]', 'Custom override directory') - .option('--wipeLua', 'Delete existing top-level Lua files before regenerating', true) + .option('-c, --custom-overrides ', 'Custom override directory', './custom') + .option('--no-wipe-lua', 'Skip deleting existing top-level Lua files before regenerating') + .option('--raw-wiki', 'Skip applying custom overrides (use raw wiki data only)') .parse(process.argv); const options = program.opts(); const outputDirectory = options.output.replace(/\/$/, ''); - const customDirectory = options.customOverrides?.replace(/\/$/, ''); + const customDirectory = options.customOverrides.replace(/\/$/, ''); if (!fs.existsSync(outputDirectory)) { throw new Error(`Output directory does not exist: ${outputDirectory}`); @@ -71,7 +72,7 @@ async function main() { wipeLuaFiles(outputDirectory); } - if (customDirectory) { + if (!options.rawWiki) { if (!fs.existsSync(customDirectory)) { throw new Error(`Custom overrides directory does not exist: ${customDirectory}`); } From d8e0b9b189ccd007ac4d00585f1715703f594e38 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Thu, 11 Jun 2026 06:21:42 +0100 Subject: [PATCH 12/19] Fix debug.getmetatable annotation --- __tests__/cli-generate-lua.spec.ts | 70 ++++++++++++++++++++++++++++++ custom/debug.getmetatable.lua | 9 ++-- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/__tests__/cli-generate-lua.spec.ts b/__tests__/cli-generate-lua.spec.ts index c3501b3..6bb289c 100644 --- a/__tests__/cli-generate-lua.spec.ts +++ b/__tests__/cli-generate-lua.spec.ts @@ -36,6 +36,76 @@ describe('cli-generate-lua', () => { } }); + test('uses runtime-generic debug.getmetatable annotation override', () => { + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gluals-generate-lua-debug-getmetatable-')); + const outputPath = path.join(tmpRoot, 'output'); + const customOverridesPath = path.join(tmpRoot, 'custom'); + const debugDir = path.join(outputPath, 'debug'); + + fs.mkdirSync(debugDir, { recursive: true }); + fs.mkdirSync(customOverridesPath, { recursive: true }); + + fs.copyFileSync( + path.join(process.cwd(), 'custom', 'debug.getmetatable.lua'), + path.join(customOverridesPath, 'debug.getmetatable.lua'), + ); + + const pagesPath = path.join(debugDir, 'getmetatable.json'); + fs.writeFileSync( + pagesPath, + JSON.stringify([ + { + type: 'libraryfunc', + parent: 'debug', + name: 'getmetatable', + address: 'debug.getmetatable', + description: 'Returns the metatable of the specified value.', + realm: 'shared', + url: 'https://wiki.facepunch.com/gmod/debug.getmetatable', + arguments: [ + { + args: [ + { + name: 'object', + type: 'any', + }, + ], + }, + ], + returns: [ + { + type: 'any', + }, + ], + }, + ], null, 2), + 'utf8', + ); + + try { + const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'; + const result = spawnSync( + `${command} run generate-lua -- --output "${outputPath}" --custom-overrides "${customOverridesPath}"`, + [], + { + cwd: process.cwd(), + encoding: 'utf8', + shell: true, + }, + ); + + expect(result.status).toBe(0); + const debugLua = fs.readFileSync(path.join(outputPath, 'debug.lua'), 'utf8'); + expect(debugLua).toContain('---@generic T'); + expect(debugLua).toContain('---@param object T The value to get the metatable of.'); + expect(debugLua).toContain('---@return (definition) T # The metatable of the value.'); + expect(debugLua).not.toContain('`T`'); + expect(debugLua).not.toContain('---@generic T : table'); + } finally { + fs.rmSync(tmpRoot, { recursive: true, force: true }); + } + }); + test('applies typed Entity networked getter overrides', () => { const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gluals-generate-lua-')); const outputPath = path.join(tmpRoot, 'output'); diff --git a/custom/debug.getmetatable.lua b/custom/debug.getmetatable.lua index f10834e..aefd2b3 100644 --- a/custom/debug.getmetatable.lua +++ b/custom/debug.getmetatable.lua @@ -1,8 +1,9 @@ ----Returns the metatable of the specified value. Can return any value. +---Returns the metatable of an object. This function ignores the metatable's __metatable field. +---@deprecated ---@realm shared ---@realm menu ---@source https://wiki.facepunch.com/gmod/debug.getmetatable ----@generic T : table ----@param object `T` The value to get the metatable of. ----@return (definition) `T` # The metatable of the value. +---@generic T +---@param object T The value to get the metatable of. +---@return (definition) T # The metatable of the value. function debug.getmetatable(object) end From 3eb045bd1145a08b962247728d20e931876544a9 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 01:09:00 +0100 Subject: [PATCH 13/19] Add error annotation --- custom/Global.error(lowercase).lua | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 custom/Global.error(lowercase).lua diff --git a/custom/Global.error(lowercase).lua b/custom/Global.error(lowercase).lua new file mode 100644 index 0000000..64d54b0 --- /dev/null +++ b/custom/Global.error(lowercase).lua @@ -0,0 +1,8 @@ +---Throws a Lua error and breaks out of the current call stack. +---@realm shared +---@realm menu +---@source https://wiki.facepunch.com/gmod/Global.error(lowercase) +---@param message string # The error message to throw. +---@param errorLevel? number # The level to throw the error at. +---@return never +function _G.error(message, errorLevel) end From d7a0cf5aa8ade612805178abdadb8ffc0e09ef0c Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:03:17 +0100 Subject: [PATCH 14/19] Add IsHostingGame menu annotation --- custom/Global.IsHostingGame.lua | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 custom/Global.IsHostingGame.lua diff --git a/custom/Global.IsHostingGame.lua b/custom/Global.IsHostingGame.lua new file mode 100644 index 0000000..16decdb --- /dev/null +++ b/custom/Global.IsHostingGame.lua @@ -0,0 +1,4 @@ +---Returns true when the current menu session is hosting a local game. +---@realm menu +---@return boolean #True if the local client is hosting the active game session. +function _G.IsHostingGame() end From 16e86a9f8a69073dcc328e56af338137102d2098 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:18:09 +0100 Subject: [PATCH 15/19] Fix PropertyAdd optional fields --- custom/PropertyAdd.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 custom/PropertyAdd.lua diff --git a/custom/PropertyAdd.lua b/custom/PropertyAdd.lua new file mode 100644 index 0000000..ebe48fa --- /dev/null +++ b/custom/PropertyAdd.lua @@ -0,0 +1,16 @@ +---Structure used for [properties.Add](https://wiki.facepunch.com/gmod/properties.Add). +---@realm shared +---@source https://wiki.facepunch.com/gmod/Structures/PropertyAdd +---@class (partial) PropertyAdd +---@field Type? string|"simple"|"toggle" Can be set to "toggle" to make this property a toggle property. +---@field MenuLabel string Label to show on opened menu. +---@field MenuIcon? string Icon to show on opened menu for this item. Optional for simple properties and unused for toggle properties. +---@field Order number Where in the list this property should be positioned, relative to other properties. +---@field PrependSpacer? boolean Whether to add a spacer before this property. +---@field Filter fun(self: table, ent: Entity, player: Player):(check: boolean) Used clientside to decide whether this property should be shown for an entity. +---@field Checked? fun(self: table, ent: Entity, tr: table):(check: boolean) Required only for toggle properties. +---@field Action fun(self: table, ent: Entity, tr: table) Called clientside when the property is clicked. +---@field Receive? fun(self: table, len: number, ply: Player) Called serverside if the client sends a message in the Action function. +---@field MenuOpen? fun(self: table, option: DMenuOption, ent: Entity, tr: table) Called clientside when the property option has been created in the right-click menu. +---@field OnCreate? fun(self: table, menu: DMenu, option: DMenuOption) Called clientside after the property option has been created. +local PropertyAdd = {} From 5c5e83c2f757eee878f46a027bcd2a40f643da60 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:22:44 +0100 Subject: [PATCH 16/19] Fix scripted entity registration table type --- custom/scripted_ents.Register.lua | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 custom/scripted_ents.Register.lua diff --git a/custom/scripted_ents.Register.lua b/custom/scripted_ents.Register.lua new file mode 100644 index 0000000..4951dca --- /dev/null +++ b/custom/scripted_ents.Register.lua @@ -0,0 +1,8 @@ +---Registers an ENT table with a classname. Reregistering an existing classname will automatically update the functions of all existing entities of that class. +--- +---The input is a registration table. Garry's Mod fills and inherits fields such as `ClassName`, `BaseClass`, and base-provided `Type` later during scripted entity registration and lookup. +---@realm shared +---@source https://wiki.facepunch.com/gmod/scripted_ents.Register +---@param ENT table The ENT table to register. +---@param classname string The classname to register. +function scripted_ents.Register(ENT, classname) end From 39cad47d8b4f5159c791437034176d1b4b72a5e8 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:27:48 +0100 Subject: [PATCH 17/19] Fix VideoData optional lockfps --- custom/VideoData.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 custom/VideoData.lua diff --git a/custom/VideoData.lua b/custom/VideoData.lua new file mode 100644 index 0000000..00fe4b0 --- /dev/null +++ b/custom/VideoData.lua @@ -0,0 +1,16 @@ +---Table structure used by [video.Record](https://wiki.facepunch.com/gmod/video.Record). +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/Structures/VideoData +---@class (partial) VideoData +---@field container string The video container format. +---@field video string The video codec. +---@field audio string The audio codec. +---@field quality number The video quality. +---@field bitrate number The record bitrate. +---@field fps number Frames per second. +---@field lockfps? boolean Lock the frame count per second. +---@field name string The file name for the video. +---@field width number The video's width. +---@field height number The video's height. +local VideoData = {} From dbcb8c68366c22c76d681cfe561c86018f15bd2e Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:42:31 +0100 Subject: [PATCH 18/19] Add vgui.RegisterTable call metadata --- custom/vgui.RegisterTable.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 custom/vgui.RegisterTable.lua diff --git a/custom/vgui.RegisterTable.lua b/custom/vgui.RegisterTable.lua new file mode 100644 index 0000000..a053cc2 --- /dev/null +++ b/custom/vgui.RegisterTable.lua @@ -0,0 +1,13 @@ +---Registers a table to use as a panel, to be used with [vgui.CreateFromTable](https://wiki.facepunch.com/gmod/vgui.CreateFromTable). +--- +--- All this function does is assigns Base key to your table and returns the table. +---@realm client +---@realm menu +---@source https://wiki.facepunch.com/gmod/vgui.RegisterTable +---@generic T: table +---@[call_arg("gmod.vgui_panel", "register_table")] +---@param panel T The PANEL table. +---@[call_arg("gmod.vgui_panel", "base")] +---@param base? string A base for the panel. +---@return T # The PANEL table +function vgui.RegisterTable(panel, base) end From 4417a3731c145a1b14cdf1bde099ff3bc85a3235 Mon Sep 17 00:00:00 2001 From: Pollux <39353174+Pollux12@users.noreply.github.com> Date: Fri, 12 Jun 2026 04:18:39 +0100 Subject: [PATCH 19/19] Add vgui.CreateFromTable call metadata --- custom/vgui.CreateFromTable.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/custom/vgui.CreateFromTable.lua b/custom/vgui.CreateFromTable.lua index 1ff486e..ecfa400 100644 --- a/custom/vgui.CreateFromTable.lua +++ b/custom/vgui.CreateFromTable.lua @@ -2,7 +2,10 @@ ---@realm client ---@realm menu ---@source https://wiki.facepunch.com/gmod/vgui.CreateFromTable ----@param metatable table Your PANEL table. +---@generic T: table +---@[call_arg("gmod.vgui_panel", "register_table")] +---@[call_arg_field("gmod.vgui_panel", "base", "Base")] +---@param metatable T Your PANEL table. ---@param parent? Panel Which panel to parent the newly created panel to. ---@param name? string Custom name of the created panel for scripting/debugging purposes. Can be retrieved with Panel:GetName. ---@return (instance) Panel # The created panel, or `nil` if creation failed for whatever reason.