summaryrefslogtreecommitdiff
path: root/script/provider/build-meta.lua
blob: a1900e5e0e0389401099937e7e12de03b3c15f78 (plain)
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
local fs     = require 'bee.filesystem'
local config = require 'config'
local util   = require 'utility'
local await  = require 'await'

local m = {}

---@class meta
---@field root    string
---@field classes meta.class[]

---@class meta.class
---@field name        string
---@field comment     string
---@field location    string
---@field namespace   string
---@field baseClass   string
---@field attribute   string
---@field integerface string[]
---@field fields      meta.field[]
---@field methods     meta.method[]

---@class meta.field
---@field name     string
---@field typeName string
---@field comment  string
---@field location string

---@class meta.method
---@field name           string
---@field comment        string
---@field location       string
---@field isStatic       boolean
---@field returnTypeName string
---@field params         {name: string, typeName: string}[]

---@param ... string
---@return string
local function mergeString(...)
    local buf = {}
    for i = 1, select('#', ...) do
        local str = select(i, ...)
        if str ~= '' then
            buf[#buf+1] = str
        end
    end
    return table.concat(buf, '.')
end

local function addComments(lines, comment)
    if comment == '' then
        return
    end
    lines[#lines+1] = '--'
    lines[#lines+1] = '--' .. comment:gsub('[\r\n]+$', ''):gsub('\n', '\n--')
    lines[#lines+1] = '--'
end

---@param lines string[]
---@param name string
---@param method meta.method
local function addMethod(lines, name, method)
    if not method.name:match '^[%a_][%w_]*$' then
        return
    end
    addComments(lines, method.comment)
    local params = {}
    for _, param in ipairs(method.params) do
        lines[#lines+1] = ('---@param %s %s'):format(param.name, param.typeName)
        params[#params+1] = param.name
    end
    if  method.returnTypeName ~= ''
    and method.returnTypeName ~= 'Void' then
        lines[#lines+1] = ('---@return %s'):format(method.returnTypeName)
    end
    lines[#lines+1] = ('function %s%s%s(%s) end'):format(
        name,
        method.isStatic and ':' or '.',
        method.name,
        table.concat(params, ', ')
    )
    lines[#lines+1] = ''
end

---@param root string
---@param class meta.class
---@return string
local function buildText(root, class)
    local lines = {}

    addComments(lines, class.comment)
    if class.baseClass == '' then
        lines[#lines+1] = ('---@class %s'):format(mergeString(class.namespace, class.name))
    else
        lines[#lines+1] = ('---@class %s: %s'):format(mergeString(class.namespace, class.name), class.baseClass)
    end

    for _, field in ipairs(class.fields) do
        addComments(lines, field.comment)
        lines[#lines+1] = ('---@source %s'):format(field.location:gsub('#', ':'))
        lines[#lines+1] = ('---@field %s %s'):format(field.name, field.typeName)
    end

    local name = mergeString(root, class.namespace, class.name)
    lines[#lines+1] = ('%s = {}'):format(name)
    lines[#lines+1] = ''

    for _, method in ipairs(class.methods) do
        addMethod(lines, name, method)
    end

    return table.concat(lines, '\n')
end

local function buildRootText(api)
    local lines = {}

    lines[#lines+1] = ('---@class %s'):format(api.root)
    lines[#lines+1] = ('%s = {}'):format(api.root)
    lines[#lines+1] = ''
    return table.concat(lines, '\n')
end

---@async
---@param name string
---@param api meta
---@return string
function m.build(name, api)
    local encoding = config.get(nil, 'Lua.runtime.fileEncoding')
    local fileDir = fs.path(METAPATH) / (name .. ' ' .. encoding)
    fs.create_directories(fileDir)

    local files = util.multiTable(2, function ()
        return { '---@meta' }
    end)

    files[api.root][#files[api.root]+1] = buildRootText(api)

    for _, class in ipairs(api.classes) do
        local space = class.namespace ~= '' and class.namespace or api.root
        local text = buildText(api.root, class)
        files[space][#files[space]+1] = text
        await.delay()
    end

    for space, texts in pairs(files) do
        util.saveFile((fileDir / (space .. '.lua')):string(), table.concat(texts, '\n\n'))
    end

    return fileDir:string()
end

return m