Jump to content

Module:LinkParser

Documentation for this module may be created at Module:LinkParser/doc

-- Module:LinkParser
-- Handles external and wiki link processing with caching

local p = {}

--------------------------------------------------------------------------------
-- Caching and Utilities
--------------------------------------------------------------------------------

-- Cache for processed URLs and wiki links (non-persistent)
local stripCache = {}
local wikiLinkCache = {}

--------------------------------------------------------------------------------
-- External Link Processing
--------------------------------------------------------------------------------

-- Strip URL protocol, www prefix, and trailing slash
function p.strip(link)
	-- Input validation
	if not link or link == "" then
		return link
	end
	
	-- Check cache first for previously processed URLs
	if stripCache[link] then
		return stripCache[link]
	end
	
	-- Chain operations to minimize string allocations
	local result = link:gsub("^%a+://", ""):gsub("^www%.", ""):gsub("/$", "")
	
	-- Cache the result before returning
	stripCache[link] = result
	return result
end

--------------------------------------------------------------------------------
-- Creates MediaWiki link: [ originalURL strippedDisplayText ]
--------------------------------------------------------------------------------
function p.render(frame)
	-- Input validation
	if not frame or not frame.getParent then
		return ""
	end
	
	local parent = frame:getParent()
	if not parent or not parent.args then
		return ""
	end
	
	local args = parent.args
	local rawLink = args["link"] or ""
	
	-- Skip empty links
	if not rawLink or rawLink == "" then
		return ""
	end

	-- Clean URL for display
	local displayText = p.strip(rawLink)

	-- Format as [ rawLink displayText ]
	return string.format("[%s %s]", rawLink, displayText)
end

--------------------------------------------------------------------------------
-- Wiki Link Processing
--------------------------------------------------------------------------------

-- Process wiki links in different modes (extract, strip, check)
-- @param value Wiki link to process
-- @param mode Processing mode: "extract", "strip", or "check"
-- @return Processed value or boolean based on mode
function p.processWikiLink(value, mode)
    -- Default mode is "extract"
    mode = mode or "extract"
    
    -- Early return for nil or empty values
    if not value or value == "" then
        return mode == "check" and false or value
    end
    
    -- Generate cache key
    local cacheKey = value .. ":" .. mode
    
    -- Check cache first
    if wikiLinkCache[cacheKey] ~= nil then
        return wikiLinkCache[cacheKey]
    end
    
    -- Verify wiki link format
    local isWikiLink = value:match("^%[%[.-%]%]$") ~= nil
    
    -- Handle check mode
    if mode == "check" then
        wikiLinkCache[cacheKey] = isWikiLink
        return isWikiLink
    end
    
    -- Return original if not a wiki link
    if not isWikiLink then
        wikiLinkCache[cacheKey] = value
        return value
    end
    
    -- Parse wiki link components
    local pageName, displayText
    
    -- Match [[PageName|DisplayText]] pattern
    pageName, displayText = value:match("^%[%[([^%|%]]+)%|([^%]]+)%]%]$")
    
    if not pageName then
        -- Match [[PageName]] pattern
        pageName = value:match("^%[%[([^%|%]]+)%]%]$")
        displayText = pageName -- Display text equals page name
    end
    
    -- Process based on mode
    local result
    if mode == "extract" then
        result = pageName or value
    elseif mode == "strip" then
        result = displayText or value
    else
        -- Use extract for unknown modes
        result = pageName or value
    end
    
    -- Cache result
    wikiLinkCache[cacheKey] = result
    
    return result
end

-- Extract page name from wiki link
-- @param value Wiki link to process
-- @return Extracted page name
function p.extractFromWikiLink(value)
    return p.processWikiLink(value, "extract")
end

-- Add wiki links based on field config
-- @param value Value to process
-- @param field Field configuration
-- @return Value with wiki links if needed
function p.applyWikiLinkHandling(value, field)
    -- Skip invalid values
    if not value or type(value) ~= "string" or value == "" then
        return value
    end
    
    -- Add wiki links if autoWikiLink is true
    -- Prevents stripping by later processing
    if field.autoWikiLink and not value:match("%[%[.-%]%]") then
        return "[[" .. value .. "]]"
    end
    
    return value
end

-- Preserve wiki links in processed values
-- Keeps original if links were lost during processing
-- @param originalValue Value before processing
-- @param processedValue Value after processing
-- @param preserveWikiLinks Whether to keep wiki links
-- @return Value with links preserved if needed
function p.preserveWikiLinks(originalValue, processedValue, preserveWikiLinks)
    -- Skip non-string values
    if type(originalValue) ~= "string" or type(processedValue) ~= "string" then
        return processedValue
    end
    
    -- Restore original if links were lost
    if preserveWikiLinks and 
       originalValue:match("%[%[.-%]%]") and 
       not processedValue:match("%[%[.-%]%]") then
        return originalValue
    end
    
    return processedValue
end

return p