I'm surprised nobody has done it before and I was just about to hack my own script to convert package.json to CITATION.cff to have a single source of truth and avoid crafting and updating CITATION.cff by hand. Maybe I can extend this library instead?
Here is a sketch, just to illustrate the idea:
function parseAuthor(author: string | PackageAuthor): PackageAuthor {
if (typeof author === 'string') {
// Pattern: "Name <email> (url)"
const m = author.match(/^(.*?)\s*(?:<([^>]+)>)?\s*(?:\(([^)]+)\))?/);
return {
name: m?.[1]?.trim() || author,
email: m?.[2] || undefined,
url: m?.[3] || undefined,
};
} else if (typeof author === 'object') {
return {
name: author.name,
email: author.email,
url: author.url,
orcid: author.orcid,
};
}
return { name: String(author) };
}
const authors: PackageAuthor[] = [];
if (pkg.author) authors.push(parseAuthor(pkg.author));
if (Array.isArray(pkg.contributors)) {
for (const c of pkg.contributors) authors.push(parseAuthor(c));
// TODO add ORCID from another source, e.g. something like https://git-scm.com/docs/gitmailmap
}
const repoUrl = typeof pkg.repository === 'object' ? pkg.repository.url : pkg.repository;
const citation: Record<string, any> = {
'cff-version': '1.2.0',
message: 'If you use this software, please cite it using this metadata',
title: pkg.name, // required
version: pkg.version, // required
'date-released': pkg.cff.?release || '', // TODO: get from git history instead
abstract: pkg.description || '',
'repository-code': repoUrl.?replace(/^git\+/, '').?replace(/\.git$/, ''),
type: 'software',
authors: authors.filter(a => a?.name),
};
This would also solve #1.
I'm surprised nobody has done it before and I was just about to hack my own script to convert
package.jsontoCITATION.cffto have a single source of truth and avoid crafting and updatingCITATION.cffby hand. Maybe I can extend this library instead?Here is a sketch, just to illustrate the idea:
This would also solve #1.