Module:Slug
From Landrace.wiki
More actions
Documentation for this module may be created at Module:Slug/doc
local p = {}
-- Canonical record slug.
--
-- Mirrors slugify() in tools/upload_newsitems.py (itself a mirror of
-- newsbot_move.php), so a title built by Form:NewsItem matches the
-- batch-created corpus exactly. Verified against all 357 live News:
-- pages that carry Has event headline.
--
-- Order matters: quotes and apostrophes are DROPPED before the
-- non-alphanumeric sweep, so "don't" slugs to "dont", not "don-t".
local function slugify(s)
if not s or s == '' then
return ''
end
local U = mw.ustring
s = U.gsub(s, '^%s+', '')
s = U.gsub(s, '%s+$', '')
s = U.lower(s)
s = U.gsub(s, '&', ' and ')
-- Dropped outright, not hyphenated: straight and curly apostrophes,
-- straight and curly double quotes.
s = U.gsub(s, "'", '')
s = U.gsub(s, '‘', '')
s = U.gsub(s, '’', '')
s = U.gsub(s, '"', '')
s = U.gsub(s, '“', '')
s = U.gsub(s, '”', '')
-- Every run of anything that is not a letter or a digit collapses to a
-- single hyphen. %w is Unicode-aware under mw.ustring, so non-ASCII
-- place names survive.
s = U.gsub(s, '[^%w]+', '-')
s = U.gsub(s, '^%-+', '')
s = U.gsub(s, '%-+$', '')
-- Cap length, then re-trim in case the cut landed on a hyphen.
if U.len(s) > 110 then
s = U.sub(s, 1, 110)
s = U.gsub(s, '%-+$', '')
end
return s
end
local function isTaken( name )
local t = mw.title.new( name )
return t ~= nil and t.exists
end
-- Slug only.
function p.make( frame )
local s = frame.args[1] or frame.args.text or ''
return slugify( s )
end
-- Whole canonical NewsItem page name, including the corpus's collision
-- convention: the bare title, then -2, -3, ...
--
-- This has to live here rather than in the form, because Page Forms'
-- own <unique number> cannot express it. PF swaps <unique number> for a
-- {num} placeholder BEFORE running the parser and only substitutes the
-- real value AFTER (PF_AutoeditAPI::generateTargetName), so at parse
-- time a conditional is looking at the literal string "{num}" and can
-- never tell "first page" from "third". PF also appends a BARE number,
-- giving slug2 where the corpus uses slug-2.
--
-- Usage: {{#invoke:Slug|newsitem|<date>|<category>|<headline>}}
-- Returns '' on missing input, so an incomplete form fails loudly with
-- an invalid-target error rather than building a malformed title.
function p.newsitem( frame )
local a = frame.args
local date = mw.text.trim( a[1] or a.date or '' )
local cat = mw.text.trim( a[2] or a.category or '' )
local slug = slugify( a[3] or a.headline or '' )
if date == '' or cat == '' or slug == '' then
return ''
end
local base = 'News:' .. date .. '/' .. cat .. '/' .. slug
if not isTaken( base ) then
return base
end
-- .exists is an expensive parser call; the deepest run in the live
-- corpus is -3, so this ceiling is never reached in practice.
for n = 2, 20 do
local candidate = base .. '-' .. n
if not isTaken( candidate ) then
return candidate
end
end
return base .. '-21'
end
return p