diff options
Diffstat (limited to 'Data/Libraries/LDoc/ldoc.lua')
-rw-r--r-- | Data/Libraries/LDoc/ldoc.lua | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/Data/Libraries/LDoc/ldoc.lua b/Data/Libraries/LDoc/ldoc.lua new file mode 100644 index 0000000..ad49f86 --- /dev/null +++ b/Data/Libraries/LDoc/ldoc.lua @@ -0,0 +1,858 @@ +#!/usr/bin/env lua +--------------- +-- ## ldoc, a Lua documentation generator. +-- +-- Compatible with luadoc-style annotations, but providing +-- easier customization options. +-- +-- C/C++ support for Lua extensions is provided. +-- +-- Available from LuaRocks as 'ldoc' and as a [Zip file](http://stevedonovan.github.com/files/ldoc-1.4.3.zip) +-- +-- [Github Page](https://github.com/stevedonovan/ldoc) +-- +-- @author Steve Donovan +-- @copyright 2011 +-- @license MIT/X11 +-- @script ldoc + +local class = require 'pl.class' +local app = require 'pl.app' +local path = require 'pl.path' +local dir = require 'pl.dir' +local utils = require 'pl.utils' +local List = require 'pl.List' +local stringx = require 'pl.stringx' +local tablex = require 'pl.tablex' + +-- Penlight compatibility +utils.unpack = utils.unpack or unpack or table.unpack +local lapp = require 'pl.lapp' + +local version = '1.4.6' + +-- so we can find our private modules +app.require_here() + +--- @usage +local usage = [[ +ldoc, a documentation generator for Lua, v]]..version..[[ + + Invocation: + ldoc [options] <file> + ldoc --version + + Options: + -d,--dir (default doc) output directory + -o,--output (default 'index') output name + -v,--verbose verbose + -a,--all show local functions, etc, in docs + -q,--quiet suppress output + -m,--module module docs as text + -s,--style (default !) directory for style sheet (ldoc.css) + -l,--template (default !) directory for template (ldoc.ltp) + -p,--project (default ldoc) project name + -t,--title (default Reference) page title + -f,--format (default plain) formatting - can be markdown, discount or plain + -b,--package (default .) top-level package basename (needed for module(...)) + -x,--ext (default html) output file extension + -c,--config (default config.ld) configuration name + -u,--unqualified don't show package name in sidebar links + -i,--ignore ignore any 'no doc comment or no module' warnings + -X,--not_luadoc break LuaDoc compatibility. Descriptions may continue after tags. + -D,--define (default none) set a flag to be used in config.ld + -C,--colon use colon style + -N,--no_args_infer don't infer arguments from source + -B,--boilerplate ignore first comment in source files + -M,--merge allow module merging + -S,--simple no return or params, no summary + -O,--one one-column output layout + -V,--version show version information + --date (default system) use this date in generated doc + --dump debug output dump + --filter (default none) filter output as Lua data (e.g pl.pretty.dump) + --tags (default none) show all references to given tags, comma-separated + --fatalwarnings non-zero exit status on any warning + --testing reproducible build; no date or version on output + --icon (default none) an image that will be displayed under the project name on all pages + + <file> (string) source file or directory containing source + + `ldoc .` reads options from an `config.ld` file in same directory; + `ldoc -c path/to/myconfig.ld <file>` reads options from `path/to/myconfig.ld` + and processes <file> if 'file' was not defined in the ld file. +]] +local args = lapp(usage) +local lfs = require 'lfs' +local doc = require 'ldoc.doc' +local lang = require 'ldoc.lang' +local tools = require 'ldoc.tools' +local global = require 'ldoc.builtin.globals' +local markup = require 'ldoc.markup' +local parse = require 'ldoc.parse' +local KindMap = tools.KindMap +local Item,File = doc.Item,doc.File +local quit = utils.quit + +if args.version then + print('LDoc v' .. version) + os.exit(0) +end + + +local ModuleMap = class(KindMap) +doc.ModuleMap = ModuleMap + +function ModuleMap:_init () + self.klass = ModuleMap + self.fieldname = 'section' +end + +local ProjectMap = class(KindMap) +ProjectMap.project_level = true + +function ProjectMap:_init () + self.klass = ProjectMap + self.fieldname = 'type' +end + +local lua, cc = lang.lua, lang.cc + +local file_types = { + ['.lua'] = lua, + ['.ldoc'] = lua, + ['.luadoc'] = lua, + ['.c'] = cc, + ['.h'] = cc, + ['.cpp'] = cc, + ['.cxx'] = cc, + ['.C'] = cc, + ['.mm'] = cc, + ['.cs'] = cc, + ['.moon'] = lang.moon, +} +------- ldoc external API ------------ + +-- the ldoc table represents the API available in `config.ld`. +local ldoc = { charset = 'UTF-8', version = version } + +local known_types, kind_names = {} + +local function lookup (itype,igroup,isubgroup) + local kn = kind_names[itype] + known_types[itype] = true + if kn then + if type(kn) == 'string' then + igroup = kn + else + igroup = kn[1] + isubgroup = kn[2] + end + end + return itype, igroup, isubgroup +end + +local function setup_kinds () + kind_names = ldoc.kind_names or {} + + ModuleMap:add_kind(lookup('function','Functions','Parameters')) + ModuleMap:add_kind(lookup('table','Tables','Fields')) + ModuleMap:add_kind(lookup('field','Fields')) + ModuleMap:add_kind(lookup('type','Types')) + ModuleMap:add_kind(lookup('lfunction','Local Functions','Parameters')) + ModuleMap:add_kind(lookup('annotation','Issues')) + + ProjectMap:add_kind(lookup('module','Modules')) + ProjectMap:add_kind(lookup('script','Scripts')) + ProjectMap:add_kind(lookup('classmod','Classes')) + ProjectMap:add_kind(lookup('topic','Topics')) + ProjectMap:add_kind(lookup('example','Examples')) + ProjectMap:add_kind(lookup('file','Source')) + + for k in pairs(kind_names) do + if not known_types[k] then + quit("unknown item type "..tools.quote(k).." in kind_names") + end + end +end + + +-- hacky way for doc module to be passed options... +doc.ldoc = ldoc + +-- if the corresponding argument was the default, then any ldoc field overrides +local function override (field,defval) + defval = defval or false + if args[field] == defval and ldoc[field] ~= nil then args[field] = ldoc[field] end +end + +-- aliases to existing tags can be defined. E.g. just 'p' for 'param' +function ldoc.alias (a,tag) + doc.add_alias(a,tag) +end + +-- standard aliases -- + +ldoc.alias('tparam',{'param',modifiers={type="$1"}}) +ldoc.alias('treturn',{'return',modifiers={type="$1"}}) +ldoc.alias('tfield',{'field',modifiers={type="$1"}}) + +function ldoc.tparam_alias (name,type) + type = type or name + ldoc.alias(name,{'param',modifiers={type=type}}) +end + +ldoc.alias ('error',doc.error_macro) + +ldoc.tparam_alias 'string' +ldoc.tparam_alias 'number' +ldoc.tparam_alias 'int' +ldoc.tparam_alias 'bool' +ldoc.tparam_alias 'func' +ldoc.tparam_alias 'tab' +ldoc.tparam_alias 'thread' + +function ldoc.add_language_extension(ext, lang) + lang = (lang=='c' and cc) or (lang=='lua' and lua) or quit('unknown language') + if ext:sub(1,1) ~= '.' then ext = '.'..ext end + file_types[ext] = lang +end + +function ldoc.add_section (name, title, subname) + ModuleMap:add_kind(name,title,subname) +end + +-- new tags can be added, which can be on a project level. +function ldoc.new_type (tag, header, project_level,subfield) + doc.add_tag(tag,doc.TAG_TYPE,project_level) + if project_level then + ProjectMap:add_kind(tag,header,subfield) + else + ModuleMap:add_kind(tag,header,subfield) + end +end + +function ldoc.manual_url (url) + global.set_manual_url(url) +end + +function ldoc.custom_see_handler(pat, handler) + doc.add_custom_see_handler(pat, handler) +end + +local ldoc_contents = { + 'alias','add_language_extension','custom_tags','new_type','add_section', 'tparam_alias', + 'file','project','title','package', 'icon','format','output','dir','ext', 'topics', + 'one','style','template','description','examples', 'pretty', 'charset', 'plain', + 'readme','all','manual_url', 'ignore', 'colon', 'sort', 'module_file','vars', + 'boilerplate','merge', 'wrap', 'not_luadoc', 'template_escape','merge_error_groups', + 'no_return_or_parms','no_summary','full_description','backtick_references', 'custom_see_handler', + 'no_space_before_args','parse_extra','no_lua_ref','sort_modules','use_markdown_titles', + 'unqualified', 'custom_display_name_handler', 'kind_names', 'custom_references', + 'dont_escape_underscore','global_lookup','prettify_files','convert_opt', 'user_keywords', + 'postprocess_html', + 'custom_css','version', + 'no_args_infer' +} +ldoc_contents = tablex.makeset(ldoc_contents) + +local function loadstr (ldoc,txt) + local chunk, err + -- Penlight's Lua 5.2 compatibility has wobbled over the years... + if not rawget(_G,'loadin') then -- Penlight 0.9.5 + -- Penlight 0.9.7; no more global load() override + local load = load or utils.load + chunk,err = load(txt,'config',nil,ldoc) + else + -- luacheck: push ignore 113 + chunk,err = loadin(ldoc,txt) + -- luacheck: pop + end + return chunk, err +end + +-- any file called 'config.ld' found in the source tree will be +-- handled specially. It will be loaded using 'ldoc' as the environment. +local function read_ldoc_config (fname) + local directory = path.dirname(fname) + if directory == '' then + directory = '.' + end + local chunk, err, _ + if args.filter == 'none' then + print('reading configuration from '..fname) + end + local txt,not_found = utils.readfile(fname) + if txt then + chunk, err = loadstr(ldoc,txt) + if chunk then + if args.define ~= 'none' then ldoc[args.define] = true end + _,err = pcall(chunk) + end + end + if err then quit('error loading config file '..fname..': '..err) end + for k in pairs(ldoc) do + if not ldoc_contents[k] then + quit("this config file field/function is unrecognized: "..k) + end + end + return directory, not_found +end + +local quote = tools.quote +--- processing command line and preparing for output --- + +local file_list = List() +File.list = file_list +local config_dir + + +local ldoc_dir = arg[0]:gsub('[^/\\]+$','') +local doc_path = ldoc_dir..'/ldoc/builtin/?.lua' + +-- ldoc -m is expecting a Lua package; this converts this to a file path +if args.module then + -- first check if we've been given a global Lua lib function + if args.file:match '^%a+$' and global.functions[args.file] then + args.file = 'global.'..args.file + end + local fullpath,mod,_ = tools.lookup_existing_module_or_function (args.file, doc_path) + if not fullpath then + quit(mod) + else + args.file = fullpath + args.module = mod + end +end + +local abspath = tools.abspath + +-- a special case: 'ldoc .' can get all its parameters from config.ld +if args.file == '.' then + local err + config_dir,err = read_ldoc_config(args.config) + if err then quit("no "..quote(args.config).." found") end + local config_path = path.dirname(args.config) + if config_path ~= '' then + print('changing to directory',config_path) + lfs.chdir(config_path) + end + args.file = ldoc.file or '.' + if args.file == '.' then + args.file = lfs.currentdir() + elseif type(args.file) == 'table' then + for i,f in ipairs(args.file) do + args.file[i] = abspath(f) + end + else + args.file = abspath(args.file) + end +else + -- user-provided config file + if args.config ~= 'config.ld' then + local err + config_dir,err = read_ldoc_config(args.config) + if err then quit("no "..quote(args.config).." found") end + end + -- with user-provided file + if args.file == nil then + lapp.error('missing required parameter: file') + end + args.file = abspath(args.file) +end + +if type(ldoc.custom_tags) == 'table' then -- custom tags + for i, custom in ipairs(ldoc.custom_tags) do + if type(custom) == 'string' then + custom = {custom} + ldoc.custom_tags[i] = custom + end + doc.add_tag(custom[1], 'ML') + end +end -- custom tags + +local source_dir = args.file +if type(source_dir) == 'table' then + source_dir = source_dir[1] +end +if type(source_dir) == 'string' and path.isfile(source_dir) then + source_dir = path.splitpath(source_dir) +end +source_dir = source_dir:gsub('[/\\]%.$','') + +---------- specifying the package for inferring module names -------- +-- If you use module(...), or forget to explicitly use @module, then +-- ldoc has to infer the module name. There are three sensible values for +-- `args.package`: +-- +-- * '.' the actual source is in an immediate subdir of the path given +-- * '..' the path given points to the source directory +-- * 'NAME' explicitly give the base module package name +-- + +override ('package','.') + +local function setup_package_base() + if ldoc.package then args.package = ldoc.package end + if args.package == '.' then + args.package = source_dir + elseif args.package == '..' then + args.package = path.splitpath(source_dir) + elseif not args.package:find '[\\/]' then + local subdir,dir = path.splitpath(source_dir) + if dir == args.package then + args.package = subdir + elseif path.isdir(path.join(source_dir,args.package)) then + args.package = source_dir + else + quit("args.package is not the name of the source directory") + end + end +end + + +--------- processing files --------------------- +-- ldoc may be given a file, or a directory. `args.file` may also be specified in config.ld +-- where it is a list of files or directories. If specified on the command-line, we have +-- to find an optional associated config.ld, if not already loaded. + +if ldoc.ignore then args.ignore = true end + +local function process_file (f, flist) + local ext = path.extension(f) + local ftype = file_types[ext] + if ftype then + if args.verbose then print(f) end + ftype.extra = ldoc.parse_extra or {} + local F,err = parse.file(f,ftype,args) + if err then + if F then + F:warning("internal LDoc error") + end + quit(err) + end + flist:append(F) + end +end + +local process_file_list = tools.process_file_list + +setup_package_base() + +override 'no_args_infer' +override 'colon' +override 'merge' +override 'not_luadoc' +override 'module_file' +override 'boilerplate' +override 'all' + +setup_kinds() + +-- LDoc is doing plain ole C, don't want random Lua references! +if ldoc.parse_extra and ldoc.parse_extra.C then + ldoc.no_lua_ref = true +end + +if ldoc.merge_error_groups == nil then + ldoc.merge_error_groups = 'Error Message' +end + +-- ldoc.module_file establishes a partial ordering where the +-- master module files are processed first. +local function reorder_module_file () + if args.module_file then + local mf = {} + for mname, f in pairs(args.module_file) do + local fullpath = abspath(f) + mf[fullpath] = true + end + return function(x,y) + return mf[x] and not mf[y] + end + end +end + +-- process files, optionally in order that respects master module files +local function process_all_files(files) + local sortfn = reorder_module_file() + local files = tools.expand_file_list(files,'*.*') + if sortfn then files:sort(sortfn) end + for f in files:iter() do + process_file(f, file_list) + end + if #file_list == 0 then quit "no source files found" end +end + +if type(args.file) == 'table' then + -- this can only be set from config file so we can assume config is already read + process_all_files(args.file) + +elseif path.isdir(args.file) then + -- use any configuration file we find, if not already specified + if not config_dir then + local files = List(dir.getallfiles(args.file,'*.*')) + local config_files = files:filter(function(f) + return path.basename(f) == args.config + end) + if #config_files > 0 then + config_dir = read_ldoc_config(config_files[1]) + if #config_files > 1 then + print('warning: other config files found: '..config_files[2]) + end + end + end + + process_all_files({args.file}) + +elseif path.isfile(args.file) then + -- a single file may be accompanied by a config.ld in the same dir + if not config_dir then + config_dir = path.dirname(args.file) + if config_dir == '' then config_dir = '.' end + local config = path.join(config_dir,args.config) + if path.isfile(config) then + read_ldoc_config(config) + end + end + process_file(args.file, file_list) + if #file_list == 0 then quit "unsupported file extension" end +else + quit ("file or directory does not exist: "..quote(args.file)) +end + + +-- create the function that renders text (descriptions and summaries) +-- (this also will initialize the code prettifier used) +override ('format','plain') +override 'pretty' +ldoc.markup = markup.create(ldoc, args.format, args.pretty, ldoc.user_keywords) + +------ 'Special' Project-level entities --------------------------------------- +-- Examples and Topics do not contain code to be processed for doc comments. +-- Instead, they are intended to be rendered nicely as-is, whether as pretty-lua +-- or as Markdown text. Treating them as 'modules' does stretch the meaning of +-- of the term, but allows them to be treated much as modules or scripts. +-- They define an item 'body' field (containing the file's text) and a 'postprocess' +-- field which is used later to convert them into HTML. They may contain @{ref}s. + +local function add_special_project_entity (f,tags,process) + local F = File(f) + tags.name = path.basename(f) + local text = utils.readfile(f) + local item = F:new_item(tags,1) + if process then + text = process(F, text) + end + F:finish() + file_list:append(F) + item.body = text + return item, F +end + +local function prettify_source_files(files,class,linemap) + local prettify = require 'ldoc.prettify' + + process_file_list (files, '*.*', function(f) + local ext = path.extension(f) + local ftype = file_types[ext] + if ftype then + local item = add_special_project_entity(f,{ + class = class, + }) + -- wrap prettify for this example so it knows which file to blame + -- if there's a problem + local lang = ext:sub(2) + item.postprocess = function(code) + return '<h2>'..path.basename(f)..'</h2>\n' .. + prettify.lua(lang,f,code,0,true,linemap and linemap[f]) + end + end + end) +end + +if type(ldoc.examples) == 'string' then + ldoc.examples = {ldoc.examples} +end +if type(ldoc.examples) == 'table' then + prettify_source_files(ldoc.examples,"example") +end + +ldoc.is_file_prettified = {} + +if ldoc.prettify_files then + local files = List() + local linemap = {} + for F in file_list:iter() do + files:append(F.filename) + local mod = F.modules[1] + if mod then + local ls = List() + for item in mod.items:iter() do + ls:append(item.lineno) + end + linemap[F.filename] = ls + end + end + + if type(ldoc.prettify_files) == 'table' then + files = tools.expand_file_list(ldoc.prettify_files, '*.*') + elseif type(ldoc.prettify_files) == 'string' then + -- the gotcha is that if the person has a folder called 'show', only the contents + -- of that directory will be converted. So, we warn of this amibiguity + if ldoc.prettify_files == 'show' then + -- just fall through with all module files collected above + if path.exists 'show' then + print("Notice: if you only want to prettify files in `show`, then set prettify_files to `show/`") + end + else + files = tools.expand_file_list({ldoc.prettify_files}, '*.*') + end + end + + ldoc.is_file_prettified = tablex.makeset(files) + prettify_source_files(files,"file",linemap) +end + +if args.simple then + ldoc.no_return_or_parms=true + ldoc.no_summary=true +end + +ldoc.readme = ldoc.readme or ldoc.topics +if type(ldoc.readme) == 'string' then + ldoc.readme = {ldoc.readme} +end +if type(ldoc.readme) == 'table' then + process_file_list(ldoc.readme, '*.md', function(f) + local item, F = add_special_project_entity(f,{ + class = 'topic' + }, markup.add_sections) + -- add_sections above has created sections corresponding to the 2nd level + -- headers in the readme, which are attached to the File. So + -- we pass the File to the postprocesser, which will insert the section markers + -- and resolve inline @ references. + if ldoc.use_markdown_titles then + item.display_name = F.display_name + end + item.postprocess = function(txt) return ldoc.markup(txt,F) end + end) +end + +-- extract modules from the file objects, resolve references and sort appropriately --- + +local first_module +local project = ProjectMap() +local module_list = List() +module_list.by_name = {} + +local modcount = 0 + +for F in file_list:iter() do + for mod in F.modules:iter() do + if not first_module then first_module = mod end + if doc.code_tag(mod.type) then modcount = modcount + 1 end + module_list:append(mod) + module_list.by_name[mod.name] = mod + end +end + +for mod in module_list:iter() do + if not args.module then -- no point if we're just showing docs on the console + mod:resolve_references(module_list) + end + project:add(mod,module_list) +end + + +if ldoc.sort_modules then + table.sort(module_list,function(m1,m2) + return m1.name < m2.name + end) +end + +ldoc.single = modcount == 1 and first_module or nil + +--do return end + +-------- three ways to dump the object graph after processing ----- + +-- ldoc -m will give a quick & dirty dump of the module's documentation; +-- using -v will make it more verbose +if args.module then + if #module_list == 0 then quit("no modules found") end + if args.module == true then + file_list[1]:dump(args.verbose) + else + local M,name = module_list[1], args.module + local fun = M.items.by_name[name] + if not fun then + fun = M.items.by_name[M.mod_name..':'..name] + end + if not fun then quit(quote(name).." is not part of "..quote(args.file)) end + fun:dump(true) + end + return +end + +-- ldoc --dump will do the same as -m, except for the currently specified files +if args.dump then + for mod in module_list:iter() do + mod:dump(true) + end + os.exit() +end +if args.tags ~= 'none' then + local tagset = {} + for t in stringx.split(args.tags,','):iter() do + tagset[t] = true + end + for mod in module_list:iter() do + mod:dump_tags(tagset) + end + os.exit() +end + +-- ldoc --filter mod.name will load the module `mod` and pass the object graph +-- to the function `name`. As a special case --filter dump will use pl.pretty.dump. +if args.filter ~= 'none' then + doc.filter_objects_through_function(args.filter, module_list) + os.exit() +end + +-- can specify format, output, dir and ext in config.ld +override ('output','index') +override ('dir','doc') +override ('ext','html') +override 'one' + +-- handling styling and templates -- +ldoc.css, ldoc.templ = 'ldoc.css','ldoc.ltp' + +-- special case: user wants to generate a .md file from a .lua file +if args.ext == 'md' then + if #module_list ~= 1 then + quit("can currently only generate Markdown output from one module only") + end + if not ldoc.template or ldoc.template == '!' then + ldoc.template = '!md' + end + args.output = module_list[1].name + args.dir = '.' + ldoc.template_escape = '>' + ldoc.style = false + args.ext = '.md' +end + +local function match_bang (s) + if type(s) ~= 'string' then return end + return s:match '^!(.*)' +end + +local function style_dir (sname) + local style = ldoc[sname] + local dir + if style==false and sname == 'style' then + args.style = false + ldoc.css = false + end + if style then + if style == true then + dir = config_dir + elseif type(style) == 'string' and (path.isdir(style) or match_bang(style)) then + dir = style + else + quit(quote(tostring(style)).." is not a directory") + end + args[sname] = dir + end +end + +-- the directories for template and stylesheet can be specified +-- either by command-line '--template','--style' arguments or by 'template and +-- 'style' fields in config.ld. +-- The assumption here is that if these variables are simply true then the directory +-- containing config.ld contains a ldoc.css and a ldoc.ltp respectively. Otherwise +-- they must be a valid subdirectory. + +style_dir 'style' +style_dir 'template' + +if not args.ext:find '^%.' then + args.ext = '.'..args.ext +end + +if args.one then + ldoc.style = '!one' +end + +local builtin_style, builtin_template = match_bang(args.style),match_bang(args.template) +if builtin_style or builtin_template then + -- '!' here means 'use built-in templates' + local user = path.expanduser('~'):gsub('[/\\: ]','_') + local tmpdir = path.join(path.is_windows and os.getenv('TMP') or (os.getenv('TMPDIR') or '/tmp'),'ldoc'..user) + if not path.isdir(tmpdir) then + lfs.mkdir(tmpdir) + end + local function tmpwrite (name) + local ok,text = pcall(require,'ldoc.html.'..name:gsub('%.','_')) + if not ok then + quit("cannot find builtin template "..name.." ("..text..")") + end + if not utils.writefile(path.join(tmpdir,name),text) then + quit("cannot write to temp directory "..tmpdir) + end + end + if builtin_style then + if builtin_style ~= '' then + ldoc.css = 'ldoc_'..builtin_style..'.css' + end + tmpwrite(ldoc.css) + args.style = tmpdir + end + if builtin_template then + if builtin_template ~= '' then + ldoc.templ = 'ldoc_'..builtin_template..'.ltp' + end + tmpwrite(ldoc.templ) + args.template = tmpdir + end +end + +-- default icon to nil +if args.icon == 'none' then args.icon = nil end + +ldoc.log = print +ldoc.kinds = project +ldoc.modules = module_list +ldoc.title = ldoc.title or args.title +ldoc.project = ldoc.project or args.project +ldoc.package = args.package:match '%a+' and args.package or nil +ldoc.icon = ldoc.icon or args.icon + +local source_date_epoch = os.getenv("SOURCE_DATE_EPOCH") +if args.testing then + ldoc.updatetime = "2015-01-01 12:00:00" + ldoc.version = 'TESTING' +elseif source_date_epoch == nil then + if args.date == 'system' then + ldoc.updatetime = os.date("%Y-%m-%d %H:%M:%S") + else + ldoc.updatetime = args.date + end +else + ldoc.updatetime = os.date("!%Y-%m-%d %H:%M:%S",source_date_epoch) +end + +local html = require 'ldoc.html' + +html.generate_output(ldoc, args, project) + +if args.verbose then + print 'modules' + for k in pairs(module_list.by_name) do print(k) end +end + +if args.fatalwarnings and Item.had_warning then + os.exit(1) +end |