summaryrefslogtreecommitdiff
path: root/src/utility/feed/atom.ts
blob: d8827e952c790e17d1ddadcde7d02706afd03d27 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*** UTILITY ------------------------------------------ ***/

import { BaseFeed, escapeXML, type FeedOptions } from "./helper.ts";

interface AtomEntry {
  content?: {
    body: string;
    type?: string;
  };
  id: string;
  image?: string;
  link: string;
  summary: string;
  title: string;
  updated?: Date;
}

/*** EXPORT ------------------------------------------- ***/

export class FeedAtom extends BaseFeed<AtomEntry> {
  constructor(options: FeedOptions) {
    super(options);
  }

  build(): string {
    const xmlParts: string[] = [
      `<?xml version="1.0" encoding="UTF-8"?>\n`,
      `<feed xmlns="http://www.w3.org/2005/Atom">\n`,
      `  <title>${escapeXML(this.options.title)}</title>\n`,
      `  <subtitle>${escapeXML(this.options.description)}</subtitle>\n`,
      `  <link rel="alternate" href="${escapeXML(this.options.link)}"/>\n`,
      `  <link rel="self" href="${escapeXML(this.options.link)}"/>\n`,
      `  <updated>${this.options.updated?.toISOString()}</updated>\n`,
      `  <generator>${this.options.generator || "the webb blog"}</generator>\n`,
      `  <id>${escapeXML(this.options.link)}</id>\n`
    ];

    for (const author of this.options.authors) {
      xmlParts.push(`  <author>\n`);

      if (author.name)
        xmlParts.push(`    <name>${escapeXML(author.name)}</name>\n`);

      if (author.email)
        xmlParts.push(`    <email>${escapeXML(author.email)}</email>\n`);

      if (author.link)
        xmlParts.push(`    <uri>${escapeXML(author.link)}</uri>\n`);

      xmlParts.push(`  </author>\n`);
    }

    if (this.options.icon) {
      xmlParts.push(`  <icon>${escapeXML(this.options.icon)}</icon>\n`);
      xmlParts.push(`  <logo>${escapeXML(this.options.icon)}</logo>\n`);
    }

    if (this.options.feed)
      xmlParts.push(`  <link rel="self" href="${escapeXML(this.options.feed)}"/>\n`);

    for (const entry of this.items) {
      xmlParts.push(
        `  <entry>\n`,
        `    <title type="html">${escapeXML(entry.title)}</title>\n`,
        `    <link href="${escapeXML(entry.link)}"/>\n`,
        `    <id>${escapeXML(entry.id)}</id>\n`,
        `    <updated>${entry.updated?.toISOString() || new Date().toISOString()}</updated>\n`,
        `    <summary type="html">${escapeXML(entry.summary)}</summary>\n`,
        `    <content type="${entry.content?.type || "html"}">${escapeXML(entry.content?.body || entry.summary)}</content>\n`,
        entry.image ?
          `    <media:thumbnail url="${escapeXML(entry.image)}" />\n` :
          "",
        `  </entry>\n`
      );
    }

    for (const category of this.categories) {
      xmlParts.push(`  <category term="${escapeXML(category)}"/>\n`);
    }

    xmlParts.push("</feed>");
    return xmlParts.join("");
  }
}