123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- local serpent = require 'serpent'
- -- Helpers
- local function copy(t)
- if type(t) ~= 'table' then return t end
- local result = {}
- for k, v in pairs(t) do
- result[k] = copy(v)
- end
- return result
- end
- local function unindent(code)
- local indent = code:match('^(% +)')
- if indent then
- return code:gsub('\n' .. indent, '\n'):gsub('^' .. indent, ''):gsub('%s*$', '')
- else
- return code
- end
- end
- local function unwrap(str)
- if not str then return str end
- str = unindent(str)
- return str:gsub('([^\n])\n(%S)', function(a, b)
- if b == '-' or b == '>' then
- return a .. '\n' .. b
- else
- return a .. ' ' .. b
- end
- end)
- :gsub('^%s+', '')
- :gsub('%s+$', '')
- end
- local function pluralify(t, key)
- t[key .. 's'] = t[key .. 's'] or (t[key] and { t[key] } or nil)
- t[key] = nil
- return t[key .. 's']
- end
- -- Processors
- local function processExample(example)
- if type(example) == 'string' then
- return {
- code = unindent(example)
- }
- else
- example.description = unwrap(example.description)
- example.code = unindent(example.code)
- end
- return example
- end
- local function processEnum(path, parent)
- local enum = require(path)
- enum.name = path:match('[^/]+$')
- enum.key = enum.name
- enum.module = parent.name
- enum.description = unwrap(enum.description)
- enum.notes = unwrap(enum.notes)
- for _, value in ipairs(enum.values) do
- value.description = unwrap(value.description)
- end
- return enum
- end
- local function processFunction(path, parent)
- local fn = require(path)
- fn.name = path:match('[^/]+$')
- fn.key = parent.name:match('^[A-Z]') and (parent.key .. ':' .. fn.name) or (path:gsub('/', '.'):gsub('callbacks%.', ''))
- fn.description = unwrap(fn.description)
- fn.module = parent.module or parent.key
- fn.notes = unwrap(fn.notes)
- fn.examples = pluralify(fn, 'example')
- for k, example in ipairs(fn.examples or {}) do
- fn.examples[k] = processExample(example)
- end
- if not fn.variants then
- fn.variants = {
- {
- arguments = fn.arguments,
- returns = fn.returns
- }
- }
- else
- for name, arg in pairs(fn.arguments) do
- arg.name = name
- end
- for name, ret in pairs(fn.returns) do
- ret.name = name
- end
- for _, variant in ipairs(fn.variants) do
- for i, name in ipairs(variant.arguments) do
- variant.arguments[i] = copy(fn.arguments[name])
- end
- for i, name in ipairs(variant.returns) do
- variant.returns[i] = copy(fn.returns[name])
- end
- end
- end
- for _, variant in ipairs(fn.variants) do
- local function processTable(t)
- if not t then return end
- for _, field in ipairs(t) do
- field.description = unwrap(field.description)
- end
- t.description = unwrap(t.description)
- processTable(t.table)
- end
- variant.description = unwrap(variant.description)
- for _, arg in ipairs(variant.arguments) do
- arg.description = unwrap(arg.description)
- processTable(arg.table)
- end
- for _, ret in ipairs(variant.returns) do
- ret.description = unwrap(ret.description)
- processTable(ret.table)
- end
- end
- fn.arguments = nil
- fn.returns = nil
- return fn
- end
- local function processObject(path, parent)
- local object = require(path)
- object.key = path:match('[^/]+$')
- object.name = object.key
- object.description = unwrap(object.description)
- object.summary = object.summary or object.description
- object.module = parent.key
- object.methods = {}
- object.constructors = pluralify(object, 'constructor')
- object.notes = unwrap(object.notes)
- object.examples = pluralify(object, 'example')
- if object.sections then
- for _, section in ipairs(object.sections) do
- section.description = unwrap(section.description)
- end
- end
- for k, example in ipairs(object.examples or {}) do
- object.examples[k] = processExample(example)
- end
- for _, file in ipairs(lovr.filesystem.getDirectoryItems(path)) do
- if file ~= 'init.lua' then
- table.insert(object.methods, processFunction(path .. '/' .. file:gsub('%..+$', ''), object))
- end
- end
- table.sort(object.methods, function(a, b) return a.key < b.key end)
- return object
- end
- local function processModule(path)
- local module = require(path .. '.init') -- So we avoid requiring the module itself
- module.key = module.external and path:match('[^/]+$') or path:gsub('/', '.')
- module.name = module.external and module.key or module.key:match('[^%.]+$')
- module.description = unwrap(module.description)
- module.functions = {}
- module.objects = {}
- module.enums = {}
- module.notes = unwrap(module.notes)
- if module.sections then
- for _, section in ipairs(module.sections) do
- section.description = unwrap(section.description)
- end
- end
- module.examples = pluralify(module, 'example')
- for k, example in ipairs(module.examples or {}) do
- module.examples[k] = processExample(example)
- end
- for _, file in ipairs(lovr.filesystem.getDirectoryItems(path)) do
- local childPath = path .. '/' .. file
- local childModule = childPath:gsub('%..+$', '')
- local isFile = lovr.filesystem.isFile(childPath)
- local capitalized = file:match('^[A-Z]')
- if file ~= 'init.lua' and not capitalized and isFile then
- table.insert(module.functions, processFunction(childModule, module))
- elseif capitalized and not isFile then
- table.insert(module.objects, processObject(childModule, module))
- elseif capitalized and isFile then
- table.insert(module.enums, processEnum(childModule, module))
- end
- end
- table.sort(module.functions, function(a, b) return a.key < b.key end)
- table.sort(module.objects, function(a, b) return a.key < b.key end)
- table.sort(module.enums, function(a, b) return a.key < b.key end)
- return module
- end
- function lovr.load()
- local api = {
- modules = {},
- callbacks = {}
- }
- -- Modules
- table.insert(api.modules, processModule('lovr'))
- for _, file in ipairs(lovr.filesystem.getDirectoryItems('lovr')) do
- local path = 'lovr/' .. file
- if file ~= 'callbacks' and file:match('^[a-z]') and lovr.filesystem.isDirectory(path) then
- table.insert(api.modules, processModule(path))
- end
- end
- -- Callbacks
- local callbacks = 'lovr/callbacks'
- for _, file in ipairs(lovr.filesystem.getDirectoryItems(callbacks)) do
- table.insert(api.callbacks, processFunction(callbacks .. '/' .. file:gsub('%.lua', ''), api.modules[1]))
- end
- -- Sort
- table.sort(api.modules, function(a, b) return a.key < b.key end)
- table.sort(api.callbacks, function(a, b) return a.key < b.key end)
- -- Serialize
- local file = io.open(lovr.filesystem.getSource() .. '/init.lua', 'w')
- assert(file, 'Could not open init.lua for writing')
- local keyPriority = {
- name = 1,
- tag = 2,
- summary = 3,
- type = 4,
- description = 5,
- key = 6,
- module = 7,
- arguments = 8,
- returns = 9
- }
- local function sort(keys, t)
- table.sort(keys, function(a, b) return (keyPriority[a] or 1000) < (keyPriority[b] or 1000) end)
- end
- local contents = 'return ' .. serpent.block(api, { comment = false, sortkeys = sort })
- file:write(contents)
- file:close()
- -- Bye
- lovr.event.quit()
- end
|