Jump to content

Module:WikitextProcessor: Difference between revisions

// via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
Line 1: Line 1:
-- Module:WikitextProcessor
-- Module:WikitextProcessor
-- Processes JSON content with wikitext formatting for frontend display
-- Clean, generalized content processor for wikitext formatting and frontend display
-- Handles placeholder replacement, wiki link conversion to HTML, and content normalization
-- Handles placeholder replacement, wiki link conversion to HTML, and content normalization
--
-- Features:
-- - Simple, unified error handling
-- - Three wiki link patterns: [[Page]], [[Page|text]], [[#anchor|text]]
-- - Placeholder replacement with $VARIABLE$ syntax
-- - Content normalization and whitespace cleanup
-- - Resilient design that adapts to any context


local p = {}
local p = {}
Line 8: Line 15:
local ErrorHandling = require('Module:ErrorHandling')
local ErrorHandling = require('Module:ErrorHandling')


-- Helper function to determine appropriate context name for error reporting
-- Constants for performance
local function getContextName(errorContext)
local CONTEXT_NAME = 'wikitextProcessor'
    if not errorContext then
        return 'wikitextProcessor'
    end
   
    -- Check if this is a campaign context (backward compatibility)
    if errorContext.contextType == 'T-Campaign' or
      (errorContext.errors and errorContext.errors.campaignBanner) then
        return 'campaignBanner'  -- Maintain existing behavior
    end
   
    -- Default to generic context for new uses
    return errorContext.contextName or 'wikitextProcessor'
end
 
-- Error message mapping for backward compatibility
local ERROR_MESSAGES = {
local ERROR_MESSAGES = {
     -- Campaign-specific messages (preserve existing)
     urlFailed = 'URL generation failed for wiki link',
    campaignBanner = {
    encodeFailed = 'Text encoding failed for wiki link',
        urlFailed = 'mw.uri.fullUrl failed for page link',
    formatFailed = 'HTML formatting failed for wiki link'
        urlFailedPattern2 = 'Pattern 2 mw.uri.fullUrl failed',
        urlFailedPattern3 = 'Pattern 3 mw.uri.anchorEncode failed',
        encodeFailed = 'mw.text.encode failed for page link',
        encodeFailedPattern2 = 'Pattern 2 mw.text.encode failed',
        encodeFailedPattern3 = 'Pattern 3 mw.text.encode failed',
        formatFailed = 'string.format failed for page link',
        formatFailedPattern2 = 'Pattern 2 string.format failed',
        formatFailedPattern3 = 'Pattern 3 string.format failed'
    },
    -- Generic messages for new contexts
    wikitextProcessor = {
        urlFailed = 'URL generation failed for wiki link',
        urlFailedPattern2 = 'URL generation failed for wiki link',
        urlFailedPattern3 = 'Anchor encoding failed for wiki link',
        encodeFailed = 'Text encoding failed for wiki link',
        encodeFailedPattern2 = 'Text encoding failed for wiki link',
        encodeFailedPattern3 = 'Text encoding failed for wiki link',
        formatFailed = 'HTML formatting failed for wiki link',
        formatFailedPattern2 = 'HTML formatting failed for wiki link',
        formatFailedPattern3 = 'HTML formatting failed for wiki link'
    }
}
}


-- Get appropriate error message based on context
-- Clean error handling
local function getErrorMessage(contextName, messageType)
local function handleError(errorContext, operation, fallbackValue)
    local messages = ERROR_MESSAGES[contextName] or ERROR_MESSAGES.wikitextProcessor
    return messages[messageType] or messages.urlFailed
end
 
-- Unified error handling that preserves existing T-Campaign behavior
local function handleProcessingError(errorContext, operation, errorDetails, fallbackValue)
     if errorContext then
     if errorContext then
         local contextName = getContextName(errorContext)
         ErrorHandling.addStatus(errorContext, CONTEXT_NAME, ERROR_MESSAGES[operation] or ERROR_MESSAGES.urlFailed, nil)
        local message = getErrorMessage(contextName, operation)
       
        -- Preserve existing detailed error format for campaigns
        if contextName == 'campaignBanner' then
            ErrorHandling.addStatus(errorContext, contextName, message, errorDetails)
        else
            -- Simplified error reporting for new contexts
            ErrorHandling.addStatus(errorContext, contextName, message, nil)
        end
     end
     end
     return fallbackValue
     return fallbackValue
Line 81: Line 37:
         pattern = '%[%[([^#|%]]+)%]%]',
         pattern = '%[%[([^#|%]]+)%]%]',
         processor = function(pageName, errorContext)
         processor = function(pageName, errorContext)
            -- Step 1: Generate URL
             local spacesReplaced = (pageName:gsub(' ', '_'))
             local spacesReplaced = (pageName:gsub(' ', '_'))
             local success1, pageUrl = pcall(function()
             local success, pageUrl = pcall(function()
                 return tostring(mw.uri.fullUrl(spacesReplaced))
                 return tostring(mw.uri.fullUrl(spacesReplaced))
             end)
             end)
           
             if not success then
             if not success1 then
                 return handleError(errorContext, 'urlFailed', '[[' .. pageName .. ']]')
                 return handleProcessingError(errorContext, 'urlFailed',  
                    'Page: ' .. pageName .. ', Error: ' .. tostring(pageUrl),
                    '[[' .. pageName .. ']]')
             end
             end
              
              
            -- Step 2: Encode text
             local pageNameStr = type(pageName) == "string" and pageName or tostring(pageName)
             local pageNameStr = type(pageName) == "string" and pageName or tostring(pageName)
             local success2, encodedName = pcall(mw.text.encode, pageNameStr)
             success, pageNameStr = pcall(mw.text.encode, pageNameStr)
           
             if not success then
             if not success2 then
                 return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. ']]')
                 return handleProcessingError(errorContext, 'encodeFailed',
                    'Page: ' .. pageName .. ', Error: ' .. tostring(encodedName),
                    '[[' .. pageName .. ']]')
             end
             end
              
              
             -- Step 3: Format HTML
             success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, pageNameStr)
            local success3, result = pcall(string.format, '<a href="%s">%s</a>', pageUrl, encodedName)
             if not success then
           
                 return handleError(errorContext, 'formatFailed', '[[' .. pageName .. ']]')
             if not success3 then
                 return handleProcessingError(errorContext, 'formatFailed',
                    'Page: ' .. pageName .. ', Error: ' .. tostring(result),
                    '[[' .. pageName .. ']]')
             end
             end
              
              
             return result
             return pageUrl
         end
         end
     },
     },
Line 120: Line 64:
         pattern = '%[%[([^#|%]]+)|([^%]]+)%]%]',
         pattern = '%[%[([^#|%]]+)|([^%]]+)%]%]',
         processor = function(pageName, text, errorContext)
         processor = function(pageName, text, errorContext)
            -- Step 1: Generate URL
             local success, pageUrl = pcall(function()
             local success1, pageUrl = pcall(function()
                 return tostring(mw.uri.fullUrl((pageName:gsub(' ', '_'))))
                 return tostring(mw.uri.fullUrl((pageName:gsub(' ', '_'))))
             end)
             end)
           
             if not success then
             if not success1 then
                 return handleError(errorContext, 'urlFailed', '[[' .. pageName .. '|' .. text .. ']]')
                 return handleProcessingError(errorContext, 'urlFailedPattern2',
                    'Error: ' .. tostring(pageUrl),
                    '[[' .. pageName .. '|' .. text .. ']]')
             end
             end
              
              
            -- Step 2: Encode text
             local textStr = type(text) == "string" and text or tostring(text)
             local textStr = type(text) == "string" and text or tostring(text)
             local success2, encodedText = pcall(mw.text.encode, textStr)
             success, textStr = pcall(mw.text.encode, textStr)
           
             if not success then
             if not success2 then
                 return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. '|' .. text .. ']]')
                 return handleProcessingError(errorContext, 'encodeFailedPattern2',
                    'Error: ' .. tostring(encodedText),
                    '[[' .. pageName .. '|' .. text .. ']]')
             end
             end
              
              
             -- Step 3: Format HTML
             success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, textStr)
            local success3, result = pcall(string.format, '<a href="%s">%s</a>', pageUrl, encodedText)
             if not success then
           
                 return handleError(errorContext, 'formatFailed', '[[' .. pageName .. '|' .. text .. ']]')
             if not success3 then
                 return handleProcessingError(errorContext, 'formatFailedPattern2',
                    'Error: ' .. tostring(result),
                    '[[' .. pageName .. '|' .. text .. ']]')
             end
             end
              
              
             return result
             return pageUrl
         end
         end
     },
     },
Line 158: Line 90:
         pattern = '%[%[#([^|%]]+)|([^%]]+)%]%]',
         pattern = '%[%[#([^|%]]+)|([^%]]+)%]%]',
         processor = function(anchor, text, errorContext)
         processor = function(anchor, text, errorContext)
            -- Step 1: Encode anchor
             local success, encodedAnchor = pcall(mw.uri.anchorEncode, anchor)
             local success1, encodedAnchor = pcall(mw.uri.anchorEncode, anchor)
             if not success then
           
                 return handleError(errorContext, 'urlFailed', '[[#' .. anchor .. '|' .. text .. ']]')
             if not success1 then
                 return handleProcessingError(errorContext, 'urlFailedPattern3',
                    'Error: ' .. tostring(encodedAnchor),
                    '[[#' .. anchor .. '|' .. text .. ']]')
             end
             end
              
              
            -- Step 2: Encode text
             local textStr = type(text) == "string" and text or tostring(text)
             local textStr = type(text) == "string" and text or tostring(text)
             local success2, encodedText = pcall(mw.text.encode, textStr)
             success, textStr = pcall(mw.text.encode, textStr)
           
             if not success then
             if not success2 then
                 return handleError(errorContext, 'encodeFailed', '[[#' .. anchor .. '|' .. text .. ']]')
                 return handleProcessingError(errorContext, 'encodeFailedPattern3',
                    'Error: ' .. tostring(encodedText),
                    '[[#' .. anchor .. '|' .. text .. ']]')
             end
             end
              
              
             -- Step 3: Format HTML
             success, encodedAnchor = pcall(string.format, '<a href="#%s">%s</a>', encodedAnchor, textStr)
            local success3, result = pcall(string.format, '<a href="#%s">%s</a>', encodedAnchor, encodedText)
             if not success then
           
                 return handleError(errorContext, 'formatFailed', '[[#' .. anchor .. '|' .. text .. ']]')
             if not success3 then
                 return handleProcessingError(errorContext, 'formatFailedPattern3',
                    'Error: ' .. tostring(result),
                    '[[#' .. anchor .. '|' .. text .. ']]')
             end
             end
              
              
             return result
             return encodedAnchor
         end
         end
     }
     }

Revision as of 21:26, 1 August 2025

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

-- Module:WikitextProcessor
-- Clean, generalized content processor for wikitext formatting and frontend display
-- Handles placeholder replacement, wiki link conversion to HTML, and content normalization
-- 
-- Features:
-- - Simple, unified error handling
-- - Three wiki link patterns: [[Page]], [[Page|text]], [[#anchor|text]]
-- - Placeholder replacement with $VARIABLE$ syntax
-- - Content normalization and whitespace cleanup
-- - Resilient design that adapts to any context

local p = {}

-- Dependencies
local ErrorHandling = require('Module:ErrorHandling')

-- Constants for performance
local CONTEXT_NAME = 'wikitextProcessor'
local ERROR_MESSAGES = {
    urlFailed = 'URL generation failed for wiki link',
    encodeFailed = 'Text encoding failed for wiki link',
    formatFailed = 'HTML formatting failed for wiki link'
}

-- Clean error handling
local function handleError(errorContext, operation, fallbackValue)
    if errorContext then
        ErrorHandling.addStatus(errorContext, CONTEXT_NAME, ERROR_MESSAGES[operation] or ERROR_MESSAGES.urlFailed, nil)
    end
    return fallbackValue
end

-- Constants as upvalues for performance
local WIKI_LINK_PATTERNS = {
    -- Pattern 1: [[Page Name]] -> HTML page links
    {
        pattern = '%[%[([^#|%]]+)%]%]',
        processor = function(pageName, errorContext)
            local spacesReplaced = (pageName:gsub(' ', '_'))
            local success, pageUrl = pcall(function()
                return tostring(mw.uri.fullUrl(spacesReplaced))
            end)
            if not success then
                return handleError(errorContext, 'urlFailed', '[[' .. pageName .. ']]')
            end
            
            local pageNameStr = type(pageName) == "string" and pageName or tostring(pageName)
            success, pageNameStr = pcall(mw.text.encode, pageNameStr)
            if not success then
                return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. ']]')
            end
            
            success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, pageNameStr)
            if not success then
                return handleError(errorContext, 'formatFailed', '[[' .. pageName .. ']]')
            end
            
            return pageUrl
        end
    },
    
    -- Pattern 2: [[Page|text]] -> HTML page links with custom text
    {
        pattern = '%[%[([^#|%]]+)|([^%]]+)%]%]',
        processor = function(pageName, text, errorContext)
            local success, pageUrl = pcall(function()
                return tostring(mw.uri.fullUrl((pageName:gsub(' ', '_'))))
            end)
            if not success then
                return handleError(errorContext, 'urlFailed', '[[' .. pageName .. '|' .. text .. ']]')
            end
            
            local textStr = type(text) == "string" and text or tostring(text)
            success, textStr = pcall(mw.text.encode, textStr)
            if not success then
                return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. '|' .. text .. ']]')
            end
            
            success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, textStr)
            if not success then
                return handleError(errorContext, 'formatFailed', '[[' .. pageName .. '|' .. text .. ']]')
            end
            
            return pageUrl
        end
    },
    
    -- Pattern 3: [[#anchor|text]] -> HTML anchor links
    {
        pattern = '%[%[#([^|%]]+)|([^%]]+)%]%]',
        processor = function(anchor, text, errorContext)
            local success, encodedAnchor = pcall(mw.uri.anchorEncode, anchor)
            if not success then
                return handleError(errorContext, 'urlFailed', '[[#' .. anchor .. '|' .. text .. ']]')
            end
            
            local textStr = type(text) == "string" and text or tostring(text)
            success, textStr = pcall(mw.text.encode, textStr)
            if not success then
                return handleError(errorContext, 'encodeFailed', '[[#' .. anchor .. '|' .. text .. ']]')
            end
            
            success, encodedAnchor = pcall(string.format, '<a href="#%s">%s</a>', encodedAnchor, textStr)
            if not success then
                return handleError(errorContext, 'formatFailed', '[[#' .. anchor .. '|' .. text .. ']]')
            end
            
            return encodedAnchor
        end
    }
}

-- Normalizes content string by cleaning up whitespace
function p.normalizeContentString(content)
    if not content or content == "" then
        return content
    end
    
    -- Apply string normalization exactly like the original T-Campaign code
    return content:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
end

-- Replaces placeholder patterns ($VARIABLE$) with actual values
function p.replacePlaceholders(content, placeholderMap)
    if not content or not placeholderMap then
        return content
    end
    
    local result = content
    
    -- Apply placeholder replacement exactly like the original T-Campaign code
    for key, value in pairs(placeholderMap) do
        if value and value ~= "" then
            result = result:gsub("%$" .. key .. "%$", value)
        end
    end
    
    -- Clean up any remaining unfilled placeholders (TemplateStarter's removeEmptyPlaceholders logic)
    result = result:gsub("%$[A-Z_]+%$", "")
    result = result:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
    
    return result
end

-- Processes wiki links in content and converts them to HTML
function p.processWikiLinksToHTML(content, errorContext)
    if not content or content == "" then
        return content
    end
    
    -- UNIFIED PIPELINE: Process ALL wiki links with custom patterns (no frame:preprocess)
    local originalContent = content
    local result = content
    
    -- Process each wiki link pattern in sequence exactly like the original T-Campaign code
    for _, patternInfo in ipairs(WIKI_LINK_PATTERNS) do
        result = result:gsub(patternInfo.pattern, function(...)
            return patternInfo.processor(..., errorContext)
        end)
    end
    
    return result
end

-- Main entry point: Processes JSON content with wikitext formatting for frontend display
-- @param content The content string to process
-- @param placeholders Optional table of placeholder values for $VARIABLE$ replacement
-- @param errorContext Optional error context for error reporting
-- @return Processed content ready for frontend display
function p.processContentForFrontend(content, placeholders, errorContext)
    if not content or content == "" then
        return content
    end
    
    -- Step 1: Normalize content string
    local processedContent = p.normalizeContentString(content)
    
    -- Step 2: Replace placeholders if provided
    if placeholders then
        processedContent = p.replacePlaceholders(processedContent, placeholders)
    end
    
    -- Step 3: Process wiki links to HTML
    processedContent = p.processWikiLinksToHTML(processedContent, errorContext)
    
    return processedContent
end

return p