Module:ConfigRepository
Appearance
Documentation for this module may be created at Module:ConfigRepository/doc
-- Module:ConfigRepository
-- Single source of truth for all template configurations across the ICANNWiki ecosystem
--
-- This module centralizes configuration data to ensure consistency, eliminate duplication,
-- and provide standardized structure for all templates. Works with the Template Blueprint
-- Framework to power rendering and semantic processing.
--
-- This module consists of three main parts:
-- 1. Global constants and properties shared across templates
-- 2. Template-specific configurations with standardized structure
-- 3. Configuration access functions for retrieving and standardizing configurations
--
-- Each template configuration provides a standardized structure with the following components:
--
-- meta: Template metadata including description and rendering options
-- categories: Base and conditional categories for the template
-- patterns: Regular expression patterns for validation and parsing
-- fields: Maps template field names in article source to display labels
-- mappings: Canonical mappings for normalizing user input values
-- constants: Template-specific constant values
-- semantics: Semantic MediaWiki integration with the following sub-components:
-- properties: Maps semantic properties to template fields (1:1 mapping)
-- additionalProperties: Maps properties to multiple possible template fields
-- transforms: Functions to transform field values before storing as properties
-- skipProperties: Properties to exclude from automatic processing
local p = {}
local ErrorHandling = require('Module:ErrorHandling')
local ConfigHelpers = require('Module:ConfigHelpers')
------------------------------------------------------------------------------
-- Global Constants
------------------------------------------------------------------------------
-- Global field labels used in multiple templates
p.fieldLabels = {
-- Geographic
city = "City",
country = "Country",
region = "Region",
-- Temporal
date = "Date",
ending = "End",
start = "Start",
-- Others
process = "Process",
website = "Websites"
-- IMPORTANT: "Logo" is processed automatically whenever it is called as a key by the Template Blueprint, in such a way that it does not need to be declared for any templates in this repository
}
-- Global canonical mappings used in multiple templates
p.mappings = {
-- PROCESS (Property:Has process connection)
process = {
{canonical = "AFRINIC",
category = "AFRINIC"},
{canonical = "APNIC",
category = "APNIC"},
{canonical = "ARIN",
category = "ARIN"},
{canonical = "DNS-OARC",
category = "DNS-OARC"},
{canonical = "EuroDIG",
category = "EuroDIG"},
{canonical = "ICANN",
category = "ICANN"},
{canonical = "IEEE",
category = "IEEE"},
{canonical = "IETF",
category = "IETF"},
{canonical = "IGF",
category = "IGF"},
{canonical = "ITU",
category = "ITU"},
{canonical = "LACNIC",
category = "LACNIC"},
{canonical = "RIPE NCC",
category = "RIPE NCC"},
{canonical = "W3C",
category = "W3C"},
{canonical = "WSIS",
category = "WSIS"}
}
}
-- Global semantic property names used in multiple templates (Cross-template semantic queries)
p.semanticProperties = {
country = "Has country",
region = "Has ICANN region",
language = "Knows language",
person = "Has person",
}
-- Global date formatting configuration
-- When true, use "Apr. 21, 2025" format; when false, use "April 21, 2025"
p.dateFormatting = {
useShortMonthNames = true
}
-- Global page creator fields for TemplateStarter form generation
p.pageCreatorFields = {
PAGE_NAME = {
key = "PAGE_NAME",
label = "Page Name",
placeholder = "Enter page name...",
required = true
},
COUNTRY = {
key = "COUNTRY",
label = "Country",
placeholder = "Enter country (optional)...",
required = false
},
YEAR = {
key = "YEAR",
label = "Year",
placeholder = "Enter year (optional)...",
required = false
},
ORGANIZATION_TYPE = {
key = "ORGANIZATION_TYPE",
label = "Organization Type",
placeholder = "Enter organization type (optional)...",
required = false
},
OCCUPATION = {
key = "OCCUPATION",
label = "Occupation",
placeholder = "Enter occupation (optional)...",
required = false
},
NORM_TYPE = {
key = "NORM_TYPE",
label = "Type of Norm",
placeholder = "Enter norm type (optional)...",
required = false
}
}
------------------------------------------------------------------------------
-- Transform registry mapping string keys to functions
------------------------------------------------------------------------------
p.transformRegistry = {
date = function(value)
return tostring(require('Module:NormalizationDate').formatDate(value))
end,
normalize = function(value, mappings)
-- Return original if mappings invalid
if type(mappings) ~= 'table' or #mappings == 0 then
return value
end
local CanonicalForms = require('Module:CanonicalForms')
local canonical = select(1, CanonicalForms.normalize(value, mappings))
return canonical or value
end,
semantic = function(value, templateName)
return require('Module:TemplateHelpers').extractSemanticValue(value, templateName)
end,
boolean = function(value)
if value and value ~= "" then
return "true"
end
end,
raw = function(value)
return value
end,
string = function(value)
return tostring(value or "")
end
}
------------------------------------------------------------------------------
-- TEMPLATE-SPECIFIC CONFIGURATIONS
------------------------------------------------------------------------------
p.templates = {
------------------------------------------------------------------------------
-- ANCHOR: EVENT TEMPLATE
------------------------------------------------------------------------------
Event = {
meta = {
description = "Event template"
},
categories = { -- Default categories
base = {"Events"}
},
boilerplate = {
intro = "'''$PAGE_NAME$''' was an event that took place in $COUNTRY$ in $YEAR$."
},
creatorFields = {"PAGE_NAME", "COUNTRY", "YEAR"},
mappings = {
-- Process (Property:Has process connection)
process = p.mappings.process
},
patterns = {
-- Patterns for event navigation detection
seriesNumber = "^([%w%s]+)%s+(%d+)$", -- e.g., "ICANN 76"
seriesYear = "^([%w%s]+)%s+(%d%d%d%d)$" -- e.g., "IGF 2023"
},
fields = {
{key="process", label=p.fieldLabels.process, autoWikiLink=true},
{key="start", label=p.fieldLabels.start},
{key="ending", label=p.fieldLabels.ending},
{key="region", label=p.fieldLabels.region},
{key="country", label=p.fieldLabels.country},
{key="city", label=p.fieldLabels.city},
{key="venue", label="Venue"},
{key="organizer", label="Organizer"},
{keys={"website", "url"}, label=p.fieldLabels.website},
},
semantics = {
properties = {
["Has process connection"] = "process",
["Has start date"] = "start",
["Has end date"] = "ending",
["Has city"] = "city",
["Has venue"] = "venue",
["Has event organizer"] = "organizer"
},
-- Normalizations applied
transforms = {
["Has start date"] = "date",
["Has end date"] = "date"
},
fixedProperties = {
["Has entity type"] = "Event"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: LIBRARY INTERVIEW TEMPLATE
------------------------------------------------------------------------------
LibraryInterview = {
meta = {
description = "Library Interview template"
},
categories = { -- Default categories
base = {
"Internet & Digital Governance Library",
"ICANNWiki Interviews"
}
},
constants = { -- REVIEW
title = "Internet & Digital Governance Library",
tableClass = "library-box"
},
fields = {
{key="title", label="Title"},
{key="format_interview", 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 = {
-- Direct property mappings (1:1 relationship between property and field)
properties = {
["Has interview format"] = "format_interview",
["Has date"] = "date",
["Has interviewer"] = "interviewer",
["Has interviewee"] = "interviewee",
["Permanent ID"] = "id"
},
-- Properties that map to multiple possible fields
additionalProperties = {
["Has person"] = {"interviewer", "interviewee"} -- Links interviews to person pages
},
-- Normalizations applied
transforms = {
["Has date"] = "date",
["Permanent ID"] = "string"
},
fixedProperties = {
["Has entity type"] = "Library"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: NORM TEMPLATE
------------------------------------------------------------------------------
Norm = {
meta = {
description = "Norm template for laws, regulations, standards, etc."
},
categories = {
base = {"Norms"}
},
boilerplate = {
intro = "'''$PAGE_NAME$''' is a $NORM_TYPE$ proposed in $YEAR$."
},
creatorFields = {"PAGE_NAME", "NORM_TYPE", "YEAR"},
mappings = {
norm_type = {
{canonical = "Act", category = "Acts"},
{canonical = "Law", category = "Laws"},
{canonical = "Regulation", category = "Regulations"},
{canonical = "Standard", category = "Standards"},
{canonical = "Policy", category = "Policies"},
{canonical = "Guideline", category = "Guidelines"},
{canonical = "Treaty", category = "Treaties"},
{canonical = "Decree", category = "Decrees"},
{canonical = "Ordinance", category = "Ordinances"},
{canonical = "By-law", category = "By-laws"},
{canonical = "Code", category = "Codes"},
{canonical = "Convention", category = "Conventions"},
{canonical = "Directive", category = "Directives"}
},
scope_geo = {
{canonical = "Global", category = "Global Norms"},
{canonical = "Regional", category = "Regional Norms"},
{canonical = "National", category = "National Norms"}
},
norm_status = { -- Key used in templatedata
{canonical = "Active", category = "Active Norms"},
{canonical = "Repealed", category = "Repealed Norms"},
{canonical = "Draft", category = "Draft Norms"},
{canonical = "Proposed", category = "Proposed Norms"},
{canonical = "Superseded", category = "Superseded Norms"},
{canonical = "Amended", category = "Amended Norms"}
}
},
fields = {
{key="norm_title", label="Norm title"},
{key="alternative_title", label="Alternative name"}, -- Key used in templatedata
{key="norm_type", label="Type of norm"},
{key="issuing_body", label="Issuing body", autoWikiLink=true},
{key="scope_geo", label="Geographic scope"},
{key="country", label=p.fieldLabels.country},
{key="norm_status", label="Status"}, -- Key used in templatedata
{key="official_text", label="Official text"},
{key="related_norm", label="Related Norms"},
{key="parent_framework", label="Parent legal framework", autoWikiLink=true},
{key="norm_language", label="Language"}
},
semantics = {
properties = {
["Has alternative title"] = "alternative_title",
["Has norm type"] = "norm_type",
["Has issuing body"] = "issuing_body",
["Has geographic scope"] = "scope_geo",
["Has status"] = "norm_status",
["Links to official text"] = "official_text",
["Is related to norm"] = "related_norm",
["Is part of framework"] = "parent_framework",
["Has language"] = "norm_language"
},
transforms = {
["Has norm type"] = "normalize",
["Has geographic scope"] = "normalize",
["Has status"] = "normalize",
["Has issuing body"] = "semantic",
["Is related to norm"] = "semantic",
["Is part of framework"] = "semantic",
["Links to official text"] = "string",
["Has language"] = "string"
},
fixedProperties = {
["Has entity type"] = "Norm"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: ORGANIZATION TEMPLATE
------------------------------------------------------------------------------
Organization = {
meta = {
description = "Organization template"
},
categories = { -- Default categories
base = {"Organization"}
},
boilerplate = {
intro = "'''$PAGE_NAME$''' is a $ORGANIZATION_TYPE$ founded in $YEAR$."
},
creatorFields = {"PAGE_NAME", "ORGANIZATION_TYPE", "YEAR"},
mappings = {
organization_type = {
{canonical = "Academic institution",
synonyms = {"university", "college", "academia", "institute", "school"},
category = "Academic institution"},
{canonical = "ALS",
synonyms = {"at-large structure", "at large structure", "at-large", "at large"},
category = "ALS"},
{canonical = "Commercial",
synonyms = {"for-profit", "for profit", "business", "private", "private company", "privately held", "company", "publicly held", "joint stock company", "corporation", "corp", "firm", "enterprise", "limited liability", "llc", "gmbh"},
category = "Commercial"},
{canonical = "Community network",
synonyms = {"community"},
category = "Community network"},
{canonical = "Consortium",
synonyms = {"alliance", "joint venture", "joint-venture"},
category = "Consortium"},
{canonical = "Cooperative",
synonyms = {"co-op", "coop", "co-operative"},
category = "Cooperative"},
{canonical = "Government agency",
synonyms = {"government", "govt", "regulator", "regulatory authority", "nra", "bureau"},
category = "Government agency"},
{canonical = "Industry association",
synonyms = {"trade association", "industry group", "trade group"},
category = "Industry association"},
{canonical = "Intergovernmental organization",
synonyms = {"igo", "ingo"},
category = "Intergovernmental organization"},
{canonical = "Internet Society Chapter",
synonyms = {"isoc chapter"},
category = "Internet Society Chapter"},
{canonical = "Non-profit",
synonyms = {"nonprofit", "not-for-profit", "not for profit", "charity", "foundation", "economic forum", "ngo", "association", "non-profit organization"},
category = "Non-profit"},
{canonical = "Public-private partnership",
synonyms = {"public-private partnership", "ppp"},
category = "Public-private partnership"},
{canonical = "Standards development organization",
synonyms = {"sdo", "standards body", "standards organisation"},
category = "Standards development organization"}
}
},
fields = {
{key="organization_type", label="Type"},
{key="focus", label="Focus"},
{key="region", label=p.fieldLabels.region},
{key="country", label=p.fieldLabels.country},
{key="city", label=p.fieldLabels.city},
{key="date_founded", label="Founded"},
{key="founders", label="Founders"},
{key="ownership", label="Ownership", autoWikiLink=true},
{key="subsidiaries", label="Subsidiaries"},
{keys={"website", "url"}, label=p.fieldLabels.website},
},
semantics = {
properties = {
["Has organization type"] = "organization_type",
["Has focus"] = "focus",
["Has city"] = "city",
["Date founded"] = "date_founded",
["Has owner"] = "ownership",
["Has subsidiary"] = "subsidiaries"
},
-- Normalizations applied
transforms = {
-- None
},
fixedProperties = {
["Has entity type"] = "Organization"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: PERSON TEMPLATE
------------------------------------------------------------------------------
Person = {
meta = {
description = "Person template"
},
categories = { -- Default categories
base = {"Person"}
},
boilerplate = {
intro = "'''$PAGE_NAME$''' is a $OCCUPATION$ based in $COUNTRY$."
},
creatorFields = {"PAGE_NAME", "OCCUPATION", "COUNTRY"},
mappings = {
-- REVIEW Community (Property:Has governance community)
community = {
-- ICANN-related communities
{canonical = "ICANN Community",
synonyms = {"icann", "community"},
category = "ICANN Community"},
{canonical = "ICANN Staff",
synonyms = {"staff", "icann org"},
category = "ICANN Staff"},
-- Technical communities
{canonical = "Technical Community",
synonyms = {"technical"},
category = "Technical Community"},
{canonical = "Root Server Operator Community",
synonyms = {"root server operator", "rso"},
category = "Root Server Operator Community"},
{canonical = "RIR Community",
synonyms = {"rir"},
category = "RIR Community"},
{canonical = "Universal Acceptance Community",
synonyms = {"universal acceptance", "ua", "uasg", "idn", "idn community"},
category = "Universal Acceptance Community"},
-- Internet governance organizations
{canonical = "ISOC Community",
synonyms = {"isoc", "internet society", "isoc member"},
category = "ISOC Community"},
{canonical = "IETF Community",
synonyms = {"ietf", "ietf member"},
category = "IETF Community"},
{canonical = "IGF Community",
synonyms = {"igf", "nri", "youth igf"},
category = "IGF Community"},
{canonical = "W3C Community",
synonyms = {"w3c", "w3c member"},
category = "W3C Community"},
-- Government-related
{canonical = "Governmental",
synonyms = {"government", "public sector"},
category = "Governmental"},
{canonical = "Intergovernmental",
synonyms = {"igo", "ingo"},
category = "Intergovernmental"}
}
},
fields = {
{key="community", label="Community"},
{key="icann_group", label="ICANN group", autoWikiLink=true}, -- (Property:Has ICANN affiliation)
{key="organization", label="Organization", autoWikiLink=true},
{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"},
{key="user", label="User", hidden=true}
},
patterns = {
itemDelimiter = ";%s*", -- Matches semicolon followed by optional whitespace; used for splitting multi-value fields
websitePattern = "^https?://[^%s]+" -- Matches URLs starting with http:// or https:// followed by non-whitespace chars
},
semantics = {
properties = {
["Has governance community"] = "community",
["Has ICANN affiliation"] = "icann_group",
["Has organization"] = "organization",
["Has username"] = "user"
},
-- Normalizations applied
transforms = {
["Has governance community"] = "normalize",
["Knows language"] = "raw"
},
fixedProperties = {
["Has entity type"] = "Person"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: PROCESS TEMPLATE
------------------------------------------------------------------------------
Process = {
meta = {
description = "Process Template",
templateId = "process"
},
categories = {
base = {"Processes", "Events"}
},
boilerplate = {
intro = "'''$PAGE_NAME$''' is a process started in $YEAR$."
},
creatorFields = {"PAGE_NAME", "YEAR"},
mappings = {
-- Process (Property:Has process connection)
process = p.mappings.process,
-- Model (Property:Has process model)
model = {
{canonical = "Multistakeholder",
synonyms = {"multi-stakeholder", "multi stakeholder"},
category = "Multistakeholder Processes"},
{canonical = "Single stakeholder",
synonyms = {"single-stakeholder", "intergovernmental"},
category = "Single Stakeholder Processes"}
},
-- Status (Property:Has process status)
status = {
{canonical = "Active",
synonyms = {"ongoing"},
category = "Active Processes"},
{canonical = "Paused",
synonyms = {"inactive", "dormant"},
category = "Dormant Processes"},
{canonical = "Concluded",
synonyms = {"completed", "ended", "finished"},
category = "Concluded Processes"}
},
-- Frequency (Property:Has frequency)
frequency = {
{canonical = "One-off",
synonyms = {"one off", "single"},
category = "One-off Processes"},
{canonical = "Ad-hoc",
synonyms = {"ad hoc", "eventual"},
category = "Ad-hoc Processes"},
{canonical = "Periodic",
synonyms = {"recurring", "regular", "annual", "yearly"},
category = "Periodic Processes"},
{canonical = "Continuous",
synonyms = {"permanent"},
category = "Continuous Processes"}
},
-- Scope (Property:Has geographic scope)
scope_geo = {
{canonical = "Global",
synonyms = {"worldwide", "world", "international"},
category = "Global Processes"},
{canonical = "Regional",
synonyms = {"continent", "continental"},
category = "Regional Processes"},
{canonical = "National",
synonyms = {"country", "domestic"},
category = "National Processes"}
}
},
fields = {
{key="process", label=p.fieldLabels.process, autoWikiLink=true},
{key="model", label="Model"},
{key="start", label=p.fieldLabels.start},
{key="ending", label=p.fieldLabels.ending},
{key="process_status", label="Status"},
{key="governing_body", label="Governing Body", autoWikiLink=true},
{key="secretariat", label="Secretariat", autoWikiLink=true},
{key="frequency", label="Frequency"},
{key="scope_geo", label="Scope"},
{key="region", label=p.fieldLabels.region},
{key="country", label=p.fieldLabels.country},
{key="website", label=p.fieldLabels.website},
{key="has_previous", label="Preceded By", hidden=true},
{key="has_next", label="Succeeded By", hidden=true},
},
semantics = {
properties = {
["Has start date"] = "start",
["Has end date"] = "ending",
["Has process status"] = "process_status",
["Has governing body"] = "governing_body",
["Has event organizer"] = "secretariat",
["Has process model"] = "model",
["Has frequency"] = "frequency",
["Has geographic scope"] = "scope_geo",
["Has process connection"] = "process"
},
additionalProperties = {
["Has process connection"] = {"process", "has_previous", "has_next"}
},
-- Normalizations applied
transforms = {
["Has start date"] = "date",
["Has end date"] = "date",
["Has process status"] = "normalize",
["Has process model"] = "normalize",
["Has frequency"] = "normalize",
["Has geographic scope"] = "normalize",
["Has process connection"] = "semantic"
},
fixedProperties = {
["Has entity type"] = "Process"
}
}
},
------------------------------------------------------------------------------
-- ANCHOR: TLD TEMPLATE
------------------------------------------------------------------------------
TLD = {
meta = {
description = "TLD Template"
},
categories = {
base = {}, -- No default category for TLDs as they use type-based categories
conditional = {
rvc = "TLDs with RVCs",
idn = "IDN",
idn_cctld = "IDN ccTLD"
},
},
boilerplate = {
intro = "'''$PAGE_NAME$''' is a TLD proposed in $YEAR$."
},
creatorFields = {"PAGE_NAME", "YEAR"},
mappings = {
-- Type (Property:Has TLD type)
tld_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 (Property:Has TLD subtype)
tld_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"}
}
},
patterns = {
tldExtension="%.([^%.]+)$", -- Extracts the TLD part after the last dot (e.g., "com" from "example.com")
countryDelimiter="([^;]+)" -- Matches any sequence of characters not containing semicolons; used for country parsing
},
fields = {
{key="tld_type", label="Type"},
{key="tld_subtype", label="Subtype"},
{key="tld_status", label="Status"}, -- (Property:Has TLD status)
{key="region", label=p.fieldLabels.region},
{key="country", label=p.fieldLabels.country},
{key="introduced", label="Introduced"},
{key="implemented", label="Implemented"},
{key="script", label="Script"},
{key="language", label="Language"},
{key="translation", label="In English"},
{key="ascii", label="Punycode"},
{key="registry", label="Registry", autoWikiLink=true},
{key="website", label=p.fieldLabels.website},
{keys={"RVC", "PIC"}, label = "PIC/RVC"}
},
semantics = {
properties = {
["Has TLD type"] = "tld_type",
["Has TLD subtype"] = "tld_subtype",
["Has TLD status"] = "tld_status",
["Date introduced"] = "introduced",
["Date implemented"] = "implemented",
["Uses writing script"] = "script",
["Has registry operator"] = "registry",
["Has language"] = "language",
["Has PIC or RVC"] = "RVC", -- Will also handle PIC
["Is IDN"] = "idn", -- Boolean
},
additionalProperties = {
["Has PIC or RVC"] = {"RVC", "PIC"}
},
-- Normalizations applied
transforms = {
["Has TLD type"] = "normalize",
["Has TLD subtype"] = "normalize",
["Date introduced"] = "date",
["Date implemented"] = "date",
["Has PIC or RVC"] = "boolean",
["Is IDN"] = "boolean",
},
fixedProperties = {
["Has entity type"] = "TLD"
}
}
}
}
------------------------------------------------------------------------------
-- CONFIGURATION ACCESS FUNCTIONS
------------------------------------------------------------------------------
-- Get configuration for a specific template type
function p.getConfig(templateType)
return p.templates[templateType] or {}
end
-- Local references to ConfigHelpers functions for better readability
local deepMerge = ConfigHelpers.deepMerge
local fieldHasKey = ConfigHelpers.fieldHasKey
-- Creates a standardized configuration structure for template modules
function p.createStandardConfig(config, customOverrides, templateType)
config = config or {}
customOverrides = customOverrides or {}
-- Initialize with defaults from config
local standardConfig = {
meta = config.meta or {
description = "Template module configuration"
},
mappings = config.mappings or {},
fields = config.fields or {},
semantics = config.semantics or {
properties = {},
transforms = {},
additionalProperties = {}
},
constants = config.constants or {},
patterns = config.patterns or {},
categories = config.categories or {} -- Add categories field to preserve base categories
}
-- Deep-merge customOverrides into standardConfig
standardConfig = deepMerge(standardConfig, customOverrides)
-- Auto-inject country/region semantic mappings if fields exist
if standardConfig.fields and #standardConfig.fields > 0 then
local hasCountryField = false
local hasRegionField = false
-- Check if country or region fields exist
for _, field in ipairs(standardConfig.fields) do
if fieldHasKey(field, "country") or fieldHasKey(field, "territory") then
hasCountryField = true
end
if fieldHasKey(field, "region") then
hasRegionField = true
end
end
-- Initialize additionalProperties if it doesn't exist
standardConfig.semantics.additionalProperties = standardConfig.semantics.additionalProperties or {}
-- Auto-inject country mapping if a country field exists
if hasCountryField then
standardConfig.semantics.additionalProperties[p.semanticProperties.country] =
standardConfig.semantics.additionalProperties[p.semanticProperties.country] or {"country", "territory"}
end
-- Auto-inject region mapping if a region field exists
if hasRegionField then
standardConfig.semantics.additionalProperties[p.semanticProperties.region] =
standardConfig.semantics.additionalProperties[p.semanticProperties.region] or {"region"}
end
end
-- Inject built-in transform functions for declarative transforms
for propertyName, transformIdentifier in pairs(standardConfig.semantics.transforms) do
if type(transformIdentifier) == "string" then
local registryFn = p.transformRegistry[transformIdentifier]
if registryFn then
standardConfig.semantics.transforms[propertyName] = function(value)
if transformIdentifier == "normalize" then
local mappingKey = standardConfig.semantics.properties[propertyName]
local mappingTable = standardConfig.mappings[mappingKey]
if not mappingTable then
local suffix = mappingKey:match(".*_(.*)")
mappingTable = suffix and standardConfig.mappings[suffix] or mappingTable
end
return registryFn(value, mappingTable)
elseif transformIdentifier == "semantic" then
return registryFn(value, templateType)
else
return registryFn(value)
end
end
else
ErrorHandling.addError(
ErrorHandling.createContext(templateType),
"TransformInjection",
"Unknown transform type",
transformIdentifier,
false
)
end
end
end
return standardConfig
end
-- Get a standard config object for use with existing template modules
function p.getStandardConfig(templateType, customOverrides)
-- Get the base configuration
local baseConfig = p.getConfig(templateType)
-- Create a standard config
return p.createStandardConfig(baseConfig, customOverrides, templateType)
end
return p