summaryrefslogtreecommitdiff
path: root/biblio/citation-style-language/citeproc-yaml.lua
blob: 5cc7e3b3360b498b919bb0c5ec64e261e49e79c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
--
-- Copyright (c) 2021-2024 Zeping Lee
-- Released under the MIT license.
-- Repository: https://github.com/zepinglee/citeproc-lua
--

local csl_yaml = {}

local yaml
local util

if kpse then
  yaml = require("tinyyaml")
  util = require("citeproc-util")
else
  yaml = require("tinyyaml")
  util = require("citeproc.util")
end


-- Convert CSL-YAML string to CSL-JSON

---@param str string
---@return CslData
function csl_yaml.parse(str)
  -- lua-tinyyaml 0.4.2 doesn't support dots terminator.
  -- See <https://github.com/api7/lua-tinyyaml/issues/22>.
  str = string.gsub(str, "%.%.%.%s*$", "")

  local status, items = pcall(yaml.parse, str)
  if not status then
    local err = items
    util.error("Failed to parse the YAML contents:\n" .. err)
    return {}
  end

  -- The items exported from Better BibTeX has a {references = []} structure.
  if type(items) == 'table' and items.references then
    items = items.references
  end

  for _, item in ipairs(items) do
    for field, value in pairs(item) do
      if util.variable_types[field] == "date" then
        if type(value) == "number" then
          value = tostring(value)
        end
        if type(value) == "string" then
          -- "2005-11-22"
          -- EDTF is not supported until CSL v1.1.
          local date = util.parse_edtf(value)
          if not date then
            date = {literal = value}
          end
          item[field] = date

        elseif type(value) == "table" and not value["date-parts"] then
          local new_date = {
            ["date-parts"] = {}
          }

          if value.year then
            -- Generated by lua-tinyyaml parser
            new_date["date-parts"][1] = {}
            for j, part_name in ipairs({"year", "month", "day"}) do
              local date_part = value[part_name]
              if date_part then
                new_date["date-parts"][1][j] = date_part
              end
            end

          elseif #value >= 1 then
            -- Exported by Better BibTeX
            for i, range_part in ipairs(value) do
              new_date["date-parts"][i] = {}
              for _, part_name in ipairs({"year", "month", "day"}) do
                local date_part = range_part[part_name]
                if date_part then
                  table.insert(new_date["date-parts"][i], date_part)
                end
              end
            end
          end

          item[field] = new_date
        end
      end
    end
  end

  return items
end


return csl_yaml