Move to an AST like data structure #76
9
.busted
9
.busted
|
@ -1,3 +1,7 @@
|
||||||
|
if os.getenv "LOCAL_LUA_DEBUGGER_VSCODE" == "1" then
|
||||||
|
require("lldebugger").start()
|
||||||
|
end
|
||||||
|
|
||||||
require("tl").loader()
|
require("tl").loader()
|
||||||
|
|
||||||
local version <const> = _VERSION:match "%d+%.%d+"
|
local version <const> = _VERSION:match "%d+%.%d+"
|
||||||
|
@ -10,11 +14,14 @@ local function lua_module_paths(module_base_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
default = {
|
_all = {
|
||||||
lpath = lua_module_paths("lua_modules/share/lua/" .. version)
|
lpath = lua_module_paths("lua_modules/share/lua/" .. version)
|
||||||
.. lua_module_paths "types"
|
.. lua_module_paths "types"
|
||||||
.. lua_module_paths "./src/awesomewm.d.tl",
|
.. lua_module_paths "./src/awesomewm.d.tl",
|
||||||
cpath = "lua_modules/lib/lua/" .. version .. "/?.so;",
|
cpath = "lua_modules/lib/lua/" .. version .. "/?.so;",
|
||||||
loaders = { "teal" },
|
loaders = { "teal" },
|
||||||
},
|
},
|
||||||
|
coverage = {
|
||||||
|
coverage = true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,7 @@ charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
[*.lua]
|
[*.{lua,tl,d.tl,busted,luacheckrc,luacov}]
|
||||||
indent_size = 3
|
|
||||||
|
|
||||||
[*.{tl,d.tl}]
|
|
||||||
indent_size = 3
|
|
||||||
|
|
||||||
[.busted]
|
|
||||||
indent_size = 3
|
indent_size = 3
|
||||||
|
|
||||||
[justfile]
|
[justfile]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
lua_modules
|
lua_modules
|
||||||
generated
|
generated
|
||||||
build
|
build
|
||||||
|
luacov
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
-- -- Per https://github.com/lunarmodules/luacov/blob/c915f4b95e8df5dbfaf2b1f04f0b7da04506fc7a/src/luacov/reporter.lua#L102
|
||||||
|
-- -- > The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.
|
||||||
|
-- -- So I'm ok with including it here, since it's already an hard dependency.
|
||||||
|
-- local lfs = require "lfs"
|
||||||
|
|
||||||
|
-- local function walk(dir, callback)
|
||||||
|
-- for file in lfs.dir(dir) do
|
||||||
|
-- if file ~= "." and file ~= ".." then
|
||||||
|
-- local path = dir .. "/" .. file
|
||||||
|
-- local attr = lfs.attributes(path)
|
||||||
|
-- if attr.mode == "directory" then
|
||||||
|
-- walk(path, callback)
|
||||||
|
-- else
|
||||||
|
-- callback(path)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local teal_files = {}
|
||||||
|
-- for _, path in pairs { "spec", "src" } do
|
||||||
|
-- walk(path, function(file)
|
||||||
|
-- if file:match "%.tl$" then
|
||||||
|
-- table.insert(teal_files, file)
|
||||||
|
-- end
|
||||||
|
-- end)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
return {
|
||||||
|
statsfile = "luacov/luacov.stats.out",
|
||||||
|
reporter = "html",
|
||||||
|
reportfile = "luacov/luacov.report.html",
|
||||||
|
include = {
|
||||||
|
"spec",
|
||||||
|
"src",
|
||||||
|
},
|
||||||
|
exclude = {
|
||||||
|
"lua_modules",
|
||||||
|
"spec/tlconfig.lua",
|
||||||
|
"src/awesome.d.tl/types",
|
||||||
|
"types",
|
||||||
|
},
|
||||||
|
-- runreport = true, -- For some reason, it makes my computer crash
|
||||||
|
-- includeuntestedfiles = teal_files,
|
||||||
|
includeuntestedfiles = true,
|
||||||
|
}
|
|
@ -8,7 +8,21 @@
|
||||||
"program": {
|
"program": {
|
||||||
"command": "just"
|
"command": "just"
|
||||||
},
|
},
|
||||||
"args": ["debug"]
|
"args": ["run"],
|
||||||
|
"scriptFiles": ["${workspaceFolder}/**/*.tl"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug specs",
|
||||||
|
"type": "lua-local",
|
||||||
|
"request": "launch",
|
||||||
|
"program": {
|
||||||
|
"command": "just"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"_spec" // Adapt to the spec to debug
|
||||||
|
],
|
||||||
|
"scriptFiles": ["${workspaceFolder}/**/*.tl"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.formatOnPaste": true,
|
|
||||||
"[markdown]": {
|
"[markdown]": {
|
||||||
"editor.wordWrap": "on",
|
"editor.acceptSuggestionOnEnter": "off",
|
||||||
"editor.renderWhitespace": "all",
|
"editor.renderWhitespace": "all",
|
||||||
"editor.acceptSuggestionOnEnter": "off"
|
"editor.wordWrap": "on"
|
||||||
},
|
},
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"aire-one",
|
"aire-one",
|
||||||
|
@ -13,10 +11,12 @@
|
||||||
"ansicolors",
|
"ansicolors",
|
||||||
"awesomewm",
|
"awesomewm",
|
||||||
"buildx",
|
"buildx",
|
||||||
|
"concat",
|
||||||
"dryrun",
|
"dryrun",
|
||||||
"getcontent",
|
"getcontent",
|
||||||
"gitea",
|
"gitea",
|
||||||
"htmlparser",
|
"htmlparser",
|
||||||
|
"includeuntestedfiles",
|
||||||
"isdir",
|
"isdir",
|
||||||
"justfile",
|
"justfile",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -24,24 +24,37 @@
|
||||||
"lpath",
|
"lpath",
|
||||||
"Luacheck",
|
"Luacheck",
|
||||||
"luacheckrc",
|
"luacheckrc",
|
||||||
|
"luacov",
|
||||||
"luafilesystem",
|
"luafilesystem",
|
||||||
"lualogging",
|
"lualogging",
|
||||||
"Luarocks",
|
"Luarocks",
|
||||||
"luasec",
|
"luasec",
|
||||||
"luasocket",
|
"luasocket",
|
||||||
"mkdir",
|
"mkdir",
|
||||||
|
"modname",
|
||||||
|
"reportfile",
|
||||||
"rockspec",
|
"rockspec",
|
||||||
|
"rstrip",
|
||||||
|
"runreport",
|
||||||
"setopt",
|
"setopt",
|
||||||
|
"statsfile",
|
||||||
|
"stringx",
|
||||||
"Stylua",
|
"Stylua",
|
||||||
|
"sublist",
|
||||||
"tablex",
|
"tablex",
|
||||||
|
"tbody",
|
||||||
"tmpl",
|
"tmpl",
|
||||||
"wibox",
|
"wibox",
|
||||||
"woodpeckerci",
|
"woodpeckerci",
|
||||||
"writefunction"
|
"writefunction"
|
||||||
],
|
],
|
||||||
|
"debug.allowBreakpointsEverywhere": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
|
".busted": "lua",
|
||||||
".luacheckrc": "lua",
|
".luacheckrc": "lua",
|
||||||
"*.rockspec": "lua",
|
".luacov": "lua",
|
||||||
".busted": "lua"
|
"*.rockspec": "lua"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
justfile
15
justfile
|
@ -47,13 +47,10 @@ validate:
|
||||||
awesomerc.tl
|
awesomerc.tl
|
||||||
# `find . -type f -iname '*.d.tl' | xargs`
|
# `find . -type f -iname '*.d.tl' | xargs`
|
||||||
|
|
||||||
test:
|
test PATTERN="_spec":
|
||||||
busted
|
busted --pattern={{ PATTERN }}
|
||||||
|
|
||||||
# TODO : how to run a debugger on Teal code?
|
# Requires a patched version of luacov (https://github.com/lunarmodules/luacov/issues/98#issuecomment-1530491759)
|
||||||
debug:
|
coverage:
|
||||||
{{ lua }} debug.lua build/awesomewm.d.tl/init.lua
|
busted --coverage
|
||||||
debug-gen:
|
luacov
|
||||||
cyan gen --output set_paths.lua --gen-compat "off" set_paths.tl
|
|
||||||
sed -i 's/"src\/awesomewm.d.tl"/"build\/awesomewm.d.tl"/g' set_paths.lua
|
|
||||||
stylua set_paths.lua
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
local assert = require("luassert")
|
|
||||||
|
|
||||||
describe("Busted unit testing framework", function()
|
|
||||||
describe("should be awesome", function()
|
|
||||||
it("should be easy to use", function()
|
|
||||||
assert.truthy "Yup."
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("should have lots of features", function()
|
|
||||||
-- deep check comparisons!
|
|
||||||
assert.same({ table = "great" }, { table = "great" })
|
|
||||||
|
|
||||||
-- or check by reference!
|
|
||||||
assert.not_equal({ table = "great" }, { table = "great" })
|
|
||||||
|
|
||||||
assert.truthy "this is a string" -- truthy: not false or nil
|
|
||||||
|
|
||||||
assert.is_true(1 == 1)
|
|
||||||
|
|
||||||
assert.falsy(nil)
|
|
||||||
assert.has_error(function()
|
|
||||||
error "Wat"
|
|
||||||
end, "Wat")
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("should provide some shortcuts to common functions", function()
|
|
||||||
assert.is_unique { { thing = 1 }, { thing = 2 }, { thing = 3 } }
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
end)
|
|
|
@ -1,10 +0,0 @@
|
||||||
local assert = require("luassert")
|
|
||||||
local utils = require("utils")
|
|
||||||
|
|
||||||
describe("test", function()
|
|
||||||
it("has_item", function()
|
|
||||||
local t = {1, 2, 3}
|
|
||||||
assert.equal(utils.has_item(t, 1), 1)
|
|
||||||
assert.is_nil(utils.has_item(t, 4))
|
|
||||||
end)
|
|
||||||
end)
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
local assert = require("luassert")
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
local stringx = require("pl.stringx")
|
||||||
|
local teal_type_definition_printer = require("printer.teal_type_definition")
|
||||||
|
|
||||||
|
local printer = teal_type_definition_printer.printer
|
||||||
|
|
||||||
|
-- We need to remove the last newline inserted by Penlight's dedent
|
||||||
|
local function dedent(str: string): string
|
||||||
|
return (stringx.dedent(str):sub(1, -2))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gen(ast: Node, expected_code: string): function()
|
||||||
|
return function()
|
||||||
|
local generated = printer(ast)
|
||||||
|
assert.same(dedent(expected_code), generated)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("Teal type definition Printer", function()
|
||||||
|
it("should print a simple module type definition", gen(
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
dependencies = {},
|
||||||
|
name = "Empty",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
|
||||||
|
local record Empty
|
||||||
|
end
|
||||||
|
|
||||||
|
return Empty
|
||||||
|
]]))
|
||||||
|
|
||||||
|
it("should print an Enum exposed by the module", gen(
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "widget::layout_changed",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "widget::redraw_needed",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dependencies = {},
|
||||||
|
name = "Signal_Module",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
|
||||||
|
local record Signal_Module
|
||||||
|
enum Signal
|
||||||
|
"widget::layout_changed"
|
||||||
|
"widget::redraw_needed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Signal_Module
|
||||||
|
]]))
|
||||||
|
|
||||||
|
it("should print a property exposed by the module", gen(
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "text",
|
||||||
|
types = { "string", "nil" },
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies = {},
|
||||||
|
name = "Property_Module",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
|
||||||
|
local record Property_Module
|
||||||
|
text: string | nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return Property_Module
|
||||||
|
]]))
|
||||||
|
|
||||||
|
it("should print a function exposed by the module", gen(
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "integer" },
|
||||||
|
name = "pid",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "integer" },
|
||||||
|
name = "sig",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_types = { "boolean" },
|
||||||
|
name = "kill",
|
||||||
|
token = "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dependencies = {},
|
||||||
|
name = "Function_Module",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
|
||||||
|
local record Function_Module
|
||||||
|
kill: function(pid: integer, sig: integer): boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
return Function_Module
|
||||||
|
]]))
|
||||||
|
|
||||||
|
it("should print nested Record exposed by the module", gen(
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Nested",
|
||||||
|
token = "record",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies = {},
|
||||||
|
name = "Nested_Module",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
|
||||||
|
local record Nested_Module
|
||||||
|
record Nested
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Nested_Module
|
||||||
|
]]))
|
||||||
|
|
||||||
|
it("should print require statement for module's dependencies", gen(
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
dependencies = {
|
||||||
|
dep = "dep",
|
||||||
|
deeper = "path.dep.deeper",
|
||||||
|
},
|
||||||
|
name = "Module",
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
[[
|
||||||
|
-- This file was auto-generated.
|
||||||
|
local type deeper = require("path.dep.deeper")
|
||||||
|
local type dep = require("dep")
|
||||||
|
|
||||||
|
local record Module
|
||||||
|
end
|
||||||
|
|
||||||
|
return Module
|
||||||
|
]]))
|
||||||
|
end)
|
|
@ -0,0 +1,823 @@
|
||||||
|
local assert = require("luassert")
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
local scraper = require("scraper.module_doc")
|
||||||
|
|
||||||
|
local get_doc_from_page = scraper.get_doc_from_page
|
||||||
|
|
||||||
|
local function test(html: string, module_path: string, expected_ast: Node, expected_other_nodes: { Node } | nil): function()
|
||||||
|
return function()
|
||||||
|
local ast <const>, other_nodes <const> = get_doc_from_page(html, module_path)
|
||||||
|
assert.same(expected_ast, ast)
|
||||||
|
assert.same(expected_other_nodes or {}, other_nodes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("Scrap documentation", function()
|
||||||
|
it("should return a valid AST for an empty module", test(
|
||||||
|
"",
|
||||||
|
"empty",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Empty",
|
||||||
|
module_path = "empty",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce Variable and `property::` Signal nodes", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Object_properties"></a>Object properties
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="value" href="#value">🔗</a>
|
||||||
|
<strong>value</strong>
|
||||||
|
<span class="proptype"><span class="summary_type">number</span></span>
|
||||||
|
<span class="baseclass"> · 1 signal </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<h3>Constraints:</h3>
|
||||||
|
<span class="property_type">
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody><tr class="">
|
||||||
|
<td style="padding-left:0px;">
|
||||||
|
<i>
|
||||||
|
Default value
|
||||||
|
</i>
|
||||||
|
</td>
|
||||||
|
<td>: <code>0</code></td>
|
||||||
|
</tr><tr>
|
||||||
|
</tr><tr class="">
|
||||||
|
<td style="padding-left:0px;">
|
||||||
|
<i>
|
||||||
|
Negative allowed
|
||||||
|
</i>
|
||||||
|
</td>
|
||||||
|
<td>: true</td>
|
||||||
|
</tr><tr>
|
||||||
|
</tr></tbody></table>
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"property_signal",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "property::value",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "value",
|
||||||
|
types = { "number" },
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Property_signal",
|
||||||
|
module_path = "property_signal",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce Enum nodes when an Object Property type is a String with constraints", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Object_properties"></a>Object properties
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a
|
||||||
|
class="copy-link js-copy-link"
|
||||||
|
name="horizontal_fit_policy"
|
||||||
|
href="#horizontal_fit_policy"
|
||||||
|
>🔗</a
|
||||||
|
>
|
||||||
|
<strong>horizontal_fit_policy</strong>
|
||||||
|
<span class="proptype"><span class="summary_type">string</span></span>
|
||||||
|
<span class="baseclass"> · 1 signal </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<span class="property_type">
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody>
|
||||||
|
<tr class="">
|
||||||
|
<td style="padding-left: 0px">
|
||||||
|
<i> Default value </i>
|
||||||
|
</td>
|
||||||
|
<td>: <code>"auto"</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
<tr class="">
|
||||||
|
<td style="padding-left: 0px">
|
||||||
|
<i> Valid values: </i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
<tr class="see_also_sublist">
|
||||||
|
<td style="padding-left: 15px">
|
||||||
|
<i>
|
||||||
|
<code>"auto"</code>
|
||||||
|
</i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
: Honor the <code>resize</code> variable and preserve the aspect
|
||||||
|
ratio.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
<tr class="see_also_sublist">
|
||||||
|
<td style="padding-left: 15px">
|
||||||
|
<i>
|
||||||
|
<code>"none"</code>
|
||||||
|
</i>
|
||||||
|
</td>
|
||||||
|
<td>: Do not resize at all.</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
<tr class="see_also_sublist">
|
||||||
|
<td style="padding-left: 15px">
|
||||||
|
<i>
|
||||||
|
<code>"fit"</code>
|
||||||
|
</i>
|
||||||
|
</td>
|
||||||
|
<td>: Resize to the widget width.</td>
|
||||||
|
</tr>
|
||||||
|
<tr></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"property_enum",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "property::horizontal_fit_policy",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "auto",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "none",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "fit",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Horizontal_fit_policy",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "horizontal_fit_policy",
|
||||||
|
types = { "Horizontal_fit_policy" },
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Property_enum",
|
||||||
|
module_path = "property_enum",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce a `string` typed Variable node when a String Property has no constraint", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Object_properties"></a>Object properties
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="markup" href="#markup">🔗</a>
|
||||||
|
<strong>markup</strong>
|
||||||
|
<span class="proptype"><span class="summary_type">string</span></span>
|
||||||
|
<span class="baseclass"> · 1 signal </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<span class="property_type">string</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"property_string",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "property::markup",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "markup",
|
||||||
|
types = { "string" },
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Property_string",
|
||||||
|
module_path = "property_string",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should provide a Function node with the `self` as the first positional parameter", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header"><a name="Object_methods"></a>Object methods</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="swap" href="#swap">🔗</a>
|
||||||
|
<strong
|
||||||
|
>:swap <span class="function_args"> <b>(</b>tag2<b>)</b></span></strong
|
||||||
|
>
|
||||||
|
<span class="proptype"></span>
|
||||||
|
<span class="baseclass"> </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody>
|
||||||
|
<tr class="param_header">
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Type(s)</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">tag2</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">tag</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">The second tag</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"awful.tag",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "Tag" },
|
||||||
|
name = "self",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "tag" }, -- This needs to be fixed : tag -> Tag
|
||||||
|
name = "tag2",
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
return_types = {},
|
||||||
|
name = "swap",
|
||||||
|
token = "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Tag",
|
||||||
|
module_path = "awful.tag",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce Signal nodes", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header"><a name="Signals"></a>Signals</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a
|
||||||
|
class="copy-link js-copy-link"
|
||||||
|
name="widget::layout_changed"
|
||||||
|
href="#widget::layout_changed"
|
||||||
|
>🔗</a
|
||||||
|
>
|
||||||
|
<strong>widget::layout_changed</strong>
|
||||||
|
<span class="baseclass"> · Inherited from wibox.widget.base </span>
|
||||||
|
</dt>
|
||||||
|
<dd></dd>
|
||||||
|
<dt>
|
||||||
|
<a
|
||||||
|
class="copy-link js-copy-link"
|
||||||
|
name="widget::redraw_needed"
|
||||||
|
href="#widget::redraw_needed"
|
||||||
|
>🔗</a
|
||||||
|
>
|
||||||
|
<strong>widget::redraw_needed</strong>
|
||||||
|
<span class="baseclass"> · Inherited from wibox.widget.base </span>
|
||||||
|
</dt>
|
||||||
|
<dd></dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"signal",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
name = "widget::layout_changed",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "widget::redraw_needed",
|
||||||
|
token = "identifier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Signal",
|
||||||
|
module_path = "signal",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce Function nodes", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Static_module_functions"></a>Static module functions
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="kill" href="#kill">🔗</a>
|
||||||
|
<strong
|
||||||
|
><span class="function_modname">awesome.</span>kill
|
||||||
|
<span class="function_args"> <b>(</b>pid, sig<b>)</b></span></strong
|
||||||
|
>
|
||||||
|
<span class="proptype"
|
||||||
|
><span class="summary_type"> -> boolean</span></span
|
||||||
|
>
|
||||||
|
<span class="baseclass"> </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Send a signal to a process.
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody>
|
||||||
|
<tr class="param_header">
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Type(s)</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">pid</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">integer</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">
|
||||||
|
Process identifier. 0 and negative values have special meaning. See
|
||||||
|
<code>man 3 kill</code>.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">sig</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">integer</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">
|
||||||
|
Signal number. See
|
||||||
|
<a href="../core_components/awesome.html#unix_signal"
|
||||||
|
>awesome.unix_signal</a
|
||||||
|
>
|
||||||
|
for a list of signals.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h3>Returns:</h3>
|
||||||
|
<ol>
|
||||||
|
<span class="types"><span class="type">boolean</span></span>
|
||||||
|
true if the signal was successfully sent, else false
|
||||||
|
</ol>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"awesome", -- The module name must be the same as the module name in the doc
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "integer" },
|
||||||
|
name = "pid",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "integer" },
|
||||||
|
name = "sig",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_types = { "boolean" },
|
||||||
|
name = "kill",
|
||||||
|
token = "function",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Awesome",
|
||||||
|
module_path = "awesome",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should produce a Record node when a function parameter is a named-parameter-table", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Static_module_functions"></a>Static module functions
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a
|
||||||
|
class="copy-link js-copy-link"
|
||||||
|
name="awful.screen.focused"
|
||||||
|
href="#awful.screen.focused"
|
||||||
|
>🔗</a
|
||||||
|
>
|
||||||
|
<strong
|
||||||
|
>awful.screen.focused
|
||||||
|
<span class="function_named_args"><b>{</b>[args]<b>}</b></span></strong
|
||||||
|
>
|
||||||
|
<span class="proptype"
|
||||||
|
><span class="summary_type"> -> nil <i>or</i> screen</span></span
|
||||||
|
>
|
||||||
|
<span class="baseclass"> </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody>
|
||||||
|
<tr class="param_header">
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Type(s)</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Default value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">args</span></td>
|
||||||
|
<td><span class="chips">Optional</span></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">table</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description"></td>
|
||||||
|
<td><span class="not_applicable">Undefined</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="see_also_sublist">
|
||||||
|
<td><span class="parameter">client</span></td>
|
||||||
|
<td><span class="chips">Optional</span></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">boolean</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">
|
||||||
|
Use the client screen instead of the mouse screen.
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="default_value"><code>false</code></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="see_also_sublist">
|
||||||
|
<td><span class="parameter">mouse</span></td>
|
||||||
|
<td><span class="chips">Optional</span></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"><span class="type">boolean</span></span>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">Use the mouse screen</td>
|
||||||
|
<td>
|
||||||
|
<span class="default_value"><code>true</code></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h3>Returns:</h3>
|
||||||
|
<ol>
|
||||||
|
<span class="types"
|
||||||
|
>optional
|
||||||
|
<a class="type" href="../core_components/screen.html#screen"
|
||||||
|
>screen</a
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
The focused screen object, or
|
||||||
|
<code>nil</code>
|
||||||
|
in case no screen is present currently.
|
||||||
|
</ol>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"awful.screen",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
types = { "boolean" },
|
||||||
|
name = "client",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "boolean" },
|
||||||
|
name = "mouse",
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Focused_Args",
|
||||||
|
token = "record",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "Focused_Args" },
|
||||||
|
name = "args",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_types = { "screen" },
|
||||||
|
name = "focused",
|
||||||
|
token = "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Screen",
|
||||||
|
module_path = "awful.screen",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should go back to a table typed parameter when the record is empty", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header "><a name="Static_module_functions"></a>Static module functions</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="crush" href="#crush">🔗</a>
|
||||||
|
<strong><span class="function_modname">gears.table.</span>crush <span class="function_args"> <b>(</b>target, source, <span class="optional_param">raw</span><b>)</b></span></strong>
|
||||||
|
<span class="proptype"><span class="summary_type"> -> table</span></span>
|
||||||
|
<span class="baseclass">
|
||||||
|
</span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
</p><h3>Parameters:</h3>
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody><tr class="param_header">
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Type(s)</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Default value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">target</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td><span class="types"><a class="type" href="https://www.lua.org/manual/5.3/manual.html#6.6" target="_blank">table</a></span></td>
|
||||||
|
<td class="see_also_description"> The target table. Values from <code>source</code> will be copied
|
||||||
|
into this table.</td>
|
||||||
|
<td><span class="not_applicable" title="This parameter is mandatory">Not applicable</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">source</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td><span class="types"><a class="type" href="https://www.lua.org/manual/5.3/manual.html#6.6" target="_blank">table</a></span></td>
|
||||||
|
<td class="see_also_description"> The source table. Its values will be copied into
|
||||||
|
<code>target</code>.</td>
|
||||||
|
<td><span class="not_applicable" title="This parameter is mandatory">Not applicable</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">raw</span></td>
|
||||||
|
<td><span class="chips">Optional</span></td>
|
||||||
|
<td><span class="types"><span class="type">bool</span></span></td>
|
||||||
|
<td class="see_also_description"> If <code>true</code>, values will be assigned with <a href="https://www.lua.org/manual/5.3/manual.html#pdf-rawset" target="_blank">rawset</a>.
|
||||||
|
This will bypass metamethods on <code>target</code>.</td>
|
||||||
|
<td><span class="default_value"><code>false</code></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<h3>Returns:</h3>
|
||||||
|
<ol>
|
||||||
|
<span class="types"><a class="type" href="https://www.lua.org/manual/5.3/manual.html#6.6" target="_blank">table</a></span>
|
||||||
|
The target table.
|
||||||
|
</ol>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"gears.table",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "table" },
|
||||||
|
name = "target",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "table" },
|
||||||
|
name = "source",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "bool" },
|
||||||
|
name = "raw",
|
||||||
|
token = "variable",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
return_types = { "table" },
|
||||||
|
name = "crush",
|
||||||
|
token = "function",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name = "Table",
|
||||||
|
module_path = "gears.table",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should go back to a table typed parameter when the record is empty and it's the last parameter", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header"><a name="Object_methods"></a>Object methods</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="tags" href="#tags">🔗</a>
|
||||||
|
<strong
|
||||||
|
>:tags
|
||||||
|
<span class="function_args"> <b>(</b>tags_table<b>)</b></span></strong
|
||||||
|
>
|
||||||
|
<span class="proptype"
|
||||||
|
><span class="summary_type"> -> table</span></span
|
||||||
|
>
|
||||||
|
<span class="baseclass"> · 1 signal </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<table class="see_also">
|
||||||
|
<tbody>
|
||||||
|
<tr class="param_header">
|
||||||
|
<th>Name</th>
|
||||||
|
<th></th>
|
||||||
|
<th>Type(s)</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="parameter">tags_table</span></td>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<span class="types"
|
||||||
|
><a
|
||||||
|
class="type"
|
||||||
|
href="https://www.lua.org/manual/5.3/manual.html#6.6"
|
||||||
|
target="_blank"
|
||||||
|
>table</a
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td class="see_also_description">
|
||||||
|
A table with tags to set, or <code>nil</code> to get the current
|
||||||
|
tags.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h3>Returns:</h3>
|
||||||
|
<ol>
|
||||||
|
<span class="types"
|
||||||
|
><a
|
||||||
|
class="type"
|
||||||
|
href="https://www.lua.org/manual/5.3/manual.html#6.6"
|
||||||
|
target="_blank"
|
||||||
|
>table</a
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
A table with all tags.
|
||||||
|
</ol>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"awful.client",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameters = {
|
||||||
|
{
|
||||||
|
types = { "Client" },
|
||||||
|
name = "self",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
types = { "table" },
|
||||||
|
name = "tags_table",
|
||||||
|
token = "variable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
return_types = { "table" },
|
||||||
|
name = "tags",
|
||||||
|
token = "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Client",
|
||||||
|
module_path = "awful.client",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
}))
|
||||||
|
|
||||||
|
it("should return Function nodes with the `other_nodes` list when the function module name doesn't match the module name", test(
|
||||||
|
[[
|
||||||
|
<h2 class="section-header">
|
||||||
|
<a name="Static_module_functions"></a>Static module functions
|
||||||
|
</h2>
|
||||||
|
<dl class="function">
|
||||||
|
<dt>
|
||||||
|
<a class="copy-link js-copy-link" name="instances" href="#instances">🔗</a>
|
||||||
|
<strong
|
||||||
|
><span class="function_modname">client.</span>instances
|
||||||
|
<span class="function_args"> <b>(</b><b>)</b></span></strong
|
||||||
|
>
|
||||||
|
<span class="proptype"
|
||||||
|
><span class="summary_type"> -> integer</span></span
|
||||||
|
>
|
||||||
|
<span class="baseclass"> </span>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Get the number of instances.
|
||||||
|
<h3>Returns:</h3>
|
||||||
|
<ol>
|
||||||
|
<span class="types"><span class="type">integer</span></span>
|
||||||
|
The number of client objects alive.
|
||||||
|
</ol>
|
||||||
|
<span id="item826" class="hide_extra"> </span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
]],
|
||||||
|
"awful.client",
|
||||||
|
{
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
children = {},
|
||||||
|
name = "Signal",
|
||||||
|
token = "enum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name = "Client",
|
||||||
|
module_path = "awful.client",
|
||||||
|
dependencies = {},
|
||||||
|
token = "module",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
parameters = {},
|
||||||
|
return_types = { "integer" },
|
||||||
|
name = "client.instances",
|
||||||
|
token = "function",
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
end)
|
|
@ -0,0 +1,81 @@
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
|
||||||
|
local basic_nodes <total>: { Node.Token : function(name: string, ...: any): Node } = {
|
||||||
|
module = function(name: string, module_path: string): Node
|
||||||
|
return {
|
||||||
|
token = "module",
|
||||||
|
name = name,
|
||||||
|
module_path = module_path,
|
||||||
|
dependencies = {},
|
||||||
|
children = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
record = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "record",
|
||||||
|
name = name,
|
||||||
|
children = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
enum = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "enum",
|
||||||
|
name = name,
|
||||||
|
children = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
identifier = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "identifier",
|
||||||
|
name = name,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
variable = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "variable",
|
||||||
|
name = name,
|
||||||
|
types = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
["function"] = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "function",
|
||||||
|
name = name,
|
||||||
|
parameters = {},
|
||||||
|
return_types = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
metamethod = function(name: string): Node
|
||||||
|
return {
|
||||||
|
token = "metamethod",
|
||||||
|
name = name,
|
||||||
|
parameters = {},
|
||||||
|
return_types = {},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function create_node(token: Node.Token, name: string, ...: any): Node
|
||||||
|
local node = basic_nodes[token](name, ...)
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
local function iter_children(node: Node): function(): integer, Node
|
||||||
|
if node.children == nil then
|
||||||
|
return function(): integer, Node end
|
||||||
|
end
|
||||||
|
return ipairs(node.children)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function in_order_visitor(node: Node, visitor: function(Node))
|
||||||
|
for _, child in iter_children(node) do
|
||||||
|
in_order_visitor(child, visitor)
|
||||||
|
end
|
||||||
|
visitor(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
create_node = create_node,
|
||||||
|
iter_children = iter_children,
|
||||||
|
in_order_visitor = in_order_visitor,
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
local type Dag = require("types.Dag")
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
local utils = require("utils")
|
||||||
|
|
||||||
|
local function new(): Dag
|
||||||
|
local dag <total>: Dag = {
|
||||||
|
modules = {},
|
||||||
|
global_nodes = {},
|
||||||
|
}
|
||||||
|
return dag
|
||||||
|
end
|
||||||
|
|
||||||
|
local function push_module(dag: Dag, module_path: string, root_node: Node)
|
||||||
|
dag.modules[module_path] = root_node
|
||||||
|
end
|
||||||
|
|
||||||
|
local function push_global_nodes(dag: Dag, nodes: { Node })
|
||||||
|
utils.spread(dag.global_nodes, nodes)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function iter_modules(dag: Dag): function(): string, Node
|
||||||
|
return pairs(dag.modules)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
new = new,
|
||||||
|
push_module = push_module,
|
||||||
|
push_global_nodes = push_global_nodes,
|
||||||
|
iter_modules = iter_modules,
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
return {
|
|
||||||
global_env_def = require "generator.global_env_def",
|
|
||||||
module_init_definition = require "generator.module_init_definition",
|
|
||||||
snippets = require "generator.snippets",
|
|
||||||
teal_type_definitions = require "generator.teal_type_definitions",
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
local Module_Doc = require "entity.Module_Doc"
|
|
||||||
local template = require "pl.template"
|
|
||||||
local utils = require "utils"
|
|
||||||
local snippets = require "generator.snippets"
|
|
||||||
|
|
||||||
-- The long therm goal is to have so many `snippets.render_*` functions that
|
|
||||||
-- we can render the whole file with the smallest template possible.
|
|
||||||
local tmpl = [[
|
|
||||||
-- Auto generated file (Do not manually edit this file!)
|
|
||||||
|
|
||||||
# if module.requires:len() ~= 0 then
|
|
||||||
$(snippets.render_requires(module.requires))
|
|
||||||
# end -- /requires
|
|
||||||
|
|
||||||
local record $(module.record_name)
|
|
||||||
# if #module.signals ~= 0 then
|
|
||||||
$(snippets.indent(snippets.render_enum("Signal", module.signals)))
|
|
||||||
|
|
||||||
# end -- /signals
|
|
||||||
# if #module.methods ~= 0 then
|
|
||||||
-- Object methods
|
|
||||||
$(snippets.indent(snippets.render_record_functions(module.methods)))
|
|
||||||
|
|
||||||
# end -- /methods
|
|
||||||
# if #module.properties ~= 0 then
|
|
||||||
-- Object properties
|
|
||||||
$(snippets.indent(snippets.render_record_properties(module.properties)))
|
|
||||||
|
|
||||||
# end -- /properties
|
|
||||||
# if #module.constructors ~= 0 then
|
|
||||||
-- Constructors
|
|
||||||
$(snippets.indent(snippets.render_record_functions(module.constructors)))
|
|
||||||
|
|
||||||
# end -- /constructors
|
|
||||||
# if #module.static_functions ~= 0 then
|
|
||||||
-- Static functions
|
|
||||||
$(snippets.indent(snippets.render_record_functions(module.static_functions)))
|
|
||||||
# end -- /static_functions
|
|
||||||
end
|
|
||||||
|
|
||||||
return $(module.record_name)
|
|
||||||
]]
|
|
||||||
|
|
||||||
local module = {}
|
|
||||||
|
|
||||||
function module.generate_teal(data: Module_Doc.Module_Doc): string
|
|
||||||
local tmpl_args = {
|
|
||||||
ipairs = ipairs,
|
|
||||||
module = data,
|
|
||||||
snippets = snippets,
|
|
||||||
}
|
|
||||||
return utils.do_or_fail(template.substitute, tmpl, tmpl_args)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return module
|
|
|
@ -1,14 +1,22 @@
|
||||||
|
if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
|
||||||
|
require("lldebugger").start()
|
||||||
|
end
|
||||||
|
|
||||||
|
local ast = require "ast"
|
||||||
local crawler = require "crawler"
|
local crawler = require "crawler"
|
||||||
|
local dag = require "dag"
|
||||||
local filesystem = require "filesystem"
|
local filesystem = require "filesystem"
|
||||||
local generator = require "generator"
|
local printer = require "printer"
|
||||||
local List = require "pl.List"
|
local List = require "pl.List"
|
||||||
local logger = require "logger"
|
local logger = require "logger"
|
||||||
local Map = require "pl.Map"
|
local Map = require "pl.Map"
|
||||||
local Module_Doc = require "entity.Module_Doc"
|
|
||||||
local Module_Info = require "entity.Module_Info"
|
local Module_Info = require "entity.Module_Info"
|
||||||
|
local module_dependencies = require "visitors.module_dependencies"
|
||||||
|
local type Node = require "types.Node"
|
||||||
local property = require "property"
|
local property = require "property"
|
||||||
local scraper = require "scraper"
|
local scraper = require "scraper"
|
||||||
local stringx = require "pl.stringx"
|
local stringx = require "pl.stringx"
|
||||||
|
local type_mapping = require "visitors.type_mapping"
|
||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
|
|
||||||
local log = logger.log("main")
|
local log = logger.log("main")
|
||||||
|
@ -38,7 +46,7 @@ local function module_lists(
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The module's children list produced can contain duplicates.
|
-- The module's children list produced can contain duplicates.
|
||||||
-- We ignore them for now because they are dismissed when building a Map for the generator.
|
-- We ignore them for now because they are dismissed when building a Map for the printer.
|
||||||
local function modules_tree(modules: List<Module_Info.Module_Info>): Map<string, List<string>>
|
local function modules_tree(modules: List<Module_Info.Module_Info>): Map<string, List<string>>
|
||||||
local tree: Map<string, List<string>> = Map()
|
local tree: Map<string, List<string>> = Map()
|
||||||
for module in modules:iter() do
|
for module in modules:iter() do
|
||||||
|
@ -65,27 +73,37 @@ local function modules_tree(modules: List<Module_Info.Module_Info>): Map<string,
|
||||||
return tree
|
return tree
|
||||||
end
|
end
|
||||||
|
|
||||||
local function do_one_file(
|
--- TODO : rewrite this to use the DAG
|
||||||
url: string,
|
local function do_module_init_definition(
|
||||||
record_name: string,
|
module_infos: List<Module_Info.Module_Info>
|
||||||
output_path: string
|
|
||||||
)
|
)
|
||||||
local html = crawler.fetch(url)
|
local tree = modules_tree(module_infos)
|
||||||
local module_doc = scraper.module_doc.get_doc_from_page(html, record_name)
|
for module, children in tree:iter() do
|
||||||
module_doc:fixup()
|
-- TODO : this map should be coupled with the all_module_infos list
|
||||||
module_doc:populate_requires()
|
local requires: Map<string, string> = Map()
|
||||||
|
for child in children:iter() do
|
||||||
|
local name = child:gmatch(".*%.(.*)$")()
|
||||||
|
requires:set(name, child)
|
||||||
|
end
|
||||||
filesystem.file_writer.write(
|
filesystem.file_writer.write(
|
||||||
generator.teal_type_definitions.generate_teal(module_doc),
|
printer.module_init_definition.generate_teal(requires),
|
||||||
output_path
|
property.out_directory .. "/" .. stringx.split(module, "."):slice(1, -1):join("/") .. "/init.d.tl"
|
||||||
)
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- TODO : rewrite the module_info thingy
|
||||||
local all_module_infos, module_infos, global_module_infos = module_lists(
|
local all_module_infos, module_infos, global_module_infos = module_lists(
|
||||||
property.base_url .. property.index_uri,
|
property.base_url .. property.index_uri,
|
||||||
List(property.capi_modules),
|
List(),-- List(property.capi_modules),
|
||||||
List(property.ignored_modules)
|
List(utils.spread(
|
||||||
|
property.ignored_modules,
|
||||||
|
{
|
||||||
|
-- Modules that broke the parser.
|
||||||
|
--- TODO : fix the parser
|
||||||
|
"awful.screenshot",
|
||||||
|
}))
|
||||||
)
|
)
|
||||||
local tree = modules_tree(module_infos)
|
|
||||||
|
|
||||||
log:info(
|
log:info(
|
||||||
logger.message_with_metadata(
|
logger.message_with_metadata(
|
||||||
|
@ -94,49 +112,52 @@ log:info(
|
||||||
total_module_count = #all_module_infos,
|
total_module_count = #all_module_infos,
|
||||||
module_count = #module_infos,
|
module_count = #module_infos,
|
||||||
global_module_count = #global_module_infos,
|
global_module_count = #global_module_infos,
|
||||||
tree_items = tree:len(),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
-- Build the DAG
|
||||||
|
local module_dag = dag.new()
|
||||||
for module in module_infos:iter() do
|
for module in module_infos:iter() do
|
||||||
do_one_file(
|
local module_ast, other_nodes = scraper.module_doc.get_doc_from_page(
|
||||||
property.base_url .. "/" .. module.uri,
|
crawler.fetch(property.base_url .. "/" .. module.uri),
|
||||||
module.name,
|
(module.name:gsub(".*%sand%s", ""))
|
||||||
property.out_directory .. "/" .. module.name:gsub("%.", "/") .. ".d.tl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dag.push_module(module_dag, module_ast.module_path, module_ast)
|
||||||
|
dag.push_global_nodes(module_dag, other_nodes)
|
||||||
end
|
end
|
||||||
|
|
||||||
local global_env_def: List<Module_Doc.Module_Doc> = List()
|
-- Run the visitors
|
||||||
for module in global_module_infos:iter() do
|
for _,root in dag.iter_modules(module_dag) do
|
||||||
if module.name:gmatch(".*%sand%s.*") then
|
ast.in_order_visitor(root, function(node: Node)
|
||||||
do_one_file(
|
type_mapping.visit(node)
|
||||||
property.base_url .. "/" .. module.uri,
|
end)
|
||||||
module.name,
|
ast.in_order_visitor(root, function(node: Node)
|
||||||
property.out_directory .. "/" .. module.name:gsub(".*%sand%s", ""):gsub("%.", "/") .. ".d.tl"
|
module_dependencies.visit(node, root, module_dag)
|
||||||
)
|
end)
|
||||||
end
|
|
||||||
|
|
||||||
local html = crawler.fetch(property.base_url .. "/" .. module.uri)
|
|
||||||
local module_doc = scraper.module_doc.get_doc_from_page(html, (module.name:gsub("%sand%s.*", "")))
|
|
||||||
module_doc:fixup()
|
|
||||||
module_doc.record_name = utils.lowercase(module_doc.record_name)
|
|
||||||
global_env_def:append(module_doc)
|
|
||||||
end
|
end
|
||||||
filesystem.file_writer.write(
|
|
||||||
generator.global_env_def.generate_teal(global_env_def),
|
|
||||||
property.out_directory .. "/global_env.d.tl"
|
|
||||||
)
|
|
||||||
|
|
||||||
for module, children in tree:iter() do
|
-- Build the global module from dag.global_nodes
|
||||||
-- TODO : this map should be coupled with the all_module_infos list
|
--- TODO : todo
|
||||||
local requires: Map<string, string> = Map()
|
|
||||||
for child in children:iter() do
|
--- TODO : this is fun, but we need to do something with it
|
||||||
local name = child:gmatch(".*%.(.*)$")()
|
-- Write the DAG to a file
|
||||||
requires:set(name, child)
|
-- local inspect = require("inspect")
|
||||||
end
|
-- filesystem.file_writer.write(
|
||||||
|
-- inspect(module_dag, { newline = "\n", indent = " ", depth = 2 }),
|
||||||
|
-- "generated_dag.lua"
|
||||||
|
-- )
|
||||||
|
|
||||||
|
log:info("Preprocessing finished")
|
||||||
|
|
||||||
|
-- Write modules types definitions to files
|
||||||
|
for module_path, root in dag.iter_modules(module_dag) do
|
||||||
filesystem.file_writer.write(
|
filesystem.file_writer.write(
|
||||||
generator.module_init_definition.generate_teal(requires),
|
printer.teal_type_definition.printer(root),
|
||||||
property.out_directory .. "/" .. stringx.split(module, "."):slice(1, -1):join("/") .. "/init.d.tl"
|
property.out_directory .. "/" .. module_path:gsub("%.", "/") .. ".d.tl"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do_module_init_definition(module_infos)
|
||||||
|
log:info("Module init files generated")
|
||||||
|
|
|
@ -2,7 +2,7 @@ local List = require "pl.List"
|
||||||
local Module_Doc = require "entity.Module_Doc"
|
local Module_Doc = require "entity.Module_Doc"
|
||||||
local template = require "pl.template"
|
local template = require "pl.template"
|
||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
local snippets = require "generator.snippets"
|
local snippets = require "printer.snippets"
|
||||||
|
|
||||||
-- The long therm goal is to have so many `snippets.render_*` functions that
|
-- The long therm goal is to have so many `snippets.render_*` functions that
|
||||||
-- we can render the whole file with the smallest template possible.
|
-- we can render the whole file with the smallest template possible.
|
|
@ -0,0 +1,6 @@
|
||||||
|
return {
|
||||||
|
global_env_def = require("printer.global_env_def"),
|
||||||
|
module_init_definition = require("printer.module_init_definition"),
|
||||||
|
snippets = require("printer.snippets"),
|
||||||
|
teal_type_definition = require("printer.teal_type_definition"),
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
local Map = require "pl.Map"
|
local Map = require "pl.Map"
|
||||||
local template = require "pl.template"
|
local template = require "pl.template"
|
||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
local snippets = require "generator.snippets"
|
local snippets = require "printer.snippets"
|
||||||
|
|
||||||
-- The long therm goal is to have so many `snippets.render_*` functions that
|
-- The long therm goal is to have so many `snippets.render_*` functions that
|
||||||
-- we can render the whole file with the smallest template possible.
|
-- we can render the whole file with the smallest template possible.
|
|
@ -0,0 +1,167 @@
|
||||||
|
local ast = require("ast")
|
||||||
|
local logger = require("logger")
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
local stringx = require("pl.stringx")
|
||||||
|
local utils = require("utils")
|
||||||
|
|
||||||
|
local log = logger.log("scraper")
|
||||||
|
|
||||||
|
local function render_types(types: { string }): string
|
||||||
|
if not types or #types == 0 then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
return ": " .. table.concat(types, " | ")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dedent(str: string): string
|
||||||
|
return stringx.dedent(str):sub(1, -2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function render_code(code: string, indent_level: integer): string
|
||||||
|
if not code or code == "" then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local generated = ""
|
||||||
|
for line in stringx.lines(dedent(code)) do
|
||||||
|
generated = generated .. stringx.rstrip(string.rep(" ", 3 * indent_level) .. line) .. "\n"
|
||||||
|
end
|
||||||
|
return generated
|
||||||
|
end
|
||||||
|
|
||||||
|
local function render_require(dependencies: { string : string }): string
|
||||||
|
local generated = ""
|
||||||
|
for dependency, path in utils.pairsByKeys(dependencies) do
|
||||||
|
generated = generated .. string.format("local type %s = require(\"%s\")\n", dependency, path)
|
||||||
|
end
|
||||||
|
return generated
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Node_Printer_Function
|
||||||
|
on_node: function(node: Node, indent_level: integer): string, integer
|
||||||
|
before_node: nil | function(node: Node, indent_level: integer): string, integer
|
||||||
|
after_node: nil | function(node: Node, indent_level: integer): string, integer
|
||||||
|
end
|
||||||
|
|
||||||
|
-- pre-declare functions to prevent forward reference errors
|
||||||
|
local print_teal: function(node: Node, indent_level: integer | nil): string
|
||||||
|
local print_children: function(node: Node): string
|
||||||
|
|
||||||
|
local node_printer <total>: { Node.Token : Node_Printer_Function } = {
|
||||||
|
["module"] = {
|
||||||
|
before_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(
|
||||||
|
string.format(
|
||||||
|
"-- This file was auto-generated.\n%s\nlocal record %s",
|
||||||
|
render_require(node.dependencies), -- last require statement will have a newline
|
||||||
|
node.name),
|
||||||
|
indent_level), indent_level + 1
|
||||||
|
end,
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(print_children(node), indent_level), indent_level
|
||||||
|
end,
|
||||||
|
after_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code("end", indent_level - 1) ..
|
||||||
|
"\n" ..
|
||||||
|
render_code(
|
||||||
|
string.format("return %s", node.name),
|
||||||
|
indent_level - 1
|
||||||
|
), indent_level - 1
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["record"] = {
|
||||||
|
before_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(
|
||||||
|
string.format(
|
||||||
|
"record %s",
|
||||||
|
node.name),
|
||||||
|
indent_level), indent_level + 1
|
||||||
|
end,
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(print_children(node), indent_level), indent_level
|
||||||
|
end,
|
||||||
|
after_node = function(_: Node, indent_level: integer): string, integer
|
||||||
|
return render_code("end", indent_level - 1), indent_level - 1
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["enum"] = {
|
||||||
|
before_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(
|
||||||
|
string.format(
|
||||||
|
"enum %s",
|
||||||
|
node.name),
|
||||||
|
indent_level), indent_level + 1
|
||||||
|
end,
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(print_children(node), indent_level), indent_level
|
||||||
|
end,
|
||||||
|
after_node = function(_: Node, indent_level: integer): string, integer
|
||||||
|
return render_code("end", indent_level - 1), indent_level - 1
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["identifier"] = {
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(string.format('"%s"', node.name), indent_level), indent_level
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["variable"] = {
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
return render_code(
|
||||||
|
string.format(
|
||||||
|
"%s%s",
|
||||||
|
node.name,
|
||||||
|
render_types(node.types)),
|
||||||
|
indent_level), indent_level
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["function"] = {
|
||||||
|
on_node = function(node: Node, indent_level: integer): string, integer
|
||||||
|
local args = {}
|
||||||
|
for _, parameter in ipairs(node.parameters) do
|
||||||
|
table.insert(args, print_teal(parameter):sub(1, -2)) -- need to remove the newline ending
|
||||||
|
end
|
||||||
|
return render_code(
|
||||||
|
string.format(
|
||||||
|
"%s: function(%s)%s",
|
||||||
|
node.name,
|
||||||
|
table.concat(args, ", "),
|
||||||
|
render_types(node.return_types)),
|
||||||
|
indent_level), indent_level
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
["metamethod"] = {
|
||||||
|
on_node = function(): string, integer
|
||||||
|
log:warn("Metamethods are not supported yet")
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function print_teal(node: Node, indent_level: integer | nil): string
|
||||||
|
indent_level = indent_level or 0
|
||||||
|
local printer = node_printer[node.token]
|
||||||
|
local generated = ""
|
||||||
|
local full_generated = ""
|
||||||
|
if printer.before_node then
|
||||||
|
generated, indent_level = (printer.before_node as function(Node, integer): string, integer)(node, indent_level)
|
||||||
|
full_generated = generated
|
||||||
|
end
|
||||||
|
generated, indent_level = printer.on_node(node, indent_level)
|
||||||
|
full_generated = full_generated .. generated
|
||||||
|
if printer.after_node then
|
||||||
|
generated, indent_level = (printer.after_node as function(Node, integer): string, integer)(node, indent_level)
|
||||||
|
full_generated = full_generated .. generated
|
||||||
|
end
|
||||||
|
return full_generated
|
||||||
|
end
|
||||||
|
|
||||||
|
function print_children(node: Node): string
|
||||||
|
local generated = ""
|
||||||
|
for _, child in ast.iter_children(node) do
|
||||||
|
generated = generated .. print_teal(child)
|
||||||
|
end
|
||||||
|
return generated
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
printer = print_teal,
|
||||||
|
}
|
|
@ -1,14 +1,10 @@
|
||||||
local Function_Info = require "entity.Function_Info"
|
local ast <const> = require("ast")
|
||||||
local List = require "pl.List"
|
local type Node = require("types.Node")
|
||||||
local logger = require "logger"
|
local logger = require "logger"
|
||||||
local Map = require "pl.Map"
|
|
||||||
local Module_Doc = require "entity.Module_Doc"
|
|
||||||
local scan = require "web_sanitize.query.scan_html"
|
local scan = require "web_sanitize.query.scan_html"
|
||||||
local scraper_utils = require "scraper.utils"
|
local scraper_utils = require "scraper.utils"
|
||||||
local stringx = require "pl.stringx"
|
local stringx = require "pl.stringx"
|
||||||
local Type_Info = require "entity.Type_Info"
|
|
||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
local Variable_Info = require "entity.Variable_Info"
|
|
||||||
|
|
||||||
local log = logger.log("scraper")
|
local log = logger.log("scraper")
|
||||||
|
|
||||||
|
@ -16,176 +12,184 @@ local function extract_node_text(node: scan.HTMLNode): string
|
||||||
return utils.sanitize_string(node:inner_text())
|
return utils.sanitize_string(node:inner_text())
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parse_parameter_types(parameter_type: string): List<Type_Info.Type_Info>
|
local function parse_parameter_types(parameter_type: string): { string }
|
||||||
if parameter_type == "" then
|
if parameter_type == "" then
|
||||||
local type_info: Type_Info.Type_Info = Type_Info("any")
|
return { "any" }
|
||||||
return List({ type_info })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return stringx.split(parameter_type, " or "):map(
|
local types = {}
|
||||||
function(type_name: string): Type_Info.Type_Info
|
for t in stringx.split(parameter_type, " or "):iter() do
|
||||||
return Type_Info(utils.sanitize_string(type_name))
|
table.insert(types, t)
|
||||||
end
|
end
|
||||||
)
|
return types
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_item_name(item_name_node: scan.HTMLNode): string
|
local function extract_item_name(item_name_node: scan.HTMLNode): string, string | nil
|
||||||
return item_name_node and ((item_name_node.attr.name as string):gsub("^.*[%.:]", ""))
|
if not item_name_node then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local module_name_node <const> = scraper_utils.find(item_name_node:outer_html(), "span.function_modname")[1]
|
||||||
|
local module_name = module_name_node and module_name_node:inner_text():gsub("[%.:]$", "")
|
||||||
|
local name <const> = item_name_node:inner_text():gsub("^.*[%.:](.+)%s*[%(%{].*[%)%}]", "%1")
|
||||||
|
return utils.sanitize_string(name), module_name and utils.sanitize_string(module_name) or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_function_parameter_Parameters(tr_node: scan.HTMLNode): { Variable_Info.Variable_Info }
|
local function extract_function_parameters(table_html: string, function_name: string): { Node }, { Node }
|
||||||
local query_selectors = {
|
local parameters_types <const>: { Node } = {}
|
||||||
name = "span.parameter",
|
local is_populating_parameters_types: boolean = false
|
||||||
types = "span.types"
|
local current_field: Node = nil
|
||||||
}
|
|
||||||
|
|
||||||
return scraper_utils.scrape_tuples(
|
|
||||||
tr_node:outer_html(),
|
|
||||||
{ query_selectors.name, query_selectors.types },
|
|
||||||
function(nodes: { string : scan.HTMLNode | nil }): Variable_Info.Variable_Info
|
|
||||||
return Variable_Info(
|
|
||||||
extract_node_text(nodes[query_selectors.name] as scan.HTMLNode),
|
|
||||||
parse_parameter_types(extract_node_text(nodes[query_selectors.types] as scan.HTMLNode))
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function extract_function_parameters(function_parameters_node: scan.HTMLNode): { Variable_Info.Variable_Info }
|
|
||||||
local current_record_parameter: Type_Info.Type_Info | nil = nil
|
|
||||||
|
|
||||||
return scraper_utils.scrape(
|
|
||||||
function_parameters_node:outer_html(),
|
|
||||||
"tr",
|
|
||||||
function(line_node: scan.HTMLNode): Variable_Info.Variable_Info
|
|
||||||
local parameters = extract_function_parameter_Parameters(line_node)
|
|
||||||
if #parameters == 0 then
|
|
||||||
return nil
|
|
||||||
elseif #parameters ~= 1 then
|
|
||||||
log:error(logger.message_with_metadata("Expected 1 parameter by <tr> node",
|
|
||||||
{ len = #parameters, line_node = line_node, parameters = parameters }))
|
|
||||||
error("Expected 1 parameter by <tr> node")
|
|
||||||
end
|
|
||||||
local name, types = parameters[1].name, parameters[1].types
|
|
||||||
|
|
||||||
if line_node.attr ~= nil and line_node.attr.class == "see_also_sublist" and current_record_parameter then
|
|
||||||
local record_parameter = current_record_parameter as Type_Info.Type_Info
|
|
||||||
if not record_parameter.record_entries then
|
|
||||||
record_parameter.record_entries = Map()
|
|
||||||
end
|
|
||||||
|
|
||||||
(record_parameter.record_entries as Map<string, List<Type_Info.Type_Info>>):set(name, types)
|
|
||||||
|
|
||||||
|
local parameters <const> = scraper_utils.scrape(table_html, "tr", function(tr: scan.HTMLNode): Node
|
||||||
|
local tr_html = tr:outer_html()
|
||||||
|
local name_node <const> = scraper_utils.find(tr_html, "span.parameter")[1]
|
||||||
|
local types_node <const> = scraper_utils.find(tr_html, "span.types")[1]
|
||||||
|
if not name_node or not types_node then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if #types == 1 and types[1].name == "table" then
|
local name <const> = extract_node_text(name_node)
|
||||||
local record_name = utils.capitalize(name)
|
local types <const> = parse_parameter_types(extract_node_text(types_node))
|
||||||
current_record_parameter = Type_Info(record_name)
|
|
||||||
return Variable_Info(
|
-- Add a field to the current parameter type record
|
||||||
name,
|
if tr.attr ~= nil and tr.attr.class == "see_also_sublist" and is_populating_parameters_types then
|
||||||
List({ current_record_parameter })
|
local field = ast.create_node("variable", name)
|
||||||
)
|
field.types = types
|
||||||
|
table.insert(parameters_types[#parameters_types].children, field)
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return Variable_Info(name, types)
|
-- Still here and we are populating the parameter type record ?
|
||||||
|
-- Then oops, we wrongly tried to convert a table to a record
|
||||||
|
if is_populating_parameters_types then
|
||||||
|
table.remove(parameters_types, #parameters_types)
|
||||||
|
is_populating_parameters_types = false
|
||||||
|
current_field.types = { "table" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Otherwise, add a new parameter
|
||||||
|
local field = ast.create_node("variable", name)
|
||||||
|
field.types = types
|
||||||
|
current_field = field
|
||||||
|
|
||||||
|
-- If the parameter is a table, then we try to convert it to a record
|
||||||
|
if #types == 1 and types[1] == "table" then
|
||||||
|
local record_name <const> = string.format(
|
||||||
|
"%s_%s",
|
||||||
|
utils.capitalize(function_name),
|
||||||
|
utils.capitalize(name))
|
||||||
|
table.insert(parameters_types, ast.create_node("record", record_name))
|
||||||
|
is_populating_parameters_types = true
|
||||||
|
field.types = { record_name }
|
||||||
|
end
|
||||||
|
|
||||||
|
return field
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
if is_populating_parameters_types and #parameters_types[#parameters_types].children == 0 then
|
||||||
|
table.remove(parameters_types, #parameters_types)
|
||||||
|
current_field.types = { "table" }
|
||||||
|
end
|
||||||
|
|
||||||
|
return parameters, parameters_types
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_function_return_types(function_return_types_node: scan.HTMLNode): List<Type_Info.Type_Info>
|
local function extract_function_return_types(ol_html: string): { string }
|
||||||
if not function_return_types_node then
|
return scraper_utils.scrape(ol_html, "span.types .type", extract_node_text)
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local selector = "span.types .type"
|
|
||||||
local html = function_return_types_node:outer_html()
|
|
||||||
|
|
||||||
return List(scraper_utils.scrape(html, selector, extract_node_text)):map(
|
|
||||||
function(type_name: string): Type_Info.Type_Info
|
|
||||||
return Type_Info(type_name)
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_property_constraints(property_constraint_node: scan.HTMLNode): { string }
|
local function extract_property_constraints(property_constraint_node: scan.HTMLNode): { string }
|
||||||
return scraper_utils.scrape(
|
return scraper_utils.scrape(
|
||||||
property_constraint_node:outer_html(),
|
property_constraint_node:outer_html(),
|
||||||
"tr.see_also_sublist",
|
"tr.see_also_sublist i code",
|
||||||
extract_node_text
|
extract_node_text
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_section_functions(dl: string): { Function_Info.Function_Info }
|
local function extract_section_functions(dl: string, module_name: string | nil): { Node }, { Node}
|
||||||
local query_selectors = {
|
local list_query_selectors <const>: { string : string } = {
|
||||||
header = "dt",
|
function_name = "dt strong",
|
||||||
name = "a",
|
|
||||||
body = "dd",
|
body = "dd",
|
||||||
parameters = "table",
|
|
||||||
return_types = "ol",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return scraper_utils.scrape_tuples(
|
local functions <const>: { Node } = {}
|
||||||
|
local other_functions <const>: { Node } = {}
|
||||||
|
|
||||||
|
for nodes in scraper_utils.iter_tuples(
|
||||||
dl,
|
dl,
|
||||||
{ query_selectors.header, query_selectors.body },
|
utils.values(list_query_selectors)
|
||||||
function(nodes: { string : scan.HTMLNode | nil }): Function_Info.Function_Info
|
) do
|
||||||
if not nodes[query_selectors.header] or not nodes[query_selectors.body] then
|
local function_name <const>, function_module_name <const> = extract_item_name(nodes[list_query_selectors.function_name])
|
||||||
log:warn(
|
local function_node <const> = ast.create_node(
|
||||||
logger.message_with_metadata(
|
"function",
|
||||||
"Missing header or body",
|
function_name
|
||||||
{ nodes = nodes }
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
error("Missing header or body")
|
local body_html = nodes[list_query_selectors.body]:outer_html()
|
||||||
|
|
||||||
|
local parameter_node = scraper_utils.find(body_html, "table")[1]
|
||||||
|
local parameters, parameters_types: { Node }, { Node } = {}, {}
|
||||||
|
if parameter_node then
|
||||||
|
parameters, parameters_types = extract_function_parameters(parameter_node:outer_html(), function_name)
|
||||||
end
|
end
|
||||||
local header = nodes[query_selectors.header] as scan.HTMLNode
|
function_node.parameters = parameters
|
||||||
local body = nodes[query_selectors.body] as scan.HTMLNode
|
|
||||||
local body_elements = scraper_utils.extract_nodes(
|
local return_node = scraper_utils.find(body_html, "ol")[1]
|
||||||
body:outer_html(),
|
function_node.return_types = return_node and
|
||||||
{ query_selectors.parameters, query_selectors.return_types }
|
extract_function_return_types(return_node:outer_html()) or
|
||||||
)
|
{}
|
||||||
return Function_Info(
|
|
||||||
scraper_utils.scrape(
|
if module_name and function_module_name and module_name ~= function_module_name then
|
||||||
header:outer_html(),
|
function_node.name = function_module_name .. "." .. function_node.name
|
||||||
query_selectors.name,
|
utils.spread(other_functions, parameters_types)
|
||||||
extract_item_name
|
table.insert(other_functions, function_node)
|
||||||
)[1],
|
else
|
||||||
#body_elements:get(query_selectors.parameters) ~= 0 and
|
utils.spread(functions, parameters_types)
|
||||||
List(extract_function_parameters(body_elements:get(query_selectors.parameters)[1])) or
|
table.insert(functions, function_node)
|
||||||
(List() as List<Variable_Info.Variable_Info>),
|
|
||||||
#body_elements:get(query_selectors.return_types) ~= 0 and
|
|
||||||
extract_function_return_types(body_elements:get(query_selectors.return_types)[1]) or
|
|
||||||
(List() as List<Type_Info.Type_Info>)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
)
|
end
|
||||||
|
|
||||||
|
return functions, other_functions
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_section_variables(dl: string): { Variable_Info.Variable_Info }
|
local function extract_section_variables(dl: string): { Node }, { string }
|
||||||
local query_selectors = {
|
local query_selectors <const>: { string : string } = {
|
||||||
variable_name = "dt a",
|
variable_name = "dt strong",
|
||||||
variable_summary_type = "dt span.summary_type",
|
variable_summary_type = "dt span.summary_type",
|
||||||
variable_property_constraint = "dd span.property_type",
|
variable_property_constraint = "dd span.property_type",
|
||||||
}
|
}
|
||||||
|
|
||||||
return scraper_utils.scrape_tuples(
|
local variables <const>: { Node } = {}
|
||||||
|
local signals <const>: { string } = {}
|
||||||
|
|
||||||
|
for nodes in scraper_utils.iter_tuples(
|
||||||
dl,
|
dl,
|
||||||
{ query_selectors.variable_name, query_selectors.variable_summary_type, query_selectors.variable_property_constraint },
|
utils.values(query_selectors)
|
||||||
function(nodes: { string : scan.HTMLNode | nil }): Variable_Info.Variable_Info
|
) do
|
||||||
local variable_info = Variable_Info()
|
local node = ast.create_node("variable", (extract_item_name(nodes[query_selectors.variable_name])))
|
||||||
|
node.types = parse_parameter_types(extract_node_text(nodes[query_selectors.variable_summary_type]))
|
||||||
|
|
||||||
variable_info.name = extract_item_name(nodes[query_selectors.variable_name])
|
if #node.types == 1 and node.types[1] == "string" then
|
||||||
variable_info.types = parse_parameter_types(extract_node_text(nodes[query_selectors.variable_summary_type]))
|
log:debug("extract variable string with constraints, this is an enum", { name = node.name })
|
||||||
|
local type_enum <const> = ast.create_node("enum", utils.capitalize(node.name))
|
||||||
if #variable_info.types == 1 and variable_info.types[1].name == "string" then
|
for _, constraint in ipairs(extract_property_constraints(nodes[query_selectors.variable_property_constraint])) do
|
||||||
log:debug("extract variable string with constraints, this is an enum")
|
table.insert(
|
||||||
variable_info.constraints = List(extract_property_constraints(nodes[query_selectors.variable_property_constraint])):map(
|
type_enum.children,
|
||||||
function(constraint: string): string
|
ast.create_node("identifier", (constraint:gsub(""", "")))
|
||||||
return (constraint:gsub(""", ""))
|
|
||||||
end
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
if #type_enum.children == 0 then
|
||||||
return variable_info
|
log:debug("Enum has no children, get back to variable", { name = node.name })
|
||||||
|
else
|
||||||
|
table.insert(variables, type_enum)
|
||||||
|
node.types = { type_enum.name }
|
||||||
end
|
end
|
||||||
)
|
end
|
||||||
|
|
||||||
|
table.insert(variables, node)
|
||||||
|
table.insert(signals, string.format("property::%s", node.name)) -- TODO : actually scrape the signals from the doc
|
||||||
|
end
|
||||||
|
|
||||||
|
return variables, signals
|
||||||
end
|
end
|
||||||
|
|
||||||
local function extract_section_signal(dl: string): { string }
|
local function extract_section_signal(dl: string): { string }
|
||||||
|
@ -202,58 +206,93 @@ local enum Section
|
||||||
"Signals"
|
"Signals"
|
||||||
end
|
end
|
||||||
|
|
||||||
local section_scrapers: { Section : function(html: string, module_doc: Module_Doc.Module_Doc) } = {
|
-- returns
|
||||||
["Constructors"] = function(html: string, module_doc: Module_Doc.Module_Doc)
|
-- - Nodes that should be added to the module
|
||||||
module_doc.constructors = List(extract_section_functions(html))
|
-- - Nodes that should be added to the global scope
|
||||||
end,
|
-- - Strings that should be added to the record Signals
|
||||||
["Static module functions"] = function(html: string, module_doc: Module_Doc.Module_Doc)
|
local section_scrapers <total>: { Section : function(html: string, record_name: string, module_name: string): { Node }, { Node }, { string } } = {
|
||||||
module_doc.static_functions = List(extract_section_functions(html))
|
["Constructors"] = function(html: string): { Node }, { Node }, { string }
|
||||||
end,
|
local constructors <const> = extract_section_functions(html)
|
||||||
["Object properties"] = function(html: string, module_doc: Module_Doc.Module_Doc)
|
for _, constructor in ipairs(constructors) do
|
||||||
module_doc.properties = List(extract_section_variables(html))
|
if constructor.token == "function" then
|
||||||
end,
|
constructor.name = "new"
|
||||||
["Object methods"] = function(html: string, module_doc: Module_Doc.Module_Doc)
|
|
||||||
local self_parameter = Variable_Info("self", List({ Type_Info(module_doc.record_name) }))
|
|
||||||
module_doc.methods = List(extract_section_functions(html)):map(
|
|
||||||
function(method: Function_Info.Function_Info): Function_Info.Function_Info
|
|
||||||
method.parameters:insert(1, self_parameter)
|
|
||||||
return method
|
|
||||||
end
|
end
|
||||||
)
|
end
|
||||||
|
return constructors, {}, {}
|
||||||
end,
|
end,
|
||||||
["Signals"] = function(html: string, module_doc: Module_Doc.Module_Doc)
|
["Static module functions"] = function(html: string, _: string, module_name: string): { Node }, { Node }, { string }
|
||||||
module_doc.signals = List(extract_section_signal(html))
|
local static_functions, other_functions = extract_section_functions(html, module_name)
|
||||||
|
return static_functions, other_functions, {}
|
||||||
|
end,
|
||||||
|
["Object properties"] = function(html: string): { Node }, { Node }, { string }
|
||||||
|
local properties, signals = extract_section_variables(html)
|
||||||
|
return properties, {}, signals
|
||||||
|
end,
|
||||||
|
["Object methods"] = function(html: string, record_name: string): { Node }, { Node }, { string }
|
||||||
|
local methods <const> = extract_section_functions(html)
|
||||||
|
for _, method in ipairs(methods) do
|
||||||
|
if method.token == "function" then
|
||||||
|
local self_parameter = ast.create_node("variable", "self")
|
||||||
|
self_parameter.types = { record_name }
|
||||||
|
table.insert(method.parameters, 1, self_parameter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return methods, {}, {}
|
||||||
|
end,
|
||||||
|
["Signals"] = function(html: string): { Node }, { Node }, { string }
|
||||||
|
local signals = extract_section_signal(html)
|
||||||
|
return {}, {}, signals
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- local function extract_node_module_name(node: Node): string
|
||||||
|
-- return (node.name:gsub("(.*)[%.:].+$", "%1"))
|
||||||
|
-- end
|
||||||
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
function module.get_doc_from_page(html: string, module_name: string): Module_Doc.Module_Doc
|
function module.get_doc_from_page(html: string, module_path: string): Node, { Node }
|
||||||
local nodes = scraper_utils.extract_nodes(html, {
|
local html_nodes = scraper_utils.extract_nodes(html, {
|
||||||
"h2.section-header",
|
"h2.section-header",
|
||||||
"dl.function",
|
"dl.function",
|
||||||
})
|
})
|
||||||
|
|
||||||
if #nodes:get "h2.section-header" ~= #nodes:get "dl.function" then
|
if #html_nodes:get "h2.section-header" ~= #html_nodes:get "dl.function" then
|
||||||
error "The list aren't the same size!"
|
error "The list aren't the same size!"
|
||||||
end
|
end
|
||||||
|
|
||||||
local module_doc = Module_Doc()
|
local record_name <const> = utils.capitalize((module_path:gsub(".*%.", "")))
|
||||||
module_doc.record_name = utils.capitalize((module_name:gsub(".*%.", "")))
|
local module_root <const> = ast.create_node("module", record_name, module_path)
|
||||||
|
local other_nodes <const>: { Node } = {}
|
||||||
|
|
||||||
for i = 1, #nodes:get("h2.section-header") do
|
local module_signals_node <const> = ast.create_node("enum", "Signal")
|
||||||
local h2 = nodes:get("h2.section-header")[i]
|
table.insert(module_root.children, module_signals_node)
|
||||||
|
|
||||||
|
for i = 1, #html_nodes:get("h2.section-header") do
|
||||||
|
local h2 = html_nodes:get("h2.section-header")[i]
|
||||||
local section_name = utils.sanitize_string(h2:inner_text()) as Section -- promote to Section, we then test if the section_name is in the table
|
local section_name = utils.sanitize_string(h2:inner_text()) as Section -- promote to Section, we then test if the section_name is in the table
|
||||||
local dl_html = nodes:get("dl.function")[i]:outer_html()
|
local dl_html = html_nodes:get("dl.function")[i]:outer_html()
|
||||||
|
|
||||||
if section_scrapers[section_name] then
|
if section_scrapers[section_name] then
|
||||||
section_scrapers[section_name](dl_html, module_doc)
|
local module_nodes, global_nodes, signals_name = section_scrapers[section_name](dl_html, record_name, module_path)
|
||||||
|
for _, node in ipairs(module_nodes) do
|
||||||
|
table.insert(module_root.children, node)
|
||||||
|
end
|
||||||
|
for _, node in ipairs(global_nodes) do
|
||||||
|
table.insert(other_nodes, node)
|
||||||
|
end
|
||||||
|
for _, signal_name in ipairs(signals_name) do
|
||||||
|
table.insert(
|
||||||
|
module_signals_node.children,
|
||||||
|
ast.create_node("identifier", signal_name)
|
||||||
|
)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
log:warn("Section scraper not implemented: " .. section_name)
|
log:warn("Section scraper not implemented: " .. section_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return module_doc
|
return module_root, other_nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|
|
@ -15,15 +15,14 @@ function scraper_utils.scrape<T>(html: string, query_selector: string, extract_c
|
||||||
scanner.scan_html(html, function(stack: scan.NodeStack)
|
scanner.scan_html(html, function(stack: scan.NodeStack)
|
||||||
if stack:is(query_selector) then
|
if stack:is(query_selector) then
|
||||||
local node = stack:current()
|
local node = stack:current()
|
||||||
local success, info_or_error = pcall(extract_callback, node)
|
local success, ret_or_error = pcall(extract_callback, node)
|
||||||
|
|
||||||
if not success then
|
if not success then
|
||||||
local error_message = info_or_error as string
|
log:error(logger.message_with_metadata("Extraction error", { error = ret_or_error as string }))
|
||||||
log:error(logger.message_with_metadata("Extraction error", { error = error_message }))
|
return
|
||||||
else
|
|
||||||
local info = info_or_error as T
|
|
||||||
table.insert(ret, info)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
table.insert(ret, ret_or_error as T)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -48,28 +47,56 @@ function scraper_utils.extract_nodes(html: string, query_selectors: { string }):
|
||||||
return siblings
|
return siblings
|
||||||
end
|
end
|
||||||
|
|
||||||
function scraper_utils.scrape_tuples<T>(html: string, query_selectors: { string }, extract_callback: function(tuple: { string : scan.HTMLNode | nil }): T): { T }
|
function scraper_utils.find(html: string, query_selector: string): { scan.HTMLNode }
|
||||||
local nodes = scraper_utils.extract_nodes(html, query_selectors)
|
local nodes: { scan.HTMLNode } = {}
|
||||||
|
|
||||||
local ret: { T } = {}
|
scanner.scan_html(html, function(stack: scan.NodeStack)
|
||||||
|
if stack:is(query_selector) then
|
||||||
for i = 1, #nodes:get(query_selectors[1]) do
|
table.insert(nodes, stack:current())
|
||||||
local node_list: { string : scan.HTMLNode | nil } = {}
|
end
|
||||||
tablex.foreach(query_selectors, function(query_selector: string)
|
|
||||||
node_list[query_selector] = nodes:get(query_selector)[i] or nil
|
|
||||||
end)
|
end)
|
||||||
local success, info_or_error = pcall(extract_callback, node_list)
|
|
||||||
|
|
||||||
if not success then
|
return nodes
|
||||||
local error_message = info_or_error as string
|
end
|
||||||
log:error(logger.message_with_metadata("Extraction error", { error = error_message }))
|
|
||||||
else
|
function scraper_utils.iter_tuples(html: string, query_selectors: { string }): function(): { string : scan.HTMLNode }
|
||||||
local info = info_or_error as T
|
local siblings: { string : { scan.HTMLNode } } = {}
|
||||||
table.insert(ret, info)
|
for _, query_selector in ipairs(query_selectors) do
|
||||||
|
siblings[query_selector] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
scanner.scan_html(
|
||||||
|
html,
|
||||||
|
function(stack: scan.NodeStack)
|
||||||
|
for _, query_selector in ipairs(query_selectors) do
|
||||||
|
if stack:is(query_selector) then
|
||||||
|
table.insert(siblings[query_selector], stack:current())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
local siblings_count = #siblings[query_selectors[1]]
|
||||||
|
for _, query_selector in ipairs(query_selectors) do
|
||||||
|
if #siblings[query_selector] ~= siblings_count then
|
||||||
|
error("Query selectors do not have the same number of siblings")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret
|
local i = 0
|
||||||
|
return function(): { string : scan.HTMLNode }
|
||||||
|
i = i + 1
|
||||||
|
if i > siblings_count then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local node_list: { string : scan.HTMLNode } = {}
|
||||||
|
for _, query_selector in ipairs(query_selectors) do
|
||||||
|
node_list[query_selector] = siblings[query_selector][i]
|
||||||
|
end
|
||||||
|
|
||||||
|
return node_list
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return scraper_utils
|
return scraper_utils
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
|
||||||
|
local record Dag
|
||||||
|
modules: { string : Node } -- module_path (AKA "full name" `package.module.name`) -> root_node (token = "module")
|
||||||
|
global_nodes: { Node }
|
||||||
|
end
|
||||||
|
|
||||||
|
return Dag
|
|
@ -0,0 +1,29 @@
|
||||||
|
local record Node
|
||||||
|
enum Token
|
||||||
|
"module" -- file root node, it is always a record and the generated .d.tl file returns it
|
||||||
|
"record"
|
||||||
|
"enum"
|
||||||
|
"identifier" -- blank token with only a name (used for enum values)
|
||||||
|
"variable"
|
||||||
|
"function"
|
||||||
|
"metamethod"
|
||||||
|
end
|
||||||
|
token: Token
|
||||||
|
name: string
|
||||||
|
|
||||||
|
-- for "module", "record", "enum"
|
||||||
|
children: { Node }
|
||||||
|
|
||||||
|
-- for "variable"
|
||||||
|
types: { string }
|
||||||
|
|
||||||
|
-- for "function" and "metamethod"
|
||||||
|
parameters: { Node }
|
||||||
|
return_types: { string }
|
||||||
|
|
||||||
|
-- for "module"
|
||||||
|
module_path: string
|
||||||
|
dependencies: { string : string } -- module_name -> module_path
|
||||||
|
end
|
||||||
|
|
||||||
|
return Node
|
|
@ -35,6 +35,16 @@ function utils.map<T, U>(list: { T }, iteratee: function(value: T, position: int
|
||||||
return mapped
|
return mapped
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function utils.values<T>(t: table): { T }
|
||||||
|
local values: { T } = {}
|
||||||
|
|
||||||
|
for _, v in pairs(t) do
|
||||||
|
table.insert(values, v as T)
|
||||||
|
end
|
||||||
|
|
||||||
|
return values
|
||||||
|
end
|
||||||
|
|
||||||
function utils.sanitize_string(s: string): string
|
function utils.sanitize_string(s: string): string
|
||||||
return (stringx.strip(web_sanitize.extract_text(s)))
|
return (stringx.strip(web_sanitize.extract_text(s)))
|
||||||
end
|
end
|
||||||
|
@ -66,4 +76,29 @@ function utils.do_or_fail<T>(func: function<T>(...: any): (T | nil, string), ...
|
||||||
return res as T -- promote to T since pcall succeeded at this point
|
return res as T -- promote to T since pcall succeeded at this point
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function utils.spread<T>(t: { T }, ...: { T }): { T }
|
||||||
|
for _, a in ipairs({ ... }) do
|
||||||
|
for _, v in ipairs(a) do
|
||||||
|
table.insert(t, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function utils.pairsByKeys<Key, Value>(list: { Key : Value }, comp: function(Key, Key): boolean): function(): Key, Value
|
||||||
|
local sortedKeys = {}
|
||||||
|
for n in pairs(list) do table.insert(sortedKeys, n) end
|
||||||
|
table.sort(sortedKeys, comp)
|
||||||
|
|
||||||
|
local index = 0
|
||||||
|
return function(): Key, Value
|
||||||
|
index = index + 1
|
||||||
|
if sortedKeys[index] == nil then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return sortedKeys[index], list[sortedKeys[index]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return utils
|
return utils
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
local type Dag = require("types.Dag")
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
local utils = require("utils")
|
||||||
|
|
||||||
|
local spread = utils.spread
|
||||||
|
|
||||||
|
local function get_all_types_in_node(node: Node): { string }
|
||||||
|
local parameters_types = {}
|
||||||
|
if node.parameters then
|
||||||
|
for _, v in ipairs(node.parameters) do
|
||||||
|
spread(parameters_types, v.types)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return spread(
|
||||||
|
{},
|
||||||
|
node.types or {},
|
||||||
|
node.return_types or {},
|
||||||
|
parameters_types or {})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function replace_in_node_type(node: Node, old_type: string, new_type: string)
|
||||||
|
if node.parameters then
|
||||||
|
for _, v in ipairs(node.parameters) do
|
||||||
|
for i, t in ipairs(v.types) do
|
||||||
|
if t == old_type then
|
||||||
|
v.types[i] = new_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.types then
|
||||||
|
for i, t in ipairs(node.types) do
|
||||||
|
if t == old_type then
|
||||||
|
node.types[i] = new_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if node.return_types then
|
||||||
|
for i, t in ipairs(node.return_types) do
|
||||||
|
if t == old_type then
|
||||||
|
node.return_types[i] = new_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Module_Dependencies
|
||||||
|
visit: function(node: Node, mod: Node, d: Dag)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Module_Dependencies.visit(node: Node, mod: Node, d: Dag)
|
||||||
|
local all_types <const> = get_all_types_in_node(node)
|
||||||
|
for _, type_name in ipairs(all_types) do
|
||||||
|
if type_name == mod.name then
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
local dependency = d.modules[type_name] or d.modules[utils.lowercase(type_name)]
|
||||||
|
if dependency then
|
||||||
|
mod.dependencies[dependency.name] = dependency.module_path
|
||||||
|
replace_in_node_type(node, dependency.module_path, dependency.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Module_Dependencies
|
|
@ -0,0 +1,68 @@
|
||||||
|
local type Node = require("types.Node")
|
||||||
|
|
||||||
|
-- Special types I don't want to deal with for now
|
||||||
|
local gears_shape_function = "function(cr: any, width: integer, height: integer)"
|
||||||
|
|
||||||
|
local type_map <const>: { string : string } = {
|
||||||
|
awesome = "Awesome",
|
||||||
|
bool = "boolean",
|
||||||
|
client = "Client",
|
||||||
|
["gears.shape"] = gears_shape_function,
|
||||||
|
["gears.surface"] = "Surface",
|
||||||
|
image = "Image",
|
||||||
|
int = "integer",
|
||||||
|
screen = "Screen",
|
||||||
|
shape = gears_shape_function,
|
||||||
|
surface = "Surface",
|
||||||
|
tag = "Tag",
|
||||||
|
widget = "wibox.widget",
|
||||||
|
|
||||||
|
-- fixes we shouldn't have to do (We need to PR Awesome to fix the doc)
|
||||||
|
timer = "gears.timer",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function get_type(t: string): string
|
||||||
|
return type_map[t] or t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_node(node: Node)
|
||||||
|
if not node.types then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, t in ipairs(node.types) do
|
||||||
|
node.types[i] = get_type(t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_function_parameters(node: Node)
|
||||||
|
if not node.parameters then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, parameter in ipairs(node.parameters) do
|
||||||
|
check_node(parameter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_function_returns(node: Node)
|
||||||
|
if not node.return_types then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, ret in ipairs(node.return_types) do
|
||||||
|
node.return_types[i] = get_type(ret)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Type_Mapping
|
||||||
|
visit: function(node: Node)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Type_Mapping.visit(node: Node)
|
||||||
|
check_node(node)
|
||||||
|
check_function_parameters(node)
|
||||||
|
check_function_returns(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Type_Mapping
|
|
@ -0,0 +1,5 @@
|
||||||
|
local record Lldebugger
|
||||||
|
start: function()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Lldebugger
|
Loading…
Reference in New Issue