summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua')
-rw-r--r--Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua379
1 files changed, 379 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua
new file mode 100644
index 00000000000..9c712a8135b
--- /dev/null
+++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-node-date.lua
@@ -0,0 +1,379 @@
+local date_module = {}
+
+local element = require("citeproc-element")
+local util = require("citeproc-util")
+
+
+local Date = element.Element:new()
+
+function Date:render (item, context)
+ self:debug_info(context)
+ context = self:process_context(context)
+
+ if context.sorting then
+ return self:render_sort_key(item, context)
+ end
+
+ local variable_name = context.options["variable"]
+
+ local is_locale_date
+ if variable_name then
+ context.variable = variable_name
+ is_locale_date = false
+ else
+ variable_name = context.variable
+ is_locale_date = true
+ end
+
+ local date = self:get_variable(item, variable_name, context)
+ if not date then
+ return nil
+ end
+
+ local res = nil
+ local form = context.options["form"]
+ if form and not is_locale_date then
+ for _, date_part in ipairs(self:query_selector("date-part")) do
+ local name = date_part:get_attribute("name")
+ if not context.date_part_attributes then
+ context.date_part_attributes = {}
+ end
+ if not context.date_part_attributes[name] then
+ context.date_part_attributes[name] = {}
+ end
+
+ for attr, value in pairs(date_part._attr) do
+ if attr ~= name then
+ context.date_part_attributes[name][attr] = value
+ end
+ end
+ end
+ res = self:get_locale_date(context, form):render(item, context)
+ else
+ if not date["date-parts"] or #date["date-parts"] == 0 then
+ local literal = date["literal"]
+ if literal then
+ res = literal
+ else
+ local raw = date["raw"]
+ if raw then
+ res = raw
+ end
+ end
+
+ else
+ if #date["date-parts"] == 1 then
+ res = self:_render_single_date(date, context)
+ elseif #date["date-parts"] == 2 then
+ res = self:_render_date_range(date, context)
+ end
+ end
+ end
+
+ table.insert(context.variable_attempt, res ~= nil)
+
+ res = self:format(res, context)
+ res = self:wrap(res, context)
+ return res
+end
+
+function Date:get_locale_date(context, form)
+ local date = nil
+ local style = context.style
+ local query = string.format("date[form=\"%s\"]", form)
+ for _, locale in ipairs(style:get_locales()) do
+ date = locale:query_selector(query)[1]
+ if date then
+ break
+ end
+ end
+ if not date then
+ error(string.format("Failed to find '%s'", query))
+ end
+ return date
+end
+
+function Date:render_sort_key (item, context)
+ local variable_name = context.options["variable"]
+ local date = self:get_variable(item, variable_name, context)
+ if not date or not date["date-parts"] then
+ return nil
+ end
+ local show_parts = {
+ year = false,
+ month = false,
+ day = false,
+ }
+ if self:get_attribute("form") then
+ local date_parts = self:get_attribute("date-parts") or "year-month-day"
+ for _, dp_name in ipairs(util.split(date_parts, "%-")) do
+ show_parts[dp_name] = true
+ end
+ else
+ for _, child in ipairs(self:query_selector("date-part")) do
+ show_parts[child:get_attribute("name")] = true
+ end
+ end
+ local res = ""
+ for _, date_parts in ipairs(date["date-parts"]) do
+ for i, dp_name in ipairs({"year", "month", "day"}) do
+ local value = date_parts[i]
+ if not value or not show_parts[dp_name] then
+ value = 0
+ end
+ if i == 1 then
+ res = res .. string.format("%05d", value + 10000)
+ else
+ res = res .. string.format("%02d", value)
+ end
+ end
+ end
+ return res
+end
+
+function Date:_render_single_date (date, context)
+ local show_parts = self:_get_show_parts(context)
+
+ local output = {}
+ for _, child in ipairs(self:query_selector("date-part")) do
+ if show_parts[child:get_attribute("name")] then
+ table.insert(output, child:render(date, context))
+ end
+ end
+ return self:concat(output, context)
+end
+
+function Date:_render_date_range (date, context)
+ local show_parts = self:_get_show_parts(context)
+ local part_index = {}
+
+ local largest_diff_part = nil
+ for i, name in ipairs({"year", "month", "day"}) do
+ part_index[name] = i
+ local part_value1 = date["date-parts"][1][i]
+ if show_parts[name] and part_value1 then
+ if not largest_diff_part then
+ largest_diff_part = name
+ end
+ end
+ end
+
+ local date_parts = {}
+ for _, date_part in ipairs(self:query_selector("date-part")) do
+ if show_parts[date_part:get_attribute("name")] then
+ table.insert(date_parts, date_part)
+ end
+ end
+
+ local diff_begin = 0
+ local diff_end = #date_parts
+ local range_delimiter = nil
+
+ for i, date_part in ipairs(date_parts) do
+ local name = date_part:get_attribute("name")
+ if name == largest_diff_part then
+ range_delimiter = date_part:get_attribute("range-delimiter")
+ if not range_delimiter then
+ range_delimiter = util.unicode["en dash"]
+ end
+ end
+
+ local index = part_index[name]
+ local part_value1 = date["date-parts"][1][index]
+ local part_value2 = date["date-parts"][2][index]
+ if part_value1 and part_value1 ~= part_value2 then
+ if diff_begin == 0 then
+ diff_begin = i
+ end
+ diff_end = i
+ end
+ end
+
+ local same_prefix = {}
+ local range_begin = {}
+ local range_end = {}
+ local same_suffix = {}
+
+ local no_suffix_context = self:process_context(context)
+ no_suffix_context.options["suffix"] = nil
+
+ for i, date_part in ipairs(date_parts) do
+ local res = nil
+ if i == diff_end then
+ res = date_part:render(date, no_suffix_context, true)
+ else
+ res = date_part:render(date, context)
+ end
+ if i < diff_begin then
+ table.insert(same_prefix, res)
+ elseif i <= diff_end then
+ table.insert(range_begin, res)
+ table.insert(range_end, date_part:render(date, context, false, true))
+ else
+ table.insert(same_suffix, res)
+ end
+ end
+
+ local prefix_output = self:concat(same_prefix, context) or ""
+ local range_begin_output = self:concat(range_begin, context) or ""
+ local range_end_output = self:concat(range_end, context) or ""
+ local suffix_output = self:concat(same_suffix, context)
+ local range_output = range_begin_output .. range_delimiter .. range_end_output
+
+ local res = self:concat({prefix_output, range_output, suffix_output}, context)
+
+ return res
+end
+
+function Date:_get_show_parts (context)
+ local show_parts = {}
+ local date_parts = context.options["date-parts"] or "year-month-day"
+ for _, date_part in ipairs(util.split(date_parts, "%-")) do
+ show_parts[date_part] = true
+ end
+ return show_parts
+end
+
+
+local DatePart = element.Element:new()
+
+DatePart.render = function (self, date, context, last_range_begin, range_end)
+ self:debug_info(context)
+ context = self:process_context(context)
+ local name = context.options["name"]
+ local range_delimiter = context.options["range-delimiter"] or false
+
+ -- The attributes set on cs:date-part elements of a cs:date with form
+ -- attribute override those specified for the localized date formats
+ if context.date_part_attributes then
+ local context_attributes = context.date_part_attributes[name]
+ if context_attributes then
+ for attr, value in pairs(context_attributes) do
+ context.options[attr] = value
+ end
+ end
+ end
+
+ if last_range_begin then
+ context.options["suffix"] = ""
+ end
+
+ local date_parts_index = 1
+ if range_end then
+ date_parts_index = 2
+ end
+
+ local res = nil
+ if name == "day" then
+ local day = date["date-parts"][date_parts_index][3]
+ if not day then
+ return nil
+ end
+ day = tonumber(day)
+ -- range open
+ if day == 0 then
+ return nil
+ end
+ local form = context.options["form"] or "numeric"
+
+ if form == "ordinal" then
+ local option = self:get_locale_option("limit-day-ordinals-to-day-1")
+ if option and option ~= "false" and day > 1 then
+ form = "numeric"
+ end
+ end
+ if form == "numeric" then
+ res = tostring(day)
+ elseif form == "numeric-leading-zeros" then
+ -- TODO: day == nil?
+ if not day then
+ return nil
+ end
+ res = string.format("%02d", day)
+ elseif form == "ordinal" then
+ res = util.to_ordinal(day)
+ end
+
+ elseif name == "month" then
+ local form = context.options["form"] or "long"
+
+ local month = date["date-parts"][date_parts_index][2]
+ if month then
+ month = tonumber(month)
+ -- range open
+ if month == 0 then
+ return nil
+ end
+ end
+
+ if form == "long" or form == "short" then
+ local term_name = nil
+ if month then
+ if month >= 1 and month <= 12 then
+ term_name = string.format("month-%02d", month)
+ elseif month >= 13 and month <= 24 then
+ local season = month % 4
+ if season == 0 then
+ season = 4
+ end
+ term_name = string.format("season-%02d", season)
+ else
+ util.warning("Invalid month value")
+ return nil
+ end
+ else
+ local season = date["season"]
+ if season then
+ season = tonumber(season)
+ term_name = string.format("season-%02d", season)
+ else
+ return nil
+ end
+ end
+ res = self:get_term(term_name, form):render(context)
+ elseif form == "numeric" then
+ res = tostring(month)
+ elseif form == "numeric-leading-zeros" then
+ -- TODO: month == nil?
+ if not month then
+ return nil
+ end
+ res = string.format("%02d", month)
+ end
+ res = self:strip_periods(res, context)
+
+ elseif name == "year" then
+ local year = date["date-parts"][date_parts_index][1]
+ if year then
+ year = tonumber(year)
+ -- range open
+ if year == 0 then
+ return nil
+ end
+ local form = context.options["form"] or "long"
+ if form == "long" then
+ year = tonumber(year)
+ if year < 0 then
+ res = tostring(-year) .. self:get_term("bc"):render(context)
+ elseif year < 1000 then
+ res = tostring(year) .. self:get_term("ad"):render(context)
+ else
+ res = tostring(year)
+ end
+ elseif form == "short" then
+ res = string.sub(tostring(year), -2)
+ end
+ end
+ end
+ res = self:case(res, context)
+ res = self:format(res, context)
+ res = self:wrap(res, context)
+ res = self:display(res, context)
+ return res
+end
+
+
+date_module.Date = Date
+date_module.DatePart = DatePart
+
+return date_module