Module:ConfigRepository: Difference between revisions
No edit summary Tag: Reverted |
HARD FIX Tag: Reverted |
||
| Line 1: | Line 1: | ||
-- Module:ConfigRepository | -- Module:ConfigRepository -- 2025-04-24 “hardened” edition | ||
-- Single source of truth for | -- 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 = {} | local p = {} | ||
------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ||
-- | -- Global constants --------------------------------------------------- | ||
------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | ||
-- | |||
-- | |||
-- | |||
p.fieldLabels = { | p.fieldLabels = { | ||
region = 'Region', | |||
region = | country = 'Country', | ||
country = | date = 'Date', | ||
website = 'Website', | |||
date = | |||
website = | |||
} | } | ||
p.dateFormatting = { useShortMonthNames = true } | |||
p.dateFormatting = { | |||
} | |||
p.semanticProperties = { | p.semanticProperties = { | ||
region = 'Has ICANN region', | |||
region = | country = 'Has country', | ||
country = | language= 'Knows language', | ||
person = 'Has person', | |||
language = | |||
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) | function p.getConfig(templateType) | ||
return p.templates[templateType] or {} | return p.templates[templateType] or {} | ||
end | end | ||
function p.createStandardConfig(cfg) | |||
function p.createStandardConfig( | cfg = cfg or {} | ||
return { | |||
meta = cfg.meta or { description = 'Template module configuration' }, | |||
mappings = cfg.mappings or {}, | |||
fields = cfg.fields or {}, | |||
meta = | semantics = cfg.semantics or { properties={}, transforms={}, additionalProperties={} }, | ||
constants = cfg.constants or {}, | |||
patterns = cfg.patterns or {}, | |||
mappings = | categories = cfg.categories or {}, | ||
fields = | |||
semantics = | |||
constants = | |||
patterns = | |||
categories = | |||
} | } | ||
end | end | ||
function p.getStandardConfig(templateType, overrides) | |||
function p.getStandardConfig(templateType, | return p.createStandardConfig(p.getConfig(templateType), overrides) | ||
end | end | ||
---------------------------------------------------------------------- | |||
mw.log('ConfigRepository loaded; heap '..collectgarbage('count')..' kB') | |||
return p | return p | ||