Plain is headed towards 1.0! Subscribe for development updates →

 1import os
 2
 3import frontmatter
 4
 5from plain.templates import Template
 6from plain.utils.functional import cached_property
 7
 8from .markdown import render_markdown
 9
10
11class Page:
12    def __init__(self, url_path, relative_path, absolute_path):
13        self.url_path = url_path
14        self.relative_path = relative_path
15        self.absolute_path = absolute_path
16
17    @cached_property
18    def _frontmatter(self):
19        with open(self.absolute_path) as f:
20            return frontmatter.load(f)
21
22    @cached_property
23    def vars(self):
24        return self._frontmatter.metadata
25
26    @cached_property
27    def title(self):
28        default_title = os.path.splitext(os.path.basename(self.relative_path))[0]
29        return self.vars.get("title", default_title)
30
31    @cached_property
32    def content(self):
33        # Strip the frontmatter
34        content = self._frontmatter.content
35
36        if not self.vars.get("render_plain", False):
37            template = Template(os.path.join("pages", self.relative_path))
38            content = template.render({})
39            # Strip the frontmatter again, since it was in the template file itself
40            _, content = frontmatter.parse(content)
41
42        if self.content_type == "markdown":
43            content = render_markdown(content)
44
45        return content
46
47    @property
48    def content_type(self):
49        extension = os.path.splitext(self.absolute_path)[1]
50
51        # Explicitly define the known content types that we intend to handle
52        # (others will still pass through)
53        if extension == ".md":
54            return "markdown"
55
56        if extension == ".html":
57            return "html"
58
59        if extension == ".redirect":
60            return "redirect"
61
62        return extension.lstrip(".")
63
64    def get_template_name(self):
65        if template_name := self.vars.get("template_name"):
66            return template_name
67
68        return f"{self.content_type}.html"