add extensions
This commit is contained in:
6
_extensions/pandoc-ext/abstract-section/_extension.yaml
Executable file
6
_extensions/pandoc-ext/abstract-section/_extension.yaml
Executable file
@@ -0,0 +1,6 @@
|
||||
name: abstract-section
|
||||
author: Albert Krewinkel
|
||||
version: 1.0.0
|
||||
contributes:
|
||||
filters:
|
||||
- abstract-section.lua
|
||||
59
_extensions/pandoc-ext/abstract-section/abstract-section.lua
Executable file
59
_extensions/pandoc-ext/abstract-section/abstract-section.lua
Executable file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
abstract-to-meta – move an "abstract" section into document metadata
|
||||
|
||||
Copyright: © 2017–2021 Albert Krewinkel
|
||||
License: MIT – see LICENSE file for details
|
||||
]]
|
||||
local abstract = {}
|
||||
|
||||
--- Extract abstract from a list of blocks.
|
||||
function abstract_from_blocklist (blocks)
|
||||
local body_blocks = {}
|
||||
local looking_at_abstract = false
|
||||
|
||||
for _, block in ipairs(blocks) do
|
||||
if block.t == 'Header' and block.level == 1 then
|
||||
if block.identifier == 'abstract' then
|
||||
looking_at_abstract = true
|
||||
else
|
||||
looking_at_abstract = false
|
||||
body_blocks[#body_blocks + 1] = block
|
||||
end
|
||||
elseif looking_at_abstract then
|
||||
if block.t == 'HorizontalRule' then
|
||||
looking_at_abstract = false
|
||||
else
|
||||
abstract[#abstract + 1] = block
|
||||
end
|
||||
else
|
||||
body_blocks[#body_blocks + 1] = block
|
||||
end
|
||||
end
|
||||
|
||||
return body_blocks
|
||||
end
|
||||
|
||||
if PANDOC_VERSION >= {2,9,2} then
|
||||
-- Check all block lists with pandoc 2.9.2 or later
|
||||
return {{
|
||||
Blocks = abstract_from_blocklist,
|
||||
Meta = function (meta)
|
||||
if not meta.abstract and #abstract > 0 then
|
||||
meta.abstract = pandoc.MetaBlocks(abstract)
|
||||
end
|
||||
return meta
|
||||
end
|
||||
}}
|
||||
else
|
||||
-- otherwise, just check the top-level block-list
|
||||
return {{
|
||||
Pandoc = function (doc)
|
||||
local meta = doc.meta
|
||||
local other_blocks = abstract_from_blocklist(doc.blocks)
|
||||
if not meta.abstract and #abstract > 0 then
|
||||
meta.abstract = pandoc.MetaBlocks(abstract)
|
||||
end
|
||||
return pandoc.Pandoc(other_blocks, meta)
|
||||
end,
|
||||
}}
|
||||
end
|
||||
6
_extensions/pandoc-ext/author-info-blocks/_extension.yaml
Executable file
6
_extensions/pandoc-ext/author-info-blocks/_extension.yaml
Executable file
@@ -0,0 +1,6 @@
|
||||
name: author-info-blocks
|
||||
author: Albert Krewinkel
|
||||
version: 1.0.0
|
||||
contributes:
|
||||
filters:
|
||||
- author-info-blocks.lua
|
||||
179
_extensions/pandoc-ext/author-info-blocks/author-info-blocks.lua
Executable file
179
_extensions/pandoc-ext/author-info-blocks/author-info-blocks.lua
Executable file
@@ -0,0 +1,179 @@
|
||||
local List = require("pandoc.List")
|
||||
local utils = require("pandoc.utils")
|
||||
local stringify = utils.stringify
|
||||
local byAuthor
|
||||
local byAffiliation
|
||||
local Authors = {}
|
||||
local Affiliations = {}
|
||||
|
||||
local authorHoriz
|
||||
|
||||
local Corresponding = nil
|
||||
local function make_correspondance(name, email)
|
||||
correspondance = List:new({
|
||||
pandoc.Str("* Corresponding Author: "),
|
||||
pandoc.Str(name),
|
||||
pandoc.Str(" ("),
|
||||
pandoc.Link(email, "mailto:" .. email),
|
||||
pandoc.Str(")"),
|
||||
})
|
||||
Corresponding = List:new({ pandoc.Para(correspondance) })
|
||||
end
|
||||
|
||||
local equalCont
|
||||
local function make_equal_contributor()
|
||||
eq_statement = pandoc.Str("† These authors contributed equally to this work.")
|
||||
equalCont = List:new({ pandoc.Para(eq_statement) })
|
||||
end
|
||||
|
||||
local function create_author_list(byAuthor)
|
||||
local authors = {}
|
||||
for i, author in ipairs(byAuthor) do
|
||||
local sups = {}
|
||||
|
||||
for j, aff in ipairs(author.affiliations) do
|
||||
table.insert(sups, aff.number)
|
||||
end
|
||||
sups_str = table.concat(sups, ",")
|
||||
|
||||
local name = stringify(author.name.literal)
|
||||
|
||||
if author.attributes ~= nil then
|
||||
if author.attributes["equal-contributor"] ~= nil and author.attributes["equal-contributor"] then
|
||||
sups_str = sups_str .. ",†"
|
||||
make_equal_contributor()
|
||||
end
|
||||
if author.attributes.corresponding ~= nil and author.attributes.corresponding then
|
||||
local email = stringify(author.email)
|
||||
sups_str = sups_str .. ",*"
|
||||
make_correspondance(name, email)
|
||||
end
|
||||
end
|
||||
|
||||
local authorEntry = List:new({
|
||||
pandoc.Str(name),
|
||||
pandoc.Superscript(pandoc.Str(sups_str)),
|
||||
})
|
||||
|
||||
if authorHoriz and i < #byAuthor then
|
||||
authorEntry:extend({ pandoc.Str(", ") })
|
||||
end
|
||||
|
||||
table.insert(authors, pandoc.Span(authorEntry))
|
||||
end
|
||||
|
||||
if authorHoriz then
|
||||
Authors = { pandoc.Para(authors) }
|
||||
else
|
||||
Authors = authors
|
||||
end
|
||||
end
|
||||
|
||||
local function create_affiliation_list(byAffiliation)
|
||||
for i, aff in ipairs(byAffiliation) do
|
||||
local full_aff = pandoc.List({})
|
||||
if aff.name then
|
||||
full_aff:insert(stringify(aff.name))
|
||||
end
|
||||
|
||||
if aff.address then
|
||||
full_aff:insert(stringify(aff.address))
|
||||
end
|
||||
|
||||
if aff.city then
|
||||
full_aff:insert(stringify(aff.city))
|
||||
end
|
||||
|
||||
if aff["postal-code"] then
|
||||
full_aff:insert(stringify(aff["postal-code"]))
|
||||
end
|
||||
|
||||
if aff.region then
|
||||
full_aff:insert(stringify(aff.region))
|
||||
end
|
||||
|
||||
if aff.country then
|
||||
full_aff:insert(stringify(aff.country))
|
||||
end
|
||||
|
||||
local entry = table.concat(full_aff, ", ")
|
||||
entry = aff.number .. ". " .. entry .. "."
|
||||
table.insert(Affiliations, pandoc.Para(pandoc.Str(entry)))
|
||||
end
|
||||
end
|
||||
|
||||
local Abstract = nil
|
||||
local function create_abstract(ab)
|
||||
Abstract = {}
|
||||
table.insert(Abstract, pandoc.Header(1, "Abstract"))
|
||||
table.insert(Abstract, pandoc.Para(ab))
|
||||
end
|
||||
|
||||
local Keywords = nil
|
||||
local function create_keyword_list(kw)
|
||||
Keywords = {}
|
||||
-- quarto.log.output(kw)
|
||||
local kws = pandoc.List({})
|
||||
for i, keyword in ipairs(kw) do
|
||||
kws:insert(stringify(keyword))
|
||||
end
|
||||
local kwentry = table.concat(kws, "; ")
|
||||
kwentry = "Keywords: " .. kwentry .. "."
|
||||
table.insert(Keywords, pandoc.Para(pandoc.Str(kwentry)))
|
||||
end
|
||||
|
||||
local function remove_author_meta(meta)
|
||||
meta.author = nil
|
||||
meta.authors = nil
|
||||
meta.affiliations = nil
|
||||
meta["by-author"] = nil
|
||||
meta["by-affiliation"] = nil
|
||||
meta["abstract"] = nil
|
||||
return meta
|
||||
end
|
||||
|
||||
return {
|
||||
{
|
||||
Meta = function(meta)
|
||||
byAuthor = meta["by-author"]
|
||||
byAffiliation = meta["by-affiliation"]
|
||||
if meta["author-horizontal"] ~= nil then
|
||||
authorHoriz = meta["author-horizontal"]
|
||||
else
|
||||
authorHoriz = true
|
||||
end
|
||||
create_author_list(byAuthor)
|
||||
create_affiliation_list(byAffiliation)
|
||||
if meta["abstract"] ~= nil then
|
||||
create_abstract(meta["abstract"])
|
||||
end
|
||||
if meta["keywords"] ~= nil then
|
||||
create_keyword_list(meta["keywords"])
|
||||
end
|
||||
return meta
|
||||
end,
|
||||
},
|
||||
{
|
||||
Pandoc = function(doc)
|
||||
local meta = doc.meta
|
||||
local body = List:new({})
|
||||
body:extend(Authors)
|
||||
body:extend(Affiliations)
|
||||
if equalCont ~= nil then
|
||||
body:extend(equalCont)
|
||||
end
|
||||
if Corresponding ~= nil then
|
||||
body:extend(Corresponding)
|
||||
end
|
||||
if Abstract then
|
||||
body:extend(Abstract)
|
||||
end
|
||||
if Keywords then
|
||||
body:extend(Keywords)
|
||||
end
|
||||
body:extend(doc.blocks)
|
||||
meta = remove_author_meta(meta)
|
||||
return pandoc.Pandoc(body, meta)
|
||||
end,
|
||||
},
|
||||
}
|
||||
6
_extensions/pandoc-ext/scholarly-metadata/_extension.yaml
Executable file
6
_extensions/pandoc-ext/scholarly-metadata/_extension.yaml
Executable file
@@ -0,0 +1,6 @@
|
||||
name: scholarly-metadata
|
||||
author: Albert Krewinkel
|
||||
version: 1.0.0
|
||||
contributes:
|
||||
filters:
|
||||
- scholarly-metadata.lua
|
||||
197
_extensions/pandoc-ext/scholarly-metadata/scholarly-metadata.lua
Executable file
197
_extensions/pandoc-ext/scholarly-metadata/scholarly-metadata.lua
Executable file
@@ -0,0 +1,197 @@
|
||||
--[[
|
||||
ScholarlyMeta – normalize author/affiliation meta variables
|
||||
|
||||
Copyright (c) 2017-2021 Albert Krewinkel, Robert Winkler
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
]]
|
||||
local List = require("pandoc.List")
|
||||
|
||||
--- Returns the type of a metadata value.
|
||||
--
|
||||
-- @param v a metadata value
|
||||
-- @treturn string one of `Blocks`, `Inlines`, `List`, `Map`, `string`, `boolean`
|
||||
local function metatype(v)
|
||||
if PANDOC_VERSION <= "2.16.2" then
|
||||
local metatag = type(v) == "table" and v.t and v.t:gsub("^Meta", "")
|
||||
return metatag and metatag ~= "Map" and metatag or type(v)
|
||||
end
|
||||
return pandoc.utils.type(v)
|
||||
end
|
||||
|
||||
local type = pandoc.utils.type or metatype
|
||||
|
||||
-- Split a string at commas.
|
||||
local function comma_separated_values(str)
|
||||
local acc = List:new({})
|
||||
for substr in str:gmatch("([^,]*)") do
|
||||
acc[#acc + 1] = substr:gsub("^%s*", ""):gsub("%s*$", "") -- trim
|
||||
end
|
||||
return acc
|
||||
end
|
||||
|
||||
--- Ensure the return value is a list.
|
||||
local function ensure_list(val)
|
||||
if type(val) == "List" then
|
||||
return val
|
||||
elseif type(val) == "Inlines" then
|
||||
-- check if this is really a comma-separated list
|
||||
local csv = comma_separated_values(pandoc.utils.stringify(val))
|
||||
if #csv >= 2 then
|
||||
return csv
|
||||
end
|
||||
return List:new({ val })
|
||||
elseif type(val) == "table" and #val > 0 then
|
||||
return List:new(val)
|
||||
else
|
||||
-- Anything else, use as a singleton (or empty list if val == nil).
|
||||
return List:new({ val })
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a function which checks whether an object has the given ID.
|
||||
local function has_id(id)
|
||||
return function(x)
|
||||
return x.id == id
|
||||
end
|
||||
end
|
||||
|
||||
--- Copy all key-value pairs of the first table into the second iff there is no
|
||||
-- such key yet in the second table.
|
||||
-- @returns the second argument
|
||||
function add_missing_entries(a, b)
|
||||
for k, v in pairs(a) do
|
||||
b[k] = b[k] or v
|
||||
end
|
||||
return b
|
||||
end
|
||||
|
||||
--- Create an object with a name. The name is either taken directly from the
|
||||
-- `name` field, or from the *only* field name (i.e., key) if the object is a
|
||||
-- dictionary with just one entry. If neither exists, the name is left unset
|
||||
-- (`nil`).
|
||||
function to_named_object(obj)
|
||||
local named = {}
|
||||
if type(obj) == "Inlines" then
|
||||
-- Treat inlines as the name
|
||||
named.name = obj
|
||||
named.id = pandoc.utils.stringify(obj)
|
||||
elseif type(obj) ~= "table" then
|
||||
-- if the object isn't a table, just use its value as a name.
|
||||
named.name = pandoc.MetaInlines({ pandoc.Str(tostring(obj)) })
|
||||
named.id = tostring(obj)
|
||||
elseif obj.name ~= nil then
|
||||
-- object has name attribute → just create a copy of the object
|
||||
add_missing_entries(obj, named)
|
||||
named.id = pandoc.utils.stringify(named.id or named.name)
|
||||
elseif next(obj) and next(obj, next(obj)) == nil then
|
||||
-- Single-entry table. The entry's key is taken as the name, the value
|
||||
-- contains the attributes.
|
||||
key, attribs = next(obj)
|
||||
if type(attribs) == "string" or type(attribs) == "Inlines" then
|
||||
named.name = attribs
|
||||
else
|
||||
add_missing_entries(attribs, named)
|
||||
named.name = named.name or pandoc.MetaInlines({ pandoc.Str(tostring(key)) })
|
||||
end
|
||||
named.id = named.id and pandoc.utils.stringify(named.id) or key
|
||||
else
|
||||
-- this is not a named object adhering to the usual conventions.
|
||||
error("not a named object: " .. tostring(obj))
|
||||
end
|
||||
return named
|
||||
end
|
||||
|
||||
--- Resolve affiliations placeholders to full named objects
|
||||
local function resolve_affiliations(affiliations, known_affiliations)
|
||||
local unresolved_affiliations
|
||||
if affiliations == nil then
|
||||
unresolved_affiliations = {}
|
||||
elseif type(affiliations) == "string" or type(affiliations) == "number" then
|
||||
unresolved_affiliations = { affiliations }
|
||||
else
|
||||
unresolved_affiliations = affiliations
|
||||
end
|
||||
|
||||
local result = List:new({})
|
||||
for i, inst in ipairs(unresolved_affiliations) do
|
||||
result[i] = known_affiliations[tonumber(inst)]
|
||||
or known_affiliations:find_if(has_id(pandoc.utils.stringify(inst)))
|
||||
or to_named_object(inst)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Insert a named object into a list; if an object of the same name exists
|
||||
-- already, add all properties only present in the new object to the existing
|
||||
-- item.
|
||||
function merge_on_id(list, namedObj)
|
||||
local elem, idx = list:find_if(has_id(namedObj.id))
|
||||
local res = elem and add_missing_entries(namedObj, elem) or namedObj
|
||||
local obj_idx = idx or (#list + 1)
|
||||
-- return res, obj_idx
|
||||
list[obj_idx] = res
|
||||
return res, #list
|
||||
end
|
||||
|
||||
--- Flatten a list of lists.
|
||||
local function flatten(lists)
|
||||
local result = List:new({})
|
||||
for _, lst in ipairs(lists) do
|
||||
result:extend(lst)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Canonicalize authors and affiliations
|
||||
local function canonicalize(raw_author, raw_affiliations)
|
||||
local affiliations = ensure_list(raw_affiliations):map(to_named_object)
|
||||
local authors = ensure_list(raw_author):map(to_named_object)
|
||||
|
||||
for _, author in ipairs(authors) do
|
||||
author.affiliations = resolve_affiliations(ensure_list(author.affiliations), affiliations)
|
||||
end
|
||||
|
||||
-- Merge affiliations defined in author objects with those defined in the
|
||||
-- top-level list.
|
||||
local author_insts = flatten(authors:map(function(x)
|
||||
return x.affiliations
|
||||
end))
|
||||
for _, inst in ipairs(author_insts) do
|
||||
merge_on_id(affiliations, inst)
|
||||
end
|
||||
|
||||
-- Add list indices to affiliations for numbering and reference purposes
|
||||
for idx, inst in ipairs(affiliations) do
|
||||
inst.index = pandoc.MetaInlines({ pandoc.Str(tostring(idx)) })
|
||||
end
|
||||
|
||||
-- replace affiliations with their indices
|
||||
local to_index = function(inst)
|
||||
return tostring(select(2, affiliations:find_if(has_id(inst.id))))
|
||||
end
|
||||
for _, author in ipairs(authors) do
|
||||
author.affiliations = pandoc.MetaList(author.affiliations:map(to_index))
|
||||
end
|
||||
|
||||
return authors, affiliations
|
||||
end
|
||||
|
||||
return {
|
||||
{
|
||||
Meta = function(meta)
|
||||
meta.author, meta.affiliations = canonicalize(meta.author, meta.affiliations)
|
||||
return meta
|
||||
end,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user