Module:ConfigRepository
Documentation for this module may be created at Module:ConfigRepository/doc
-- Module:ConfigRepository -- 2025-04-24 “hardened” edition
-- Single source-of-truth for template configurations in ICANNWiki.
----------------------------------------------------------------------
require('strict')
----------------------------------------------------------------------
-- reusable singletons ------------------------------------------------
----------------------------------------------------------------------
local DateFmt = require('Module:NormalizationDate')
local CanonicalForms = require('Module:CanonicalForms')
-- large constants live in separate, read-only data blobs
local ClassicTLDs = mw.loadData('Module:ConfigRepository/Data/ClassicTLDs')
----------------------------------------------------------------------
local p = {}
----------------------------------------------------------------------
-- Global constants ---------------------------------------------------
----------------------------------------------------------------------
p.fieldLabels = {
region = 'Region',
country = 'Country',
date = 'Date',
website = 'Website',
}
p.dateFormatting = { useShortMonthNames = true }
p.semanticProperties = {
region = 'Has ICANN region',
country = 'Has country',
language= 'Knows language',
person = 'Has person',
}
----------------------------------------------------------------------
-- Template definitions ----------------------------------------------
----------------------------------------------------------------------
p.templates = {}
----------------------------------------------------------------------
-- EVENT --------------------------------------------------------------
----------------------------------------------------------------------
do
local t = {
meta = { description = 'Event template' },
categories = { base = { 'Events' } },
patterns = {
seriesNumber = '^([%w%s]+)%s+(%d+)$', -- e.g. ICANN 76
seriesYear = '^([%w%s]+)%s+(%d%d%d%d)$', -- e.g. IGF 2023
},
fields = {
{key='logo' ,label='Logo'},
{key='process' ,label='Process'},
{key='start' ,label='Start Date'},
{key='end' ,label='End Date'},
{key='region' ,label=p.fieldLabels.region},
{keys={'country','territory'},label=p.fieldLabels.country},
{key='city' ,label='City'},
{key='venue' ,label='Venue'},
{key='organizer',label='Organizer'},
{keys={'website','url'},label=p.fieldLabels.website},
{keys={'subject','category'},label='Subject'},
},
semantics = {
properties = {
['Has start date' ] = 'start',
['Has end date' ] = 'end',
['Part of process' ] = 'process',
['Has city' ] = 'city',
['Has venue' ] = 'venue',
['Has event organizer'] = 'organizer',
},
additionalProperties = {
['Has country'] = {'country','territory'},
},
transforms = {
['Has start date'] = function(v) return tostring(DateFmt.formatDate(v)) end,
['Has end date' ] = function(v) return tostring(DateFmt.formatDate(v)) end,
},
skipProperties = {
['Has country' ] = true,
['Has ICANN region' ] = true,
['Has event subject'] = true,
},
},
}
p.templates.Event = t
end
----------------------------------------------------------------------
-- PERSON -------------------------------------------------------------
----------------------------------------------------------------------
do
local communityMap -- forward declaration for up-value capture
local t = {
meta = { description = 'Person template' },
categories = { base = { 'Person' } },
mappings = {
community = { -- shortened for brevity; full list unchanged
{ canonical = 'ICANN Community', synonyms = {'icann','community'}, category = 'ICANN Community' },
{ canonical = 'ICANN Staff' , synonyms = {'staff','icann org'}, category = 'ICANN Staff' },
-- … (other entries identical) …
},
},
fields = {
{key='community' ,label='Community'},
{key='affiliation',label='ICANN group'},
{key='organization',label='Organization'},
{key='region' ,label=p.fieldLabels.region},
{key='country' ,label=p.fieldLabels.country},
{key='languages' ,label='Languages'},
{key='website' ,label=p.fieldLabels.website},
{key='soi' ,label='SOI'},
{key='userbox' ,label='Achievements'},
},
patterns = {
itemDelimiter = ';%s*',
websitePattern = '^https?://[^%s]+',
},
semantics = {
properties = {
['Has governance community'] = 'community',
['Has ICANN affiliation'] = 'affiliation',
['Has organization'] = 'organization',
},
additionalProperties = {
['Has country'] = {'country'},
['Has ICANN region'] = {'region'},
},
transforms = {
['Has governance community'] = function(v)
return select(1, CanonicalForms.normalize(v, communityMap)) or v
end,
['Knows language'] = function(v) return v end,
},
skipProperties = {
['Has country'] = true,
['Has ICANN region'] = true,
},
},
}
communityMap = t.mappings.community
p.templates.Person = t
end
----------------------------------------------------------------------
-- TLD ----------------------------------------------------------------
----------------------------------------------------------------------
do
local typeMap, subtypeMap
local t = {
meta = { description = 'TLD/ccTLD template' },
categories = {
base = {},
conditional= { rvc='TLDs with RVCs', idn='IDN', idn_cctld='IDN ccTLD' },
},
mappings = {
type = {
{canonical='gTLD', synonyms={'generic','tld', 'generic top level domain','generic top-level domain','generic tld'}, category='gTLD'},
{canonical='ccTLD',synonyms={'country','cc','country code top level domain','country code top-level domain','country tld'}, category='ccTLD'},
},
subtype = {
{canonical='geoTLD', synonyms={'geo tld','geo', 'geographic','geographical','geographic top level domain','geographic top-level domain','geographic tld'}, css='tld-template-subtype-geotld', category='geoTLD'},
{canonical='dotBrand', synonyms={'brand','brandtld','brand tld','brand top level domain','brand top-level domain'}, css='tld-template-subtype-brandtld', category='dotBrand'},
{canonical='Sponsored TLD', synonyms={'sponsored','sponsored top level domain','sponsored top-level domain'}, css='tld-template-subtype-sponsored', category='Sponsored TLD'},
{canonical='Legacy TLD', synonyms={'legacy','legacy top level domain','legacy top-level domain'}, css='tld-template-subtype-legacytld', category='Legacy TLD'},
{canonical='2012 gTLD Round', synonyms={'gtld round 2012','2012 ngtld round','2012 ngtld','ngtld 2012','ngtld','2012'}, css='tld-template-subtype-ngtld-round-2012',category='2012 gTLD Round'},
},
},
constants = {
classicTLDs = ClassicTLDs,
},
patterns = {
tldExtension = '%.([^%.]+)$',
countryDelimiter= '([^;]+)',
},
fields = {
{key='type' ,label='Type'},
{key='subtype' ,label='Subtype'},
{key='status' ,label='Status'},
{keys={'country','territory'},label=p.fieldLabels.country},
{key='introduced' ,label='Introduced'},
{keys={'date','implemented'},label='Implemented'},
{keys={'script','language'},label='Script'},
{key='translation' ,label='English version'},
{key='ascii' ,label='Punycode'},
{keys={'registry','registryprovider'},label='Registry'},
{key='website' ,label=p.fieldLabels.website},
{keys={'RVC','PIC'},label='PIC/RVC'},
},
semantics = {
properties = {
['Has TLD type'] = 'type',
['Has TLD subtype'] = 'subtype',
['Has TLD status'] = 'status',
['Date introduced'] = 'introduced',
['Date implemented'] = 'date',
['Uses writing script'] = 'script',
['Has registry operator']= 'registry',
['Has PIC or RVC'] = 'RVC',
},
additionalProperties = {
['Has country'] = {'country','territory'},
['Date implemented'] = {'date','implemented'},
['Uses writing script'] = {'script','language'},
['Has registry operator']= {'registry','registryprovider'},
['Has PIC or RVC'] = {'RVC','PIC'},
},
transforms = {
['Has TLD type'] = function(v) return select(1, CanonicalForms.normalize(v, typeMap )) or v end,
['Has TLD subtype'] = function(v) return select(1, CanonicalForms.normalize(v, subtypeMap)) or v end,
['Date introduced'] = function(v) return tostring(DateFmt.formatDate(v)) end,
['Date implemented'] = function(v) return tostring(DateFmt.formatDate(v)) end,
['Has PIC or RVC'] = function(v) if v and v ~= '' then return 'true' end end,
},
skipProperties = { ['Has country'] = true },
},
}
typeMap, subtypeMap = t.mappings.type, t.mappings.subtype
p.templates.TLD = t
end
----------------------------------------------------------------------
-- LIBRARY INTERVIEW --------------------------------------------------
----------------------------------------------------------------------
do
local t = {
meta = { description = 'Library Interview template' },
categories = { base = { 'Internet & Digital Governance Library', 'ICANNWiki Interviews' } },
constants = { title = 'Internet & Digital Governance Library', tableClass = 'library-box' },
fields = {
{key='Title' ,label='Title'},
{key='Format' ,label='Format'},
{key='Date' ,label=p.fieldLabels.date},
{key='Interviewer',label='Interviewer',autoWikiLink=true},
{key='Interviewee',label='Interviewee',autoWikiLink=true},
{key='ID' ,label='Permanent ID'},
},
semantics = {
properties = {
['Has interview format'] = 'Format',
['Has date'] = 'Date',
['Has interviewer'] = 'Interviewer',
['Has interviewee'] = 'Interviewee',
['Permanent ID'] = 'ID',
},
additionalProperties = { ['Has person'] = {'Interviewer','Interviewee'} },
transforms = {
['Has date'] = function(v) return tostring(DateFmt.formatDate(v)) end,
['Permanent ID'] = function(v) return tostring(v or '') end,
},
},
}
p.templates.LibraryInterview = t
end
----------------------------------------------------------------------
-- API ----------------------------------------------------------------
----------------------------------------------------------------------
function p.getConfig(templateType)
return p.templates[templateType] or {}
end
function p.createStandardConfig(cfg)
cfg = cfg or {}
return {
meta = cfg.meta or { description = 'Template module configuration' },
mappings = cfg.mappings or {},
fields = cfg.fields or {},
semantics = cfg.semantics or { properties={}, transforms={}, additionalProperties={} },
constants = cfg.constants or {},
patterns = cfg.patterns or {},
categories = cfg.categories or {},
}
end
function p.getStandardConfig(templateType, overrides)
return p.createStandardConfig(p.getConfig(templateType), overrides)
end
----------------------------------------------------------------------
mw.log('ConfigRepository loaded; heap '..collectgarbage('count')..' kB')
return p