Module:Road data explained

local p =

-- Change to "" upon deployment.local moduleSuffix = ""

local parserModuleName = "Module:Road data/parser" .. moduleSuffixlocal statenameModuleName = "Module:Jct/statename" .. moduleSuffix -- TODO transition

local concat = table.concatlocal insert = table.insertlocal format = mw.ustring.formatlocal trim = mw.text.trim

local parserModule = require(parserModuleName)local parser = parserModule.parserlocal util = require("Module:Road data/util")local sizeModule = require("Module:Road data/size").size

-- Shieldslocal defaultShieldSize = 24

local function addContextBanner(route, name, suffix, bannerSpec) local bannerModule = 'Module:Road data/banners/' .. string.upper(route.country) local shieldfield = name .. 'shield' local shield = parser(route, shieldfield) if shield

nil then -- This route type does not define shield. -- Find shield in the default banner table. shield = parser(route, 'shield', name, bannerModule) if shield and shield ~= then if suffix

nil then suffix = parser(route, 'shield', 'suffix', bannerModule) end if suffix and suffix ~= then shield = shield .. " " .. suffix end shield = shield .. ".svg" end end if shield and shield ~= then local shieldSize = sizeModule -- Add banner plate. insert(bannerSpec,) endend

local function bannerSpec(banner, bannerSize, bannerSuffix, route) local banners = if type(banner)

"table" then local bannerSizeIsNotTable = type(bannerSize) ~= "table" for i,filename in ipairs(banner) do local bannersize = bannerSizeIsNotTable and bannerSize or bannerSize[i] or defaultShieldSize insert(banners,) end elseif banner ~= then insert(banners,) end

if route.dir then addContextBanner(route, 'dir', bannerSuffix, banners) end if route.to then addContextBanner(route, 'to', bannerSuffix, banners) end

return bannersend

local function shieldSpec(route, mainShield, shieldList) local shieldSpec =

local shield if mainShield then shield = parser(route, "shieldmain") end if shieldList then shield = parser(route, "shieldlist") end if not shield then shield = parser(route, 'shield') or end if shield

then return shieldSpec end local orientation = parser(route, 'orientation')

local function size(route) if orientation

"upright" then return sizeModule else return "x" .. sizeModule end end local shieldsize = sizeModule local banner = parser(route, 'banner') or local bannersize = sizeModule local bannersuffix = parser(route, 'bannersuffix')

local bannerIsNotTable = type(banner) ~= "table" local bannersizeIsNotTable = type(bannersize) ~= "table" local bannersuffixIsNotTable = type(bannersuffix) ~= "table"

if type(shield)

"table" then for i,filename in ipairs(shield) do local size = shieldsize or shieldsize[i] if size

"" then size = nil end -- banner.all describes banners that apply to all multiple shields. local shieldBanner = bannerIsNotTable and banner or (banner[i] or banner.all or) -- Banner size is default if the corresponding entry -- in bannerSize table is not set. local shieldBannerSize = bannersizeIsNotTable and bannersize or (bannersize[i] or bannersize.all or defaultShieldSize) local shieldBannerSuffix = bannersuffix and (bannersuffixIsNotTable and bannersuffix or bannersuffix[i]) insert(shieldSpec,) end elseif shield ~= then if shieldsize

"" then shieldsize = nil end insert(shieldSpec,) end

return shieldSpecend

local missingShields

local shieldExistsCache =

-- Return up to two booleans.-- The first boolean is false if `shield` does not exist, and true otherwise.-- If the first boolean is true, the second boolean is true if the shield is-- landscape (width >= height), and false otherwise.local function shieldExists(shield) local result = shieldExistsCache[shield] if result

nil then local file = mw.title.new(shield, 'Media').file -- Cache result. local exists = file.exists result = if exists then result[2] = file.width >= file.height end shieldExistsCache[shield] = result end if result[1] then return true, result[2] end insert(missingShields, shield) return falseend

local function render(shieldEntry, scale, showLink) local shield = shieldEntry.shield local banners = shieldEntry.banners local exists, landscape = shieldExists(shield[1]) if not exists then return end

local size if shield[2] then local width, height = mw.ustring.match(shield[2], "(%d*)x?(%d*)") width = tonumber(width) height = tonumber(height) local sizeparts = if width then insert(sizeparts, format("%d", width * scale)) end if height then insert(sizeparts, format("x%d", height * scale)) end size = concat(sizeparts) else size = format("%s%d", landscape and "x" or "", sizeModule) end local shieldCode = format("", shield[1], size) if not banners[1] then return shieldCode end

for _,banner in ipairs(banners) do if shieldExists(banner[1]) then shieldCode = format("
%s", banner[1], banner[2], shieldCode) end end return '

' .. shieldCode .. ''end

function p.shield(route, scale, showLink, mainShield, shieldList) missingShields = if route.rdt then local shieldSize = mw.ustring.match(route.rdt, '^(%d+)$') or 17 scale = shieldSize/defaultShieldSize end scale = scale or 1

local rendered = for _,entry in ipairs(shieldSpec(route, mainShield, shieldList)) do insert(rendered, render(entry, scale, showLink)) end return concat(rendered), missingShieldsend

function p.link(route) local abbr, errMsg = parser(route, 'abbr') if not abbr then route.typeerror = true return util.err(errMsg or format("Invalid type: %s", route.type or "(nil)")) end if route.nolink then return abbr, abbr end

local link = parser(route, 'link') or if link

then return abbr, abbr end

return format("%s", link, abbr), abbrend

local function stateName(args) -- TODO transition local data = mw.loadData(statenameModuleName) local abbr = args.state or args.province local countryData = data[args.country] return countryData and countryData[abbr]end

function p.locations(args, module, group) module = module or "" local modulearticle = module .. "article" local moduleprefix = module .. "prefix" local modulenameprefix = module .. "nameprefix" local modulenamesuffix = module .. "namesuffix"

local warnings =

-- Region, for disambiguation local region = parserModule.parser(args, "region", " common ") if not region then -- TODO transition if args.region then warnings.region = "region parameter is deprecated" region = args.region elseif args.country and (args.state or args.province) then warnings.region = "Inferring region from country and state/province" region = stateName(args) end end local regionName local regionText if type(region)

"table" then regionName = region.name regionText = format("%s", region.link, regionName) elseif region then regionName = region regionText = format("%s", regionName) end args.region = regionName

local locations = parserModule.parser(args, "locations", " common ") or

-- Primary topic requires no specialization to supplied locations. local primaryTopic = not locations and module

"jctint" and args.primary_topic ~= 'no' if args.primary_topic then -- TODO transition warnings.primary_topic = "primary_topic parameter is deprecated" end

-- Independent city local indepCityText if args.indep_city_special then indepCityText = args.indep_city_special -- Overrides `indep_city` argument. elseif args.indep_city then local indepCity = args.indep_city local spec = locations.indep_city if spec then local link = format("%s%s%s", spec.linkprefix or "", indepCity, spec.linksuffix or "") local name = format("%s%s%s", spec[modulenameprefix] or spec.nameprefix or "", indepCity, spec[modulenamesuffix] or spec.namesuffix or "") indepCityText = format("%s%s%s", spec[modulearticle] or spec.article or "", spec[moduleprefix] or spec.prefix or "", link, name) else -- TODO transition warnings.indep_city = "Spec for indep_city parameter undefined in road data module" local cityLink -- Wikilink for independent city if primaryTopic then cityLink = format('%s', indepCity) else -- Specialize independent city to the region. cityLink = format('%s', indepCity, region, indepCity) end indepCityText = "City of " .. cityLink end end if indepCityText then return end

-- First-level subdivision, e.g., county -- Name of the type of subdivision, e.g., "County" and "Parish" local sub1name = args.sub1name -- TODO transition local sub1Text if args.sub1_special then sub1Text = args.sub1_special -- Overrides `sub1` argument. elseif args.sub1 then local sub1 = args.sub1 local article local link = sub1 local name = sub1 -- Type of first-level subdivision area, as a form of disambiguation local sub1area = args.sub1area if sub1area then local sub1areaSpec = locations.sub1areas and locations.sub1areas[sub1area] if sub1areaSpec then article = sub1areaSpec[modulearticle] or sub1areaSpec.article or "" link = format("%s%s%s", sub1areaSpec.linkprefix or "", link, sub1areaSpec.linksuffix or "") name = format("%s%s%s", group and "" or sub1areaSpec[modulenameprefix] or sub1areaSpec.nameprefix or "", name, group and "" or sub1areaSpec[modulenamesuffix] or sub1areaSpec.namesuffix or "") else -- TODO report error local errMsg = util.err(format("Undefined sub1area: %s", sub1area)) name = format("%s%s", name, errMsg) end end if locations.sub1 then local spec = locations.sub1 -- Prepend and append text from spec. link = format("%s%s%s", spec.linkprefix or "", link, spec.linksuffix or "") name = format("%s%s%s", spec[modulenameprefix] or spec.nameprefix or "", name, spec[modulenamesuffix] or spec.namesuffix or "") sub1Text = format("%s%s", article or "", link, name) else -- TODO transition warnings.sub1 = "Spec for sub1 parameter undefined in road data module" -- Add type (if specified) to wikilink for first-level subdivision. local sub1Link = sub1name and trim(format("%s %s", sub1, sub1name)) or sub1 local sub1Name = module

"jcttop" and sub1Link or sub1 if primaryTopic then sub1Text = format('%s', sub1Link, sub1Name) else -- Specialize first-level subdivision, with type added, to the region. sub1Text = format('%s', sub1Link, region, sub1Name) end end end

-- Second-level subdivision, e.g., city and town local sub2Text if args.sub2_special then sub2Text = args.sub2_special -- Overrides `sub2` argument. elseif args.sub2 then local sub2 = args.sub2 if sub2

"none" then sub2Text = "​" -- Zero-width space elseif sub2

" " then -- TODO transition warnings.sub2 = "  argument for sub2 parameter is deprecated" sub2Text = "​" -- Zero-width space elseif primaryTopic then -- TODO transition sub2Text = format("%s", sub2) else local article local link = sub2 local name = sub2 -- Type of area, e.g., city and village, as a form of disambiguation local sub2area = args.sub2area --TODO transition or args.area if sub2area then local sub2areaSpec = locations.sub2areas and locations.sub2areas[sub2area] if not sub2areaSpec then -- TODO transition warnings.sub2 = format("Spec for area parameter '%s' undefined in road data module", sub2area) local sub2areas = sub2areaSpec = sub2areas[sub2area] end if sub2areaSpec then article = sub2areaSpec[modulearticle] or sub2areaSpec.article or "" link = format("%s%s%s", sub2areaSpec.linkprefix or "", link, sub2areaSpec.linksuffix or "") name = format("%s%s%s", group and "" or sub2areaSpec[modulenameprefix] or sub2areaSpec.nameprefix or "", name, group and "" or sub2areaSpec[modulenamesuffix] or sub2areaSpec.namesuffix or "") else -- TODO report error local errMsg = util.err(format("Undefined sub2area: %s", sub2area)) name = format("%s%s", name, errMsg) end end if locations.sub2 then local spec = locations.sub2 -- Prepend and append text from spec. link = format("%s%s%s", spec.linkprefix or "", link, spec.linksuffix or "") name = format("%s%s%s", spec[modulenameprefix] or spec.nameprefix or "", name, spec[modulenamesuffix] or spec.namesuffix or "") else -- TODO transition warnings.sub2 = "Spec for sub2 parameter undefined in road data module" -- Some second-level subdivisions are not unique in a given region. -- `sub1dab` is the first-level subdivision to be used for disambiguation. local sub1dab = args.sub1dab if sub1dab then sub1dab = sub1name and trim(format("%s %s", sub1dab, sub1name)) or sub1dab link = format("%s, %s", link, sub1dab) end link = format("%s, %s", link, region) -- Add region to wikilink end sub2Text = format("%s%s", article or "", link, name) end end return end

return p