Module:Autoname/sandbox
Appearance
| This is the module sandbox page for Module:Autoname (diff). |
local utilities = require ('Module:Citation/CS1/Utilities');
local cfg = mw.loadData ('Module:Citation/CS1/Configuration');
local data = mw.loadData ('Module:Autoname/data/sandbox');
--[[--------------------------< N A M E _ H A S _ E T A L >----------------------------------------------------
Evaluates the content of name parameters (contributor, author, editor) for variations on the theme of et al. If
found, the et al. is removed.
Adapted from same-named function in Module:Citation/CS1
]]
local function name_has_etal (name)
if utilities.is_set (name) then -- name can be nil in which case just return
local patterns = cfg.et_al_patterns; -- get patterns from configuration
for _, pattern in ipairs (patterns) do -- loop through all of the patterns
if name:match (pattern) then -- if this 'et al' pattern is found in name
name = name:gsub (pattern, ''); -- remove the offending text
return name; -- and done;
end
end
end
return name; -- no etal found, return <name>
end
--[=[-------------------------< G E T _ V _ N A M E _ T A B L E >----------------------------------------------
split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in accept-
as-written markup to also have commas. Individual author names may be wikilinked.
|vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.))
Adapted from same-named function in Module:Citation/CS1
]=]
local function get_v_name_table (vparam, out_t)
local names_t = mw.text.split (vparam, "%s*,%s*"); -- names in vparam are separated by commas
local label; -- label from a wikilinked name
local i = 1; -- initialize indexer
while names_t[i] and i < 5 do -- no more than four names
if names_t[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses
local name = names_t[i];
i = i + 1; -- bump indexer to next segment
while names_t[i] do
name = name .. ', ' .. names_t[i]; -- concatenate with previous segments
if names_t[i]:match ('^.*%)%)$') then -- if this table member has the closing doubled parentheses
break; -- and done reassembling so
end
i = i + 1; -- bump indexer
end
table.insert (out_t, name); -- and add corporate name to the output table
else
local _;
_, label, _ = utilities.is_wikilink (names_t[i]); -- wl_type is: 0, no wl (text in <label>); 1, [[D]]; 2, [[L|D]]
table.insert (out_t, label); -- add this name
end
i = i + 1;
end
return out_t;
end
--[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >--------------------------------
This function extracts author / editor surnames from |vauthors= or |veditors=. Initials and generational suffixes
are discarded. Accept-as-written markup around an individual name is stripped.
Adapted from same-named function in Module:Citation/CS1
]]
local function parse_vauthors_veditors (vparam)
local names_t = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn=
local v_name_table = {};
local last, first, suffix;
vparam = name_has_etal (vparam); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period)
v_name_table = get_v_name_table (vparam, v_name_table); -- names are separated by commas
for i, v_name in ipairs (v_name_table) do
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor
local accept_name;
v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name>
if accept_name then
last = v_name;
elseif string.find (v_name, "%s") then
local lastfirst_t = mw.text.split (v_name, "%s+");
first = table.remove (lastfirst_t); -- removes and returns value of last element in table which should be initials or generational suffix
if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-Latin characters
suffix = first; -- not initials so assume that whatever we got is a generational suffix
first = table.remove (lastfirst_t); -- get what should be the initials from the table
end
last = table.concat (lastfirst_t, ' '); -- returns a string that is the concatenation of all other names that are not initials and generational suffix
if not utilities.is_set (last) then
first = ''; -- unset
last = v_name; -- last empty because something wrong with first
end
else
last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this?
end
if utilities.is_set (first) then
if utilities.is_set (suffix) then
suffix = ''; -- unset so we don't add this suffix to all subsequent names
end
end
names_t[i] = last; -- add name to names list
end
return names_t; -- all done, return list of names
end
--[[--------------------------< Y E A R _ G E T >--------------------------------------------------------------
because |date= and |publication-date= will be full aliases ofeach other at the next cs1|2 suite update, accept
only one of them; assume that |date= is the canonical form
]]
local function year_get (args_t)
local date, year;
local d_dab, y_dab; -- used to identify which to returm when both 'date' and year are set
date, d_dab = (args_t['date'] or args_t['publication-date'] or ''):match ('([1-9]%d%d%d?(%l?))'); -- if both are present prefer |date=
year, y_dab = (args_t['year'] or ''):match ('([1-9]%d%d%d?(%l?))');
if date and year then
if '' ~= d_dab then -- when no CITEREF disambiguator, <d_dab> is empty string
return date; -- prefer |date= and |publication-date= over year when 'date' has a CITEREF disambiguator
elseif '' ~= y_dab then -- when no CITEREF disambiguator, <y_dab> is empty string
return year; -- prefer |year= over 'date' when |year= has a CITEREF disambiguator
end
end
return date or year; -- when no dabs or only one of |date=, |publication-date=, or |year= set
end
--[[--------------------------< D O M A I N _ G E T >----------------------------------------------------------
extract domain name from a url.
]]
local function domain_get (url)
url = mw.text.trim (url or '')
if url == '' then return nil end
local domain = mw.ustring.match(url, "^%a[%w+.-]*://([^/?#]+)") -- Extract the domain (with or without protocol)
or mw.ustring.match(url, "^//([^/?#]+)")
or mw.ustring.match(url, "^([^/?#]+)")
if not domain then return nil end
domain = domain:gsub ("^.*@", ""):gsub (":%d+$", "") -- Remove credentials (user:pass@) and port (:8080)
local _, segments = domain:gsub ("[^.]+", "")
if segments < 2 or domain:find ('%.%.') then -- Reject values that don't look like a domain name
return nil
elseif segments > 2 then -- Remove common prefixes
domain = domain:gsub ("^ww[w%d]%d*%.", ""):gsub ("^m%.", ""):gsub ("^ftp%.", "")
end
return domain
end
--[[--------------------------< A U T O N A M E _ M A K E >----------------------------------------------------
Common function to create autoname from whichever of contributor / author / editor name list is chosen.
Attempt to prevent the autoname from being over 78 characters (80 total including a 2-digit index).
]]
local function autoname_make (names_t, year)
local suffix = (year or '') .. '-'; -- add year to name list followed by a hyphen to separate year from ve-added index digit(s)
local length = mw.ustring.len (suffix);
local output = '';
for i, name in ipairs(names_t) do
local name_length = mw.ustring.len (name);
if length + name_length > 78 then -- check if the next item would push the string over 78 characters
if i == 1 then -- first item in the list, try to truncate first on punctuation, then on spaces
local prefix = mw.ustring.sub (name, 1, 78 - length);
name = mw.ustring.match (prefix, "^(.*)%p") or mw.ustring.match (prefix, "^(.*)%s") or name;
else -- stop concatenation if it would push the string over 78 characters
break;
end
end
output = output .. name;
length = length + name_length;
end
return mw.uri.anchorEncode (output .. suffix); -- concatenate, anchor encode, and done
end
--[[--------------------------< _ A U T O N A M E >------------------------------------------------------------
entry point from another module or from the debug console
]]
local function _autoname (args_t)
local params_order_t = data.params_order_t;
local enum_params_order_t = data.enum_params_order_t;
local enum_params_t = data.enum_params_t;
local params_t = data.params_t;
local names_t = {}; -- sequence to hold values to potentially pass to autoname_make
for _, ntype in ipairs (params_order_t) do
names_t[ntype] = {};
end
for param, value in pairs (args_t) do
local enum = tonumber (param:match ('%d+')); -- get the enumerator if this parameter has one; nil else
local index = param:gsub ('%d+', '#');
local accept;
value, accept = utilities.has_accept_as_written (value); -- remove accept-as-written markup if present
if not accept then
value = name_has_etal (value);
end
if enum and (5 > enum) then -- sort enumerated name parameter values into the various sequences
for _, ntype in ipairs (enum_params_order_t) do
if enum_params_t[ntype][index] then
names_t[ntype][enum] = value;
break;
end
end
else -- sort non-enumerated name parameter values into the various sequences
for _, ntype in ipairs (params_order_t) do
if params_t[ntype][index] then
if ntype == 'url' then
names_t[ntype][1] = domain_get (value)
else
names_t[ntype][1] = value;
end
break;
end
end
end
end
if args_t['vauthors'] and #names_t.author == 0 then
names_t.author = parse_vauthors_veditors (args_t['vauthors']); -- fetch a sequence of vauthor surnames
end
if args_t['veditors'] and #names_t.editor == 0 then
names_t.editor = parse_vauthors_veditors (args_t['veditors']); -- fetch a sequence of veditor surnames
end
local year = year_get (args_t); -- get year portion of date from |date=, |publication-date=, or |year=
for _, ntype in ipairs(params_order_t) do -- in params_order_t order, make a CITEREF-like anchor for autonaming
if names_t[ntype][1] then
return autoname_make (names_t[ntype], year);
end
end
end
--[[--------------------------< A U T O N A M E >--------------------------------------------------------------
entry point from a template
]]
local function autoname (frame)
local args_t = require ('Module:Arguments').getArgs (frame); -- get the template's parameters
return _autoname (args_t); -- and render the reference name
end
--[[--------------------------E X P O R T S >------------------------------------------------------------------
]]
return {
autoname = autoname, -- entry point from a template
_autoname = _autoname, -- entry point from another module or from the debug console
}