Skip to content

Commit 54a50f9

Browse files
committed
Resolve paths that appear in custom listing items
1 parent 3b889d8 commit 54a50f9

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

news/changelog-1.3.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818

1919
## Listings
2020

21-
- Listings now support `template-params`, which will be passed to custom EJS templates when a listing is rendered.
21+
- Listings now support `template-params`, which will be passed to custom EJS templates in a variable called `templateParams` when a listing is rendered.
22+
- Custom listing objects now resolve `path: ` fields into the metadata that would be generated by standard listings, giving custom listing access to computed metadata like `reading-time`, etc.
23+
2224

2325
## Miscellaneous
2426

2527
- ensure `video` shortcode works with `embed-resources` and `self-contained` ([#3310](https://github.com/quarto-dev/quarto-cli/issues/3310))
28+

src/project/types/website/listing/website-listing-read.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,13 @@ async function readContents(
583583
const yaml = readYaml(file);
584584
if (Array.isArray(yaml)) {
585585
const items = yaml as Array<unknown>;
586-
items.forEach((item) => {
586+
for (const item of items) {
587587
if (typeof (item) === "object") {
588-
const listingItem = listItemFromMeta(item as Metadata);
588+
const listingItem = await listItemFromMeta(
589+
item as Metadata,
590+
project,
591+
listing,
592+
);
589593
validateItem(listing, listingItem, (field: string) => {
590594
return `An item from the file '${file}' is missing the required field '${field}'.`;
591595
});
@@ -596,9 +600,13 @@ async function readContents(
596600
`Unexpected listing contents in file ${file}. The array may only contain listing items, not paths or other types of data.`,
597601
);
598602
}
599-
});
603+
}
600604
} else if (typeof (yaml) === "object") {
601-
const listingItem = listItemFromMeta(yaml as Metadata);
605+
const listingItem = await listItemFromMeta(
606+
yaml as Metadata,
607+
project,
608+
listing,
609+
);
602610
validateItem(listing, listingItem, (field: string) => {
603611
return `The item defined in file '${file}' is missing the required field '${field}'.`;
604612
});
@@ -634,14 +642,14 @@ async function readContents(
634642

635643
// Process any metadata that appears in contents
636644
if (contentMetadatas.length > 0) {
637-
contentMetadatas.forEach((content) => {
638-
const listingItem = listItemFromMeta(content);
645+
for (const content of contentMetadatas) {
646+
const listingItem = await listItemFromMeta(content, project, listing);
639647
validateItem(listing, listingItem, (field: string) => {
640648
return `An item in the listing '${listing.id}' is missing the required field '${field}'.`;
641649
});
642650
listingItemSources.add(ListingItemSource.metadata);
643651
listingItems.push(listingItem);
644-
});
652+
}
645653
}
646654

647655
return {
@@ -679,14 +687,35 @@ function validateItem(
679687
}
680688
}
681689

682-
function listItemFromMeta(meta: Metadata) {
683-
const listingItem = cloneDeep(meta);
690+
async function listItemFromMeta(
691+
meta: Metadata,
692+
project: ProjectContext,
693+
listing: ListingDehydrated,
694+
) {
695+
let listingItem = cloneDeep(meta);
684696

685697
// If there is a path, try to complete the filename and
686698
// modified values
687-
if (meta.path !== undefined) {
688-
meta[kFieldFileName] = basename(meta.path as string);
689-
meta[kFieldFileModified] = fileModifiedDate(meta.path as string);
699+
if (typeof meta.path === "string") {
700+
const base = basename(meta.path);
701+
const extension = extname(base).toLocaleLowerCase();
702+
meta[kFieldFileName] = base;
703+
meta[kFieldFileModified] = fileModifiedDate(meta.path);
704+
705+
const markdownExtensions = [".qmd", ".md", ".rmd"];
706+
if (markdownExtensions.indexOf(extension) !== -1) {
707+
const fileListing = await listItemFromFile(meta.path, project, listing);
708+
if (fileListing === undefined) {
709+
warning(
710+
`Draft document ${meta.path} found in a custom listing: item will not have computed metadata.`,
711+
);
712+
} else {
713+
listingItem = {
714+
...(fileListing.item || {}),
715+
...listingItem,
716+
};
717+
}
718+
}
690719
}
691720

692721
if (meta.author) {

src/project/types/website/listing/website-listing-template.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function templateMarkdownHandler(
150150
ejsParams.listing = reshapedListing;
151151
} else {
152152
ejsParams["metadataAttrs"] = reshapedListing.utilities.metadataAttrs;
153-
ejsParams["template-params"] = reshapedListing["template-params"];
153+
ejsParams["templateParams"] = reshapedListing["template-params"];
154154
}
155155
return ejsParams;
156156
};

0 commit comments

Comments
 (0)