1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
|
--- This module is responsible for generating documentation and metadata for
--- the luv project. It processes documentation sections from docs.lua,
--- and writes the output to markdown (docs.md) and Lua files (meta.lua).
local docs = dofile('docs/docs.lua')
local doctop = docs[1]
local types = docs[2]
--- @param str string
--- @param indent? integer
--- @return string
local function dedent(str, indent)
local prefix = 99
str = str:gsub('^\n', ''):gsub('%s+$', '')
for line in str:gmatch('[^\n]+') do
local s, e = line:find('^%s*')
local amount = (e - s) + 1
if amount < prefix then
prefix = amount
end
end
local result = {} --- @type string[]
for line in str:gmatch('([^\n]*)\n?') do
result[#result + 1] = line:sub(prefix + 1)
end
local ret = table.concat(result, '\n')
ret = ret:gsub('\n+$', '')
if indent then
local ind = string.rep(' ', indent)
ret = ind .. ret:gsub('\n', '\n' .. ind)
ret = ret:gsub('\n%s+\n', '\n\n')
end
return ret
end
--- Enumerates key-value pairs of a table, ordered by key.
--- @generic T: table, K, V
--- @param t T Dict-like table
--- @return fun(table: table<K, V>, index?: K):K, V # |for-in| iterator over sorted keys and their values
--- @return T
local function spairs(t)
--- @cast t table<any,any>
-- collect the keys
local keys = {}
for k in pairs(t) do
table.insert(keys, k)
end
table.sort(keys)
-- Return the iterator function.
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end,
t
end
--- @param ty Doc.Type
--- @return Doc.Type
local function remove_nil(ty)
if not (type(ty) == 'table' and ty.kind == 'union') then
return ty
end
local r = { kind = 'union', {} } --- @type Doc.Type.Union
for _, uty in ipairs(ty[1]) do
if uty ~= 'nil' then
table.insert(r[1], uty)
end
end
if #r[1] == 1 then
return r[1][1]
end
return r
end
--- @type table<Doc.Type, string>
local gtypes = {}
--- @param nm string
--- @param ty Doc.Type
local function add_gtype(nm, ty)
if gtypes[ty] then
error('Type already exists: ' .. nm)
end
gtypes[ty] = nm
types[nm] = ty
end
--- @param ns string
--- @param nm? string
--- @param ty Doc.Type
local function gen_type(ns, nm, ty)
ty = remove_nil(ty)
if type(ty) ~= 'table' or gtypes[ty] then
return
end
local ty_nm = nm and ('%s.%s'):format(ns, nm) or ns
if ty.kind == 'function' then
if #ty.args > 2 then
add_gtype(ty_nm, ty)
end
for _, f in ipairs(ty.args) do
local arg_nm, arg_ty = f[1], f[2]
gen_type(ty_nm, arg_nm, arg_ty)
end
elseif ty.kind == 'union' then
local nonstrtys = 0
for _, uty in ipairs(ty[1]) do
if type(uty) == 'table' and not types[uty] then
nonstrtys = nonstrtys + 1
end
end
for i, uty in ipairs(ty[1]) do
gen_type(ty_nm, nonstrtys > 1 and '_' .. i or nil, uty)
end
elseif ty.kind == 'dict' then
gen_type(ty_nm, types[ty_nm] and 'value' or nil, ty.value)
elseif ty.kind == 'table' then
if #ty.fields > 2 or (#ty.fields > 0 and ty.fields[1][4]) then
add_gtype(ty_nm, ty)
end
for _, f in ipairs(ty.fields) do
local field_nm, field_ty = f[1], f[2]
gen_type(ty_nm, field_nm, field_ty)
end
end
end
--- @param section Doc
local function gen_types_for_doc(section)
for _, funcs in ipairs(section.funcs or {}) do
for _, p in ipairs(funcs.params or {}) do
gen_type(funcs.name, p.name, p.type)
end
local returns = funcs.returns or funcs.returns_sync
if type(returns) == 'table' then
for _, p in ipairs(returns) do
gen_type(funcs.name, p[2], p[1])
end
end
end
for _, subsection in ipairs(section.sections or {}) do
gen_types_for_doc(subsection)
end
end
local Doc = {}
do -- doc
--- @param lvl integer
--- @param str string
--- @return string
local function heading(lvl, str)
return string.rep('#', lvl) .. ' ' .. str:gsub(' %- ', ' — ')
end
--- @param ty Doc.Type
--- @return boolean
local function isoptional(ty)
if type(ty) == 'string' then
return ty == 'nil'
end
if ty.kind == 'union' then
for _, uty in ipairs(ty[1]) do
if isoptional(uty) then
return true
end
end
end
return false
end
local function pad(lvl)
return string.rep(' ', lvl * 2)
end
--- @param ty Doc.Type.Fun
--- @param lvl? integer
--- @param desc? string
--- @return string
local function tyfun(ty, lvl, desc)
local r = {} --- @type string[]
r[#r + 1] = '`callable`'
if desc then
r[#r] = r[#r] .. ' ' .. desc
end
for _, arg in ipairs(ty.args) do
local arg_nm, arg_ty, arg_desc = arg[1], arg[2], arg[3]
if arg_nm == 'err' then
arg_ty = 'nil|string'
end
r[#r + 1] = ('%s- `%s`: %s'):format(pad(lvl), arg_nm, Doc.ty(arg_ty, lvl + 1))
if arg_desc then
r[#r] = r[#r] .. ' ' .. arg_desc
end
end
return table.concat(r, '\n')
end
--- @param ty Doc.Type.Table
--- @param lvl? integer
--- @param desc? string
--- @return string
local function tytbl(ty, lvl, desc)
local r = {} --- @type string[]
r[#r + 1] = '`table`'
if desc then
r[#r] = r[#r] .. ' ' .. desc
end
for _, field in ipairs(ty.fields) do
local name, aty, default, adesc = field[1], field[2], field[3], field[4]
r[#r + 1] = ('%s- `%s`: %s'):format(pad(lvl), name, Doc.ty(aty, lvl + 1, adesc))
if default then
r[#r] = ('%s (default: `%s`)'):format(r[#r], default)
end
end
return table.concat(r, '\n')
end
--- @param ty string
--- @param lvl? integer
--- @param desc? string
--- @return string
local function tystr(ty, lvl, desc)
do -- TODO(lewis6991): remove
if ty == 'uv_handle_t' or ty == 'uv_req_t' or ty == 'uv_stream_t' then
return '`userdata` for sub-type of `' .. ty .. '`'
end
ty = ty:gsub('uv_[a-z_]+', '%0 userdata')
ty = ty:gsub('%|', '` or `')
end
if desc then
if desc:match('\n') then
desc = '\n' .. dedent(desc, lvl * 2)
else
desc = ' ' .. desc
end
end
return '`' .. ty .. '`' .. (desc or '')
end
--- @param ty Doc.Type.Dict
--- @param lvl? integer
--- @param desc? string
--- @return string
local function tydict(ty, lvl, desc)
local r = {} --- @type string[]
r[#r + 1] = '`table`'
if desc then
r[#r] = r[#r] .. ' ' .. desc
end
-- TODO(lewis6991): remove
if ty.key == 'integer' then
ty = {
kind = 'dict',
key = '1, 2, 3, ..., n',
value = ty.value,
}
end
r[#r + 1] = ('%s- `[%s]`: %s'):format(pad(lvl), ty.key, Doc.ty(ty.value, lvl + 1))
return table.concat(r, '\n')
end
--- @param ty Doc.Type.Union
--- @param lvl? integer
--- @param desc? string
--- @return string
local function tyunion(ty, lvl, desc)
local tys = ty[1]
local r = {} --- @type string[]
local main_ty --- @type integer?
for i, uty in ipairs(tys) do
if Doc.ty(uty):match('\n') then
main_ty = i
end
r[#r + 1] = Doc.ty(uty, lvl, i == #tys and desc or nil)
end
if main_ty and #tys > 1 then
local others = {} --- @type string[]
for i, oty in ipairs(r) do
if i ~= main_ty then
others[#others + 1] = oty
end
end
local other_ty_str = table.concat(others, ' or ')
-- local other_ty_str = table.concat(others, '|')
return (r[main_ty]:gsub('\n', ' or ' .. other_ty_str .. '\n', 1))
end
return table.concat(r, ' or ')
-- return table.concat(r, '|')
end
local types_noinline = {
threadargs = true,
buffer = true,
}
local ty_dispatch = {
['function'] = tyfun,
['table'] = tytbl,
['dict'] = tydict,
['union'] = tyunion,
}
--- @param ty Doc.Type
--- @param lvl? integer
--- @param desc? string
--- @return string
function Doc.ty(ty, lvl, desc)
-- resolve type
if types[ty] and not types_noinline[ty] and not types[ty].extends then
ty = types[ty]
end
lvl = lvl or 0
local f --- @type fun(ty: Doc.Type, lvl: integer, desc: string): string
if type(ty) == 'string' then
f = tystr
else
f = assert(ty_dispatch[ty.kind])
end
return f(ty, lvl, desc)
end
--- @param out file*
--- @param param Doc.Func.Param
local function write_param(out, param)
out:write(('- `%s`:'):format(param.name))
local ty = param.type
if ty then
out:write(' ', Doc.ty(ty, 1, param.desc))
elseif param.desc then
out:write(' ', param.desc)
end
if param.default then
out:write((' (default: `%s`)'):format(param.default))
end
out:write('\n')
end
--- @param out file*
--- @param x string|Doc.Func.Return[]
--- @param variant? string
local function write_return(out, x, variant)
local variant_str = variant and (' (%s version)'):format(variant) or ''
if type(x) == 'string' then
out:write(('**Returns%s:** %s\n'):format(variant_str, Doc.ty(x)))
elseif type(x) == 'table' then
if x[2] and x[2][2] == 'err' and x[3] and x[3][2] == 'err_name' then
local sty = x[1][1]
sty = remove_nil(sty)
local rty = Doc.ty(sty, nil, 'or `fail`')
out:write(('**Returns%s:** %s\n\n'):format(variant_str, rty))
return
else
local tys = {} --- @type string[]
for _, ret in ipairs(x) do
tys[#tys + 1] = Doc.ty(ret[1])
end
out:write(('**Returns%s:** %s\n'):format(variant_str, table.concat(tys, ', ')))
end
else
out:write('**Returns:** Nothing.\n')
end
out:write('\n')
end
--- @param out file*
--- @param x string
--- @param variant? string
local function write_return_doc(out, x, variant)
local variant_str = variant and (' (%s version)'):format(variant) or ''
out:write(('**Returns%s:**'):format(variant_str))
local r = dedent(x)
out:write(r:sub(1, 1) == '-' and '\n' or ' ')
out:write(r, '\n\n')
end
--- @param func Doc.Func
--- @return string
local function sig(func)
local args = {} --- @type string[]
for _, param in ipairs(func.params or {}) do
local nm = param.name
if isoptional(param.type) then
nm = '[' .. nm .. ']'
end
args[#args + 1] = nm
end
return ('`uv.%s(%s)`'):format(func.name, table.concat(args, ', '))
end
--- @param out file*
--- @param func Doc.Func
--- @param lvl integer
local function write_func(out, func, lvl)
out:write(heading(lvl, sig(func)), '\n\n')
if func.method_form then
out:write(('> method form `%s`\n\n'):format(func.method_form))
end
if func.deprecated then
out:write('**Deprecated:** ', dedent(func.deprecated), '\n\n')
return
end
if func.params then
out:write('**Parameters:**\n')
for _, param in ipairs(func.params) do
write_param(out, param)
end
out:write('\n')
end
if func.desc then
out:write(dedent(func.desc), '\n\n')
end
if func.returns_doc then
write_return_doc(out, func.returns_doc)
elseif func.returns_sync and func.returns_async then
if func.returns_sync_doc then
write_return_doc(out, func.returns_sync_doc, 'sync')
else
write_return(out, func.returns_sync, 'sync')
end
write_return(out, func.returns_async, 'async')
else
write_return(out, func.returns)
end
if func.example then
out:write(dedent(func.example), '\n\n')
end
if func.see then
out:write(('See [%s][].\n\n'):format(func.see))
end
for _, note in ipairs(func.notes or {}) do
local notes = dedent(note)
out:write('**Note**:')
out:write(notes:sub(1, 3) == '1. ' and '\n' or ' ')
out:write(notes, '\n\n')
end
for _, warn in ipairs(func.warnings or {}) do
out:write(('**Warning**: %s\n\n'):format(dedent(warn)))
end
if func.since then
out:write(('**Note**: New in libuv version %s.\n\n'):format(func.since))
end
end
--- @param out file*
--- @param doc Doc
--- @param lvl? integer
function Doc.write(out, doc, lvl)
lvl = lvl or 1
local title = doc.title
if title then
out:write(heading(lvl, title))
out:write('\n\n')
end
local id = doc.id
if id then
local tag = assert(title):match('^`[a-z_]+`') or title
out:write(('[%s]: #%s\n\n'):format(tag, id))
end
if doc.desc then
out:write(dedent(doc.desc), '\n\n')
end
if doc.constants then
for _, constant in ipairs(doc.constants) do
out:write(('- `%s`: "%s"\n'):format(constant[1], constant[2]))
end
out:write('\n')
end
for _, alias in spairs(doc.aliases or {}) do
for _, a in ipairs(alias) do
out:write(('- `%s`: %s\n'):format(a[1], a[2]))
end
out:write('\n')
end
for _, func in ipairs(doc.funcs or {}) do
write_func(out, func, lvl + 1)
end
for _, subsection in ipairs(doc.sections or {}) do
Doc.write(out, subsection, lvl + 1)
end
end
end
local Meta = {}
do -- meta
--- @param x string
--- @return string
local function id(x)
if x == 'repeat' then
x = 'repeat_'
end
return (x:gsub(' ', '_'))
end
--- @param func Doc.Func
--- @param method? {class: string, name: string}
--- @return string
local function sig(func, method)
local args = {} --- @type string[]
for i, param in ipairs(func.params or {}) do
if not (func.returns_async and param.name == 'callback') and (not method or i > 1) then
args[#args + 1] = id(param.name)
end
end
if method then
return ('function %s:%s(%s) end'):format(method.class, method.name, table.concat(args, ', '))
end
return ('function uv.%s(%s) end'):format(func.name, table.concat(args, ', '))
end
--- @param ty Doc.Type
--- @param no_gtypes? boolean
--- @return string
function Meta.ty(ty, no_gtypes)
if type(ty) == 'string' then
if types[ty] then
ty = 'uv.' .. ty
end
return ty
end
if not no_gtypes and gtypes[ty] then
return 'uv.' .. gtypes[ty]
end
if ty.kind == 'dict' then
return ('table<%s, %s>'):format(ty.key, Meta.ty(ty.value))
elseif ty.kind == 'function' then
local r = {} --- @type string[]
for _, arg in pairs(ty.args) do
local arg_nm, arg_ty = arg[1], arg[2]
r[#r + 1] = ('%s: %s'):format(arg_nm, Meta.ty(arg_ty))
end
return ('fun(%s)'):format(table.concat(r, ', '))
elseif ty.kind == 'table' then
if #ty.fields == 0 then
return '{}'
end
local r = {} --- @type string[]
for _, arg in pairs(ty.fields) do
local field_nm, field_ty = arg[1], arg[2]
r[#r + 1] = ('%s: %s'):format(field_nm, Meta.ty(field_ty))
end
return ('{ %s }'):format(table.concat(r, ', '))
elseif ty.kind == 'union' then
local r = {} --- @type string[]
local add_optional = false
for i, uty in ipairs(ty[1]) do
if i == #ty[1] and uty == 'nil' then
add_optional = true
else
r[#r + 1] = Meta.ty(uty)
end
end
return table.concat(r, '|') .. (add_optional and '?' or '')
end
error('unknown type: ' .. ty)
end
--- @param out file*
--- @param x string|Doc.Func.Return[]?
local function write_return(out, x)
if type(x) == 'string' then
out:write('--- @return ', Meta.ty(x), '\n')
elseif type(x) == 'table' then
for _, ret in ipairs(x) do
out:write('--- @return ', Meta.ty(ret[1]))
if ret[2] then
out:write(' ', id(ret[2]))
end
out:write('\n')
end
end
end
--- @param out file*
--- @param func Doc.Func
--- @param x string|Doc.Func.Return[]
local function write_async_overload(out, func, x)
if type(x) == 'string' then
x = { { x } }
end
out:write('--- @overload fun(')
local args = {} --- @type string[]
for _, arg in ipairs(func.params) do
local ty = arg.type
if arg.name == 'callback' then
ty = remove_nil(ty)
end
args[#args + 1] = ('%s: %s'):format(id(arg.name), Meta.ty(ty))
end
out:write(table.concat(args, ', '), '): ')
local ret = {} --- @type string[]
for _, r in ipairs(x) do
ret[#ret + 1] = Meta.ty(r[1])
end
out:write(table.concat(ret, ', '), '\n')
end
--- @param out file*
--- @param str string
local function write_comment(out, str)
--- @diagnostic disable-next-line: no-unknown
for line, nl in str:gmatch('([^\r\n]*)([\n\r]?)') do
if line ~= '' then
out:write('--- ', line, '\n')
elseif nl ~= '' then
out:write('---\n')
end
end
end
local types_written = {} --- @type table<string,true>
--- @param out file*
--- @param nm string
--- @param ty Doc.Type
--- @param nonl? boolean
--- @return boolean
local function write_type(out, nm, ty, nonl)
if types_written[nm] then
return false
end
types_written[nm] = true
if type(ty) == 'string' then
out:write('--- @alias ', Meta.ty(nm), ' ', Meta.ty(ty), '\n\n')
end
if ty.kind == 'dict' then
if type(ty.value) == 'string' then
out:write(
'--- @alias ',
Meta.ty(nm),
' table<',
Meta.ty(ty.key),
',',
Meta.ty(ty.value),
'>\n'
)
else
out:write('--- @class ', Meta.ty(nm), '\n')
out:write('--- @field [', Meta.ty(ty.key), '] ', Meta.ty(ty.value), '\n')
end
elseif ty.kind == 'table' then
out:write('--- @class ', Meta.ty(nm))
if ty.extends then
out:write(' : ', Meta.ty(ty.extends))
end
out:write('\n')
for _, arg in pairs(ty.fields) do
local name, aty, desc = arg[1], arg[2], arg[4]
if desc then
out:write('---\n')
write_comment(out, dedent(desc))
end
out:write('--- @field ', name, ' ', Meta.ty(aty), '\n')
end
elseif ty.kind == 'union' then
local tys = ty[1]
out:write('--- @alias ', Meta.ty(nm), '\n')
for _, uty in ipairs(tys) do
out:write('--- | ', Meta.ty(uty), '\n')
end
elseif ty.kind == 'function' then
out:write('--- @alias ', Meta.ty(nm), '\n')
out:write('--- | ', Meta.ty(ty, true), '\n')
else
error('unknown')
end
if not nonl then
out:write('\n')
end
return true
end
--- @param out file*
--- @param func Doc.Func
--- @param method? { class: string, name: string }
local function write_func(out, func, method)
for nm, ty in spairs(types) do
if nm:sub(1, #func.name) == func.name then
write_type(out, nm, ty)
end
end
if func.deprecated then
out:write('--- @deprecated ', dedent(func.deprecated), '\n')
end
if func.desc then
write_comment(out, dedent(func.desc))
end
if func.example then
out:write('--- Example\n')
write_comment(out, dedent(func.example))
end
for _, note in ipairs(func.notes or {}) do
local notes = dedent(note)
out:write('--- **Note**:\n')
write_comment(out, notes)
end
for _, warn in ipairs(func.warnings or {}) do
out:write('--- **Warning**:\n')
write_comment(out, dedent(warn))
end
-- if method.see then
-- out:write(('--- @see %s\n'):format(method.see))
-- end
-- if method.since then
-- out:write(('**Note**: New in libuv version %s.\n\n'):format(method.since))
-- end
if func.params then
for i, param in ipairs(func.params) do
if not (func.returns_async and param.name == 'callback') and (not method or i > 1) then
out:write('--- @param ', id(param.name), ' ', Meta.ty(param.type))
if param.desc then
if param.desc:match('\n') then
write_comment(out, param.desc)
else
out:write(' ', param.desc)
end
end
out:write('\n')
end
end
end
write_return(out, func.returns or func.returns_sync)
if func.returns_async then
write_async_overload(out, func, func.returns_async)
end
out:write(sig(func, method), '\n\n')
end
--- @param out file*
--- @param doc Doc
local function write_doc(out, doc)
if doc.title then
out:write('--- # ', doc.title, '\n')
end
if doc.desc then
if doc.title then
out:write('---\n')
end
write_comment(out, dedent(doc.desc))
end
if doc.class then
assert(write_type(out, doc.class, types[doc.class], true))
out:write('local ', doc.class, ' = {}\n')
end
for _, constant in ipairs(doc.constants or {}) do
out:write(("uv.constants.%s = '%s'\n"):format(constant[1], constant[2]))
end
for name, alias in spairs(doc.aliases or {}) do
out:write('\n')
out:write(('--- @alias uv.%s\n'):format(name))
for _, a in ipairs(alias) do
out:write(("--- | '%s' # %s\n"):format(a[1], a[2]))
end
end
if doc.funcs then
out:write('\n')
for _, func in ipairs(doc.funcs or {}) do
write_func(out, func)
if func.method_form then
assert(func.params, func.name)
local name = func.method_form:match('^[%w_]+%:([%w_]+)%(')
local class = func.params[1].type
assert(type(class) == 'string')
if write_type(out, class, types[class], true) then
out:write('local ', class, ' = {}\n\n')
end
write_func(out, func, { class = class, name = name })
end
end
end
if doc.sections then
out:write('\n')
for _, subsection in ipairs(doc.sections) do
write_doc(out, subsection)
end
end
out:write('\n')
end
--- @param out file*
--- @param doc Doc
function Meta.write(out, doc)
out:write('--- @meta\n')
out:write('--- @class uv\n')
out:write('local uv = {}\n')
out:write('uv.constants = {}\n')
out:write('\n')
write_doc(out, doc)
for nm, ty in spairs(types) do
write_type(out, nm, ty)
end
end
end
local function main()
-- Generate types for large inline types
gen_types_for_doc(doctop)
local outdoc = assert(io.open('docs/docs.md', 'w'))
Doc.write(outdoc, doctop)
local outmeta = assert(io.open('docs/meta.lua', 'w'))
Meta.write(outmeta, doctop)
end
main()
|