2013-09-09 16:28:02 -04:00
-- main.lua
-- Implements the plugin entrypoint (in this case the entire plugin)
2013-07-30 10:02:20 -04:00
2013-07-30 11:26:06 -04:00
2013-09-11 10:57:57 -04:00
-- Global variables:
g_Plugin = nil ;
2013-10-09 04:24:24 -04:00
g_PluginFolder = " " ;
2013-10-18 06:30:06 -04:00
g_TrackedPages = { } ; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
2013-09-11 10:57:57 -04:00
2013-07-30 11:26:06 -04:00
2013-07-30 10:02:20 -04:00
function Initialize ( Plugin )
2013-09-11 10:57:57 -04:00
g_Plugin = Plugin ;
2013-09-12 12:46:37 -04:00
Plugin : SetName ( " APIDump " ) ;
Plugin : SetVersion ( 1 ) ;
2013-07-30 10:02:20 -04:00
2013-10-16 02:04:06 -04:00
LOG ( " Initialised " .. Plugin : GetName ( ) .. " v. " .. Plugin : GetVersion ( ) )
2013-10-09 04:24:24 -04:00
g_PluginFolder = Plugin : GetLocalFolder ( ) ;
2013-07-30 10:02:20 -04:00
-- dump all available API functions and objects:
2013-09-10 16:02:18 -04:00
-- DumpAPITxt();
2013-09-09 16:28:02 -04:00
2013-09-10 16:02:18 -04:00
-- Dump all available API object in HTML format into a subfolder:
DumpAPIHtml ( ) ;
2013-09-11 10:57:57 -04:00
2013-07-30 10:02:20 -04:00
return true
end
2013-07-30 11:26:06 -04:00
2013-09-10 16:02:18 -04:00
function DumpAPITxt ( )
2013-07-30 10:02:20 -04:00
LOG ( " Dumping all available functions to API.txt... " ) ;
function dump ( prefix , a , Output )
for i , v in pairs ( a ) do
if ( type ( v ) == " table " ) then
if ( GetChar ( i , 1 ) ~= " . " ) then
if ( v == _G ) then
2013-09-09 16:28:02 -04:00
-- LOG(prefix .. i .. " == _G, CYCLE, ignoring");
2013-07-30 10:02:20 -04:00
elseif ( v == _G.package ) then
2013-09-09 16:28:02 -04:00
-- LOG(prefix .. i .. " == _G.package, ignoring");
2013-07-30 10:02:20 -04:00
else
dump ( prefix .. i .. " . " , v , Output )
end
end
elseif ( type ( v ) == " function " ) then
if ( string.sub ( i , 1 , 2 ) ~= " __ " ) then
table.insert ( Output , prefix .. i .. " () " ) ;
end
end
end
end
local Output = { } ;
dump ( " " , _G , Output ) ;
table.sort ( Output ) ;
local f = io.open ( " API.txt " , " w " ) ;
for i , n in ipairs ( Output ) do
f : write ( n , " \n " ) ;
end
f : close ( ) ;
LOG ( " API.txt written. " ) ;
end
2013-09-09 16:28:02 -04:00
2013-09-10 16:02:18 -04:00
function CreateAPITables ( )
2013-09-09 16:28:02 -04:00
--[[
We want an API table of the following shape :
local API = {
2013-09-11 10:57:57 -04:00
{
Name = " cCuboid " ,
2013-09-09 16:28:02 -04:00
Functions = {
2013-09-11 10:57:57 -04:00
{ Name = " Sort " } ,
{ Name = " IsInside " }
2013-09-09 16:28:02 -04:00
} ,
Constants = {
}
2013-09-13 04:51:01 -04:00
Descendants = { } , -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree)
2013-09-09 16:28:02 -04:00
} } ,
2013-09-11 10:57:57 -04:00
{
Name = " cBlockArea " ,
2013-09-09 16:28:02 -04:00
Functions = {
2013-09-11 10:57:57 -04:00
{ Name = " Clear " } ,
{ Name = " CopyFrom " } ,
2013-09-09 16:28:02 -04:00
...
}
Constants = {
2013-09-11 10:57:57 -04:00
{ Name = " baTypes " , Value = 0 } ,
{ Name = " baMetas " , Value = 1 } ,
2013-09-09 16:28:02 -04:00
...
}
...
} }
} ;
local Globals = {
Functions = {
...
} ,
Constants = {
...
}
} ;
--]]
2013-09-13 04:51:01 -04:00
local Globals = { Functions = { } , Constants = { } , Descendants = { } } ;
2013-09-09 16:28:02 -04:00
local API = { } ;
2013-09-13 08:05:18 -04:00
local function Add ( a_APIContainer , a_ObjName , a_ObjValue )
if ( type ( a_ObjValue ) == " function " ) then
table.insert ( a_APIContainer.Functions , { Name = a_ObjName } ) ;
2013-09-13 04:51:01 -04:00
elseif (
2013-09-13 08:05:18 -04:00
( type ( a_ObjValue ) == " number " ) or
( type ( a_ObjValue ) == " string " )
2013-09-13 04:51:01 -04:00
) then
2013-09-13 08:05:18 -04:00
table.insert ( a_APIContainer.Constants , { Name = a_ObjName , Value = a_ObjValue } ) ;
2013-09-09 16:28:02 -04:00
end
end
2013-09-11 10:57:57 -04:00
local function ParseClass ( a_ClassName , a_ClassObj )
2013-09-13 04:51:01 -04:00
local res = { Name = a_ClassName , Functions = { } , Constants = { } , Descendants = { } } ;
2013-09-09 16:28:02 -04:00
for i , v in pairs ( a_ClassObj ) do
Add ( res , i , v ) ;
end
return res ;
end
for i , v in pairs ( _G ) do
2013-09-13 10:38:39 -04:00
if (
( v ~= _G ) and -- don't want the global namespace
( v ~= _G.packages ) and -- don't want any packages
2013-09-14 10:27:12 -04:00
( v ~= _G [ " .get " ] ) and
( v ~= g_APIDesc )
2013-09-13 10:38:39 -04:00
) then
if ( type ( v ) == " table " ) then
table.insert ( API , ParseClass ( i , v ) ) ;
else
Add ( Globals , i , v ) ;
end
2013-09-09 16:28:02 -04:00
end
end
2013-09-10 16:02:18 -04:00
return API , Globals ;
end
function DumpAPIHtml ( )
LOG ( " Dumping all available functions and constants to API subfolder... " ) ;
local API , Globals = CreateAPITables ( ) ;
2013-10-09 09:10:25 -04:00
local Hooks = { } ;
local UndocumentedHooks = { } ;
2013-09-14 10:20:54 -04:00
-- Sort the classes by name:
table.sort ( API ,
function ( c1 , c2 )
return ( string.lower ( c1.Name ) < string.lower ( c2.Name ) ) ;
end
) ;
-- Add Globals into the API:
2013-09-11 10:57:57 -04:00
Globals.Name = " Globals " ;
table.insert ( API , Globals ) ;
2013-10-09 09:10:25 -04:00
-- Extract hook constants:
for name , obj in pairs ( cPluginManager ) do
2013-10-14 15:57:23 -04:00
if (
( type ( obj ) == " number " ) and
name : match ( " HOOK_.* " ) and
( name ~= " HOOK_MAX " ) and
( name ~= " HOOK_NUM_HOOKS " )
) then
2013-10-09 09:10:25 -04:00
table.insert ( Hooks , { Name = name } ) ;
end
end
table.sort ( Hooks ,
function ( Hook1 , Hook2 )
return ( Hook1.Name < Hook2.Name ) ;
end
) ;
2013-09-11 10:57:57 -04:00
-- Read in the descriptions:
ReadDescriptions ( API ) ;
2013-10-09 09:10:25 -04:00
ReadHooks ( Hooks ) ;
2013-09-09 16:28:02 -04:00
2013-10-09 04:02:07 -04:00
-- Create the output folder
if not ( cFile : IsFolder ( " API " ) ) then
cFile : CreateFolder ( " API " ) ;
end
2013-09-10 16:02:18 -04:00
-- Create a "class index" file, write each class as a link to that file,
-- then dump class contents into class-specific file
local f = io.open ( " API/index.html " , " w " ) ;
2013-09-11 15:21:51 -04:00
if ( f == nil ) then
2013-10-09 04:02:07 -04:00
LOGINFO ( " Cannot output HTML API: " .. err ) ;
return ;
2013-09-11 15:21:51 -04:00
end
2013-10-16 02:04:06 -04:00
f : write ( [ [ < ! DOCTYPE html >
< html >
< head >
< title > MCServer API - Index </ title >
< link rel = " stylesheet " type = " text/css " href = " main.css " />
</ head >
< body >
< div id = " content " >
< header >
< h1 > MCServer API - Index </ h1 >
< hr />
</ header >
< p > The API reference is divided into the following sections : </ p >
< ul >
< li >< a href = " #classes " > Class index </ a ></ li >
< li >< a href = " #hooks " > Hooks </ a ></ li >
< li >< a href = " #extra " > Extra pages </ a ></ li >
</ ul >
< hr />
< a name = " classes " >< h2 > Class index </ h2 ></ a >
< p > The following classes are available in the MCServer Lua scripting language : </ p >
< ul >
] ] ) ;
2013-09-11 10:57:57 -04:00
for i , cls in ipairs ( API ) do
2013-10-16 02:04:06 -04:00
f : write ( " <li><a href= \" " .. cls.Name .. " .html \" > " .. cls.Name .. " </a></li> \n " ) ;
2013-09-13 04:22:04 -04:00
WriteHtmlClass ( cls , API ) ;
2013-09-09 16:28:02 -04:00
end
2013-10-16 02:04:06 -04:00
f : write ( [ [ </ ul >
< hr />
< a name = " hooks " >< h2 > Hooks </ h2 ></ a >
< p > A plugin can register to be called whenever an " interesting event " occurs . It does so by calling < a href = " cPluginManager.html " > cPluginManager </ a > ' s AddHook() function and implementing a callback function to handle the event.</p>
< p > A plugin can decide whether it will let the event pass through to the rest of the plugins , or hide it from them . This is determined by the return value from the hook callback function . If the function returns false or no value , the event is propagated further . If the function returns true , the processing is stopped , no other plugin receives the notification ( and possibly MCServer disables the default behavior for the event ) . See each hook ' s details to see the exact behavior.</p>
< table >
< tr >
< th > Hook name </ th >
< th > Called when </ th >
</ tr >
] ] ) ;
2013-10-09 09:10:25 -04:00
for i , hook in ipairs ( Hooks ) do
if ( hook.DefaultFnName == nil ) then
-- The hook is not documented yet
2013-10-16 02:04:06 -04:00
f : write ( " <tr> \n <td> " .. hook.Name .. " </td> \n <td><i>(No documentation yet)</i></td> \n </tr> \n " ) ;
2013-10-09 09:10:25 -04:00
table.insert ( UndocumentedHooks , hook.Name ) ;
else
2013-10-18 06:30:06 -04:00
f : write ( " <tr> \n <td><a href= \" " .. hook.DefaultFnName .. " .html \" > " .. hook.Name .. " </a></td> \n <td> " .. LinkifyString ( hook.CalledWhen , hook.Name ) .. " </td> \n </tr> \n " ) ;
2013-10-09 09:10:25 -04:00
WriteHtmlHook ( hook ) ;
end
end
2013-10-16 02:04:06 -04:00
f : write ( [ [ </ table >
< hr />
< a name = " extra " >< h2 > Extra pages </ h2 ></ a >
< p > The following pages provide various extra information </ p >
< ul >
] ] ) ;
2013-10-09 04:24:24 -04:00
for i , extra in ipairs ( g_APIDesc.ExtraPages ) do
2013-10-09 09:56:24 -04:00
local SrcFileName = g_PluginFolder .. " / " .. extra.FileName ;
if ( cFile : Exists ( SrcFileName ) ) then
local DstFileName = " API/ " .. extra.FileName ;
if ( cFile : Exists ( DstFileName ) ) then
cFile : Delete ( DstFileName ) ;
end
cFile : Copy ( SrcFileName , DstFileName ) ;
2013-10-16 02:04:06 -04:00
f : write ( " <li><a href= \" " .. extra.FileName .. " \" > " .. extra.Title .. " </a></li> \n " ) ;
2013-10-09 04:24:24 -04:00
else
2013-10-16 02:04:06 -04:00
f : write ( " <li> " .. extra.Title .. " <i>(file is missing)</i></li> \n " ) ;
2013-10-09 04:24:24 -04:00
end
end
2013-10-16 02:04:06 -04:00
f : write ( [ [ </ ul >
</ div >
</ body >
</ html > ] ] ) ;
2013-09-09 16:28:02 -04:00
f : close ( ) ;
2013-09-11 15:21:51 -04:00
2013-10-18 15:02:43 -04:00
-- Copy the static files to the output folder (overwrite any existing):
cFile : Copy ( g_Plugin : GetLocalFolder ( ) .. " /main.css " , " API/main.css " ) ;
cFile : Copy ( g_Plugin : GetLocalFolder ( ) .. " /prettify.js " , " API/prettify.js " ) ;
cFile : Copy ( g_Plugin : GetLocalFolder ( ) .. " /prettify.css " , " API/prettify.css " ) ;
2013-10-18 14:21:26 -04:00
cFile : Copy ( g_Plugin : GetLocalFolder ( ) .. " /lang-lua.js " , " API/lang-lua.js " ) ;
2013-10-18 14:32:36 -04:00
-- List the documentation problems:
ListUndocumentedObjects ( API , UndocumentedHooks ) ;
ListUnexportedObjects ( ) ;
2013-10-18 06:30:06 -04:00
ListMissingPages ( ) ;
2013-09-11 15:21:51 -04:00
LOG ( " API subfolder written " ) ;
2013-09-10 16:02:18 -04:00
end
2013-09-11 10:57:57 -04:00
function ReadDescriptions ( a_API )
2013-09-28 18:10:42 -04:00
-- Returns true if the class of the specified name is to be ignored
local function IsClassIgnored ( a_ClsName )
if ( g_APIDesc.IgnoreClasses == nil ) then
return false ;
end
for i , name in ipairs ( g_APIDesc.IgnoreClasses ) do
if ( a_ClsName : match ( name ) ) then
return true ;
end
end
return false ;
end
2013-09-13 08:05:18 -04:00
-- Returns true if the function (specified by its fully qualified name) is to be ignored
local function IsFunctionIgnored ( a_FnName )
2013-09-14 16:15:58 -04:00
if ( g_APIDesc.IgnoreFunctions == nil ) then
return false ;
end
2013-09-13 08:05:18 -04:00
for i , name in ipairs ( g_APIDesc.IgnoreFunctions ) do
if ( a_FnName : match ( name ) ) then
return true ;
end
end
return false ;
end
2013-09-14 16:15:58 -04:00
-- Returns true if the constant (specified by its fully qualified name) is to be ignored
local function IsConstantIgnored ( a_CnName )
if ( g_APIDesc.IgnoreConstants == nil ) then
return false ;
end ;
for i , name in ipairs ( g_APIDesc.IgnoreConstants ) do
if ( a_CnName : match ( name ) ) then
return true ;
end
end
return false ;
end
2013-09-28 18:10:42 -04:00
-- Remove ignored classes from a_API:
local APICopy = { } ;
for i , cls in ipairs ( a_API ) do
if not ( IsClassIgnored ( cls.Name ) ) then
table.insert ( APICopy , cls ) ;
end
end
for i = 1 , # a_API do
a_API [ i ] = APICopy [ i ] ;
end ;
-- Process the documentation for each class:
2013-09-11 10:57:57 -04:00
for i , cls in ipairs ( a_API ) do
2013-09-14 02:38:39 -04:00
-- Rename special functions:
for j , fn in ipairs ( cls.Functions ) do
if ( fn.Name == " .call " ) then
fn.DocID = " constructor " ;
fn.Name = " () <i>(constructor)</i> " ;
elseif ( fn.Name == " .add " ) then
fn.DocID = " operator_plus " ;
fn.Name = " <i>operator +</i> " ;
elseif ( fn.Name == " .div " ) then
fn.DocID = " operator_div " ;
fn.Name = " <i>operator /</i> " ;
elseif ( fn.Name == " .mul " ) then
fn.DocID = " operator_mul " ;
fn.Name = " <i>operator *</i> " ;
elseif ( fn.Name == " .sub " ) then
fn.DocID = " operator_sub " ;
fn.Name = " <i>operator -</i> " ;
2013-09-30 14:45:13 -04:00
elseif ( fn.Name == " .eq " ) then
2013-10-02 02:49:15 -04:00
fn.DocID = " operator_eq " ;
2013-09-30 14:45:13 -04:00
fn.Name = " <i>operator ==</i> " ;
2013-09-14 02:38:39 -04:00
end
end
2013-09-11 10:57:57 -04:00
local APIDesc = g_APIDesc.Classes [ cls.Name ] ;
if ( APIDesc ~= nil ) then
2013-09-14 16:34:19 -04:00
APIDesc.IsExported = true ;
2013-09-11 10:57:57 -04:00
cls.Desc = APIDesc.Desc ;
2013-09-14 11:28:22 -04:00
cls.AdditionalInfo = APIDesc.AdditionalInfo ;
2013-09-13 04:51:01 -04:00
-- Process inheritance:
if ( APIDesc.Inherits ~= nil ) then
for j , icls in ipairs ( a_API ) do
if ( icls.Name == APIDesc.Inherits ) then
table.insert ( icls.Descendants , cls ) ;
cls.Inherits = icls ;
end
end
end
2013-09-14 10:52:15 -04:00
2013-09-14 16:15:58 -04:00
cls.UndocumentedFunctions = { } ; -- This will contain names of all the functions that are not documented
cls.UndocumentedConstants = { } ; -- This will contain names of all the constants that are not documented
2013-09-14 10:52:15 -04:00
local DoxyFunctions = { } ; -- This will contain all the API functions together with their documentation
local function AddFunction ( a_Name , a_Params , a_Return , a_Notes )
table.insert ( DoxyFunctions , { Name = a_Name , Params = a_Params , Return = a_Return , Notes = a_Notes } ) ;
end
2013-09-11 10:57:57 -04:00
if ( APIDesc.Functions ~= nil ) then
-- Assign function descriptions:
for j , func in ipairs ( cls.Functions ) do
2013-09-14 02:38:39 -04:00
local FnName = func.DocID or func.Name ;
2013-09-13 10:04:32 -04:00
local FnDesc = APIDesc.Functions [ FnName ] ;
2013-09-14 10:52:15 -04:00
if ( FnDesc == nil ) then
-- No description for this API function
AddFunction ( func.Name ) ;
2013-09-14 16:15:58 -04:00
if not ( IsFunctionIgnored ( cls.Name .. " . " .. FnName ) ) then
table.insert ( cls.UndocumentedFunctions , FnName ) ;
end
2013-09-14 10:52:15 -04:00
else
-- Description is available
if ( FnDesc [ 1 ] == nil ) then
-- Single function definition
AddFunction ( func.Name , FnDesc.Params , FnDesc.Return , FnDesc.Notes ) ;
else
-- Multiple function overloads
for k , desc in ipairs ( FnDesc ) do
AddFunction ( func.Name , desc.Params , desc.Return , desc.Notes ) ;
end -- for k, desc - FnDesc[]
end
2013-09-11 10:57:57 -04:00
FnDesc.IsExported = true ;
end
end -- for j, func
2013-09-14 10:52:15 -04:00
-- Replace functions with their described and overload-expanded versions:
cls.Functions = DoxyFunctions ;
2013-09-11 10:57:57 -04:00
end -- if (APIDesc.Functions ~= nil)
if ( APIDesc.Constants ~= nil ) then
-- Assign constant descriptions:
for j , cons in ipairs ( cls.Constants ) do
local CnDesc = APIDesc.Constants [ cons.Name ] ;
2013-09-14 10:52:15 -04:00
if ( CnDesc == nil ) then
-- Not documented
2013-09-14 16:15:58 -04:00
if not ( IsConstantIgnored ( cls.Name .. " . " .. cons.Name ) ) then
table.insert ( cls.UndocumentedConstants , cons.Name ) ;
end
2013-09-14 10:52:15 -04:00
else
2013-09-11 10:57:57 -04:00
cons.Notes = CnDesc.Notes ;
CnDesc.IsExported = true ;
end
end -- for j, cons
end -- if (APIDesc.Constants ~= nil)
2013-10-18 15:29:38 -04:00
-- Process member variables:
local vars = { } ;
for name , desc in pairs ( APIDesc.Variables or { } ) do
desc.Name = name ;
table.insert ( vars , desc ) ;
end
cls.Variables = vars ;
else -- if (APIDesc ~= nil)
2013-09-14 17:47:37 -04:00
-- Class is not documented at all, add all its members to Undocumented lists:
cls.UndocumentedFunctions = { } ;
cls.UndocumentedConstants = { } ;
2013-10-18 15:29:38 -04:00
cls.Variables = { } ;
2013-09-14 17:47:37 -04:00
for j , func in ipairs ( cls.Functions ) do
local FnName = func.DocID or func.Name ;
if not ( IsFunctionIgnored ( cls.Name .. " . " .. FnName ) ) then
table.insert ( cls.UndocumentedFunctions , FnName ) ;
end
end -- for j, func - cls.Functions[]
for j , cons in ipairs ( cls.Constants ) do
if not ( IsConstantIgnored ( cls.Name .. " . " .. cons.Name ) ) then
table.insert ( cls.UndocumentedConstants , cons.Name ) ;
end
end -- for j, cons - cls.Constants[]
end -- else if (APIDesc ~= nil)
2013-09-14 02:27:31 -04:00
-- Remove ignored functions:
local NewFunctions = { } ;
for j , fn in ipairs ( cls.Functions ) do
if ( not ( IsFunctionIgnored ( cls.Name .. " . " .. fn.Name ) ) ) then
table.insert ( NewFunctions , fn ) ;
end
end -- for j, fn
cls.Functions = NewFunctions ;
2013-09-14 10:20:54 -04:00
-- Sort the functions (they may have been renamed):
table.sort ( cls.Functions ,
function ( f1 , f2 )
2013-09-14 10:52:15 -04:00
if ( f1.Name == f2.Name ) then
-- Same name, either comparing the same function to itself, or two overloads, in which case compare the params
if ( ( f1.Params == nil ) or ( f2.Params == nil ) ) then
return 0 ;
end
return ( f1.Params < f2.Params ) ;
end
2013-09-14 10:20:54 -04:00
return ( f1.Name < f2.Name ) ;
end
) ;
-- Sort the constants:
table.sort ( cls.Constants ,
function ( c1 , c2 )
return ( c1.Name < c2.Name ) ;
end
) ;
2013-10-18 15:29:38 -04:00
-- Sort the member variables:
table.sort ( cls.Variables ,
function ( v1 , v2 )
return ( v1.Name < v2.Name ) ;
end
) ;
2013-09-13 04:51:01 -04:00
end -- for i, cls
2013-09-13 08:05:18 -04:00
2013-09-13 04:51:01 -04:00
-- Sort the descendants lists:
for i , cls in ipairs ( a_API ) do
table.sort ( cls.Descendants ,
function ( c1 , c2 )
return ( c1.Name < c2.Name ) ;
end
) ;
end -- for i, cls
2013-09-11 10:57:57 -04:00
end
2013-10-09 09:10:25 -04:00
function ReadHooks ( a_Hooks )
--[[
a_Hooks = {
{ Name = " HOOK_1 " } ,
{ Name = " HOOK_2 " } ,
...
} ;
We want to add hook descriptions to each hook in this array
--]]
for i , hook in ipairs ( a_Hooks ) do
local HookDesc = g_APIDesc.Hooks [ hook.Name ] ;
if ( HookDesc ~= nil ) then
for key , val in pairs ( HookDesc ) do
hook [ key ] = val ;
end
end
end -- for i, hook - a_Hooks[]
end
-- Make a link out of anything with the special linkifying syntax {{link|title}}
2013-10-18 06:30:06 -04:00
function LinkifyString ( a_String , a_Referrer )
assert ( a_Referrer ~= nil ) ;
assert ( a_Referrer ~= " " ) ;
--- Adds a page to the list of tracked pages (to be checked for existence at the end)
local function AddTrackedPage ( a_PageName )
local Pg = ( g_TrackedPages [ a_PageName ] or { } ) ;
table.insert ( Pg , a_Referrer ) ;
g_TrackedPages [ a_PageName ] = Pg ;
end
--- Creates the HTML for the specified link and title
2013-10-15 12:42:33 -04:00
local function CreateLink ( Link , Title )
if ( Link : sub ( 1 , 7 ) == " http:// " ) then
-- The link is a full absolute URL, do not modify, do not track:
return " <a href= \" " .. Link .. " \" > " .. Title .. " </a> " ;
end
local idxHash = Link : find ( " # " ) ;
if ( idxHash ~= nil ) then
-- The link contains an anchor:
if ( idxHash == 1 ) then
-- Anchor in the current page, no need to track:
return " <a href= \" " .. Link .. " \" > " .. Title .. " </a> " ;
end
-- Anchor in another page:
2013-10-18 06:30:06 -04:00
local PageName = Link : sub ( 1 , idxHash - 1 ) ;
AddTrackedPage ( PageName ) ;
return " <a href= \" " .. PageName .. " .html# " .. Link : sub ( idxHash + 1 ) .. " \" > " .. Title .. " </a> " ;
2013-10-15 12:42:33 -04:00
end
-- Link without anchor:
2013-10-18 06:30:06 -04:00
AddTrackedPage ( Link ) ;
2013-10-15 12:42:33 -04:00
return " <a href= \" " .. Link .. " .html \" > " .. Title .. " </a> " ;
end
2013-10-18 06:30:06 -04:00
-- Linkify the strings using the CreateLink() function:
2013-10-15 12:42:33 -04:00
local txt = a_String : gsub ( " {{([^|}]*)|([^}]*)}} " , CreateLink ) -- {{link|title}}
txt = txt : gsub ( " {{([^|}]*)}} " , -- {{LinkAndTitle}}
function ( LinkAndTitle )
local idxHash = LinkAndTitle : find ( " # " ) ;
if ( idxHash ~= nil ) then
-- The LinkAndTitle contains a hash, remove the hashed part from the title:
return CreateLink ( LinkAndTitle , LinkAndTitle : sub ( 1 , idxHash - 1 ) ) ;
end
return CreateLink ( LinkAndTitle , LinkAndTitle ) ;
end
) ;
2013-10-09 09:10:25 -04:00
return txt ;
end
2013-09-13 04:22:04 -04:00
function WriteHtmlClass ( a_ClassAPI , a_AllAPI )
2013-09-11 10:57:57 -04:00
local cf , err = io.open ( " API/ " .. a_ClassAPI.Name .. " .html " , " w " ) ;
2013-09-10 16:02:18 -04:00
if ( cf == nil ) then
return ;
end
2013-09-09 16:28:02 -04:00
2013-09-13 04:22:04 -04:00
-- Writes a table containing all functions in the specified list, with an optional "inherited from" header when a_InheritedName is valid
local function WriteFunctions ( a_Functions , a_InheritedName )
if ( # a_Functions == 0 ) then
return ;
end
2013-09-14 10:20:54 -04:00
2013-09-13 04:22:04 -04:00
if ( a_InheritedName ~= nil ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <h2>Functions inherited from " .. a_InheritedName .. " </h2> \n " ) ;
2013-09-13 04:22:04 -04:00
end
2013-10-16 02:04:06 -04:00
cf : write ( " <table> \n <tr> \n <th>Name</th> \n <th>Parameters</th> \n <th>Return value</th> \n <th>Notes</th> \n </tr> \n " ) ;
2013-09-13 04:22:04 -04:00
for i , func in ipairs ( a_Functions ) do
2013-10-16 02:04:06 -04:00
cf : write ( " <tr> \n <td> " .. func.Name .. " </td> \n " ) ;
2013-10-18 06:30:06 -04:00
cf : write ( " <td> " .. LinkifyString ( func.Params or " " , ( a_InheritedName or a_ClassAPI.Name ) ) .. " </td> \n " ) ;
cf : write ( " <td> " .. LinkifyString ( func.Return or " " , ( a_InheritedName or a_ClassAPI.Name ) ) .. " </td> \n " ) ;
2013-10-18 15:29:38 -04:00
cf : write ( " <td> " .. LinkifyString ( func.Notes or " <i>(undocumented)</i> " , ( a_InheritedName or a_ClassAPI.Name ) ) .. " </td> \n </tr> \n " ) ;
2013-09-13 04:22:04 -04:00
end
2013-10-16 02:04:06 -04:00
cf : write ( " </table> \n \n " ) ;
2013-09-13 04:22:04 -04:00
end
2013-09-13 04:51:01 -04:00
2013-10-18 14:49:30 -04:00
local function WriteConstants ( a_Constants , a_InheritedName )
if ( # a_Constants == 0 ) then
return ;
end
if ( a_InheritedName ~= nil ) then
cf : write ( " <h2>Constants inherited from " .. a_InheritedName .. " </h2> \n " ) ;
end
cf : write ( " <table> \n <tr> \n <th>Name</th> \n <th>Value</th> \n <th>Notes</th> \n </tr> \n " ) ;
for i , cons in ipairs ( a_Constants ) do
cf : write ( " <tr> \n <td> " .. cons.Name .. " </td> \n " ) ;
cf : write ( " <td> " .. cons.Value .. " </td> \n " ) ;
cf : write ( " <td> " .. LinkifyString ( cons.Notes or " " , a_InheritedName or a_ClassAPI.Name ) .. " </td> \n </tr> \n " ) ;
end
cf : write ( " </table> \n \n " ) ;
end
2013-10-18 15:29:38 -04:00
local function WriteVariables ( a_Variables , a_InheritedName )
if ( # a_Variables == 0 ) then
return ;
end
if ( a_InheritedName ~= nil ) then
cf : write ( " <h2>Member variables inherited from " .. a_InheritedName .. " </h2> \n " ) ;
end
cf : write ( " <table> \n <tr> \n <th>Name</th> \n <th>Type</th> \n <th>Notes</th> \n </tr> \n " ) ;
for i , var in ipairs ( a_Variables ) do
cf : write ( " <tr> \n <td> " .. var.Name .. " </td> \n " ) ;
cf : write ( " <td> " .. LinkifyString ( var.Type or " <i>(undocumented)</i> " , a_InheritedName or a_ClassAPI.Name ) .. " </td> \n " ) ;
cf : write ( " <td> " .. LinkifyString ( var.Notes or " " , a_InheritedName or a_ClassAPI.Name ) .. " </td> \n </tr> \n " ) ;
end
cf : write ( " </table> \n \n " ) ;
end
2013-09-13 04:51:01 -04:00
local function WriteDescendants ( a_Descendants )
if ( # a_Descendants == 0 ) then
return ;
end
cf : write ( " <ul> " ) ;
for i , desc in ipairs ( a_Descendants ) do
cf : write ( " <li><a href= \" " .. desc.Name .. " .html \" > " .. desc.Name .. " </a> " ) ;
WriteDescendants ( desc.Descendants ) ;
cf : write ( " </li> \n " ) ;
end
cf : write ( " </ul> \n " ) ;
end
2013-10-18 06:30:06 -04:00
local ClassName = a_ClassAPI.Name ;
2013-09-13 04:22:04 -04:00
-- Build an array of inherited classes chain:
local InheritanceChain = { } ;
2013-09-13 04:51:01 -04:00
local CurrInheritance = a_ClassAPI.Inherits ;
2013-09-13 04:22:04 -04:00
while ( CurrInheritance ~= nil ) do
table.insert ( InheritanceChain , CurrInheritance ) ;
2013-09-13 04:51:01 -04:00
CurrInheritance = CurrInheritance.Inherits ;
2013-09-13 04:22:04 -04:00
end
2013-10-16 02:04:06 -04:00
cf : write ( [ [ < ! DOCTYPE html >
< html >
< head >
2013-10-18 05:56:58 -04:00
< title > MCServer API - ] ] .. a_ClassAPI.Name .. [ [ Class </ title >
2013-10-16 02:04:06 -04:00
< link rel = " stylesheet " type = " text/css " href = " main.css " />
2013-10-18 15:02:43 -04:00
< link rel = " stylesheet " type = " text/css " href = " prettify.css " />
< script src = " prettify.js " ></ script >
2013-10-18 14:21:26 -04:00
< script src = " lang-lua.js " ></ script >
2013-10-16 02:04:06 -04:00
</ head >
< body >
< div id = " content " >
< header >
< h1 > ] ] .. a_ClassAPI.Name .. [ [ </ h1 >
< hr />
</ header >
< h1 > Contents </ h1 >
< ul >
] ] ) ;
2013-09-10 16:02:18 -04:00
2013-09-13 04:51:01 -04:00
local HasInheritance = ( ( # a_ClassAPI.Descendants > 0 ) or ( a_ClassAPI.Inherits ~= nil ) ) ;
2013-10-18 14:49:30 -04:00
local HasConstants = ( # a_ClassAPI.Constants > 0 ) ;
local HasFunctions = ( # a_ClassAPI.Functions > 0 ) ;
2013-10-18 15:29:38 -04:00
local HasVariables = ( # a_ClassAPI.Variables > 0 ) ;
2013-10-18 14:49:30 -04:00
if ( a_ClassAPI.Inherits ~= nil ) then
for idx , cls in ipairs ( a_ClassAPI.Inherits ) do
HasConstants = HasConstants or ( # cls.Constants > 0 ) ;
HasFunctions = HasFunctions or ( # cls.Functions > 0 ) ;
2013-10-18 15:29:38 -04:00
HasVariables = HasVariables or ( # cls.Variables > 0 ) ;
2013-10-18 14:49:30 -04:00
end
end
2013-09-10 16:02:18 -04:00
-- Write the table of contents:
2013-09-13 04:51:01 -04:00
if ( HasInheritance ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <li><a href= \" #inherits \" >Inheritance</a></li> \n " ) ;
2013-09-10 16:02:18 -04:00
end
2013-10-18 14:49:30 -04:00
if ( HasConstants ) then
cf : write ( " <li><a href= \" #constants \" >Constants</a></li> \n " ) ;
end
2013-10-18 15:29:38 -04:00
if ( HasVariables ) then
cf : write ( " <li><a href= \" #variables \" >Member variables</a></li> \n " ) ;
end
2013-10-18 14:49:30 -04:00
if ( HasFunctions ) then
cf : write ( " <li><a href= \" #functions \" >Functions</a></li> \n " ) ;
end
2013-09-14 11:28:22 -04:00
if ( a_ClassAPI.AdditionalInfo ~= nil ) then
for i , additional in ipairs ( a_ClassAPI.AdditionalInfo ) do
2013-10-18 17:22:26 -04:00
cf : write ( " <li><a href= \" #additionalinfo_ " .. i .. " \" > " .. ( additional.Header or " <i>(No header)</i> " ) .. " </a></li> \n " ) ;
2013-09-14 11:28:22 -04:00
end
end
2013-10-16 02:04:06 -04:00
cf : write ( " </ul> \n \n " ) ;
2013-09-10 16:02:18 -04:00
-- Write the class description:
2013-10-19 15:47:59 -04:00
cf : write ( " <a name= \" desc \" ><hr /><h1> " .. ClassName .. " class</h1></a> \n " ) ;
2013-09-11 10:57:57 -04:00
if ( a_ClassAPI.Desc ~= nil ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <p> " ) ;
2013-10-18 06:30:06 -04:00
cf : write ( LinkifyString ( a_ClassAPI.Desc , ClassName ) ) ;
2013-10-16 02:04:06 -04:00
cf : write ( " </p> \n \n " ) ;
2013-09-10 16:02:18 -04:00
end ;
2013-09-13 04:22:04 -04:00
-- Write the inheritance, if available:
2013-09-13 04:51:01 -04:00
if ( HasInheritance ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <a name= \" inherits \" > \n <hr /><h1>Inheritance</h1></a> \n " ) ;
2013-09-13 04:51:01 -04:00
if ( # InheritanceChain > 0 ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <p>This class inherits from the following parent classes:</p> \n \n <ul> \n " ) ;
2013-09-13 04:51:01 -04:00
for i , cls in ipairs ( InheritanceChain ) do
2013-10-16 02:04:06 -04:00
cf : write ( " <li><a href= \" " .. cls.Name .. " .html \" > " .. cls.Name .. " </a></li> \n " ) ;
2013-09-13 04:51:01 -04:00
end
2013-10-16 02:04:06 -04:00
cf : write ( " </ul> \n \n " ) ;
2013-09-13 04:51:01 -04:00
end
if ( # a_ClassAPI.Descendants > 0 ) then
2013-10-16 02:04:06 -04:00
cf : write ( " <p>This class has the following descendants: \n " ) ;
2013-09-13 04:51:01 -04:00
WriteDescendants ( a_ClassAPI.Descendants ) ;
2013-10-16 02:04:06 -04:00
cf : write ( " </p> \n \n " ) ;
2013-09-10 16:02:18 -04:00
end
end
2013-09-13 04:22:04 -04:00
-- Write the constants:
2013-10-18 14:49:30 -04:00
if ( HasConstants ) then
cf : write ( " <a name= \" constants \" ><hr /><h1>Constants</h1></a> \n " ) ;
WriteConstants ( a_ClassAPI.Constants , nil ) ;
for i , cls in ipairs ( InheritanceChain ) do
WriteConstants ( cls.Constants , cls.Name ) ;
end ;
end ;
2013-09-13 04:22:04 -04:00
2013-10-18 15:29:38 -04:00
-- Write the member variables:
if ( HasVariables ) then
cf : write ( " <a name= \" variables \" ><hr /><h1>Member variables</h1></a> \n " ) ;
WriteVariables ( a_ClassAPI.Variables , nil ) ;
for i , cls in ipairs ( InheritanceChain ) do
WriteVariables ( cls.Variables , cls.Name ) ;
end ;
end
2013-09-13 04:22:04 -04:00
-- Write the functions, including the inherited ones:
2013-10-18 14:49:30 -04:00
if ( HasFunctions ) then
cf : write ( " <a name= \" functions \" ><hr /><h1>Functions</h1></a> \n " ) ;
WriteFunctions ( a_ClassAPI.Functions , nil ) ;
for i , cls in ipairs ( InheritanceChain ) do
WriteFunctions ( cls.Functions , cls.Name ) ;
end
2013-09-10 16:02:18 -04:00
end
2013-09-14 11:28:22 -04:00
-- Write the additional infos:
if ( a_ClassAPI.AdditionalInfo ~= nil ) then
for i , additional in ipairs ( a_ClassAPI.AdditionalInfo ) do
2013-10-16 02:04:06 -04:00
cf : write ( " <a name= \" additionalinfo_ " .. i .. " \" ><h1> " .. additional.Header .. " </h1></a> \n " ) ;
2013-10-18 06:30:06 -04:00
cf : write ( LinkifyString ( additional.Contents , ClassName ) ) ;
2013-09-14 11:28:22 -04:00
end
end
2013-10-18 16:02:06 -04:00
cf : write ( [ [
</ div >
< script >
prettyPrint ( ) ;
</ script >
</ body >
</ html >
] ] ) ;
2013-09-10 16:02:18 -04:00
cf : close ( ) ;
2013-09-09 16:28:02 -04:00
end
2013-09-11 15:21:51 -04:00
2013-10-09 09:10:25 -04:00
function WriteHtmlHook ( a_Hook )
local fnam = " API/ " .. a_Hook.DefaultFnName .. " .html " ;
local f , error = io.open ( fnam , " w " ) ;
if ( f == nil ) then
LOG ( " Cannot write \" " .. fnam .. " \" : \" " .. error .. " \" . " ) ;
return ;
end
2013-10-18 06:30:06 -04:00
local HookName = a_Hook.DefaultFnName ;
2013-10-16 02:04:06 -04:00
f : write ( [ [ < ! DOCTYPE html >
< html >
< head >
2013-10-18 06:30:06 -04:00
< title > MCServer API - ] ] .. HookName .. [ [ Hook </ title >
2013-10-16 02:04:06 -04:00
< link rel = " stylesheet " type = " text/css " href = " main.css " />
2013-10-18 15:02:43 -04:00
< link rel = " stylesheet " type = " text/css " href = " prettify.css " />
< script src = " prettify.js " ></ script >
2013-10-18 14:21:26 -04:00
< script src = " lang-lua.js " ></ script >
2013-10-16 02:04:06 -04:00
</ head >
< body >
< div id = " content " >
< header >
< h1 > ] ] .. a_Hook.Name .. [ [ </ h1 >
< hr />
</ header >
< p >
] ] ) ;
2013-10-18 06:30:06 -04:00
f : write ( LinkifyString ( a_Hook.Desc , HookName ) ) ;
2013-10-16 02:04:06 -04:00
f : write ( " </p> \n <hr /><h1>Callback function</h1> \n <p>The default name for the callback function is " ) ;
f : write ( a_Hook.DefaultFnName .. " . It has the following signature: \n \n " ) ;
2013-10-18 06:30:06 -04:00
f : write ( " <pre class= \" prettyprint lang-lua \" >function " .. HookName .. " ( " ) ;
2013-10-09 09:10:25 -04:00
if ( a_Hook.Params == nil ) then
a_Hook.Params = { } ;
end
for i , param in ipairs ( a_Hook.Params ) do
if ( i > 1 ) then
f : write ( " , " ) ;
end
f : write ( param.Name ) ;
end
2013-10-16 02:04:06 -04:00
f : write ( " )</pre> \n \n <hr /><h1>Parameters:</h1> \n \n <table> \n <tr> \n <th>Name</th> \n <th>Type</th> \n <th>Notes</th> \n </tr> \n " ) ;
2013-10-09 09:10:25 -04:00
for i , param in ipairs ( a_Hook.Params ) do
2013-10-18 06:30:06 -04:00
f : write ( " <tr> \n <td> " .. param.Name .. " </td> \n <td> " .. LinkifyString ( param.Type , HookName ) .. " </td> \n <td> " .. LinkifyString ( param.Notes , HookName ) .. " </td> \n </tr> \n " ) ;
2013-10-16 02:04:06 -04:00
end
f : write ( " </table> \n \n <p> " .. ( a_Hook.Returns or " " ) .. " </p> \n \n " ) ;
f : write ( [ [ < hr />< h1 > Code examples </ h1 >
< h2 > Registering the callback </ h2 >
] ] ) ;
f : write ( " <pre class= \" prettyprint lang-lua \" > \n " ) ;
f : write ( [[cPluginManager.AddHook(cPluginManager.]] .. a_Hook.Name .. " , My " .. a_Hook.DefaultFnName .. [[);]] ) ;
f : write ( " </pre> \n \n " ) ;
2013-10-12 12:11:14 -04:00
local Examples = a_Hook.CodeExamples or { } ;
for i , example in ipairs ( Examples ) do
2013-10-17 07:54:41 -04:00
f : write ( " <h2> " .. ( example.Title or " <i>missing Title</i> " ) .. " </h2> \n " ) ;
f : write ( " <p> " .. ( example.Desc or " <i>missing Desc</i> " ) .. " </p> \n \n " ) ;
f : write ( " <pre class= \" prettyprint lang-lua \" > " .. ( example.Code or " <i>missing Code</i> " ) .. " \n </pre> \n \n " ) ;
2013-10-12 12:11:14 -04:00
end
2013-10-16 02:04:06 -04:00
f : write ( [ [ </ div >
2013-10-18 16:02:06 -04:00
< script >
prettyPrint ( ) ;
</ script >
2013-10-16 02:04:06 -04:00
</ body >
</ html > ] ] ) ;
2013-10-09 09:10:25 -04:00
f : close ( ) ;
end
2013-10-18 06:30:06 -04:00
2013-10-18 14:32:36 -04:00
--- Writes a list of undocumented objects into a file
function ListUndocumentedObjects ( API , UndocumentedHooks )
f = io.open ( " API/_undocumented.lua " , " w " ) ;
if ( f ~= nil ) then
f : write ( " \n -- This is the list of undocumented API objects, automatically generated by APIDump \n \n " ) ;
f : write ( " g_APIDesc = \n { \n \t Classes = \n \t { \n " ) ;
for i , cls in ipairs ( API ) do
local HasFunctions = ( ( cls.UndocumentedFunctions ~= nil ) and ( # cls.UndocumentedFunctions > 0 ) ) ;
local HasConstants = ( ( cls.UndocumentedConstants ~= nil ) and ( # cls.UndocumentedConstants > 0 ) ) ;
if ( HasFunctions or HasConstants ) then
f : write ( " \t \t " .. cls.Name .. " = \n \t \t { \n " ) ;
if ( ( cls.Desc == nil ) or ( cls.Desc == " " ) ) then
f : write ( " \t \t \t Desc = \" \" \n " ) ;
end
end
if ( HasFunctions ) then
f : write ( " \t \t \t Functions = \n \t \t \t { \n " ) ;
table.sort ( cls.UndocumentedFunctions ) ;
for j , fn in ipairs ( cls.UndocumentedFunctions ) do
f : write ( " \t \t \t \t " .. fn .. " = { Params = \" \" , Return = \" \" , Notes = \" \" }, \n " ) ;
end -- for j, fn - cls.Undocumented[]
f : write ( " \t \t \t }, \n \n " ) ;
end
if ( HasConstants ) then
f : write ( " \t \t \t Constants = \n \t \t \t { \n " ) ;
table.sort ( cls.UndocumentedConstants ) ;
for j , cn in ipairs ( cls.UndocumentedConstants ) do
f : write ( " \t \t \t \t " .. cn .. " = { Notes = \" \" }, \n " ) ;
end -- for j, fn - cls.Undocumented[]
f : write ( " \t \t \t }, \n \n " ) ;
end
if ( HasFunctions or HasConstants ) then
f : write ( " \t \t }, \n \n " ) ;
end
end -- for i, cls - API[]
f : write ( " \t }, \n " ) ;
if ( # UndocumentedHooks > 0 ) then
f : write ( " \n \t Hooks = \n \t { \n " ) ;
for i , hook in ipairs ( UndocumentedHooks ) do
if ( i > 1 ) then
f : write ( " \n " ) ;
end
f : write ( " \t \t " .. hook .. " = \n \t \t { \n " ) ;
f : write ( " \t \t \t CalledWhen = \" \" , \n " ) ;
f : write ( " \t \t \t DefaultFnName = \" On \" , -- also used as pagename \n " ) ;
f : write ( " \t \t \t Desc = [[ \n \t \t \t \t \n \t \t \t ]], \n " ) ;
f : write ( " \t \t \t Params = \n \t \t \t { \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t \t { Name = \" \" , Type = \" \" , Notes = \" \" }, \n " ) ;
f : write ( " \t \t \t }, \n " ) ;
f : write ( " \t \t \t Returns = [[ \n \t \t \t \t \n \t \t \t ]], \n " ) ;
f : write ( " \t \t }, -- " .. hook .. " \n " ) ;
end
end
f : close ( ) ;
end
end
--- Lists the API objects that are documented but not available in the API:
function ListUnexportedObjects ( )
f = io.open ( " API/_unexported-documented.txt " , " w " ) ;
if ( f ~= nil ) then
for clsname , cls in pairs ( g_APIDesc.Classes ) do
if not ( cls.IsExported ) then
-- The whole class is not exported
f : write ( " class \t " .. clsname .. " \n " ) ;
else
if ( cls.Functions ~= nil ) then
for fnname , fnapi in pairs ( cls.Functions ) do
if not ( fnapi.IsExported ) then
f : write ( " func \t " .. clsname .. " . " .. fnname .. " \n " ) ;
end
end -- for j, fn - cls.Functions[]
end
if ( cls.Constants ~= nil ) then
for cnname , cnapi in pairs ( cls.Constants ) do
if not ( cnapi.IsExported ) then
f : write ( " const \t " .. clsname .. " . " .. cnname .. " \n " ) ;
end
end -- for j, fn - cls.Functions[]
end
end
end -- for i, cls - g_APIDesc.Classes[]
f : close ( ) ;
end
end
2013-10-18 06:30:06 -04:00
function ListMissingPages ( )
local MissingPages = { } ;
for PageName , Referrers in pairs ( g_TrackedPages ) do
if not ( cFile : Exists ( " API/ " .. PageName .. " .html " ) ) then
table.insert ( MissingPages , { Name = PageName , Refs = Referrers } ) ;
end
end ;
g_TrackedPages = { } ;
if ( # MissingPages == 0 ) then
-- No missing pages, congratulations!
return ;
end
-- Sort the pages by name:
table.sort ( MissingPages ,
function ( Page1 , Page2 )
return ( Page1.Name < Page2.Name ) ;
end
) ;
-- Output the pages:
local f , err = io.open ( " API/_missingPages.txt " , " w " ) ;
if ( f == nil ) then
LOGWARNING ( " Cannot open _missingPages.txt for writing: ' " .. err .. " '. There are " .. # MissingPages .. " pages missing. " ) ;
return ;
end
for idx , pg in ipairs ( MissingPages ) do
f : write ( pg.Name .. " : \n " ) ;
-- Sort and output the referrers:
table.sort ( pg.Refs ) ;
f : write ( " \t " .. table.concat ( pg.Refs , " \n \t " ) ) ;
f : write ( " \n \n " ) ;
end
f : close ( ) ;
end