Skip to content

Commit 9f82f96

Browse files
committed
Support contributor roles via CRediT
1 parent 31ffd1e commit 9f82f96

File tree

16 files changed

+820
-1
lines changed

16 files changed

+820
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
`Inara` uses [SemVer][] (semantic versioning).
44

5+
## UNRELEASED
6+
7+
- Support for annotating contributor roles with the Contribution Role Taxonomy (CRediT).
8+
A text table is generated at the bottom of the PDF and preprint template containing
9+
this information. As of https://github.com/jgm/pandoc/pull/10153, Pandoc will generate
10+
conformant JATS containing contibutor roles. (https://github.com/openjournals/inara/pull/87)
11+
512
## Inara v1.1.4
613

714
Released 2024-11-06.

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
FROM pandoc/latex:3.2.0-alpine
1+
# WARNING: this PR contains changes to pandoc from https://github.com/jgm/pandoc/pull/10153
2+
# that aren't yet released. They should land in the 3.6.3 future version
3+
FROM pandoc/latex:3.6.3-alpine
24

35
RUN apk add --no-cache ttf-hack
46

data/defaults/jats.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ filters:
1818
# do it here for that reason.
1919
type: lua
2020
path: orcid-uri.lua
21+
22+
- type: lua
23+
path: prepare-credit.lua

data/defaults/pdf.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ filters:
1111
path: self-citation.lua
1212
- type: lua
1313
path: fix-bibentry-spacing.lua
14+
- type: lua
15+
path: prepare-credit.lua
1416
variables:
1517
# styling options
1618
colorlinks: true

data/defaults/preprint.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
to: latex
22
output-file: paper.preprint.tex
33
template: preprint.latex
4+
filters:
5+
- type: lua
6+
path: prepare-credit.lua
47
variables:
58
# styling options
69
colorlinks: true

data/defaults/tex.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ filters:
1111
path: self-citation.lua
1212
- type: lua
1313
path: fix-bibentry-spacing.lua
14+
- type: lua
15+
path: prepare-credit.lua
1416
variables:
1517
# styling options
1618
colorlinks: true

data/filters/prepare-credit.lua

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
-- Checks if any contributor information is available
2+
3+
local roles = {
4+
["conceptualization"] = {
5+
name = "Conceptualization",
6+
id = "8b73531f-db56-4914-9502-4cc4d4d8ed73",
7+
uri = "https://credit.niso.org/contributor-roles/conceptualization/"
8+
},
9+
["data-curation"] = {
10+
name = "Data curation",
11+
id = "f93e0f44-f2a4-4ea1-824a-4e0853b05c9d",
12+
uri = "https://credit.niso.org/contributor-roles/data-curation/"
13+
},
14+
["formal-analysis"] = {
15+
name = "Formal analysis",
16+
id = "95394cbd-4dc8-4735-b589-7e5f9e622b3f",
17+
uri = "https://credit.niso.org/contributor-roles/formal-analysis/"
18+
},
19+
["funding-acquisition"] = {
20+
name = "Funding acquisition",
21+
id = "34ff6d68-132f-4438-a1f4-fba61ccf364a",
22+
uri = "https://credit.niso.org/contributor-roles/funding-acquisition/"
23+
},
24+
["investigation"] = {
25+
name = "Investigation",
26+
id = "2451924d-425e-4778-9f4c-36c848ca70c2",
27+
uri = "https://credit.niso.org/contributor-roles/investigation/"
28+
},
29+
["methodology"] = {
30+
name = "Methodology",
31+
id = "f21e2be9-4e38-4ab7-8691-d6f72d5d5843",
32+
uri = "https://credit.niso.org/contributor-roles/methodology/"
33+
},
34+
["project-administration"] = {
35+
name = "Project administration",
36+
id = "a693fe76-ea33-49ad-9dcc-5e4f3ac5f938",
37+
uri = "https://credit.niso.org/contributor-roles/project-administration/"
38+
},
39+
["resources"] = {
40+
name = "Resources",
41+
id = "ebd781f0-bf79-492c-ac21-b31b9c3c990c",
42+
uri = "https://credit.niso.org/contributor-roles/resources/"
43+
},
44+
["software"] = {
45+
name = "Software",
46+
id = "f89c5233-01b0-4778-93e9-cc7d107aa2c8",
47+
uri = "https://credit.niso.org/contributor-roles/software/"
48+
},
49+
["supervision"] = {
50+
name = "Supervision",
51+
id = "0c8ca7d4-06ad-4527-9cea-a8801fcb8746",
52+
uri = "https://credit.niso.org/contributor-roles/supervision/"
53+
},
54+
["validation"] = {
55+
name = "Validation",
56+
id = "4b1bf348-faf2-4fc4-bd66-4cd3a84b9d44",
57+
uri = "https://credit.niso.org/contributor-roles/validation/"
58+
},
59+
["visualization"] = {
60+
name = "Visualization",
61+
id = "76b9d56a-e430-4e0a-84c9-59c11be343ae",
62+
uri = "https://credit.niso.org/contributor-roles/visualization/"
63+
},
64+
["writing-original-draft"] = {
65+
name = "Writing – original draft",
66+
id = "43ebbd94-98b4-42f1-866b-c930cef228ca",
67+
uri = "https://credit.niso.org/contributor-roles/writing-original-draft/"
68+
},
69+
["writing-review-editing"] = {
70+
name = "Writing – review & editing",
71+
id = "d3aead86-f2a2-47f7-bb99-79de6421164d",
72+
uri = "https://credit.niso.org/contributor-roles/writing-review-editing/"
73+
}
74+
}
75+
76+
-- An enumeration of the JATS-recommended degrees of contribution
77+
degrees = pandoc.List {
78+
"Lead",
79+
"Supporting",
80+
"Equal"
81+
}
82+
83+
-- Check if the given string is one of the 14 valid
84+
-- CRediT identifiers by looking at the `roles` dict
85+
-- defined above
86+
function invalidCreditID(str)
87+
return roles[str] == nil
88+
end
89+
90+
-- Check if the degree contribution is valid based on the JATS recommendation,
91+
-- see https://jats.taylorandfrancis.com/jats-guide/topics/author-contributions-credit/#degree-of-contribution
92+
function invalidDegree(str)
93+
return not degrees:includes(str)
94+
end
95+
96+
function join_with_commas_and(list)
97+
local len = #list
98+
if len == 0 then
99+
return ""
100+
elseif len == 1 then
101+
return list[1]
102+
elseif len == 2 then
103+
return list[1] .. " & " .. list[2]
104+
else
105+
local result = table.concat(list, ", ", 1, len - 1)
106+
return result .. ", & " .. list[len]
107+
end
108+
end
109+
110+
function capitalize_first_letter(str)
111+
return str:sub(1, 1):upper() .. str:sub(2)
112+
end
113+
114+
-- If the data is just a string corresponding to a
115+
-- CRediT identifier, upgrade it to a dictionary,
116+
-- otherwise return it as is
117+
function clean_role_dict(d)
118+
if d.credit then
119+
return d
120+
else
121+
return { ["credit"] = pandoc.utils.stringify(d) }
122+
end
123+
end
124+
125+
local function prepare_credit (meta)
126+
meta.hasRoles = false
127+
for _, author in ipairs(meta.authors or {}) do
128+
if author.roles then
129+
roleList = {}
130+
for _, roleDict in ipairs(author.roles) do
131+
roleDict = clean_role_dict(roleDict)
132+
credit_id = pandoc.utils.stringify(roleDict.credit)
133+
if invalidCreditID(credit_id) then
134+
print("invalid credit ID for author " .. author.name .. ": " .. credit_id)
135+
elseif roleDict.degree then
136+
degree = capitalize_first_letter(pandoc.utils.stringify(roleDict.degree))
137+
if invalidDegree(degree) then
138+
print("invalid degree for author " .. author.name .. ": " .. degree)
139+
-- even though the degree is invalid, add the role anyway
140+
table.insert(roleList, roles[credit_id].name)
141+
else
142+
table.insert(roleList, roles[credit_id].name .. " (" .. degree .. ")")
143+
end
144+
else
145+
table.insert(roleList, roles[credit_id].name)
146+
end
147+
end
148+
if #roleList > 0 then
149+
meta.hasRoles = true
150+
author.rolesString = join_with_commas_and(roleList)
151+
end
152+
end
153+
end
154+
return meta
155+
end
156+
157+
function Meta (meta)
158+
local ok, result = pcall(prepare_credit, meta)
159+
if ok then
160+
return result
161+
end
162+
end
163+
164+
function assertEqual(expected, actual)
165+
assert(expected == actual, "got \"" .. actual .. "\", expected \"" .. expected .. "\"")
166+
end
167+
168+
function tests()
169+
assert("" == join_with_commas_and({ }))
170+
assert("foo" == join_with_commas_and({ "foo" }))
171+
assert("foo & bar" == join_with_commas_and({ "foo", "bar" }))
172+
assert("foo, bar, & baz" == join_with_commas_and({ "foo", "bar", "baz" }))
173+
174+
local m1 = {
175+
["authors"] = {
176+
{
177+
["name"] = "Author 1",
178+
["roles"] = {
179+
"methodology"
180+
}
181+
},
182+
{
183+
["name"] = "Author 2",
184+
['roles'] = {
185+
{ ["credit"] = "methodology" }
186+
}
187+
},
188+
{
189+
["name"] = "Author 3",
190+
['roles'] = {
191+
{ ["credit"] = "methodology" },
192+
{ ["credit"] = "data-curation" },
193+
{ ["credit"] = "conceptualization" },
194+
}
195+
},
196+
{
197+
["name"] = "Author 4",
198+
['roles'] = {
199+
{ ["credit"] = "methodology", ["degree"] = "lead" },
200+
{ ["credit"] = "data-curation", ["degree"] = "supporting" },
201+
{ ["credit"] = "conceptualization" },
202+
}
203+
},
204+
}
205+
}
206+
local m1t = prepare_credit(m1)
207+
assert(m1t.hasRoles, "hasRoles should be set to true")
208+
assertEqual("Methodology", m1t['authors'][1].rolesString)
209+
assertEqual("Methodology", m1t['authors'][2].rolesString)
210+
assertEqual("Methodology, Data curation, & Conceptualization", m1t['authors'][3].rolesString)
211+
assertEqual("Methodology (Lead), Data curation (Supporting), & Conceptualization", m1t['authors'][4].rolesString)
212+
213+
local m2 = {
214+
["authors"] = {
215+
{
216+
["name"] = "Author 1"
217+
},
218+
{
219+
["name"] = "Author 2"
220+
}
221+
}
222+
}
223+
local m2t = prepare_credit(m2)
224+
assert(not m2t.hasRoles, "hasRoles should be set to false")
225+
end
226+
227+
tests()

data/templates/default.latex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,17 @@ $if(lof)$
554554
$endif$
555555
$body$
556556

557+
$if(hasRoles)$
558+
\section{Author Contributions}\label{author-contributions}
559+
\begin{enumerate}
560+
$for(authors)$
561+
$if(it.rolesString)$
562+
\item $it.name$ - $it.rolesString$
563+
$endif$
564+
$endfor$
565+
\end{enumerate}
566+
$endif$
567+
557568
$if(natbib)$
558569
$if(bibliography)$
559570
$if(biblio-title)$

data/templates/preprint.latex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,17 @@ $if(has-frontmatter)$
435435
$endif$
436436
$body$
437437

438+
$if(hasRoles)$
439+
\section{Author Contributions}\label{author-contributions}
440+
\begin{enumerate}
441+
$for(authors)$
442+
$if(it.rolesString)$
443+
\item $it.name$ - $it.rolesString$
444+
$endif$
445+
$endfor$
446+
\end{enumerate}
447+
$endif$
448+
438449
$if(has-frontmatter)$
439450
\backmatter
440451
$endif$

0 commit comments

Comments
 (0)