Module:Script docs

Lua错误:无法创建进程:proc_open(/dev/null): Failed to open stream: Operation not permitted Documentation for this module may be created at Module:Script docs/doc

Implements {{Script effects}}, {{Script event targets}}, {{Script modifier types}}, and {{Script triggers}}.

脚本错误:Lua错误:无法创建进程:proc_open(/dev/null): Failed to open stream: Operation not permitted

local getArgs = require('Module:Arguments').getArgs
local tableTools = require('Module:TableTools')
local sortedPairs = tableTools.sortedPairs
local uString = mw.ustring
local html = mw.html
local tConcat = table.concat

-- standardize table style
local mwCollapsed = ' mw-collapsed'
local tStart = '{| class="wikitable sortable mw-collapsible%s"\n|+ style="white-space:nowrap;" | %s%s' --mwCollapsed, caption, header

local p = {};
local functTable = {};

-- wrapper functions
function p.commonTable(frame)
    local args = getArgs(frame)
    return p._commonTable(args)
end

function p.effectTable(frame)
    local args = getArgs(frame)
    return p._effectTable(args)
end

function p.eventTargetTable(frame)
    local args = getArgs(frame)
    return p._eventTargetTable(args)
end

function p.triggerTable(frame)
    local args = getArgs(frame)
    return p._triggerTable(args)
end

function p.modTypeTable(frame)
    local args = getArgs(frame)
    return p._modTypeTable(args)
end

-- utility functions
local rowBuilder, lister, keyBreak, preCollapse, findKey, tagSetup
-- creates a column for each filled row or up to the specified number of columns
rowBuilder = function(args)
    local colNum = args.colNum or #args
    if type(colNum) ~= 'number' or colNum <= 0 then error("Invalid number of columns", 2) return end
    for i = 1, colNum do
        args[i] = args[i] or ''
    end
    if args.id then
        return uString.format('\n|- id="%s"\n| %s', args.id, tConcat(args, '\n| ', 1, colNum))
    else
        return uString.format("\n|-\n| %s", tConcat(args, '\n| ', 1, colNum))
    end
end
-- creates comma separated list of table keys
lister = function(t)
    if type(t) ~= 'table' then return t end
    local s = ''
    for k, _ in sortedPairs(t) do
        k = keyBreak(k)
        s = uString.format('%s%s, ', s, k)
    end
    s = uString.sub(s, 1, -3)
    --s = uString.gsub(s, '_', ' ')
    return s
end
-- adds word break for long keys
keyBreak = function(str)
    if type(str) ~= 'string' then return str end
    str = mw.text.split(str, '_')
    if #str > 6 then
        --approx. 1/3 and 2/3 split
        str[math.ceil(#str/3+1)] = '<wbr>'..str[math.ceil(#str/3 + 1)]
        str[math.ceil(#str/3*2+2/3)] = '<wbr>'..str[math.ceil(#str/3*2+2/3)]
    elseif #str > 3 then
        --approx 1/2 split
        str[math.ceil(#str/2+4/#str)] = '<wbr>'..str[math.ceil(#str/2+4/#str)]
    end
    return table.concat(str, '_')
end
-- sets a <pre> around string and collapses if more than 6 lines
preCollapse = function(str, count)
    if type(str) ~= 'string' then return str end

    str, count = uString.gsub(str, '\n', '%0')
    str = html.create('pre'):wikitext(str)
    if count > 5 then
        str:addClass('mw-collapsible'):addClass('mw-collapsed')
    end
    return tostring(str)
end
-- matches input key with table keys
findKey = function(key, t)
    if type(t) ~= 'table' then return nil end 
    for tk, _ in pairs(t) do
        local found = uString.match(tk, '^'..key..'$')
        if found then return true end
    end
    return false
end

tagSetup = function(tags, args)
    for _, tag in ipairs(args) do
        if uString.sub(tag, 1, 1) == '!' then
            table.insert(tags.excludes, (uString.gsub( uString.lower(tag), '[ !]', { [' '] = '_', ['!'] = '' } ) ) )
        else
            table.insert(tags.includes, (uString.gsub( uString.lower(tag), ' ', '_') ) )
        end
    end
    return tags
end

-- main functions
function p._commonTable(args)
    local args = args or {}
    local tags = { includes = {}, excludes = {} }
    tags = tagSetup(tags, args)

    mwCollapsed = (args.noCollapse and '') or mwCollapsed
    --local tStart = '{| class="wikitable sortable mw-collapsible'..mwCollapsed..'"\n|+ style="white-space:nowrap;" | '
    local tCaption = uString.format('List of %s%s', ((args.caption and args.caption..' ') or ''), uString.lower(args.tType))
    local tHeader = uString.format("\n|-\n! %s !! class=unsortable | Description !! class=unsortable | Example", uString.sub(args.tType, 1, -2) )
    local header = uString.format(tStart, mwCollapsed, tCaption, tHeader)
    local docData = mw.loadData('Module:Script docs/'..args.tType)
    return p.tableBuilder{ header=header, funct=args.funct, sType=args.sType, tags=tags, includeSpecial=args.includeSpecial, data=docData, cat='Common' }
end

function p._effectTable(args)
    local args = args or {}
    mwCollapsed = (args.noCollapse and '') or mwCollapsed
    --local tStart = '{| class="wikitable sortable mw-collapsible'..mwCollapsed..'"\n|+ style="white-space:nowrap;" | '
    local cType = args.cType or args.sType
    local tCaption = uString.format('List of %s%seffects', ((cType and cType..' ') or ''), ((args.funct and args.funct..' ') or ''))
    local tHeader = "\n|-\n! Effect !! class=unsortable | Description !! class=unsortable | Example"
    local header = uString.format(tStart, mwCollapsed, tCaption, tHeader)
    local effectData = mw.loadData('Module:Script docs/Effects')
    return p.tableBuilder{ header=header, funct=args.funct, sType=args.sType or cType, includeSpecial=args.includeSpecial, data=effectData, cat='Effect' }
end

function p._eventTargetTable(args)
    local args = args or {}
    mwCollapsed = (args.noCollapse and '') or mwCollapsed
    --local tStart = '{| class="wikitable sortable mw-collapsible'..mwCollapsed..'"\n|+ style="white-space:nowrap;" | '
    local cType = args.cType or args.sType
    local tCaption = uString.format('List of %s%sevent targets', ((args.funct and args.funct..' ') or ''), ((cType and cType..' ') or ''))
    local tHeader = "\n|-\n! Event target !! class=unsortable | Description"
    local header = uString.format(tStart, mwCollapsed, tCaption, tHeader)
    local eventTargetData = mw.loadData('Module:Script docs/Event targets')
    return p.tableBuilder{ header=header, funct=args.funct, sType=args.sType or cType, includeSpecial=args.includeSpecial, data=eventTargetData, cat='EventTarget' }
end

function p._triggerTable(args)
    local args = args or {}
    mwCollapsed = (args.noCollapse and '') or mwCollapsed
    --local tStart = '{| class="wikitable sortable mw-collapsible'..mwCollapsed..'"\n|+ style="white-space:nowrap;" | '
    local cType = args.cType or args.sType
    local tCaption = uString.format('List of %s%striggers', ((cType and cType..' ') or ''), ((args.funct and args.funct..' ') or ''))
    local tHeader = "\n|-\n! Trigger !! class=unsortable | Description !! class=unsortable | Example"
    local header = uString.format(tStart, mwCollapsed, tCaption, tHeader)
    local triggerData = mw.loadData('Module:Script docs/Triggers')
    return p.tableBuilder{ header=header, funct=args.funct, sType=args.sType or cType, includeSpecial=args.includeSpecial, data=triggerData, cat='Trigger' }
end

function p._modTypeTable(args)
    local args = args or {}
    mwCollapsed = (args.noCollapse and '') or mwCollapsed
    --local tStart = '{| class="wikitable sortable mw-collapsible'..mwCollapsed..'"\n|+ style="white-space:nowrap;" | '
    local cType = args.cType or args.sType
    local tCaption = uString.format('List of %s%smodifier types', ((args.funct and args.funct..' ') or ''), ((cType and cType..' ') or ''))
    local tHeader = "\n|-\n! Modifier type"
    local header = uString.format(tStart, mwCollapsed, tCaption, tHeader)
    local modTypes = {
        battle = true, building = true, building_group = true,
        character = true, country = true,
        goods = true, interest_group = true,
        market = true, military_formation = true,
        political_movement = true, power_bloc = true,
        state = true, tariff = true,
        tax = true, unit = true,
    }
    local modSuf = { add = 'additive', mult = 'multiplicative', bool = 'boolean' }
    return p.tableBuilder{ header=header, funct=args.funct, sType=args.sType or cType, modTypes=modTypes, modSuf=modSuf, cat='ModType' }
end

function p.tableBuilder(args)
    local args = args or {}
    local funct = uString.lower(args.funct or 'regular')
    local sType = uString.gsub(uString.lower(args.sType or '.+'), ' ', '_')
    local lang = mw.getContentLanguage()

    if not functTable[funct..args.cat] then
        return '<span style="color:red; font-size:11px;">(unrecognized script category "' .. funct .. '" for [[Module:Script docs]])</span>[[Category:Pages with script doc errors]]'
    end
    return args.header .. functTable[funct..args.cat](sType, args) .. '\n|}'
end

-- table type functions
function functTable.regularCommon(sType, args)
    local tags, t, num = args.tags, {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    if #tags.includes == 0 then tags.includes[1] = '.+' end
    if #tags.excludes == 0 then tags.excludes[1] = '' end
    local include, exclude, id
    for key, val in sortedPairs(args.data) do
        include = false
        exclude = false
        for i, j in ipairs(tags.includes) do
            include = findKey(j, val.tags)
            if not include then break end
        end
        for _, j in ipairs(tags.excludes) do
            exclude = findKey(j, val.tags)
            if exclude then break end          
        end
        if (include and (not exclude)) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            id = key
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{id=id, key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.debugCommon(sType, args)
    local tags, t, num = args.tags, {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets !! style="width:0px;" | Tags'
    if #tags.includes == 0 then tags.includes[1] = '.+' end
    if #tags.excludes == 0 then tags.excludes[1] = '' end
    local include, exclude
    for key, val in sortedPairs(args.data) do
        include = false
        exclude = false
        for i, j in ipairs(tags.includes) do
            include = findKey(j, val.tags)
            if not include then break end
        end
        for _, j in ipairs(tags.excludes) do
            exclude = findKey(j, val.tags)
            if exclude then break end          
        end
        if (include and (not exclude)) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), lister(val.tags), colNum=6}
        end
    end
    return tConcat(num)
end

-- vanilla modifier types, rather bespoke because of differing data module format
function functTable.regularModType(sType, args, t)
    local t, num = {}, 1
    local modTypeData = mw.loadData('Module:Modifier type/Notes')
    if uString.match(sType, '%w') then
        t[1] = ' !! Localization !! style="width:0px;" | Type !! style="width:0px;" | Format !! style="width:0px;" | Notes'
    else
        t[1] = ' !! Localization !! style="width:0px;" | Category !! style="width:0px;" | Type !! style="width:0px;" | Format !! style="width:0px;" | Notes'
    end
    local category, mType, mFormat, notes, id
    for key, val in sortedPairs(modTypeData) do
        for k, _ in pairs(args.modTypes) do
            category = uString.match(key, '^'..k)
            if category then break end
        end

        for k, v in pairs(args.modSuf) do
            mType = uString.match(key, k..'$') and v
            if mType then break end
        end
        if val.boolean then mType = 'boolean' end
        mType = mType or ''

        if val.positive == 'green' then mFormat = 'good'
        elseif val.positive == 'red' then mFormat = 'bad'
        else mFormat = 'neutral' end
        if val.percent then mFormat = 'percent, '..mFormat end

        notes = ''
        if val.notes then
            for _, note in ipairs(val.notes) do
                notes = notes .. '\n* ' .. note
            end
        end
        if not uString.match(sType, '%w') then
            id = key
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{id=id, key, val.loc, category, mType, mFormat, notes, colNum=6}
        elseif category and uString.match(sType, '^'..category..'$') then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.loc, mType, mFormat, notes, colNum=5}
        end
    end
    return tConcat(t)
end

-- potential modifier types, also somewhat bespoke because of different data structure
function functTable.potentialModType(sType, args, t)
    local t, num = {}, 1
    local modTypeData = mw.loadData('Module:Modifier type/Potential')
    if uString.match(sType, '%w') then
        t[1] = ' !! class=unsortable | Description !! style="width:0px;" | Type'
    else
        t[1] = ' !! class=unsortable | Description !! style="width:0px;" | Category !! style="width:0px;" | Type'
    end
    local category, mType, mFormat
    for key, val in sortedPairs(modTypeData) do
        for k, _ in pairs(args.modTypes) do
            category = uString.match(uString.lower(key), '^%$?('..k..')')
            if category then break end
        end

        for k, v in pairs(args.modSuf) do
            mType = uString.match(key, k..'$') and v
            if mType then break end
        end
        mType = mType or ''

        if not uString.match(sType, '%w') then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{prev=t, key, val, category, mType, colNum=4}
        elseif category and uString.match(sType, '^'..category..'$') then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{prev=t, key, val, mType, colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.regularEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if ((not val.eType) or args.includeSpecial) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.regularEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if ((not val.etType) or (not val.etType.wildCard)) and (findKey(sType, val.from) or findKey(sType, val.to)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end

function functTable.regularTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if ((not val.tType) or args.includeSpecial) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.allEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    local id = ''
    for key, val in sortedPairs(args.data) do
        if findKey(sType, val.scopes) or findKey(sType, val.targets) then
            id = key
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{id=id, key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.allEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    local id = ''
    for key, val in sortedPairs(args.data) do
        if findKey(sType, val.from) or findKey(sType, val.to) then
            id = key
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{id=id, key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end

function functTable.allTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    local id = ''
    for key, val in sortedPairs(args.data) do
        if findKey(sType, val.scopes) or findKey(sType, val.targets) then
            id = key
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{id=id, key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.scopeEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if ((not val.eType) or args.includeSpecial) and findKey(sType, val.scopes) then
            if noIterators and val.iterator then
            else
                key = keyBreak(key)
                num = num + 1
                t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.targets), colNum=4}
            end
        end
    end
    return tConcat(t)
end
functTable.scopesEffect = functTable.scopeEffect

function functTable.targetEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes'
    for key, val in sortedPairs(args.data) do
        if ((not val.eType) or args.includeSpecial) and findKey(sType, val.targets) then
            if noIterators and val.iterator then
            else
                key = keyBreak(key)
                num = num + 1
                t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), colNum=4}
            end
        end
    end
    return tConcat(t)
end
functTable.targetsEffect = functTable.targetEffect

function functTable.scopeTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if ((not val.tType) or args.includeSpecial) and findKey(sType, val.scopes) then
            if noIterators and val.tType and val.tType.iterator then
            else
                key = keyBreak(key)
                num = num + 1
                t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.targets), colNum=4}
            end
        end
    end
    return tConcat(t)
end
functTable.scopesTrigger = functTable.scopeTrigger

function functTable.targetTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Scopes'
    for key, val in sortedPairs(args.data) do
        if ((not val.tType) or args.includeSpecial) and findKey(sType, val.targets) then
            if noIterators and val.tType and val.tType.iterator then
            else
                key = keyBreak(key)
                num = num + 1
                t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), colNum=4}
            end
        end
    end
    return tConcat(t)
end
functTable.targetsTrigger = functTable.targetTrigger

function functTable.fromEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if ((not val.etType) or (not val.etType.wildCard)) and findKey(sType, val.from) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.to), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.toEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope'
    for key, val in sortedPairs(args.data) do
        if ((not val.etType) or (not val.etType.wildCard)) and findKey(sType, val.to) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.iteratorEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scopes !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if val.eType == 'iterator' and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.iteratorTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scopes !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.tType and val.tType.iterator) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.flowEffect(sType, args)
    local t, num = {}, 0
    --t = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if val.eType == 'flow' and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.flowTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scopes !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.tType and val.tType.flow) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lister(val.scopes), lister(val.targets), colNum=5}
        end
    end
    return tConcat(t)
end

function functTable.logEffect(sType, args)
    local t, num = {}, 0
    --t = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if val.eType == 'log' and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.logTrigger(sType, args)
    local t, num = {}, 0
    --t[1] = ' !! style="width:0px;" | From scopes !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.tType and val.tType.log) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.variableEffect(sType, args)
    local t, num = {}, 0
    --t = ' !! style="width:0px;" | Scopes !! style="width:0px;" | Targets'
    for key, val in sortedPairs(args.data) do
        if val.eType == 'variable' and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.variableTrigger(sType, args)
    local t, num = {}, 0
    --t[1] = ' !! style="width:0px;" | From scopes !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.tType and val.tType.variable) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), colNum=3}
        end
    end
    return tConcat(t)
end

function functTable.specialEffect(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Type'
    for key, val in sortedPairs(args.data) do
        if (val.eType and val.eType ~= 'iterator') and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lang:ucfirst(val.eType), colNum=4}
        end
    end
    return tConcat(t)
end

function functTable.specialTrigger(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | Type'
    for key, val in sortedPairs(args.data) do
        if (val.tType and (not val.tType.iterator)) and (findKey(sType, val.scopes) or findKey(sType, val.targets)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, preCollapse(val.example), lang:ucfirst(lister(val.tType)), colNum=4}
        end
    end
    return tConcat(t)
end

function functTable.dataEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.etType and val.etType.data) and (findKey(sType, val.from) or findKey(sType, val.to)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end

function functTable.wildCardEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.etType and val.etType.wildCard) and (findKey(sType, val.from) or findKey(sType, val.to)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end
functTable['wild cardEventTarget'] = functTable.wildCardEventTarget

function functTable.scopeDataEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (val.etType and val.etType.data) and not (findKey('boolean', val.to) or findKey('value', val.to)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end
functTable['specified scopeEventTarget'] = functTable.scopeDataEventTarget

function functTable.scopeContextEventTarget(sType, args)
    local t, num = {}, 1
    t[1] = ' !! style="width:0px;" | From scope !! style="width:0px;" | To scope'
    for key, val in sortedPairs(args.data) do
        if (not val.etType) and not (findKey('boolean', val.to) or findKey('value', val.to)) then
            key = keyBreak(key)
            num = num + 1
            t[num] = rowBuilder{key, val.description, lister(val.from), lister(val.to), colNum=4}
        end
    end
    return tConcat(t)
end
functTable['contextual scopeEventTarget'] = functTable.scopeContextEventTarget

-- Utility function to build table of usable tags
function p.getTags(tType)
    local t = ''
    local tTags = {}
    local docData = mw.loadData('Module:Script docs/'..tType)

    if not docData then return "Error: bad tType specified" end

    for k, v in pairs(docData) do
        for n, _ in pairs(v.tags) do
            tTags[n] = true
        end
--[[
        if v.from then
            for n, _ in pairs(v.from) do tTags[n] = true end
        end
        if v.to then
            for n, _ in pairs(v.to) do tTags[n] = true end
        end
        if v.scopes then
            for n, _ in pairs(v.scopes) do tTags[n] = true end
        end
        if v.targets then
            for n, _ in pairs(v.targets) do tTags[n] = true end
        end
--]]
    end

    for k, _ in sortedPairs(tTags) do
        t = uString.format("%s\n|-\n| %s", t, k)
    end

    return '{| class="wikitable"' .. t .. '\n|}'
end

return p