diff --git a/.changeset/curly-ads-repeat.md b/.changeset/curly-ads-repeat.md new file mode 100644 index 000000000..6e291082e --- /dev/null +++ b/.changeset/curly-ads-repeat.md @@ -0,0 +1,5 @@ +--- +'myst-templates': patch +--- + +Eliminate frontmatter validation warnings for template doc diff --git a/.changeset/kind-planes-rhyme.md b/.changeset/kind-planes-rhyme.md new file mode 100644 index 000000000..d1c40270f --- /dev/null +++ b/.changeset/kind-planes-rhyme.md @@ -0,0 +1,5 @@ +--- +'myst-frontmatter': patch +--- + +Add dois to venue and biblio diff --git a/docs/frontmatter.md b/docs/frontmatter.md index 311162ee3..d3aebc0f7 100644 --- a/docs/frontmatter.md +++ b/docs/frontmatter.md @@ -728,13 +728,14 @@ The term `venue` is borrowed from the [OpenAlex](https://docs.openalex.org/about > Venues are where works are hosted. -Available fields in the `venue` object are `title` and `url`. +Available fields in the `venue` object are `title`, `short_title` (or title abbreviation), and `url`. You may also provide a DOI under `biblio`; this DOI is the _venue_ DOI. Some typical `venue` values may be: ```yaml venue: title: Journal of Geophysics + short_title: J. Geophys url: https://journal.geophysicsjournal.com ``` @@ -752,7 +753,7 @@ The term `biblio` is borrowed from the [OpenAlex](https://docs.openalex.org/abou > Old-timey bibliographic info for this work. This is mostly useful only in citation/reference contexts. These are all strings because sometimes you'll get fun values like "Spring" and "Inside cover." -Available fields in the `biblio` object are `volume`, `issue`, `first_page` and `last_page`. +Available fields in the `biblio` object are `volume`, `issue`, `first_page` and `last_page`. You may also provide a DOI under `biblio`; this DOI is the _issue_ DOI. Some example `biblio` values may be: @@ -771,4 +772,5 @@ biblio: volume: '2022' issue: Winter first_page: Inside cover # can be a number or string + doi: 10.62329/MYISSUE ``` diff --git a/packages/myst-frontmatter/src/biblio/biblio.yml b/packages/myst-frontmatter/src/biblio/biblio.yml index 09f8fa292..4460674d3 100644 --- a/packages/myst-frontmatter/src/biblio/biblio.yml +++ b/packages/myst-frontmatter/src/biblio/biblio.yml @@ -19,9 +19,11 @@ cases: issue: example first_page: 1 last_page: 2 + doi: 10.0000/abc123 normalized: biblio: volume: test issue: example first_page: 1 last_page: 2 + doi: 10.0000/abc123 diff --git a/packages/myst-frontmatter/src/biblio/types.ts b/packages/myst-frontmatter/src/biblio/types.ts index 9eec57339..b44716a2d 100644 --- a/packages/myst-frontmatter/src/biblio/types.ts +++ b/packages/myst-frontmatter/src/biblio/types.ts @@ -2,6 +2,7 @@ export type Biblio = { // https://docs.openalex.org/about-the-data/work#biblio volume?: string | number; // sometimes you'll get fun values like "Spring" and "Inside cover." issue?: string | number; + doi?: string; // Issue DOI first_page?: string | number; last_page?: string | number; }; diff --git a/packages/myst-frontmatter/src/biblio/validators.ts b/packages/myst-frontmatter/src/biblio/validators.ts index b7bfd394e..d0cbb7aed 100644 --- a/packages/myst-frontmatter/src/biblio/validators.ts +++ b/packages/myst-frontmatter/src/biblio/validators.ts @@ -1,9 +1,9 @@ import type { ValidationOptions } from 'simple-validators'; import { defined, incrementOptions, validateObjectKeys } from 'simple-validators'; -import { validateStringOrNumber } from '../utils/validators.js'; +import { validateDoi, validateStringOrNumber } from '../utils/validators.js'; import type { Biblio } from './types.js'; -const BIBLIO_KEYS = ['volume', 'issue', 'first_page', 'last_page']; +const BIBLIO_KEYS = ['volume', 'issue', 'doi', 'first_page', 'last_page']; /** * Validate Biblio object @@ -20,6 +20,9 @@ export function validateBiblio(input: any, opts: ValidationOptions) { if (defined(value.issue)) { output.issue = validateStringOrNumber(value.issue, incrementOptions('issue', opts)); } + if (defined(value.doi)) { + output.doi = validateDoi(value.doi, incrementOptions('doi', opts)); + } if (defined(value.first_page)) { output.first_page = validateStringOrNumber( value.first_page, diff --git a/packages/myst-frontmatter/src/utils/fillPageFrontmatter.spec.ts b/packages/myst-frontmatter/src/utils/fillPageFrontmatter.spec.ts index 937414561..5ec7776ae 100644 --- a/packages/myst-frontmatter/src/utils/fillPageFrontmatter.spec.ts +++ b/packages/myst-frontmatter/src/utils/fillPageFrontmatter.spec.ts @@ -710,6 +710,11 @@ describe('fillPageFrontmatter', () => { options: { a: 'b' }, }); }); + it('biblio object fills', async () => { + expect( + fillPageFrontmatter({ biblio: { first_page: 10 } }, { biblio: { issue: 1 } }, opts), + ).toEqual({ biblio: { first_page: 10, issue: 1 } }); + }); }); describe('fillSiteFrontmatter', () => { diff --git a/packages/myst-frontmatter/src/utils/fillPageFrontmatter.ts b/packages/myst-frontmatter/src/utils/fillPageFrontmatter.ts index 3ab022c5d..085cbe0c4 100644 --- a/packages/myst-frontmatter/src/utils/fillPageFrontmatter.ts +++ b/packages/myst-frontmatter/src/utils/fillPageFrontmatter.ts @@ -211,6 +211,13 @@ export function fillProjectFrontmatter( }; } + if (filler.biblio || base.biblio) { + frontmatter.biblio = { + ...(filler.biblio ?? {}), + ...(base.biblio ?? {}), + }; + } + if (!trimUnused) { if (filler.bibliography || base.bibliography) { frontmatter.bibliography = [ diff --git a/packages/myst-frontmatter/src/venues/types.ts b/packages/myst-frontmatter/src/venues/types.ts index cb251c7ad..5269e026c 100644 --- a/packages/myst-frontmatter/src/venues/types.ts +++ b/packages/myst-frontmatter/src/venues/types.ts @@ -1,4 +1,6 @@ export type Venue = { title?: string; + short_title?: string; url?: string; + doi?: string; }; diff --git a/packages/myst-frontmatter/src/venues/validators.ts b/packages/myst-frontmatter/src/venues/validators.ts index 89a7ce0d4..ef04835ba 100644 --- a/packages/myst-frontmatter/src/venues/validators.ts +++ b/packages/myst-frontmatter/src/venues/validators.ts @@ -6,6 +6,7 @@ import { validateString, validateUrl, } from 'simple-validators'; +import { validateDoi } from '../utils/validators.js'; import type { Venue } from './types.js'; /** @@ -22,14 +23,24 @@ export function validateVenue(input: any, opts: ValidationOptions) { // This means 'venue.title' only shows up in errors if present in original input titleOpts = incrementOptions('title', opts); } - const value = validateObjectKeys(input, { optional: ['title', 'url'] }, opts); + const value = validateObjectKeys( + input, + { optional: ['title', 'short_title', 'url', 'doi'] }, + opts, + ); if (value === undefined) return undefined; const output: Venue = {}; if (defined(value.title)) { output.title = validateString(value.title, titleOpts); } + if (defined(value.short_title)) { + output.short_title = validateString(value.short_title, incrementOptions('short_title', opts)); + } if (defined(value.url)) { output.url = validateUrl(value.url, incrementOptions('url', opts)); } + if (defined(value.doi)) { + output.doi = validateDoi(value.doi, incrementOptions('doi', opts)); + } return output; } diff --git a/packages/myst-frontmatter/src/venues/venues.yml b/packages/myst-frontmatter/src/venues/venues.yml index 46f14214e..423d2c6c0 100644 --- a/packages/myst-frontmatter/src/venues/venues.yml +++ b/packages/myst-frontmatter/src/venues/venues.yml @@ -29,3 +29,16 @@ cases: venue: title: test warnings: 1 + - title: doi/short_title validate + raw: + venue: + title: test + url: http://example.com + doi: 10.0000/abc123 + short_title: test + normalized: + venue: + title: test + url: http://example.com + doi: 10.0000/abc123 + short_title: test diff --git a/packages/myst-templates/src/validators.ts b/packages/myst-templates/src/validators.ts index 89fce5484..3c5c5015c 100644 --- a/packages/myst-templates/src/validators.ts +++ b/packages/myst-templates/src/validators.ts @@ -6,6 +6,7 @@ import { TemplateKind, TemplateOptionType } from 'myst-common'; import type { ReferenceStash } from 'myst-frontmatter'; import { PAGE_FRONTMATTER_KEYS, + PROJECT_FRONTMATTER_KEYS, RESERVED_EXPORT_KEYS, validateAffiliation, validateAndStashObject, @@ -16,6 +17,7 @@ import { } from 'myst-frontmatter'; import { defined, + filterKeys, incrementOptions, validateBoolean, validateChoice, @@ -211,7 +213,10 @@ export function validateTemplateDoc( options: Record, opts: ValidationOptions, ) { - const output = validateProjectFrontmatter(frontmatter, opts); + const output = validateProjectFrontmatter( + filterKeys(frontmatter, PROJECT_FRONTMATTER_KEYS), + opts, + ); if (output === undefined) return undefined; const filteredDoc = docDefinitions.filter((def) => { return conditionMet(def, { ...options });