Module:Quotations/date validation

From Wiktionary, the free dictionary
Jump to navigation Jump to search
This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local canonical_AD = 'AD'
local canonical_BCE = 'BCE'
local AD_limit = 999 -- maximum year to append CE
local export = {}

local function validate_year(yearstring)
	local year = tonumber(yearstring)
	if (year == nil) then
		return false
	end
	if (year <= 0) then
		return false
	end
	return year
end

local function validate_tp(tpstring)
	-- validates ad, bc, bce, ...
	local tpstring = string.upper(tpstring)
	local tpstring = string.gsub(tpstring, "%.", "")

	local bcetable = {["BC"] = true, ["BCE"] = true}
	local adtable = {["AD"] = true, ["CE"] = true}

	if bcetable[tpstring] then
		return canonical_BCE
	end
	if adtable[tpstring] then
		return canonical_AD
	end
	return false
end

local function validate_approx(approxstring)
	approxstring = string.lower(approxstring)
	approxstring = string.gsub(approxstring, "%.", "")

	local approx_table = {["a"] = true,
				          ["c"] = true,
					      ["circa"] = true,
					      ["approx"] = true}

	if approx_table[approxstring] then
		return "a"
	end
	return false
end
	
local function parse_date(datestring)
	local result = {}
	local separators = {'-', '–'}
	local canonical_separator = '-'
	
	for i, separator in pairs(separators) do -- replace any nonstandard separators
		datestring = string.gsub(datestring, separator, canonical_separator)
	end
	
	local datetable = mw.text.split(datestring, canonical_separator)
	
	for i, yearstring in ipairs(datetable) do
		local yeartable_temp = mw.text.split(yearstring, ' ')
		
		local yeartable = {}
		for i, v in ipairs(yeartable_temp) do -- remove any empty strings
			if (v ~= '') then
				table.insert(yeartable, v)
			end
		end
		
		if (#yeartable == 1) then
			-- only year is specified
			table.insert(result, {'e', validate_year(yeartable[1]), "?"})
		end
		
		if (#yeartable == 2) then
			-- either year, BCE/AD or c, year
			local yt1 = validate_year(yeartable[1])
			local yt2 = validate_year(yeartable[2])
			
			if (yt1 ~= false) then -- year, BCE/AD
				table.insert(result, {'e', yt1, validate_tp(yeartable[2])})
			end
			
			if (yt1 == false) then -- c, year
				table.insert(result, {validate_approx(yeartable[1]), yt2, "?"})
			end
		end
		
		if (#yeartable == 3) then
			-- c, year, BCE/AD
			table.insert(result, {validate_approx(yeartable[1]), validate_year(yeartable[2]), validate_tp(yeartable[3])})
		end
		
	end

	for i, v in pairs(result) do
		for i_, v_ in pairs(v) do
			if (v_ == false) then
				return false
			end
		end
	end
	
	if (#result == 1) then
		if result[1][3] == "?" then
			result[1][3] = canonical_AD
		end
		return result
	end
	
	if (#result == 2) then
		-- add in missing time periods
		if result[1][3] == "?" then
			if result[2][3] == "?" then
				result[1][3] = canonical_AD
				result[2][3] = canonical_AD
			end
			if result[2][3] == canonical_AD then
				result[1][3] = canonical_AD
			end
			if result[2][3] == canonical_BCE then
				result[1][3] = canonical_BCE
			end
		end
		
		if result[1][3] == canonical_AD then
			if result[2][3] == "?" then
				result[2][3] = canonical_AD
			end
			if result[2][3] == canonical_BCE then
				return false
			end
		end
		
		if result[1][3] == canonical_BCE then
			if result[2][3] == "?" then
				result[2][3] = canonical_BCE
			end
		end

		-- validate time ranges
        if result[1][3] == result[2][3] then
            if result[1][3] == canonical_BCE then
                if result[2][2] > result[1][2] then
                    return false
                end
            else
            	if result[2][2] < result[1][2] then
            		return false
        		end
        	end
    	else
        	if result[1][3] == canonical_AD and result[2][3] == canonical_BCE then
            	return false
        	end
        end

		return result
	end
	
	return false
end

local function display_date(parsed_date)
	local separator = ' – '

    local CE = "<small class='ce-date'>[[Appendix:Glossary#CE|<span title=\"Glossary and display preference\">CE</span>]]</small>"
    local BCE = "<small class='ce-date'>[[Appendix:Glossary#BCE|<span title=\"Glossary and display preference\">BCE</span>]]</small>"
    local circa = "''[[circa|c.]]''"
    
    local result = {}
    
    for i, v in ipairs(parsed_date) do
    	local s = ""
    	if v[1] == 'a' then
    		s = s..circa.." "
		end
		s = s..tostring(v[2]).." "
		if v[3] == canonical_BCE then
			s = s..BCE
		end
		if v[3] == canonical_AD then
			if (v[2] <= AD_limit) then
				s = s..CE
			end
		end
		table.insert(result, mw.text.trim(s))
	end
	
	return table.concat(result, separator)
end

function export.main(datestring)

	local parsed_date = parse_date(datestring)
	if (parsed_date ~= false) then
		return display_date(parsed_date)
	end
	return datestring
end

return export