Module:Introspection utils: Difference between revisions
add page-existence function; add todo |
No edit summary |
||
| (18 intermediate revisions by the same user not shown) | |||
| Line 3: | Line 3: | ||
-- TODO: | -- TODO: | ||
-- - | -- Add support for detecting modules providing data, not just functions. | ||
-- Address edge case of lazy-loaded modules (loaded within a function) | |||
-- Common functions for module and template introspection. | -- Common functions for module and template introspection. | ||
| Line 14: | Line 15: | ||
-- ----------------------------------------------------------------------------- | -- ----------------------------------------------------------------------------- | ||
-- --------------- | -- --------------- CODE EXTRACTION AND PREPROCESSING FUNCTIONS ----------------- | ||
-- ----------------------------------------------------------------------------- | -- ----------------------------------------------------------------------------- | ||
| Line 56: | Line 57: | ||
end | end | ||
end | end | ||
table.insert(lines, processed) | |||
end | |||
return table.concat(lines, "\n") | |||
end | |||
-- Helper function: preprocess wikitext so that: | |||
-- - Only text inside includeonly tags is captured. | |||
-- - That captured text has normalized spacing and line breaks | |||
function p.preprocess_wikitext(raw_wikitext) | |||
if not raw_wikitext or raw_wikitext == "" then | |||
return "" | |||
end | |||
-- Gather all includeonly sections, if any exist | |||
local includeonly_blocks = {} | |||
for block in raw_wikitext:gmatch("<includeonly>(.-)</includeonly>") do | |||
table.insert(includeonly_blocks, block) | |||
end | |||
local text_to_scan | |||
if #includeonly_blocks > 0 then | |||
text_to_scan = table.concat(includeonly_blocks, " ") | |||
else | |||
text_to_scan = raw_wikitext | |||
end | |||
-- Normalize tags | |||
text_to_scan = text_to_scan | |||
:gsub("<noinclude>.-</noinclude>", "") | |||
:gsub("<noinclude%s*/>", "") | |||
:gsub("<includeonly>", "") | |||
:gsub("</includeonly>", "") | |||
:gsub("<onlyinclude>", "") | |||
:gsub("</onlyinclude>", "") | |||
-- Normalize subst/safesubst | |||
text_to_scan = text_to_scan | |||
:gsub("{{+%s*[Ss]afesubst:", "{{") | |||
:gsub("{{+%s*[Ss]ubst:", "{{") | |||
-- Normalize spaces | |||
text_to_scan = text_to_scan | |||
:gsub("[\r\n]", " ") | |||
:gsub("%s+", " ") | |||
:match("^%s*(.-)%s*$") | |||
return text_to_scan | |||
end | |||
function p.get_and_preprocess_content(namespace, pagename) | |||
local title = mw.title.new(string.format("%s:%s", namespace, pagename)) | |||
local content = title:getContent() | |||
if string.lower(namespace) == "module" then | |||
return p.preprocess_code(content) | |||
elseif string.lower(namespace) == "template" then | |||
return p.preprocess_wikitext(content) | |||
else | |||
return "" | |||
end | end | ||
end | |||
--[[ | |||
function p.get_and_preprocess_content(fullpagename) | |||
if not fullpagename then return "" end | |||
local title = mw.title.new(fullpagename) | |||
local content = title and title:getContent() or "" | |||
return | local lowercase_name = string.lower(fullpagename) | ||
if string.match(lowercase_name, "^module:") then | |||
return p.preprocess_code(content) | |||
elseif string.match(lowercase_name, "^template:") then | |||
return p.preprocess_wikitext(content) | |||
else | |||
return "" | |||
end | |||
end | end | ||
]]-- | |||
-- ----------------------------------------------------------------------------- | |||
-- ----------------------- LUA MODULE INTROSPECTION ---------------------------- | |||
-- ----------------------------------------------------------------------------- | |||
-- Helper function | -- Helper function | ||
| Line 200: | Line 278: | ||
-- ------------------------ TEMPLATE INTROSPECTION ----------------------------- | -- ------------------------ TEMPLATE INTROSPECTION ----------------------------- | ||
-- ----------------------------------------------------------------------------- | -- ----------------------------------------------------------------------------- | ||
-- Find all invokes in a wikitext string | -- Find all invokes in a wikitext string | ||
| Line 255: | Line 293: | ||
return results | return results | ||
end | |||
-- Produce a link to an invoked module | |||
function p.make_module_link(raw_module_name) | |||
if not raw_module_name or raw_module_name == "" then | |||
return nil | |||
end | |||
-- Trim and replace spaces with underscores | |||
local raw_module_name = mw.text.trim(raw_module_name):gsub(" ", "_") | |||
-- Add namespace if missing | |||
if not raw_module_name:find(":", 1, true) then | |||
raw_module_name = "Module:" .. raw_module_name | |||
end | |||
-- Create a normalized title object | |||
local title = mw.title.new(raw_module_name) | |||
if not title then | |||
return nil -- Invalid title (contains illegal characters) | |||
end | |||
-- Format a wiki link: [[Module:Name|Name]] | |||
return string.format("[[%s|%s]]", title.fullText, title.text) | |||
end | end | ||
-- ----------------------------------------------------------------------------- | -- ----------------------------------------------------------------------------- | ||
-- ------------------ | -- ------------------ FUNCTION AND PAGE CHECKING FUNCTIONS --------------------- | ||
-- ----------------------------------------------------------------------------- | -- ----------------------------------------------------------------------------- | ||
| Line 266: | Line 328: | ||
return title and title.exists | return title and title.exists | ||
end | |||
local function normalize_module_name(name) | |||
if not name then return "" end | |||
-- Trim, replace spaces with underscores, remove namespace, lowercase first | |||
-- letter | |||
name = mw.text.trim(name) | |||
name = name:gsub(" ", "_") | |||
name = name:gsub("^[Mm]odule:", "") | |||
name = name:gsub("^%a", string.lower) | |||
return name | |||
end | |||
-- Check whether a template invokes a function from a module. Input is a table | |||
-- of invocations, from find_invokes, and mod_name is the module name. | |||
function p.invocation_exists(invokes, mod_name) | |||
if type(invokes) ~= "table" then | |||
return false | |||
end | |||
local target_mod = normalize_module_name(mod_name) | |||
for _, invoke in ipairs(invokes) do | |||
if normalize_module_name(invoke["module"]) == target_mod then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
function p.tester() | |||
local wikitext = p.get_and_preprocess_content("Template", "MOS intro") | |||
local invokes = p.find_invokes(wikitext) | |||
return p.invocation_exists(invokes, "MOS intro") | |||
end | end | ||
return p | return p | ||