Skip to content

Commit

Permalink
Migrate from xml to xml-js
Browse files Browse the repository at this point in the history
  • Loading branch information
jpmonette committed May 28, 2019
1 parent 919ad32 commit 0cae9bf
Show file tree
Hide file tree
Showing 12 changed files with 886 additions and 937 deletions.
5 changes: 2 additions & 3 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "feed",
"version": "2.0.4",
"version": "3.0.0",
"description": "Feed is a RSS, Atom and JSON feed generator for Node.js, making content syndication simple and intuitive!",
"homepage": "https://github.com/jpmonette",
"author": "Jean-Philippe Monette <contact@jpmonette.net>",
Expand All @@ -23,8 +23,7 @@
"blog"
],
"dependencies": {
"luxon": "^1.3.3",
"xml": "^1.0.1"
"xml-js": "^1.6.11"
},
"devDependencies": {
"@types/jest": "^23.3.1",
Expand Down
6 changes: 2 additions & 4 deletions src/__tests__/__snapshots__/atom1.spec.ts.snap
Expand Up @@ -17,8 +17,7 @@ exports[`atom 1.0 should generate a valid feed 1`] = `
<subtitle>This is my personnal feed!</subtitle>
<logo>http://example.com/image.png</logo>
<rights>All rights reserved 2013, John Doe</rights>
<category term=\\"Technology\\">
</category>
<category term=\\"Technology\\"/>
<contributor>
<name>Johan Cruyff</name>
<email>johancruyff@example.com</email>
Expand All @@ -27,8 +26,7 @@ exports[`atom 1.0 should generate a valid feed 1`] = `
<entry>
<title type=\\"html\\"><![CDATA[Hello World]]></title>
<id>https://example.com/hello-world</id>
<link href=\\"https://example.com/hello-world\\">
</link>
<link href=\\"https://example.com/hello-world\\"/>
<updated>2013-07-13T23:00:00.000Z</updated>
<summary type=\\"html\\"><![CDATA[This is an article about Hello World.]]></summary>
<content type=\\"html\\"><![CDATA[Content of my item]]></content>
Expand Down
3 changes: 1 addition & 2 deletions src/__tests__/__snapshots__/rss2.spec.ts.snap
Expand Up @@ -28,8 +28,7 @@ exports[`rss 2.0 should generate a valid feed 1`] = `
<content:encoded><![CDATA[Content of my item]]></content:encoded>
<author>janedoe@example.com (Jane Doe)</author>
<author>joesmith@example.com (Joe Smith)</author>
<enclosure url=\\"https://example.com/hello-world.jpg\\">
</enclosure>
<enclosure url=\\"https://example.com/hello-world.jpg\\"/>
</item>
</channel>
</rss>"
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/atom1.spec.ts
Expand Up @@ -2,7 +2,7 @@ import { sampleFeed } from "./setup";

describe("atom 1.0", () => {
it("should generate a valid feed", () => {
let actual = sampleFeed.atom1();
const actual = sampleFeed.atom1();
expect(actual).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion src/__tests__/rss2.spec.ts
Expand Up @@ -2,7 +2,7 @@ import { sampleFeed } from "./setup";

describe("rss 2.0", () => {
it("should generate a valid feed", () => {
let actual = sampleFeed.rss2();
const actual = sampleFeed.rss2();
expect(actual).toMatchSnapshot();
});
});
130 changes: 68 additions & 62 deletions src/atom1.ts
@@ -1,109 +1,120 @@
/// <reference path="types/index.ts" />

import * as xml from "xml";
import { generator } from "./config";

const DOCTYPE = '<?xml version="1.0" encoding="utf-8"?>\n';
import * as convert from "xml-js";
import { Feed } from "./feed";
import { Author, Item } from "./typings";

export default (ins: Feed) => {
const { options } = ins;

let feed: any = [];

feed.push({ _attr: { xmlns: "http://www.w3.org/2005/Atom" } });
feed.push({ id: options.id });
feed.push({ title: options.title });

if (options.updated) {
feed.push({ updated: options.updated.toISOString() });
} else {
feed.push({ updated: new Date().toISOString() });
}

feed.push({ generator: options.generator || generator });
const base: any = {
_declaration: { _attributes: { version: "1.0", encoding: "utf-8" } },
feed: {
_attributes: { xmlns: "http://www.w3.org/2005/Atom" },
id: options.id,
title: options.title,
updated: options.updated ? options.updated.toISOString() : new Date().toISOString(),
generator: options.generator || generator
}
};

if (options.author) {
feed.push({ author: formatAuthor(options.author) });
base.feed.author = formatAuthor(options.author);
}

base.feed.link = [];

// link (rel="alternate")
if (options.link) {
feed.push({ link: { _attr: { rel: "alternate", href: options.link } } });
base.feed.link.push({ _attributes: { rel: "alternate", href: options.link } });
}

// link (rel="self")
const atomLink = options.feed || (options.feedLinks && options.feedLinks.atom);

if (atomLink) {
feed.push({ link: { _attr: { rel: "self", href: atomLink } } });
base.feed.link.push({ _attributes: { rel: "self", href: atomLink } });
}

// link (rel="hub")
if (options.hub) {
feed.push({ link: { _attr: { rel: "hub", href: options.hub } } });
base.feed.link.push({ _attributes: { rel: "hub", href: options.hub } });
}

/**************************************************************************
* "feed" node: optional elements
*************************************************************************/

if (options.description) {
feed.push({ subtitle: options.description });
base.feed.subtitle = options.description;
}

if (options.image) {
feed.push({ logo: options.image });
base.feed.logo = options.image;
}

if (options.favicon) {
feed.push({ icon: options.favicon });
base.feed.icon = options.favicon;
}

if (options.copyright) {
feed.push({ rights: options.copyright });
base.feed.rights = options.copyright;
}

ins.categories.forEach((category: string) => {
feed.push({ category: [{ _attr: { term: category } }] });
base.feed.category = [];

ins.categories.map((category: string) => {
base.feed.category.push({ _attributes: { term: category } });
});

ins.contributors.forEach((contributor: Author) => feed.push({ contributor: formatAuthor(contributor) }));
base.feed.contributor = [];

ins.contributors.map((contributor: Author) => {
base.feed.contributor.push(formatAuthor(contributor));
});

// icon

base.feed.entry = [];

/**************************************************************************
* "entry" nodes
*************************************************************************/
ins.items.forEach((item: Item) => {
ins.items.map((item: Item) => {
//
// entry: required elements
//

let entry: any = [
{ title: { _attr: { type: "html" }, _cdata: item.title } },
{ id: item.id || item.link },
{ link: [{ _attr: { href: item.link } }] },
{ updated: item.date.toISOString() }
];
let entry: convert.ElementCompact = {
title: { _attributes: { type: "html" }, _cdata: item.title },
id: item.id || item.link,
link: [{ _attributes: { href: item.link } }],
updated: item.date.toISOString()
};

//
// entry: recommended elements
//
if (item.description) {
entry.push({
summary: { _attr: { type: "html" }, _cdata: item.description }
});
entry.summary = {
_attributes: { type: "html" },
_cdata: item.description
};
}

if (item.content) {
entry.push({
content: { _attr: { type: "html" }, _cdata: item.content }
});
entry.content = {
_attributes: { type: "html" },
_cdata: item.content
};
}

// entry author(s)
if (Array.isArray(item.author)) {
item.author.forEach((author: Author) => entry.push({ author: formatAuthor(author) }));
entry.author = [];

item.author.map((author: Author) => {
entry.author.push(formatAuthor(author));
});
}

// content
Expand All @@ -118,42 +129,37 @@ export default (ins: Feed) => {

// contributor
if (item.contributor && Array.isArray(item.contributor)) {
item.contributor.forEach((contributor: Author) => entry.push({ contributor: formatAuthor(contributor) }));
entry.contributor = [];

item.contributor.map((contributor: Author) => {
entry.contributor.push(formatAuthor(contributor));
});
}

// published
if (item.published) {
entry.push({ published: item.published.toISOString() });
entry.published = item.published.toISOString();
}

// source

// rights
if (item.copyright) {
entry.push({ rights: item.copyright });
entry.rights = item.copyright;
}

feed.push({ entry });
base.feed.entry.push(entry);
});

return DOCTYPE + xml([{ feed }], true);
return convert.js2xml(base, { compact: true, ignoreComment: true, spaces: 4 });
};

const formatAuthor = (author: Author) => {
const { name, email, link } = author;
let contributor = [];

if (name) {
contributor.push({ name });
}

if (email) {
contributor.push({ email });
}

if (link) {
contributor.push({ uri: link });
}

return contributor;
return {
name,
email,
uri: link
};
};
3 changes: 1 addition & 2 deletions src/feed.ts
@@ -1,8 +1,7 @@
/// <reference path="types/index.ts" />

import renderAtom from "./atom1";
import renderJSON from "./json";
import renderRSS from "./rss2";
import { FeedOptions, Item, Author, Extension } from "./typings";

export class Feed {
options: FeedOptions;
Expand Down
8 changes: 5 additions & 3 deletions src/json.ts
@@ -1,7 +1,9 @@
/// <reference path="types/index.ts" />
import { Extension, Item, Author } from "./typings";
import { Feed } from "./feed";

export default (ins: Feed) => {
const { options, items, extensions } = ins;

let feed: any = {
version: "https://jsonfeed.org/version/1",
title: options.title
Expand Down Expand Up @@ -33,7 +35,7 @@ export default (ins: Feed) => {
}
}

extensions.forEach((e: Extension) => {
extensions.map((e: Extension) => {
feed[e.name] = e.objects;
});

Expand Down Expand Up @@ -81,7 +83,7 @@ export default (ins: Feed) => {
}

if (item.extensions) {
item.extensions.forEach((e: Extension) => {
item.extensions.map((e: Extension) => {
feedItem[e.name] = e.objects;
});
}
Expand Down

0 comments on commit 0cae9bf

Please sign in to comment.